diff --git a/DEPS b/DEPS
index ab864ea..38aae97 100644
--- a/DEPS
+++ b/DEPS
@@ -275,19 +275,19 @@
   # 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': 'd881def3e544be7db5524a80e5dce7ca0a970f09',
+  'skia_revision': '3789354a30884796e45a69bf786af55829b312ed',
   # 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': 'dca05c50dc29a73c4396bb79318dd6b387974c25',
+  'v8_revision': '08753688ef97fc22d5d4c19f4df1d9ad4dee8369',
   # 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': 'bbf67e2e41d8acdcb72b8c1a154032f378b13b39',
+  'angle_revision': '415ff51b8005ab462c3bd883dff75d31499132dc',
   # 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': 'b96e5c7ae73cf3d3e8b0cb36e69cf5996ec358b2',
+  'swiftshader_revision': '19e3080dfe86936d88bd68c38281fc4095128758',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -354,7 +354,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'ae1192b6309e632d35ff71b4e8ab28daa1b057e0',
+  'devtools_frontend_revision': 'de7492ce96704a4f786c234a75caf5c24689cef0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -390,11 +390,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '4313dba514e2b05c5941c65b92f489cda3655fb0',
+  'dawn_revision': 'f0c150b01bd832ea2922c49b37860cca5e23cc83',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': 'e4c94b8f2beff14b5384c92c01142a5f9b049a6c',
+  'quiche_revision': 'ac5d3befbfeb25d0342a1b92dceeb0e41a23b320',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -438,7 +438,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libunwind_revision':    '86ab9dd74328fda5fca5d2a36d557fb0cb7e15fa',
+  'libunwind_revision':    '125ac3cd81ac3d9ca9517a63adb11d9821985d61',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -751,7 +751,7 @@
   },
 
   'src/ios/third_party/earl_grey2/src': {
-      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '9d8a5c2b806286ee427c44591d9ee2a0f1b01896',
+      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'a4306080636bae86ea7d1d9cedac9db36f308262',
       'condition': 'checkout_ios',
   },
 
@@ -920,7 +920,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'EKR4SCLSFfEmo0jX5ydw8CXB5JVIF8JzSzpccM2Rq-UC',
+          'version': 't8u6cpAO_nKvgbs2QTi9-n-W4xNyj5EefknR_0PXopkC',
       },
     ],
     'condition': 'checkout_android',
@@ -1136,7 +1136,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '14e6d235f254941a03fa18570880e5b1b2fc147b',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '04663d61d15e0bcc4eb50b15fb3e9cba3d8857df',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1781,7 +1781,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@9ec0b6929b2c684a720018288f767b72ed331de4',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1b6dc50ac8969e6c1d87f3f829dc5169bd433e02',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/safe_browsing/docs/differences.md b/android_webview/browser/safe_browsing/docs/differences.md
index 3bbb4fa..674dc4a0 100644
--- a/android_webview/browser/safe_browsing/docs/differences.md
+++ b/android_webview/browser/safe_browsing/docs/differences.md
@@ -1,5 +1,15 @@
 # Differences in support/behavior compared to Chrome
 
+## Sometimes, no interstitial
+
+If we detect the WebView is not visible to the user (ex. if it is not attached
+to a window or the WebView is marked as invisible with `View#setVisibility()`),
+then WebView does not show an interstitial at all. In this case, we just return
+the [`ERROR_UNSAFE_RESOURCE`][1] network error and block the unsafe resource.
+
+This behavior is determined in the code by
+[`AwContents#canShowInterstitial()`](https://source.chromium.org/search?q=class:AwContents%20%5CbcanShowInterstitial%5Cb%20lang:java&sq=&ss=chromium).
+
 ## Quiet interstitials
 
 The main interstitials in Chrome are **Loud** interstitials, which are blocking
@@ -20,9 +30,9 @@
 |---|---|---|
 | ![Small Quiet interstitial](small-interstitial.png) | ![Medium Quiet interstitials](medium-interstitials.png) | ![Giant Quiet interstitial](giant-interstitial.png) |
 
-## Network error
+## Network error on "back to safety"
 
-WebView returns a particular network error to the application when the user
+WebView returns [`ERROR_UNSAFE_RESOURCE`][1] to the application when the user
 clicks "back to safety." This is to stay consistent with expectations of legacy
 applications (to communicate the page failed to load).
 
@@ -41,3 +51,5 @@
 | With "back to safety" button (like Chrome) | No "back to safety" button (WebView only) |
 |---|---|
 | ![With back-to-safety button](loud-interstitial-with-back-button.png) | ![No back-to-safety button](loud-interstitial-no-back-button.png) |
+
+[1]: https://developer.android.com/reference/android/webkit/WebViewClient#ERROR_UNSAFE_RESOURCE
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
index fffc7729..6e68d77d 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
@@ -6,7 +6,6 @@
 
 import android.graphics.Rect;
 import android.net.Uri;
-import android.os.Build.VERSION_CODES;
 import android.support.test.InstrumentationRegistry;
 import android.webkit.JavascriptInterface;
 
@@ -32,7 +31,6 @@
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.CriteriaNotSatisfiedException;
-import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.browser.MessagePort;
@@ -388,7 +386,7 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.Q, message = "https://crbug.com/1251900")
+    @DisabledTest(message = "https://crbug.com/1251900")
     public void testPopupWindowHasUserGestureForUserInitiated() throws Throwable {
         runPopupUserGestureTest(true);
     }
@@ -396,7 +394,7 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
-    @DisabledTest(message = "https://crbug.com/1331093")
+    @DisabledTest(message = "https://crbug.com/1251900")
     public void testPopupWindowHasUserGestureForUserInitiatedNoOpener() throws Throwable {
         runPopupUserGestureTest(false);
     }
diff --git a/ash/ambient/ambient_controller.cc b/ash/ambient/ambient_controller.cc
index 3e5c323..7119c1b3 100644
--- a/ash/ambient/ambient_controller.cc
+++ b/ash/ambient/ambient_controller.cc
@@ -259,8 +259,13 @@
         auto elapsed = base::Time::Now() - start_time_.value();
         DVLOG(2) << "Exit ambient mode. Elapsed time: " << elapsed;
         ambient::RecordAmbientModeTimeElapsed(
-            /*time_delta=*/elapsed,
-            /*tablet_mode=*/Shell::Get()->IsInTabletMode());
+            elapsed, Shell::Get()->IsInTabletMode(),
+            // The user currently has no way of changing the animation theme
+            // (|current_theme_from_pref_|) without exiting screensaver first,
+            // so it is safe to assume that |current_theme_from_pref_| did not
+            // change while the screensaver was active.
+            current_theme_from_pref_ ? *current_theme_from_pref_
+                                     : kDefaultAmbientAnimationTheme);
         start_time_.reset();
       }
 
@@ -688,7 +693,7 @@
           static_cast<int>(AmbientAnimationTheme::kMaxValue)) {
     LOG(WARNING) << "Loaded invalid ambient theme from pref storage: "
                  << current_theme_as_int << ". Default to "
-                 << kDefaultAmbientAnimationTheme;
+                 << ToString(kDefaultAmbientAnimationTheme);
     current_theme_as_int = static_cast<int>(kDefaultAmbientAnimationTheme);
   }
   current_theme_from_pref_ =
@@ -696,8 +701,8 @@
 
   if (previous_theme_from_pref.has_value()) {
     DVLOG(4) << "AmbientAnimationTheme changed from "
-             << *previous_theme_from_pref << " to "
-             << *current_theme_from_pref_;
+             << ToString(*previous_theme_from_pref) << " to "
+             << ToString(*current_theme_from_pref_);
     // For a given topic category, the topics downloaded from IMAX and saved to
     // cache differ from theme to theme:
     // 1) Slideshow mode keeps primary/related photos paired within a topic,
@@ -718,7 +723,7 @@
     ambient_photo_controller_->ClearCache();
   } else {
     DVLOG(4) << "AmbientAnimationTheme initialized to "
-             << *current_theme_from_pref_;
+             << ToString(*current_theme_from_pref_);
   }
 }
 
@@ -867,7 +872,7 @@
     DCHECK(current_theme_from_pref_);
     current_theme = *current_theme_from_pref_;
   }
-  DVLOG(4) << "Loaded ambient theme " << current_theme;
+  DVLOG(4) << "Loaded ambient theme " << ToString(current_theme);
 
   pending_animation_static_resources_.reset();
   if (current_theme == AmbientAnimationTheme::kSlideshow) {
diff --git a/ash/ambient/ambient_controller_unittest.cc b/ash/ambient/ambient_controller_unittest.cc
index baca984..031b749 100644
--- a/ash/ambient/ambient_controller_unittest.cc
+++ b/ash/ambient/ambient_controller_unittest.cc
@@ -21,8 +21,11 @@
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/system/power/power_status.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/run_loop.h"
+#include "base/strings/strcat.h"
 #include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "build/buildflag.h"
@@ -1179,4 +1182,44 @@
   EXPECT_TRUE(GetCachedFiles().empty());
 }
 
+TEST_P(AmbientControllerTestForAnyTheme, MetricsEngagementTime) {
+  base::HistogramTester histogram_tester;
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
+  LockScreen();
+
+  FastForwardToLockScreenTimeout();
+  FastForwardTiny();
+  ASSERT_TRUE(ambient_controller()->IsShown());
+
+  task_environment()->FastForwardBy(base::Minutes(1));
+
+  UnlockScreen();
+  ASSERT_FALSE(ambient_controller()->IsShown());
+
+  histogram_tester.ExpectTimeBucketCount(
+      "Ash.AmbientMode.EngagementTime.ClamshellMode", base::Minutes(1), 1);
+  histogram_tester.ExpectTimeBucketCount(
+      base::StrCat({"Ash.AmbientMode.EngagementTime.", ToString(GetParam())}),
+      base::Minutes(1), 1);
+
+  // Now do the same sequence in tablet mode.
+  Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
+  LockScreen();
+
+  FastForwardToLockScreenTimeout();
+  FastForwardTiny();
+  ASSERT_TRUE(ambient_controller()->IsShown());
+
+  task_environment()->FastForwardBy(base::Minutes(1));
+
+  UnlockScreen();
+  ASSERT_FALSE(ambient_controller()->IsShown());
+
+  histogram_tester.ExpectTimeBucketCount(
+      "Ash.AmbientMode.EngagementTime.TabletMode", base::Minutes(1), 1);
+  histogram_tester.ExpectTimeBucketCount(
+      base::StrCat({"Ash.AmbientMode.EngagementTime.", ToString(GetParam())}),
+      base::Minutes(1), 2);
+}
+
 }  // namespace ash
diff --git a/ash/ambient/resources/ambient_animation_static_resources_impl.cc b/ash/ambient/resources/ambient_animation_static_resources_impl.cc
index a04959d..16b70b0 100644
--- a/ash/ambient/resources/ambient_animation_static_resources_impl.cc
+++ b/ash/ambient/resources/ambient_animation_static_resources_impl.cc
@@ -88,7 +88,8 @@
       }
       // End Themes
   };
-  DCHECK(m.contains(theme)) << "Asset/resource ids missing for " << theme;
+  DCHECK(m.contains(theme))
+      << "Asset/resource ids missing for " << ToString(theme);
   return m.at(theme);
 }
 
diff --git a/ash/components/arc/compat_mode/arc_splash_screen_dialog_view.cc b/ash/components/arc/compat_mode/arc_splash_screen_dialog_view.cc
index b9e34a20..04b100b 100644
--- a/ash/components/arc/compat_mode/arc_splash_screen_dialog_view.cc
+++ b/ash/components/arc/compat_mode/arc_splash_screen_dialog_view.cc
@@ -13,6 +13,7 @@
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/notreached.h"
 #include "base/scoped_multi_source_observation.h"
 #include "chromeos/ui/frame/default_frame_header.h"
 #include "components/strings/grit/components_strings.h"
@@ -214,6 +215,10 @@
   highlight_border_ =
       anchor_->AddChildView(std::make_unique<HighlightBorder>());
 
+  // Observe anchor and its highlight to be notified when it's destroyed.
+  anchor_highlight_observations_.AddObservation(anchor_);
+  anchor_highlight_observations_.AddObservation(highlight_border_);
+
   // Add window observer.
   window_observer_ = std::make_unique<ArcSplashScreenWindowObserver>(
       parent,
@@ -246,6 +251,17 @@
     frame->SetCornerRadius(kCornerRadius);
 }
 
+void ArcSplashScreenDialogView::OnViewIsDeleting(View* observed_view) {
+  if (observed_view == anchor_)
+    anchor_ = nullptr;
+  else if (observed_view == highlight_border_)
+    highlight_border_ = nullptr;
+  else
+    NOTREACHED();
+
+  anchor_highlight_observations_.RemoveObservation(observed_view);
+}
+
 void ArcSplashScreenDialogView::OnWindowActivated(ActivationReason reason,
                                                   aura::Window* gained_active,
                                                   aura::Window* lost_active) {
@@ -281,11 +297,14 @@
   if (!close_callback_)
     return;
 
-  anchor_->RemoveChildViewT(highlight_border_);
+  if (anchor_ && highlight_border_)
+    anchor_->RemoveChildViewT(highlight_border_);
 
   std::move(close_callback_).Run();
-  GetWidget()->CloseWithReason(
-      views::Widget::ClosedReason::kCloseButtonClicked);
+
+  auto* const widget = GetWidget();
+  if (widget)
+    widget->CloseWithReason(views::Widget::ClosedReason::kCloseButtonClicked);
 }
 
 void ArcSplashScreenDialogView::Show(aura::Window* parent,
@@ -308,7 +327,7 @@
   OverlayDialog::Show(
       parent,
       base::BindOnce(&ArcSplashScreenDialogView::OnCloseButtonClicked,
-                     base::Unretained(dialog_view.get())),
+                     dialog_view->weak_ptr_factory_.GetWeakPtr()),
       /*dialog_view=*/nullptr);
 
   // TODO(b/206336651): Investigate the cases when the following check fails.
diff --git a/ash/components/arc/compat_mode/arc_splash_screen_dialog_view.h b/ash/components/arc/compat_mode/arc_splash_screen_dialog_view.h
index 267cee7..c93b1b34 100644
--- a/ash/components/arc/compat_mode/arc_splash_screen_dialog_view.h
+++ b/ash/components/arc/compat_mode/arc_splash_screen_dialog_view.h
@@ -6,7 +6,10 @@
 #define ASH_COMPONENTS_ARC_COMPAT_MODE_ARC_SPLASH_SCREEN_DIALOG_VIEW_H_
 
 #include "base/callback_forward.h"
+#include "base/scoped_multi_source_observation.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/view.h"
+#include "ui/views/view_observer.h"
 #include "ui/wm/public/activation_change_observer.h"
 #include "ui/wm/public/activation_client.h"
 
@@ -15,7 +18,6 @@
 }  // namespace aura
 
 namespace views {
-class View;
 class MdTextButton;
 }  // namespace views
 
@@ -27,6 +29,7 @@
 // inserted into a window. The content container contains a logo, a heading
 // text, a message box in vertical alignment.
 class ArcSplashScreenDialogView : public views::BubbleDialogDelegateView,
+                                  public views::ViewObserver,
                                   public wm::ActivationChangeObserver {
  public:
   // TestApi is used for tests to get internal implementation details.
@@ -58,6 +61,9 @@
   gfx::Size CalculatePreferredSize() const override;
   void AddedToWidget() override;
 
+  // views::ViewObserver:
+  void OnViewIsDeleting(View* observed_view) override;
+
   // wm::ActivationChangeObserver:
   void OnWindowActivated(ActivationReason reason,
                          aura::Window* gained_active,
@@ -68,11 +74,15 @@
 
   void OnCloseButtonClicked();
 
-  views::View* const anchor_;
+  views::View* anchor_;
   views::View* highlight_border_{nullptr};
 
   base::OnceClosure close_callback_;
   views::MdTextButton* close_button_ = nullptr;
+
+  base::ScopedMultiSourceObservation<views::View, views::ViewObserver>
+      anchor_highlight_observations_{this};
+
   std::unique_ptr<ArcSplashScreenWindowObserver> window_observer_;
 
   bool forwarding_activation_{false};
diff --git a/ash/components/arc/compat_mode/arc_splash_screen_dialog_view_unittest.cc b/ash/components/arc/compat_mode/arc_splash_screen_dialog_view_unittest.cc
index a21e192..50e55f1 100644
--- a/ash/components/arc/compat_mode/arc_splash_screen_dialog_view_unittest.cc
+++ b/ash/components/arc/compat_mode/arc_splash_screen_dialog_view_unittest.cc
@@ -29,9 +29,7 @@
   void SetUp() override {
     CompatModeTestBase::SetUp();
     parent_widget_ = CreateWidget();
-
-    anchor_ = parent_widget_->GetRootView()->AddChildView(
-        std::make_unique<views::View>());
+    EnsureAnchor();
   }
 
   void TearDown() override {
@@ -49,13 +47,24 @@
     return widget;
   }
 
+  void EnsureAnchor() {
+    if (anchor_)
+      return;
+    anchor_ = parent_widget_->GetRootView()->AddChildView(
+        std::make_unique<views::View>());
+  }
+  void RemoveAnchor() {
+    parent_widget_->GetRootView()->RemoveChildViewT(anchor_);
+    anchor_ = nullptr;
+  }
+
   views::View* anchor() { return anchor_; }
   aura::Window* parent_window() { return parent_widget_->GetNativeView(); }
   views::Widget* parent_widget() { return parent_widget_.get(); }
 
  private:
   std::unique_ptr<views::Widget> parent_widget_;
-  views::View* anchor_;
+  views::View* anchor_{nullptr};
 };
 
 TEST_F(ArcSplashScreenDialogViewTest, TestCloseButton) {
@@ -85,6 +94,23 @@
   }
 }
 
+TEST_F(ArcSplashScreenDialogViewTest, TestAnchorDestroy) {
+  for (const bool is_for_unresizable : {true, false}) {
+    EnsureAnchor();
+    auto dialog_view = std::make_unique<ArcSplashScreenDialogView>(
+        base::DoNothing(), parent_window(), anchor(), is_for_unresizable);
+    ArcSplashScreenDialogView::TestApi dialog_view_test(dialog_view.get());
+    ShowAsBubble(std::move(dialog_view));
+
+    // Removing the anchor from view hierarchy makes the anchor destroyed.
+    RemoveAnchor();
+
+    // Verify that clicking the button won't cause any crash even after
+    // destroying the anchor.
+    LeftClickOnView(parent_widget(), dialog_view_test.close_button());
+  }
+}
+
 TEST_F(ArcSplashScreenDialogViewTest,
        TestSplashScreenInFullscreenOrMaximinzedWindow) {
   for (const bool is_for_unresizable : {true, false}) {
diff --git a/ash/components/arc/compat_mode/touch_mode_mouse_rewriter.cc b/ash/components/arc/compat_mode/touch_mode_mouse_rewriter.cc
index d2e16527..5fcfc488 100644
--- a/ash/components/arc/compat_mode/touch_mode_mouse_rewriter.cc
+++ b/ash/components/arc/compat_mode/touch_mode_mouse_rewriter.cc
@@ -110,19 +110,21 @@
   const ui::MouseEvent& mouse_event = *event.AsMouseEvent();
   if (mouse_event.IsRightMouseButton() || mouse_event.IsLeftMouseButton()) {
     if (!base::FeatureList::IsEnabled(arc::kRightClickLongPress)) {
-      RecordRightClickConversionResultHistogram(
-          RightClickConversionResultHistogramResult::kDisabled);
+      if (mouse_event.IsRightMouseButton()) {
+        RecordRightClickConversionResultHistogram(
+            RightClickConversionResultHistogramResult::kDisabled);
+      }
       return SendEvent(continuation, &event);
     }
 
     if (!in_resize_locked) {
-      RecordRightClickConversionResultHistogram(
-          RightClickConversionResultHistogramResult::kNotConverted);
+      if (mouse_event.IsRightMouseButton()) {
+        RecordRightClickConversionResultHistogram(
+            RightClickConversionResultHistogramResult::kNotConverted);
+      }
       return SendEvent(continuation, &event);
     }
 
-    RecordRightClickConversionResultHistogram(
-        RightClickConversionResultHistogramResult::kConverted);
     return RewriteMouseClickEvent(mouse_event, continuation);
   }
 
@@ -207,6 +209,10 @@
         base::BindOnce(&TouchModeMouseRewriter::SendReleaseEvent,
                        weak_ptr_factory_.GetWeakPtr(), event, continuation),
         kLongPressInterval);
+
+    RecordRightClickConversionResultHistogram(
+        RightClickConversionResultHistogramResult::kConverted);
+
     // Send the press event now.
     ui::MouseEvent press_event(
         ui::ET_MOUSE_PRESSED, event.location(), event.root_location(),
diff --git a/ash/constants/ambient_animation_theme.cc b/ash/constants/ambient_animation_theme.cc
index 3d82a8c..7d89ef08 100644
--- a/ash/constants/ambient_animation_theme.cc
+++ b/ash/constants/ambient_animation_theme.cc
@@ -6,14 +6,17 @@
 
 namespace ash {
 
-std::ostream& operator<<(std::ostream& os, AmbientAnimationTheme theme) {
+base::StringPiece ToString(AmbientAnimationTheme theme) {
+  // See the "AmbientModeThemes" <variants> tag in histograms.xml. These names
+  // are currently used for metrics purposes, so they cannot be arbitrarily
+  // renamed.
   switch (theme) {
     case AmbientAnimationTheme::kSlideshow:
-      return os << "SLIDESHOW";
+      return "SlideShow";
     case AmbientAnimationTheme::kFeelTheBreeze:
-      return os << "FEEL_THE_BREZE";
+      return "FeelTheBreeze";
     case AmbientAnimationTheme::kFloatOnBy:
-      return os << "FLOAT_ON_BY";
+      return "FloatOnBy";
   }
 }
 
diff --git a/ash/constants/ambient_animation_theme.h b/ash/constants/ambient_animation_theme.h
index 4f854eb..029ee8eb 100644
--- a/ash/constants/ambient_animation_theme.h
+++ b/ash/constants/ambient_animation_theme.h
@@ -5,9 +5,8 @@
 #ifndef ASH_CONSTANTS_AMBIENT_ANIMATION_THEME_H_
 #define ASH_CONSTANTS_AMBIENT_ANIMATION_THEME_H_
 
-#include <ostream>
-
 #include "base/component_export.h"
+#include "base/strings/string_piece.h"
 
 namespace ash {
 
@@ -30,8 +29,10 @@
 inline constexpr AmbientAnimationTheme kDefaultAmbientAnimationTheme =
     AmbientAnimationTheme::kSlideshow;
 
+// The returned StringPiece is guaranteed to be null-terminated and point to
+// memory valid for the lifetime of the program.
 COMPONENT_EXPORT(ASH_CONSTANTS)
-std::ostream& operator<<(std::ostream& os, AmbientAnimationTheme theme);
+base::StringPiece ToString(AmbientAnimationTheme theme);
 
 }  // namespace ash
 
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 06b13d9f..8dc8542 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -995,6 +995,16 @@
 const base::Feature kMediaAppHandlesPdf{"MediaAppHandlesPdf",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Within the ChromeOS media app, reveals the button to edit the current image
+// in Photos.
+const base::Feature kMediaAppPhotosIntegrationImage{
+    "MediaAppPhotosIntegrationImage", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Within the ChromeOS media app, reveals the button to edit the current video
+// in Photos.
+const base::Feature kMediaAppPhotosIntegrationVideo{
+    "MediaAppPhotosIntegrationVideo", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Feature to continuously log PSI memory pressure data to UMA.
 const base::Feature kMemoryPressureMetricsDetail{
     "MemoryPressureMetricsDetail", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 9afa1cd..5c5d2933 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -397,6 +397,10 @@
 extern const base::Feature kManagedDeviceUIRedesign;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kMediaAppHandlesPdf;
 COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kMediaAppPhotosIntegrationImage;
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kMediaAppPhotosIntegrationVideo;
+COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kMemoryPressureMetricsDetail;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::FeatureParam<int> kMemoryPressureMetricsDetailLogPeriod;
diff --git a/ash/public/cpp/ambient/ambient_metrics.cc b/ash/public/cpp/ambient/ambient_metrics.cc
index 8864d378..cea8418 100644
--- a/ash/public/cpp/ambient/ambient_metrics.cc
+++ b/ash/public/cpp/ambient/ambient_metrics.cc
@@ -9,6 +9,7 @@
 #include "ash/public/cpp/ambient/ambient_ui_model.h"
 #include "ash/public/cpp/ambient/common/ambient_settings.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/strings/strcat.h"
 #include "base/time/time.h"
 
 namespace ash {
@@ -16,7 +17,12 @@
 
 namespace {
 
-// 144 == 24 * 60 / 10. Each histogram bucket therefore represents 10 minutes.
+// Histograms default to exponential bucketing, so the smallest bucket occupies
+// 24 hours / (2 ^ (144 - 1)) milliseconds. Exponential bucketing is desirable
+// for engagement time because most users exit screensaver on the order of
+// several minutes, while a small fraction of users exit screensaver after
+// many hours. So the histogram's highest resolution should occupy the smaller
+// engagement times.
 constexpr int kAmbientModeElapsedTimeHistogramBuckets = 144;
 
 std::string GetHistogramName(const char* prefix, bool tablet_mode) {
@@ -60,13 +66,26 @@
 }
 
 void RecordAmbientModeTimeElapsed(base::TimeDelta time_delta,
-                                  bool tablet_mode) {
+                                  bool tablet_mode,
+                                  AmbientAnimationTheme theme) {
   base::UmaHistogramCustomTimes(
       /*name=*/GetHistogramName("Ash.AmbientMode.EngagementTime", tablet_mode),
       /*sample=*/time_delta,
       /*min=*/base::Hours(0),
       /*max=*/base::Hours(24),
       /*buckets=*/kAmbientModeElapsedTimeHistogramBuckets);
+
+  base::UmaHistogramCustomTimes(
+      /*name=*/base::StrCat(
+          {"Ash.AmbientMode.EngagementTime.", ToString(theme)}),
+      /*sample=*/time_delta,
+      // There is no value in bucketing engagement times that are on the order
+      // of milliseconds. A 1 second minimum is imposed here but not in the
+      // metric above for legacy reasons (the metric above was already pushed
+      // to the field and established before this change was made).
+      /*min=*/base::Seconds(1),
+      /*max=*/base::Hours(24),
+      /*buckets=*/kAmbientModeElapsedTimeHistogramBuckets);
 }
 
 void RecordAmbientModeTotalNumberOfAlbums(int num_albums) {
diff --git a/ash/public/cpp/ambient/ambient_metrics.h b/ash/public/cpp/ambient/ambient_metrics.h
index f9624e7..d8000e39 100644
--- a/ash/public/cpp/ambient/ambient_metrics.h
+++ b/ash/public/cpp/ambient/ambient_metrics.h
@@ -5,6 +5,7 @@
 #ifndef ASH_PUBLIC_CPP_AMBIENT_AMBIENT_METRICS_H_
 #define ASH_PUBLIC_CPP_AMBIENT_AMBIENT_METRICS_H_
 
+#include "ash/constants/ambient_animation_theme.h"
 #include "ash/public/cpp/ash_public_export.h"
 #include "base/time/time.h"
 
@@ -33,8 +34,10 @@
 ASH_PUBLIC_EXPORT void RecordAmbientModeActivation(AmbientUiMode ui_mode,
                                                    bool tablet_mode);
 
-ASH_PUBLIC_EXPORT void RecordAmbientModeTimeElapsed(base::TimeDelta time_delta,
-                                                    bool tablet_mode);
+ASH_PUBLIC_EXPORT void RecordAmbientModeTimeElapsed(
+    base::TimeDelta time_delta,
+    bool tablet_mode,
+    AmbientAnimationTheme theme);
 
 ASH_PUBLIC_EXPORT void RecordAmbientModeTotalNumberOfAlbums(int num_albums);
 
diff --git a/ash/system/message_center/ash_notification_view.cc b/ash/system/message_center/ash_notification_view.cc
index cb78030..6a94067b 100644
--- a/ash/system/message_center/ash_notification_view.cc
+++ b/ash/system/message_center/ash_notification_view.cc
@@ -1006,17 +1006,15 @@
 void AshNotificationView::CreateOrUpdateInlineSettingsViews(
     const message_center::Notification& notification) {
   if (inline_settings_enabled()) {
-    // TODO(crbug/1265636): Fix this logic when grouped parent notification has
-    // inline settings.
-    DCHECK(is_grouped_parent_view_ ||
-           (message_center::SettingsButtonHandler::INLINE ==
-            notification.rich_notification_data().settings_button_handler));
+    DCHECK(message_center::SettingsButtonHandler::INLINE ==
+           notification.rich_notification_data().settings_button_handler);
     return;
   }
 
   set_inline_settings_enabled(
+      !is_grouped_child_view_ &&
       notification.rich_notification_data().settings_button_handler ==
-      message_center::SettingsButtonHandler::INLINE);
+          message_center::SettingsButtonHandler::INLINE);
 
   if (!inline_settings_enabled()) {
     return;
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service.cc b/ash/webui/shimless_rma/backend/shimless_rma_service.cc
index 9346617..0680de1 100644
--- a/ash/webui/shimless_rma/backend/shimless_rma_service.cc
+++ b/ash/webui/shimless_rma/backend/shimless_rma_service.cc
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/public/cpp/network_config_service.h"
 #include "ash/webui/shimless_rma/backend/shimless_rma_delegate.h"
 #include "ash/webui/shimless_rma/backend/version_updater.h"
@@ -17,6 +18,7 @@
 #include "base/bind.h"
 #include "base/check_op.h"
 #include "base/containers/contains.h"
+#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "chromeos/ash/components/dbus/rmad/rmad.pb.h"
@@ -103,12 +105,14 @@
   network_config::BindToInProcessInstance(
       remote_cros_network_config_.BindNewPipeAndPassReceiver());
 
-  version_updater_.SetOsUpdateStatusCallback(
-      base::BindRepeating(&ShimlessRmaService::OnOsUpdateStatusCallback,
-                          weak_ptr_factory_.GetWeakPtr()));
-  // Check if an OS update is available to minimize delays if needed later.
-  if (HaveAllowedNetworkConnection()) {
-    version_updater_.CheckOsUpdateAvailable();
+  if (base::FeatureList::IsEnabled(chromeos::features::kShimlessRMAOsUpdate)) {
+    version_updater_.SetOsUpdateStatusCallback(
+        base::BindRepeating(&ShimlessRmaService::OnOsUpdateStatusCallback,
+                            weak_ptr_factory_.GetWeakPtr()));
+    // Check if an OS update is available to minimize delays if needed later.
+    if (HaveAllowedNetworkConnection()) {
+      version_updater_.CheckOsUpdateAvailable();
+    }
   }
 }
 
@@ -193,10 +197,15 @@
                             /*can_cancel=*/true, /*can_go_back=*/true,
                             rmad::RmadErrorCode::RMAD_ERROR_OK);
   } else {
-    check_os_callback_ =
-        base::BindOnce(&ShimlessRmaService::OsUpdateOrNextRmadStateCallback,
-                       weak_ptr_factory_.GetWeakPtr(), std::move(callback));
-    version_updater_.CheckOsUpdateAvailable();
+    if (base::FeatureList::IsEnabled(
+            chromeos::features::kShimlessRMAOsUpdate)) {
+      check_os_callback_ =
+          base::BindOnce(&ShimlessRmaService::OsUpdateOrNextRmadStateCallback,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback));
+      version_updater_.CheckOsUpdateAvailable();
+    } else {
+      TransitionNextStateGeneric(std::move(callback));
+    }
   }
 }
 
@@ -302,7 +311,8 @@
                             rmad::RmadErrorCode::RMAD_ERROR_REQUEST_INVALID);
     return;
   }
-  if (HaveAllowedNetworkConnection()) {
+  if (HaveAllowedNetworkConnection() &&
+      base::FeatureList::IsEnabled(chromeos::features::kShimlessRMAOsUpdate)) {
     check_os_callback_ =
         base::BindOnce(&ShimlessRmaService::OsUpdateOrNextRmadStateCallback,
                        weak_ptr_factory_.GetWeakPtr(), std::move(callback));
@@ -314,12 +324,16 @@
 
 void ShimlessRmaService::GetCurrentOsVersion(
     GetCurrentOsVersionCallback callback) {
+  DCHECK(
+      base::FeatureList::IsEnabled(chromeos::features::kShimlessRMAOsUpdate));
   // TODO(gavindodd): Decide whether to use full or short Chrome version.
   std::move(callback).Run(chromeos::version_loader::GetVersion(
       chromeos::version_loader::VERSION_FULL));
 }
 
 void ShimlessRmaService::CheckForOsUpdates(CheckForOsUpdatesCallback callback) {
+  DCHECK(
+      base::FeatureList::IsEnabled(chromeos::features::kShimlessRMAOsUpdate));
   if (state_proto_.state_case() != rmad::RmadState::kWelcome ||
       mojo_state_ != mojom::State::kUpdateOs) {
     LOG(ERROR) << "CheckForOsUpdates called from incorrect state "
@@ -338,6 +352,8 @@
 }
 
 void ShimlessRmaService::UpdateOs(UpdateOsCallback callback) {
+  DCHECK(
+      base::FeatureList::IsEnabled(chromeos::features::kShimlessRMAOsUpdate));
   if (state_proto_.state_case() != rmad::RmadState::kWelcome ||
       mojo_state_ != mojom::State::kUpdateOs) {
     LOG(ERROR) << "UpdateOs called from incorrect state "
@@ -349,6 +365,8 @@
 }
 
 void ShimlessRmaService::UpdateOsSkipped(UpdateOsSkippedCallback callback) {
+  DCHECK(
+      base::FeatureList::IsEnabled(chromeos::features::kShimlessRMAOsUpdate));
   if (state_proto_.state_case() != rmad::RmadState::kWelcome ||
       mojo_state_ != mojom::State::kUpdateOs) {
     LOG(ERROR) << "UpdateOsSkipped called from incorrect state "
@@ -1076,6 +1094,8 @@
 void ShimlessRmaService::OsUpdateProgress(update_engine::Operation operation,
                                           double progress,
                                           update_engine::ErrorCode error_code) {
+  DCHECK(
+      base::FeatureList::IsEnabled(chromeos::features::kShimlessRMAOsUpdate));
   if (os_update_observer_.is_bound()) {
     os_update_observer_->OnOsUpdateProgressUpdated(operation, progress,
                                                    error_code);
@@ -1154,6 +1174,8 @@
 
 void ShimlessRmaService::ObserveOsUpdateProgress(
     ::mojo::PendingRemote<mojom::OsUpdateObserver> observer) {
+  DCHECK(
+      base::FeatureList::IsEnabled(chromeos::features::kShimlessRMAOsUpdate));
   os_update_observer_.Bind(std::move(observer));
 }
 
@@ -1353,6 +1375,8 @@
     const std::string& version,
     int64_t update_size,
     update_engine::ErrorCode error_code) {
+  DCHECK(
+      base::FeatureList::IsEnabled(chromeos::features::kShimlessRMAOsUpdate));
   if (check_os_callback_) {
     switch (operation) {
       // If IDLE is received when there is a callback it means no update is
diff --git a/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc b/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc
index 0ee56839..e3af915 100644
--- a/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc
+++ b/ash/webui/shimless_rma/backend/shimless_rma_service_unittest.cc
@@ -10,12 +10,14 @@
 #include <utility>
 #include <vector>
 
+#include "ash/constants/ash_features.h"
 #include "ash/webui/shimless_rma/backend/shimless_rma_delegate.h"
 #include "ash/webui/shimless_rma/mojom/shimless_rma.mojom.h"
 #include "base/callback_helpers.h"
 #include "base/files/file_path.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "chromeos/ash/components/dbus/rmad/fake_rmad_client.h"
 #include "chromeos/ash/components/dbus/rmad/rmad_client.h"
@@ -116,6 +118,8 @@
   ~ShimlessRmaServiceTest() override {}
 
   void SetUp() override {
+    scoped_feature_list_.InitWithFeatures(
+        {chromeos::features::kShimlessRMAOsUpdate}, {});
     chromeos::DBusThreadManager::Initialize();
 
     SetupFakeNetwork();
@@ -274,6 +278,8 @@
         /*visible_only=*/true, /*no_limit=*/0, list);
   }
 
+  void ResetFeatures() { scoped_feature_list_.Reset(); }
+
  protected:
   network_config::CrosNetworkConfigTestHelper&
   cros_network_config_test_helper() {
@@ -299,6 +305,7 @@
       managed_network_configuration_handler_;
   std::unique_ptr<NetworkConfigurationHandler> network_configuration_handler_;
   base::test::TaskEnvironment task_environment_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_F(ShimlessRmaServiceTest, AbortAndGoBackStatePassedCorrectly) {
@@ -366,7 +373,8 @@
       }));
   run_loop.RunUntilIdle();
 
-  // With a WiFi network it should redirect to kUpdateOs
+  // With a WiFi network it should redirect to kUpdateOs if the update flag is
+  // on.
   shimless_rma_provider_->BeginFinalization(base::BindLambdaForTesting(
       [&](mojom::State state, bool can_exit, bool can_go_back,
           rmad::RmadErrorCode error) {
@@ -377,6 +385,39 @@
   run_loop.Run();
 }
 
+TEST_F(ShimlessRmaServiceTest, WelcomePageSkipsOsUpdateIfFlagIsOff) {
+  ResetFeatures();
+
+  SetupWiFiNetwork(kDefaultWifiGuid);
+  const std::vector<rmad::GetStateReply> fake_states = {
+      CreateStateReply(rmad::RmadState::kWelcome, rmad::RMAD_ERROR_OK),
+      CreateStateReply(rmad::RmadState::kComponentsRepair,
+                       rmad::RMAD_ERROR_OK)};
+  fake_rmad_client_()->SetFakeStateReplies(std::move(fake_states));
+
+  base::RunLoop run_loop;
+
+  // Initialize current state
+  shimless_rma_provider_->GetCurrentState(base::BindLambdaForTesting(
+      [&](mojom::State state, bool can_exit, bool can_go_back,
+          rmad::RmadErrorCode error) {
+        EXPECT_EQ(state, mojom::State::kWelcomeScreen);
+        EXPECT_EQ(error, rmad::RmadErrorCode::RMAD_ERROR_OK);
+      }));
+  run_loop.RunUntilIdle();
+
+  // With a WiFi network it should redirect to kComponentsRepair if the Os
+  // Update flag is off.
+  shimless_rma_provider_->BeginFinalization(base::BindLambdaForTesting(
+      [&](mojom::State state, bool can_exit, bool can_go_back,
+          rmad::RmadErrorCode error) {
+        EXPECT_EQ(state, mojom::State::kSelectComponents);
+        EXPECT_EQ(error, rmad::RmadErrorCode::RMAD_ERROR_OK);
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+}
+
 TEST_F(ShimlessRmaServiceTest, WelcomeHasNoNetworkConnection) {
   const std::vector<rmad::GetStateReply> fake_states = {
       CreateStateReply(rmad::RmadState::kWelcome, rmad::RMAD_ERROR_OK),
@@ -448,6 +489,48 @@
   run_loop.Run();
 }
 
+TEST_F(ShimlessRmaServiceTest, ChooseNetworkPageSkipsOsUpdateIfFlagIsOff) {
+  ResetFeatures();
+
+  const std::vector<rmad::GetStateReply> fake_states = {
+      CreateStateReply(rmad::RmadState::kWelcome, rmad::RMAD_ERROR_OK),
+      CreateStateReply(rmad::RmadState::kComponentsRepair,
+                       rmad::RMAD_ERROR_OK)};
+  fake_rmad_client_()->SetFakeStateReplies(std::move(fake_states));
+
+  base::RunLoop run_loop;
+
+  // Initialize current state
+  shimless_rma_provider_->GetCurrentState(base::BindLambdaForTesting(
+      [&](mojom::State state, bool can_exit, bool can_go_back,
+          rmad::RmadErrorCode error) {
+        EXPECT_EQ(state, mojom::State::kWelcomeScreen);
+        EXPECT_EQ(error, rmad::RmadErrorCode::RMAD_ERROR_OK);
+      }));
+  run_loop.RunUntilIdle();
+
+  // No network should prompt select network page
+  shimless_rma_provider_->BeginFinalization(base::BindLambdaForTesting(
+      [&](mojom::State state, bool can_exit, bool can_go_back,
+          rmad::RmadErrorCode error) {
+        EXPECT_EQ(state, mojom::State::kConfigureNetwork);
+        EXPECT_EQ(error, rmad::RmadErrorCode::RMAD_ERROR_OK);
+      }));
+  run_loop.RunUntilIdle();
+  SetupWiFiNetwork(kDefaultWifiGuid);
+
+  // With a WiFi network it should redirect to kSelectComponents because the OS
+  // Update flag is off.
+  shimless_rma_provider_->NetworkSelectionComplete(base::BindLambdaForTesting(
+      [&](mojom::State state, bool can_exit, bool can_go_back,
+          rmad::RmadErrorCode error) {
+        EXPECT_EQ(state, mojom::State::kSelectComponents);
+        EXPECT_EQ(error, rmad::RmadErrorCode::RMAD_ERROR_OK);
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+}
+
 TEST_F(ShimlessRmaServiceTest, ChooseNetworkHasNoNetworkConnection) {
   const std::vector<rmad::GetStateReply> fake_states = {
       CreateStateReply(rmad::RmadState::kWelcome, rmad::RMAD_ERROR_OK),
diff --git a/ash/webui/shimless_rma/resources/onboarding_landing_page.html b/ash/webui/shimless_rma/resources/onboarding_landing_page.html
index 67609d6..e9c592a 100644
--- a/ash/webui/shimless_rma/resources/onboarding_landing_page.html
+++ b/ash/webui/shimless_rma/resources/onboarding_landing_page.html
@@ -69,7 +69,7 @@
           [[i18n('exitButtonLabel')]]
         </span>
         <paper-spinner-lite class="button-spinner"
-            hidden$="[[!landingExitButtonClicked]]" active>
+            hidden$="[[!confirmExitButtonClicked]]" active>
         </paper-spinner-lite>
       </cr-button>
     </div>
diff --git a/ash/webui/shimless_rma/resources/onboarding_landing_page.js b/ash/webui/shimless_rma/resources/onboarding_landing_page.js
index cd9d448..a141b882 100644
--- a/ash/webui/shimless_rma/resources/onboarding_landing_page.js
+++ b/ash/webui/shimless_rma/resources/onboarding_landing_page.js
@@ -84,7 +84,7 @@
        * After the exit button is clicked, true until the next state is
        * processed. It is set back to false by shimless_rma.js.
        */
-      landingExitButtonClicked: {
+      confirmExitButtonClicked: {
         type: Boolean,
         value: false,
       },
@@ -149,8 +149,6 @@
   onLandingExitButtonClicked_(e) {
     e.preventDefault();
 
-    this.landingExitButtonClicked = true;
-
     this.dispatchEvent(new CustomEvent(
         'click-exit-button',
         {
diff --git a/ash/webui/shimless_rma/resources/onboarding_update_page.js b/ash/webui/shimless_rma/resources/onboarding_update_page.js
index f17cdb2..8ad74e7 100644
--- a/ash/webui/shimless_rma/resources/onboarding_update_page.js
+++ b/ash/webui/shimless_rma/resources/onboarding_update_page.js
@@ -12,6 +12,7 @@
 
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getShimlessRmaService} from './mojo_interface_provider.js';
@@ -104,6 +105,10 @@
 
   constructor() {
     super();
+    if (!loadTimeData.getBoolean('osUpdateEnabled')) {
+      return;
+    }
+
     /** @private {ShimlessRmaServiceInterface} */
     this.shimlessRmaService_ = getShimlessRmaService();
     /** @protected {string} */
@@ -135,6 +140,9 @@
   /** @override */
   ready() {
     super.ready();
+    if (!loadTimeData.getBoolean('osUpdateEnabled')) {
+      return;
+    }
     this.getCurrentVersionText_();
     this.getUpdateVersionNumber_();
     enableNextButton(this);
@@ -144,6 +152,9 @@
    * @private
    */
   getCurrentVersionText_() {
+    if (!loadTimeData.getBoolean('osUpdateEnabled')) {
+      return;
+    }
     this.shimlessRmaService_.getCurrentOsVersion().then((res) => {
       this.currentVersion_ = res.version;
       this.currentVersionText_ =
@@ -153,6 +164,9 @@
 
   /** @private */
   getUpdateVersionNumber_() {
+    if (!loadTimeData.getBoolean('osUpdateEnabled')) {
+      return;
+    }
     this.shimlessRmaService_.checkForOsUpdates().then((res) => {
       assert(res.updateAvailable);
       this.updateVersionButtonLabel_ =
@@ -162,6 +176,9 @@
 
   /** @protected */
   onUpdateButtonClicked_() {
+    if (!loadTimeData.getBoolean('osUpdateEnabled')) {
+      return;
+    }
     this.updateInProgress_ = true;
     this.shimlessRmaService_.updateOs().then((res) => {
       if (!res.updateStarted) {
@@ -181,6 +198,9 @@
    * @param {number} progress
    */
   onOsUpdateProgressUpdated(operation, progress) {
+    if (!loadTimeData.getBoolean('osUpdateEnabled')) {
+      return;
+    }
     // Ignore progress when not updating, it is just the update available check.
     if (!this.updateInProgress_) {
       return;
@@ -201,6 +221,9 @@
    * @param {string} errorMessage
    */
   onHardwareVerificationResult(isCompliant, errorMessage) {
+    if (!loadTimeData.getBoolean('osUpdateEnabled')) {
+      return;
+    }
     this.isCompliant_ = isCompliant;
 
     if (!this.isCompliant_) {
@@ -211,6 +234,9 @@
 
   /** @private */
   setVerificationFailedMessage_() {
+    if (!loadTimeData.getBoolean('osUpdateEnabled')) {
+      return;
+    }
     this.verificationFailedMessage_ = this.i18nAdvanced(
         'osUpdateUnqualifiedComponentsTopText', {attrs: ['id']});
 
@@ -228,11 +254,17 @@
 
   /** @private */
   closeDialog_() {
+    if (!loadTimeData.getBoolean('osUpdateEnabled')) {
+      return;
+    }
     this.shadowRoot.querySelector('#unqualifiedComponentsDialog').close();
   }
 
   /** @private */
   onUpdateInProgressChange_() {
+    if (!loadTimeData.getBoolean('osUpdateEnabled')) {
+      return;
+    }
     if (this.updateInProgress_) {
       disableAllButtons(this, /*showBusyStateOverlay=*/ false);
     } else {
diff --git a/ash/webui/shimless_rma/resources/shimless_rma.html b/ash/webui/shimless_rma/resources/shimless_rma.html
index 553ae9d2..f975cb9 100644
--- a/ash/webui/shimless_rma/resources/shimless_rma.html
+++ b/ash/webui/shimless_rma/resources/shimless_rma.html
@@ -116,7 +116,7 @@
         [[getExitButtonLabel_(currentPage_.buttonExitLabelKey)]]
       </span>
       <paper-spinner-lite id="exitButtonSpinner" class="busy-icon"
-          hidden$="[[!exitButtonClicked_]]" active>
+          hidden$="[[!confirmExitButtonClicked_]]" active>
       </paper-spinner-lite>
     </cr-button>
     <cr-button
@@ -135,3 +135,21 @@
     </cr-button>
   </div>
 </div>
+<cr-dialog id="exitDialog">
+  <div slot="title">
+    [[i18n('exitDialogTitleText')]]
+  </div>
+  <div slot="body">
+    [[i18n('exitDialogDescriptionText')]]
+  </div>
+  <div class="dialog-footer" slot="button-container">
+    <cr-button id="cancelExitDialogButton" class="pill"
+        on-click="closeDialog_">
+      [[i18n('exitDialogCancelButtonLabel')]]
+    </cr-button>
+    <cr-button id="confirmExitDialogButton" class="action-button"
+        on-click="onConfirmExitButtonClicked_">
+      [[i18n('exitDialogConfirmButtonLabel')]]
+    </cr-button>
+  </div>
+</cr-dialog>
diff --git a/ash/webui/shimless_rma/resources/shimless_rma.js b/ash/webui/shimless_rma/resources/shimless_rma.js
index 7aff117a..542d765 100644
--- a/ash/webui/shimless_rma/resources/shimless_rma.js
+++ b/ash/webui/shimless_rma/resources/shimless_rma.js
@@ -314,7 +314,7 @@
        * processed.
        * @protected
        */
-      exitButtonClicked_: {
+      confirmExitButtonClicked_: {
         type: Boolean,
         value: false,
       },
@@ -531,7 +531,7 @@
     // Reset clicked variables to hide the spinners.
     this.nextButtonClicked_ = false;
     this.backButtonClicked_ = false;
-    this.exitButtonClicked_ = false;
+    this.confirmExitButtonClicked_ = false;
 
     const nextStatePageInfo = StateComponentMapping[stateResult.state];
     assert(nextStatePageInfo);
@@ -564,7 +564,7 @@
       // A special case for the landing page, which has its own navigation
       // buttons.
       currentPageComponent.getStartedButtonClicked = false;
-      currentPageComponent.landingExitButtonClicked = false;
+      currentPageComponent.confirmExitButtonClicked = false;
     }
 
     this.setAllButtonsState_(
@@ -694,10 +694,9 @@
 
   /** @protected */
   onExitButtonClicked_() {
-    this.exitButtonClicked_ = true;
-    this.setAllButtonsState_(
-        /* shouldDisableButtons= */ true, /* showBusyStateOverlay= */ true);
     const page = this.shadowRoot.querySelector(this.currentPage_.componentIs);
+
+    // Don't show the exit dialog if it's on calibration failed page.
     if (page.onExitButtonClick) {
       // A special case for the calibration failed page, where the skip button
       // replaces the exit button.
@@ -707,19 +706,40 @@
             this.processStateResult_(stateResult);
           })
           .catch((err) => {
-            this.exitButtonClicked_ = false;
+            this.confirmExitButtonClicked_ = false;
             this.setAllButtonsState_(
                 /* shouldDisableButtons= */ false,
                 /* showBusyStateOverlay= */ false);
           });
     } else {
-      this.shimlessRmaService_.abortRma().then((result) => {
-        this.exitButtonClicked_ = false;
-        this.handleStandardAndCriticalError_(result.error);
-      });
+      this.shadowRoot.querySelector('#exitDialog').showModal();
     }
   }
 
+  /** @protected */
+  onConfirmExitButtonClicked_() {
+    this.confirmExitButtonClicked_ = true;
+    this.shadowRoot.querySelector('#exitDialog').close();
+
+    // Show exit button spinner on the landing page
+    const currentPageComponent =
+        this.shadowRoot.querySelector(this.currentPage_.componentIs);
+    currentPageComponent.confirmExitButtonClicked = true;
+
+    this.setAllButtonsState_(
+        /* shouldDisableButtons= */ true, /* showBusyStateOverlay= */ true);
+
+    this.shimlessRmaService_.abortRma().then((result) => {
+      this.confirmExitButtonClicked_ = false;
+      this.handleStandardAndCriticalError_(result.error);
+    });
+  }
+
+  /** @protected */
+  closeDialog_() {
+    this.shadowRoot.querySelector('#exitDialog').close();
+  }
+
   /**
    * @return {string}
    * @private
diff --git a/ash/webui/shimless_rma/shimless_rma.cc b/ash/webui/shimless_rma/shimless_rma.cc
index 8c1183e6..5a9b107d 100644
--- a/ash/webui/shimless_rma/shimless_rma.cc
+++ b/ash/webui/shimless_rma/shimless_rma.cc
@@ -80,6 +80,13 @@
       {"cancelButtonLabel", IDS_SHIMLESS_RMA_CANCEL_BUTTON},
       {"retryButtonLabel", IDS_SHIMLESS_RMA_RETRY_BUTTON},
       {"tryAgainButtonLabel", IDS_SHIMLESS_RMA_TRY_AGAIN_BUTTON},
+      // Exit dialog
+      {"exitDialogTitleText", IDS_SHIMLESS_RMA_EXIT_DIALOG_TITLE},
+      {"exitDialogDescriptionText", IDS_SHIMLESS_RMA_EXIT_DIALOG_DESCRIPTION},
+      {"exitDialogCancelButtonLabel",
+       IDS_SHIMLESS_RMA_EXIT_DIALOG_CANCEL_BUTTON_LABEL},
+      {"exitDialogConfirmButtonLabel",
+       IDS_SHIMLESS_RMA_EXIT_DIALOG_CONFIRM_BUTTON_LABEL},
       // Landing page
       {"beginRmaWarningText", IDS_SHIMLESS_RMA_AUTHORIZED_TECH_ONLY_WARNING},
       {"validatingComponentsText", IDS_SHIMLESS_RMA_VALIDATING_COMPONENTS},
@@ -337,6 +344,12 @@
       ui::SubstituteChromeOSDeviceType(IDS_SHIMLESS_RMA_CRITICAL_ERROR_TITLE));
 }
 
+void AddFeatureFlags(content::WebUIDataSource* html_source) {
+  html_source->AddBoolean(
+      "osUpdateEnabled",
+      base::FeatureList::IsEnabled(chromeos::features::kShimlessRMAOsUpdate));
+}
+
 }  // namespace
 
 namespace shimless_rma {
@@ -390,6 +403,7 @@
 
   AddShimlessRmaStrings(html_source);
   AddDevicePlaceholderStrings(html_source);
+  AddFeatureFlags(html_source);
 
   ui::network_element::AddLocalizedStrings(html_source);
   ui::network_element::AddOncLocalizedStrings(html_source);
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 98fb33a..5fbe3cfc 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1430,8 +1430,6 @@
     "//base/third_party/double_conversion",
     "//base/third_party/dynamic_annotations",
     "//build:branding_buildflags",
-    "//build:chromecast_buildflags",
-    "//build:chromeos_buildflags",
     "//build/config/compiler:compiler_buildflags",
     "//third_party/modp_b64",
   ]
@@ -1487,7 +1485,10 @@
     ":sanitizer_buildflags",
     ":synchronization_buildflags",
     ":tracing_buildflags",
+    "//base/allocator/partition_allocator:buildflags",
     "//base/numerics:base_numerics",
+    "//build:chromecast_buildflags",
+    "//build:chromeos_buildflags",
     "//third_party/abseil-cpp:absl",
   ]
 
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
index 1f4b506..4f423cf 100644
--- a/base/allocator/BUILD.gn
+++ b/base/allocator/BUILD.gn
@@ -13,10 +13,6 @@
   assert(use_allocator_shim || !_use_partition_alloc_as_malloc,
          "Partition alloc requires the allocator shim")
 
-  # Duplicates the setup Chromium uses to define `DCHECK_IS_ON()`,
-  # but avails it as a buildflag.
-  _dcheck_is_on = is_debug || dcheck_always_on
-
   # BackupRefPtr(BRP) build flags.
   _use_backup_ref_ptr = use_backup_ref_ptr && use_partition_alloc && !is_nacl
   _put_ref_count_in_previous_slot =
@@ -30,8 +26,6 @@
   # MTECheckedPtr requires 64-bit pointers (not available in NaCl).
   _use_mte_checked_ptr = use_mte_checked_ptr && !is_nacl
 
-  _record_alloc_info = false
-
   flags = [
     "USE_ALLOCATOR_SHIM=$use_allocator_shim",
     "USE_PARTITION_ALLOC=$use_partition_alloc",
@@ -43,14 +37,10 @@
     "ENABLE_DANGLING_RAW_PTR_CHECKS=$_enable_dangling_raw_ptr_checks",
     "PUT_REF_COUNT_IN_PREVIOUS_SLOT=$_put_ref_count_in_previous_slot",
 
-    "PA_DCHECK_IS_ON=$_dcheck_is_on",
-
     # Not to be used directly - see `partition_alloc_config.h`.
     "USE_MTE_CHECKED_PTR=$_use_mte_checked_ptr",
 
     "USE_FAKE_BINARY_EXPERIMENT=$use_fake_binary_experiment",
-
-    "RECORD_ALLOC_INFO=$_record_alloc_info",
   ]
 }
 
@@ -61,7 +51,10 @@
       "early_zone_registration_mac.h",
     ]
 
-    deps = [ ":buildflags" ]
+    deps = [
+      ":buildflags",
+      "//base/allocator/partition_allocator:buildflags",
+    ]
   }
 }
 
diff --git a/base/allocator/partition_allocator/BUILD.gn b/base/allocator/partition_allocator/BUILD.gn
index af5679f..9d56e5cf 100644
--- a/base/allocator/partition_allocator/BUILD.gn
+++ b/base/allocator/partition_allocator/BUILD.gn
@@ -4,6 +4,11 @@
 
 import("//base/allocator/allocator.gni")
 import("//base/allocator/partition_allocator/partition_alloc.gni")
+import("//build/buildflag_header.gni")
+import("//build/config/chromecast_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
+import("//build/config/dcheck_always_on.gni")
+import("//build/config/logging.gni")
 
 # Add partition_alloc.gni and import it for partition_alloc configs.
 
@@ -265,14 +270,14 @@
     # To support a trampoline for another arch, please refer to v8/src/heap/base.
   }
   public_deps = [
-    "//base:debugging_buildflags",
-    "//base:logging_buildflags",
+    ":chromecast_buildflags",
+    ":chromeos_buildflags",
+    ":debugging_buildflags",
+    ":logging_buildflags",
+    ":partition_alloc_buildflags",
     "//base:synchronization_buildflags",
     "//base:tracing_buildflags",
-    "//base/allocator:buildflags",
     "//build:branding_buildflags",
-    "//build:chromecast_buildflags",
-    "//build:chromeos_buildflags",
     "//build/config/compiler:compiler_buildflags",
   ]
 
@@ -353,14 +358,14 @@
     ]
   }
   public_deps = [
-    "//base:debugging_buildflags",
-    "//base:logging_buildflags",
+    ":chromecast_buildflags",
+    ":chromeos_buildflags",
+    ":debugging_buildflags",
+    ":logging_buildflags",
+    ":partition_alloc_buildflags",
     "//base:synchronization_buildflags",
     "//base:tracing_buildflags",
-    "//base/allocator:buildflags",
     "//build:branding_buildflags",
-    "//build:chromecast_buildflags",
-    "//build:chromeos_buildflags",
     "//build/config/compiler:compiler_buildflags",
   ]
   public_configs = []
@@ -384,15 +389,91 @@
   }
 }
 
+buildflag_header("partition_alloc_buildflags") {
+  header = "partition_alloc_buildflags.h"
+
+  _use_partition_alloc_as_malloc = use_allocator == "partition"
+  assert(use_allocator_shim || !_use_partition_alloc_as_malloc,
+         "Partition alloc requires the allocator shim")
+
+  # BackupRefPtr(BRP) build flags.
+  _use_backup_ref_ptr = use_backup_ref_ptr && use_partition_alloc && !is_nacl
+  _put_ref_count_in_previous_slot =
+      put_ref_count_in_previous_slot && _use_backup_ref_ptr
+  _enable_backup_ref_ptr_slow_checks =
+      enable_backup_ref_ptr_slow_checks && _use_backup_ref_ptr
+  _enable_dangling_raw_ptr_checks =
+      enable_dangling_raw_ptr_checks && _use_backup_ref_ptr
+
+  # MTECheckedPtr is exclusive against BRP (asserted at declaration).
+  # MTECheckedPtr requires 64-bit pointers (not available in NaCl).
+  _use_mte_checked_ptr = use_mte_checked_ptr && !is_nacl
+
+  _record_alloc_info = false
+
+  # TODO(crbug.com/1151236): Need to refactor the following buildflags.
+  # The buildflags (expect RECORD_ALLOC_INFO) are used by both chrome and
+  # partition alloc. For partition alloc,
+  # gen/base/allocator/partition_allocator/partition_alloc_buildflags.h
+  # defines and partition alloc includes the header file. For chrome,
+  # gen/base/allocator/buildflags.h defines and chrome includes.
+  flags = [
+    "USE_PARTITION_ALLOC_AS_MALLOC=$_use_partition_alloc_as_malloc",
+
+    "USE_BACKUP_REF_PTR=$_use_backup_ref_ptr",
+    "ENABLE_BACKUP_REF_PTR_SLOW_CHECKS=$_enable_backup_ref_ptr_slow_checks",
+    "ENABLE_DANGLING_RAW_PTR_CHECKS=$_enable_dangling_raw_ptr_checks",
+    "PUT_REF_COUNT_IN_PREVIOUS_SLOT=$_put_ref_count_in_previous_slot",
+
+    "USE_MTE_CHECKED_PTR=$_use_mte_checked_ptr",
+
+    "RECORD_ALLOC_INFO=$_record_alloc_info",
+  ]
+}
+
+buildflag_header("chromecast_buildflags") {
+  header = "chromecast_buildflags.h"
+
+  flags = [ "PA_IS_CASTOS=$is_castos" ]
+}
+
+buildflag_header("chromeos_buildflags") {
+  header = "chromeos_buildflags.h"
+
+  flags = [ "PA_IS_CHROMEOS_ASH=$is_chromeos_ash" ]
+}
+
+buildflag_header("logging_buildflags") {
+  header = "logging_buildflags.h"
+
+  flags = [ "PA_ENABLE_LOG_ERROR_NOT_REACHED=$enable_log_error_not_reached" ]
+}
+
+buildflag_header("debugging_buildflags") {
+  header = "debugging_buildflags.h"
+  header_dir = rebase_path(".", "//") + "/partition_alloc_base/debug"
+
+  # Duplicates the setup Chromium uses to define `DCHECK_IS_ON()`,
+  # but avails it as a buildflag.
+  _dcheck_is_on = is_debug || dcheck_always_on
+
+  flags = [
+    "PA_DCHECK_IS_ON=$_dcheck_is_on",
+    "PA_EXPENSIVE_DCHECKS_ARE_ON=$enable_expensive_dchecks",
+  ]
+}
+
+group("buildflags") {
+  public_deps = [
+    ":chromecast_buildflags",
+    ":chromeos_buildflags",
+    ":debugging_buildflags",
+    ":logging_buildflags",
+    ":partition_alloc_buildflags",
+  ]
+}
+
 # TODO(crbug.com/1151236): After making partition_alloc a standalone library,
 # move test code here. i.e. test("partition_alloc_tests") { ... } and
 # test("partition_alloc_perftests").
 
-# TODO(crbug.com/1151236): Generate partition_alloc_buildflags. The following
-# flags will be defined by the buildflags:
-#    "USE_BACKUP_REF_PTR=$_use_backup_ref_ptr",
-#    "ENABLE_BACKUP_REF_PTR_SLOW_CHECKS=$_enable_backup_ref_ptr_slow_checks",
-#    "ENABLE_DANGLING_RAW_PTR_CHECKS=$_enable_dangling_raw_ptr_checks",
-#    "PUT_REF_COUNT_IN_PREVIOUS_SLOT=$_put_ref_count_in_previous_slot",
-#    "USE_MTE_CHECKED_PTR=$_use_mte_checked_ptr",
-#    "RECORD_ALLOC_INFO=$_record_alloc_info",
diff --git a/base/allocator/partition_allocator/DEPS b/base/allocator/partition_allocator/DEPS
index 6536ff9a..69a2d86 100644
--- a/base/allocator/partition_allocator/DEPS
+++ b/base/allocator/partition_allocator/DEPS
@@ -4,14 +4,9 @@
 noparent = True
 
 include_rules = [
-    "+base/allocator/buildflags.h",
-    "+base/logging_buildflags.h",
     "+base/mac/foundation_util.h",
-    "+base/debug/debugging_buildflags.h",
     "+build/build_config.h",
     "+build/buildflag.h",
-    "+build/chromeos_buildflags.h",
-    "+build/chromecast_buildflags.h",
     "+third_party/lss/linux_syscall_support.h",
 ]
 
diff --git a/base/allocator/partition_allocator/address_pool_manager.cc b/base/allocator/partition_allocator/address_pool_manager.cc
index bc55d250..2b08878 100644
--- a/base/allocator/partition_allocator/address_pool_manager.cc
+++ b/base/allocator/partition_allocator/address_pool_manager.cc
@@ -9,10 +9,11 @@
 #include <cstdint>
 #include <limits>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_space_stats.h"
 #include "base/allocator/partition_allocator/page_allocator.h"
 #include "base/allocator/partition_allocator/page_allocator_constants.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_notreached.h"
diff --git a/base/allocator/partition_allocator/address_pool_manager.h b/base/allocator/partition_allocator/address_pool_manager.h
index 186bf9c..42d0f7042 100644
--- a/base/allocator/partition_allocator/address_pool_manager.h
+++ b/base/allocator/partition_allocator/address_pool_manager.h
@@ -8,12 +8,12 @@
 #include <bitset>
 #include <limits>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_pool_manager_bitmap.h"
 #include "base/allocator/partition_allocator/address_pool_manager_types.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
diff --git a/base/allocator/partition_allocator/address_pool_manager_bitmap.cc b/base/allocator/partition_allocator/address_pool_manager_bitmap.cc
index 5765bdf..1a7417c 100644
--- a/base/allocator/partition_allocator/address_pool_manager_bitmap.cc
+++ b/base/allocator/partition_allocator/address_pool_manager_bitmap.cc
@@ -4,7 +4,7 @@
 
 #include "base/allocator/partition_allocator/address_pool_manager_bitmap.h"
 
-#include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 
 #if !defined(PA_HAS_64_BITS_POINTERS)
diff --git a/base/allocator/partition_allocator/address_pool_manager_bitmap.h b/base/allocator/partition_allocator/address_pool_manager_bitmap.h
index f9ab470..72e5346 100644
--- a/base/allocator/partition_allocator/address_pool_manager_bitmap.h
+++ b/base/allocator/partition_allocator/address_pool_manager_bitmap.h
@@ -10,9 +10,9 @@
 #include <bitset>
 #include <limits>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
diff --git a/base/allocator/partition_allocator/address_space_randomization_unittest.cc b/base/allocator/partition_allocator/address_space_randomization_unittest.cc
index ee90dd5..bf3559c 100644
--- a/base/allocator/partition_allocator/address_space_randomization_unittest.cc
+++ b/base/allocator/partition_allocator/address_space_randomization_unittest.cc
@@ -7,8 +7,8 @@
 #include <cstdint>
 #include <vector>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/page_allocator.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/random.h"
 #include "build/build_config.h"
diff --git a/base/allocator/partition_allocator/address_space_stats.h b/base/allocator/partition_allocator/address_space_stats.h
index 40fe522d..3954a1bf 100644
--- a/base/allocator/partition_allocator/address_space_stats.h
+++ b/base/allocator/partition_allocator/address_space_stats.h
@@ -7,8 +7,8 @@
 
 #include <cstddef>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 
 namespace partition_alloc {
diff --git a/base/allocator/partition_allocator/extended_api.cc b/base/allocator/partition_allocator/extended_api.cc
index 444c371f..348d1084 100644
--- a/base/allocator/partition_allocator/extended_api.cc
+++ b/base/allocator/partition_allocator/extended_api.cc
@@ -5,7 +5,7 @@
 #include "base/allocator/partition_allocator/extended_api.h"
 
 #include "base/allocator/allocator_shim_default_dispatch_to_partition_alloc.h"
-#include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/thread_cache.h"
 
 namespace partition_alloc::internal {
diff --git a/base/allocator/partition_allocator/memory_reclaimer_unittest.cc b/base/allocator/partition_allocator/memory_reclaimer_unittest.cc
index 12b23c28..3c8193a 100644
--- a/base/allocator/partition_allocator/memory_reclaimer_unittest.cc
+++ b/base/allocator/partition_allocator/memory_reclaimer_unittest.cc
@@ -8,10 +8,10 @@
 #include <utility>
 
 #include "base/allocator/allocator_shim_default_dispatch_to_partition_alloc.h"
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/logging.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/allocator/partition_allocator/page_allocator_internals_posix.h b/base/allocator/partition_allocator/page_allocator_internals_posix.h
index bef7f49..b0453a06 100644
--- a/base/allocator/partition_allocator/page_allocator_internals_posix.h
+++ b/base/allocator/partition_allocator/page_allocator_internals_posix.h
@@ -12,9 +12,9 @@
 
 #include <sys/mman.h>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/oom.h"
 #include "base/allocator/partition_allocator/page_allocator.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/posix/eintr_wrapper.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "build/build_config.h"
diff --git a/base/allocator/partition_allocator/partition_address_space.h b/base/allocator/partition_allocator/partition_address_space.h
index 0167dba8..33a2d85d 100644
--- a/base/allocator/partition_allocator/partition_address_space.h
+++ b/base/allocator/partition_allocator/partition_address_space.h
@@ -9,12 +9,12 @@
 #include <array>
 #include <limits>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_pool_manager_types.h"
 #include "base/allocator/partition_allocator/page_allocator_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
@@ -22,7 +22,6 @@
 #include "base/allocator/partition_allocator/partition_alloc_notreached.h"
 #include "base/allocator/partition_allocator/tagging.h"
 #include "build/build_config.h"
-#include "build/buildflag.h"
 
 // The feature is not applicable to 32-bit address space.
 #if defined(PA_HAS_64_BITS_POINTERS)
diff --git a/base/allocator/partition_allocator/partition_alloc-inl.h b/base/allocator/partition_allocator/partition_alloc-inl.h
index 1953caa..f973695 100644
--- a/base/allocator/partition_allocator/partition_alloc-inl.h
+++ b/base/allocator/partition_allocator/partition_alloc-inl.h
@@ -8,8 +8,8 @@
 #include <algorithm>
 #include <cstring>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_ref_count.h"
 #include "base/allocator/partition_allocator/random.h"
 #include "build/build_config.h"
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index 94995d0f..671ae93 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -9,10 +9,11 @@
 #include <cstdint>
 #include <memory>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_pool_manager.h"
 #include "base/allocator/partition_allocator/memory_reclaimer.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_hooks.h"
 #include "base/allocator/partition_allocator/partition_direct_map_extent.h"
 #include "base/allocator/partition_allocator/partition_oom.h"
diff --git a/base/allocator/partition_allocator/partition_alloc_base/check.h b/base/allocator/partition_allocator/partition_alloc_base/check.h
index 27aee111..ff6db46 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/check.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/check.h
@@ -7,9 +7,9 @@
 
 #include <iosfwd>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
 
 // This header defines the CHECK, DCHECK, and DPCHECK macros.
diff --git a/base/allocator/partition_allocator/partition_alloc_base/files/file_path_pa_unittest.cc b/base/allocator/partition_allocator/partition_alloc_base/files/file_path_pa_unittest.cc
index 059660a..1138786 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/files/file_path_pa_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/files/file_path_pa_unittest.cc
@@ -9,7 +9,6 @@
 #include <sstream>
 
 #include "build/build_config.h"
-#include "build/buildflag.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 // This macro helps avoid wrapped lines in the test structs.
diff --git a/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging.h b/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging.h
index 78a8a9be..393571e 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging.h
@@ -8,8 +8,8 @@
 #include <lib/fit/function.h>
 #include <zircon/types.h>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/logging.h"
 #include "build/build_config.h"
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging_pa_unittest.cc b/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging_pa_unittest.cc
index 50f7f3f..bb6ce13 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging_pa_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/fuchsia/fuchsia_logging_pa_unittest.cc
@@ -8,7 +8,7 @@
 #include <lib/fidl/cpp/binding.h>
 #include <lib/sys/cpp/component_context.h>
 
-#include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/logging.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/base/allocator/partition_allocator/partition_alloc_base/logging.h b/base/allocator/partition_allocator/partition_alloc_base/logging.h
index 9abf1d52..fcec8abc 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/logging.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/logging.h
@@ -12,9 +12,9 @@
 #include <sstream>
 #include <string>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/scoped_clear_last_error.h"
 #include "build/build_config.h"
diff --git a/base/allocator/partition_allocator/partition_alloc_base/logging_pa_unittest.cc b/base/allocator/partition_allocator/partition_alloc_base/logging_pa_unittest.cc
index 104079c..e61f5c0 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/logging_pa_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/logging_pa_unittest.cc
@@ -5,7 +5,7 @@
 #include <sstream>
 #include <string>
 
-#include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/logging.h"
 #include "build/build_config.h"
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.cc b/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.cc
index b613d12..bce47b5 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.cc
@@ -8,7 +8,7 @@
 #include <ostream>
 #include <type_traits>
 
-#include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 
 namespace partition_alloc::internal::base::subtle {
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.h b/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.h
index 5150fa3..4618e20 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/memory/ref_counted.h
@@ -5,10 +5,10 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/atomic_ref_count.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/memory/scoped_refptr.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "build/build_config.h"
diff --git a/base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h b/base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h
index 7beab2b2..c73bb1f 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h
@@ -37,7 +37,7 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_THREAD_ANNOTATIONS_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_THREAD_ANNOTATIONS_H_
 
-#include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "build/build_config.h"
 
 #if defined(__clang__)
diff --git a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix.cc b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix.cc
index d47ac1e..a69ffab 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix.cc
@@ -12,7 +12,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/logging.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_internal_posix.h"
 #include "build/build_config.h"
diff --git a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix_for_testing.cc b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix_for_testing.cc
index 4947e7b7..8e8280a 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix_for_testing.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_posix_for_testing.cc
@@ -13,9 +13,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/logging.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_internal_posix.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "build/build_config.h"
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_win.cc b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_win.cc
index 077432f..952dd11 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_win.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_win.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/time/time_override.h"
 
 #include <windows.h>
diff --git a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_win_for_testing.cc b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_win_for_testing.cc
index 3bf5977036..8c9a8d8 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_win_for_testing.cc
+++ b/base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_win_for_testing.cc
@@ -6,9 +6,9 @@
 
 #include <stddef.h>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/oom.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/debug/alias.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "build/build_config.h"
 
diff --git a/base/allocator/partition_allocator/partition_alloc_base/time/time.h b/base/allocator/partition_allocator/partition_alloc_base/time/time.h
index 0f5cd71..54980b3 100644
--- a/base/allocator/partition_allocator/partition_alloc_base/time/time.h
+++ b/base/allocator/partition_allocator/partition_alloc_base/time/time.h
@@ -68,12 +68,12 @@
 #include <iosfwd>
 #include <limits>
 
+#include "base/allocator/partition_allocator/chromeos_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/numerics/clamped_math.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
 
 #if BUILDFLAG(IS_FUCHSIA)
 #include <zircon/types.h>
@@ -888,14 +888,14 @@
 
 #endif  // BUILDFLAG(IS_MAC)
 
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(PA_IS_CHROMEOS_ASH)
   // Converts to TimeTicks the value obtained from SystemClock.uptimeMillis().
   // Note: this conversion may be non-monotonic in relation to previously
   // obtained TimeTicks::Now() values because of the truncation (to
   // milliseconds) performed by uptimeMillis().
   static TimeTicks FromUptimeMillis(int64_t uptime_millis_value);
 
-#endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(PA_IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_ANDROID)
   // Converts to TimeTicks the value obtained from System.nanoTime(). This
diff --git a/base/allocator/partition_allocator/partition_alloc_check.h b/base/allocator/partition_allocator/partition_alloc_check.h
index b0f7c26..80e06ee 100644
--- a/base/allocator/partition_allocator/partition_alloc_check.h
+++ b/base/allocator/partition_allocator/partition_alloc_check.h
@@ -7,12 +7,13 @@
 
 #include <cstdint>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/page_allocator_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/check.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/debug/alias.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "build/build_config.h"
 
 #define PA_STRINGIFY_IMPL(s) #s
diff --git a/base/allocator/partition_allocator/partition_alloc_config.h b/base/allocator/partition_allocator/partition_alloc_config.h
index ae4749f..16ed3cc 100644
--- a/base/allocator/partition_allocator/partition_alloc_config.h
+++ b/base/allocator/partition_allocator/partition_alloc_config.h
@@ -5,7 +5,8 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CONFIG_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CONFIG_H_
 
-#include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "build/build_config.h"
 
 // ARCH_CPU_64_BITS implies 64-bit instruction set, but not necessarily 64-bit
diff --git a/base/allocator/partition_allocator/partition_alloc_forward.h b/base/allocator/partition_allocator/partition_alloc_forward.h
index b0c8f4e..3c573caa 100644
--- a/base/allocator/partition_allocator/partition_alloc_forward.h
+++ b/base/allocator/partition_allocator/partition_alloc_forward.h
@@ -8,9 +8,10 @@
 #include <algorithm>
 #include <cstddef>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 
 namespace partition_alloc {
 
diff --git a/base/allocator/partition_allocator/partition_alloc_notreached.h b/base/allocator/partition_allocator/partition_alloc_notreached.h
index d19b4282..f1329d40 100644
--- a/base/allocator/partition_allocator/partition_alloc_notreached.h
+++ b/base/allocator/partition_allocator/partition_alloc_notreached.h
@@ -5,17 +5,18 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_NOTREACHED_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_NOTREACHED_H_
 
-#include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/logging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
-#include "base/logging_buildflags.h"
 
 // When PartitionAlloc is used as the default allocator, we cannot use the
 // regular (D)CHECK() macros, as they allocate internally. (c.f. //
 // base/allocator/partition_allocator/partition_alloc_check.h)
 // So PA_NOTREACHED() uses PA_DCHECK() instead of DCHECK().
 
-#if BUILDFLAG(ENABLE_LOG_ERROR_NOT_REACHED)
+#if BUILDFLAG(PA_ENABLE_LOG_ERROR_NOT_REACHED)
 #define PA_NOTREACHED()                                                    \
   true ? ::partition_alloc::internal::logging::RawError(                   \
              __FILE__ "(" PA_STRINGIFY(__LINE__) ") PA_NOTREACHED() hit.") \
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 350bd7d5..46c9ad7 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -17,20 +17,22 @@
 #include <tuple>
 #include <vector>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_space_randomization.h"
+#include "base/allocator/partition_allocator/chromecast_buildflags.h"
 #include "base/allocator/partition_allocator/dangling_raw_ptr_checks.h"
 #include "base/allocator/partition_allocator/page_allocator_constants.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/cpu.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/logging.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/numerics/checked_math.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/rand_util.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/strings/stringprintf.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_for_testing.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_bucket.h"
@@ -42,10 +44,8 @@
 #include "base/allocator/partition_allocator/partition_tag_bitmap.h"
 #include "base/allocator/partition_allocator/reservation_offset_table.h"
 #include "base/allocator/partition_allocator/tagging.h"
-#include "base/debug/debugging_buildflags.h"
 #include "base/system/sys_info.h"
 #include "build/build_config.h"
-#include "build/chromecast_buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(__ARM_FEATURE_MEMORY_TAGGING)
@@ -937,7 +937,7 @@
   // Check that the realloc copied correctly.
   char* new_char_ptr = static_cast<char*>(new_ptr);
   EXPECT_EQ(*new_char_ptr, 'A');
-#if BUILDFLAG(EXPENSIVE_DCHECKS_ARE_ON)
+#if BUILDFLAG(PA_EXPENSIVE_DCHECKS_ARE_ON)
   // Subtle: this checks for an old bug where we copied too much from the
   // source of the realloc. The condition can be detected by a trashing of
   // the uninitialized value in the space of the upsized allocation.
@@ -1054,7 +1054,7 @@
     allocator.root()->Free(new_ptr_2);
     allocator.root()->Free(ptr4);
 
-#if BUILDFLAG(EXPENSIVE_DCHECKS_ARE_ON)
+#if BUILDFLAG(PA_EXPENSIVE_DCHECKS_ARE_ON)
     // |SlotSpanMetadata::Free| must poison the slot's contents with
     // |kFreedByte|.
     EXPECT_EQ(kFreedByte,
@@ -1364,7 +1364,7 @@
   char* char_ptr2 = static_cast<char*>(ptr2);
   EXPECT_EQ('A', char_ptr2[0]);
   EXPECT_EQ('A', char_ptr2[size - 1]);
-#if BUILDFLAG(EXPENSIVE_DCHECKS_ARE_ON)
+#if BUILDFLAG(PA_EXPENSIVE_DCHECKS_ARE_ON)
   EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(char_ptr2[size]));
 #endif
 
@@ -1376,7 +1376,7 @@
   char* char_ptr = static_cast<char*>(ptr);
   EXPECT_EQ('A', char_ptr[0]);
   EXPECT_EQ('A', char_ptr[size - 2]);
-#if BUILDFLAG(EXPENSIVE_DCHECKS_ARE_ON)
+#if BUILDFLAG(PA_EXPENSIVE_DCHECKS_ARE_ON)
   EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(char_ptr[size - 1]));
 #endif
 
@@ -1396,7 +1396,7 @@
   char_ptr2 = static_cast<char*>(ptr2);
   EXPECT_EQ('A', char_ptr2[0]);
   EXPECT_EQ('A', char_ptr2[size - 1]);
-#if BUILDFLAG(EXPENSIVE_DCHECKS_ARE_ON)
+#if BUILDFLAG(PA_EXPENSIVE_DCHECKS_ARE_ON)
   EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(char_ptr2[size]));
 #endif
   allocator.root()->Free(ptr2);
@@ -4165,7 +4165,7 @@
 // https://ci.chromium.org/ui/p/chromium/builders/ci/Cast%20Audio%20Linux/98492/overview
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) &&                \
     defined(GTEST_HAS_DEATH_TEST) && !BUILDFLAG(IS_ANDROID) && \
-    !BUILDFLAG(IS_CHROMECAST)
+    !BUILDFLAG(PA_IS_CASTOS)
 
 namespace {
 
@@ -4243,7 +4243,7 @@
 
 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) &&
         // defined(GTEST_HAS_DEATH_TEST) && !BUILDFLAG(IS_ANDROID) &&
-        // !BUILDFLAG(IS_CHROMECAST)
+        // !BUILDFLAG(PA_IS_CASTOS)
 
 // Checks the bucket index logic.
 TEST_P(PartitionAllocTest, GetIndex) {
@@ -4520,7 +4520,7 @@
 #endif  // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
 
 #if BUILDFLAG(IS_ANDROID) && BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
-    BUILDFLAG(IS_CHROMECAST)
+    BUILDFLAG(PA_IS_CASTOS)
 extern "C" {
 void* __real_malloc(size_t);
 }  // extern "C"
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index 8107f5d..36c7b43 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -8,7 +8,6 @@
 #include <cstdint>
 #include <tuple>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_pool_manager.h"
 #include "base/allocator/partition_allocator/oom.h"
 #include "base/allocator/partition_allocator/page_allocator.h"
@@ -19,8 +18,10 @@
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/debug/alias.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
diff --git a/base/allocator/partition_allocator/partition_cookie.h b/base/allocator/partition_allocator/partition_cookie.h
index ed38f035..a3fe230 100644
--- a/base/allocator/partition_allocator/partition_cookie.h
+++ b/base/allocator/partition_allocator/partition_cookie.h
@@ -5,8 +5,8 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_COOKIE_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_COOKIE_H_
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 
 namespace partition_alloc::internal {
diff --git a/base/allocator/partition_allocator/partition_freelist_entry.h b/base/allocator/partition_allocator/partition_freelist_entry.h
index 9be80ff..ac097fb 100644
--- a/base/allocator/partition_allocator/partition_freelist_entry.h
+++ b/base/allocator/partition_allocator/partition_freelist_entry.h
@@ -8,12 +8,13 @@
 #include <cstddef>
 #include <cstdint>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc-inl.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/sys_byteorder.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
diff --git a/base/allocator/partition_allocator/partition_lock.h b/base/allocator/partition_allocator/partition_lock.h
index cb5d685..f0efc921 100644
--- a/base/allocator/partition_allocator/partition_lock.h
+++ b/base/allocator/partition_allocator/partition_lock.h
@@ -8,8 +8,8 @@
 #include <atomic>
 #include <type_traits>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread.h"
diff --git a/base/allocator/partition_allocator/partition_lock_unittest.cc b/base/allocator/partition_allocator/partition_lock_unittest.cc
index a45d0d7..7b634ff 100644
--- a/base/allocator/partition_allocator/partition_lock_unittest.cc
+++ b/base/allocator/partition_allocator/partition_lock_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "base/allocator/partition_allocator/partition_lock.h"
 
-#include "base/allocator/buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_for_testing.h"
diff --git a/base/allocator/partition_allocator/partition_page.cc b/base/allocator/partition_allocator/partition_page.cc
index 4f1a72a..3f11d6dc 100644
--- a/base/allocator/partition_allocator/partition_page.cc
+++ b/base/allocator/partition_allocator/partition_page.cc
@@ -7,13 +7,14 @@
 #include <algorithm>
 #include <cstdint>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_pool_manager.h"
 #include "base/allocator/partition_allocator/page_allocator.h"
 #include "base/allocator/partition_allocator/page_allocator_constants.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index 59fe1129..d28712c 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -10,14 +10,15 @@
 #include <limits>
 #include <utility>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_pool_manager.h"
 #include "base/allocator/partition_allocator/address_pool_manager_types.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
diff --git a/base/allocator/partition_allocator/partition_ref_count.h b/base/allocator/partition_allocator/partition_ref_count.h
index bb0f7e3..e144953 100644
--- a/base/allocator/partition_allocator/partition_ref_count.h
+++ b/base/allocator/partition_allocator/partition_ref_count.h
@@ -8,10 +8,11 @@
 #include <atomic>
 #include <cstdint>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc
index 2127867..c5b9543 100644
--- a/base/allocator/partition_allocator/partition_root.cc
+++ b/base/allocator/partition_allocator/partition_root.cc
@@ -6,7 +6,6 @@
 
 #include <cstdint>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_pool_manager_bitmap.h"
 #include "base/allocator/partition_allocator/oom.h"
 #include "base/allocator/partition_allocator/page_allocator.h"
@@ -14,7 +13,9 @@
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index 0f29c175..e9624ca6 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -35,9 +35,9 @@
 #include <cstddef>
 #include <cstdint>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_pool_manager_types.h"
 #include "base/allocator/partition_allocator/allocation_guard.h"
+#include "base/allocator/partition_allocator/chromecast_buildflags.h"
 #include "base/allocator/partition_allocator/page_allocator.h"
 #include "base/allocator/partition_allocator/page_allocator_constants.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
@@ -45,8 +45,10 @@
 #include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
@@ -67,9 +69,7 @@
 #include "base/allocator/partition_allocator/starscan/state_bitmap.h"
 #include "base/allocator/partition_allocator/tagging.h"
 #include "base/allocator/partition_allocator/thread_cache.h"
-#include "base/debug/debugging_buildflags.h"
 #include "build/build_config.h"
-#include "build/chromecast_buildflags.h"
 
 // We use this to make MEMORY_TOOL_REPLACES_ALLOCATOR behave the same for max
 // size as other alloc code.
@@ -993,7 +993,7 @@
   PA_DCHECK(root->brp_enabled());
 
   // memset() can be really expensive.
-#if BUILDFLAG(EXPENSIVE_DCHECKS_ARE_ON)
+#if BUILDFLAG(PA_EXPENSIVE_DCHECKS_ARE_ON)
   DebugMemset(reinterpret_cast<void*>(slot_start), kFreedByte,
               slot_span->GetUtilizedSlotSize()
 #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
@@ -1130,7 +1130,7 @@
   //
   // On Chromecast, this is already checked in PartitionFree() in the shim.
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
-    ((BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMECAST)))
+    ((BUILDFLAG(IS_ANDROID) && !BUILDFLAG(PA_IS_CASTOS)))
   PA_CHECK(IsManagedByPartitionAlloc(object_addr));
 #endif
 
@@ -1283,7 +1283,7 @@
 #endif  // BUILDFLAG(USE_BACKUP_REF_PTR)
 
   // memset() can be really expensive.
-#if BUILDFLAG(EXPENSIVE_DCHECKS_ARE_ON)
+#if BUILDFLAG(PA_EXPENSIVE_DCHECKS_ARE_ON)
   internal::DebugMemset(SlotStartAddr2Ptr(slot_start), internal::kFreedByte,
                         slot_span->GetUtilizedSlotSize()
 #if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
@@ -1824,7 +1824,7 @@
   // PA_LIKELY: operator new() calls malloc(), not calloc().
   if (PA_LIKELY(!zero_fill)) {
     // memset() can be really expensive.
-#if BUILDFLAG(EXPENSIVE_DCHECKS_ARE_ON)
+#if BUILDFLAG(PA_EXPENSIVE_DCHECKS_ARE_ON)
     internal::DebugMemset(object, internal::kUninitializedByte, usable_size);
 #endif
   } else if (!is_already_zeroed) {
diff --git a/base/allocator/partition_allocator/partition_tag.h b/base/allocator/partition_allocator/partition_tag.h
index d8b5965..db224b86 100644
--- a/base/allocator/partition_allocator/partition_tag.h
+++ b/base/allocator/partition_allocator/partition_tag.h
@@ -10,8 +10,8 @@
 
 #include <string.h>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_notreached.h"
 #include "base/allocator/partition_allocator/partition_cookie.h"
diff --git a/base/allocator/partition_allocator/partition_tag_bitmap.h b/base/allocator/partition_allocator/partition_tag_bitmap.h
index d494fa4..2911e724 100644
--- a/base/allocator/partition_allocator/partition_tag_bitmap.h
+++ b/base/allocator/partition_allocator/partition_tag_bitmap.h
@@ -5,9 +5,9 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_TAG_BITMAP_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_TAG_BITMAP_H_
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/page_allocator_constants.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 
 namespace partition_alloc::internal {
diff --git a/base/allocator/partition_allocator/reservation_offset_table.h b/base/allocator/partition_allocator/reservation_offset_table.h
index 43804ba..18daf13 100644
--- a/base/allocator/partition_allocator/reservation_offset_table.h
+++ b/base/allocator/partition_allocator/reservation_offset_table.h
@@ -10,11 +10,12 @@
 #include <limits>
 #include <tuple>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/address_pool_manager.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/allocator/partition_allocator/tagging.h"
diff --git a/base/allocator/partition_allocator/spinning_mutex.h b/base/allocator/partition_allocator/spinning_mutex.h
index 5c922e6..7719bb05 100644
--- a/base/allocator/partition_allocator/spinning_mutex.h
+++ b/base/allocator/partition_allocator/spinning_mutex.h
@@ -8,7 +8,6 @@
 #include <algorithm>
 #include <atomic>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
diff --git a/base/allocator/partition_allocator/thread_cache.cc b/base/allocator/partition_allocator/thread_cache.cc
index a927c42..c09ac4e4a 100644
--- a/base/allocator/partition_allocator/thread_cache.cc
+++ b/base/allocator/partition_allocator/thread_cache.cc
@@ -10,10 +10,11 @@
 #include <atomic>
 #include <cstdint>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/cxx17_backports.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
diff --git a/base/allocator/partition_allocator/thread_cache.h b/base/allocator/partition_allocator/thread_cache.h
index ca8daba5..6ced855 100644
--- a/base/allocator/partition_allocator/thread_cache.h
+++ b/base/allocator/partition_allocator/thread_cache.h
@@ -10,12 +10,13 @@
 #include <limits>
 #include <memory>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
+#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/gtest_prod_util.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_alloc_forward.h"
 #include "base/allocator/partition_allocator/partition_bucket_lookup.h"
diff --git a/base/allocator/partition_allocator/thread_cache_unittest.cc b/base/allocator/partition_allocator/thread_cache_unittest.cc
index a970f960..1f36943 100644
--- a/base/allocator/partition_allocator/thread_cache_unittest.cc
+++ b/base/allocator/partition_allocator/thread_cache_unittest.cc
@@ -8,12 +8,12 @@
 #include <atomic>
 #include <vector>
 
-#include "base/allocator/buildflags.h"
 #include "base/allocator/partition_allocator/extended_api.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
 #include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_for_testing.h"
+#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/partition_alloc_config.h"
 #include "base/allocator/partition_allocator/partition_lock.h"
 #include "base/allocator/partition_allocator/tagging.h"
diff --git a/cc/paint/oop_pixeltest.cc b/cc/paint/oop_pixeltest.cc
index 3d278cc..a47e0dc 100644
--- a/cc/paint/oop_pixeltest.cc
+++ b/cc/paint/oop_pixeltest.cc
@@ -468,7 +468,7 @@
   // green, but its record bounds are configured to clip it to the bottom right
   // quarter of the output.
   PaintFlags internal_flags;
-  internal_flags.setColor4f(SkColors::kGreen);
+  internal_flags.setColor(SkColors::kGreen);
   sk_sp<PaintOpBuffer> filter_buffer(new PaintOpBuffer);
   filter_buffer->push<DrawRectOp>(
       SkRect::MakeLTRB(output_size.width() / 2.f, 0.f, output_size.width(),
@@ -617,7 +617,7 @@
   // tiling starts from the origin, so starting at 2,1 in the offset_rect
   // below cuts off part of that, leaving two green i's.
   PaintFlags internal_flags;
-  internal_flags.setColor4f(SkColors::kGreen);
+  internal_flags.setColor(SkColors::kGreen);
   sk_sp<PaintOpBuffer> shader_buffer(new PaintOpBuffer);
   shader_buffer->push<DrawRectOp>(SkRect::MakeXYWH(x_offset, y_offset, 1, 2),
                                   internal_flags);
@@ -1514,7 +1514,7 @@
   display_item_list->StartPaint();
   PaintFlags flags;
   flags.setStyle(PaintFlags::kFill_Style);
-  flags.setColor4f(SkColors::kGreen);
+  flags.setColor(SkColors::kGreen);
   display_item_list->push<DrawRectOp>(
       gfx::RectToSkRect(gfx::Rect(options.resource_size)), flags);
   display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
@@ -1872,7 +1872,7 @@
 
     PaintFlags text_flags;
     text_flags.setStyle(PaintFlags::kFill_Style);
-    text_flags.setColor4f(SkColors::kGreen);
+    text_flags.setColor(SkColors::kGreen);
     if (filter && (strategy == TextBlobStrategy::kDirect ||
                    strategy == TextBlobStrategy::kDrawRecord)) {
       // If there's a filter, the only PaintFlags that are available for these
@@ -2048,7 +2048,7 @@
   display_item_list->StartPaint();
   PaintFlags flags;
   flags.setStyle(PaintFlags::kFill_Style);
-  flags.setColor4f(SkColors::kGreen);
+  flags.setColor(SkColors::kGreen);
   display_item_list->push<DrawTextBlobOp>(BuildTextBlob(sk_typeface_1), 0.0f,
                                           kTextBlobY, flags);
   display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
@@ -2089,7 +2089,7 @@
   display_item_list->StartPaint();
   PaintFlags flags;
   flags.setStyle(PaintFlags::kFill_Style);
-  flags.setColor4f(SkColors::kGreen);
+  flags.setColor(SkColors::kGreen);
   display_item_list->push<DrawTextBlobOp>(BuildTextBlob(), 0.0f, kTextBlobY,
                                           flags);
   display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
@@ -2391,11 +2391,11 @@
     display_item_list->push<DrawColorOp>(SkColors::kWhite, SkBlendMode::kSrc);
     PaintFlags flags;
     flags.setStyle(PaintFlags::kFill_Style);
-    flags.setColor4f(SkColors::kGreen);
+    flags.setColor(SkColors::kGreen);
     SkPath path;
     path.addCircle(20, 20, 10);
     display_item_list->push<DrawPathOp>(path, flags);
-    flags.setColor4f(SkColors::kBlue);
+    flags.setColor(SkColors::kBlue);
     display_item_list->push<DrawRectOp>(SkRect::MakeWH(10, 10), flags);
     display_item_list->EndPaintOfUnpaired(options.full_raster_rect);
     display_item_list->Finalize();
@@ -2427,7 +2427,7 @@
   shader_record->push<DrawColorOp>(SkColors::kWhite, SkBlendMode::kSrc);
   PaintFlags flags;
   flags.setStyle(PaintFlags::kFill_Style);
-  flags.setColor4f(SkColors::kGreen);
+  flags.setColor(SkColors::kGreen);
   shader_record->push<DrawRectOp>(rect, flags);
   auto shader = PaintShader::MakePaintRecord(
       shader_record, rect, SkTileMode::kRepeat, SkTileMode::kRepeat, nullptr);
diff --git a/cc/paint/paint_flags.cc b/cc/paint/paint_flags.cc
index 29918c7..c80d3cc 100644
--- a/cc/paint/paint_flags.cc
+++ b/cc/paint/paint_flags.cc
@@ -144,7 +144,7 @@
   paint.setColorFilter(color_filter_);
   if (image_filter_)
     paint.setImageFilter(image_filter_->cached_sk_filter_);
-  paint.setColor4f(color_);
+  paint.setColor(color_);
   paint.setStrokeWidth(width_);
   paint.setStrokeMiter(miter_limit_);
   paint.setBlendMode(getBlendMode());
diff --git a/cc/paint/paint_flags.h b/cc/paint/paint_flags.h
index d3a850d2..537c13f9 100644
--- a/cc/paint/paint_flags.h
+++ b/cc/paint/paint_flags.h
@@ -41,12 +41,13 @@
     return static_cast<Style>(bitfields_.style_);
   }
   ALWAYS_INLINE void setStyle(Style style) { bitfields_.style_ = style; }
+  // TODO(crbug.com/1308932): Remove this function
   ALWAYS_INLINE SkColor getColor() const { return color_.toSkColor(); }
   ALWAYS_INLINE SkColor4f getColor4f() const { return color_; }
   ALWAYS_INLINE void setColor(SkColor color) {
     color_ = SkColor4f::FromColor(color);
   }
-  ALWAYS_INLINE void setColor4f(SkColor4f color) { color_ = color; }
+  ALWAYS_INLINE void setColor(SkColor4f color) { color_ = color; }
   ALWAYS_INLINE uint8_t getAlpha() const {
     return SkColorGetA(color_.toSkColor());
   }
@@ -205,7 +206,7 @@
 
   // Match(ish) SkPaint defaults.  SkPaintDefaults is not public, so this
   // just uses these values and ignores any SkUserConfig overrides.
-  SkColor4f color_ = SkColor4f::FromColor(SK_ColorBLACK);
+  SkColor4f color_ = SkColors::kBlack;
   float width_ = 0.f;
   float miter_limit_ = 4.f;
   uint32_t blend_mode_ = static_cast<uint32_t>(SkBlendMode::kSrcOver);
diff --git a/cc/paint/solid_color_analyzer_unittest.cc b/cc/paint/solid_color_analyzer_unittest.cc
index 26c50f99..a343e1d 100644
--- a/cc/paint/solid_color_analyzer_unittest.cc
+++ b/cc/paint/solid_color_analyzer_unittest.cc
@@ -116,7 +116,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   canvas()->drawOval(SkRect::MakeWH(100, 100), flags);
   EXPECT_FALSE(IsSolidColor());
 }
@@ -125,7 +125,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(200, 200);
   canvas()->clipRect(rect, SkClipOp::kIntersect, false);
   canvas()->drawRect(rect, flags);
@@ -142,7 +142,7 @@
   Initialize(canvas_rect);
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   canvas()->drawRRect(rrect, flags);
   EXPECT_EQ(color, GetColor());
 }
@@ -151,7 +151,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(200, 200);
   canvas()->clipRect(SkRect::MakeWH(50, 50), SkClipOp::kIntersect, false);
   canvas()->drawRect(rect, flags);
@@ -162,7 +162,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect drawRect = SkRect::MakeWH(200, 200);
   canvas()->clipRect(drawRect, SkClipOp::kIntersect, false);
   SkRect differenceRect = SkRect::MakeXYWH(50, 50, 200, 200);
@@ -176,7 +176,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(100, 100);
   canvas()->translate(1, 1);
   canvas()->drawRect(rect, flags);
@@ -187,7 +187,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(101, 101);
   canvas()->translate(1, 1);
   canvas()->drawRect(rect, flags);
@@ -206,7 +206,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   flags.setBlendMode(SkBlendMode::kClear);
   SkRect rect = SkRect::MakeWH(200, 200);
   canvas()->drawRect(rect, flags);
@@ -217,7 +217,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   flags.setBlendMode(SkBlendMode::kSrcOver);
   SkRect rect = SkRect::MakeWH(200, 200);
   canvas()->drawRect(rect, flags);
@@ -228,7 +228,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(200, 200);
   canvas()->rotate(50);
   canvas()->drawRect(rect, flags);
@@ -239,7 +239,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(200, 200);
   canvas()->scale(0.1f, 0.1f);
   canvas()->drawRect(rect, flags);
@@ -250,7 +250,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(10, 10);
   canvas()->scale(10, 10);
   canvas()->drawRect(rect, flags);
@@ -261,7 +261,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
   flags.setImageFilter(sk_make_sp<OffsetPaintFilter>(10, 10, nullptr));
   SkRect rect = SkRect::MakeWH(200, 200);
   canvas()->drawRect(rect, flags);
@@ -272,7 +272,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
 
   SkPath path;
   path.moveTo(0, 0);
@@ -291,7 +291,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(128, 128, 0, 0));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(100, 100);
   canvas()->drawRect(rect, flags);
 #if BUILDFLAG(IS_MAC)
@@ -307,11 +307,11 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 128, 0, 0));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(100, 50);
   canvas()->drawRect(rect, flags);
   color = SkColor4f::FromColor(SkColorSetARGB(128, 0, 128, 0));
-  flags.setColor4f(color);
+  flags.setColor(color);
   rect = SkRect::MakeWH(100, 100);
   canvas()->drawRect(rect, flags);
   EXPECT_FALSE(IsSolidColor(2 /* max_ops_to_analyze */));
@@ -321,11 +321,11 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 128, 0, 0));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(100, 50);
   canvas()->drawRect(rect, flags);
   color = SkColor4f::FromColor(SkColorSetARGB(255, 0, 128, 0));
-  flags.setColor4f(color);
+  flags.setColor(color);
   rect = SkRect::MakeWH(100, 100);
   canvas()->drawRect(rect, flags);
   EXPECT_EQ(color, GetColor(2 /* max_ops_to_analyze */));
@@ -335,11 +335,11 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(64, 40, 50, 60));
-  flags.setColor4f(color);
+  flags.setColor(color);
   SkRect rect = SkRect::MakeWH(100, 100);
   canvas()->drawRect(rect, flags);
   color = SkColor4f::FromColor(SkColorSetARGB(128, 10, 20, 30));
-  flags.setColor4f(color);
+  flags.setColor(color);
   rect = SkRect::MakeWH(100, 100);
   canvas()->drawRect(rect, flags);
 #if BUILDFLAG(IS_MAC)
@@ -357,7 +357,7 @@
   Initialize();
   PaintFlags flags;
   SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
-  flags.setColor4f(color);
+  flags.setColor(color);
 
   SkRect rect = SkRect::MakeWH(200, 200);
   canvas()->saveLayer(&rect, &flags);
@@ -379,7 +379,7 @@
   int canvas_size = 255;
   gfx::Rect canvas_rect(canvas_size, canvas_size);
   PaintFlags flags;
-  flags.setColor4f(SkColors::kWhite);
+  flags.setColor(SkColors::kWhite);
 
   struct {
     SkVector offset;
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc
index 811f7f8f..c6bb12f 100644
--- a/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -70,7 +70,7 @@
     PaintFlags flags;
     flags.setStyle(PaintFlags::kStroke_Style);
     flags.setStrokeWidth(SkIntToScalar(2));
-    flags.setColor4f(SkColors::kWhite);
+    flags.setColor(SkColors::kWhite);
 
     gfx::Rect inset_rect(bounds_);
     while (!inset_rect.IsEmpty()) {
@@ -792,7 +792,7 @@
     display_list->StartPaint();
     display_list->push<DrawColorOp>(color_even, SkBlendMode::kSrc);
     PaintFlags flags;
-    flags.setColor4f(color_odd);
+    flags.setColor(color_odd);
     for (int j = 0; j < (bounds.height() + kGridSize - 1) / kGridSize; j++) {
       for (int i = 0; i < (bounds.width() + kGridSize - 1) / kGridSize; i++) {
         bool is_odd_grid = (i ^ j) & 1;
diff --git a/chrome/VERSION b/chrome/VERSION
index 546f4914..b8a9cae 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=104
 MINOR=0
-BUILD=5100
+BUILD=5101
 PATCH=0
diff --git a/chrome/android/java/res/layout/custom_tabs_handle_view.xml b/chrome/android/java/res/layout/custom_tabs_handle_view.xml
index 502272a..6427f52 100644
--- a/chrome/android/java/res/layout/custom_tabs_handle_view.xml
+++ b/chrome/android/java/res/layout/custom_tabs_handle_view.xml
@@ -6,13 +6,15 @@
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/custom_tabs_handle_height"
+    android:layout_height="match_parent"
     android:background="@drawable/custom_tabs_handle_view_shape">
 
     <ImageView
+        android:id="@+id/handle_bar"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="bottom|center_horizontal"
+        android:layout_marginTop="0dp"
+        android:layout_gravity="center_horizontal"
         android:importantForAccessibility="no"
         android:src="@drawable/drag_handlebar"
         android:tint="@macro/drag_handlebar_color" />
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index ddf3421..a9ffbc4 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -279,8 +279,10 @@
     <dimen name="custom_tabs_screenshot_height">300dp</dimen>
     <dimen name="custom_tabs_screenshot_width">190dp</dimen>
     <dimen name="custom_tabs_handle_height">16dp</dimen>
+    <dimen name="custom_tabs_drag_bar_height">4dp</dimen>
     <dimen name="custom_tabs_elevation">8dp</dimen>
     <dimen name="custom_tabs_shadow_offset">4dp</dimen>
+    <dimen name="custom_tabs_outline_width">1dp</dimen>
     <dimen name="custom_tabs_default_corner_radius">16dp</dimen>
 
     <!-- Account chooser dialog dimensions -->
diff --git a/chrome/android/java/res_app/layout/main.xml b/chrome/android/java/res_app/layout/main.xml
index 24cae95..3c9947a 100644
--- a/chrome/android/java/res_app/layout/main.xml
+++ b/chrome/android/java/res_app/layout/main.xml
@@ -13,7 +13,7 @@
         android:id="@+id/custom_tabs_handle_view_stub"
         android:inflatedId="@+id/custom_tabs_handle_view"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/custom_tabs_handle_height"
+        android:layout_height="match_parent"
         android:layout_marginTop="@dimen/custom_tabs_shadow_offset"
         android:layout="@layout/custom_tabs_handle_view"
         android:visibility="gone" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
index 3eab1940..843cf3a8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PartialCustomTabHeightStrategy.java
@@ -42,6 +42,7 @@
 import androidx.swiperefreshlayout.widget.CircularProgressDrawable;
 
 import org.chromium.base.MathUtils;
+import org.chromium.base.SysUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.R;
@@ -99,6 +100,7 @@
     private final int mHandleHeight;
     private ValueAnimator mAnimator;
     private int mShadowOffset;
+    private boolean mDrawOutlineShadow;
 
     private @HeightStatus int mStatus = HeightStatus.INITIAL_HEIGHT;
     private @HeightStatus int mTargetStatus;
@@ -306,6 +308,7 @@
         mIsInMultiWindowMode = multiWindowModeStateDispatcher.isInMultiWindowMode();
         mNavigationBarColor = navigationBarColor;
         mNavigationBarDividerColor = navigationBarDividerColor;
+        mDrawOutlineShadow = SysUtils.isLowEndDevice();
         mHandleHeight =
                 mActivity.getResources().getDimensionPixelSize(R.dimen.custom_tabs_handle_height);
         mSpinnerFadeoutAnimatorListener = new AnimatorListener() {
@@ -347,9 +350,8 @@
     public void onToolbarInitialized(
             View coordinatorView, CustomTabToolbar toolbar, @Px int toolbarCornerRadius) {
         mToolbarCoordinator = coordinatorView;
-        roundCorners(coordinatorView, toolbar, toolbarCornerRadius);
-
         mToolbarView = toolbar;
+        roundCorners(coordinatorView, toolbar, toolbarCornerRadius);
         toolbar.setHandleStrategy(new PartialCustomTabHandleStrategy(mActivity));
     }
 
@@ -386,12 +388,28 @@
         View handleView = mActivity.findViewById(R.id.custom_tabs_handle_view);
         handleView.setElevation(
                 mActivity.getResources().getDimensionPixelSize(R.dimen.custom_tabs_elevation));
+        View handleBar = handleView.findViewById(R.id.handle_bar);
+        ViewGroup.MarginLayoutParams lp =
+                (ViewGroup.MarginLayoutParams) handleBar.getLayoutParams();
+        int dragBarTopMargin =
+                mActivity.getResources().getDimensionPixelSize(R.dimen.custom_tabs_handle_height)
+                - mActivity.getResources().getDimensionPixelSize(
+                        R.dimen.custom_tabs_drag_bar_height);
+        lp.setMargins(0, dragBarTopMargin, 0, 0);
+
         GradientDrawable background = (GradientDrawable) handleView.getBackground();
         background.mutate();
         background.setCornerRadii(new float[] {toolbarCornerRadius, toolbarCornerRadius,
                 toolbarCornerRadius, toolbarCornerRadius, 0, 0, 0, 0});
-        handleView.setBackground(background);
         updateShadowOffset();
+        if (mDrawOutlineShadow) {
+            int width = mActivity.getResources().getDimensionPixelSize(
+                    R.dimen.custom_tabs_outline_width);
+            int color = toolbar.getBackground().getColor();
+            background.setStroke(width, toolbar.getToolbarHairlineColor(color));
+        }
+
+        handleView.setBackground(background);
 
         // Pass the handle View to CustomTabToolbar for background color management.
         toolbar.setHandleView(handleView);
@@ -432,7 +450,7 @@
     }
 
     private void updateShadowOffset() {
-        if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
+        if (mOrientation == Configuration.ORIENTATION_LANDSCAPE || mDrawOutlineShadow) {
             // Shadow is not necessary as CCT will be always of full-height in landscape mode.
             mShadowOffset = 0;
         } else {
@@ -533,8 +551,6 @@
         // the handle bar portion of the CCT toolbar header.
         // TODO(jinsukkim):
         //   - Remove the shadow when in full-height so there won't be a gap beneath the status bar.
-        //   - Draw a thin border line around CCT on low-mem devices where the shadow effect via
-        //     android:elevation directive won't work.
         int windowPos = mActivity.getWindow().getAttributes().y;
         lp.height = getDisplayHeight() - windowPos - mHandleHeight - mShadowOffset - mNavbarHeight;
         parentView.setLayoutParams(lp);
@@ -598,9 +614,11 @@
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return;
         Integer dividerColor = CustomTabNavigationBarController.getDividerColor(
                 mActivity, mNavigationBarColor, mNavigationBarDividerColor, needsDarkButtons);
+        View divider = mNavbar.findViewById(R.id.divider);
         if (dividerColor != null) {
-            View divider = mNavbar.findViewById(R.id.divider);
             divider.setBackgroundColor(dividerColor);
+        } else {
+            divider.setVisibility(View.GONE);
         }
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java
index 30d385b4..7700ad3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PictureInPictureControllerTest.java
@@ -72,6 +72,7 @@
     @Test
     @MediumTest
     @MinAndroidSdkLevel(Build.VERSION_CODES.O)
+    @DisabledTest(message = "https://crbug.com/1332360")
     public void testFullscreenVideoDetected() throws Throwable {
         enterFullscreen();
     }
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp
index 999dd94..75f2587b 100644
--- a/chrome/app/settings_chromium_strings.grdp
+++ b/chrome/app/settings_chromium_strings.grdp
@@ -280,6 +280,11 @@
     Sign in to sync and personalize Chromium across your devices
   </message>
 
+    <!-- Autofill Assistant settings -->
+  <message name="IDS_SETTINGS_AUTOFILL_ASSISTANT_PREF" translateable="false" desc="The documentation string of the 'Use Google Assistant' preference to help with automated flows on the web">
+    Google Assistant in Chromium
+  </message>
+
   <!-- Languages Page -->
   <if expr="is_win">
     <message name="IDS_SETTINGS_LANGUAGES_IS_DISPLAYED_IN_THIS_LANGUAGE" desc="The label for a language that is currently used as the UI display language.">
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp
index 01142088..8e7219e 100644
--- a/chrome/app/settings_google_chrome_strings.grdp
+++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -306,6 +306,11 @@
     Sign in to sync and personalize Chrome across your devices
   </message>
 
+  <!-- Autofill Assistant settings -->
+  <message name="IDS_SETTINGS_AUTOFILL_ASSISTANT_PREF" translateable="false" desc="The documentation string of the 'Use Google Assistant' preference to help with automated flows on the web">
+    Google Assistant in Chrome
+  </message>
+
   <!-- Languages Page -->
   <if expr="is_win">
     <message name="IDS_SETTINGS_LANGUAGES_IS_DISPLAYED_IN_THIS_LANGUAGE" desc="The label for a language that is currently used as the UI display language.">
diff --git a/chrome/app/shared_settings_strings.grdp b/chrome/app/shared_settings_strings.grdp
index ffb0732..74a7f38 100644
--- a/chrome/app/shared_settings_strings.grdp
+++ b/chrome/app/shared_settings_strings.grdp
@@ -227,6 +227,9 @@
   <message name="IDS_DRIVE_SUGGEST_PREF" desc="The documentation string of the 'Show Drive Results in Omnibox' preference - short description">
     Google Drive search suggestions
   </message>
+  <message name="IDS_SETTINGS_AUTOFILL_ASSISTANT_PREF_DESC" translateable="false" desc="The description of the 'Use Google Assistant' preference to help with automated flows on the web">
+    Helps you complete tasks, such as changing your password, throughout the web
+  </message>
 
   <!-- Sync Accounts page (used by the <settings-sync-account-control> element) -->
   <message name="IDS_SETTINGS_PEOPLE_SYNCING_TO_ACCOUNT" desc="The text displayed to the user that the profile is currently syncing to a specific account.">
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 37f82a4..60104ff5 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -6913,6 +6913,14 @@
     {"media-app-handles-pdf", flag_descriptions::kMediaAppHandlesPdfName,
      flag_descriptions::kMediaAppHandlesPdfDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kMediaAppHandlesPdf)},
+    {"media-app-photos-integration-image",
+     flag_descriptions::kMediaAppPhotosIntegrationImageName,
+     flag_descriptions::kMediaAppPhotosIntegrationImageDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(chromeos::features::kMediaAppPhotosIntegrationImage)},
+    {"media-app-photos-integration-video",
+     flag_descriptions::kMediaAppPhotosIntegrationVideoName,
+     flag_descriptions::kMediaAppPhotosIntegrationVideoDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(chromeos::features::kMediaAppPhotosIntegrationVideo)},
     {"release-notes-notification-all-channels",
      flag_descriptions::kReleaseNotesNotificationAllChannelsName,
      flag_descriptions::kReleaseNotesNotificationAllChannelsDescription,
diff --git a/chrome/browser/apps/app_service/app_service_proxy_base.cc b/chrome/browser/apps/app_service/app_service_proxy_base.cc
index 8e4d492..186bf1d 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_base.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_base.cc
@@ -745,9 +745,12 @@
     for (const auto& delta : deltas) {
       if (delta->readiness != Readiness::kUnknown &&
           !apps_util::IsInstalled(delta->readiness)) {
-        // TODO(crbug.com/1253250): Remove dependency on mojom AppService.
-        app_service_->RemovePreferredApp(
-            ConvertAppTypeToMojomAppType(delta->app_type), delta->app_id);
+        if (preferred_apps_impl_) {
+          preferred_apps_impl_->RemovePreferredApp(delta->app_id);
+        } else {
+          app_service_->RemovePreferredApp(
+              ConvertAppTypeToMojomAppType(delta->app_type), delta->app_id);
+        }
       }
     }
   }
@@ -763,7 +766,11 @@
     for (const auto& delta : deltas) {
       if (delta->readiness != apps::mojom::Readiness::kUnknown &&
           !apps_util::IsInstalled(delta->readiness)) {
-        app_service_->RemovePreferredApp(delta->app_type, delta->app_id);
+        if (preferred_apps_impl_) {
+          preferred_apps_impl_->RemovePreferredApp(delta->app_id);
+        } else {
+          app_service_->RemovePreferredApp(delta->app_type, delta->app_id);
+        }
       }
     }
   }
diff --git a/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc b/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc
index e38d4f3f..b91be1c 100644
--- a/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc
+++ b/chrome/browser/ash/accessibility/accessibility_manager_browsertest.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_test_util.h"
 #include "chrome/browser/supervised_user/supervised_user_constants.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension_constants.h"
@@ -1300,10 +1301,12 @@
   }
 
   void StartUserSession(const AccountId& account_id) {
-    ProfileHelper::GetProfileByUserIdHashForTest(
-        user_manager::UserManager::Get()
-            ->FindUser(account_id)
-            ->username_hash());
+    profiles::testing::CreateProfileSync(
+        g_browser_process->profile_manager(),
+        ProfileHelper::GetProfilePathByUserIdHash(
+            user_manager::UserManager::Get()
+                ->FindUser(account_id)
+                ->username_hash()));
 
     auto* session_manager = session_manager::SessionManager::Get();
     session_manager->NotifyUserProfileLoaded(account_id);
diff --git a/chrome/browser/ash/accessibility/magnification_manager_browsertest.cc b/chrome/browser/ash/accessibility/magnification_manager_browsertest.cc
index e641602..b7f2592e 100644
--- a/chrome/browser/ash/accessibility/magnification_manager_browsertest.cc
+++ b/chrome/browser/ash/accessibility/magnification_manager_browsertest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_test_util.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
@@ -90,17 +91,22 @@
   // To prepare a non-new profile for tests, we must ensure the profile
   // directory and the preference files are created, because that's what
   // Profile::IsNewProfile() checks. CreateSession(), however, does not yet
-  // create the profile directory until GetProfileByUserIdHashForTest() is
-  // called.
-  ProfileHelper::Get()->GetProfileByUserIdHashForTest(
-      account_id.GetUserEmail());
+  // create the profile directory, so create the profile actually here.
+  profiles::testing::CreateProfileSync(
+      g_browser_process->profile_manager(),
+      ProfileHelper::GetProfilePathByUserIdHash(user_manager::UserManager::Get()
+                                                    ->FindUser(account_id)
+                                                    ->username_hash()));
 }
 
 // Simulates how UserSessionManager starts a user session by loading user
 // profile, notify user profile is loaded, and mark session as started.
 void StartUserSession(const AccountId& account_id) {
-  ProfileHelper::GetProfileByUserIdHashForTest(
-      user_manager::UserManager::Get()->FindUser(account_id)->username_hash());
+  profiles::testing::CreateProfileSync(
+      g_browser_process->profile_manager(),
+      ProfileHelper::GetProfilePathByUserIdHash(user_manager::UserManager::Get()
+                                                    ->FindUser(account_id)
+                                                    ->username_hash()));
 
   auto* session_manager = session_manager::SessionManager::Get();
   session_manager->NotifyUserProfileLoaded(account_id);
@@ -160,6 +166,7 @@
     command_line->AppendSwitch(switches::kLoginManager);
     command_line->AppendSwitchASCII(switches::kLoginProfile,
                                     TestingProfile::kTestUserProfileDir);
+    command_line->AppendSwitch(switches::kAllowFailedPolicyFetchForTest);
   }
 
   void SetUpOnMainThread() override {
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc
index 834a269..70bc0de 100644
--- a/chrome/browser/ash/crosapi/browser_util.cc
+++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -75,12 +75,14 @@
     case user_manager::USER_TYPE_REGULAR:
     case user_manager::USER_TYPE_WEB_KIOSK_APP:
     case user_manager::USER_TYPE_PUBLIC_ACCOUNT:
+    // Note: Lacros will not be enabled for Guest users unless LacrosSupport
+    // flag is passed in --enable-features. See https://crbug.com/1294051#c25.
+    case user_manager::USER_TYPE_GUEST:
       return true;
     case user_manager::USER_TYPE_CHILD:
       return base::FeatureList::IsEnabled(kLacrosForSupervisedUsers);
     case user_manager::USER_TYPE_KIOSK_APP:
       return base::FeatureList::IsEnabled(features::kChromeKioskEnableLacros);
-    case user_manager::USER_TYPE_GUEST:
     case user_manager::USER_TYPE_ARC_KIOSK_APP:
     case user_manager::USER_TYPE_ACTIVE_DIRECTORY:
     case user_manager::NUM_USER_TYPES:
diff --git a/chrome/browser/ash/crostini/crostini_installer.cc b/chrome/browser/ash/crostini/crostini_installer.cc
index 3b39512..f74919f8 100644
--- a/chrome/browser/ash/crostini/crostini_installer.cc
+++ b/chrome/browser/ash/crostini/crostini_installer.cc
@@ -213,6 +213,7 @@
   }
 
   restart_options_ = std::move(options);
+  restart_options_.restart_source = RestartSource::kInstaller;
   progress_callback_ = std::move(progress_callback);
   result_callback_ = std::move(result_callback);
 
diff --git a/chrome/browser/ash/crostini/crostini_manager.cc b/chrome/browser/ash/crostini/crostini_manager.cc
index adf16b4..0d93613 100644
--- a/chrome/browser/ash/crostini/crostini_manager.cc
+++ b/chrome/browser/ash/crostini/crostini_manager.cc
@@ -221,9 +221,10 @@
 
   void AddRequest(RestartRequest request);
 
-  // Start the restart flow. This should only be called once. This cannot be
-  // called directly from the constructor as in some cases it immediately
-  // (synchronously) fails and causes |this| to be deleted.
+  // Start the restart flow. This should called immediately following
+  // construction and only once. This cannot be called directly from the
+  // constructor as in some cases it immediately (synchronously) fails and
+  // causes |this| to be deleted.
   void Restart();
 
   // ash::VmShutdownObserver
@@ -300,7 +301,7 @@
   // restart (deleting |this|), and return true.
   bool MaybeCancelCurrentOperation();
 
-  void LogRestarterResult(CrostiniResult result);
+  void LogRestarterResult(const RestartRequest& request, CrostiniResult result);
 
   base::OneShotTimer stage_timeout_timer_;
   base::TimeTicks stage_start_;
@@ -368,8 +369,8 @@
   if (!requests_.empty()) {
     // This is triggered by logging out when restarts are in progress.
     LOG(WARNING) << "Destroying with outstanding requests.";
-    for (int i = 0; i < requests_.size(); i++) {
-      LogRestarterResult(CrostiniResult::NEVER_FINISHED);
+    for (const auto& request : requests_) {
+      LogRestarterResult(request, CrostiniResult::NEVER_FINISHED);
     }
   }
 }
@@ -384,13 +385,12 @@
   }
 
   crostini_manager_->AddVmShutdownObserver(this);
-  // TODO(timloh): This is currently false for additional containers created via
-  // settings, but we probably don't want those to be bucketed in the same
-  // histograms as other non-install restarts.
   // TODO(b/205650706): It is possible to invoke a CrostiniRestarter to install
   // Crostini without using the actual installer. We should handle these better.
+  RestartSource restart_source = requests_[0].options.restart_source;
   is_initial_install_ =
-      crostini_manager_->GetCrostiniDialogStatus(DialogType::INSTALLER);
+      restart_source == RestartSource::kInstaller ||
+      restart_source == RestartSource::kMultiContainerCreation;
 
   StartStage(mojom::InstallerState::kStart);
   if (ReturnEarlyIfNeeded()) {
@@ -621,13 +621,13 @@
       continue;
     }
 
+    LogRestarterResult(*it, result);
+
     crostini_manager_->RemoveRestartId(it->restart_id);
     if (it->observer)
       observer_list_.RemoveObserver(it->observer);
     callbacks.push_back(std::move(it->callback));
     requests_.erase(it);
-
-    LogRestarterResult(result);
   }
 
   return base::BindOnce(
@@ -962,13 +962,36 @@
 }
 
 void CrostiniManager::CrostiniRestarter::LogRestarterResult(
+    const RestartRequest& request,
     CrostiniResult result) {
-  // Separate Crostini installer restarts from already-installed restarts.
-  // The installer has separate histograms in Crostini.SetupResult.
-  // TODO(timloh): The installer histograms are less granular, we might want to
-  // also log something here.
-  if (!is_initial_install_) {
-    base::UmaHistogramEnumeration("Crostini.RestarterResult", result);
+  // Log different histograms depending on the restart source. For an initial
+  // install, only log for the first request. The Crostini installer also has
+  // separate histograms in Crostini.SetupResult.
+  switch (request.options.restart_source) {
+    default:
+      NOTREACHED();
+      [[fallthrough]];
+    case RestartSource::kOther:
+      if (is_initial_install_)
+        return;
+      base::UmaHistogramEnumeration("Crostini.RestarterResult", result);
+      return;
+    case RestartSource::kInstaller:
+      if (!is_initial_install_) {
+        LOG(WARNING)
+            << "Restart request from Crostini installer was not first request.";
+      }
+      base::UmaHistogramEnumeration("Crostini.RestarterResult.Installer",
+                                    result);
+      return;
+    case RestartSource::kMultiContainerCreation:
+      if (!is_initial_install_) {
+        LOG(WARNING) << "Restart request for multi-container creation was not "
+                        "first request.";
+      }
+      base::UmaHistogramEnumeration(
+          "Crostini.RestarterResult.MultiContainerCreation", result);
+      return;
   }
 }
 
diff --git a/chrome/browser/ash/crostini/crostini_manager.h b/chrome/browser/ash/crostini/crostini_manager.h
index f2ad925..3b2b71f4 100644
--- a/chrome/browser/ash/crostini/crostini_manager.h
+++ b/chrome/browser/ash/crostini/crostini_manager.h
@@ -189,6 +189,7 @@
   };
 
   struct RestartOptions {
+    RestartSource restart_source = RestartSource::kOther;
     bool start_vm_only = false;
     bool stop_after_lxd_available = false;
     // Paths to share with VM on startup.
diff --git a/chrome/browser/ash/crostini/crostini_manager_unittest.cc b/chrome/browser/ash/crostini/crostini_manager_unittest.cc
index 7dbba449..1ed0404 100644
--- a/chrome/browser/ash/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/ash/crostini/crostini_manager_unittest.cc
@@ -1441,6 +1441,49 @@
   EXPECT_FALSE(crostini_manager()->IsRestartPending(id3));
 }
 
+TEST_F(CrostiniManagerRestartTest, InstallHistogramEntries) {
+  // When the first request is tagged as RestartSource::kInstaller, we should
+  // log a single result to Crostini.RestarterResult.Installer and no results
+  // to Crostini.RestartResult even if there were additional requests.
+
+  vm_tools::concierge::StartVmResponse response;
+  response.set_status(vm_tools::concierge::VmStatus::VM_STATUS_FAILURE);
+  fake_concierge_client_->set_start_vm_response(response);
+
+  auto barrier_closure = base::BarrierClosure(2, run_loop()->QuitClosure());
+  auto result_callback =
+      base::BindLambdaForTesting([&barrier_closure](CrostiniResult result) {
+        EXPECT_EQ(CrostiniResult::VM_START_FAILED, result);
+        barrier_closure.Run();
+      });
+  CrostiniManager::RestartOptions options1;
+  options1.restart_source = RestartSource::kInstaller;
+  crostini_manager()->RestartCrostiniWithOptions(
+      container_id(), std::move(options1), result_callback);
+  crostini_manager()->RestartCrostini(container_id(), result_callback);
+  run_loop()->Run();
+
+  histogram_tester_.ExpectBucketCount("Crostini.RestarterResult.Installer",
+                                      CrostiniResult::VM_START_FAILED, 1);
+  histogram_tester_.ExpectTotalCount("Crostini.RestarterResult", 0);
+
+  // Likewise for RestartSource::kMultiContainerCreation
+  base::RunLoop run_loop2;
+  barrier_closure = base::BarrierClosure(2, run_loop2.QuitClosure());
+  CrostiniManager::RestartOptions options2;
+  options2.restart_source = RestartSource::kMultiContainerCreation;
+  crostini_manager()->RestartCrostiniWithOptions(
+      container_id(), std::move(options2), result_callback);
+  crostini_manager()->RestartCrostini(container_id(), result_callback);
+  run_loop2.Run();
+
+  histogram_tester_.ExpectBucketCount(
+      "Crostini.RestarterResult.MultiContainerCreation",
+      CrostiniResult::VM_START_FAILED, 1);
+  histogram_tester_.ExpectTotalCount("Crostini.RestarterResult.Installer", 1);
+  histogram_tester_.ExpectTotalCount("Crostini.RestarterResult", 0);
+}
+
 TEST_F(CrostiniManagerRestartTest, IsContainerRunningFalseIfVmNotStarted) {
   restart_id_ = crostini_manager()->RestartCrostini(
       container_id(),
diff --git a/chrome/browser/ash/crostini/crostini_simple_types.h b/chrome/browser/ash/crostini/crostini_simple_types.h
index 622a2d4..b549f4b 100644
--- a/chrome/browser/ash/crostini/crostini_simple_types.h
+++ b/chrome/browser/ash/crostini/crostini_simple_types.h
@@ -110,6 +110,12 @@
 using CrostiniSuccessCallback =
     base::OnceCallback<void(bool success, const std::string& failure_reason)>;
 
+enum class RestartSource {
+  kOther,
+  kInstaller,
+  kMultiContainerCreation,
+};
+
 enum class InstallLinuxPackageProgressStatus {
   SUCCEEDED,
   FAILED,
diff --git a/chrome/browser/ash/crostini/crostini_terminal.cc b/chrome/browser/ash/crostini/crostini_terminal.cc
index f42ceae..5b329732 100644
--- a/chrome/browser/ash/crostini/crostini_terminal.cc
+++ b/chrome/browser/ash/crostini/crostini_terminal.cc
@@ -47,12 +47,14 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "net/base/url_util.h"
 #include "storage/browser/file_system/external_mount_points.h"
 #include "storage/browser/file_system/file_system_url.h"
 #include "ui/base/base_window.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/color/color_provider_manager.h"
+#include "ui/color/color_provider_utils.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/native_theme/native_theme.h"
 
@@ -74,8 +76,13 @@
 constexpr char kSettingPrefix[] = "/hterm/profiles/default/";
 const size_t kSettingPrefixSize = std::size(kSettingPrefix) - 1;
 
-constexpr char kSettingBackgroundColor[] =
-    "/hterm/profiles/default/background-color";
+constexpr char kSettingsProfileUrlParam[] = "settings_profile";
+constexpr char kSettingsPrefixHterm[] = "hterm";
+constexpr char kSettingsPrefixNassh[] = "nassh";
+constexpr char kSettingsPrefixVsh[] = "vsh";
+constexpr char kSettingsKeyBackgroundColor[] = "background-color";
+constexpr char kSettingsKeyTerminalProfile[] = "terminal-profile";
+constexpr char kSettingsProfileDefault[] = "default";
 constexpr char kDefaultBackgroundColor[] = "#202124";
 
 constexpr char kSettingPassCtrlW[] = "/hterm/profiles/default/pass-ctrl-w";
@@ -90,6 +97,12 @@
   return extras;
 }
 
+std::string GetSettingsKey(const std::string& prefix,
+                           const std::string& profile,
+                           const std::string& key) {
+  return base::StrCat({"/", prefix, "/profiles/", profile, "/", key});
+}
+
 void LaunchTerminalImpl(Profile* profile,
                         const GURL& url,
                         apps::AppLaunchParams params) {
@@ -157,14 +170,21 @@
 }
 
 GURL GenerateTerminalURL(Profile* profile,
+                         const std::string& settings_profile,
                          const ContainerId& container_id,
                          const std::string& cwd,
                          const std::vector<std::string>& terminal_args) {
   auto escape = [](std::string param) {
     return base::EscapeQueryParamValue(param, /*use_plus=*/true);
   };
+  std::string settings_profile_param;
+  if (!settings_profile.empty()) {
+    settings_profile_param = base::StrCat(
+        {"&", kSettingsProfileUrlParam, "=", escape(settings_profile)});
+  }
   std::string start = base::StrCat({chrome::kChromeUIUntrustedTerminalURL,
-                                    "html/terminal.html?command=vmshell"});
+                                    "html/terminal.html?command=vmshell",
+                                    settings_profile_param});
   std::string vm_name_param =
       escape(base::StringPrintf("--vm_name=%s", container_id.vm_name.c_str()));
   std::string container_name_param = escape(base::StringPrintf(
@@ -194,7 +214,8 @@
                     const ContainerId& container_id,
                     const std::string& cwd,
                     const std::vector<std::string>& terminal_args) {
-  GURL url = GenerateTerminalURL(profile, container_id, cwd, terminal_args);
+  GURL url = GenerateTerminalURL(profile, /*settings_profile=*/std::string(),
+                                 container_id, cwd, terminal_args);
   LaunchTerminalWithUrl(profile, display_id, url);
 }
 
@@ -243,14 +264,17 @@
     return std::move(callback).Run(false, "Crostini not installed");
   }
 
-  // Look for vm_name and container_name in intent->extras.
+  // Look for vm_name, container_name, and settings_profile in intent->extras.
   ContainerId container_id = ContainerId::GetDefault();
+  std::string settings_profile;
   if (intent && intent->extras.has_value()) {
     for (const auto& extra : intent->extras.value()) {
       if (extra.first == "vm_name") {
         container_id.vm_name = extra.second;
       } else if (extra.first == "container_name") {
         container_id.container_name = extra.second;
+      } else if (extra.first == kSettingsProfileUrlParam) {
+        settings_profile = extra.second;
       }
     }
   }
@@ -290,7 +314,9 @@
 
   CrostiniManager::GetForProfile(profile)->RestartCrostiniWithOptions(
       container_id, std::move(options), base::DoNothing());
-  LaunchTerminal(profile, display_id, container_id, cwd);
+  GURL url = GenerateTerminalURL(profile, settings_profile, container_id, cwd,
+                                 /*terminal_args=*/{});
+  LaunchTerminalWithUrl(profile, display_id, url);
   std::move(callback).Run(true, "");
 }
 
@@ -412,10 +438,34 @@
   }
 }
 
-std::string GetTerminalSettingBackgroundColor(Profile* profile) {
-  const base::Value* value = profile->GetPrefs()->GetDictionary(
+std::string GetTerminalSettingBackgroundColor(
+    Profile* profile,
+    GURL url,
+    absl::optional<SkColor> opener_background_color) {
+  auto key = [](const std::string& profile) {
+    return GetSettingsKey(kSettingsPrefixHterm, profile,
+                          kSettingsKeyBackgroundColor);
+  };
+  const base::Value* settings = profile->GetPrefs()->GetDictionary(
       crostini::prefs::kCrostiniTerminalSettings);
-  const std::string* result = value->FindStringKey(kSettingBackgroundColor);
+  // 1. Use 'settings_profile' url param.
+  std::string settings_profile;
+  if (net::GetValueForKeyInQuery(url, kSettingsProfileUrlParam,
+                                 &settings_profile)) {
+    const std::string* result = settings->FindStringKey(key(settings_profile));
+    if (result) {
+      return *result;
+    }
+  }
+
+  // 2. Use same color as opener.
+  if (opener_background_color) {
+    return ui::ConvertSkColorToCSSColor(*opener_background_color);
+  }
+
+  // 3. Use 'default' profile color, or default color.
+  const std::string* result =
+      settings->FindStringKey(key(kSettingsProfileDefault));
   return result ? *result : kDefaultBackgroundColor;
 }
 
@@ -434,9 +484,35 @@
   return shortcut_id;
 }
 
-std::string ShortcutIdFromContainerId(const crostini::ContainerId& id) {
+std::string ShortcutIdFromContainerId(Profile* profile,
+                                      const crostini::ContainerId& id) {
   base::Value::Dict dict = id.ToDictValue();
   dict.Set(kShortcutKey, base::Value(kShortcutValueTerminal));
+
+  // Find terminal profile from prefs.
+  const base::Value::Dict& settings =
+      profile->GetPrefs()
+          ->GetDictionary(crostini::prefs::kCrostiniTerminalSettings)
+          ->GetDict();
+  const base::Value::List* vsh_ids = settings.FindList("/vsh/profile-ids");
+  if (vsh_ids) {
+    for (const auto& vsh_id : *vsh_ids) {
+      if (!vsh_id.is_string()) {
+        continue;
+      }
+      const std::string* vm_name = settings.FindString(
+          GetSettingsKey(kSettingsPrefixVsh, vsh_id.GetString(), "vm-name"));
+      const std::string* container_name = settings.FindString(GetSettingsKey(
+          kSettingsPrefixVsh, vsh_id.GetString(), "container-name"));
+      const std::string* settings_profile = settings.FindString(GetSettingsKey(
+          kSettingsPrefixVsh, vsh_id.GetString(), "terminal-profile"));
+      if (vm_name && *vm_name == id.vm_name && container_name &&
+          *container_name == id.container_name && settings_profile) {
+        dict.Set(kSettingsProfileUrlParam, *settings_profile);
+      }
+    }
+  }
+
   std::string shortcut_id;
   base::JSONWriter::Write(dict, &shortcut_id);
   return shortcut_id;
@@ -458,7 +534,7 @@
       continue;
     }
     const std::string* description = settings.FindString(
-        base::StrCat({"/nassh/profiles/", id.GetString(), "/description"}));
+        GetSettingsKey(kSettingsPrefixNassh, id.GetString(), "description"));
     if (description) {
       result.emplace_back(id.GetString(), *description);
     }
@@ -501,12 +577,6 @@
     apps::AddSeparator(ui::DOUBLE_SEPARATOR, &menu_items);
   }
 
-  for (const auto& connection : connections) {
-    apps::AddShortcutCommandItem(
-        next_command_id++, ShortcutIdForSSH(connection.first),
-        connection.second, terminal_ssh_icon, &menu_items);
-  }
-
   for (const auto& container : containers) {
     // Use <container_name> for termina, else <vm_name>:<container_name>.
     std::string label = container.container_name;
@@ -514,8 +584,14 @@
       label = base::StrCat({container.vm_name, ":", container.container_name});
     }
     apps::AddShortcutCommandItem(next_command_id++,
-                                 ShortcutIdFromContainerId(container), label,
-                                 crostini_mascot_icon, &menu_items);
+                                 ShortcutIdFromContainerId(profile, container),
+                                 label, crostini_mascot_icon, &menu_items);
+  }
+
+  for (const auto& connection : connections) {
+    apps::AddShortcutCommandItem(
+        next_command_id++, ShortcutIdForSSH(connection.first),
+        connection.second, terminal_ssh_icon, &menu_items);
   }
 
   std::move(callback).Run(std::move(menu_items));
@@ -534,10 +610,24 @@
     if (!profileId) {
       return false;
     }
+    const base::Value* settings = profile->GetPrefs()->GetDictionary(
+        crostini::prefs::kCrostiniTerminalSettings);
+    const std::string* settings_profile =
+        settings->FindStringKey(GetSettingsKey(kSettingsPrefixNassh, *profileId,
+                                               kSettingsKeyTerminalProfile));
+    auto escape = [](const std::string& v) {
+      return base::EscapeQueryParamValue(v, /*use_plus=*/true);
+    };
+    std::string settings_profile_param;
+    if (settings_profile && !settings_profile->empty()) {
+      settings_profile_param = base::StrCat(
+          {"?", kSettingsProfileUrlParam, "=", escape(*settings_profile)});
+    }
     LaunchTerminalWithUrl(
         profile, display_id,
         GURL(base::StrCat({chrome::kChromeUIUntrustedTerminalURL,
-                           "html/terminal_ssh.html#profile-id:", *profileId})));
+                           "html/terminal_ssh.html", settings_profile_param,
+                           "#profile-id:", escape(*profileId)})));
     return true;
   }
 
diff --git a/chrome/browser/ash/crostini/crostini_terminal.h b/chrome/browser/ash/crostini/crostini_terminal.h
index 44c3f2d..c647518 100644
--- a/chrome/browser/ash/crostini/crostini_terminal.h
+++ b/chrome/browser/ash/crostini/crostini_terminal.h
@@ -117,6 +117,7 @@
 // Generate URL to launch terminal.
 GURL GenerateTerminalURL(
     Profile* profile,
+    const std::string& setings_profile,
     const ContainerId& container_id = ContainerId::GetDefault(),
     const std::string& cwd = "",
     const std::vector<std::string>& terminal_args = {});
@@ -146,8 +147,11 @@
 // Record which terminal settings have been changed by users.
 void RecordTerminalSettingsChangesUMAs(Profile* profile);
 
-// Returns terminal setting 'background-color'.
-std::string GetTerminalSettingBackgroundColor(Profile* profile);
+// Returns terminal setting 'background-color' to use for |url|.
+std::string GetTerminalSettingBackgroundColor(
+    Profile* profile,
+    GURL url,
+    absl::optional<SkColor> opener_background_color);
 
 // Returns terminal setting 'pass-ctrl-w'.
 bool GetTerminalSettingPassCtrlW(Profile* profile);
@@ -156,7 +160,8 @@
 std::string ShortcutIdForSSH(const std::string& profileId);
 
 // Menu shortcut ID for Linux container.
-std::string ShortcutIdFromContainerId(const crostini::ContainerId& id);
+std::string ShortcutIdFromContainerId(Profile* profile,
+                                      const crostini::ContainerId& id);
 
 // Returns list of SSH connections {<profile-id>, <description>}.
 std::vector<std::pair<std::string, std::string>> GetSSHConnections(
diff --git a/chrome/browser/ash/crostini/crostini_terminal_unittest.cc b/chrome/browser/ash/crostini/crostini_terminal_unittest.cc
index a769841..3c3f47f 100644
--- a/chrome/browser/ash/crostini/crostini_terminal_unittest.cc
+++ b/chrome/browser/ash/crostini/crostini_terminal_unittest.cc
@@ -12,21 +12,65 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
 
 namespace crostini {
 
 using CrostiniTerminalTest = testing::Test;
 
+TEST_F(CrostiniTerminalTest, GenerateTerminalURL) {
+  content::BrowserTaskEnvironment task_environment;
+  TestingProfile profile;
+  EXPECT_EQ(
+      GenerateTerminalURL(&profile, "", ContainerId::GetDefault(), "", {}),
+      "chrome-untrusted://terminal/html/terminal.html"
+      "?command=vmshell"
+      "&args[]=--vm_name%3Dtermina"
+      "&args[]=--target_container%3Dpenguin"
+      "&args[]=--owner_id%3Dtest");
+  EXPECT_EQ(GenerateTerminalURL(&profile, "red",
+                                ContainerId("test-vm", "test-container"),
+                                "/home/user", {"arg1"}),
+            "chrome-untrusted://terminal/html/terminal.html"
+            "?command=vmshell"
+            "&settings_profile=red"
+            "&args[]=--vm_name%3Dtest-vm"
+            "&args[]=--target_container%3Dtest-container"
+            "&args[]=--owner_id%3Dtest"
+            "&args[]=--cwd%3D%2Fhome%2Fuser"
+            "&args[]=--&args[]=arg1");
+}
+
 TEST_F(CrostiniTerminalTest, ShortcutIdForSSH) {
   EXPECT_EQ(ShortcutIdForSSH("test-profile"),
             R"({"profileId":"test-profile","shortcut":"ssh"})");
 }
 
 TEST_F(CrostiniTerminalTest, ShortcutIdFromContainerId) {
+  content::BrowserTaskEnvironment task_environment;
+  TestingProfile profile;
   ContainerId id("test-vm", "test-container");
-  EXPECT_EQ(ShortcutIdFromContainerId(id),
+  EXPECT_EQ(ShortcutIdFromContainerId(&profile, id),
             R"({"container_name":"test-container","shortcut":"terminal",)"
             R"("vm_name":"test-vm"})");
+
+  // Container with multi-profile should include settings_profile.
+  auto pref = base::JSONReader::Read(R"({
+    "/vsh/profile-ids": ["p1", "p2"],
+    "/vsh/profiles/p1/vm-name": "test-vm",
+    "/vsh/profiles/p1/container-name": "other-container",
+    "/vsh/profiles/p1/terminal-profile": "red",
+    "/vsh/profiles/p2/vm-name": "test-vm",
+    "/vsh/profiles/p2/container-name": "test-container",
+    "/vsh/profiles/p2/terminal-profile": "green"
+  })");
+  ASSERT_TRUE(pref.has_value());
+  profile.GetPrefs()->Set(prefs::kCrostiniTerminalSettings, std::move(*pref));
+  EXPECT_EQ(ShortcutIdFromContainerId(&profile, id),
+            R"({"container_name":"test-container",)"
+            R"("settings_profile":"green",)"
+            R"("shortcut":"terminal",)"
+            R"("vm_name":"test-vm"})");
 }
 
 TEST_F(CrostiniTerminalTest, GetSSHConnections) {
@@ -48,4 +92,47 @@
   EXPECT_EQ(GetSSHConnections(&profile), expected);
 }
 
+TEST_F(CrostiniTerminalTest, GetTerminalSettingBackgroundColor) {
+  content::BrowserTaskEnvironment task_environment;
+  TestingProfile profile;
+
+  auto pref = base::JSONReader::Read(R"({
+    "/hterm/profiles/default/background-color": "#101010",
+    "/hterm/profiles/red/background-color": "#FF0000"
+  })");
+  ASSERT_TRUE(pref.has_value());
+  profile.GetPrefs()->Set(prefs::kCrostiniTerminalSettings, std::move(*pref));
+
+  // Use settings_profile param.
+  EXPECT_EQ(GetTerminalSettingBackgroundColor(
+                &profile,
+                GURL("chrome-untrusted://terminal/html/"
+                     "terminal.html?settings_profile=red"),
+                SK_ColorGREEN),
+            "#FF0000");
+
+  // Use opener color.
+  EXPECT_EQ(
+      GetTerminalSettingBackgroundColor(
+          &profile, GURL("chrome-untrusted://terminal/html/terminal.html"),
+          SK_ColorGREEN),
+      "#00ff00ff");
+
+  // Use color from 'default' profile.
+  EXPECT_EQ(
+      GetTerminalSettingBackgroundColor(
+          &profile, GURL("chrome-untrusted://terminal/html/terminal.html"),
+          absl::nullopt),
+      "#101010");
+
+  // Use default color.
+  profile.GetPrefs()->Set(prefs::kCrostiniTerminalSettings,
+                          base::Value(base::Value::Type::DICT));
+  EXPECT_EQ(
+      GetTerminalSettingBackgroundColor(
+          &profile, GURL("chrome-untrusted://terminal/html/terminal.html"),
+          absl::nullopt),
+      "#202124");
+}
+
 }  // namespace crostini
diff --git a/chrome/browser/ash/file_manager/extract_io_task.cc b/chrome/browser/ash/file_manager/extract_io_task.cc
index a81f2011..7d183813 100644
--- a/chrome/browser/ash/file_manager/extract_io_task.cc
+++ b/chrome/browser/ash/file_manager/extract_io_task.cc
@@ -29,10 +29,12 @@
 
 ExtractIOTask::ExtractIOTask(
     std::vector<storage::FileSystemURL> source_urls,
+    std::string password,
     storage::FileSystemURL parent_folder,
     Profile* profile,
     scoped_refptr<storage::FileSystemContext> file_system_context)
     : source_urls_(std::move(source_urls)),
+      password_(std::move(password)),
       parent_folder_(std::move(parent_folder)),
       profile_(profile),
       file_system_context_(std::move(file_system_context)) {
@@ -111,7 +113,7 @@
     bool created_ok) {
   if (created_ok) {
     unzip::mojom::UnzipOptionsPtr options =
-        unzip::mojom::UnzipOptions::New("auto", "");
+        unzip::mojom::UnzipOptions::New("auto", password_);
     unzip::Unzip(
         unzip::LaunchUnzipper(), source_file, destination_directory,
         std::move(options),
@@ -188,6 +190,11 @@
     Complete();
     return;
   }
+  if (have_encrypted_content_ && password_.empty()) {
+    progress_.state = State::kNeedPassword;
+    Complete();
+    return;
+  }
 
   speedometer_.SetTotalBytes(progress_.total_bytes);
   ExtractAllSources();
@@ -198,6 +205,7 @@
   if (info->size_is_valid) {
     progress_.total_bytes += info->size;
   }
+  have_encrypted_content_ = have_encrypted_content_ || info->is_encrypted;
   if (--sizingCount_ == 0) {
     // After getting the size of all the ZIPs, check if we have
     // enough available disk space, and if so, extract them.
diff --git a/chrome/browser/ash/file_manager/extract_io_task.h b/chrome/browser/ash/file_manager/extract_io_task.h
index 2fc95d4..347f67e6 100644
--- a/chrome/browser/ash/file_manager/extract_io_task.h
+++ b/chrome/browser/ash/file_manager/extract_io_task.h
@@ -44,6 +44,7 @@
   // must be under the |parent_folder| directory, and the resulting extraction
   // will be created there.
   ExtractIOTask(std::vector<storage::FileSystemURL> source_urls,
+                std::string password,
                 storage::FileSystemURL parent_folder,
                 Profile* profile,
                 scoped_refptr<storage::FileSystemContext> file_system_context);
@@ -84,6 +85,9 @@
   // URLs of the files that have archives in them for extraction.
   const std::vector<storage::FileSystemURL> source_urls_;
 
+  // Password for decrypting encrypted source_urls_ (one only).
+  const std::string password_;
+
   // Parent folder of the files in 'source_urls_'.
   const storage::FileSystemURL parent_folder_;
 
@@ -100,6 +104,9 @@
   // Counter of the number of archives needing extracted size retrieved.
   size_t sizingCount_;
 
+  // Boolean set to true if we find archives that are encrypted.
+  bool have_encrypted_content_ = false;
+
   // Counter of the number of archives needing extraction.
   size_t extractCount_;
 
diff --git a/chrome/browser/ash/file_manager/file_manager_string_util.cc b/chrome/browser/ash/file_manager/file_manager_string_util.cc
index 4cbf296..3e2a93b 100644
--- a/chrome/browser/ash/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -100,24 +100,14 @@
   SET_STRING("ISO_ARCHIVE_FILE_TYPE", IDS_FILE_BROWSER_ISO_ARCHIVE_FILE_TYPE);
   SET_STRING("7Z_ARCHIVE_FILE_TYPE", IDS_FILE_BROWSER_7Z_ARCHIVE_FILE_TYPE);
   SET_STRING("CRX_ARCHIVE_FILE_TYPE", IDS_FILE_BROWSER_CRX_ARCHIVE_FILE_TYPE);
-  SET_STRING("TAR_BZIP2_ARCHIVE_FILE_TYPE",
-             IDS_FILE_BROWSER_TAR_BZIP2_ARCHIVE_FILE_TYPE);
   SET_STRING("BZIP2_ARCHIVE_FILE_TYPE",
              IDS_FILE_BROWSER_BZIP2_ARCHIVE_FILE_TYPE);
-  SET_STRING("TAR_GZIP_ARCHIVE_FILE_TYPE",
-             IDS_FILE_BROWSER_TAR_GZIP_ARCHIVE_FILE_TYPE);
   SET_STRING("GZIP_ARCHIVE_FILE_TYPE", IDS_FILE_BROWSER_GZIP_ARCHIVE_FILE_TYPE);
-  SET_STRING("TAR_LZMA_ARCHIVE_FILE_TYPE",
-             IDS_FILE_BROWSER_TAR_LZMA_ARCHIVE_FILE_TYPE);
   SET_STRING("LZMA_ARCHIVE_FILE_TYPE", IDS_FILE_BROWSER_LZMA_ARCHIVE_FILE_TYPE);
-  SET_STRING("TAR_XZ_ARCHIVE_FILE_TYPE",
-             IDS_FILE_BROWSER_TAR_XZ_ARCHIVE_FILE_TYPE);
+  SET_STRING("LZIP_ARCHIVE_FILE_TYPE", IDS_FILE_BROWSER_LZIP_ARCHIVE_FILE_TYPE);
+  SET_STRING("LZOP_ARCHIVE_FILE_TYPE", IDS_FILE_BROWSER_LZOP_ARCHIVE_FILE_TYPE);
   SET_STRING("XZ_ARCHIVE_FILE_TYPE", IDS_FILE_BROWSER_XZ_ARCHIVE_FILE_TYPE);
-  SET_STRING("TAR_Z_ARCHIVE_FILE_TYPE",
-             IDS_FILE_BROWSER_TAR_Z_ARCHIVE_FILE_TYPE);
   SET_STRING("Z_ARCHIVE_FILE_TYPE", IDS_FILE_BROWSER_Z_ARCHIVE_FILE_TYPE);
-  SET_STRING("TAR_ZSTD_ARCHIVE_FILE_TYPE",
-             IDS_FILE_BROWSER_TAR_ZSTD_ARCHIVE_FILE_TYPE);
   SET_STRING("ZSTD_ARCHIVE_FILE_TYPE", IDS_FILE_BROWSER_ZSTD_ARCHIVE_FILE_TYPE);
   SET_STRING("VIDEO_FILE_TYPE", IDS_FILE_BROWSER_VIDEO_FILE_TYPE);
   SET_STRING("WORD_DOCUMENT_FILE_TYPE",
diff --git a/chrome/browser/ash/file_manager/file_tasks.cc b/chrome/browser/ash/file_manager/file_tasks.cc
index c072164..ab0e5000 100644
--- a/chrome/browser/ash/file_manager/file_tasks.cc
+++ b/chrome/browser/ash/file_manager/file_tasks.cc
@@ -528,10 +528,11 @@
   // manifest.json is allowed.
   if (!base::FeatureList::IsEnabled(ash::features::kFilesArchivemount2)) {
     for (const auto& entry : entries) {
-      // Deny-list: various compressed formats.
+      // Deny-list: "slow-mounter" compressed formats.
       if (entry.path.MatchesFinalExtension(".bz") ||
           entry.path.MatchesFinalExtension(".bz2") ||
           entry.path.MatchesFinalExtension(".gz") ||
+          entry.path.MatchesFinalExtension(".lz") ||
           entry.path.MatchesFinalExtension(".lzma") ||
           entry.path.MatchesFinalExtension(".taz") ||
           entry.path.MatchesFinalExtension(".tb2") ||
diff --git a/chrome/browser/ash/file_manager/io_task.h b/chrome/browser/ash/file_manager/io_task.h
index 840c941..4dc1f79f 100644
--- a/chrome/browser/ash/file_manager/io_task.h
+++ b/chrome/browser/ash/file_manager/io_task.h
@@ -32,6 +32,9 @@
   // Task has completed with errors.
   kError,
 
+  // Task has failed to finish due to missing password.
+  kNeedPassword,
+
   // Task has been canceled without finishing.
   kCancelled,
 };
diff --git a/chrome/browser/ash/file_manager/path_util_unittest.cc b/chrome/browser/ash/file_manager/path_util_unittest.cc
index 3a57338..74bf6567 100644
--- a/chrome/browser/ash/file_manager/path_util_unittest.cc
+++ b/chrome/browser/ash/file_manager/path_util_unittest.cc
@@ -618,20 +618,22 @@
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
         base::WrapUnique(std::move(fake_user_manager)));
 
-    Profile* primary_profile =
-        profile_manager_->CreateTestingProfile("user@gmail.com");
-    ASSERT_TRUE(primary_profile);
-    ASSERT_TRUE(profile_manager_->CreateTestingProfile("user2@gmail.com"));
-    primary_profile->GetPrefs()->SetString(drive::prefs::kDriveFsProfileSalt,
-                                           "a");
-    primary_profile->GetPrefs()->SetBoolean(
+    primary_profile_ =
+        profile_manager_->CreateTestingProfile(account_id.GetUserEmail());
+    ASSERT_TRUE(primary_profile_);
+    secondary_profile_ =
+        profile_manager_->CreateTestingProfile(account_id_2.GetUserEmail());
+    ASSERT_TRUE(secondary_profile_);
+    primary_profile_->GetPrefs()->SetString(drive::prefs::kDriveFsProfileSalt,
+                                            "a");
+    primary_profile_->GetPrefs()->SetBoolean(
         drive::prefs::kDriveFsPinnedMigrated, true);
 
     // Set up an Arc service manager with a fake file system.
     arc_service_manager_ = std::make_unique<arc::ArcServiceManager>();
-    arc_service_manager_->set_browser_context(primary_profile);
+    arc_service_manager_->set_browser_context(primary_profile_);
     arc::ArcFileSystemOperationRunner::GetFactory()->SetTestingFactoryAndUse(
-        primary_profile,
+        primary_profile_,
         base::BindRepeating(&CreateFileSystemOperationRunnerForTesting));
     arc_service_manager_->arc_bridge_service()->file_system()->SetInstance(
         &fake_file_system_);
@@ -643,16 +645,16 @@
     storage::ExternalMountPoints* mount_points =
         storage::ExternalMountPoints::GetSystemInstance();
     drive::DriveIntegrationService* integration_service =
-        drive::DriveIntegrationServiceFactory::GetForProfile(primary_profile);
+        drive::DriveIntegrationServiceFactory::GetForProfile(primary_profile_);
     drive_mount_point_ = integration_service->GetMountPointPath();
     integration_service->OnMounted(drive_mount_point_);
 
     // Add a crostini mount point for the primary profile.
-    crostini_mount_point_ = GetCrostiniMountDirectory(primary_profile);
-    mount_points->RegisterFileSystem(GetCrostiniMountPointName(primary_profile),
-                                     storage::kFileSystemTypeLocal,
-                                     storage::FileSystemMountOption(),
-                                     crostini_mount_point_);
+    crostini_mount_point_ = GetCrostiniMountDirectory(primary_profile_);
+    mount_points->RegisterFileSystem(
+        GetCrostiniMountPointName(primary_profile_),
+        storage::kFileSystemTypeLocal, storage::FileSystemMountOption(),
+        crostini_mount_point_);
 
     ash::disks::DiskMountManager::InitializeForTesting(
         new FakeDiskMountManager);
@@ -674,7 +676,7 @@
     ASSERT_TRUE(mount_points->RegisterFileSystem(
         kShareCacheMountPointName, storage::kFileSystemTypeLocal,
         storage::FileSystemMountOption(),
-        util::GetShareCacheFilePath(primary_profile)));
+        util::GetShareCacheFilePath(primary_profile_)));
 
     // Run pending async tasks resulting from profile construction to ensure
     // these are complete before the test begins.
@@ -699,6 +701,8 @@
   content::BrowserTaskEnvironment task_environment_;
   arc::FakeFileSystemInstance fake_file_system_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
+  TestingProfile* primary_profile_;
+  TestingProfile* secondary_profile_;
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
   std::unique_ptr<arc::ArcServiceManager> arc_service_manager_;
   base::FilePath drive_mount_point_;
@@ -743,9 +747,7 @@
   base::test::ScopedRunningOnChromeOS running_on_chromeos;
   GURL url;
   bool requires_sharing = false;
-  const base::FilePath myfiles = GetMyFilesFolderForProfile(
-      ash::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
-          "user@gmail.com-hash"));
+  const base::FilePath myfiles = GetMyFilesFolderForProfile(primary_profile_);
   EXPECT_TRUE(ConvertPathToArcUrl(myfiles.AppendASCII("a/b/c"), &url,
                                   &requires_sharing));
   EXPECT_EQ(GURL("content://org.chromium.arc.volumeprovider/"
@@ -770,9 +772,8 @@
   // Non-primary profile's downloads folder is not supported for ARC yet.
   GURL url;
   bool requires_sharing = false;
-  const base::FilePath downloads2 = GetDownloadsFolderForProfile(
-      ash::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
-          "user2@gmail.com-hash"));
+  const base::FilePath downloads2 =
+      GetDownloadsFolderForProfile(secondary_profile_);
   EXPECT_FALSE(ConvertPathToArcUrl(downloads2.AppendASCII("a/b/c"), &url,
                                    &requires_sharing));
   EXPECT_FALSE(requires_sharing);
@@ -879,9 +880,7 @@
 
 TEST_F(FileManagerPathUtilConvertUrlTest, ConvertToContentUrls_MyFiles) {
   base::test::ScopedRunningOnChromeOS running_on_chromeos;
-  const base::FilePath myfiles = GetMyFilesFolderForProfile(
-      ash::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
-          "user@gmail.com-hash"));
+  const base::FilePath myfiles = GetMyFilesFolderForProfile(primary_profile_);
   base::RunLoop run_loop;
   ConvertToContentUrls(
       ProfileManager::GetPrimaryUserProfile(),
@@ -920,9 +919,8 @@
 }
 
 TEST_F(FileManagerPathUtilConvertUrlTest, ConvertToContentUrls_Downloads) {
-  const base::FilePath downloads = GetDownloadsFolderForProfile(
-      ash::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
-          "user@gmail.com-hash"));
+  const base::FilePath downloads =
+      GetDownloadsFolderForProfile(primary_profile_);
   base::RunLoop run_loop;
   ConvertToContentUrls(
       ProfileManager::GetPrimaryUserProfile(),
@@ -944,9 +942,8 @@
 
 TEST_F(FileManagerPathUtilConvertUrlTest,
        ConvertToContentUrls_InvalidDownloads) {
-  const base::FilePath downloads = GetDownloadsFolderForProfile(
-      ash::ProfileHelper::Get()->GetProfileByUserIdHashForTest(
-          "user2@gmail.com-hash"));
+  const base::FilePath downloads =
+      GetDownloadsFolderForProfile(secondary_profile_);
   base::RunLoop run_loop;
   ConvertToContentUrls(
       ProfileManager::GetPrimaryUserProfile(),
diff --git a/chrome/browser/ash/input_method/longpress_diacritics_suggester.cc b/chrome/browser/ash/input_method/longpress_diacritics_suggester.cc
index 0671bce..753f94b 100644
--- a/chrome/browser/ash/input_method/longpress_diacritics_suggester.cc
+++ b/chrome/browser/ash/input_method/longpress_diacritics_suggester.cc
@@ -139,7 +139,14 @@
     const std::u16string& text,
     int cursor_pos,
     int anchor_pos) {
-  // TODO(b/217560706): Should dismiss when surrounding text changes.
+  if (displayed_window_base_character_ == absl::nullopt ||
+      text_changed_since_longpress_ || anchor_pos != cursor_pos ||
+      cursor_pos <= 0 || cursor_pos > text.size() ||
+      text[cursor_pos - 1] != *displayed_window_base_character_) {
+    return false;
+  }
+
+  text_changed_since_longpress_ = true;
   return true;
 }
 
@@ -241,6 +248,7 @@
 }
 
 void LongpressDiacriticsSuggester::Reset() {
+  text_changed_since_longpress_ = false;
   displayed_window_base_character_ = absl::nullopt;
   highlighted_index_ = absl::nullopt;
 }
diff --git a/chrome/browser/ash/input_method/longpress_diacritics_suggester.h b/chrome/browser/ash/input_method/longpress_diacritics_suggester.h
index cffbd0b3..b11a3ab 100644
--- a/chrome/browser/ash/input_method/longpress_diacritics_suggester.h
+++ b/chrome/browser/ash/input_method/longpress_diacritics_suggester.h
@@ -81,6 +81,7 @@
   absl::optional<char> displayed_window_base_character_;
   // Highlighted index can be nullopt even if window displayed.
   absl::optional<size_t> highlighted_index_;
+  bool text_changed_since_longpress_ = false;
 };
 
 }  // namespace input_method
diff --git a/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc b/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc
index 50c6633..49fc88e 100644
--- a/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc
@@ -20,6 +20,8 @@
 
 struct DiacriticsTestCase {
   char longpress_char;
+  std::u16string surrounding_text;
+  std::u16string invalid_surrounding_text;
   std::vector<std::u16string> candidates;
 };
 
@@ -68,6 +70,40 @@
   EXPECT_EQ(suggestion_handler.GetContextId(), kContextId);
 }
 
+TEST_P(LongpressDiacriticsSuggesterTest,
+       ShouldOnlyReturnTrueForFirstTextChangeEvent) {
+  FakeSuggestionHandler suggestion_handler;
+  LongpressDiacriticsSuggester suggester =
+      LongpressDiacriticsSuggester(&suggestion_handler);
+  suggester.OnFocus(kContextId);
+
+  suggester.TrySuggestOnLongpress(GetParam().longpress_char);
+
+  EXPECT_TRUE(suggester.TrySuggestWithSurroundingText(
+      GetParam().surrounding_text, GetParam().surrounding_text.size(),
+      GetParam().surrounding_text.size()));
+  // This cursor position hasn't changed, so the text is still valid. However
+  // it should return false because it is the second on change event.
+  EXPECT_FALSE(suggester.TrySuggestWithSurroundingText(
+      GetParam().surrounding_text + u"somechanges",
+      GetParam().surrounding_text.size(), GetParam().surrounding_text.size()));
+}
+
+TEST_P(LongpressDiacriticsSuggesterTest,
+       ShouldReturnFalseForInvalidTextChangeEvent) {
+  FakeSuggestionHandler suggestion_handler;
+  LongpressDiacriticsSuggester suggester =
+      LongpressDiacriticsSuggester(&suggestion_handler);
+  suggester.OnFocus(kContextId);
+
+  suggester.TrySuggestOnLongpress(GetParam().longpress_char);
+
+  EXPECT_FALSE(suggester.TrySuggestWithSurroundingText(
+      GetParam().invalid_surrounding_text,
+      GetParam().invalid_surrounding_text.size(),
+      GetParam().invalid_surrounding_text.size()));
+}
+
 TEST_P(LongpressDiacriticsSuggesterTest, DoesNotSuggestForInvalidKeyChar) {
   FakeSuggestionHandler suggestion_handler;
   LongpressDiacriticsSuggester suggester =
@@ -361,12 +397,12 @@
     /* no prefix */,
     LongpressDiacriticsSuggesterTest,
     testing::ValuesIn<DiacriticsTestCase>(
-        {{'a', {u"à", u"á", u"â", u"ã", u"ã", u"ä", u"å", u"ā"}},
-         {'A', {u"À", u"Á", u"Â", u"Ã", u"Ä", u"Å", u"Æ", u"Ā"}},
-         {'c', {u"ç"}},
-         {'C', {u"Ç"}},
-         {'e', {u"è", u"é", u"ê", u"ë", u"ē"}},
-         {'E', {u"È", u"É", u"Ê", u"Ë", u"Ē"}}}),
+        {{'a', u"ca", u"caf", {u"à", u"á", u"â", u"ã", u"ã", u"ä", u"å", u"ā"}},
+         {'A', u"cA", u"cAf", {u"À", u"Á", u"Â", u"Ã", u"Ä", u"Å", u"Æ", u"Ā"}},
+         {'c', u"c", u"ca", {u"ç"}},
+         {'C', u"C", u"Ca", {u"Ç"}},
+         {'e', u"soufle", u"soufles", {u"è", u"é", u"ê", u"ë", u"ē"}},
+         {'E', u"SOUFLE", u"SOUFLES", {u"È", u"É", u"Ê", u"Ë", u"Ē"}}}),
     [](const testing::TestParamInfo<
         LongpressDiacriticsSuggesterTest::ParamType>& info) {
       return std::string(1, info.param.longpress_char);
diff --git a/chrome/browser/ash/login/users/user_manager_unittest.cc b/chrome/browser/ash/login/users/user_manager_unittest.cc
index bcd7451..6168402 100644
--- a/chrome/browser/ash/login/users/user_manager_unittest.cc
+++ b/chrome/browser/ash/login/users/user_manager_unittest.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_test_util.h"
 #include "chrome/browser/ui/ash/test_wallpaper_controller.h"
 #include "chrome/browser/ui/ash/wallpaper_controller_client_impl.h"
 #include "chrome/common/pref_names.h"
@@ -335,8 +336,9 @@
       false /* browser_restart */, false /* is_child */);
   user_manager::User* const user =
       user_manager::UserManager::Get()->GetActiveUser();
-  Profile* const profile =
-      ProfileHelper::GetProfileByUserIdHashForTest(user->username_hash());
+  Profile* const profile = profiles::testing::CreateProfileSync(
+      g_browser_process->profile_manager(),
+      ash::ProfileHelper::GetProfilePathByUserIdHash(user->username_hash()));
 
   // Verify that the user is allowed to lock the screen.
   EXPECT_TRUE(user_manager::UserManager::Get()->CanCurrentUserLock());
diff --git a/chrome/browser/ash/note_taking_helper_unittest.cc b/chrome/browser/ash/note_taking_helper_unittest.cc
index c3e4c973..eb04965 100644
--- a/chrome/browser/ash/note_taking_helper_unittest.cc
+++ b/chrome/browser/ash/note_taking_helper_unittest.cc
@@ -82,6 +82,18 @@
 
 namespace {
 
+constexpr NoteTakingLockScreenSupport kNotSupported =
+    NoteTakingLockScreenSupport::kNotSupported;
+constexpr NoteTakingLockScreenSupport kNotAllowedByPolicy =
+    NoteTakingLockScreenSupport::kNotAllowedByPolicy;
+constexpr NoteTakingLockScreenSupport kSupported =
+    NoteTakingLockScreenSupport::kSupported;
+constexpr NoteTakingLockScreenSupport kEnabled =
+    NoteTakingLockScreenSupport::kEnabled;
+
+auto& kDevKeepExtensionId = NoteTakingHelper::kDevKeepExtensionId;
+auto& kProdKeepExtensionId = NoteTakingHelper::kProdKeepExtensionId;
+
 // Name of default profile.
 const char kTestProfileName[] = "test-profile";
 
@@ -447,7 +459,7 @@
   // Without the palette enabled, IsAppAvailable() should return false.
   Init(0);
   scoped_refptr<const extensions::Extension> extension =
-      CreateExtension(NoteTakingHelper::kProdKeepExtensionId, "Keep");
+      CreateExtension(kProdKeepExtensionId, "Keep");
   InstallExtension(extension.get(), profile());
   EXPECT_FALSE(helper()->IsAppAvailable(profile()));
 }
@@ -461,25 +473,23 @@
 
   // If only the prod version of the app is installed, it should be returned.
   scoped_refptr<const extensions::Extension> prod_extension =
-      CreateExtension(NoteTakingHelper::kProdKeepExtensionId, kProdKeepAppName);
+      CreateExtension(kProdKeepExtensionId, kProdKeepAppName);
   InstallExtension(prod_extension.get(), profile());
   EXPECT_TRUE(helper()->IsAppAvailable(profile()));
-  EXPECT_TRUE(AvailableAppsMatch(
-      profile(),
-      {{kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotSupported}}));
+  EXPECT_TRUE(
+      AvailableAppsMatch(profile(), {{kProdKeepAppName, kProdKeepExtensionId,
+                                      false /*preferred*/, kNotSupported}}));
 
   // If the dev version is also installed, it should be listed before the prod
   // version.
   scoped_refptr<const extensions::Extension> dev_extension =
-      CreateExtension(NoteTakingHelper::kDevKeepExtensionId, kDevKeepAppName);
+      CreateExtension(kDevKeepExtensionId, kDevKeepAppName);
   InstallExtension(dev_extension.get(), profile());
-  EXPECT_TRUE(AvailableAppsMatch(
-      profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotSupported},
-       {kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotSupported}}));
+  EXPECT_TRUE(
+      AvailableAppsMatch(profile(), {{kDevKeepAppName, kDevKeepExtensionId,
+                                      false /*preferred*/, kNotSupported},
+                                     {kProdKeepAppName, kProdKeepExtensionId,
+                                      false /*preferred*/, kNotSupported}}));
   EXPECT_TRUE(helper()->GetPreferredAppId(profile()).empty());
 
   // Now install a random web app to check that it's ignored.
@@ -492,27 +502,24 @@
       CreateExtension(kOtherId, kOtherName);
   InstallExtension(other_extension.get(), profile());
 
-  EXPECT_TRUE(AvailableAppsMatch(
-      profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotSupported},
-       {kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotSupported}}));
+  EXPECT_TRUE(
+      AvailableAppsMatch(profile(), {{kDevKeepAppName, kDevKeepExtensionId,
+                                      false /*preferred*/, kNotSupported},
+                                     {kProdKeepAppName, kProdKeepExtensionId,
+                                      false /*preferred*/, kNotSupported}}));
   EXPECT_TRUE(helper()->GetPreferredAppId(profile()).empty());
 
   // Mark the prod version as preferred.
-  helper()->SetPreferredApp(profile(), NoteTakingHelper::kProdKeepExtensionId);
-  EXPECT_TRUE(AvailableAppsMatch(
-      profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotSupported},
-       {kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kNotSupported}}));
-  EXPECT_EQ(helper()->GetPreferredAppId(profile()),
-            NoteTakingHelper::kProdKeepExtensionId);
-  EXPECT_EQ(helper()->GetLockScreenSupportForApp(
-                profile(), NoteTakingHelper::kProdKeepExtensionId),
-            NoteTakingLockScreenSupport::kNotSupported);
+  helper()->SetPreferredApp(profile(), kProdKeepExtensionId);
+  EXPECT_TRUE(
+      AvailableAppsMatch(profile(), {{kDevKeepAppName, kDevKeepExtensionId,
+                                      false /*preferred*/, kNotSupported},
+                                     {kProdKeepAppName, kProdKeepExtensionId,
+                                      true /*preferred*/, kNotSupported}}));
+  EXPECT_EQ(helper()->GetPreferredAppId(profile()), kProdKeepExtensionId);
+  EXPECT_EQ(
+      helper()->GetLockScreenSupportForApp(profile(), kProdKeepExtensionId),
+      kNotSupported);
 }
 
 TEST_F(NoteTakingHelperTest, ListChromeAppsWithLockScreenNotesSupported) {
@@ -529,28 +536,26 @@
   // Install Keep app that does not support lock screen note taking - it should
   // be reported not to support lock screen note taking.
   scoped_refptr<const extensions::Extension> prod_extension = CreateExtension(
-      NoteTakingHelper::kProdKeepExtensionId, kProdKeepAppName,
-      nullptr /* permissions */, std::move(lock_disabled_action_handler));
+      kProdKeepExtensionId, kProdKeepAppName, nullptr /* permissions */,
+      std::move(lock_disabled_action_handler));
   InstallExtension(prod_extension.get(), profile());
   EXPECT_TRUE(helper()->IsAppAvailable(profile()));
-  EXPECT_TRUE(AvailableAppsMatch(
-      profile(),
-      {{kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotSupported}}));
+  EXPECT_TRUE(
+      AvailableAppsMatch(profile(), {{kProdKeepAppName, kProdKeepExtensionId,
+                                      false /*preferred*/, kNotSupported}}));
   EXPECT_TRUE(helper()->GetPreferredAppId(profile()).empty());
 
   // Install additional Keep app - one that supports lock screen note taking.
   // This app should be reported to support note taking (given that
   // enable-lock-screen-apps flag is set).
   scoped_refptr<const extensions::Extension> dev_extension =
-      CreateAndInstallLockScreenApp(NoteTakingHelper::kDevKeepExtensionId,
-                                    kDevKeepAppName, profile());
+      CreateAndInstallLockScreenApp(kDevKeepExtensionId, kDevKeepAppName,
+                                    profile());
   EXPECT_TRUE(AvailableAppsMatch(
       profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kEnabled},
-       {kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotSupported}}));
+      {{kDevKeepAppName, kDevKeepExtensionId, false /*preferred*/, kEnabled},
+       {kProdKeepAppName, kProdKeepExtensionId, false /*preferred*/,
+        kNotSupported}}));
   EXPECT_TRUE(helper()->GetPreferredAppId(profile()).empty());
 }
 
@@ -562,42 +567,37 @@
 
   // Install lock screen enabled Keep note taking app.
   scoped_refptr<const extensions::Extension> dev_extension =
-      CreateAndInstallLockScreenApp(NoteTakingHelper::kDevKeepExtensionId,
-                                    kDevKeepAppName, profile());
+      CreateAndInstallLockScreenApp(kDevKeepExtensionId, kDevKeepAppName,
+                                    profile());
 
   // Verify that the app is reported to support lock screen note taking.
   EXPECT_TRUE(AvailableAppsMatch(
       profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kEnabled}}));
+      {{kDevKeepAppName, kDevKeepExtensionId, false /*preferred*/, kEnabled}}));
 
   // When the lock screen note taking pref is set and the Keep app is set as the
   // preferred note taking app, the app should be reported as selected as lock
   // screen note taking app.
-  helper()->SetPreferredApp(profile(), NoteTakingHelper::kDevKeepExtensionId);
+  helper()->SetPreferredApp(profile(), kDevKeepExtensionId);
   helper()->SetPreferredAppEnabledOnLockScreen(profile(), true);
 
   EXPECT_TRUE(AvailableAppsMatch(
       profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kEnabled}}));
-  EXPECT_EQ(helper()->GetPreferredAppId(profile()),
-            NoteTakingHelper::kDevKeepExtensionId);
-  EXPECT_EQ(helper()->GetLockScreenSupportForApp(
-                profile(), NoteTakingHelper::kDevKeepExtensionId),
-            NoteTakingLockScreenSupport::kEnabled);
+      {{kDevKeepAppName, kDevKeepExtensionId, true /*preferred*/, kEnabled}}));
+  EXPECT_EQ(helper()->GetPreferredAppId(profile()), kDevKeepExtensionId);
+  EXPECT_EQ(
+      helper()->GetLockScreenSupportForApp(profile(), kDevKeepExtensionId),
+      kEnabled);
 
   helper()->SetPreferredAppEnabledOnLockScreen(profile(), false);
 
-  EXPECT_TRUE(AvailableAppsMatch(
-      profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kSupported}}));
-  EXPECT_EQ(helper()->GetPreferredAppId(profile()),
-            NoteTakingHelper::kDevKeepExtensionId);
-  EXPECT_EQ(helper()->GetLockScreenSupportForApp(
-                profile(), NoteTakingHelper::kDevKeepExtensionId),
-            NoteTakingLockScreenSupport::kSupported);
+  EXPECT_TRUE(
+      AvailableAppsMatch(profile(), {{kDevKeepAppName, kDevKeepExtensionId,
+                                      true /*preferred*/, kSupported}}));
+  EXPECT_EQ(helper()->GetPreferredAppId(profile()), kDevKeepExtensionId);
+  EXPECT_EQ(
+      helper()->GetLockScreenSupportForApp(profile(), kDevKeepExtensionId),
+      kSupported);
 }
 
 TEST_F(NoteTakingHelperTest, PreferredAppWithNoLockScreenPermission) {
@@ -610,19 +610,16 @@
   // permission listed.
   scoped_refptr<const extensions::Extension> dev_extension =
       CreateAndInstallLockScreenAppWithPermissions(
-          NoteTakingHelper::kDevKeepExtensionId, kDevKeepAppName, nullptr,
-          profile());
-  helper()->SetPreferredApp(profile(), NoteTakingHelper::kDevKeepExtensionId);
+          kDevKeepExtensionId, kDevKeepAppName, nullptr, profile());
+  helper()->SetPreferredApp(profile(), kDevKeepExtensionId);
 
-  EXPECT_TRUE(AvailableAppsMatch(
-      profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kNotSupported}}));
-  EXPECT_EQ(helper()->GetPreferredAppId(profile()),
-            NoteTakingHelper::kDevKeepExtensionId);
-  EXPECT_EQ(helper()->GetLockScreenSupportForApp(
-                profile(), NoteTakingHelper::kDevKeepExtensionId),
-            NoteTakingLockScreenSupport::kNotSupported);
+  EXPECT_TRUE(
+      AvailableAppsMatch(profile(), {{kDevKeepAppName, kDevKeepExtensionId,
+                                      true /*preferred*/, kNotSupported}}));
+  EXPECT_EQ(helper()->GetPreferredAppId(profile()), kDevKeepExtensionId);
+  EXPECT_EQ(
+      helper()->GetLockScreenSupportForApp(profile(), kDevKeepExtensionId),
+      kNotSupported);
 }
 
 TEST_F(NoteTakingHelperTest,
@@ -634,8 +631,8 @@
 
   // Install dev Keep app that supports lock screen note taking.
   scoped_refptr<const extensions::Extension> dev_extension =
-      CreateAndInstallLockScreenApp(NoteTakingHelper::kDevKeepExtensionId,
-                                    kDevKeepAppName, profile());
+      CreateAndInstallLockScreenApp(kDevKeepExtensionId, kDevKeepAppName,
+                                    profile());
 
   // Install third-party app that doesn't support lock screen note taking.
   const extensions::ExtensionId kNewNoteId = crx_file::id_util::GenerateId("a");
@@ -646,35 +643,32 @@
 
   // Verify that only Keep app is reported to support lock screen note taking.
   EXPECT_TRUE(AvailableAppsMatch(
-      profile(), {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-                   false /*preferred*/, NoteTakingLockScreenSupport::kEnabled},
-                  {kName, kNewNoteId, false /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported}}));
+      profile(),
+      {{kDevKeepAppName, kDevKeepExtensionId, false /*preferred*/, kEnabled},
+       {kName, kNewNoteId, false /*preferred*/, kNotSupported}}));
 
   // When the Keep app is set as preferred app, and note taking on lock screen
   // is enabled, the keep app should be reported to be selected as the lock
   // screen note taking app.
-  helper()->SetPreferredApp(profile(), NoteTakingHelper::kDevKeepExtensionId);
+  helper()->SetPreferredApp(profile(), kDevKeepExtensionId);
   helper()->SetPreferredAppEnabledOnLockScreen(profile(), true);
 
   EXPECT_TRUE(AvailableAppsMatch(
-      profile(), {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-                   true /*preferred*/, NoteTakingLockScreenSupport::kEnabled},
-                  {kName, kNewNoteId, false /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported}}));
+      profile(),
+      {{kDevKeepAppName, kDevKeepExtensionId, true /*preferred*/, kEnabled},
+       {kName, kNewNoteId, false /*preferred*/, kNotSupported}}));
 
   // When a third party app (which does not support lock screen note taking) is
   // set as the preferred app, Keep app's lock screen support state remain
   // enabled - even though it will not be launchable from the lock screen.
   helper()->SetPreferredApp(profile(), kNewNoteId);
   EXPECT_TRUE(AvailableAppsMatch(
-      profile(), {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-                   false /*preferred*/, NoteTakingLockScreenSupport::kEnabled},
-                  {kName, kNewNoteId, true /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported}}));
+      profile(),
+      {{kDevKeepAppName, kDevKeepExtensionId, false /*preferred*/, kEnabled},
+       {kName, kNewNoteId, true /*preferred*/, kNotSupported}}));
   EXPECT_EQ(helper()->GetPreferredAppId(profile()), kNewNoteId);
   EXPECT_EQ(helper()->GetLockScreenSupportForApp(profile(), kNewNoteId),
-            NoteTakingLockScreenSupport::kNotSupported);
+            kNotSupported);
 }
 
 // Verify the note helper detects apps with "new_note" "action_handler" manifest
@@ -707,8 +701,7 @@
 
   // Only the "new_note" extension is returned from GetAvailableApps.
   EXPECT_TRUE(AvailableAppsMatch(
-      profile(), {{kName, kNewNoteId, false /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported}}));
+      profile(), {{kName, kNewNoteId, false /*preferred*/, kNotSupported}}));
 }
 
 // Web apps with a note_taking_new_note_url show as available note-taking apps.
@@ -738,8 +731,7 @@
 
   // Apps with note_taking_new_note_url are listed.
   EXPECT_TRUE(AvailableAppsMatch(
-      profile(), {{"Web App 2", app2_id, false /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported}}));
+      profile(), {{"Web App 2", app2_id, false /*preferred*/, kNotSupported}}));
 }
 
 // Verify that non-allowlisted apps cannot be enabled on lock screen.
@@ -753,15 +745,14 @@
       CreateAndInstallLockScreenApp(kNewNoteId, kName, profile());
 
   EXPECT_TRUE(AvailableAppsMatch(
-      profile(), {{kName, kNewNoteId, false /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported}}));
+      profile(), {{kName, kNewNoteId, false /*preferred*/, kNotSupported}}));
 }
 
 TEST_F(NoteTakingHelperTest, AllowlistedAndCustomAppsShowOnlyOnce) {
   Init(ENABLE_PALETTE);
 
   scoped_refptr<const extensions::Extension> extension = CreateExtension(
-      NoteTakingHelper::kProdKeepExtensionId, "Keep", nullptr /* permissions */,
+      kProdKeepExtensionId, "Keep", nullptr /* permissions */,
       extensions::ListBuilder()
           .Append(app_runtime::ToString(app_runtime::ACTION_TYPE_NEW_NOTE))
           .Build());
@@ -769,22 +760,20 @@
 
   EXPECT_TRUE(AvailableAppsMatch(
       profile(),
-      {{"Keep", NoteTakingHelper::kProdKeepExtensionId, false /*preferred*/,
-        NoteTakingLockScreenSupport::kNotSupported}}));
+      {{"Keep", kProdKeepExtensionId, false /*preferred*/, kNotSupported}}));
 }
 
 TEST_F(NoteTakingHelperTest, LaunchChromeApp) {
   Init(ENABLE_PALETTE);
   scoped_refptr<const extensions::Extension> extension =
-      CreateExtension(NoteTakingHelper::kProdKeepExtensionId, "Keep");
+      CreateExtension(kProdKeepExtensionId, "Keep");
   InstallExtension(extension.get(), profile());
 
   // Check the Chrome app is launched with the correct parameters.
   HistogramTester histogram_tester;
   helper()->LaunchAppForNewNote(profile());
   ASSERT_EQ(1u, launched_chrome_apps_.size());
-  EXPECT_EQ(NoteTakingHelper::kProdKeepExtensionId,
-            launched_chrome_apps_[0].id);
+  EXPECT_EQ(kProdKeepExtensionId, launched_chrome_apps_[0].id);
 
   histogram_tester.ExpectUniqueSample(
       NoteTakingHelper::kPreferredLaunchResultHistogramName,
@@ -861,10 +850,10 @@
 TEST_F(NoteTakingHelperTest, FallBackIfPreferredAppUnavailable) {
   Init(ENABLE_PALETTE);
   scoped_refptr<const extensions::Extension> prod_extension =
-      CreateExtension(NoteTakingHelper::kProdKeepExtensionId, "prod");
+      CreateExtension(kProdKeepExtensionId, "prod");
   InstallExtension(prod_extension.get(), profile());
   scoped_refptr<const extensions::Extension> dev_extension =
-      CreateExtension(NoteTakingHelper::kDevKeepExtensionId, "dev");
+      CreateExtension(kDevKeepExtensionId, "dev");
   InstallExtension(dev_extension.get(), profile());
   {
     // Install a default-allowed web app corresponding to ID of
@@ -879,11 +868,10 @@
 
   // Set the prod app as preferred and check that it's launched.
   std::unique_ptr<HistogramTester> histogram_tester(new HistogramTester());
-  helper()->SetPreferredApp(profile(), NoteTakingHelper::kProdKeepExtensionId);
+  helper()->SetPreferredApp(profile(), kProdKeepExtensionId);
   helper()->LaunchAppForNewNote(profile());
   ASSERT_EQ(1u, launched_chrome_apps_.size());
-  ASSERT_EQ(NoteTakingHelper::kProdKeepExtensionId,
-            launched_chrome_apps_[0].id);
+  ASSERT_EQ(kProdKeepExtensionId, launched_chrome_apps_[0].id);
 
   histogram_tester->ExpectUniqueSample(
       NoteTakingHelper::kPreferredLaunchResultHistogramName,
@@ -897,7 +885,7 @@
   histogram_tester = std::make_unique<HistogramTester>();
   helper()->LaunchAppForNewNote(profile());
   ASSERT_EQ(1u, launched_chrome_apps_.size());
-  EXPECT_EQ(NoteTakingHelper::kDevKeepExtensionId, launched_chrome_apps_[0].id);
+  EXPECT_EQ(kDevKeepExtensionId, launched_chrome_apps_[0].id);
 
   histogram_tester->ExpectUniqueSample(
       NoteTakingHelper::kPreferredLaunchResultHistogramName,
@@ -1004,22 +992,17 @@
   EXPECT_TRUE(helper()->android_apps_received());
   EXPECT_TRUE(helper()->IsAppAvailable(profile()));
   EXPECT_TRUE(AvailableAppsMatch(
-      profile(), {{kName1, kPackage1, false /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported},
-                  {kName2, kPackage2, false /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported}}));
+      profile(), {{kName1, kPackage1, false /*preferred*/, kNotSupported},
+                  {kName2, kPackage2, false /*preferred*/, kNotSupported}}));
 
   helper()->SetPreferredApp(profile(), kPackage1);
 
   EXPECT_TRUE(AvailableAppsMatch(
-      profile(), {{kName1, kPackage1, true /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported},
-                  {kName2, kPackage2, false /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported}}));
+      profile(), {{kName1, kPackage1, true /*preferred*/, kNotSupported},
+                  {kName2, kPackage2, false /*preferred*/, kNotSupported}}));
   // Preferred app is not actually installed, so no app ID should be returned.
   EXPECT_TRUE(helper()->GetPreferredAppId(profile()).empty());
-  EXPECT_EQ(helper()->GetLockScreenSupportForApp(profile(), ""),
-            NoteTakingLockScreenSupport::kNotSupported);
+  EXPECT_EQ(helper()->GetLockScreenSupportForApp(profile(), ""), kNotSupported);
 
   // Disable Play Store and check that the apps are no longer returned.
   profile()->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled, false);
@@ -1143,7 +1126,7 @@
   // extensions are queried dynamically when GetAvailableApps() is called, so we
   // don't need to actually install it.
   scoped_refptr<const extensions::Extension> keep_extension =
-      CreateExtension(NoteTakingHelper::kProdKeepExtensionId, "Keep");
+      CreateExtension(kProdKeepExtensionId, "Keep");
   InstallExtension(keep_extension.get(), profile());
   EXPECT_EQ(1, observer.num_updates());
 
@@ -1165,7 +1148,7 @@
   TestingProfile* second_profile =
       profile_manager()->CreateTestingProfile(kSecondProfileName);
   scoped_refptr<const extensions::Extension> second_keep_extension =
-      CreateExtension(NoteTakingHelper::kProdKeepExtensionId, "Keep");
+      CreateExtension(kProdKeepExtensionId, "Keep");
   InitExtensionService(second_profile);
   EXPECT_EQ(0, observer.num_updates());
   InstallExtension(second_keep_extension.get(), second_profile);
@@ -1180,11 +1163,11 @@
   TestObserver observer;
 
   scoped_refptr<const extensions::Extension> prod_keep_extension =
-      CreateExtension(NoteTakingHelper::kProdKeepExtensionId, "Keep");
+      CreateExtension(kProdKeepExtensionId, "Keep");
   InstallExtension(prod_keep_extension.get(), profile());
 
   scoped_refptr<const extensions::Extension> dev_keep_extension =
-      CreateExtension(NoteTakingHelper::kDevKeepExtensionId, "Keep");
+      CreateExtension(kDevKeepExtensionId, "Keep");
   InstallExtension(dev_keep_extension.get(), profile());
 
   ASSERT_TRUE(observer.preferred_app_updates().empty());
@@ -1219,7 +1202,7 @@
   InitExtensionService(second_profile);
   scoped_refptr<const extensions::Extension>
       second_profile_prod_keep_extension =
-          CreateExtension(NoteTakingHelper::kProdKeepExtensionId, "Keep");
+          CreateExtension(kProdKeepExtensionId, "Keep");
   InstallExtension(second_profile_prod_keep_extension.get(), second_profile);
 
   // Verify that observers are called with the scondary profile if the secondary
@@ -1241,16 +1224,16 @@
 }
 
 TEST_F(NoteTakingHelperTest,
-       NotifyObserverAboutPreferredAppLockScreenSupportChanges) {
+       NotifyObserverAboutPreferredLockScreenAppSupportChanges) {
   Init(ENABLE_PALETTE);
   TestObserver observer;
 
   scoped_refptr<const extensions::Extension> dev_extension =
-      CreateAndInstallLockScreenApp(NoteTakingHelper::kDevKeepExtensionId,
-                                    kDevKeepAppName, profile());
+      CreateAndInstallLockScreenApp(kDevKeepExtensionId, kDevKeepAppName,
+                                    profile());
 
   scoped_refptr<const extensions::Extension> prod_extension =
-      CreateExtension(NoteTakingHelper::kProdKeepExtensionId, "Keep");
+      CreateExtension(kProdKeepExtensionId, "Keep");
   InstallExtension(prod_extension.get(), profile());
 
   ASSERT_TRUE(observer.preferred_app_updates().empty());
@@ -1296,11 +1279,11 @@
   TestObserver observer;
 
   scoped_refptr<const extensions::Extension> dev_app =
-      CreateAndInstallLockScreenApp(NoteTakingHelper::kDevKeepExtensionId,
-                                    kDevKeepAppName, profile());
+      CreateAndInstallLockScreenApp(kDevKeepExtensionId, kDevKeepAppName,
+                                    profile());
   scoped_refptr<const extensions::Extension> prod_app =
-      CreateAndInstallLockScreenApp(NoteTakingHelper::kProdKeepExtensionId,
-                                    kProdKeepAppName, profile());
+      CreateAndInstallLockScreenApp(kProdKeepExtensionId, kProdKeepAppName,
+                                    profile());
   const std::string kUnsupportedAppName = "App name";
   const extensions::ExtensionId kUnsupportedAppId =
       crx_file::id_util::GenerateId("a");
@@ -1320,12 +1303,11 @@
 
   // Verify dev app is enabled on lock screen.
   EXPECT_TRUE(AvailableAppsMatch(
-      profile(), {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-                   false /*preferred*/, NoteTakingLockScreenSupport::kEnabled},
-                  {kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-                   true /*preferred*/, NoteTakingLockScreenSupport::kEnabled},
-                  {kUnsupportedAppName, kUnsupportedAppId, false /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotSupported}}));
+      profile(),
+      {{kDevKeepAppName, kDevKeepExtensionId, false /*preferred*/, kEnabled},
+       {kProdKeepAppName, kProdKeepExtensionId, true /*preferred*/, kEnabled},
+       {kUnsupportedAppName, kUnsupportedAppId, false /*preferred*/,
+        kNotSupported}}));
 
   // Allowlist prod app by policy.
   profile_prefs_->SetManagedPref(
@@ -1338,12 +1320,11 @@
 
   EXPECT_TRUE(AvailableAppsMatch(
       profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotAllowedByPolicy},
-       {kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kEnabled},
+      {{kDevKeepAppName, kDevKeepExtensionId, false /*preferred*/,
+        kNotAllowedByPolicy},
+       {kProdKeepAppName, kProdKeepExtensionId, true /*preferred*/, kEnabled},
        {kUnsupportedAppName, kUnsupportedAppId, false /*preferred*/,
-        NoteTakingLockScreenSupport::kNotSupported}}));
+        kNotSupported}}));
 
   // Change allowlist so only dev app is allowlisted.
   profile_prefs_->SetManagedPref(
@@ -1361,12 +1342,11 @@
 
   EXPECT_TRUE(AvailableAppsMatch(
       profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kEnabled},
-       {kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kNotAllowedByPolicy},
+      {{kDevKeepAppName, kDevKeepExtensionId, false /*preferred*/, kEnabled},
+       {kProdKeepAppName, kProdKeepExtensionId, true /*preferred*/,
+        kNotAllowedByPolicy},
        {kUnsupportedAppName, kUnsupportedAppId, false /*preferred*/,
-        NoteTakingLockScreenSupport::kNotSupported}}));
+        kNotSupported}}));
 
   // Switch preferred note taking app to one that does not support lock screen.
   helper()->SetPreferredApp(profile(), unsupported_app->id());
@@ -1383,14 +1363,13 @@
   // not supported on lock screen.
   EXPECT_TRUE(observer.preferred_app_updates().empty());
 
-  EXPECT_TRUE(AvailableAppsMatch(
-      profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotAllowedByPolicy},
-       {kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        false /*preferred*/, NoteTakingLockScreenSupport::kNotAllowedByPolicy},
-       {kUnsupportedAppName, kUnsupportedAppId, true /*preferred*/,
-        NoteTakingLockScreenSupport::kNotSupported}}));
+  EXPECT_TRUE(
+      AvailableAppsMatch(profile(), {{kDevKeepAppName, kDevKeepExtensionId,
+                                      false /*preferred*/, kNotAllowedByPolicy},
+                                     {kProdKeepAppName, kProdKeepExtensionId,
+                                      false /*preferred*/, kNotAllowedByPolicy},
+                                     {kUnsupportedAppName, kUnsupportedAppId,
+                                      true /*preferred*/, kNotSupported}}));
 
   UninstallExtension(dev_app.get(), profile());
   UninstallExtension(prod_app.get(), profile());
@@ -1408,14 +1387,13 @@
 
   // Add test app, set it as preferred and enable it on lock screen.
   scoped_refptr<const extensions::Extension> app =
-      CreateAndInstallLockScreenApp(NoteTakingHelper::kDevKeepExtensionId,
-                                    kDevKeepAppName, profile());
+      CreateAndInstallLockScreenApp(kDevKeepExtensionId, kDevKeepAppName,
+                                    profile());
   helper()->SetPreferredApp(profile(), app->id());
   observer.clear_preferred_app_updates();
   EXPECT_TRUE(AvailableAppsMatch(
       profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kEnabled}}));
+      {{kDevKeepAppName, kDevKeepExtensionId, true /*preferred*/, kEnabled}}));
 
   // Policy with an empty allowlist - this should disallow test app from running
   // on lock screen.
@@ -1428,9 +1406,8 @@
 
   // Verify the app is reported as not allowed by policy.
   EXPECT_TRUE(AvailableAppsMatch(
-      profile(), {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-                   true /*preferred*/,
-                   NoteTakingLockScreenSupport::kNotAllowedByPolicy}}));
+      profile(), {{kDevKeepAppName, kDevKeepExtensionId, true /*preferred*/,
+                   kNotAllowedByPolicy}}));
 
   // Remove the allowlist policy - the preferred app should become enabled on
   // lock screen again.
@@ -1441,8 +1418,7 @@
 
   EXPECT_TRUE(AvailableAppsMatch(
       profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kEnabled}}));
+      {{kDevKeepAppName, kDevKeepExtensionId, true /*preferred*/, kEnabled}}));
 }
 
 TEST_F(NoteTakingHelperTest,
@@ -1451,8 +1427,8 @@
   TestObserver observer;
 
   scoped_refptr<const extensions::Extension> app =
-      CreateAndInstallLockScreenApp(NoteTakingHelper::kDevKeepExtensionId,
-                                    kDevKeepAppName, profile());
+      CreateAndInstallLockScreenApp(kDevKeepExtensionId, kDevKeepAppName,
+                                    profile());
 
   profile_prefs_->SetManagedPref(prefs::kNoteTakingAppsLockScreenAllowlist,
                                  std::make_unique<base::ListValue>());
@@ -1474,8 +1450,7 @@
 
   EXPECT_TRUE(AvailableAppsMatch(
       profile(),
-      {{kDevKeepAppName, NoteTakingHelper::kDevKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kEnabled}}));
+      {{kDevKeepAppName, kDevKeepExtensionId, true /*preferred*/, kEnabled}}));
 }
 
 TEST_F(NoteTakingHelperTest, LockScreenSupportInSecondaryProfile) {
@@ -1501,8 +1476,8 @@
 
   // Add test apps to secondary profile.
   scoped_refptr<const extensions::Extension> prod_app =
-      CreateAndInstallLockScreenApp(NoteTakingHelper::kProdKeepExtensionId,
-                                    kProdKeepAppName, second_profile);
+      CreateAndInstallLockScreenApp(kProdKeepExtensionId, kProdKeepAppName,
+                                    second_profile);
   const std::string kUnsupportedAppName = "App name";
   const extensions::ExtensionId kUnsupportedAppId =
       crx_file::id_util::GenerateId("a");
@@ -1518,12 +1493,11 @@
 
   // Even though prod app supports lock screen it should be reported as not
   // supported in the secondary profile.
-  EXPECT_TRUE(AvailableAppsMatch(
-      second_profile,
-      {{kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kNotSupported},
-       {kUnsupportedAppName, kUnsupportedAppId, false /*preferred*/,
-        NoteTakingLockScreenSupport::kNotSupported}}));
+  EXPECT_TRUE(AvailableAppsMatch(second_profile,
+                                 {{kProdKeepAppName, kProdKeepExtensionId,
+                                   true /*preferred*/, kNotSupported},
+                                  {kUnsupportedAppName, kUnsupportedAppId,
+                                   false /*preferred*/, kNotSupported}}));
 
   // Enabling an app on lock screen in secondary profile should fail.
   EXPECT_FALSE(helper()->SetPreferredAppEnabledOnLockScreen(profile(), true));
@@ -1535,17 +1509,15 @@
   // Changing policy should not notify observers in secondary profile.
   EXPECT_TRUE(observer.preferred_app_updates().empty());
 
-  EXPECT_TRUE(AvailableAppsMatch(
-      second_profile,
-      {{kProdKeepAppName, NoteTakingHelper::kProdKeepExtensionId,
-        true /*preferred*/, NoteTakingLockScreenSupport::kNotSupported},
-       {kUnsupportedAppName, kUnsupportedAppId, false /*preferred*/,
-        NoteTakingLockScreenSupport::kNotSupported}}));
-  EXPECT_EQ(helper()->GetPreferredAppId(second_profile),
-            NoteTakingHelper::kProdKeepExtensionId);
-  EXPECT_EQ(helper()->GetLockScreenSupportForApp(
-                second_profile, NoteTakingHelper::kProdKeepExtensionId),
-            NoteTakingLockScreenSupport::kNotSupported);
+  EXPECT_TRUE(AvailableAppsMatch(second_profile,
+                                 {{kProdKeepAppName, kProdKeepExtensionId,
+                                   true /*preferred*/, kNotSupported},
+                                  {kUnsupportedAppName, kUnsupportedAppId,
+                                   false /*preferred*/, kNotSupported}}));
+  EXPECT_EQ(helper()->GetPreferredAppId(second_profile), kProdKeepExtensionId);
+  EXPECT_EQ(helper()->GetLockScreenSupportForApp(second_profile,
+                                                 kProdKeepExtensionId),
+            kNotSupported);
 }
 
 TEST_F(NoteTakingHelperTest, NoteTakingControllerClient) {
@@ -1562,10 +1534,10 @@
     SetNoteTakingClientProfile(profile());
     EXPECT_FALSE(has_note_taking_apps());
 
-    scoped_refptr<const extensions::Extension> extension1 = CreateExtension(
-        NoteTakingHelper::kProdKeepExtensionId, kProdKeepAppName);
+    scoped_refptr<const extensions::Extension> extension1 =
+        CreateExtension(kProdKeepExtensionId, kProdKeepAppName);
     scoped_refptr<const extensions::Extension> extension2 =
-        CreateExtension(NoteTakingHelper::kDevKeepExtensionId, kDevKeepAppName);
+        CreateExtension(kDevKeepExtensionId, kDevKeepAppName);
 
     InstallExtension(extension1.get(), profile());
     EXPECT_TRUE(has_note_taking_apps());
@@ -1592,10 +1564,10 @@
     SetNoteTakingClientProfile(second_profile);
     EXPECT_FALSE(has_note_taking_apps());
 
-    scoped_refptr<const extensions::Extension> extension1 = CreateExtension(
-        NoteTakingHelper::kProdKeepExtensionId, kProdKeepAppName);
+    scoped_refptr<const extensions::Extension> extension1 =
+        CreateExtension(kProdKeepExtensionId, kProdKeepAppName);
     scoped_refptr<const extensions::Extension> extension2 =
-        CreateExtension(NoteTakingHelper::kDevKeepExtensionId, kDevKeepAppName);
+        CreateExtension(kDevKeepExtensionId, kDevKeepAppName);
 
     InstallExtension(extension2.get(), second_profile);
     EXPECT_TRUE(has_note_taking_apps());
@@ -1605,8 +1577,7 @@
 
     NoteTakingClient::GetInstance()->CreateNote();
     ASSERT_EQ(1u, launched_chrome_apps_.size());
-    ASSERT_EQ(NoteTakingHelper::kProdKeepExtensionId,
-              launched_chrome_apps_[0].id);
+    ASSERT_EQ(kProdKeepExtensionId, launched_chrome_apps_[0].id);
 
     UninstallExtension(extension2.get(), second_profile);
     EXPECT_TRUE(has_note_taking_apps());
diff --git a/chrome/browser/ash/profiles/profile_helper.cc b/chrome/browser/ash/profiles/profile_helper.cc
index ff0aae0f..0238026 100644
--- a/chrome/browser/ash/profiles/profile_helper.cc
+++ b/chrome/browser/ash/profiles/profile_helper.cc
@@ -171,14 +171,6 @@
 }
 
 // static
-Profile* ProfileHelper::GetProfileByUserIdHashForTest(
-    const std::string& user_id_hash) {
-  base::ScopedAllowBlockingForTesting allow_io;
-  return g_browser_process->profile_manager()->GetProfile(
-      ProfileHelper::GetProfilePathByUserIdHash(user_id_hash));
-}
-
-// static
 base::FilePath ProfileHelper::GetProfilePathByUserIdHash(
     const std::string& user_id_hash) {
   // Fails if Chrome runs with "--login-manager", but not "--login-profile", and
@@ -268,11 +260,6 @@
 }
 
 // static
-Profile* ProfileHelper::GetLockScreenIncognitoProfile() {
-  return GetIncognitoProfile(GetLockScreenProfileDir());
-}
-
-// static
 bool ProfileHelper::IsLockScreenProfile(const Profile* profile) {
   return profile && IsLockScreenProfilePath(profile->GetBaseName());
 }
diff --git a/chrome/browser/ash/profiles/profile_helper.h b/chrome/browser/ash/profiles/profile_helper.h
index 81c39cc..17b7636 100644
--- a/chrome/browser/ash/profiles/profile_helper.h
+++ b/chrome/browser/ash/profiles/profile_helper.h
@@ -53,14 +53,6 @@
   // knowledge in one place.
   static ProfileHelper* Get();
 
-  // Loads and returns Profile instance that corresponds to |user_id_hash| for
-  // test. It should not be used in production code because it could load a
-  // not-yet-loaded user profile and skip the user profile initialization code
-  // in UserSessionManager.
-  // See http://crbug.com/728683 and http://crbug.com/718734.
-  static Profile* GetProfileByUserIdHashForTest(
-      const std::string& user_id_hash);
-
   // Returns profile path that corresponds to a given |user_id_hash|.
   static base::FilePath GetProfilePathByUserIdHash(
       const std::string& user_id_hash);
@@ -102,9 +94,6 @@
   // Returns the path that corresponds to the lockscreen profile.
   static base::FilePath GetLockScreenProfileDir();
 
-  // Returns lockscreen profile.
-  static Profile* GetLockScreenIncognitoProfile();
-
   // Returns true if |profile| is the lockscreen profile.
   static bool IsLockScreenProfile(const Profile* profile);
 
diff --git a/chrome/browser/ash/web_applications/file_manager_web_app_info.cc b/chrome/browser/ash/web_applications/file_manager_web_app_info.cc
index 0b2f5ca..037c288 100644
--- a/chrome/browser/ash/web_applications/file_manager_web_app_info.cc
+++ b/chrome/browser/ash/web_applications/file_manager_web_app_info.cc
@@ -93,6 +93,7 @@
                         "crx",    //
                         "gz",     //
                         "iso",    //
+                        "lz",     //
                         "lzma",   //
                         "rar",    //
                         "tar",    //
diff --git a/chrome/browser/ash/web_applications/media_app/media_app_guest_ui_config.cc b/chrome/browser/ash/web_applications/media_app/media_app_guest_ui_config.cc
index f71b9bde..bc12fcf 100644
--- a/chrome/browser/ash/web_applications/media_app/media_app_guest_ui_config.cc
+++ b/chrome/browser/ash/web_applications/media_app/media_app_guest_ui_config.cc
@@ -57,6 +57,12 @@
   source->AddBoolean("colorThemes",
                      chromeos::features::IsDarkLightModeEnabled());
   source->AddBoolean("photosAvailable", photosInstalled);
+  source->AddBoolean("photosIntegrationImage",
+                     base::FeatureList::IsEnabled(
+                         chromeos::features::kMediaAppPhotosIntegrationImage));
+  source->AddBoolean("photosIntegrationVideo",
+                     base::FeatureList::IsEnabled(
+                         chromeos::features::kMediaAppPhotosIntegrationVideo));
   source->AddBoolean("flagsMenu", channel != version_info::Channel::BETA &&
                                       channel != version_info::Channel::STABLE);
   source->AddBoolean("isDevChannel", channel == version_info::Channel::DEV);
diff --git a/chrome/browser/ash/web_applications/terminal_source.cc b/chrome/browser/ash/web_applications/terminal_source.cc
index 8ac46c5..1cf1d2b5 100644
--- a/chrome/browser/ash/web_applications/terminal_source.cc
+++ b/chrome/browser/ash/web_applications/terminal_source.cc
@@ -19,15 +19,19 @@
 #include "chrome/browser/ash/crostini/crostini_pref_names.h"
 #include "chrome/browser/ash/crostini/crostini_terminal.h"
 #include "chrome/browser/ash/file_manager/path_util.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/prefs/pref_service.h"
 #include "components/version_info/channel.h"
+#include "content/public/browser/web_contents.h"
 #include "net/base/mime_util.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/zlib/google/compression_utils.h"
 #include "ui/webui/webui_allowlist.h"
 
@@ -151,8 +155,24 @@
 
   // Refresh the $i8n{themeColor} replacement for css files.
   if (base::EndsWith(path, ".css", base::CompareCase::INSENSITIVE_ASCII)) {
-    replacements_["themeColor"] = base::EscapeForHTML(
-        crostini::GetTerminalSettingBackgroundColor(profile_));
+    GURL url;
+    absl::optional<SkColor> opener_background_color;
+    content::WebContents* contents = wc_getter.Run();
+    if (contents) {
+      url = contents->GetVisibleURL();
+      TabStripModel* tab_strip;
+      int tab_index;
+      extensions::ExtensionTabUtil::GetTabStripModel(contents, &tab_strip,
+                                                     &tab_index);
+      content::WebContents* opener =
+          tab_strip->GetOpenerOfWebContentsAt(tab_index);
+      if (opener) {
+        opener_background_color = opener->GetBackgroundColor();
+      }
+    }
+    replacements_["themeColor"] =
+        base::EscapeForHTML(crostini::GetTerminalSettingBackgroundColor(
+            profile_, url, opener_background_color));
   }
 
   base::ThreadPool::PostTask(
diff --git a/chrome/browser/banners/app_banner_manager_desktop.cc b/chrome/browser/banners/app_banner_manager_desktop.cc
index 5dc6b22..7615bfd 100644
--- a/chrome/browser/banners/app_banner_manager_desktop.cc
+++ b/chrome/browser/banners/app_banner_manager_desktop.cc
@@ -226,9 +226,8 @@
 void AppBannerManagerDesktop::OnWebAppWillBeUninstalled(
     const web_app::AppId& app_id) {
   // WebAppTabHelper has a app_id but it is reset during
-  // OnWebAppWillBeUninstalled so using FindAppWithUrlInScope.
-  auto local_app_id = registrar().FindAppWithUrlInScope(validated_url());
-  if (app_id == local_app_id)
+  // OnWebAppWillBeUninstalled so use IsUrlInAppScope() instead.
+  if (registrar().IsUrlInAppScope(validated_url(), app_id))
     uninstalling_app_id_ = app_id;
 }
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
index 71b0b58..47d25ba 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -175,6 +175,8 @@
       return file_manager_private::IO_TASK_STATE_SUCCESS;
     case file_manager::io_task::State::kError:
       return file_manager_private::IO_TASK_STATE_ERROR;
+    case file_manager::io_task::State::kNeedPassword:
+      return file_manager_private::IO_TASK_STATE_NEED_PASSWORD;
     case file_manager::io_task::State::kCancelled:
       return file_manager_private::IO_TASK_STATE_CANCELLED;
     default:
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
index d1e0798..c707d57 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -1658,9 +1658,13 @@
     case file_manager::io_task::OperationType::kExtract:
       if (base::FeatureList::IsEnabled(
               chromeos::features::kFilesExtractArchive)) {
+        std::string password;
+        if (params->params.password) {
+          password = *params->params.password;
+        }
         task = std::make_unique<file_manager::io_task::ExtractIOTask>(
-            std::move(source_urls), std::move(destination_folder_url), profile,
-            file_system_context);
+            std::move(source_urls), std::move(password),
+            std::move(destination_folder_url), profile, file_system_context);
         break;
       }
       // Fall through
diff --git a/chrome/browser/download/notification/download_notification_browsertest.cc b/chrome/browser/download/notification/download_notification_browsertest.cc
index fd7a255..9969422 100644
--- a/chrome/browser/download/notification/download_notification_browsertest.cc
+++ b/chrome/browser/download/notification/download_notification_browsertest.cc
@@ -20,12 +20,15 @@
 #include "base/test/scoped_feature_list.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
 #include "chrome/browser/download/download_core_service.h"
 #include "chrome/browser/download/download_core_service_factory.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/notifications/notification_display_service_tester.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_test_util.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -1216,8 +1219,9 @@
   }
 
   Profile* GetProfileByIndex(int index) {
-    return ash::ProfileHelper::GetProfileByUserIdHashForTest(
-        kTestAccounts[index].hash);
+    return g_browser_process->profile_manager()->GetProfileByPath(
+        ash::ProfileHelper::GetProfilePathByUserIdHash(
+            kTestAccounts[index].hash));
   }
 
   // Adds a new user for testing to the current session.
@@ -1230,8 +1234,9 @@
     user_manager::UserManager::Get()->SaveUserDisplayName(
         AccountId::FromUserEmailGaiaId(info.email, info.gaia_id),
         base::UTF8ToUTF16(info.display_name));
-    Profile* profile =
-        ash::ProfileHelper::GetProfileByUserIdHashForTest(info.hash);
+    Profile* profile = profiles::testing::CreateProfileSync(
+        g_browser_process->profile_manager(),
+        ash::ProfileHelper::GetProfilePathByUserIdHash(info.hash));
 
     signin::IdentityManager* identity_manager =
         IdentityManagerFactory::GetForProfile(profile);
diff --git a/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc b/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc
index 90c5804e..6a6c5a375 100644
--- a/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc
@@ -267,11 +267,11 @@
         api::CryptotokenPrivateCanAppIdGetAttestationFunction>();
     function->set_has_callback(true);
 
-    base::Value::DictStorage dict;
-    dict.emplace("appId", app_id);
-    dict.emplace("tabId", tab_id_);
-    dict.emplace("frameId", -1);  // Ignored.
-    dict.emplace("origin", app_id);
+    base::Value::Dict dict;
+    dict.Set("appId", app_id);
+    dict.Set("tabId", tab_id_);
+    dict.Set("frameId", -1);  // Ignored.
+    dict.Set("origin", app_id);
     auto args = std::make_unique<base::Value>(base::Value::Type::LIST);
     args->Append(base::Value(std::move(dict)));
     auto args_list = base::ListValue::From(std::move(args));
@@ -300,11 +300,11 @@
         api::CryptotokenPrivateCanMakeU2fApiRequestFunction>();
     function->set_has_callback(true);
 
-    base::Value::DictStorage dict;
-    dict.emplace("appId", origin);
-    dict.emplace("tabId", tab_id_);
-    dict.emplace("frameId", 0 /* main frame */);
-    dict.emplace("origin", origin);
+    base::Value::Dict dict;
+    dict.Set("appId", origin);
+    dict.Set("tabId", tab_id_);
+    dict.Set("frameId", 0 /* main frame */);
+    dict.Set("origin", origin);
     auto args = std::make_unique<base::Value>(base::Value::Type::LIST);
     args->Append(base::Value(std::move(dict)));
     auto args_list = base::ListValue::From(std::move(args));
diff --git a/chrome/browser/extensions/api/file_manager/file_browser_handler_api_ash_test.cc b/chrome/browser/extensions/api/file_manager/file_browser_handler_api_ash_test.cc
index ff26f0af..3399ea6e 100644
--- a/chrome/browser/extensions/api/file_manager/file_browser_handler_api_ash_test.cc
+++ b/chrome/browser/extensions/api/file_manager/file_browser_handler_api_ash_test.cc
@@ -333,7 +333,7 @@
   select_file_function->set_has_callback(true);
   select_file_function->set_user_gesture(true);
 
-  base::Value::DictStorage result =
+  base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           select_file_function.get(),
           "[{\"suggestedName\": \"some_file_name.txt\"}]", browser()));
@@ -356,7 +356,7 @@
   select_file_function->set_has_callback(true);
   select_file_function->set_user_gesture(true);
 
-  base::Value::DictStorage result =
+  base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           select_file_function.get(),
           "[{\"suggestedName\": \"/path_to_file/some_file_name.txt\"}]",
diff --git a/chrome/browser/extensions/api/management/management_api_browsertest.cc b/chrome/browser/extensions/api/management/management_api_browsertest.cc
index ea61ad27..c039a117 100644
--- a/chrome/browser/extensions/api/management/management_api_browsertest.cc
+++ b/chrome/browser/extensions/api/management/management_api_browsertest.cc
@@ -359,7 +359,7 @@
                        DisabledReason) {
   scoped_refptr<ManagementGetFunction> function =
       new ManagementGetFunction();
-  base::Value::DictStorage dict =
+  base::Value::Dict dict =
       test_utils::ToDictionary(test_utils::RunFunctionAndReturnSingleResult(
           function.get(), base::StringPrintf("[\"%s\"]", kId), browser()));
   std::string reason =
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api.cc b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
index 86ddc82c..746cc75 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_api.cc
+++ b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
@@ -278,7 +278,7 @@
   params_ = SendSuggestions::Params::Create(args());
   EXTENSION_FUNCTION_VALIDATE(params_);
 
-  if (is_from_service_worker()) {
+  if (is_from_service_worker() && !params_->suggest_results.empty()) {
     std::vector<base::StringPiece> inputs;
     inputs.reserve(params_->suggest_results.size());
     for (const auto& suggestion : params_->suggest_results)
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc b/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
index fb347c57..1d4af976 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
+++ b/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
@@ -833,4 +833,88 @@
   }
 }
 
+// Tests an extension passing empty suggestions. Regression test for
+// https://crbug.com/1330137.
+IN_PROC_BROWSER_TEST_P(OmniboxApiTest, PassEmptySuggestions) {
+  static constexpr char kManifest[] =
+      R"({
+           "name": "Basic Send Suggestions",
+           "manifest_version": 2,
+           "version": "0.1",
+           "omnibox": { "keyword": "alpha" },
+           "background": { "scripts": [ "background.js" ], "persistent": true }
+         })";
+  // Register a listener that passes back empty suggestions if there is no
+  // text content.
+  static constexpr char kBackground[] =
+      R"(chrome.omnibox.onInputChanged.addListener((text, suggest) => {
+           let results = text.length > 0 ?
+               [{content: "foo", description: "Foo"}] :
+               [];
+           suggest(results);
+         });)";
+
+  TestExtensionDir test_dir;
+  test_dir.WriteManifest(kManifest);
+  test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackground);
+  const Extension* extension = LoadExtension(test_dir.UnpackedPath());
+  ASSERT_TRUE(extension);
+
+  AutocompleteController* autocomplete_controller = GetAutocompleteController();
+
+  chrome::FocusLocationBar(browser());
+  ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
+
+  // Enter "alpha d" into the omnibox to trigger the extension.
+  InputKeys(browser(), {ui::VKEY_A, ui::VKEY_L, ui::VKEY_P, ui::VKEY_H,
+                        ui::VKEY_A, ui::VKEY_SPACE, ui::VKEY_D});
+  WaitForAutocompleteDone(browser());
+  EXPECT_TRUE(autocomplete_controller->done());
+
+  {
+    // We expect three results - sending the typed text to the extension,
+    // the single extension suggestion ("foo"), and to search what the user
+    // typed.
+    const AutocompleteResult& result = autocomplete_controller->result();
+    ASSERT_EQ(3u, result.size()) << AutocompleteResultAsString(result);
+
+    EXPECT_EQ(u"alpha d", result.match_at(0).fill_into_edit);
+    EXPECT_EQ(AutocompleteProvider::TYPE_KEYWORD,
+              result.match_at(0).provider->type());
+
+    EXPECT_EQ(u"alpha foo", result.match_at(1).fill_into_edit);
+    EXPECT_EQ(AutocompleteProvider::TYPE_KEYWORD,
+              result.match_at(1).provider->type());
+
+    AutocompleteMatch match = result.match_at(2);
+    EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, match.type);
+    EXPECT_EQ(AutocompleteProvider::TYPE_SEARCH,
+              result.match_at(2).provider->type());
+  }
+
+  // Now, hit the backspace key, so that the only text is "alpha ". The
+  // extension should still be receiving input.
+  InputKeys(browser(), {ui::VKEY_BACK});
+
+  WaitForAutocompleteDone(browser());
+  EXPECT_TRUE(autocomplete_controller->done());
+
+  {
+    // The extension sent back an empty set of suggestions, so we expect
+    // only two results - sending the typed text to the extension and searching
+    // for what the user typed.
+    const AutocompleteResult& result = autocomplete_controller->result();
+    ASSERT_EQ(2u, result.size()) << AutocompleteResultAsString(result);
+
+    EXPECT_EQ(u"alpha ", result.match_at(0).fill_into_edit);
+    EXPECT_EQ(AutocompleteProvider::TYPE_KEYWORD,
+              result.match_at(0).provider->type());
+
+    AutocompleteMatch match = result.match_at(1);
+    EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, match.type);
+    EXPECT_EQ(AutocompleteProvider::TYPE_SEARCH,
+              result.match_at(1).provider->type());
+  }
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/runtime/runtime_apitest.cc b/chrome/browser/extensions/api/runtime/runtime_apitest.cc
index 8330211..c2ef475 100644
--- a/chrome/browser/extensions/api/runtime/runtime_apitest.cc
+++ b/chrome/browser/extensions/api/runtime/runtime_apitest.cc
@@ -153,7 +153,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeRuntimeGetPlatformInfo) {
-  base::Value::DictStorage dict = extension_function_test_utils::ToDictionary(
+  base::Value::Dict dict = extension_function_test_utils::ToDictionary(
       extension_function_test_utils::RunFunctionAndReturnSingleResult(
           new RuntimeGetPlatformInfoFunction(), "[]", browser()));
   EXPECT_TRUE(dict.contains("os"));
diff --git a/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
index 6531d77..1d2446f 100644
--- a/chrome/browser/extensions/api/sessions/sessions_apitest.cc
+++ b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -107,7 +107,7 @@
   for (size_t i = 0; i < devices.GetListDeprecated().size(); ++i) {
     const base::Value& device_value = devices.GetListDeprecated()[i];
     EXPECT_TRUE(device_value.is_dict());
-    const base::Value::DictStorage device = utils::ToDictionary(device_value);
+    const base::Value::Dict device = utils::ToDictionary(device_value);
     EXPECT_EQ(kSessionTags[i], api_test_utils::GetString(device, "info"));
     EXPECT_EQ(kSessionTags[i], api_test_utils::GetString(device, "deviceName"));
     const std::unique_ptr<base::ListValue> sessions =
@@ -117,10 +117,9 @@
     // sessions, and if 1, that will be a Window. Grab it.
     if (num_sessions == 0)
       continue;
-    const base::Value::DictStorage session =
+    const base::Value::Dict session =
         utils::ToDictionary(sessions->GetListDeprecated()[0]);
-    const base::Value::DictStorage window =
-        api_test_utils::GetDict(session, "window");
+    const base::Value::Dict window = api_test_utils::GetDict(session, "window");
     // Only the tabs are interesting.
     const std::unique_ptr<base::ListValue> tabs =
         api_test_utils::GetList(window, "tabs");
@@ -130,7 +129,7 @@
     }
     EXPECT_EQ(std::size(kTabIDs), tabs->GetListDeprecated().size());
     for (size_t j = 0; j < tabs->GetListDeprecated().size(); ++j) {
-      const base::Value::DictStorage tab =
+      const base::Value::Dict tab =
           utils::ToDictionary(tabs->GetListDeprecated()[j]);
       EXPECT_FALSE(tab.contains("id"));  // sessions API does not give tab IDs
       EXPECT_EQ(static_cast<int>(j), api_test_utils::GetInteger(tab, "index"));
@@ -308,7 +307,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, RestoreForeignSessionWindow) {
   CreateSessionModels();
 
-  const base::Value::DictStorage restored_window_session =
+  const base::Value::Dict restored_window_session =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           CreateFunction<SessionsRestoreFunction>(true).get(), "[\"tag3.3\"]",
           browser(), api_test_utils::INCLUDE_INCOGNITO));
@@ -320,9 +319,9 @@
 
   base::ListValue* windows = result.get();
   EXPECT_EQ(2u, windows->GetListDeprecated().size());
-  const base::Value::DictStorage restored_window =
+  const base::Value::Dict restored_window =
       api_test_utils::GetDict(restored_window_session, "window");
-  base::Value::DictStorage window;
+  base::Value::Dict window;
   int restored_id = api_test_utils::GetInteger(restored_window, "id");
   for (base::Value& window_value : windows->GetListDeprecated()) {
     window = utils::ToDictionary(std::move(window_value));
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 402dd46..c598e75 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -321,6 +321,8 @@
           settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_allowlist)[::omnibox::kDocumentSuggestEnabled] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_allowlist)[::prefs::kAutofillAssistantOnDesktopEnabled] =
+      settings_api::PrefType::PREF_TYPE_BOOLEAN;
 
   // Languages page
   (*s_allowlist)[spellcheck::prefs::kSpellCheckEnable] =
diff --git a/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc b/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc
index fd7d505e..4e434a2 100644
--- a/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc
@@ -65,7 +65,7 @@
   scoped_refptr<const extensions::Extension> extension(
       extensions::ExtensionBuilder("Test").Build());
   function->set_extension(extension.get());
-  base::Value::DictStorage result =
+  base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           function.get(), "[]", new_browser));
 
@@ -212,7 +212,7 @@
 
   Browser* CreateBrowserWithEmptyTab(bool as_popup);
 
-  int GetTabId(const base::Value::DictStorage& dict) const;
+  int GetTabId(const base::Value::Dict& dict) const;
 
   std::unique_ptr<base::Value> RunFunction(ExtensionFunction* function,
                                            const std::string& params);
@@ -287,21 +287,14 @@
 }
 
 int ExtensionWindowLastFocusedTest::GetTabId(
-    const base::Value::DictStorage& dict) const {
-  auto iter = dict.find(keys::kTabsKey);
-  if (iter == dict.end() || !iter->second.is_list())
+    const base::Value::Dict& dict) const {
+  const base::Value::List* tabs = dict.FindList(keys::kTabsKey);
+  if (!tabs || tabs->empty())
     return -2;
-  const base::ListValue& tabs = base::Value::AsListValue(iter->second);
-  if (tabs.GetListDeprecated().empty())
+  const base::Value::Dict* tab_dict = (*tabs)[0].GetIfDict();
+  if (!tab_dict)
     return -2;
-  const base::Value& tab = tabs.GetListDeprecated()[0];
-  const base::DictionaryValue* tab_dict = nullptr;
-  if (!tab.GetAsDictionary(&tab_dict))
-    return -2;
-  absl::optional<int> tab_id = tab_dict->FindIntKey(keys::kIdKey);
-  if (!tab_id)
-    return -2;
-  return *tab_id;
+  return tab_dict->FindInt(keys::kIdKey).value_or(-2);
 }
 
 std::unique_ptr<base::Value> ExtensionWindowLastFocusedTest::RunFunction(
@@ -322,7 +315,7 @@
 
     scoped_refptr<WindowsGetLastFocusedFunction> function =
         new WindowsGetLastFocusedFunction();
-    const base::Value::DictStorage result = utils::ToDictionary(
+    const base::Value::Dict result = utils::ToDictionary(
         RunFunction(function.get(), "[{\"populate\": true}]"));
     EXPECT_NE(devtools_window_id, api_test_utils::GetInteger(result, "id"));
   }
@@ -339,7 +332,7 @@
 
     scoped_refptr<WindowsGetLastFocusedFunction> get_current_app_function =
         new WindowsGetLastFocusedFunction();
-    const base::Value::DictStorage result = utils::ToDictionary(
+    const base::Value::Dict result = utils::ToDictionary(
         RunFunction(get_current_app_function.get(), "[{\"populate\": true}]"));
     int app_window_id = app_window->session_id().id();
     EXPECT_NE(app_window_id, api_test_utils::GetInteger(result, "id"));
@@ -357,7 +350,7 @@
 
     scoped_refptr<WindowsGetLastFocusedFunction> function =
         new WindowsGetLastFocusedFunction();
-    const base::Value::DictStorage result = utils::ToDictionary(
+    const base::Value::Dict result = utils::ToDictionary(
         RunFunction(function.get(), "[{\"populate\": true}]"));
     int normal_browser_window_id =
         ExtensionTabUtil::GetWindowId(normal_browser);
@@ -373,7 +366,7 @@
 
     scoped_refptr<WindowsGetLastFocusedFunction> function =
         new WindowsGetLastFocusedFunction();
-    const base::Value::DictStorage result = utils::ToDictionary(
+    const base::Value::Dict result = utils::ToDictionary(
         RunFunction(function.get(), "[{\"populate\": true}]"));
     int popup_browser_window_id = ExtensionTabUtil::GetWindowId(popup_browser);
     EXPECT_EQ(popup_browser_window_id,
@@ -389,7 +382,7 @@
 
     scoped_refptr<WindowsGetLastFocusedFunction> function =
         new WindowsGetLastFocusedFunction();
-    const base::Value::DictStorage result = utils::ToDictionary(RunFunction(
+    const base::Value::Dict result = utils::ToDictionary(RunFunction(
         function.get(),
         "[{\"populate\": true, \"windowTypes\": [ \"devtools\" ]}]"));
     int devtools_window_id = ExtensionTabUtil::GetWindowId(
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index f443445..6884610 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -98,7 +98,7 @@
     std::string args = base::StringPrintf(
         R"([%u, {"windowTypes": ["normal", "popup", "devtools", "app"]}])",
         ExtensionTabUtil::GetWindowId(test_browser));
-    base::Value::DictStorage result =
+    base::Value::Dict result =
         utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
             function.get(), args, browser()));
     return api_test_utils::GetString(result, "type");
@@ -120,25 +120,17 @@
 const ExtensionTabUtil::ScrubTabBehavior kDontScrubBehavior = {
     ExtensionTabUtil::kDontScrubTab, ExtensionTabUtil::kDontScrubTab};
 
-int GetTabId(const base::Value::DictStorage& tab) {
-  auto iter = tab.find(keys::kIdKey);
-  if (iter == tab.end() || !iter->second.is_int())
-    return kUndefinedId;
-  return iter->second.GetInt();
+int GetTabId(const base::Value::Dict& tab) {
+  return tab.FindInt(keys::kIdKey).value_or(kUndefinedId);
 }
 
-int GetTabWindowId(const base::Value::DictStorage& tab) {
-  auto iter = tab.find(keys::kWindowIdKey);
-  if (iter == tab.end() || !iter->second.is_int())
-    return kUndefinedId;
-  return iter->second.GetInt();
+int GetTabWindowId(const base::Value::Dict& tab) {
+  return tab.FindInt(keys::kWindowIdKey).value_or(kUndefinedId);
 }
 
-int GetWindowId(const base::Value::DictStorage& window) {
-  auto iter = window.find(keys::kIdKey);
-  if (iter == window.end() || !iter->second.is_int())
-    return kUndefinedId;
-  return iter->second.GetInt();
+int GetWindowId(const base::Value::Dict& window) {
+  return window.FindInt(keys::kIdKey).value_or(kUndefinedId);
+  ;
 }
 
 }  // namespace
@@ -164,7 +156,7 @@
 
   function = new WindowsGetFunction();
   function->set_extension(extension.get());
-  base::Value::DictStorage result =
+  base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           function.get(), base::StringPrintf("[%u]", window_id), browser()));
   EXPECT_EQ(window_id, GetWindowId(result));
@@ -252,7 +244,7 @@
       new WindowsGetCurrentFunction();
   scoped_refptr<const Extension> extension(ExtensionBuilder("Test").Build());
   function->set_extension(extension.get());
-  base::Value::DictStorage result =
+  base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           function.get(), "[]", new_browser));
 
@@ -425,7 +417,7 @@
   // Without a callback the function will not generate a result.
   update_tab_function->set_has_callback(true);
 
-  const base::Value::DictStorage result =
+  const base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           update_tab_function.get(),
           "[null, {\"url\": \"about:blank\", \"pinned\": true}]", browser()));
@@ -476,7 +468,7 @@
       browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
   scoped_refptr<const Extension> extension(ExtensionBuilder("Test").Build());
   function->set_extension(extension.get());
-  base::Value::DictStorage result =
+  base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           function.get(), kArgsWithoutExplicitIncognitoParam, browser(),
           api_test_utils::INCLUDE_INCOGNITO));
@@ -514,7 +506,7 @@
   scoped_refptr<WindowsCreateFunction> function = new WindowsCreateFunction();
   scoped_refptr<const Extension> extension(ExtensionBuilder("Test").Build());
   function->set_extension(extension.get());
-  base::Value::DictStorage result =
+  base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           function.get(), kEmptyArgs, browser(),
           api_test_utils::INCLUDE_INCOGNITO));
@@ -703,7 +695,7 @@
   static const char kNewBlankTabArgs[] =
       "[{\"url\": \"about:blank\", \"windowId\": %u}]";
 
-  const base::Value::DictStorage result =
+  const base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           create_tab_function.get(),
           base::StringPrintf(kNewBlankTabArgs, window_id), browser()));
@@ -824,7 +816,7 @@
   scoped_refptr<const Extension> extension(
       ExtensionBuilder("Test").Build().get());
   get_function->set_extension(extension.get());
-  base::Value::DictStorage result =
+  base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           get_function.get(),
           base::StringPrintf(
@@ -892,7 +884,7 @@
   function->set_extension(extension.get());
   function->SetBrowserContextForTesting(browser()->profile());
 
-  base::Value::DictStorage result =
+  base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           function.get(), "[{\"state\": \"minimized\"}]", browser(),
           api_test_utils::INCLUDE_INCOGNITO));
@@ -1007,7 +999,7 @@
   function->SetBrowserContextForTesting(browser()->profile());
   function->set_source_context_type(Feature::Context::WEBUI_UNTRUSTED_CONTEXT);
 
-  const base::Value::DictStorage result =
+  const base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           function.get(), R"([{"type": "popup"}])", browser()));
   int window_id = GetWindowId(result);
@@ -1035,7 +1027,7 @@
   duplicate_tab_function->set_extension(empty_tab_extension.get());
   duplicate_tab_function->set_has_callback(true);
 
-  const base::Value::DictStorage duplicate_result =
+  const base::Value::Dict duplicate_result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           duplicate_tab_function.get(), base::StringPrintf("[%u]", tab_id),
           browser()));
@@ -1072,7 +1064,7 @@
   duplicate_tab_function->set_extension(empty_extension.get());
   duplicate_tab_function->set_has_callback(true);
 
-  const base::Value::DictStorage duplicate_result =
+  const base::Value::Dict duplicate_result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           duplicate_tab_function.get(), base::StringPrintf("[%u]", tab_id),
           browser()));
@@ -1361,7 +1353,7 @@
 
   // Run function passing the tab id as argument.
   int tab_id = ExtensionTabUtil::GetTabId(web_contents);
-  const base::Value::DictStorage result =
+  const base::Value::Dict result =
       utils::ToDictionary(utils::RunFunctionAndReturnSingleResult(
           discard.get(), base::StringPrintf("[%u]", tab_id), browser()));
 
@@ -1437,7 +1429,7 @@
   discard->set_extension(extension.get());
 
   // Run without passing an id.
-  const base::Value::DictStorage result = utils::ToDictionary(
+  const base::Value::Dict result = utils::ToDictionary(
       utils::RunFunctionAndReturnSingleResult(discard.get(), "[]", browser()));
 
   // Confirms that TabManager sees the tab as discarded.
@@ -1489,7 +1481,7 @@
   const char* kAutoDiscardableQueryInfo = "[{\"autoDiscardable\": true}]";
   const char* kNonAutoDiscardableQueryInfo = "[{\"autoDiscardable\": false}]";
   std::unique_ptr<base::ListValue> query_result;
-  base::Value::DictStorage update_result;
+  base::Value::Dict update_result;
 
   // Get auto-discardable tabs. Returns all since tabs are auto-discardable
   // by default.
@@ -1680,7 +1672,7 @@
   if (!get_zoom_settings_result)
     return testing::AssertionFailure() << "no result";
 
-  base::Value::DictStorage get_zoom_settings_dict =
+  base::Value::Dict get_zoom_settings_dict =
       utils::ToDictionary(std::move(get_zoom_settings_result));
   *mode = api_test_utils::GetString(get_zoom_settings_dict, "mode");
   *scope = api_test_utils::GetString(get_zoom_settings_dict, "scope");
diff --git a/chrome/browser/extensions/extension_function_test_utils.cc b/chrome/browser/extensions/extension_function_test_utils.cc
index 75746045..02b0a58 100644
--- a/chrome/browser/extensions/extension_function_test_utils.cc
+++ b/chrome/browser/extensions/extension_function_test_utils.cc
@@ -62,19 +62,19 @@
   return result;
 }
 
-base::Value::DictStorage ToDictionary(std::unique_ptr<base::Value> val) {
+base::Value::Dict ToDictionary(std::unique_ptr<base::Value> val) {
   if (!val || !val->is_dict()) {
     ADD_FAILURE() << "val is nullptr or is not a dictonary.";
-    return base::Value::DictStorage();
+    return base::Value::Dict();
   }
-  return std::move(*val).TakeDictDeprecated();
+  return std::move(val->GetDict());
 }
 
-base::Value::DictStorage ToDictionary(const base::Value& val) {
+base::Value::Dict ToDictionary(const base::Value& val) {
   EXPECT_TRUE(val.is_dict());
   if (!val.is_dict())
-    return base::Value::DictStorage();
-  return val.Clone().TakeDictDeprecated();
+    return base::Value::Dict();
+  return val.GetDict().Clone();
 }
 
 std::unique_ptr<base::ListValue> ToList(std::unique_ptr<base::Value> val) {
@@ -85,7 +85,7 @@
   return base::ListValue::From(std::move(val));
 }
 
-bool HasAnyPrivacySensitiveFields(const base::Value::DictStorage& dict) {
+bool HasAnyPrivacySensitiveFields(const base::Value::Dict& dict) {
   constexpr std::array privacySensitiveKeys{keys::kUrlKey, keys::kTitleKey,
                                             keys::kFaviconUrlKey,
                                             keys::kPendingUrlKey};
diff --git a/chrome/browser/extensions/extension_function_test_utils.h b/chrome/browser/extensions/extension_function_test_utils.h
index e8a4604..39d3472c1 100644
--- a/chrome/browser/extensions/extension_function_test_utils.h
+++ b/chrome/browser/extensions/extension_function_test_utils.h
@@ -16,11 +16,6 @@
 class Browser;
 class ExtensionFunction;
 
-namespace base {
-class Value;
-class ListValue;
-}
-
 // TODO(ckehoe): Accept args as std::unique_ptr<base::Value>,
 // and migrate existing users to the new API.
 // This file is DEPRECATED. New tests should use the versions in
@@ -31,15 +26,15 @@
 absl::optional<base::Value> ParseList(const std::string& data);
 
 // If |val| is a dictionary, return it as one, otherwise create an empty one.
-base::Value::DictStorage ToDictionary(std::unique_ptr<base::Value> val);
-base::Value::DictStorage ToDictionary(const base::Value& val);
+base::Value::Dict ToDictionary(std::unique_ptr<base::Value> val);
+base::Value::Dict ToDictionary(const base::Value& val);
 
 // If |val| is a list, return it as one, otherwise NULL.
 std::unique_ptr<base::ListValue> ToList(std::unique_ptr<base::Value> val);
 
 // Returns true if |val| contains any privacy information, e.g. url,
 // pendingUrl, title or faviconUrl.
-bool HasAnyPrivacySensitiveFields(const base::Value::DictStorage& dict);
+bool HasAnyPrivacySensitiveFields(const base::Value::Dict& dict);
 
 // Run |function| with |args| and return the resulting error. Adds an error to
 // the current test if |function| returns a result. Takes ownership of
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index c292ebf5..897e99a3 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -4018,6 +4018,16 @@
     "expiry_milestone": 106
   },
   {
+    "name": "media-app-photos-integration-image",
+    "owners": [ "//ash/webui/media_app_ui/OWNERS" ],
+    "expiry_milestone": 107
+  },
+  {
+    "name": "media-app-photos-integration-video",
+    "owners": [ "//ash/webui/media_app_ui/OWNERS" ],
+    "expiry_milestone": 107
+  },
+  {
     "name": "media-router-cast-allow-all-ips",
     "owners": [ "mfoltz" ],
     // This flag is used by users with unusual network configurations to allow
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 07a49bd06..f997c005 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -5216,6 +5216,16 @@
 const char kMediaAppHandlesPdfDescription[] =
     "Enables opening PDF files by default in chrome://media-app";
 
+const char kMediaAppPhotosIntegrationImageName[] =
+    "Media App Photos Integration (Image)";
+const char kMediaAppPhotosIntegrationImageDescription[] =
+    "Within Gallery, enable finding more editing tools for images in Photos";
+
+const char kMediaAppPhotosIntegrationVideoName[] =
+    "Media App Photos Integration (Video)";
+const char kMediaAppPhotosIntegrationVideoDescription[] =
+    "Within Gallery, enable finding editing tools for videos in Photos";
+
 const char kMeteredShowToggleName[] = "Show Metered Toggle";
 const char kMeteredShowToggleDescription[] =
     "Shows a Metered toggle in the Network settings UI for WiFI and Cellular. "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 92d606d..0420cd0 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2979,6 +2979,12 @@
 extern const char kMediaAppHandlesPdfName[];
 extern const char kMediaAppHandlesPdfDescription[];
 
+extern const char kMediaAppPhotosIntegrationImageName[];
+extern const char kMediaAppPhotosIntegrationImageDescription[];
+
+extern const char kMediaAppPhotosIntegrationVideoName[];
+extern const char kMediaAppPhotosIntegrationVideoDescription[];
+
 extern const char kMeteredShowToggleName[];
 extern const char kMeteredShowToggleDescription[];
 
diff --git a/chrome/browser/resources/app_settings/app.html b/chrome/browser/resources/app_settings/app.html
index 1a04d98..aa345e85 100644
--- a/chrome/browser/resources/app_settings/app.html
+++ b/chrome/browser/resources/app_settings/app.html
@@ -1,4 +1,4 @@
-<style include="app-management-shared-css">
+<style include="app-management-shared-style">
   #content {
     background-color: var(--cr-card-background-color);
     border-radius: var(--cr-card-border-radius);
diff --git a/chrome/browser/resources/app_settings/app.ts b/chrome/browser/resources/app_settings/app.ts
index 6a8f91c..59ee91d 100644
--- a/chrome/browser/resources/app_settings/app.ts
+++ b/chrome/browser/resources/app_settings/app.ts
@@ -5,12 +5,13 @@
 import './strings.m.js';
 import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js';
+import 'chrome://resources/cr_components/app_management/app_management_shared_style.css.js';
 import 'chrome://resources/cr_components/app_management/file_handling_item.js';
 import 'chrome://resources/cr_components/app_management/more_permissions_item.js';
 import 'chrome://resources/cr_components/app_management/run_on_os_login_item.js';
 import 'chrome://resources/cr_components/app_management/permission_item.js';
 import 'chrome://resources/cr_components/app_management/window_mode_item.js';
-import 'chrome://resources/cr_components/app_management/icons.js';
+import 'chrome://resources/cr_components/app_management/icons.html.js';
 import 'chrome://resources/cr_components/app_management/uninstall_button.js';
 import 'chrome://resources/cr_components/localized_link/localized_link.js';
 
diff --git a/chrome/browser/resources/chromeos/accessibility/.eslintrc.js b/chrome/browser/resources/chromeos/accessibility/.eslintrc.js
index de6bac6..a657fe4c 100644
--- a/chrome/browser/resources/chromeos/accessibility/.eslintrc.js
+++ b/chrome/browser/resources/chromeos/accessibility/.eslintrc.js
@@ -4,6 +4,7 @@
 
 module.exports = {
   'rules' : {
+    'arrow-parens' : ['error', 'as-needed'],
     'arrow-spacing' : ['error'],
     'brace-style' : ['error', '1tbs'],
     'curly' : ['error', 'multi-line', 'consistent'],
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/auto_scroll_handler_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/auto_scroll_handler_test.js
index 30f24a0..66f5e98 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/auto_scroll_handler_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/auto_scroll_handler_test.js
@@ -50,10 +50,10 @@
       `;
     return await this.runWithFakeScrollable(site, {
       numChildrenBeforeScroll_: -1,
-      beforeScroll: (list) => {
+      beforeScroll: list => {
         this.numChildrenBeforeScroll_ = list.children.length;
       },
-      scrollFinished: (list) =>
+      scrollFinished: list =>
           list.children.length !== this.numChildrenBeforeScroll_
     });
   }
@@ -90,10 +90,10 @@
       `;
     return await this.runWithFakeScrollable(site, {
       childrenBeforeScroll_: [],
-      beforeScroll: (list) => {
+      beforeScroll: list => {
         this.childrenBeforeScroll_ = list.children;
       },
-      scrollFinished: (list) => list.children.length === 2 &&
+      scrollFinished: list => list.children.length === 2 &&
           list.children[0] !== this.childrenBeforeScroll_[0] &&
           list.children[1] !== this.childrenBeforeScroll_[1]
     });
@@ -146,9 +146,9 @@
     };
 
     // Create a fake scrollForward and scrollBackward actions.
-    const fakeScrollFunc = (cb) => {
+    const fakeScrollFunc = cb => {
       scrolledPredicate.beforeScroll(list);
-      const listener = (ev) => {
+      const listener = ev => {
         if (!scrolledPredicate.scrollFinished(list)) {
           return;
         }
@@ -232,7 +232,7 @@
       const mockFeedback = this.createMockFeedback();
       const root = await this.runWithFakeArcSimpleScrollable();
       const list = root.find({role: RoleType.LIST});
-      list.scrollForward = (callback) => callback(false);
+      list.scrollForward = callback => callback(false);
 
       mockFeedback.expectSpeech('1st item')
           .call(doCmd('nextObject'))
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
index 983e9731..d46fab2 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background.js
@@ -82,7 +82,7 @@
     chrome.clipboard.onClipboardDataChanged.addListener(() => {
       this.onClipboardDataChanged_();
     });
-    document.addEventListener('copy', (event) => {
+    document.addEventListener('copy', event => {
       this.onClipboardCopyEvent_(event);
     });
 
@@ -102,11 +102,11 @@
     RangeAutomationHandler.init();
 
     chrome.accessibilityPrivate.onAnnounceForAccessibility.addListener(
-        (announceText) => {
+        announceText => {
           ChromeVox.tts.speak(announceText.join(' '), QueueMode.FLUSH);
         });
     chrome.accessibilityPrivate.onCustomSpokenFeedbackToggled.addListener(
-        (enabled) => this.talkBackEnabled_ = enabled);
+        enabled => this.talkBackEnabled_ = enabled);
     chrome.accessibilityPrivate.onShowChromeVoxTutorial.addListener(() => {
       (new PanelCommand(PanelCommandType.TUTORIAL)).send();
     });
@@ -403,11 +403,11 @@
           AutomationUtil.getUniqueAncestors(prevRange.start.node, start);
 
       entered
-          .filter((f) => {
+          .filter(f => {
             return f.role === RoleType.PLUGIN_OBJECT ||
                 f.role === RoleType.IFRAME;
           })
-          .forEach((container) => {
+          .forEach(container => {
             if (!container.state[StateType.FOCUSED]) {
               container.focus();
             }
@@ -418,8 +418,7 @@
       return;
     }
 
-    const isFocusableLinkOrControl = (node) =>
-        node.state[StateType.FOCUSABLE] &&
+    const isFocusableLinkOrControl = node => node.state[StateType.FOCUSABLE] &&
         AutomationPredicate.linkOrControl(node);
 
     // Next, try to focus the start or end node.
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
index 4be5703..f5f1212 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
@@ -1911,7 +1911,7 @@
     <script>
       let div =       document.body.firstElementChild;
       let start =       document.getElementById('start');
-      document.getElementById('hot').addEventListener('focus', (evt) => {
+      document.getElementById('hot').addEventListener('focus', evt => {
         let hot = evt.target;
         hot.remove();
         div.insertAfter(hot, start);
@@ -2570,13 +2570,13 @@
     <button id="click"></button>
     <script>
       const button = document.getElementById('click');
-      button.addEventListener('click', _ => document.title = 'bar');
+      button.addEventListener('click', () => document.title = 'bar');
     </script>
   `;
   const root = await this.runWithLoadedTree(site);
   const clickButtonThenReadCurrentTitle = () => {
     const desktop = root.parent.root;
-    desktop.addEventListener(EventType.TREE_CHANGED, (evt) => {
+    desktop.addEventListener(EventType.TREE_CHANGED, evt => {
       if (evt.target.role === RoleType.WINDOW && /bar/.test(evt.target.name)) {
         doCmd('readCurrentTitle')();
       }
@@ -2617,7 +2617,7 @@
   const node = root.find({role: RoleType.BUTTON});
 
   node.addEventListener(EventType.FOCUS, this.newCallback(function() {
-    chrome.automation.getAccessibilityFocus((focusedNode) => {
+    chrome.automation.getAccessibilityFocus(focusedNode => {
       assertEquals(node, focusedNode);
     });
   }));
@@ -3032,7 +3032,7 @@
   const site = `
     <p id="live" aria-live="polite"</p>
     <script>
-    document.body.addEventListener('keydown', (evt) => {
+    document.body.addEventListener('keydown', evt => {
       document.getElementById('live').textContent = evt.key;
     });
     </script>
@@ -3600,9 +3600,9 @@
 
 SYNC_TEST_F('ChromeVoxBackgroundTest', 'PageLoadEarcons', function() {
   const sawEarcons = [];
-  const fakeEarcons = {playEarcon: (earcon) => sawEarcons.push(earcon)};
+  const fakeEarcons = {playEarcon: earcon => sawEarcons.push(earcon)};
   Object.defineProperty(ChromeVox, 'earcons', {get: () => fakeEarcons});
-  AutomationUtil.getTopLevelRoot = (node) => node;
+  AutomationUtil.getTopLevelRoot = node => node;
 
   // Use this specific object to control the load environment.
   const handler = new PageLoadSoundHandler();
@@ -3819,7 +3819,7 @@
   this.newCallback(async () => {
     const speech = [];
     let onSpeech;
-    ChromeVox.tts.speak = (textString) => {
+    ChromeVox.tts.speak = textString => {
       speech.push(textString);
       if (onSpeech) {
         onSpeech(textString);
@@ -3829,7 +3829,7 @@
     chrome.runtime.openOptionsPage();
 
     await new Promise(resolve => {
-      onSpeech = (textString) => {
+      onSpeech = textString => {
         if (textString === 'ChromeVox Options') {
           resolve();
         }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js
index 9c3c37e..1b6c8a6 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_background.js
@@ -162,7 +162,7 @@
 BridgeHelper.registerHandler(
     BridgeConstants.BrailleBackground.TARGET,
     BridgeConstants.BrailleBackground.Action.BACK_TRANSLATE,
-    (cells) => new Promise(resolve => {
+    cells => new Promise(resolve => {
       BrailleBackground.instance.getTranslatorManager()
           .getDefaultTranslator()
           .backTranslate(cells, resolve);
@@ -171,5 +171,5 @@
 BridgeHelper.registerHandler(
     BridgeConstants.BrailleBackground.TARGET,
     BridgeConstants.BrailleBackground.Action.REFRESH_BRAILLE_TABLE,
-    (brailleTable) => BrailleBackground.instance.getTranslatorManager().refresh(
+    brailleTable => BrailleBackground.instance.getTranslatorManager().refresh(
         brailleTable));
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_display_manager.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_display_manager.js
index 80e9fed..5b0de8f 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_display_manager.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_display_manager.js
@@ -78,13 +78,13 @@
 
     BrailleCaptionsBackground.init(() => this.onCaptionsStateChanged_());
     if (goog.isDef(chrome.brailleDisplayPrivate)) {
-      const onDisplayStateChanged = (newState) =>
+      const onDisplayStateChanged = newState =>
           this.refreshDisplayState_(newState);
       chrome.brailleDisplayPrivate.getDisplayState(onDisplayStateChanged);
       chrome.brailleDisplayPrivate.onDisplayStateChanged.addListener(
           onDisplayStateChanged);
       chrome.brailleDisplayPrivate.onKeyEvent.addListener(
-          (event) => this.onKeyEvent_(event));
+          event => this.onKeyEvent_(event));
     } else {
       // Get the initial captions state since we won't refresh the display
       // state in an API callback in this case.
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_display_manager_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_display_manager_test.js
index 7717028..f0cfd17 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_display_manager_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_display_manager_test.js
@@ -39,11 +39,11 @@
     this.DISPLAY_ROW_SIZE = 1;
     this.DISPLAY_COLUMN_SIZE = 12;
 
-    chrome.brailleDisplayPrivate.getDisplayState = (callback) => {
+    chrome.brailleDisplayPrivate.getDisplayState = callback => {
       callback(this.displayState);
     };
     this.writtenCells = [];
-    chrome.brailleDisplayPrivate.writeDots = (cells) => {
+    chrome.brailleDisplayPrivate.writeDots = cells => {
       this.writtenCells.push(cells);
     };
     chrome.brailleDisplayPrivate.onDisplayStateChanged = new FakeChromeEvent();
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_input_handler_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_input_handler_test.js
index 36bae85..69e49996 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_input_handler_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_input_handler_test.js
@@ -36,7 +36,7 @@
     this.uncommittedText_ = '';
     /** @private {?Array<number>} */
     this.extraCells_ = [];
-    port.postMessage = (message) => this.handleMessage_(message);
+    port.postMessage = message => this.handleMessage_(message);
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_state.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_state.js
index 0b8eb1c..e928e59 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_state.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/chromevox_state.js
@@ -153,5 +153,4 @@
 BridgeHelper.registerHandler(
     BridgeConstants.ChromeVoxState.TARGET,
     BridgeConstants.ChromeVoxState.Action.UPDATE_PUNCTUATION_ECHO,
-    (echo) =>
-        ChromeVoxState.instance.backgroundTts.updatePunctuationEcho(echo));
+    echo => ChromeVoxState.instance.backgroundTts.updatePunctuationEcho(echo));
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
index 157ff8b9..2ef2466d 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
@@ -81,9 +81,9 @@
     // Inject the content script into all running tabs allowed by the
     // manifest. This block is still necessary because the extension system
     // doesn't re-inject content scripts into already running tabs.
-    chrome.windows.getAll({'populate': true}, (windows) => {
+    chrome.windows.getAll({'populate': true}, windows => {
       for (let i = 0; i < windows.length; i++) {
-        const tabs = windows[i].tabs.filter((tab) => matchesRe.test(tab.url));
+        const tabs = windows[i].tabs.filter(tab => matchesRe.test(tab.url));
         this.injectChromeVoxIntoTabs(tabs);
       }
     });
@@ -170,7 +170,7 @@
          * A helper function which executes code.
          * @param {string} code The code to execute.
          */
-        const executeScript = (code) => {
+        const executeScript = code => {
           chrome.tabs.executeScript(tab.id, {code, 'allFrames': true}, () => {
             if (!chrome.extension.lastError) {
               return;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
index 8e7b7de..0f46fb4 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/command_handler.js
@@ -253,7 +253,7 @@
           // If this is the first time, show a confirmation dialog.
           chrome.accessibilityPrivate.showConfirmationDialog(
               Msgs.getMsg('toggle_screen_title'),
-              Msgs.getMsg('toggle_screen_description'), (confirmed) => {
+              Msgs.getMsg('toggle_screen_description'), confirmed => {
                 if (confirmed) {
                   sessionStorage.setItem('darkScreen', 'true');
                   localStorage['acceptToggleScreen'] = true;
@@ -275,11 +275,11 @@
         return false;
       case 'enableChromeVoxArcSupportForCurrentApp':
         chrome.accessibilityPrivate.setNativeChromeVoxArcSupportForCurrentApp(
-            true, (response) => {});
+            true, response => {});
         break;
       case 'disableChromeVoxArcSupportForCurrentApp':
         chrome.accessibilityPrivate.setNativeChromeVoxArcSupportForCurrentApp(
-            false, (response) => {
+            false, response => {
               if (response ===
                   chrome.accessibilityPrivate.SetNativeChromeVoxResponse
                       .TALKBACK_NOT_INSTALLED) {
@@ -1534,23 +1534,23 @@
    * Performs global initialization.
    */
   init() {
-    ChromeVoxKbHandler.commandHandler = (command) => this.onCommand(command);
+    ChromeVoxKbHandler.commandHandler = command => this.onCommand(command);
 
     chrome.commandLinePrivate.hasSwitch(
-        'enable-experimental-accessibility-language-detection', (enabled) => {
+        'enable-experimental-accessibility-language-detection', enabled => {
           if (enabled) {
             this.languageLoggingEnabled_ = true;
           }
         });
     chrome.commandLinePrivate.hasSwitch(
         'enable-experimental-accessibility-language-detection-dynamic',
-        (enabled) => {
+        enabled => {
           if (enabled) {
             this.languageLoggingEnabled_ = true;
           }
         });
 
-    chrome.chromeosInfoPrivate.get(['sessionType'], (result) => {
+    chrome.chromeosInfoPrivate.get(['sessionType'], result => {
       /** @type {boolean} */
       this.isKioskSession_ = result['sessionType'] ===
           chrome.chromeosInfoPrivate.SessionType.KIOSK;
@@ -1563,4 +1563,4 @@
 BridgeHelper.registerHandler(
     BridgeConstants.CommandHandler.TARGET,
     BridgeConstants.CommandHandler.Action.ON_COMMAND,
-    (command) => CommandHandlerInterface.instance.onCommand(command));
+    command => CommandHandlerInterface.instance.onCommand(command));
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js
index 40498fe..94103c9 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js
@@ -100,7 +100,7 @@
 
     this.addListener_(EventType.LOAD_COMPLETE, this.onLoadComplete);
     this.addListener_(EventType.FOCUS_AFTER_MENU_CLOSE, this.onMenuEnd);
-    this.addListener_(EventType.MENU_START, (event) => {
+    this.addListener_(EventType.MENU_START, event => {
       Output.forceModeForNextSpeechUtterance(QueueMode.CATEGORY_FLUSH);
       this.onEventDefault(event);
     });
@@ -637,7 +637,7 @@
     // editable leading to braille output routing to the editable.
     this.textEditHandler_ = null;
 
-    chrome.automation.getFocus((focus) => {
+    chrome.automation.getFocus(focus => {
       const target = evt.target;
 
       // Desktop tabs get "selection" when there's a focused webview during
@@ -800,7 +800,7 @@
          voxTarget.root.role !== RoleType.DESKTOP &&
          !AutomationUtil.isDescendantOf(target, voxTarget) &&
          !AutomationUtil.getAncestors(voxTarget.root)
-              .find((n) => n.role === RoleType.KEYBOARD))) {
+              .find(n => n.role === RoleType.KEYBOARD))) {
       return false;
     }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler_test.js
index 8554b0f7..5da83ce 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler_test.js
@@ -89,7 +89,7 @@
     'ChromeVoxDesktopAutomationHandlerTest', 'TaskManagerTableView',
     function() {
       const mockFeedback = this.createMockFeedback();
-      this.runWithLoadedDesktop((desktop) => {
+      this.runWithLoadedDesktop(desktop => {
         mockFeedback
             .call(() => {
               EventGenerator.sendKeyPress(KeyCode.ESCAPE, {search: true});
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/earcons.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/earcons.js
index 3cc1ca2..6e9d747 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/earcons.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/earcons.js
@@ -89,7 +89,7 @@
    * @private
    */
   updateShouldPanForDevices_(devices) {
-    this.shouldPan_ = !devices.some((device) => {
+    this.shouldPan_ = !devices.some(device => {
       return device.isActive &&
           device.deviceType === chrome.audio.DeviceType.INTERNAL_SPEAKER;
     });
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/find_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/find_handler.js
index c3c8c13..321e9f1 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/find_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/find_handler.js
@@ -20,7 +20,7 @@
     this.lastFindMarkerReceived = new Date();
 
     /** @private {function(chrome.automation.TreeChange)} */
-    this.treeChangeObserver_ = (change) => this.onTextMatch_(change);
+    this.treeChangeObserver_ = change => this.onTextMatch_(change);
 
     chrome.automation.addTreeChangeObserver(
         TreeChangeObserverFilter.TEXT_MARKER_CHANGES, this.treeChangeObserver_);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/focus_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/focus_automation_handler.js
index 705b9f1..3faf94b 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/focus_automation_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/focus_automation_handler.js
@@ -25,7 +25,7 @@
     /** @private {AutomationNode|undefined} */
     this.previousActiveDescendant_;
 
-    chrome.automation.getDesktop((desktop) => {
+    chrome.automation.getDesktop(desktop => {
       desktop.addEventListener(EventType.FOCUS, this.onFocus.bind(this), false);
     });
   }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_command_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_command_handler.js
index 049ab7d..a7a677a 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_command_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/gesture_command_handler.js
@@ -127,7 +127,7 @@
   GestureCommandHandler.pointerHandler_ = new PointerHandler();
 
   GestureInterface.granularityGetter = () => GestureCommandHandler.granularity;
-  GestureInterface.granularitySetter = (granularity) =>
+  GestureInterface.granularitySetter = granularity =>
       GestureCommandHandler.granularity = granularity;
 };
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/live_regions_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/live_regions_test.js
index da7d4293..c9da6199 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/live_regions_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/live_regions_test.js
@@ -193,7 +193,7 @@
   mockFeedback.call(this.simulateUserInteraction.bind(this))
       .call(go.doDefault.bind(go))
       .expectSpeech('Focus')
-      .expectSpeech((candidate) => {
+      .expectSpeech(candidate => {
         return candidate.text === 'Live' &&
             (candidate.queueMode === QueueMode.CATEGORY_FLUSH ||
              candidate.queueMode === QueueMode.QUEUE);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js
index 76344775..5de3adc 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/media_automation_handler.js
@@ -25,7 +25,7 @@
 
     ChromeVox.tts.addCapturingEventListener(this);
 
-    chrome.automation.getDesktop((node) => {
+    chrome.automation.getDesktop(node => {
       this.node_ = node;
 
       this.addListener_(
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
index 1289c0d..cdff3053 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output.js
@@ -1356,12 +1356,12 @@
     const root = node;
     const walker = new AutomationTreeWalker(node, Dir.FORWARD, {
       visit: AutomationPredicate.leafOrStaticText,
-      leaf: (n) => {
+      leaf: n => {
         // The root might be a leaf itself, but we still want to descend
         // into it.
         return n !== root && AutomationPredicate.leafOrStaticText(n);
       },
-      root: (r) => r === root
+      root: r => r === root
     });
     const outputStrings = [];
     while (walker.next().node) {
@@ -2081,7 +2081,7 @@
       this.ancestry_(node, prevNode, type, buff, ruleStr, {preferEnd: true});
     }
 
-    range.start.node.boundsForRange(rangeStart, rangeEnd, (loc) => {
+    range.start.node.boundsForRange(rangeStart, rangeEnd, loc => {
       if (loc) {
         this.locations_.push(loc);
       }
@@ -2228,13 +2228,13 @@
       }
 
       const isWithinVirtualKeyboard = AutomationUtil.getAncestors(node).find(
-          (n) => n.role === RoleType.KEYBOARD);
+          n => n.role === RoleType.KEYBOARD);
       if (AutomationPredicate.clickable(node) && !isWithinVirtualKeyboard) {
         ret.push({msgId: 'hint_double_tap'});
       }
 
       const enteredVirtualKeyboard =
-          uniqueAncestors.find((n) => n.role === RoleType.KEYBOARD);
+          uniqueAncestors.find(n => n.role === RoleType.KEYBOARD);
       if (enteredVirtualKeyboard) {
         ret.push({msgId: 'hint_touch_type'});
       }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_format_parser.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_format_parser.js
index f916e19..97ccd4c 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_format_parser.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output/output_format_parser.js
@@ -71,7 +71,7 @@
    */
   parse(format) {
     const formatTrees = OutputFormatTree.parseFormat(format);
-    formatTrees.forEach((tree) => {
+    formatTrees.forEach(tree => {
       // Obtain the operator token.
       let token = tree.value;
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/panel/panel_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/panel/panel_background.js
index 7c4acfb..f070537 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/panel/panel_background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/panel/panel_background.js
@@ -39,7 +39,7 @@
     BridgeHelper.registerHandler(
         BridgeTargets.PANEL_BACKGROUND,
         BridgeActions.CREATE_ALL_NODE_MENU_BACKGROUNDS,
-        (opt_activateMenuTitle) =>
+        opt_activateMenuTitle =>
             PanelBackground.instance.createAllNodeMenuBackgrounds_(
                 opt_activateMenuTitle));
     BridgeHelper.registerHandler(
@@ -66,20 +66,18 @@
                 searchStr, dir, opt_nextObject));
     BridgeHelper.registerHandler(
         BridgeTargets.PANEL_BACKGROUND, BridgeActions.NODE_MENU_CALLBACK,
-        (callbackNodeIndex) =>
+        callbackNodeIndex =>
             PanelNodeMenuBackground.focusNodeCallback(callbackNodeIndex));
     BridgeHelper.registerHandler(
         BridgeTargets.PANEL_BACKGROUND,
         BridgeActions.PERFORM_CUSTOM_ACTION_ON_CURRENT_NODE,
-        (actionId) =>
-            PanelBackground.instance.performCustomActionOnCurrentNode_(
-                actionId));
+        actionId => PanelBackground.instance.performCustomActionOnCurrentNode_(
+            actionId));
     BridgeHelper.registerHandler(
         BridgeTargets.PANEL_BACKGROUND,
         BridgeActions.PERFORM_STANDARD_ACTION_ON_CURRENT_NODE,
-        (action) =>
-            PanelBackground.instance.performStandardActionOnCurrentNode_(
-                action));
+        action => PanelBackground.instance.performStandardActionOnCurrentNode_(
+            action));
     BridgeHelper.registerHandler(
         BridgeTargets.PANEL_BACKGROUND,
         BridgeActions.SET_RANGE_TO_I_SEARCH_NODE,
@@ -249,7 +247,7 @@
     return new Promise(async resolve => {
       const desktop = await new Promise(chrome.automation.getDesktop);
       // Watch for a focus event outside the panel.
-      const onFocus = (event) => {
+      const onFocus = event => {
         if (event.target.docUrl.contains('chromevox/panel')) {
           return;
         }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/pointer_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/pointer_handler.js
index ec85cf6..b1b44a0 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/pointer_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/pointer_handler.js
@@ -34,13 +34,13 @@
     /** @private {!Date} */
     this.lastHoverRequested_ = new Date();
 
-    chrome.automation.getDesktop((desktop) => {
+    chrome.automation.getDesktop(desktop => {
       this.node_ = desktop;
       this.addListener_(EventType.MOUSE_MOVED, this.onMouseMove);
 
       // This is needed for ARC++ and Lacros. They send mouse move and hit test
       // respectively. Each responds with hover.
-      this.addListener_(EventType.HOVER, (evt) => {
+      this.addListener_(EventType.HOVER, evt => {
         if (this.expectingHoverCount_ === 0) {
           return;
         }
@@ -63,7 +63,7 @@
       chrome.accessibilityPrivate.enableMouseEvents(true);
     }
 
-    chrome.chromeosInfoPrivate.get(['deviceType'], (result) => {
+    chrome.chromeosInfoPrivate.get(['deviceType'], result => {
       this.isChromebox_ = result['deviceType'] ===
           chrome.chromeosInfoPrivate.DeviceType.CHROMEBOX;
     });
@@ -90,7 +90,7 @@
     }
 
     const actOnNode = specificNode ? specificNode : this.node_;
-    actOnNode.hitTestWithReply(this.mouseX_, this.mouseY_, (target) => {
+    actOnNode.hitTestWithReply(this.mouseX_, this.mouseY_, target => {
       this.handleHitTestResult(target);
     });
   }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js
index 8e0d95d..57782ac 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/range_automation_handler.js
@@ -142,8 +142,7 @@
       let maybeControlledBy = evt.target;
       while (maybeControlledBy) {
         if (maybeControlledBy.controlledBy &&
-            maybeControlledBy.controlledBy.find(
-                (n) => Boolean(n.autoComplete))) {
+            maybeControlledBy.controlledBy.find(n => Boolean(n.autoComplete))) {
           clearTimeout(this.delayedAttributeOutputId_);
           this.delayedAttributeOutputId_ = setTimeout(() => {
             this.lastAttributeOutput_.go();
@@ -239,8 +238,8 @@
     const endRect = cur.end.node.location;
 
     const found =
-        oldFocusBounds.some((rect) => this.areRectsEqual_(rect, startRect)) &&
-        oldFocusBounds.some((rect) => this.areRectsEqual_(rect, endRect));
+        oldFocusBounds.some(rect => this.areRectsEqual_(rect, startRect)) &&
+        oldFocusBounds.some(rect => this.areRectsEqual_(rect, endRect));
     if (found) {
       return;
     }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js
index 78a65238..d979910 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/smart_sticky_mode.js
@@ -167,7 +167,7 @@
       while (!found && focus) {
         if (focus.activeDescendantFor && focus.activeDescendantFor.length) {
           found = focus.activeDescendantFor.find(
-              (n) => n.state[chrome.automation.StateType.EDITABLE]);
+              n => n.state[chrome.automation.StateType.EDITABLE]);
         }
 
         if (found) {
@@ -176,7 +176,7 @@
 
         if (focus.controlledBy && focus.controlledBy.length) {
           found = focus.controlledBy.find(
-              (n) => n.state[chrome.automation.StateType.EDITABLE]);
+              n => n.state[chrome.automation.StateType.EDITABLE]);
         }
 
         if (found) {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js
index 89054b8a..eb37079 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tts_background.js
@@ -380,7 +380,7 @@
     const utterance = this.currentUtterance_;
     const utteranceId = utterance.id;
 
-    utterance.properties['onEvent'] = (event) => {
+    utterance.properties['onEvent'] = event => {
       this.onTtsEvent_(event, utteranceId);
     };
 
@@ -583,7 +583,7 @@
   /** @override */
   removeCapturingEventListener(listener) {
     this.capturingTtsEventListeners_ =
-        this.capturingTtsEventListeners_.filter((item) => {
+        this.capturingTtsEventListeners_.filter(item => {
           return item !== listener;
         });
   }
@@ -709,7 +709,7 @@
    * @private
    */
   createPunctuationReplace_(clear) {
-    return (match) => {
+    return match => {
       const retain =
           this.retainPunctuation_.indexOf(match) !== -1 ? match : ' ';
       return clear ? retain :
@@ -774,10 +774,10 @@
    * @private
    */
   updateVoice_(voiceName, opt_callback) {
-    chrome.tts.getVoices((voices) => {
+    chrome.tts.getVoices(voices => {
       const systemVoice = {voiceName: constants.SYSTEM_VOICE};
       voices.unshift(systemVoice);
-      const newVoice = voices.find((v) => {
+      const newVoice = voices.find(v => {
         return v.voiceName === voiceName;
       }) ||
           systemVoice;
@@ -797,7 +797,7 @@
    * @private
    */
   updateFromPrefs_(announce, prefs) {
-    prefs.forEach((pref) => {
+    prefs.forEach(pref => {
       let msg;
       let propertyName;
       switch (pref.key) {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/user_action_monitor.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/user_action_monitor.js
index 8c32ef3..f93adc6a 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/user_action_monitor.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/user_action_monitor.js
@@ -350,7 +350,7 @@
 
 BridgeHelper.registerHandler(
     BridgeTargets.USER_ACTION_MONITOR, BridgeActions.CREATE,
-    (actions) =>
+    actions =>
         new Promise(resolve => UserActionMonitor.create(actions, resolve)));
 BridgeHelper.registerHandler(
     BridgeTargets.USER_ACTION_MONITOR, BridgeActions.DESTROY,
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/abstract_tts.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/abstract_tts.js
index 1e19dd5..07e2206 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/abstract_tts.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/abstract_tts.js
@@ -207,7 +207,7 @@
     // Since dollar and sterling pound signs will be replaced with text, move
     // them to after the number if they stay between a negative sign and a
     // number.
-    text = text.replace(AbstractTts.negativeCurrencyAmountRegexp_, (match) => {
+    text = text.replace(AbstractTts.negativeCurrencyAmountRegexp_, match => {
       const minus = match[0];
       const number = match.substring(2);
       const currency = match[1];
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/extension_bridge.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/extension_bridge.js
index 89255fc..14b7655e 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/extension_bridge.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/extension_bridge.js
@@ -134,7 +134,7 @@
   initBackground_() {
     this.id_ = 0;
     chrome.extension.onConnect.addListener(
-        (port) => this.backgroundOnConnectHandler_(port));
+        port => this.backgroundOnConnectHandler_(port));
   }
 
   /**
@@ -150,7 +150,7 @@
     this.portCache_.push(port);
 
     port.onMessage.addListener(
-        (message) => this.backgroundOnMessage_(message, port));
+        message => this.backgroundOnMessage_(message, port));
 
     port.onDisconnect.addListener(() => this.backgroundOnDisconnect_(port));
   }
@@ -168,7 +168,7 @@
       return;
     }
 
-    this.messageListeners_.forEach((listener) => listener(message, port));
+    this.messageListeners_.forEach(listener => listener(message, port));
   }
 
   /**
@@ -219,7 +219,7 @@
       this.gotPongFromBackgroundPage_(request[ExtensionBridge.PONG_MSG]);
     } else {
       this.messageListeners_.forEach(
-          (listener) => listener(request, this.backgroundPort_));
+          listener => listener(request, this.backgroundPort_));
     }
     sendResponse({});
   }
@@ -235,7 +235,7 @@
       return;
     }
     this.backgroundPort_.onMessage.addListener(
-        (message) => this.contentOnPortMessage_(message));
+        message => this.contentOnPortMessage_(message));
     this.backgroundPort_.onDisconnect.addListener(
         () => this.contentOnDisconnect_());
   }
@@ -345,7 +345,7 @@
    * @private
    */
   sendBackgroundToContentScript_(message) {
-    this.portCache_.forEach((port) => port.postMessage(message));
+    this.portCache_.forEach(port => port.postMessage(message));
   }
 }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/locale_output_helper.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/locale_output_helper.js
index 3f5c25a..c639d3f 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/locale_output_helper.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/locale_output_helper.js
@@ -34,7 +34,7 @@
     /** @private {!Array<!chrome.tts.TtsVoice>} */
     this.availableVoices_ = [];
     const setAvailableVoices = () => {
-      chrome.tts.getVoices((voices) => {
+      chrome.tts.getVoices(voices => {
         this.availableVoices_ = voices || [];
       });
     };
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/injected/extension_bridge.js b/chrome/browser/resources/chromeos/accessibility/chromevox/injected/extension_bridge.js
index 3feeb1c..7b9acbe 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/injected/extension_bridge.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/injected/extension_bridge.js
@@ -85,7 +85,7 @@
       return;
     }
     this.backgroundPort_.onMessage.addListener(
-        (message) => this.onMessage_(message));
+        message => this.onMessage_(message));
     this.backgroundPort_.onDisconnect.addListener(() => this.onDisconnect_());
   }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/learn_mode.js b/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/learn_mode.js
index d98bae43..a53871f 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/learn_mode.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/learn_mode/learn_mode.js
@@ -195,7 +195,7 @@
         const cells = new ArrayBuffer(1);
         const view = new Uint8Array(cells);
         view[0] = dots;
-        BackgroundBridge.BrailleBackground.backTranslate(cells).then((res) => {
+        BackgroundBridge.BrailleBackground.backTranslate(cells).then(res => {
           if (res !== null) {
             LearnMode.output(res);
           }
@@ -306,9 +306,9 @@
   static maybeClose_() {
     // Reset listeners and close this page if we somehow move outside of the
     // explorer window.
-    chrome.windows.getLastFocused({populate: true}, (focusedWindow) => {
+    chrome.windows.getLastFocused({populate: true}, focusedWindow => {
       if (focusedWindow && focusedWindow.focused &&
-          focusedWindow.tabs.find((tab) => {
+          focusedWindow.tabs.find(tab => {
             return tab.url === location.href;
           })) {
         return;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager.js
index a989c47c5..0f9cdf1 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager.js
@@ -174,7 +174,7 @@
     this.preferredDisplayAddress_ = display.address;
     localStorage['preferredBrailleDisplayAddress'] = display.address;
     if (!display.connected) {
-      chrome.bluetoothPrivate.connect(display.address, (result) => {
+      chrome.bluetoothPrivate.connect(display.address, result => {
         if (!display.paired) {
           chrome.bluetoothPrivate.pair(display.address);
         }
@@ -221,25 +221,25 @@
    * @protected
    */
   handleDevicesChanged(opt_device) {
-    chrome.bluetooth.getDevices((devices) => {
-      const displayList = devices.filter((device) => {
-        return this.displayNamePrefixes_.some((name) => {
+    chrome.bluetooth.getDevices(devices => {
+      const displayList = devices.filter(device => {
+        return this.displayNamePrefixes_.some(name => {
           return device.name && device.name.search(name) === 0;
         });
       });
       if (displayList.length === 0) {
         return;
       }
-      if (opt_device && !displayList.find((i) => i.name === opt_device.name)) {
+      if (opt_device && !displayList.find(i => i.name === opt_device.name)) {
         return;
       }
 
-      displayList.forEach((display) => {
+      displayList.forEach(display => {
         if (this.preferredDisplayAddress_ === display.address) {
           this.handlePreferredDisplayConnectionStateChanged(display);
         }
       });
-      this.listeners_.forEach((listener) => {
+      this.listeners_.forEach(listener => {
         listener.onDisplayListChanged(displayList);
       });
     });
@@ -253,7 +253,7 @@
     if (pairingEvent.pairing ===
         chrome.bluetoothPrivate.PairingEventType.REQUEST_PINCODE) {
       this.listeners_.forEach(
-          (listener) => listener.onPincodeRequested(pairingEvent.device));
+          listener => listener.onPincodeRequested(pairingEvent.device));
     }
   }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager_test.js
index 1de52cba..b95c153 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_manager_test.js
@@ -14,7 +14,7 @@
 chrome.brailleDisplayPrivate = {};
 /** Fake chrome.bluetooth object. */
 chrome.bluetooth = {};
-chrome.bluetooth.getDevices = (devices) => {};
+chrome.bluetooth.getDevices = devices => {};
 chrome.bluetooth.onDeviceAdded = new FakeChromeEvent();
 chrome.bluetooth.onDeviceChanged = new FakeChromeEvent();
 chrome.bluetooth.onDeviceRemoved = new FakeChromeEvent();
@@ -92,7 +92,7 @@
 TEST_F(
     'ChromeVoxBluetoothBrailleDisplayManagerWebUITest',
     'DisconnectPreviousPreferredOnConnectNewPreferred', function() {
-      chrome.bluetoothPrivate.connect = this.newCallback((address) => {
+      chrome.bluetoothPrivate.connect = this.newCallback(address => {
         assertEquals('abcd', address);
       });
       chrome.bluetoothPrivate.disconnectAll =
@@ -121,7 +121,7 @@
       const listener = new FakeBluetoothBrailleDisplayManagerListener();
       manager.addListener(listener);
       let devices = [];
-      chrome.bluetooth.getDevices = (callback) => callback(devices);
+      chrome.bluetooth.getDevices = callback => callback(devices);
 
       // No devices have been added, removed, or changed.
       manager.handleDevicesChanged();
@@ -157,14 +157,14 @@
     'ChromeVoxBluetoothBrailleDisplayManagerWebUITest',
     'ConnectPreferredTriggersBrlttyUpdate', function() {
       chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress =
-          this.newCallback((address) => {
+          this.newCallback(address => {
             assertEquals('abcd', address);
           });
 
       localStorage['preferredBrailleDisplayAddress'] = 'abcd';
       const manager = new BluetoothBrailleDisplayManager();
       let devices = [];
-      chrome.bluetooth.getDevices = (callback) => callback(devices);
+      chrome.bluetooth.getDevices = callback => callback(devices);
 
       // No devices.
       manager.handleDevicesChanged();
@@ -187,7 +187,7 @@
     'ForgetPreferredTriggersBrlttyUpdate', function() {
       chrome.bluetoothPrivate.forgetDevice = this.newCallback();
       chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress =
-          this.newCallback((address) => {
+          this.newCallback(address => {
             assertEquals('', address);
           });
 
@@ -203,7 +203,7 @@
     'DisconnectPreferredTriggersBrlttyUpdate', function() {
       chrome.bluetoothPrivate.disconnectAll = this.newCallback();
       chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress =
-          this.newCallback((address) => {
+          this.newCallback(address => {
             assertEquals('', address);
           });
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui.js
index 1554ed9..09e2b819 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui.js
@@ -60,7 +60,7 @@
     controls.appendChild(displaySelect);
     displaySelect.setAttribute(
         'aria-labelledby', 'bluetoothBrailleSelectLabel');
-    displaySelect.addEventListener('change', (evt) => {
+    displaySelect.addEventListener('change', evt => {
       this.updateControls_();
     });
 
@@ -100,12 +100,12 @@
     // Remove any displays that were removed.
     for (let i = 0; i < this.displaySelect_.children.length; i++) {
       const domDisplay = this.displaySelect_.children[i];
-      if (!displays.find((display) => domDisplay.id === display.address)) {
+      if (!displays.find(display => domDisplay.id === display.address)) {
         domDisplay.remove();
       }
     }
 
-    displays.forEach((display) => {
+    displays.forEach(display => {
       // Check if the element already exists.
       let displayContainer =
           this.displaySelect_.querySelector('#' + CSS.escape(display.address));
@@ -145,7 +145,7 @@
     form.appendChild(pincodeField);
 
     let timeoutId = -1;
-    form.addEventListener('submit', (evt) => {
+    form.addEventListener('submit', evt => {
       if (timeoutId) {
         clearTimeout(timeoutId);
       }
@@ -184,7 +184,7 @@
       return;
     }
 
-    chrome.bluetooth.getDevice(sel.id, (display) => {
+    chrome.bluetooth.getDevice(sel.id, display => {
       // Record metrics if the display is connected for the first time either
       // via a click of the Connect button or re-connection by selection via the
       // select.
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui_test.js
index 8ebc713..b801e71 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/bluetooth_braille_display_ui_test.js
@@ -65,7 +65,7 @@
       // Fake out getDevice using |display| as the backing source which changes
       // below.
       chrome.bluetooth.getDevice = (address, callback) => {
-        const display = displays.find((display) => display.address === address);
+        const display = displays.find(display => display.address === address);
         assertNotNullNorUndefined(display);
         callback(display);
       };
@@ -96,7 +96,7 @@
       // Fake out getDevice using |display| as the backing source which changes
       // below.
       chrome.bluetooth.getDevice = (address, callback) => {
-        const display = displays.find((display) => display.address === address);
+        const display = displays.find(display => display.address === address);
         assertNotNullNorUndefined(display);
         callback(display);
       };
@@ -210,7 +210,7 @@
   // Fake out getDevice using |display| as the backing source which changes
   // below.
   chrome.bluetooth.getDevice = (address, callback) => {
-    const display = displays.find((display) => display.address === address);
+    const display = displays.find(display => display.address === address);
     assertNotNullNorUndefined(display);
     callback(display);
   };
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
index 90f1b056..c6b1dce 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
@@ -112,7 +112,7 @@
       }
     });
 
-    $('openTtsSettings').addEventListener('click', (evt) => {
+    $('openTtsSettings').addEventListener('click', evt => {
       chrome.accessibilityPrivate.openSettingsSubpage(
           'manageAccessibility/tts');
     });
@@ -147,7 +147,7 @@
     document.addEventListener('click', OptionsPage.eventListener, false);
     document.addEventListener('keydown', OptionsPage.eventListener, false);
 
-    window.addEventListener('storage', (event) => {
+    window.addEventListener('storage', event => {
       if (event.key === 'speakTextUnderMouse') {
         chrome.accessibilityPrivate.enableMouseEvents(
             event.newValue === String(true));
@@ -195,7 +195,7 @@
       OptionsPage.bluetoothBrailleDisplayUI.attach(bluetoothBraille);
     }
 
-    $('usePitchChanges').addEventListener('click', (evt) => {
+    $('usePitchChanges').addEventListener('click', evt => {
       // The capitalStrategy pref depends on the value of usePitchChanges.
       // When usePitchChanges is toggled, we should update the preference value
       // and options for capitalStrategy.
@@ -286,7 +286,7 @@
           return 0;
         });
         addVoiceOption(Msgs.getMsg('system_voice'), constants.SYSTEM_VOICE);
-        voices.forEach((voice) => {
+        voices.forEach(voice => {
           addVoiceOption(voice.voiceName, voice.voiceName);
         });
       });
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js
index 9562331..4ec720d 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_test.js
@@ -29,7 +29,7 @@
       const desktop =
           await new Promise(resolve => chrome.automation.getDesktop(resolve));
       desktop.addEventListener(
-          EventType.LOAD_COMPLETE, (evt) => {
+          EventType.LOAD_COMPLETE, evt => {
             if (evt.target.docUrl.indexOf('options/options.html') === -1 ||
                 !evt.target.docLoaded) {
               return;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
index 040e876..b5395b29 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
@@ -33,7 +33,7 @@
     /** @type {string} */
     Panel.sessionState = '';
 
-    const updateSessionState = (sessionState) => {
+    const updateSessionState = sessionState => {
       Panel.sessionState = sessionState;
       $('options').disabled = sessionState !== 'IN_SESSION';
     };
@@ -382,7 +382,7 @@
       // Insert items from the bindings into the menus.
       const sawBindingSet = {};
       const gestures = Object.keys(GestureCommandData.GESTURE_COMMAND_MAP);
-      sortedBindings.forEach((binding) => {
+      sortedBindings.forEach(binding => {
         const command = binding.command;
         if (sawBindingSet[command]) {
           return;
@@ -1043,7 +1043,7 @@
 
   /** Open the tutorial. */
   static onTutorial() {
-    chrome.chromeosInfoPrivate.isTabletModeEnabled((enabled) => {
+    chrome.chromeosInfoPrivate.isTabletModeEnabled(enabled => {
       // Use tablet mode to decide the medium for the tutorial.
       const medium = enabled ? constants.InteractionMedium.TOUCH :
                                constants.InteractionMedium.KEYBOARD;
@@ -1097,12 +1097,12 @@
     // Add listeners. These are custom events fired from custom components.
     const backgroundPage = chrome.extension.getBackgroundPage();
 
-    $('chromevox-tutorial').addEventListener('closetutorial', async (evt) => {
+    $('chromevox-tutorial').addEventListener('closetutorial', async evt => {
       // Ensure UserActionMonitor is destroyed before closing tutorial.
       await BackgroundBridge.UserActionMonitor.destroy();
       Panel.onCloseTutorial();
     });
-    $('chromevox-tutorial').addEventListener('requestspeech', (evt) => {
+    $('chromevox-tutorial').addEventListener('requestspeech', evt => {
       /**
        * @type {{
        * text: string,
@@ -1122,7 +1122,7 @@
       cvox.tts.speak(text, queueMode, properties);
     });
     $('chromevox-tutorial')
-        .addEventListener('startinteractivemode', async (evt) => {
+        .addEventListener('startinteractivemode', async evt => {
           const actions = evt.detail.actions;
           await BackgroundBridge.UserActionMonitor.create(actions);
           await BackgroundBridge.UserActionMonitor.destroy();
@@ -1131,24 +1131,24 @@
           }
         });
     $('chromevox-tutorial')
-        .addEventListener('stopinteractivemode', async (evt) => {
+        .addEventListener('stopinteractivemode', async evt => {
           await BackgroundBridge.UserActionMonitor.destroy();
         });
-    $('chromevox-tutorial').addEventListener('requestfullydescribe', (evt) => {
+    $('chromevox-tutorial').addEventListener('requestfullydescribe', evt => {
       BackgroundBridge.CommandHandler.onCommand('fullyDescribe');
     });
-    $('chromevox-tutorial').addEventListener('requestearcon', (evt) => {
+    $('chromevox-tutorial').addEventListener('requestearcon', evt => {
       const earconId = evt.detail.earconId;
       backgroundPage['ChromeVox']['earcons']['playEarcon'](earconId);
     });
-    $('chromevox-tutorial').addEventListener('cancelearcon', (evt) => {
+    $('chromevox-tutorial').addEventListener('cancelearcon', evt => {
       const earconId = evt.detail.earconId;
       backgroundPage['ChromeVox']['earcons']['cancelEarcon'](earconId);
     });
     $('chromevox-tutorial').addEventListener('readyfortesting', () => {
       Panel.tutorialReadyForTesting_ = true;
     });
-    $('chromevox-tutorial').addEventListener('openUrl', async (evt) => {
+    $('chromevox-tutorial').addEventListener('openUrl', async evt => {
       const url = evt.detail.url;
       // Ensure UserActionMonitor is destroyed before closing tutorial.
       await BackgroundBridge.UserActionMonitor.destroy();
@@ -1270,7 +1270,7 @@
 
 BridgeHelper.registerHandler(
     BridgeConstants.Panel.TARGET, BridgeConstants.Panel.Action.ADD_MENU_ITEM,
-    (itemData) => Panel.addNodeMenuItem(itemData));
+    itemData => Panel.addNodeMenuItem(itemData));
 BridgeHelper.registerHandler(
     BridgeConstants.Panel.TARGET,
     BridgeConstants.Panel.Action.ON_CURRENT_RANGE_CHANGED,
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_menu.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_menu.js
index c3d67a3..ff4ce84 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_menu.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_menu.js
@@ -426,7 +426,7 @@
         this, menuItemTitle, menuItemShortcut, menuItemBraille, gesture,
         callback, 'result-number-' + this.searchResultCounter_.toString());
     // Ensure that item styling is updated on mouse hovers.
-    item.element.addEventListener('mouseover', (event) => {
+    item.element.addEventListener('mouseover', event => {
       this.resetItemAtActiveIndex();
     }, true);
     return item;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js
index 0558a96..adc4269c 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js
@@ -161,7 +161,7 @@
 
 // TODO(crbug.com/1088438): flaky crashes.
 TEST_F('ChromeVoxPanelTest', 'DISABLED_Gestures', async function() {
-  const doGestureAsync = async (gesture) => {
+  const doGestureAsync = async gesture => {
     doGesture(gesture)();
   };
   await this.runWithLoadedTree(`<button>Cancel</button><button>OK</button>`);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
index 9320614a..fd5bac3 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
@@ -657,7 +657,7 @@
   };
 
   // A helper to make assertions on four variables of interest.
-  const makeAssertions = (expectedVars) => {
+  const makeAssertions = expectedVars => {
     assertEquals(expectedVars.createdCount, userActionMonitorCreatedCount);
     assertEquals(expectedVars.destroyedCount, userActionMonitorDestroyedCount);
     assertEquals(expectedVars.interactiveMode, tutorial.interactiveMode_);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js
index da9c3ae..09ef2cd 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/chromevox_next_e2e_test_base.js
@@ -73,8 +73,8 @@
     for (const key in modifiers) {
       keyEvent[key] = modifiers[key];
     }
-    keyEvent.preventDefault = _ => {};
-    keyEvent.stopPropagation = _ => {};
+    keyEvent.preventDefault = () => {};
+    keyEvent.stopPropagation = () => {};
     return keyEvent;
   }
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/common.js b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/common.js
index 86703ff..0d502fc 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/common.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/common.js
@@ -25,8 +25,8 @@
     for (const key in modifiers) {
       keyEvent[key] = modifiers[key];
     }
-    keyEvent.preventDefault = _ => {};
-    keyEvent.stopPropagation = _ => {};
+    keyEvent.preventDefault = () => {};
+    keyEvent.stopPropagation = () => {};
     return keyEvent;
   }
 
@@ -38,7 +38,7 @@
    */
   static waitForSpeech(textStringToWaitFor) {
     return new Promise(resolve => {
-      ChromeVox.tts.speak = (textString) => {
+      ChromeVox.tts.speak = textString => {
         if (textString === textStringToWaitFor) {
           resolve();
         }
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/fake_dom.js b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/fake_dom.js
index 1e3c502..9f697b7 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/testing/fake_dom.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/testing/fake_dom.js
@@ -9,4 +9,4 @@
 goog.provide = () => {};
 goog.require = () => {};
 goog.addDependency = () => {};
-goog.isDef = (val) => val !== undefined;
+goog.isDef = val => val !== undefined;
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
index 1ad99467..caa78fc 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.html
@@ -247,13 +247,10 @@
     <div class="emoji-button-container">
       <button id="[[getEmojiButtonId(index)]]" data-index$="[[index]]"
         class$="[[getEmojiButtonClassName(item)]]"
+        on-mouseenter="showTooltip" on-focus="showTooltip"
         aria-label="[[getEmojiAriaLabel(item)]]">
         [[getDisplayEmojiForEmoji(item.base.string)]]
       </button>
-      <paper-tooltip for="[[getEmojiButtonId(index)]]"
-        fit-to-visible-bounds offset="8">
-        [[item.base.name]]
-      </paper-tooltip>
       <template is="dom-if"
         if="[[isEmojiVariantVisible(index,shownEmojiVariantIndex)]]">
         <emoji-variants
@@ -264,4 +261,7 @@
       </template>
     </div>
   </template>
+  <paper-tooltip id='tooltip' fit-to-visible-bounds offset="8">
+    [[focusedEmoji.base.name]]
+  </paper-tooltip>
 </div>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js
index 7256c42c..bb6041d 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js
@@ -27,6 +27,8 @@
       clearable: {type: Boolean, value: false},
       /** @type {boolean} */
       showClearRecents: {type: Boolean, value: false},
+      /** @private {?EmojiVariants} */
+      focusedEmoji: {type: Object, value: null},
       /** @type {string} */
       category: {
         type: String,
@@ -84,6 +86,31 @@
   }
 
   /**
+   * Sets and shows tooltips for an emoji button based on a mouse/focus event.
+   * By handling the on-focus and on-mouseenter events using this function,
+   * one single paper-tool is reused for all emojis in the emoji-group.
+   *
+   * @param {MouseEvent|FocusEvent} event
+   */
+  showTooltip(event) {
+    const emoji = this.findEmojiOfEmojiButton(event.target);
+
+    // If the event is for an emoji button that is not already
+    // focused, then replace the target of paper-tooltip with the new
+    // emoji button.
+    if (emoji && this.focusedEmoji !== emoji) {
+      this.focusedEmoji = emoji;
+
+      // Set the target of paper-tooltip to the focused emoji button.
+      // Paper-tooltip will un-listen the events of the previous target and
+      // starts listening the events for the focused emoji button to hide and
+      // show the tooltip at the right time.
+      this.$.tooltip.target = event.target;
+      this.$.tooltip.show();
+    }
+  }
+
+  /**
    * Handles event of clicking on an emoji button. It finds the emoji details
    * for the clicked emoji and fires another event including these the details.
    * Note: Initially, it validates and returns if the event is not for an
diff --git a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_port_forwarding.html b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_port_forwarding.html
index 2443208..9bb9456 100644
--- a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_port_forwarding.html
+++ b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_port_forwarding.html
@@ -109,7 +109,7 @@
           </div>
         </div>
         <template is="dom-repeat" items="[[allPorts_]]"
-            filter="[[byContainerId_(containerInfo.id)]]">
+            filter="[[byContainerId_(containerInfo.id)]]" mutable-data>
           <div class="list-item">
             <div id="crostiniPort[[cidx]]-[[index]]"
                 class="start"
@@ -139,7 +139,7 @@
                 aria-label="$i18n{crostiniPortForwardingToggleAriaLabel}"
                 aria-describedby$="crostiniPort[[cidx]]-[[index]] 
                     crostiniPortLabel[[cidx]]-[[index]]"
-                disabled="[[!crostiniRunning_]]">
+                disabled="[[!containerInfo.ipv4]]">
             </cr-toggle>
             <cr-icon-button 
                 id="showRemoveSinglePortMenu[[cidx]]-[[index]]"
diff --git a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_port_forwarding.js b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_port_forwarding.js
index 44cf996..092743ea 100644
--- a/chrome/browser/resources/settings/chromeos/crostini_page/crostini_port_forwarding.js
+++ b/chrome/browser/resources/settings/chromeos/crostini_page/crostini_port_forwarding.js
@@ -59,15 +59,6 @@
         notify: true,
       },
 
-      /**
-       * Whether Crostini is running.
-       * @private {boolean}
-       */
-      crostiniRunning_: {
-        type: Boolean,
-        value: false,
-      },
-
       /** @private */
       showAddPortDialog_: {
         type: Boolean,
@@ -93,7 +84,9 @@
       allContainers_: {
         type: Array,
         notify: true,
-        value: [],
+        value() {
+          return [];
+        },
       },
 
     };
@@ -127,14 +120,9 @@
         'crostini-port-forwarder-active-ports-changed',
         (ports) => this.onCrostiniPortsActiveStateChanged_(ports));
     this.addWebUIListener(
-        'crostini-status-changed',
-        (isRunning) => this.onCrostiniIsRunningStateChanged_(isRunning));
-    this.addWebUIListener(
         'crostini-container-info', (infos) => this.onContainerInfo_(infos));
     CrostiniBrowserProxyImpl.getInstance().getCrostiniActivePorts().then(
         (ports) => this.onCrostiniPortsActiveStateChanged_(ports));
-    CrostiniBrowserProxyImpl.getInstance().checkCrostiniIsRunning().then(
-        (isRunning) => this.onCrostiniIsRunningStateChanged_(isRunning));
     CrostiniBrowserProxyImpl.getInstance().requestContainerInfo();
   }
 
@@ -148,18 +136,10 @@
   }
 
   /**
-   * @param {boolean} isRunning boolean indicating if Crostini is running.
-   * @private
-   */
-  onCrostiniIsRunningStateChanged_(isRunning) {
-    this.crostiniRunning_ = isRunning;
-  }
-
-  /**
    * @param {!Array<!ContainerInfo>} containerInfos
    */
   onContainerInfo_(containerInfos) {
-    this.allContainers_ = containerInfos;
+    this.set('allContainers_', containerInfos);
   }
 
   /**
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/arc_detail_view.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/arc_detail_view.js
index d50d08b4..53b3ed9 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/arc_detail_view.js
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/arc_detail_view.js
@@ -7,7 +7,7 @@
 import './resize_lock_item.js';
 import './supported_links_item.js';
 import './shared_style.js';
-import 'chrome://resources/cr_components/app_management/icons.js';
+import 'chrome://resources/cr_components/app_management/icons.html.js';
 import 'chrome://resources/cr_components/app_management/more_permissions_item.js';
 import 'chrome://resources/cr_components/app_management/permission_item.js';
 import 'chrome://resources/cr_elements/icons.m.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/borealis_page/borealis_detail_view.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/borealis_page/borealis_detail_view.js
index 5ff220b0..d8d1be5 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/borealis_page/borealis_detail_view.js
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/borealis_page/borealis_detail_view.js
@@ -4,7 +4,7 @@
 
 import '../pin_to_shelf_item.js';
 import '../shared_style.js';
-import 'chrome://resources/cr_components/app_management/icons.js';
+import 'chrome://resources/cr_components/app_management/icons.html.js';
 import 'chrome://resources/cr_components/app_management/permission_item.js';
 import 'chrome://resources/cr_elements/icons.m.js';
 
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.js
index 1c512f06..0c2a466 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.js
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import '../pin_to_shelf_item.js';
-import 'chrome://resources/cr_components/app_management/icons.js';
+import 'chrome://resources/cr_components/app_management/icons.html.js';
 import 'chrome://resources/cr_components/app_management/permission_item.js';
 import '../shared_style.js';
 import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/pwa_detail_view.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/pwa_detail_view.js
index dee10bc7..47637a25 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/pwa_detail_view.js
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/pwa_detail_view.js
@@ -6,7 +6,7 @@
 import './supported_links_item.js';
 import './shared_style.js';
 import 'chrome://resources/cr_components/app_management/file_handling_item.js';
-import 'chrome://resources/cr_components/app_management/icons.js';
+import 'chrome://resources/cr_components/app_management/icons.html.js';
 import 'chrome://resources/cr_components/app_management/more_permissions_item.js';
 import 'chrome://resources/cr_components/app_management/permission_item.js';
 import 'chrome://resources/cr_elements/icons.m.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.html b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.html
index 77623b0..dac175f 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.html
@@ -1,6 +1,6 @@
 <template>
   <style
-      include="cr-shared-style app-management-shared-css cros-color-overrides">
+      include="cr-shared-style app-management-shared-style cros-color-overrides">
     .card-container {
       background-color: var(--cros-bg-color);
     }
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.js
index ffdc1f5..64df71d5 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.js
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_style.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import 'chrome://resources/cr_elements/chromeos/cros_color_overrides.m.js';
-import 'chrome://resources/cr_components/app_management/shared_style.js';
+import 'chrome://resources/cr_components/app_management/app_management_shared_style.css.js';
 
 const template = document.createElement('template');
 template.innerHTML = `
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_vars.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_vars.js
index 49d414e..f8fc7d5e 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_vars.js
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/shared_vars.js
@@ -4,7 +4,7 @@
 
 import 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import 'chrome://resources/cr_elements/shared_vars_css.m.js';
-import 'chrome://resources/cr_components/app_management/shared_vars.js';
+import 'chrome://resources/cr_components/app_management/shared_vars.css.js';
 
 const $_documentContainer = document.createElement('template');
 $_documentContainer.innerHTML = `{__html_template__}`;
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.js b/chrome/browser/resources/settings/chromeos/os_settings.js
index 3aa6602d..4e184b0 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings.js
@@ -55,7 +55,7 @@
 import './os_apps_page/app_management_page/borealis_page/borealis_detail_view.js';
 import './os_apps_page/app_management_page/chrome_app_detail_view.js';
 import './os_apps_page/app_management_page/dom_switch.js';
-import '//resources/cr_components/app_management/icons.js';
+import '//resources/cr_components/app_management/icons.html.js';
 import './os_apps_page/app_management_page/main_view.js';
 import './os_apps_page/app_management_page/pin_to_shelf_item.js';
 import './os_apps_page/app_management_page/plugin_vm_page/plugin_vm_detail_view.js';
diff --git a/chrome/browser/resources/settings/privacy_page/personalization_options.html b/chrome/browser/resources/settings/privacy_page/personalization_options.html
index 9d35ae4a..b21cd65 100644
--- a/chrome/browser/resources/settings/privacy_page/personalization_options.html
+++ b/chrome/browser/resources/settings/privacy_page/personalization_options.html
@@ -109,6 +109,15 @@
       </settings-toggle-button>
     </template>
 
+    <template is="dom-if" if="[[shouldShowAutofillAssistant_]]" restamp>
+      <settings-toggle-button id="enableAssistantFlows"
+          class="hr"
+          label="$i18n{autofillAssistantPref}"
+          sub-label="$i18n{autofillAssistantPrefDesc}"
+          pref="{{prefs.autofill_assistant.enabled}}">
+      </settings-toggle-button>
+    </template>
+
     <template is="dom-if" if="[[showSignoutDialog_]]" restamp>
       <settings-signout-dialog sync-status="[[syncStatus]]"
           on-close="onSignoutDialogClosed_">
diff --git a/chrome/browser/resources/settings/privacy_page/personalization_options.ts b/chrome/browser/resources/settings/privacy_page/personalization_options.ts
index e6deebe..53b6e4a 100644
--- a/chrome/browser/resources/settings/privacy_page/personalization_options.ts
+++ b/chrome/browser/resources/settings/privacy_page/personalization_options.ts
@@ -104,6 +104,12 @@
       },
       // </if>
 
+      shouldShowAutofillAssistant_: {
+        type: Boolean,
+        value: () => loadTimeData.valueExists('enableAutofillAssistant') &&
+            loadTimeData.getBoolean('enableAutofillAssistant'),
+      },
+
     };
   }
 
@@ -122,6 +128,8 @@
   private signinAvailable_: boolean;
   // </if>
 
+  private shouldShowAutofillAssistant_: boolean;
+
   private browserProxy_: PrivacyPageBrowserProxy =
       PrivacyPageBrowserProxyImpl.getInstance();
 
diff --git a/chrome/browser/speech/fake_speech_recognition_service.cc b/chrome/browser/speech/fake_speech_recognition_service.cc
index 78cf41e8..f1e1c303 100644
--- a/chrome/browser/speech/fake_speech_recognition_service.cc
+++ b/chrome/browser/speech/fake_speech_recognition_service.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/run_loop.h"
+#include "media/mojo/mojom/audio_data.mojom.h"
 #include "media/mojo/mojom/media_types.mojom.h"
 #include "media/mojo/mojom/speech_recognition_service.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/speech/fake_speech_recognition_service.h b/chrome/browser/speech/fake_speech_recognition_service.h
index 7d367a6..bd8648b 100644
--- a/chrome/browser/speech/fake_speech_recognition_service.h
+++ b/chrome/browser/speech/fake_speech_recognition_service.h
@@ -9,6 +9,7 @@
 
 #include "chrome/browser/speech/chrome_speech_recognition_service.h"
 #include "media/base/audio_parameters.h"
+#include "media/mojo/mojom/audio_data.mojom.h"
 #include "media/mojo/mojom/speech_recognition_service.mojom.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
diff --git a/chrome/browser/speech/speech_recognition_service_browsertest.cc b/chrome/browser/speech/speech_recognition_service_browsertest.cc
index 0801c91a..4a5e32e 100644
--- a/chrome/browser/speech/speech_recognition_service_browsertest.cc
+++ b/chrome/browser/speech/speech_recognition_service_browsertest.cc
@@ -32,6 +32,7 @@
 #include "media/audio/wav_audio_handler.h"
 #include "media/base/audio_bus.h"
 #include "media/base/media_switches.h"
+#include "media/mojo/mojom/audio_data.mojom.h"
 #include "media/mojo/mojom/audio_data_pipe.mojom.h"
 #include "media/mojo/mojom/audio_input_stream.mojom.h"
 #include "media/mojo/mojom/audio_stream_factory.mojom.h"
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index b1d70a7..2d813a5 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -854,9 +854,15 @@
      */
     protected void setToolbarHairlineColor(@ColorInt int toolbarColor) {
         final ImageView shadow = getRootView().findViewById(R.id.toolbar_hairline);
-        final int hairlineColor =
-                ThemeUtils.getToolbarHairlineColor(getContext(), toolbarColor, isIncognito());
-        shadow.setImageTintList(ColorStateList.valueOf(hairlineColor));
+        shadow.setImageTintList(ColorStateList.valueOf(getToolbarHairlineColor(toolbarColor)));
+    }
+
+    /**
+     * Returns the border color between the toolbar and WebContents area.
+     * @param toolbarColor Toolbar color
+     */
+    public @ColorInt int getToolbarHairlineColor(@ColorInt int toolbarColor) {
+        return ThemeUtils.getToolbarHairlineColor(getContext(), toolbarColor, isIncognito());
     }
 
     /**
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java
index 0e59df9..2350c91 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionControllerTest.java
@@ -12,6 +12,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
@@ -37,6 +38,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
@@ -155,6 +157,10 @@
                 DESIRED_AVATAR_SIZE);
     }
 
+    public ArgumentMatcher<ImageFetcher.Params> imageFetcherParamsHaveUrl(GURL url) {
+        return params -> params != null && params.url.equals(url.getSpec());
+    }
+
     @Test
     public void testShowAccountSignInHeader() {
         doAnswer(new Answer<Void>() {
@@ -200,7 +206,29 @@
                 IDP_METADATA, CLIENT_ID_METADATA, false /* isAutoSignIn */);
 
         PropertyModel headerModel = mModel.get(ItemProperties.HEADER);
+        // Brand icon should be transparent placeholder icon. This is useful so that the header text
+        // wrapping does not change in the case that the brand icon download succeeds.
+        assertNotNull(headerModel.get(IDP_BRAND_ICON));
+    }
+
+    /**
+     * Test that the FedCM account picker does not display the brand icon placeholder if the brand
+     * icon URL is empty.
+     */
+    @Test
+    public void testNoBrandIconUrl() {
+        IdentityProviderMetadata idpMetadataNoBrandIconUrl =
+                new IdentityProviderMetadata(Color.BLACK, Color.BLACK, "");
+        mMediator.showAccounts(TEST_ETLD_PLUS_ONE, TEST_ETLD_PLUS_ONE_1, Arrays.asList(ANA),
+                idpMetadataNoBrandIconUrl, CLIENT_ID_METADATA, false /* isAutoSignIn */);
+
+        PropertyModel headerModel = mModel.get(ItemProperties.HEADER);
         assertNull(headerModel.get(IDP_BRAND_ICON));
+
+        // The only downloaded icon should not be an IDP brand icon.
+        verify(mMockImageFetcher, times(1))
+                .fetchImage(
+                        argThat(imageFetcherParamsHaveUrl(TEST_PROFILE_PIC)), any(Callback.class));
     }
 
     @Test
diff --git a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java
index ee32aed..39ba191e 100644
--- a/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java
+++ b/chrome/browser/ui/android/webid/internal/java/src/org/chromium/chrome/browser/ui/android/webid/AccountSelectionMediator.java
@@ -5,7 +5,10 @@
 package org.chromium.chrome.browser.ui.android.webid;
 
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
 import android.os.Handler;
+import android.text.TextUtils;
 
 import androidx.annotation.Px;
 import androidx.annotation.VisibleForTesting;
@@ -173,11 +176,19 @@
     void showAccounts(String rpEtldPlusOne, String idpEtldPlusOne, List<Account> accounts,
             IdentityProviderMetadata idpMetadata, ClientIdMetadata clientMetadata,
             boolean isAutoSignIn) {
+        if (!TextUtils.isEmpty(idpMetadata.getBrandIconUrl())) {
+            // Use placeholder icon so that the header text wrapping does not change when the icon
+            // is fetched.
+            mBrandIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+            Canvas brandIconCanvas = new Canvas(mBrandIcon);
+            brandIconCanvas.drawColor(Color.TRANSPARENT);
+        }
+
         mSelectedAccount = accounts.size() == 1 ? accounts.get(0) : null;
         showAccountsInternal(rpEtldPlusOne, idpEtldPlusOne, accounts, idpMetadata, clientMetadata,
                 isAutoSignIn, /*focusItem=*/ItemProperties.HEADER);
 
-        if (idpMetadata.getBrandIconUrl() != null) {
+        if (!TextUtils.isEmpty(idpMetadata.getBrandIconUrl())) {
             int brandIconIdealSize = AccountSelectionBridge.getBrandIconIdealSize();
             ImageFetcher.Params params = ImageFetcher.Params.create(idpMetadata.getBrandIconUrl(),
                     ImageFetcher.WEB_ID_ACCOUNT_SELECTION_UMA_CLIENT_NAME, brandIconIdealSize,
diff --git a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
index b8cc56c..bf075e29 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_test_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -42,7 +43,9 @@
   const std::string user_id_hash =
       ProfileHelper::GetUserIdHashByUserIdForTesting(account_id.GetUserEmail());
   SessionManager::Get()->CreateSession(account_id, user_id_hash, false);
-  ProfileHelper::GetProfileByUserIdHashForTest(user_id_hash);
+  profiles::testing::CreateProfileSync(
+      g_browser_process->profile_manager(),
+      ProfileHelper::GetProfilePathByUserIdHash(user_id_hash));
   SessionManager::Get()->SessionStarted();
 }
 
diff --git a/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc b/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc
index 2c1e82b..49ef60f 100644
--- a/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc
+++ b/chrome/browser/ui/ash/shelf/app_service/exo_app_type_resolver.cc
@@ -111,4 +111,6 @@
     out_properties_container.SetProperty(
         app_restore::kParentToHiddenContainerKey, true);
   }
+
+  out_properties_container.SetProperty(aura::client::kSkipImeProcessing, true);
 }
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 30cb644..1138415 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -189,18 +189,9 @@
       [[fallthrough]];
     case ShowTranslateBubbleResult::SUCCESS:
       return translate::TranslateBubbleUiEvent::BUBBLE_SHOWN;
-    case ShowTranslateBubbleResult::BROWSER_WINDOW_NOT_VALID:
-      return translate::TranslateBubbleUiEvent::
-          BUBBLE_NOT_SHOWN_WINDOW_NOT_VALID;
     case ShowTranslateBubbleResult::BROWSER_WINDOW_MINIMIZED:
       return translate::TranslateBubbleUiEvent::
           BUBBLE_NOT_SHOWN_WINDOW_MINIMIZED;
-    case ShowTranslateBubbleResult::BROWSER_WINDOW_NOT_ACTIVE:
-      return translate::TranslateBubbleUiEvent::
-          BUBBLE_NOT_SHOWN_WINDOW_NOT_ACTIVE;
-    case ShowTranslateBubbleResult::WEB_CONTENTS_NOT_ACTIVE:
-      return translate::TranslateBubbleUiEvent::
-          BUBBLE_NOT_SHOWN_WEB_CONTENTS_NOT_ACTIVE;
     case ShowTranslateBubbleResult::EDITABLE_FIELD_IS_ACTIVE:
       return translate::TranslateBubbleUiEvent::
           BUBBLE_NOT_SHOWN_EDITABLE_FIELD_IS_ACTIVE;
diff --git a/chrome/browser/ui/translate/translate_bubble_model_impl.cc b/chrome/browser/ui/translate/translate_bubble_model_impl.cc
index 393007c..5ae3bd1 100644
--- a/chrome/browser/ui/translate/translate_bubble_model_impl.cc
+++ b/chrome/browser/ui/translate/translate_bubble_model_impl.cc
@@ -63,9 +63,6 @@
 void TranslateBubbleModelImpl::SetViewState(
     TranslateBubbleModel::ViewState view_state) {
   current_view_state_ = view_state;
-  if (view_state == TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE ||
-      view_state == TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE)
-    translate::ReportTranslateBubbleUiAction(translate::SET_STATE_OPTIONS);
 }
 
 void TranslateBubbleModelImpl::ShowError(
diff --git a/chrome/browser/ui/translate/translate_bubble_ui_action_logger.cc b/chrome/browser/ui/translate/translate_bubble_ui_action_logger.cc
index 2ded6dda8b..8b9561f 100644
--- a/chrome/browser/ui/translate/translate_bubble_ui_action_logger.cc
+++ b/chrome/browser/ui/translate/translate_bubble_ui_action_logger.cc
@@ -10,8 +10,9 @@
 namespace translate {
 
 void ReportTranslateBubbleUiAction(translate::TranslateBubbleUiEvent action) {
-  UMA_HISTOGRAM_ENUMERATION("Translate.BubbleUiEvent", action,
-                            translate::TRANSLATE_BUBBLE_UI_EVENT_MAX);
+  UMA_HISTOGRAM_ENUMERATION(
+      "Translate.BubbleUiEvent", action,
+      translate::TranslateBubbleUiEvent::TRANSLATE_BUBBLE_UI_EVENT_MAX);
 }
 
 }  // namespace translate
diff --git a/chrome/browser/ui/translate/translate_bubble_ui_action_logger.h b/chrome/browser/ui/translate/translate_bubble_ui_action_logger.h
index 36bb7514..3cbca4f 100644
--- a/chrome/browser/ui/translate/translate_bubble_ui_action_logger.h
+++ b/chrome/browser/ui/translate/translate_bubble_ui_action_logger.h
@@ -7,14 +7,14 @@
 
 namespace translate {
 
-enum TranslateBubbleUiEvent {
+enum class TranslateBubbleUiEvent {
   // Update TranslateBubbleUiEvent in enums.xml when making changes.
   // Start with 1 to match existing UMA values: see http://crbug.com/612558
   // The user clicked the advanced option.
-  SET_STATE_OPTIONS = 1,
+  // [DEPRECATED] SET_STATE_OPTIONS = 1,
 
   // The user clicked "Done" and went back from the advanced option.
-  LEAVE_STATE_OPTIONS = 2,
+  // [DEPRECATED] LEAVE_STATE_OPTIONS = 2,
 
   // The user clicked the advanced link.
   // [DEPRECATED] ADVANCED_LINK_CLICKED = 3,
@@ -34,14 +34,14 @@
   // The user selected "Never translate this site" in the "Options" menu.
   NEVER_TRANSLATE_SITE_MENU_CLICKED = 8,
 
-  // The user clicked the "Translate" button.
-  TRANSLATE_BUTTON_CLICKED = 9,
+  // The user clicked the target language tab to start a translation.
+  TARGET_LANGUAGE_TAB_SELECTED = 9,
 
   // The user clicked the "Done" button.
   DONE_BUTTON_CLICKED = 10,
 
   // The user clicked the "Cancel" button.
-  CANCEL_BUTTON_CLICKED = 11,
+  // [DEPRECATED] CANCEL_BUTTON_CLICKED = 11,
 
   // The user clicked the "Closed" [X] button.
   CLOSE_BUTTON_CLICKED = 12,
@@ -49,17 +49,17 @@
   // The user clicked the "Try Again" button.
   TRY_AGAIN_BUTTON_CLICKED = 13,
 
-  // The user clicked the "Show Original" button.
-  SHOW_ORIGINAL_BUTTON_CLICKED = 14,
+  // The user clicked the source language tab to revert the translation.
+  SOURCE_LANGUAGE_TAB_SELECTED = 14,
 
   // The user clicked the "Settings" link.
   // [DEPRECATED] SETTINGS_LINK_CLICKED = 15,
 
-  // The user changed the "Source language".
-  SOURCE_LANGUAGE_MENU_CLICKED = 16,
+  // The user made a selection in the source language combobox.
+  SOURCE_LANGUAGE_MENU_ITEM_CLICKED = 16,
 
-  // The user changed the "Target language".
-  TARGET_LANGUAGE_MENU_CLICKED = 17,
+  // The user made a selection in the target language combobox.
+  TARGET_LANGUAGE_MENU_ITEM_CLICKED = 17,
 
   // The user activated the translate page action icon.
   // [DEPRECATED] PAGE_ACTION_ICON_ACTIVATED = 18,
@@ -71,14 +71,16 @@
   BUBBLE_SHOWN = 20,
 
   // The translate bugbble could not be shown to the user, for various reasons.
-  BUBBLE_NOT_SHOWN_WINDOW_NOT_VALID = 21,
+  // [DEPRECATED] BUBBLE_NOT_SHOWN_WINDOW_NOT_VALID = 21,
   BUBBLE_NOT_SHOWN_WINDOW_MINIMIZED = 22,
-  BUBBLE_NOT_SHOWN_WINDOW_NOT_ACTIVE = 23,
-  BUBBLE_NOT_SHOWN_WEB_CONTENTS_NOT_ACTIVE = 24,
+  // [DEPRECATED] BUBBLE_NOT_SHOWN_WINDOW_NOT_ACTIVE = 23,
+  // [DEPRECATED] BUBBLE_NOT_SHOWN_WEB_CONTENTS_NOT_ACTIVE = 24,
   BUBBLE_NOT_SHOWN_EDITABLE_FIELD_IS_ACTIVE = 25,
 
-  // The user clicked the advanced menu item.
-  ADVANCED_MENU_CLICKED = 26,
+  // The user clicked the “Page is Not in {Source Language}” item, or the
+  // “Choose Another Language” item, in the options
+  // menu.
+  CHANGE_SOURCE_OR_TARGET_LANGUAGE_OPTIONS_CLICKED = 26,
 
   // The user clicked the advanced button.
   // [DEPRECATED] ADVANCED_BUTTON_CLICKED = 27,
diff --git a/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.cc b/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.cc
index b8b3f61..3ea9423 100644
--- a/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.cc
+++ b/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.cc
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/check.h"
 #include "base/feature_list.h"
 #include "base/i18n/case_conversion.h"
 #include "base/notreached.h"
@@ -217,11 +218,10 @@
       allow_pinning_(allow_pinning),
       requests_access_{
           nullptr, nullptr, nullptr,
-          IDS_EXTENSIONS_MENU_SITE_ACCESS_TAB_REQUESTS_ACCESS_SECTION_TITLE,
-          extensions::SitePermissionsHelper::SiteInteraction::kPending},
-      has_access_{nullptr, nullptr, nullptr,
-                  IDS_EXTENSIONS_MENU_SITE_ACCESS_TAB_HAS_ACCESS_SECTION_TITLE,
-                  extensions::SitePermissionsHelper::SiteInteraction::kActive} {
+          IDS_EXTENSIONS_MENU_SITE_ACCESS_TAB_REQUESTS_ACCESS_SECTION_TITLE},
+      has_access_{
+          nullptr, nullptr, nullptr,
+          IDS_EXTENSIONS_MENU_SITE_ACCESS_TAB_HAS_ACCESS_SECTION_TITLE} {
   views::Builder<ExtensionsTabbedMenuView>(this)
       .SetLayoutManager(std::make_unique<views::BoxLayout>(
           views::BoxLayout::Orientation::kVertical))
@@ -683,10 +683,18 @@
       continue;
     }
 
+    DCHECK(section);
+    auto* new_section = GetSectionForSiteInteraction(
+        item->view_controller()->GetSiteInteraction(GetActiveWebContents()));
+
+    // Remove item when it is no section at all.
+    if (!new_section) {
+      section->items->RemoveChildViewT(item);
+      return;
+    }
+
     // Reorder item when it is in the same section.
-    auto site_interaction =
-        item->view_controller()->GetSiteInteraction(GetActiveWebContents());
-    if (site_interaction == section->site_interaction) {
+    if (new_section == section) {
       item->Update();
       int new_index =
           FindIndex(section->items, item->view_controller()->GetActionName());
@@ -694,14 +702,9 @@
       return;
     }
 
-    // Remove item when it is in a different section or no section at all.
+    // Re insert item when it is in the incorrect section.
     std::unique_ptr<SiteAccessMenuItemView> item_to_move =
         section->items->RemoveChildViewT(item);
-    auto* new_section = GetSectionForSiteInteraction(site_interaction);
-    if (!new_section)
-      return;
-
-    // Re insert item to the correct section.
     item_to_move->Update();
     InsertSiteAccessItem(std::move(item_to_move), new_section);
   }
diff --git a/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.h b/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.h
index 170913b..ca1508af 100644
--- a/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.h
+++ b/chrome/browser/ui/views/extensions/extensions_tabbed_menu_view.h
@@ -139,9 +139,6 @@
     // The id of the string to use for the section heading. Does not include the
     // current site string.
     const int header_string_id;
-
-    // The site interaction that this section is handling.
-    const extensions::SitePermissionsHelper::SiteInteraction site_interaction;
   };
 
   // Initially creates the tabs.
diff --git a/chrome/browser/ui/views/translate/translate_bubble_controller.cc b/chrome/browser/ui/views/translate/translate_bubble_controller.cc
index 02b5095..1841b28 100644
--- a/chrome/browser/ui/views/translate/translate_bubble_controller.cc
+++ b/chrome/browser/ui/views/translate/translate_bubble_controller.cc
@@ -84,7 +84,8 @@
   translate_bubble_view_->SetViewState(step, error_type);
 
   translate_bubble_view_->ShowForReason(reason);
-  translate::ReportTranslateBubbleUiAction(translate::BUBBLE_SHOWN);
+  translate::ReportTranslateBubbleUiAction(
+      translate::TranslateBubbleUiEvent::BUBBLE_SHOWN);
 
   translate_bubble_view_->model()->ReportUIChange(true);
 
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.cc b/chrome/browser/ui/views/translate/translate_bubble_view.cc
index 097eae4e..51ec314 100644
--- a/chrome/browser/ui/views/translate/translate_bubble_view.cc
+++ b/chrome/browser/ui/views/translate/translate_bubble_view.cc
@@ -376,7 +376,8 @@
         should_always_translate_ = false;
         model_->SetAlwaysTranslate(should_always_translate_);
         translate::ReportTranslateBubbleUiAction(
-            translate::NEVER_TRANSLATE_LANGUAGE_MENU_CLICKED);
+            translate::TranslateBubbleUiEvent::
+                NEVER_TRANSLATE_LANGUAGE_MENU_CLICKED);
         model_->SetNeverTranslateLanguage(true);
         RevertOrDeclineTranslation();
       } else {
@@ -390,7 +391,8 @@
       should_never_translate_site_ = !should_never_translate_site_;
       if (should_never_translate_site_) {
         translate::ReportTranslateBubbleUiAction(
-            translate::NEVER_TRANSLATE_SITE_MENU_CLICKED);
+            translate::TranslateBubbleUiEvent::
+                NEVER_TRANSLATE_SITE_MENU_CLICKED);
         model_->SetNeverTranslateSite(true);
         RevertOrDeclineTranslation();
       } else {
@@ -400,13 +402,15 @@
 
     case OptionsMenuItem::CHANGE_TARGET_LANGUAGE:
       translate::ReportTranslateBubbleUiAction(
-          translate::ADVANCED_MENU_CLICKED);
+          translate::TranslateBubbleUiEvent::
+              CHANGE_SOURCE_OR_TARGET_LANGUAGE_OPTIONS_CLICKED);
       SwitchView(TranslateBubbleModel::VIEW_STATE_TARGET_LANGUAGE);
       break;
 
     case OptionsMenuItem::CHANGE_SOURCE_LANGUAGE:
       translate::ReportTranslateBubbleUiAction(
-          translate::ADVANCED_MENU_CLICKED);
+          translate::TranslateBubbleUiEvent::
+              CHANGE_SOURCE_OR_TARGET_LANGUAGE_OPTIONS_CLICKED);
       SwitchView(TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE);
       break;
 
@@ -486,7 +490,8 @@
   model_->ReportUIInteraction(translate::UIInteraction::kTranslate);
   model_->Translate();
   SwitchView(TranslateBubbleModel::VIEW_STATE_TRANSLATING);
-  translate::ReportTranslateBubbleUiAction(translate::TRANSLATE_BUTTON_CLICKED);
+  translate::ReportTranslateBubbleUiAction(
+      translate::TranslateBubbleUiEvent::TARGET_LANGUAGE_TAB_SELECTED);
 }
 
 void TranslateBubbleView::ShowOriginal() {
@@ -494,7 +499,7 @@
   model_->RevertTranslation();
   SwitchView(TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE);
   translate::ReportTranslateBubbleUiAction(
-      translate::SHOW_ORIGINAL_BUTTON_CLICKED);
+      translate::TranslateBubbleUiEvent::SOURCE_LANGUAGE_TAB_SELECTED);
 }
 
 void TranslateBubbleView::ConfirmAdvancedOptions() {
@@ -514,7 +519,8 @@
     SwitchView(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE);
   }
 
-  translate::ReportTranslateBubbleUiAction(translate::DONE_BUTTON_CLICKED);
+  translate::ReportTranslateBubbleUiAction(
+      translate::TranslateBubbleUiEvent::DONE_BUTTON_CLICKED);
 }
 
 void TranslateBubbleView::SourceLanguageChanged() {
@@ -523,7 +529,7 @@
       source_language_combobox_->GetSelectedIndex());
   UpdateAdvancedView();
   translate::ReportTranslateBubbleUiAction(
-      translate::SOURCE_LANGUAGE_MENU_CLICKED);
+      translate::TranslateBubbleUiEvent::SOURCE_LANGUAGE_MENU_ITEM_CLICKED);
 }
 
 void TranslateBubbleView::TargetLanguageChanged() {
@@ -532,7 +538,7 @@
       target_language_combobox_->GetSelectedIndex());
   UpdateAdvancedView();
   translate::ReportTranslateBubbleUiAction(
-      translate::TARGET_LANGUAGE_MENU_CLICKED);
+      translate::TranslateBubbleUiEvent::TARGET_LANGUAGE_MENU_ITEM_CLICKED);
 }
 
 void TranslateBubbleView::AlwaysTranslatePressed() {
@@ -540,8 +546,9 @@
       translate::UIInteraction::kAlwaysTranslateLanguage);
   should_always_translate_ = GetAlwaysTranslateCheckbox()->GetChecked();
   translate::ReportTranslateBubbleUiAction(
-      should_always_translate_ ? translate::ALWAYS_TRANSLATE_CHECKED
-                               : translate::ALWAYS_TRANSLATE_UNCHECKED);
+      should_always_translate_
+          ? translate::TranslateBubbleUiEvent::ALWAYS_TRANSLATE_CHECKED
+          : translate::TranslateBubbleUiEvent::ALWAYS_TRANSLATE_UNCHECKED);
   // In the tab UI the always translate button should apply immediately
   // except for in an advanced view.
   if (GetViewState() != TranslateBubbleModel::VIEW_STATE_SOURCE_LANGUAGE) {
@@ -738,7 +745,7 @@
       base::BindRepeating(
           [](TranslateBubbleModel* model) {
             translate::ReportTranslateBubbleUiAction(
-                translate::TRY_AGAIN_BUTTON_CLICKED);
+                translate::TranslateBubbleUiEvent::TRY_AGAIN_BUTTON_CLICKED);
             model->Translate();
           },
           base::Unretained(model_.get())),
@@ -980,7 +987,7 @@
       views::BubbleFrameView::CreateCloseButton(base::BindRepeating(
           [](View* view) {
             translate::ReportTranslateBubbleUiAction(
-                translate::CLOSE_BUTTON_CLICKED);
+                translate::TranslateBubbleUiEvent::CLOSE_BUTTON_CLICKED);
             view->GetWidget()->CloseWithReason(
                 views::Widget::ClosedReason::kCloseButtonClicked);
           },
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view.cc b/chrome/browser/ui/views/webid/account_selection_bubble_view.cc
index c7312d0d..fd30186 100644
--- a/chrome/browser/ui/views/webid/account_selection_bubble_view.cc
+++ b/chrome/browser/ui/views/webid/account_selection_bubble_view.cc
@@ -160,23 +160,27 @@
   std::u16string title = l10n_util::GetStringFUTF16(
       IDS_ACCOUNT_SELECTION_SHEET_TITLE_EXPLICIT,
       base::UTF8ToUTF16(rp_etld_plus_one), idp_etld_plus_one_);
-  header_view_ = AddChildView(CreateHeaderView(title));
+  bool has_icon = idp_metadata.brand_icon_url.is_valid();
+  header_view_ = AddChildView(CreateHeaderView(title, has_icon));
   AddChildView(std::make_unique<views::Separator>());
   AddChildView(CreateAccountChooser(accounts));
 
-  image_fetcher::ImageFetcherParams params(kTrafficAnnotation,
-                                           kImageFetcherUmaClient);
-  image_fetcher_->FetchImage(
-      idp_metadata.brand_icon_url,
-      base::BindOnce(&AccountSelectionBubbleView::OnBrandImageFetched,
-                     weak_ptr_factory_.GetWeakPtr()),
-      std::move(params));
+  if (has_icon) {
+    image_fetcher::ImageFetcherParams params(kTrafficAnnotation,
+                                             kImageFetcherUmaClient);
+    image_fetcher_->FetchImage(
+        idp_metadata.brand_icon_url,
+        base::BindOnce(&AccountSelectionBubbleView::OnBrandImageFetched,
+                       weak_ptr_factory_.GetWeakPtr()),
+        std::move(params));
+  }
 }
 
 AccountSelectionBubbleView::~AccountSelectionBubbleView() = default;
 
 std::unique_ptr<views::View> AccountSelectionBubbleView::CreateHeaderView(
-    const std::u16string& title) {
+    const std::u16string& title,
+    bool has_icon) {
   auto header = std::make_unique<views::View>();
   // Do not use a top margin as it has already been set in the bubble.
   header->SetLayoutManager(std::make_unique<views::FlexLayout>())
@@ -184,10 +188,15 @@
           0, kLeftRightPadding, kVerticalSpacing, kLeftRightPadding));
 
   // Add the icon.
-  auto image_view = std::make_unique<views::ImageView>();
-  image_view->SetProperty(views::kMarginsKey,
-                          gfx::Insets().set_right(kLeftRightPadding));
-  bubble_icon_view_ = header->AddChildView(image_view.release());
+  if (has_icon) {
+    // Show placeholder brand icon prior to brand icon being fetched so that
+    // header text wrapping does not change when brand icon is fetched.
+    auto image_view = std::make_unique<views::ImageView>();
+    image_view->SetImageSize(gfx::Size(kDesiredIconSize, kDesiredIconSize));
+    image_view->SetProperty(views::kMarginsKey,
+                            gfx::Insets().set_right(kLeftRightPadding));
+    bubble_icon_view_ = header->AddChildView(image_view.release());
+  }
 
   // Add the title.
   title_label_ = header->AddChildView(std::make_unique<views::Label>(
@@ -437,7 +446,7 @@
 void AccountSelectionBubbleView::OnBrandImageFetched(
     const gfx::Image& image,
     const image_fetcher::RequestMetadata& metadata) {
-  if (image.Width() == image.Height() &&
+  if (bubble_icon_view_ != nullptr && image.Width() == image.Height() &&
       image.Width() >= AccountSelectionView::GetBrandIconMinimumSize()) {
     gfx::ImageSkia resized_image = gfx::ImageSkiaOperations::CreateResizedImage(
         image.AsImageSkia(), skia::ImageOperations::RESIZE_LANCZOS3,
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view.h b/chrome/browser/ui/views/webid/account_selection_bubble_view.h
index 932eeb29..2af8ace 100644
--- a/chrome/browser/ui/views/webid/account_selection_bubble_view.h
+++ b/chrome/browser/ui/views/webid/account_selection_bubble_view.h
@@ -42,7 +42,8 @@
  private:
   // Returns a View containing the logo of the identity provider and the title
   // of the bubble, properly formatted.
-  std::unique_ptr<views::View> CreateHeaderView(const std::u16string& title);
+  std::unique_ptr<views::View> CreateHeaderView(const std::u16string& title,
+                                                bool has_icon);
 
   void CloseBubble();
 
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc b/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc
index 7f7f9f5..8968a0e 100644
--- a/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/webid/account_selection_bubble_view_unittest.cc
@@ -145,20 +145,15 @@
     EXPECT_FALSE(dialog()->GetCancelButton());
 
     std::vector<views::View*> header_children = header->children();
-    ASSERT_EQ(header_children.size(), 3u);
-
-    // Check logo image.
-    views::ImageView* image_view =
-        static_cast<views::ImageView*>(header_children[0]);
-    EXPECT_TRUE(image_view);
+    ASSERT_EQ(header_children.size(), 2u);
 
     // Check title text.
-    views::Label* title_view = static_cast<views::Label*>(header_children[1]);
+    views::Label* title_view = static_cast<views::Label*>(header_children[0]);
     ASSERT_TRUE(title_view);
     EXPECT_EQ(title_view->GetText(), title);
 
     // Check close button.
-    views::Button* button = static_cast<views::Button*>(header_children[2]);
+    views::Button* button = static_cast<views::Button*>(header_children[1]);
     EXPECT_TRUE(button);
 
     // Check separator.
diff --git a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
index 6b5d7ce..4ac20d97 100644
--- a/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/crostini_handler.cc
@@ -152,6 +152,10 @@
       "shutdownCrostini",
       base::BindRepeating(&CrostiniHandler::HandleShutdownCrostini,
                           handler_weak_ptr_factory_.GetWeakPtr()));
+  web_ui()->RegisterMessageCallback(
+      "requestContainerInfo",
+      base::BindRepeating(&CrostiniHandler::HandleRequestContainerInfo,
+                          handler_weak_ptr_factory_.GetWeakPtr()));
   if (crostini::CrostiniFeatures::Get()->IsMultiContainerAllowed(profile_)) {
     web_ui()->RegisterMessageCallback(
         "createContainer",
@@ -162,10 +166,6 @@
         base::BindRepeating(&CrostiniHandler::HandleDeleteContainer,
                             handler_weak_ptr_factory_.GetWeakPtr()));
     web_ui()->RegisterMessageCallback(
-        "requestContainerInfo",
-        base::BindRepeating(&CrostiniHandler::HandleRequestContainerInfo,
-                            handler_weak_ptr_factory_.GetWeakPtr()));
-    web_ui()->RegisterMessageCallback(
         "setContainerBadgeColor",
         base::BindRepeating(&CrostiniHandler::HandleSetContainerBadgeColor,
                             handler_weak_ptr_factory_.GetWeakPtr()));
@@ -697,6 +697,7 @@
   VLOG(1) << "Creating container_id = " << container_id;
 
   crostini::CrostiniManager::RestartOptions options;
+  options.restart_source = crostini::RestartSource::kMultiContainerCreation;
   if (image_server_url.is_valid()) {
     options.image_server_url = image_server_url.spec();
     VLOG(1) << "image_server_url = " << image_server_url;
@@ -757,9 +758,6 @@
   constexpr char kIdKey[] = "id";
   constexpr char kIpv4Key[] = "ipv4";
 
-  if (!crostini::CrostiniFeatures::Get()->IsMultiContainerAllowed(profile_)) {
-    return;
-  }
   base::Value::List container_info_list;
 
   const base::Value::List& containers =
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index bda0b74e..418fbca 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -279,6 +279,13 @@
       "enableSendPasswords",
       base::FeatureList::IsEnabled(password_manager::features::kSendPasswords));
 
+  // Autofill Assistant on Desktop is currently used only by password change.
+  // As soon as it becomes more widely used, this condition needs to be
+  // adjusted.
+  html_source->AddBoolean(
+      "enableAutofillAssistant",
+      password_manager::features::IsAutomatedPasswordChangeEnabled());
+
 #if !BUILDFLAG(IS_CHROMEOS)
   html_source->AddBoolean(
       "enableDesktopDetailedLanguageSettings",
diff --git a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
index 89e7ebf..600283a 100644
--- a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
@@ -205,6 +205,8 @@
     {"linkDoctorPrefDesc", IDS_SETTINGS_LINKDOCTOR_PREF_DESC},
     {"driveSuggestPref", IDS_DRIVE_SUGGEST_PREF},
     {"driveSuggestPrefDesc", IDS_DRIVE_SUGGEST_PREF_DESC},
+    {"autofillAssistantPref", IDS_SETTINGS_AUTOFILL_ASSISTANT_PREF},
+    {"autofillAssistantPrefDesc", IDS_SETTINGS_AUTOFILL_ASSISTANT_PREF_DESC},
   };
   html_source->AddLocalizedStrings(kLocalizedStrings);
 }
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc
index 77a27c0..230700e1 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc
@@ -562,7 +562,7 @@
   // (https://crbug.com/1060398).
   const int group_color_id =
       GetThumbnailTabStripTabGroupColorId(visual_data->color(), true);
-  const SkColor group_color = embedder_->GetColor(group_color_id);
+  const SkColor group_color = embedder_->GetColorProviderColor(group_color_id);
   tab_group->color = color_utils::SkColorToRgbString(group_color);
   // TODO(tluk): Incorporate the text color into the ColorProvider.
   tab_group->text_color = color_utils::SkColorToRgbString(
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc
index 2ae166c..fb9822d2 100644
--- a/chrome/browser/web_applications/web_app_registrar.cc
+++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -277,7 +277,7 @@
   size_t best_score = 0U;
   bool best_app_is_shortcut = true;
 
-  for (const AppId& app_id : GetAppIdsForAppSet(GetAppsIncludingStubs())) {
+  for (const AppId& app_id : GetAppIdsForAppSet(GetApps())) {
     // TODO(crbug.com/910016): Treat shortcuts as PWAs.
     bool app_is_shortcut = IsShortcutApp(app_id);
     if (app_is_shortcut && !best_app_is_shortcut)
diff --git a/chrome/browser/web_applications/web_app_registrar_unittest.cc b/chrome/browser/web_applications/web_app_registrar_unittest.cc
index d7a33fe..415a3f8 100644
--- a/chrome/browser/web_applications/web_app_registrar_unittest.cc
+++ b/chrome/browser/web_applications/web_app_registrar_unittest.cc
@@ -517,6 +517,7 @@
   const GURL app1_scope("https://example.com/app");
   const GURL app2_scope("https://example.com/app-two");
   const GURL app3_scope("https://not-example.com/app");
+  const GURL app4_scope("https://app-four.com/");
 
   const AppId app1_id =
       GenerateAppId(/*manifest_id=*/absl::nullopt, app1_scope);
@@ -524,6 +525,8 @@
       GenerateAppId(/*manifest_id=*/absl::nullopt, app2_scope);
   const AppId app3_id =
       GenerateAppId(/*manifest_id=*/absl::nullopt, app3_scope);
+  const AppId app4_id =
+      GenerateAppId(/*manifest_id=*/absl::nullopt, app3_scope);
 
   auto app1 = test::CreateWebApp(app1_scope);
   app1->SetScope(app1_scope);
@@ -538,6 +541,10 @@
       registrar().FindAppWithUrlInScope(app3_scope);
   EXPECT_FALSE(app3_match);
 
+  absl::optional<AppId> app4_match =
+      registrar().FindAppWithUrlInScope(app4_scope);
+  EXPECT_FALSE(app4_match);
+
   auto app2 = test::CreateWebApp(app2_scope);
   app2->SetScope(app2_scope);
   RegisterApp(std::move(app2));
@@ -546,6 +553,11 @@
   app3->SetScope(app3_scope);
   RegisterApp(std::move(app3));
 
+  auto app4 = test::CreateWebApp(app4_scope);
+  app4->SetScope(app4_scope);
+  app4->SetIsUninstalling(true);
+  RegisterApp(std::move(app4));
+
   absl::optional<AppId> origin_match =
       registrar().FindAppWithUrlInScope(origin_scope);
   EXPECT_FALSE(origin_match);
@@ -562,6 +574,10 @@
   app3_match = registrar().FindAppWithUrlInScope(app3_scope);
   DCHECK(app3_match);
   EXPECT_EQ(*app3_match, app3_id);
+
+  // Apps in the process of uninstalling are ignored.
+  app4_match = registrar().FindAppWithUrlInScope(app4_scope);
+  EXPECT_FALSE(app4_match);
 }
 
 TEST_F(WebAppRegistrarTest, CanFindShortcutWithUrlInScope) {
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 1c6aec9..1430255 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1654192625-b5ca57012856671f01cf837887aa49be35798779.profdata
+chrome-linux-main-1654235556-3a6bb23c1fba31850a51010fe374154ca90b11da.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index d00b932..c5835215 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1654192625-5758f252c39321335b090c4593a40a74f10cfa06.profdata
+chrome-mac-arm-main-1654235556-642096f9a7ff902b2282571bea537d3854040f24.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 682dee4..e0b5072 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1654192625-9eb361640a1a48de84c3a44066ce74e556ccb01f.profdata
+chrome-mac-main-1654214139-e5415ba116770198300b75231d57bcca3262c033.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 412b326..e7cb33a 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1654192625-f761d45cfa19f1ed36e5558b01f18cedb537a60d.profdata
+chrome-win32-main-1654224653-fbfa09cc2dfc075107051e2f2908047ee2ec09d3.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 728a895..9fde94e 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1654203511-7532bb557d03a986e71e081b2a1564c0ba1b6f73.profdata
+chrome-win64-main-1654224653-1af8104e2c257326f925bd88671e693129591564.profdata
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl
index 4767af3..84fac49 100644
--- a/chrome/common/extensions/api/file_manager_private.idl
+++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -352,6 +352,7 @@
   in_progress,
   success,
   error,
+  need_password,
   cancelled
 };
 
@@ -940,6 +941,9 @@
   // Destination folder for tasks that require one. Not required by |delete|
   // task.
   [instanceof=DirectoryEntry] object? destinationFolder;
+
+  // Password used for unpacking encrypted archives.
+  DOMString? password;
 };
 
 // IO Task Progress status, see file_manager::io_task::ProgressStatus.
diff --git a/chrome/common/extensions/api/file_manager_private_internal.idl b/chrome/common/extensions/api/file_manager_private_internal.idl
index 03a3d2e..ca236f0 100644
--- a/chrome/common/extensions/api/file_manager_private_internal.idl
+++ b/chrome/common/extensions/api/file_manager_private_internal.idl
@@ -15,6 +15,7 @@
   };
   dictionary IOTaskParams {
     DOMString? destinationFolderUrl;
+    DOMString? password;
   };
 
   callback SimpleCallback = void();
diff --git a/chrome/renderer/media/chrome_speech_recognition_client.cc b/chrome/renderer/media/chrome_speech_recognition_client.cc
index 6963e73..0440ecf8 100644
--- a/chrome/renderer/media/chrome_speech_recognition_client.cc
+++ b/chrome/renderer/media/chrome_speech_recognition_client.cc
@@ -14,6 +14,7 @@
 #include "media/base/audio_timestamp_helper.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/channel_mixer.h"
+#include "media/mojo/mojom/audio_data.mojom.h"
 #include "media/mojo/mojom/media_types.mojom.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 
diff --git a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
index f740c77a..2bc4603 100644
--- a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
@@ -382,6 +382,9 @@
           newParams.destinationFolderUrl =
               getEntryURL(params.destinationFolder);
         }
+        if (params.password) {
+          newParams.password = params.password;
+        }
         fileManagerPrivateInternal.startIOTask(type, urls, newParams, callback);
       });
 });
diff --git a/chrome/services/speech/audio_source_fetcher_impl.cc b/chrome/services/speech/audio_source_fetcher_impl.cc
index 761555e..c2b7ba7 100644
--- a/chrome/services/speech/audio_source_fetcher_impl.cc
+++ b/chrome/services/speech/audio_source_fetcher_impl.cc
@@ -17,6 +17,7 @@
 #include "media/base/channel_mixer.h"
 #include "media/base/limits.h"
 #include "media/mojo/common/media_type_converters.h"
+#include "media/mojo/mojom/audio_data.mojom.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "services/audio/public/cpp/device_factory.h"
 
diff --git a/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc b/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc
index 5b3d206..75e7376 100644
--- a/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc
+++ b/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc
@@ -13,6 +13,7 @@
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/limits.h"
 #include "media/base/media_switches.h"
+#include "media/mojo/mojom/audio_data.mojom.h"
 #include "media/mojo/mojom/media_types.mojom.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
diff --git a/chrome/services/speech/speech_recognition_recognizer_impl.cc b/chrome/services/speech/speech_recognition_recognizer_impl.cc
index db205242..93f6394a 100644
--- a/chrome/services/speech/speech_recognition_recognizer_impl.cc
+++ b/chrome/services/speech/speech_recognition_recognizer_impl.cc
@@ -25,6 +25,7 @@
 #include "media/base/limits.h"
 #include "media/base/media_switches.h"
 #include "media/mojo/common/media_type_converters.h"
+#include "media/mojo/mojom/audio_data.mojom.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
 namespace speech {
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_app_test.js b/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_app_test.js
index 7cdb874..b92a151 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_app_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_app_test.js
@@ -164,12 +164,43 @@
 
     assertFalse(initialPage.allButtonsDisabled);
     exitButton.click();
+
+    const exitDialog = component.shadowRoot.querySelector('#exitDialog');
+    assertTrue(exitDialog.open);
+
+    const confirmExitButton =
+        component.shadowRoot.querySelector('#confirmExitDialogButton');
+    assertTrue(!!confirmExitButton);
+    confirmExitButton.click();
     await flushTasks();
 
     assertEquals(1, abortRmaCount);
     assertTrue(initialPage.allButtonsDisabled);
   });
 
+  test('CancelExitDialog', async () => {
+    await initializeShimlessRMAApp(fakeStates, fakeChromeVersion[0]);
+    let abortRmaCount = 0;
+    service.abortRma = () => {
+      abortRmaCount++;
+      return Promise.resolve(RmadErrorCode.kOk);
+    };
+    const initialPage =
+        component.shadowRoot.querySelector('onboarding-landing-page');
+    const exitButton = component.shadowRoot.querySelector('#exit');
+
+    assertFalse(initialPage.allButtonsDisabled);
+    exitButton.click();
+    const exitDialog = component.shadowRoot.querySelector('#exitDialog');
+    assertTrue(exitDialog.open);
+    component.shadowRoot.querySelector('#cancelExitDialogButton').click();
+    assertFalse(exitDialog.open);
+    await flushTasks();
+
+    assertEquals(0, abortRmaCount);
+    assertFalse(initialPage.allButtonsDisabled);
+  });
+
   test('NextButtonClickedOnReady', async () => {
     await initializeShimlessRMAApp(fakeStates, fakeChromeVersion[0]);
 
@@ -360,6 +391,14 @@
     await clickExit();
     assertTrue(nextButtonSpinner.hidden);
     assertTrue(backButtonSpinner.hidden);
+    assertTrue(exitButtonSpinner.hidden);
+
+    const exitDialog = component.shadowRoot.querySelector('#exitDialog');
+    assertTrue(exitDialog.open);
+    await component.shadowRoot.querySelector('#confirmExitDialogButton')
+        .click();
+    assertTrue(nextButtonSpinner.hidden);
+    assertTrue(backButtonSpinner.hidden);
     assertFalse(exitButtonSpinner.hidden);
 
     exitResolver.resolve({state: State.kUpdateOs, error: RmadErrorCode.kOk});
@@ -422,7 +461,9 @@
         ));
 
     await flushTasks();
-    assertEquals(1, callCounter);
+    const exitDialog = component.shadowRoot.querySelector('#exitDialog');
+    assertTrue(exitDialog.open);
+    assertEquals(0, callCounter);
   });
 
   test('TransitionStateListener', async () => {
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_browsertest.js b/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_browsertest.js
index b87337a..f3bf46ae 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_browsertest.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_browsertest.js
@@ -35,7 +35,8 @@
     return {
       enabled: [
         'chromeos::features::kShimlessRMAFlow',
-        'chromeos::features::kShimlessRMAEnableStandalone'
+        'chromeos::features::kShimlessRMAEnableStandalone',
+        'chromeos::features::kShimlessRMAOsUpdate'
       ]
     };
   }
diff --git a/chrome/test/data/webui/settings/chromeos/crostini_page_test.js b/chrome/test/data/webui/settings/chromeos/crostini_page_test.js
index abd1079..7af4ea7d 100644
--- a/chrome/test/data/webui/settings/chromeos/crostini_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/crostini_page_test.js
@@ -516,8 +516,21 @@
 
       const allContainers = /** @type {!Array<!ContainerInfo>}*/
           ([
-            {id: {vm_name: 'termina', container_name: 'penguin'}},
-            {id: {vm_name: 'not-termina', container_name: 'not-penguin'}}
+            {
+              id: {
+                vm_name: 'termina',
+                container_name: 'penguin',
+              },
+              ipv4: '1.2.3.4',
+            },
+            {
+              id: {
+                vm_name: 'not-termina',
+                container_name: 'not-penguin',
+
+              },
+              ipv4: '1.2.3.5',
+            }
           ]);
       setup(async function() {
         crostiniBrowserProxy.portOperationSuccess = true;
@@ -548,6 +561,8 @@
         await flushTasks();
         subpage = crostiniPage.$$('settings-crostini-port-forwarding');
         assertTrue(!!subpage);
+        assertEquals(
+            1, crostiniBrowserProxy.getCallCount('requestContainerInfo'));
       });
 
       test('DisplayPorts', async function() {
@@ -677,11 +692,13 @@
       });
 
 
-      test('ActivateSinglePortSucess', async function() {
+      test('ActivateSinglePortSuccess', async function() {
         assertFalse(subpage.$$('#errorToast').open);
         await flushTasks();
         subpage = crostiniPage.$$('settings-crostini-port-forwarding');
-        subpage.$$('#toggleActivationButton0-0').click();
+        const crToggle = subpage.$$('#toggleActivationButton0-0');
+        assertFalse(crToggle.disabled);
+        crToggle.click();
 
         await flushTasks();
         assertEquals(
@@ -697,6 +714,7 @@
         subpage = crostiniPage.$$('settings-crostini-port-forwarding');
         const crToggle = subpage.$$('#toggleActivationButton1-0');
         assertTrue(!!crToggle);
+        assertFalse(crToggle.disabled);
         assertEquals(crToggle.checked, false);
         crToggle.click();
 
@@ -712,6 +730,7 @@
         await flushTasks();
         subpage = crostiniPage.$$('settings-crostini-port-forwarding');
         const crToggle = subpage.$$('#toggleActivationButton0-0');
+        assertFalse(crToggle.disabled);
         crToggle.checked = true;
         crToggle.click();
 
@@ -795,14 +814,20 @@
             0, subpage.shadowRoot.querySelectorAll('.list-item').length);
       });
 
-      test('CrostiniStopAndStart', async function() {
+      test('ContainerStopAndStart', async function() {
         const crToggle = subpage.$$('#toggleActivationButton0-0');
         assertFalse(crToggle.disabled);
 
-        webUIListenerCallback('crostini-status-changed', false);
+        delete allContainers[0].ipv4;
+        webUIListenerCallback(
+            'crostini-container-info', structuredClone(allContainers));
+        await flushTasks();
         assertTrue(crToggle.disabled);
 
-        webUIListenerCallback('crostini-status-changed', true);
+        allContainers[0].ipv4 = '1.2.3.4';
+        webUIListenerCallback(
+            'crostini-container-info', structuredClone(allContainers));
+        await flushTasks();
         assertFalse(crToggle.disabled);
       });
     });
diff --git a/chrome/test/data/webui/settings/personalization_options_test.ts b/chrome/test/data/webui/settings/personalization_options_test.ts
index 3672f52..71cab30 100644
--- a/chrome/test/data/webui/settings/personalization_options_test.ts
+++ b/chrome/test/data/webui/settings/personalization_options_test.ts
@@ -29,6 +29,7 @@
   suiteSetup(function() {
     loadTimeData.overrideValues({
       driveSuggestAvailable: true,
+      enableAutofillAssistant: true,
       signinAvailable: true,
     });
   });
@@ -37,6 +38,7 @@
     document.body.innerHTML = '';
     testElement = document.createElement('settings-personalization-options');
     testElement.prefs = {
+      autofill_assistant: {enabled: {value: false}},
       signin: {
         allowed_on_next_startup:
             {type: chrome.settingsPrivate.PrefType.BOOLEAN, value: true},
@@ -225,6 +227,18 @@
         testElement.shadowRoot!.querySelector('#searchSuggestToggle')));
   });
   // </if>
+
+  test('autofillAssistantAvailable', function() {
+    assertTrue(
+        !!testElement.shadowRoot!.querySelector('#enableAssistantFlows'));
+  });
+
+  test('autofillAssistantUnavailable', function() {
+    loadTimeData.overrideValues({'enableAutofillAssistant': false});
+    buildTestElement();  // Rebuild the element after modifying loadTimeData.
+    assertFalse(
+        !!testElement.shadowRoot!.querySelector('#enableAssistantFlows'));
+  });
 });
 
 suite('PersonalizationOptionsTests_OfficialBuild', function() {
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index 8d11601..bdafa3a 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -110,12 +110,6 @@
     "//ui/base:ui_base_unittests",
   ]
 
-  if (enable_chromecast_extensions && media_use_ffmpeg) {
-    tests += [
-      "//chromecast/browser/accessibility/flutter:cast_accessibility_unittests",
-    ]
-  }
-
   if (!is_cast_audio_only) {
     tests += [ "//gpu:gpu_unittests" ]
 
diff --git a/chromecast/browser/accessibility/flutter/BUILD.gn b/chromecast/browser/accessibility/flutter/BUILD.gn
deleted file mode 100644
index 85b8e79..0000000
--- a/chromecast/browser/accessibility/flutter/BUILD.gn
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//chromecast/build/tests/cast_test.gni")
-import("//chromecast/chromecast.gni")
-
-cast_source_set("accessibility") {
-  sources = [
-    "ax_tree_source_flutter.cc",
-    "ax_tree_source_flutter.h",
-    "flutter_accessibility_helper_bridge.cc",
-    "flutter_accessibility_helper_bridge.h",
-    "flutter_semantics_node.h",
-    "flutter_semantics_node_wrapper.cc",
-    "flutter_semantics_node_wrapper.h",
-  ]
-  public_deps = [ "//ui/accessibility" ]
-  deps = [
-    "//base",
-    "//chromecast/base",
-    "//chromecast/browser",
-    "//chromecast/browser/accessibility/proto:gallium_accessibility_proto",
-    "//chromecast/common",
-    "//components/exo",
-    "//content/public/browser",
-    "//extensions/browser/api/automation_internal",
-    "//skia",
-    "//third_party/grpc:grpc++",
-    "//ui/views",
-  ]
-}
-
-test("cast_accessibility_unittests") {
-  sources = [
-    "ax_tree_source_flutter_unittest.cc",
-    "flutter_semantics_node_wrapper_unittest.cc",
-  ]
-
-  deps = [
-    ":accessibility",
-    "//base",
-    "//base/test:run_all_unittests",
-    "//chromecast:cast_shell_lib",
-    "//chromecast/browser",
-    "//content/test:test_support",
-    "//extensions/browser/api/automation_internal",
-    "//skia",
-    "//testing/gmock",
-    "//testing/gtest",
-    "//third_party/protobuf:protobuf_lite",
-    "//ui/views",
-  ]
-}
diff --git a/chromecast/browser/accessibility/flutter/DEPS b/chromecast/browser/accessibility/flutter/DEPS
deleted file mode 100644
index a1bbce47..0000000
--- a/chromecast/browser/accessibility/flutter/DEPS
+++ /dev/null
@@ -1,13 +0,0 @@
-include_rules = [
-  "+chromecast/browser",
-  "+chromecast/common/extensions_api",
-  "+components/exo",
-  "+content/browser",
-  "+content/public/browser",
-  "+extensions/browser",
-  '+third_party/grpc',
-  "+ui/accessibility",
-  "+ui/aura",
-  "+ui/gfx",
-  "+ui/views",
-]
diff --git a/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.cc b/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.cc
deleted file mode 100644
index 7b4b274b..0000000
--- a/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.cc
+++ /dev/null
@@ -1,753 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h"
-
-#include <stack>
-
-#include "base/check_op.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "chromecast/browser/accessibility/accessibility_manager.h"
-#include "chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h"
-#include "chromecast/browser/cast_browser_process.h"
-#include "chromecast/browser/cast_web_contents_observer.h"
-#include "chromecast/browser/ui/aura/accessibility/automation_manager_aura.h"
-#include "content/public/browser/tts_controller.h"
-#include "content/public/browser/tts_utterance.h"
-#include "extensions/browser/api/automation_internal/automation_event_router.h"
-#include "extensions/browser/api/automation_internal/automation_event_router_interface.h"
-#include "ui/accessibility/aura/aura_window_properties.h"
-#include "ui/aura/window.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_delegate.h"
-
-namespace {
-ax::mojom::Event ToAXEvent(
-    gallium::castos::OnAccessibilityEventRequest_EventType flutter_event_type) {
-  switch (flutter_event_type) {
-    case gallium::castos::OnAccessibilityEventRequest_EventType_FOCUSED:
-      return ax::mojom::Event::kFocus;
-    case gallium::castos::OnAccessibilityEventRequest_EventType_CLICKED:
-    case gallium::castos::OnAccessibilityEventRequest_EventType_LONG_CLICKED:
-      return ax::mojom::Event::kClicked;
-    case gallium::castos::OnAccessibilityEventRequest_EventType_TEXT_CHANGED:
-      return ax::mojom::Event::kTextChanged;
-    case gallium::castos::
-        OnAccessibilityEventRequest_EventType_TEXT_SELECTION_CHANGED:
-      return ax::mojom::Event::kTextSelectionChanged;
-    case gallium::castos::OnAccessibilityEventRequest_EventType_HOVER_ENTER:
-      return ax::mojom::Event::kHover;
-    case gallium::castos::OnAccessibilityEventRequest_EventType_SCROLLED:
-      return ax::mojom::Event::kScrollPositionChanged;
-    case gallium::castos::OnAccessibilityEventRequest_EventType_CONTENT_CHANGED:
-      return ax::mojom::Event::kChildrenChanged;
-    case gallium::castos::
-        OnAccessibilityEventRequest_EventType_WINDOW_STATE_CHANGED:
-      return ax::mojom::Event::kLayoutComplete;
-    default:
-      return ax::mojom::Event::kNone;
-  }
-}
-}  // namespace
-
-namespace chromecast {
-namespace accessibility {
-
-AXTreeSourceFlutter::AXTreeWebContentsObserver::AXTreeWebContentsObserver(
-    content::WebContents* web_contents,
-    AXTreeSourceFlutter* ax_tree_source)
-    : WebContentsObserver(web_contents), ax_tree_source_(ax_tree_source) {}
-
-void AXTreeSourceFlutter::AXTreeWebContentsObserver::RenderFrameHostChanged(
-    content::RenderFrameHost* old_host,
-    content::RenderFrameHost* new_host) {
-  ax_tree_source_->UpdateTree();
-}
-
-void AXTreeSourceFlutter::AXTreeWebContentsObserver::
-    AXTreeIDForMainFrameHasChanged() {
-  ax_tree_source_->UpdateTree();
-}
-
-constexpr int kInvalidId = -1;
-
-AXTreeSourceFlutter::AXTreeSourceFlutter(
-    Delegate* delegate,
-    content::BrowserContext* browser_context,
-    extensions::AutomationEventRouterInterface* event_router)
-    : current_tree_serializer_(std::make_unique<AXTreeFlutterSerializer>(this)),
-      root_id_(kInvalidId),
-      window_id_(kInvalidId),
-      focused_id_(kInvalidId),
-      delegate_(delegate),
-      browser_context_(browser_context),
-      event_router_(event_router
-                        ? event_router
-                        : extensions::AutomationEventRouter::GetInstance()),
-      cast_web_contents_(nullptr),
-      accessibility_enabled_(false) {
-  DCHECK(delegate_);
-}
-
-AXTreeSourceFlutter::~AXTreeSourceFlutter() {
-  Reset();
-}
-
-void AXTreeSourceFlutter::NotifyAccessibilityEvent(
-    const gallium::castos::OnAccessibilityEventRequest* event_data) {
-  DCHECK(event_data);
-
-  if (event_data->node_data_size() > 0) {
-    // Remember most recent tree in case we need to update parents
-    // of child trees with new ax tree ids (i.e. due to embedded webview
-    // navigation)
-    last_event_data_ = *event_data;
-  }
-
-  // First find out if we know what to do with this event type from flutter.
-  if (event_data->event_type() ==
-      gallium::castos::OnAccessibilityEventRequest_EventType_ANNOUNCEMENT) {
-    if (!event_data->has_text())
-      return;
-
-    SubmitTTS(event_data->text());
-    return;
-  }
-
-  ax::mojom::Event translated_event = ToAXEvent(event_data->event_type());
-  if (translated_event == ax::mojom::Event::kNone) {
-    LOG(INFO) << "Ignoring unknown flutter ax event "
-              << event_data->event_type() << ". No mapping available.";
-    return;
-  }
-
-  // b/150992421 - We sometimes get nodes that have been reparented.
-  // Any node that is reparented must first be deleted from its old
-  // parent before appearing under a new one. The tree serializer
-  // should be handling this case for us but isn't so the tree
-  // update fails. As a workaround until this is fixed upstream, we
-  // will identify these nodes ourselves and provide a separate update
-  // that will delete them prior to the full update.
-  reparented_children_.clear();
-  std::vector<int32_t> parents_with_deleted_children;
-  for (int i = 0; i < event_data->node_data_size(); ++i) {
-    const SemanticsNode& node = event_data->node_data(i);
-    for (int j = 0; j < node.child_node_ids_size(); ++j) {
-      int child_id = node.child_node_ids(j);
-      auto it = parent_map_.find(child_id);
-      if (it != parent_map_.end()) {
-        if (node.node_id() != it->second) {
-          // Remember this child and who its parent was.
-          reparented_children_.push_back(child_id);
-          parents_with_deleted_children.push_back(it->second);
-        }
-      }
-    }
-  }
-
-  tree_map_.clear();
-  cached_computed_bounds_.clear();
-  if (event_data->node_data_size() > 0) {
-    // Unless there are new nodes, don't clear previous parent map so we
-    // can detect reparenting above.
-    parent_map_.clear();
-  }
-
-  window_id_ = event_data->window_id();
-
-  // The following loops perform caching to prepare for AXTreeSerializer.
-  // First, we need to cache parent links, which are implied by a node's child
-  // ids. Next, we cache the nodes by id. During this process, we can detect
-  // the root node based upon the parent links we cached above. Finally, we
-  // cache each node's computed bounds, based on its descendants.
-  std::map<int32_t, int32_t> all_parent_map;
-  std::map<int32_t, std::vector<int32_t>> all_children_map;
-  for (int i = 0; i < event_data->node_data_size(); ++i) {
-    const SemanticsNode& node = event_data->node_data(i);
-    for (int j = 0; j < node.child_node_ids_size(); ++j) {
-      all_children_map[node.node_id()].push_back(node.child_node_ids(j));
-      all_parent_map[node.child_node_ids(j)] = node.node_id();
-    }
-  }
-
-  // Now copy just the relevant subtree containing the source_id into the
-  // |parent_map_|.
-  root_id_ = event_data->source_id();
-  // Walk up to the root from the source_id.
-  for (auto it = all_parent_map.find(root_id_); it != all_parent_map.end();
-       it = all_parent_map.find(root_id_)) {
-    root_id_ = it->second;
-  }
-
-  // Walk back down through children map to populate parent_map_.
-  std::stack<int32_t> stack;
-  stack.push(root_id_);
-  while (!stack.empty()) {
-    int32_t parent = stack.top();
-    stack.pop();
-    for (int32_t child_id : all_children_map[parent]) {
-      parent_map_[child_id] = parent;
-      stack.push(child_id);
-    }
-  }
-
-  std::vector<std::string> new_child_trees;
-  for (int i = 0; i < event_data->node_data_size(); ++i) {
-    int32_t id = event_data->node_data(i).node_id();
-    // Only map nodes in the parent_map and the root.
-    // This avoids adding other subtrees that are not interesting.
-    if (parent_map_.find(id) == parent_map_.end() && id != root_id_)
-      continue;
-    const SemanticsNode& node = event_data->node_data(i);
-    tree_map_[id] = std::make_unique<FlutterSemanticsNodeWrapper>(this, &node);
-    if (tree_map_[id]->IsFocused()) {
-      focused_id_ = id;
-    }
-    // Place focus on the node that holds a child tree. When the
-    // child tree is removed, focus will be placed back on the root.
-    if (node.has_plugin_id()) {
-      std::string ax_tree_id = node.plugin_id();
-      new_child_trees.push_back(ax_tree_id);
-
-      if (std::find(child_trees_.begin(), child_trees_.end(), ax_tree_id) ==
-          child_trees_.end()) {
-        if (ax_tree_id.rfind("T:", 0) == 0) {
-          int web_contents_id;
-          base::StringToInt(ax_tree_id.substr(2), &web_contents_id);
-          std::vector<CastWebContents*> all_contents =
-              CastWebContents::GetAll();
-          for (CastWebContents* contents : all_contents) {
-            if (contents->id() == web_contents_id &&
-                child_tree_observers_.find(web_contents_id) ==
-                    child_tree_observers_.end()) {
-              child_tree_observers_[contents->id()] = std::make_unique<
-                  AXTreeSourceFlutter::AXTreeWebContentsObserver>(
-                  contents->web_contents(), this);
-              CastWebContentsObserver::Observe(contents);
-              cast_web_contents_ = contents;
-              break;
-            }
-          }
-        }
-      }
-
-      focused_id_ = node.node_id();
-    }
-  }
-
-  // Do we need to put focus somewhere after a child tree
-  // has been removed?
-  bool need_focus_clear = false;
-  for (std::string id : child_trees_) {
-    // Is this old child tree still known?
-    if (std::find(new_child_trees.begin(), new_child_trees.end(), id) ==
-        new_child_trees.end()) {
-      // No, clear focus.
-      need_focus_clear = true;
-      focused_id_ = root_id_;
-      break;
-    }
-  }
-  child_trees_ = new_child_trees;
-
-  // Assuming |nodeData| is in pre-order, compute cached bounds in post-order to
-  // avoid an O(n^2) amount of work as the computed bounds uses descendant
-  // bounds.
-  for (int i = 0; i < event_data->node_data_size(); ++i) {
-    int32_t id = event_data->node_data(i).node_id();
-    if (parent_map_.find(id) == parent_map_.end() && id != root_id_)
-      continue;
-    cached_computed_bounds_[id] = ComputeEnclosingBounds(tree_map_[id].get());
-  }
-
-  // If focus was not set from above, set it now on the root node.
-  if (focused_id_ < 0 && root_id_ >= 0) {
-    focused_id_ = root_id_;
-  }
-
-  std::vector<ui::AXEvent> events;
-  ui::AXEvent event;
-  event.event_type = translated_event;
-  event.id = event_data->source_id();
-  events.push_back(std::move(event));
-
-  if (event_data->event_type() ==
-      gallium::castos::OnAccessibilityEventRequest_EventType_CONTENT_CHANGED) {
-    current_tree_serializer_->InvalidateSubtree(
-        GetFromId(event_data->source_id()));
-  }
-
-  std::vector<ui::AXTreeUpdate> updates;
-  if (event_data->event_type() !=
-          gallium::castos::OnAccessibilityEventRequest_EventType_HOVER_ENTER &&
-      event_data->event_type() !=
-          gallium::castos::OnAccessibilityEventRequest_EventType_HOVER_EXIT) {
-    // For every parent whose child has been moved, serialize an update.
-    // This update will filter all the children that have moved.
-    for (int32_t nid : parents_with_deleted_children) {
-      ui::AXTreeUpdate update;
-      current_tree_serializer_->SerializeChanges(GetFromId(nid), &update);
-      updates.push_back(std::move(update));
-    }
-
-    // If there were any children that were reparented, invalidate the entire
-    // tree so the new parents get the children.
-    if (reparented_children_.size() > 0) {
-      current_tree_serializer_->InvalidateSubtree(GetFromId(root_id_));
-    }
-
-    // Clear reparented children.
-    reparented_children_.clear();
-
-    // Handle routes added/removed from the tree.
-    HandleRoutes(&events);
-
-    ui::AXTreeUpdate update;
-    current_tree_serializer_->SerializeChanges(
-        GetFromId(event_data->source_id()), &update);
-    updates.push_back(std::move(update));
-
-    HandleLiveRegions(&events);
-
-    // b/162311902: For nodes that have scroll extents, rapidly changing the
-    // value will result in queueing up the values and speak out one by one.
-    // Here we handle the tts natively.
-    HandleNativeTTS();
-
-    HandleVirtualKeyboardNodes();
-  }
-
-  // Need to refocus
-  if (need_focus_clear) {
-    ui::AXEvent focus_event;
-    focus_event.event_type = ax::mojom::Event::kFocus;
-    focus_event.id = focused_id_;
-    focus_event.event_from = ax::mojom::EventFrom::kNone;
-    focus_event.event_from_action = ax::mojom::Action::kNone;
-    events.push_back(std::move(focus_event));
-  }
-
-  if (event_router_) {
-    event_router_->DispatchAccessibilityEvents(ax_tree_id(), std::move(updates),
-                                               gfx::Point(), std::move(events));
-  }
-}
-
-void AXTreeSourceFlutter::NotifyActionResult(const ui::AXActionData& data,
-                                             bool result) {
-  if (!event_router_)
-    return;
-
-  event_router_->DispatchActionResult(data, result, browser_context_);
-}
-
-bool AXTreeSourceFlutter::GetTreeData(ui::AXTreeData* data) const {
-  DCHECK(data);
-  data->tree_id = ax_tree_id();
-  if (focused_id_ >= 0) {
-    data->focus_id = focused_id_;
-  } else if (root_id_ >= 0) {
-    data->focus_id = root_id_;
-  }
-  return true;
-}
-
-FlutterSemanticsNode* AXTreeSourceFlutter::GetRoot() const {
-  return GetFromId(root_id_);
-}
-
-FlutterSemanticsNode* AXTreeSourceFlutter::GetFromId(int32_t id) const {
-  auto it = tree_map_.find(id);
-  if (it == tree_map_.end())
-    return nullptr;
-  return it->second.get();
-}
-
-int32_t AXTreeSourceFlutter::GetId(FlutterSemanticsNode* info_data) const {
-  if (!info_data)
-    return kInvalidId;
-  return info_data->GetId();
-}
-
-void AXTreeSourceFlutter::GetChildren(
-    FlutterSemanticsNode* info_data,
-    std::vector<FlutterSemanticsNode*>* out_children) const {
-  if (!info_data)
-    return;
-
-  info_data->GetChildren(out_children);
-  if (out_children->empty())
-    return;
-
-  // Filter out any reparented children so the update doesn't see them.
-  auto it = out_children->begin();
-  while (it != out_children->end()) {
-    if (std::find(reparented_children_.begin(), reparented_children_.end(),
-                  (*it)->GetId()) != reparented_children_.end()) {
-      it = out_children->erase(it);
-    } else {
-      ++it;
-    }
-  }
-}
-
-FlutterSemanticsNode* AXTreeSourceFlutter::GetParent(
-    FlutterSemanticsNode* info_data) const {
-  if (!info_data)
-    return nullptr;
-  auto it = parent_map_.find(info_data->GetId());
-  if (it != parent_map_.end())
-    return GetFromId(it->second);
-  return nullptr;
-}
-
-bool AXTreeSourceFlutter::IsValid(FlutterSemanticsNode* info_data) const {
-  return info_data;
-}
-
-bool AXTreeSourceFlutter::IsIgnored(FlutterSemanticsNode* info_data) const {
-  return false;
-}
-
-bool AXTreeSourceFlutter::IsEqual(FlutterSemanticsNode* info_data1,
-                                  FlutterSemanticsNode* info_data2) const {
-  if (!info_data1 || !info_data2)
-    return false;
-  return info_data1->GetId() == info_data2->GetId();
-}
-
-FlutterSemanticsNode* AXTreeSourceFlutter::GetNull() const {
-  return nullptr;
-}
-
-void AXTreeSourceFlutter::SerializeNode(FlutterSemanticsNode* info_data,
-                                        ui::AXNodeData* out_data) const {
-  if (!info_data)
-    return;
-
-  int32_t id = info_data->GetId();
-  out_data->id = id;
-  if (id == root_id_) {
-    out_data->role = ax::mojom::Role::kRootWebArea;
-  } else {
-    info_data->PopulateAXRole(out_data);
-  }
-
-  info_data->Serialize(out_data);
-}
-
-gfx::Rect AXTreeSourceFlutter::ComputeEnclosingBounds(
-    FlutterSemanticsNode* info_data) const {
-  gfx::Rect computed_bounds;
-  // Exit early if the node or window is invisible.
-  if (!info_data->IsVisibleToUser())
-    return computed_bounds;
-
-  ComputeEnclosingBoundsInternal(info_data, &computed_bounds);
-  return computed_bounds;
-}
-
-void AXTreeSourceFlutter::ComputeEnclosingBoundsInternal(
-    FlutterSemanticsNode* info_data,
-    gfx::Rect* computed_bounds) const {
-  auto cached_bounds = cached_computed_bounds_.find(info_data->GetId());
-  if (cached_bounds != cached_computed_bounds_.end()) {
-    computed_bounds->Union(cached_bounds->second);
-    return;
-  }
-
-  if (!info_data->IsVisibleToUser())
-    return;
-
-  if (info_data->CanBeAccessibilityFocused()) {
-    // Only consider nodes that can possibly be accessibility focused.
-    computed_bounds->Union(info_data->GetBounds());
-    return;
-  }
-
-  std::vector<FlutterSemanticsNode*> children;
-  info_data->GetChildren(&children);
-  if (children.empty())
-    return;
-
-  for (FlutterSemanticsNode* child : children)
-    ComputeEnclosingBoundsInternal(child, computed_bounds);
-}
-
-void AXTreeSourceFlutter::PerformAction(const ui::AXActionData& data) {
-  delegate_->OnAction(data);
-}
-
-void AXTreeSourceFlutter::Reset() {
-  tree_map_.clear();
-  parent_map_.clear();
-  cached_computed_bounds_.clear();
-  current_tree_serializer_ = std::make_unique<AXTreeFlutterSerializer>(this);
-  root_id_ = kInvalidId;
-  focused_id_ = kInvalidId;
-  if (!event_router_)
-    return;
-  event_router_->DispatchTreeDestroyedEvent(ax_tree_id(), browser_context_);
-}
-
-void AXTreeSourceFlutter::HandleVirtualKeyboardNodes() {
-  gfx::Rect bounds;
-  for (const auto& it : tree_map_) {
-    FlutterSemanticsNode* node_info = it.second.get();
-    if (!node_info->IsKeyboardNode())
-      continue;
-    bounds.Union(node_info->GetBounds());
-  }
-
-  if (bounds != keyboard_bounds_) {
-    keyboard_bounds_ = bounds;
-    delegate_->OnVirtualKeyboardBoundsChange(keyboard_bounds_);
-  }
-}
-
-void AXTreeSourceFlutter::HandleNativeTTS() {
-  std::map<int32_t, std::string> new_native_tts_name_cache;
-
-  // Cache current native tts name cache.
-  for (const auto& it : tree_map_) {
-    FlutterSemanticsNode* node_info = it.second.get();
-    if (!node_info->IsRapidChangingSlider())
-      continue;
-
-    std::vector<std::string> names;
-    if (node_info->HasLabelHint()) {
-      names.push_back(node_info->GetLabelHint());
-    }
-    if (node_info->HasValue()) {
-      names.push_back(node_info->GetValue());
-    }
-
-    new_native_tts_name_cache[node_info->GetId()] =
-        base::JoinString(names, " ");
-  }
-
-  // Compare to the previous one, and send out TTS if needed.
-  for (const auto& it : new_native_tts_name_cache) {
-    auto prev_it = native_tts_name_cache_.find(it.first);
-    if (prev_it != native_tts_name_cache_.end() &&
-        prev_it->second != it.second) {
-      // Send to TTS controller.
-      SubmitTTS(it.second);
-    }
-  }
-
-  std::swap(native_tts_name_cache_, new_native_tts_name_cache);
-}
-
-void AXTreeSourceFlutter::HandleLiveRegions(std::vector<ui::AXEvent>* events) {
-  std::map<int32_t, std::string> new_live_region_map;
-
-  // Cache current live region's name.
-  for (const auto& it : tree_map_) {
-    FlutterSemanticsNode* node_info = it.second.get();
-    if (!node_info->IsLiveRegion())
-      continue;
-
-    std::stack<FlutterSemanticsNode*> stack;
-    stack.push(node_info);
-    while (!stack.empty()) {
-      FlutterSemanticsNode* node = stack.top();
-      stack.pop();
-      DCHECK(node);
-
-      ui::AXNodeData data;
-      SerializeNode(node, &data);
-      std::string name;
-      data.GetStringAttribute(ax::mojom::StringAttribute::kName, &name);
-      new_live_region_map[node->GetId()] = name;
-
-      std::vector<FlutterSemanticsNode*> children;
-      node->GetChildren(&children);
-      for (FlutterSemanticsNode* child : children)
-        stack.push(child);
-    }
-  }
-
-  // Compare to the previous one, and add an event if needed.
-  for (const auto& it : new_live_region_map) {
-    auto prev_it = live_region_name_cache_.find(it.first);
-    if (prev_it == live_region_name_cache_.end())
-      continue;
-
-    if (prev_it->second != it.second) {
-      events->emplace_back();
-      ui::AXEvent& event = events->back();
-      event.event_type = ax::mojom::Event::kLiveRegionChanged;
-      event.id = it.first;
-    }
-  }
-
-  std::swap(live_region_name_cache_, new_live_region_map);
-}
-
-// Handle created/deleted nodes with scopes routes flag set.
-void AXTreeSourceFlutter::HandleRoutes(std::vector<ui::AXEvent>* events) {
-  bool focused_new = false;
-  for (const auto& it : tree_map_) {
-    FlutterSemanticsNode* node = it.second.get();
-    if (!node->HasScopesRoute())
-      continue;
-
-    // Do we know about this node already? If so, skip.
-    if (std::find(scopes_route_cache_.begin(), scopes_route_cache_.end(),
-                  node->GetId()) != scopes_route_cache_.end()) {
-      continue;
-    }
-
-    // Find a node in the sub-tree with names route flag set.
-    FlutterSemanticsNode* sub_node = FindRoutesNode(node);
-    if (sub_node) {
-      // Only register the scopes route node in our cache
-      // if a names route is found.
-      scopes_route_cache_.push_back(node->GetId());
-
-      ui::AXNodeData data;
-      SerializeNode(sub_node, &data);
-      std::string name;
-      data.GetStringAttribute(ax::mojom::StringAttribute::kName, &name);
-      if (name.length() > 0) {
-        focused_new = true;
-
-        // Focus the node.
-        focused_id_ = sub_node->GetId();
-        events->emplace_back();
-        ui::AXEvent& focus_event = events->back();
-        focus_event.event_type = ax::mojom::Event::kFocus;
-        focus_event.id = focused_id_;
-        focus_event.event_from = ax::mojom::EventFrom::kNone;
-        focus_event.event_from_action = ax::mojom::Action::kNone;
-      }
-    }
-  }
-
-  // Clean up the cache for those nodes that should not be in the cache anymore.
-  bool need_refocus = false;
-  for (std::vector<int32_t>::iterator it = scopes_route_cache_.begin();
-       it != scopes_route_cache_.end();) {
-    int32_t id = *it;
-    FlutterSemanticsNode* scopes_route_node = GetFromId(id);
-    if (scopes_route_node == nullptr || !scopes_route_node->HasScopesRoute() ||
-        FindRoutesNode(scopes_route_node) == nullptr) {
-      // This was removed in the latest tree update or there are no more
-      // RoutesNode child.
-      it = scopes_route_cache_.erase(it++);
-      need_refocus = true;
-    } else {
-      it++;
-    }
-  }
-
-  // After a deletion, use the last scopes route node to refocus on a child
-  // with names route set (unless we already focused on a new node from above).
-  if (need_refocus && !focused_new) {
-    // Select the last in-depth node with scopesRoute for refocus
-    FlutterSemanticsNode* refocused_routes_node = nullptr;
-    if (scopes_route_cache_.size() > 0)
-      refocused_routes_node =
-          FindRoutesNode(GetFromId(scopes_route_cache_.back()));
-    if (refocused_routes_node) {
-      focused_id_ = refocused_routes_node->GetId();
-    } else {
-      focused_id_ = FindFirstFocusableNodeId();
-    }
-    events->emplace_back();
-    ui::AXEvent& focus_event = events->back();
-    focus_event.event_type = ax::mojom::Event::kFocus;
-    focus_event.id = focused_id_;
-    focus_event.event_from = ax::mojom::EventFrom::kNone;
-    focus_event.event_from_action = ax::mojom::Action::kNone;
-  }
-}
-
-// Perform depth first search for a subtree node under 'parent'
-// with names route flag set.
-FlutterSemanticsNode* AXTreeSourceFlutter::FindRoutesNode(
-    FlutterSemanticsNode* parent) {
-  if (parent == nullptr)
-    return nullptr;
-
-  std::stack<FlutterSemanticsNode*> stack;
-  stack.push(parent);
-  while (!stack.empty()) {
-    FlutterSemanticsNode* node = stack.top();
-    stack.pop();
-    DCHECK(node);
-
-    if (node->HasNamesRoute()) {
-      return node;
-    }
-
-    std::vector<FlutterSemanticsNode*> children;
-    node->GetChildren(&children);
-    for (FlutterSemanticsNode* child : children)
-      stack.push(child);
-  }
-  return nullptr;
-}
-
-// Find the first focusable node.
-int32_t AXTreeSourceFlutter::FindFirstFocusableNodeId() {
-  std::stack<FlutterSemanticsNode*> stack;
-  stack.push(GetFromId(root_id_));
-  while (!stack.empty()) {
-    FlutterSemanticsNode* node = stack.top();
-    stack.pop();
-    DCHECK(node);
-
-    if (node->CanBeAccessibilityFocused()) {
-      return node->GetId();
-    }
-
-    std::vector<FlutterSemanticsNode*> children;
-    node->GetChildren(&children);
-    for (FlutterSemanticsNode* child : children)
-      stack.push(child);
-  }
-
-  // Fallback to root if none found.
-  return root_id_;
-}
-
-void AXTreeSourceFlutter::SubmitTTS(const std::string& text) {
-  if (!accessibility_enabled_)
-    return;
-
-  std::unique_ptr<content::TtsUtterance> utterance =
-      content::TtsUtterance::Create(browser_context_);
-
-  utterance->SetText(text);
-
-  auto* tts_controller = content::TtsController::GetInstance();
-  tts_controller->Stop();
-  tts_controller->SpeakOrEnqueue(std::move(utterance));
-}
-
-void AXTreeSourceFlutter::UpdateTree() {
-  // Update the tree with last known flutter nodes.
-  // TODO: A more efficient update would be to isolate just the parent node
-  // whose child has changed. Consider giving the node to the observer
-  // class on creation and passing through here.
-  NotifyAccessibilityEvent(&last_event_data_);
-}
-
-void AXTreeSourceFlutter::PageStopped(PageState page_state, int error_code) {
-  // Webview is gone. Stop observing.
-  CastWebContentsObserver::Observe(nullptr);
-  child_tree_observers_.erase(cast_web_contents_->id());
-  cast_web_contents_ = nullptr;
-}
-
-void AXTreeSourceFlutter::SetAccessibilityEnabled(bool value) {
-  accessibility_enabled_ = value;
-}
-
-}  // namespace accessibility
-}  // namespace chromecast
diff --git a/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h b/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h
deleted file mode 100644
index 6c07d34..0000000
--- a/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_AX_TREE_SOURCE_FLUTTER_H_
-#define CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_AX_TREE_SOURCE_FLUTTER_H_
-
-#include <stdint.h>
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/containers/flat_map.h"
-#include "chromecast/browser/accessibility/proto/cast_server_accessibility.pb.h"
-#include "chromecast/browser/cast_web_contents.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "ui/accessibility/ax_action_handler.h"
-#include "ui/accessibility/ax_node.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/accessibility/ax_tree_data.h"
-#include "ui/accessibility/ax_tree_serializer.h"
-#include "ui/accessibility/ax_tree_source.h"
-
-namespace aura {
-class Window;
-}  // namespace aura
-
-namespace content {
-class BrowserContext;
-}  // namespace content
-
-namespace extensions {
-class AutomationEventRouterInterface;
-}  // namespace extensions
-
-namespace ui {
-struct AXEvent;
-}  // namespace ui
-
-namespace chromecast {
-namespace accessibility {
-
-class FlutterSemanticsNode;
-
-// This class translates accessibility trees found in the gallium accessibility
-// OnAccessibilityEventRequest proto into a tree update Chrome's accessibility
-// API can work with.
-class AXTreeSourceFlutter : public ui::AXTreeSource<FlutterSemanticsNode*>,
-                            public CastWebContentsObserver,
-                            public ui::AXActionHandler {
- public:
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-    virtual void OnAction(const ui::AXActionData& data) = 0;
-    virtual void OnVirtualKeyboardBoundsChange(const gfx::Rect& bounds) = 0;
-  };
-
-  AXTreeSourceFlutter(
-      Delegate* delegate,
-      content::BrowserContext* browser_context,
-      extensions::AutomationEventRouterInterface* event_router = nullptr);
-  AXTreeSourceFlutter(const AXTreeSourceFlutter&) = delete;
-  ~AXTreeSourceFlutter() override;
-  AXTreeSourceFlutter& operator=(const AXTreeSourceFlutter&) = delete;
-
-  // AXTreeSource implementation.
-  bool GetTreeData(ui::AXTreeData* data) const override;
-
-  // AXTreeSource implementation used by FlutterAccessibilityInfoData
-  // subclasses.
-  FlutterSemanticsNode* GetRoot() const override;
-  FlutterSemanticsNode* GetFromId(int32_t id) const override;
-  void SerializeNode(FlutterSemanticsNode* node,
-                     ui::AXNodeData* out_data) const override;
-  FlutterSemanticsNode* GetParent(FlutterSemanticsNode* node) const override;
-
-  // Notifies automation of an accessibility event.
-  void NotifyAccessibilityEvent(
-      const ::gallium::castos::OnAccessibilityEventRequest* event_data);
-
-  // Notifies automation of a result to an action.
-  void NotifyActionResult(const ui::AXActionData& data, bool result);
-
-  // Attaches tree to an aura window and gives it system focus.
-  void Focus(aura::Window* window);
-
-  // Gets the window id of this tree.
-  int32_t window_id() const { return window_id_; }
-
-  void UpdateTree();
-
-  // CastWebContentsObserver
-  void PageStopped(PageState page_state, int error_code) override;
-
-  void SetAccessibilityEnabled(bool value);
-
- private:
-  class AXTreeWebContentsObserver : public content::WebContentsObserver {
-   public:
-    AXTreeWebContentsObserver(
-        content::WebContents* web_contents,
-        chromecast::accessibility::AXTreeSourceFlutter* ax_tree_source);
-
-    AXTreeWebContentsObserver(const AXTreeWebContentsObserver&) = delete;
-    AXTreeWebContentsObserver& operator=(const AXTreeWebContentsObserver&) =
-        delete;
-
-    void RenderFrameHostChanged(content::RenderFrameHost* old_host,
-                                content::RenderFrameHost* new_host) override;
-
-    void AXTreeIDForMainFrameHasChanged() override;
-
-   private:
-    chromecast::accessibility::AXTreeSourceFlutter* ax_tree_source_;
-  };
-
-  using AXTreeFlutterSerializer = ui::AXTreeSerializer<FlutterSemanticsNode*>;
-
-  friend class AXTreeSourceFlutterTest;
-
-  // AXTreeSource overrides.
-  int32_t GetId(FlutterSemanticsNode* node) const override;
-  void GetChildren(
-      FlutterSemanticsNode* node,
-      std::vector<FlutterSemanticsNode*>* out_children) const override;
-  bool IsValid(FlutterSemanticsNode* node) const override;
-  bool IsIgnored(FlutterSemanticsNode* node) const override;
-  bool IsEqual(FlutterSemanticsNode* node1,
-               FlutterSemanticsNode* node2) const override;
-  FlutterSemanticsNode* GetNull() const override;
-
-  // Computes the smallest rect that encloses all of the descendants of |node|.
-  gfx::Rect ComputeEnclosingBounds(FlutterSemanticsNode* node) const;
-
-  // Helper to recursively compute bounds for |node|. Returns true if non-empty
-  // bounds were encountered.
-  void ComputeEnclosingBoundsInternal(FlutterSemanticsNode* node,
-                                      gfx::Rect* computed_bounds) const;
-
-  // AXHostDelegate implementation.
-  void PerformAction(const ui::AXActionData& data) override;
-
-  // Resets tree state.
-  void Reset();
-
-  // Detects live region changes and generates events for them.
-  void HandleLiveRegions(std::vector<ui::AXEvent>* events);
-
-  // Detects added or deleted routes that trigger TTS from edge
-  // transitions (i.e. alert dialogs).
-  void HandleRoutes(std::vector<ui::AXEvent>* events);
-
-  // Detects rapidly changing nodes and use native TTS instead.
-  void HandleNativeTTS();
-
-  // Handle the virtual keyboard nodes and calculate the bounds of it.
-  void HandleVirtualKeyboardNodes();
-
-  // Depth first search for a node under 'parent' with names route flag.
-  FlutterSemanticsNode* FindRoutesNode(FlutterSemanticsNode* parent);
-
-  // Find the first focusable node from the root.  If none found, return
-  // the root node id.
-  int32_t FindFirstFocusableNodeId();
-
-  // Submit text to TTS engine.
-  void SubmitTTS(const std::string& text);
-
-  std::unique_ptr<AXTreeFlutterSerializer> current_tree_serializer_;
-  int32_t root_id_;
-  int32_t window_id_;
-  int32_t focused_id_;
-
-  // A delegate that handles accessibility actions on behalf of this tree. The
-  // delegate is valid during the lifetime of this tree.
-  Delegate* delegate_;
-  content::BrowserContext* const browser_context_;
-  extensions::AutomationEventRouterInterface* const event_router_;
-
-  // Maps a node id to its tree data.
-  base::flat_map<int32_t /* node_id */, std::unique_ptr<FlutterSemanticsNode>>
-      tree_map_;
-
-  // Maps a node id to its parent.
-  base::flat_map<int32_t /* node_id */, int32_t /* parent_node_id */>
-      parent_map_;
-
-  // Mapping from ArcAccessibilityInfoData ID to its cached computed bounds.
-  // This simplifies bounds calculations.
-  base::flat_map<int32_t, gfx::Rect> cached_computed_bounds_;
-
-  // Cache from node id to computed name for live region.
-  std::map<int32_t, std::string> live_region_name_cache_;
-
-  // Cache for nodes with scopes route flags.
-  std::vector<int32_t> scopes_route_cache_;
-
-  // Cache form node id to tts string for native tts components.
-  std::map<int32_t, std::string> native_tts_name_cache_;
-
-  std::vector<int32_t> reparented_children_;
-  std::vector<std::string> child_trees_;
-
-  // Maps web contents id to the web contents observer
-  base::flat_map<int32_t, std::unique_ptr<AXTreeWebContentsObserver>>
-      child_tree_observers_;
-
-  // Observed CastWebContents for this tree node.
-  CastWebContents* cast_web_contents_;
-
-  // Copy of most recent tree data
-  gallium::castos::OnAccessibilityEventRequest last_event_data_;
-
-  bool accessibility_enabled_ = false;
-
-  // The bounds of virtual keyboard.
-  gfx::Rect keyboard_bounds_;
-};
-
-}  // namespace accessibility
-}  // namespace chromecast
-
-#endif  // CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_AX_TREE_SOURCE_FLUTTER_H_
diff --git a/chromecast/browser/accessibility/flutter/ax_tree_source_flutter_unittest.cc b/chromecast/browser/accessibility/flutter/ax_tree_source_flutter_unittest.cc
deleted file mode 100644
index e2bdabd..0000000
--- a/chromecast/browser/accessibility/flutter/ax_tree_source_flutter_unittest.cc
+++ /dev/null
@@ -1,944 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h"
-
-#include <string>
-
-#include "base/json/values_util.h"
-#include "base/unguessable_token.h"
-#include "chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/tts_controller.h"
-#include "content/public/browser/tts_platform.h"
-#include "content/public/common/content_client.h"
-#include "content/public/test/browser_task_environment.h"
-#include "content/public/test/test_browser_context.h"
-#include "extensions/browser/api/automation_internal/automation_event_router_interface.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/accessibility/ax_action_data.h"
-
-using ::testing::StrictMock;
-
-using ::gallium::castos::ActionProperties;
-using ::gallium::castos::BooleanProperties;
-using ::gallium::castos::OnAccessibilityEventRequest;
-using ::gallium::castos::OnAccessibilityEventRequest_EventType_ANNOUNCEMENT;
-using ::gallium::castos::OnAccessibilityEventRequest_EventType_CONTENT_CHANGED;
-using ::gallium::castos::OnAccessibilityEventRequest_EventType_FOCUSED;
-using ::gallium::castos::Rect;
-
-namespace content {
-
-class MockTtsPlatformImpl : public TtsPlatform {
- public:
-  MockTtsPlatformImpl() = default;
-  virtual ~MockTtsPlatformImpl() = default;
-
-  void set_voices(const std::vector<VoiceData>& voices) { voices_ = voices; }
-
-  void set_run_speak_callback(bool value) { run_speak_callback_ = value; }
-  void set_is_speaking(bool value) { is_speaking_ = value; }
-
-  // TtsPlatform:
-  bool PlatformImplSupported() override { return true; }
-  bool PlatformImplInitialized() override { return true; }
-  void Speak(int utterance_id,
-             const std::string& utterance,
-             const std::string& lang,
-             const VoiceData& voice,
-             const UtteranceContinuousParameters& params,
-             base::OnceCallback<void(bool)> on_speak_finished) override {
-    if (run_speak_callback_)
-      std::move(on_speak_finished).Run(true);
-    last_spoken_utterance_ = utterance;
-  }
-  bool IsSpeaking() override { return is_speaking_; }
-  bool StopSpeaking() override { return true; }
-  void Pause() override {}
-  void Resume() override {}
-  void GetVoices(std::vector<VoiceData>* out_voices) override {
-    *out_voices = voices_;
-  }
-  void GetVoicesForBrowserContext(content::BrowserContext* browser_context,
-                                  const GURL& source_url,
-                                  std::vector<VoiceData>* out_voices) override {
-  }
-  void RefreshVoices() override {}
-  void LoadBuiltInTtsEngine(BrowserContext* browser_context) override {}
-  void WillSpeakUtteranceWithVoice(TtsUtterance* utterance,
-                                   const VoiceData& voice_data) override {}
-  void SetError(const std::string& error) override {}
-  std::string GetError() override { return std::string(); }
-  void ClearError() override {}
-  const std::string& GetLastSpokenUtterance() { return last_spoken_utterance_; }
-  void ClearLastSpokenUtterance() { last_spoken_utterance_ = ""; }
-  void Shutdown() override {}
-  void FinalizeVoiceOrdering(std::vector<VoiceData>& voices) override {}
-
- private:
-  std::vector<VoiceData> voices_;
-  bool run_speak_callback_ = true;
-  bool is_speaking_ = false;
-  std::string last_spoken_utterance_;
-};
-
-class MockContentBrowserClient : public ContentBrowserClient {
- public:
-  ~MockContentBrowserClient() override {}
-};
-
-class MockContentClient : public ContentClient {
- public:
-  ~MockContentClient() override {}
-};
-
-}  // namespace content
-
-namespace chromecast {
-namespace accessibility {
-
-class MockAutomationEventRouter
-    : public extensions::AutomationEventRouterInterface {
- public:
-  MockAutomationEventRouter() {}
-  virtual ~MockAutomationEventRouter() = default;
-
-  void DispatchAccessibilityEvents(const ui::AXTreeID& tree_id,
-                                   std::vector<ui::AXTreeUpdate> updates,
-                                   const gfx::Point& mouse_location,
-                                   std::vector<ui::AXEvent> events) {
-    for (const auto& event : events)
-      event_count_[event.event_type]++;
-
-    last_updates_ = updates;
-  }
-  MOCK_METHOD(void,
-              DispatchAccessibilityLocationChange,
-              (const ExtensionMsg_AccessibilityLocationChangeParams&),
-              (override));
-  MOCK_METHOD(void,
-              DispatchTreeDestroyedEvent,
-              (ui::AXTreeID, content::BrowserContext*),
-              (override));
-  MOCK_METHOD(void,
-              DispatchActionResult,
-              (const ui::AXActionData&, bool, content::BrowserContext*),
-              (override));
-  void DispatchGetTextLocationDataResult(
-      const ui::AXActionData& data,
-      const absl::optional<gfx::Rect>& rect) override {}
-
-  std::map<ax::mojom::Event, int> event_count_;
-  std::vector<ui::AXTreeUpdate> last_updates_;
-};
-
-class AXTreeSourceFlutterTest : public testing::Test,
-                                public AXTreeSourceFlutter::Delegate {
- public:
-  AXTreeSourceFlutterTest()
-      : tree_(std::make_unique<AXTreeSourceFlutter>(this,
-                                                    &browser_context_,
-                                                    &router_)) {
-    // Enable by default.
-    tree_->SetAccessibilityEnabled(true);
-    // Setup some mocks required for tts platform impl
-    content::SetContentClient(&client_);
-    content::SetBrowserClientForTesting(&mock_content_browser_client_);
-  }
-  AXTreeSourceFlutterTest(const AXTreeSourceFlutterTest&) = delete;
-  ~AXTreeSourceFlutterTest() override {
-    EXPECT_CALL(router_, DispatchTreeDestroyedEvent).Times(1);
-    content::SetBrowserClientForTesting(nullptr);
-    content::SetContentClient(nullptr);
-  }
-  AXTreeSourceFlutterTest& operator=(const AXTreeSourceFlutterTest&) = delete;
-
- protected:
-  void CallNotifyAccessibilityEvent(OnAccessibilityEventRequest* event_data) {
-    tree_->NotifyAccessibilityEvent(event_data);
-  }
-
-  void SetAccessibilityEnabled(bool value) {
-    tree_->SetAccessibilityEnabled(value);
-  }
-
-  void CallGetChildren(SemanticsNode* node,
-                       std::vector<FlutterSemanticsNode*>* out_children) const {
-    FlutterSemanticsNodeWrapper node_data(tree_.get(), node);
-    tree_->GetChildren(&node_data, out_children);
-  }
-
-  void CallSerializeNode(SemanticsNode* node,
-                         std::unique_ptr<ui::AXNodeData>* out_data) const {
-    ASSERT_TRUE(out_data);
-    FlutterSemanticsNodeWrapper node_data(tree_.get(), node);
-    *out_data = std::make_unique<ui::AXNodeData>();
-    tree_->SerializeNode(&node_data, out_data->get());
-  }
-
-  FlutterSemanticsNode* CallGetFromId(int32_t id) const {
-    return tree_->GetFromId(id);
-  }
-
-  bool CallGetTreeData(ui::AXTreeData* data) {
-    return tree_->GetTreeData(data);
-  }
-
-  int GetDispatchedEventCount(ax::mojom::Event type) {
-    return router_.event_count_[type];
-  }
-
-  const std::vector<ui::AXTreeUpdate>& GetLastUpdates() {
-    return router_.last_updates_;
-  }
-
-  void SetRect(Rect* rect, int left, int top, int right, int bottom) {
-    rect->set_left(left);
-    rect->set_top(top);
-    rect->set_right(right);
-    rect->set_bottom(bottom);
-  }
-
-  void ReparentHelperInitial() {
-    OnAccessibilityEventRequest event;
-    event.set_source_id(0);
-    event.set_window_id(1);
-    event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-    //     0
-    //    / \
-    //   1   2
-    //        \
-    //         3
-    SemanticsNode* root = event.add_node_data();
-    SemanticsNode* child1 = event.add_node_data();
-    SemanticsNode* child2 = event.add_node_data();
-    SemanticsNode* child3 = event.add_node_data();
-    root->set_node_id(0);
-    root->add_child_node_ids(1);
-    root->add_child_node_ids(2);
-    child1->set_node_id(1);
-    child2->set_node_id(2);
-    child2->add_child_node_ids(3);
-    child3->set_node_id(3);
-
-    // Populate the tree source with the data.
-    CallNotifyAccessibilityEvent(&event);
-    EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-  }
-
-  void ReparentHelperUpdate() {
-    OnAccessibilityEventRequest event;
-    event.set_source_id(0);
-    event.set_window_id(1);
-    event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-    // We are going to reparent child 3
-    //     0
-    //    / \
-    //   1   4
-    //        \
-    //         3
-    SemanticsNode* root = event.add_node_data();
-    SemanticsNode* child1 = event.add_node_data();
-    SemanticsNode* child4 = event.add_node_data();
-    SemanticsNode* child3 = event.add_node_data();
-    root->set_node_id(0);
-    root->add_child_node_ids(1);
-    root->add_child_node_ids(4);
-    child1->set_node_id(1);
-    child4->set_node_id(4);
-    child4->add_child_node_ids(3);
-    child3->set_node_id(3);
-
-    // Populate the tree source with the data.
-    CallNotifyAccessibilityEvent(&event);
-    EXPECT_EQ(3, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-  }
-
-  SemanticsNode* AddChild(OnAccessibilityEventRequest* event,
-                          SemanticsNode* parent,
-                          int id,
-                          int x,
-                          int y,
-                          int w,
-                          int h,
-                          bool click) {
-    BooleanProperties* boolean_properties;
-    ActionProperties* action_properties;
-
-    SemanticsNode* new_node = event->add_node_data();
-    new_node->set_node_id(id);
-    Rect* bounds = new_node->mutable_bounds_in_screen();
-    SetRect(bounds, x, y, x + w, y + h);
-    boolean_properties = new_node->mutable_boolean_properties();
-    boolean_properties->set_is_button(click);
-    if (click) {
-      new_node->set_label("Button");
-    }
-    action_properties = new_node->mutable_action_properties();
-    action_properties->set_tap(click);
-
-    parent->add_child_node_ids(id);
-    return new_node;
-  }
-
-  gfx::Rect GetVirtualKeyboardBounds() const {
-    return virtual_keyboard_bounds_;
-  }
-
- private:
-  void OnAction(const ui::AXActionData& data) override {}
-  void OnVirtualKeyboardBoundsChange(const gfx::Rect& bounds) override {
-    virtual_keyboard_bounds_ = bounds;
-  }
-
-  // Required for the TestBrowserContext.
-  content::BrowserTaskEnvironment task_environment_;
-  content::TestBrowserContext browser_context_;
-  MockAutomationEventRouter router_;
-  std::unique_ptr<AXTreeSourceFlutter> tree_;
-  content::MockContentBrowserClient mock_content_browser_client_;
-  content::MockContentClient client_;
-  gfx::Rect virtual_keyboard_bounds_;
-};
-
-TEST_F(AXTreeSourceFlutterTest, AccessibleNameComputation) {
-  ActionProperties* action_properties;
-
-  OnAccessibilityEventRequest event;
-  event.set_source_id(0);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-  //     0
-  //    / \
-  //   1   2
-  SemanticsNode* root = event.add_node_data();
-  root->set_node_id(0);
-  root->add_child_node_ids(1);
-  root->add_child_node_ids(2);
-
-  // Child.
-  SemanticsNode* child1 = event.add_node_data();
-  child1->set_node_id(1);
-
-  // Another child.
-  SemanticsNode* child2 = event.add_node_data();
-  child2->set_node_id(2);
-
-  // Populate the tree source with the data.
-  CallNotifyAccessibilityEvent(&event);
-  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-
-  // No attributes.
-  std::unique_ptr<ui::AXNodeData> data;
-  CallSerializeNode(root, &data);
-  std::string name;
-  ASSERT_FALSE(
-      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
-  EXPECT_EQ("", name);
-
-  // Label (empty).
-  root->set_label("");
-  CallSerializeNode(root, &data);
-  ASSERT_TRUE(
-      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
-  EXPECT_EQ("", name);
-
-  // Label (non-empty).
-  root->set_label("label text");
-  CallSerializeNode(root, &data);
-  ASSERT_TRUE(
-      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
-  EXPECT_EQ("label text", name);
-
-  // Hint (empty), Label (non-empty).
-  root->set_hint("");
-  CallSerializeNode(root, &data);
-  ASSERT_TRUE(
-      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
-  EXPECT_EQ("label text", name);
-
-  // Hint (non-empty), Label (empty).
-  root->set_hint("hint");
-  root->clear_label();
-  CallSerializeNode(root, &data);
-  ASSERT_TRUE(
-      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
-  EXPECT_EQ("hint", name);
-
-  // Name from contents.
-
-  // Root node has no name, but has descendants with name.
-  root->clear_hint();
-  root->clear_label();
-  // Name from contents only happens if a node is clickable.
-  action_properties = root->mutable_action_properties();
-  action_properties->set_tap(true);
-  child1->set_label("child1 label text");
-  child2->set_label("child2 label text");
-  CallSerializeNode(root, &data);
-  ASSERT_TRUE(
-      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
-  ASSERT_EQ("child1 label text child2 label text", name);
-
-  // If the node has a name, it should override the contents.
-  root->set_label("root label text");
-  CallSerializeNode(root, &data);
-  ASSERT_TRUE(
-      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
-  ASSERT_EQ("root label text", name);
-
-  // Clearing both clickable and name from root, the name should not be
-  // populated.
-  root->clear_label();
-  action_properties->clear_tap();
-  CallSerializeNode(root, &data);
-  ASSERT_FALSE(
-      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
-}
-
-// Flutter's 'hidden' attribute should not translate to the node being
-// ignored or in any way not a11y focusable.
-TEST_F(AXTreeSourceFlutterTest, NeverHidden) {
-  OnAccessibilityEventRequest event;
-  event.set_source_id(0);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-  BooleanProperties* boolean_properties;
-  SemanticsNode* root = event.add_node_data();
-  root->add_child_node_ids(1);
-  SemanticsNode* child1 = event.add_node_data();
-  child1->set_node_id(1);
-  child1->set_label("some label text");
-  boolean_properties = child1->mutable_boolean_properties();
-  boolean_properties->set_is_hidden(true);
-
-  CallNotifyAccessibilityEvent(&event);
-  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-
-  std::unique_ptr<ui::AXNodeData> data;
-  CallSerializeNode(child1, &data);
-
-  ASSERT_TRUE(data->role == ax::mojom::Role::kStaticText);
-  ASSERT_FALSE(data->HasState(ax::mojom::State::kInvisible));
-}
-
-TEST_F(AXTreeSourceFlutterTest, GetTreeDataAppliesFocus) {
-  OnAccessibilityEventRequest event;
-  event.set_source_id(5);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-  SemanticsNode* root = event.add_node_data();
-  root->set_node_id(5);
-
-  CallNotifyAccessibilityEvent(&event);
-  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-  ui::AXTreeData data;
-
-  // If no node claimed focus, the root node should get it.
-  EXPECT_TRUE(CallGetTreeData(&data));
-  EXPECT_EQ(5, data.focus_id);
-
-  // Add a child node with focus.
-  root->add_child_node_ids(6);
-  SemanticsNode* child = event.add_node_data();
-  child->set_node_id(6);
-  child->mutable_boolean_properties()->set_is_focused(true);
-
-  CallNotifyAccessibilityEvent(&event);
-  EXPECT_EQ(2, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-
-  EXPECT_TRUE(CallGetTreeData(&data));
-  EXPECT_EQ(6, data.focus_id);
-}
-
-TEST_F(AXTreeSourceFlutterTest, LiveRegion) {
-  OnAccessibilityEventRequest event;
-  event.set_source_id(1);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-  SemanticsNode* root = event.add_node_data();
-  root->set_node_id(10);
-  root->add_child_node_ids(1);
-  root->add_child_node_ids(2);
-  BooleanProperties* boolean_properties = root->mutable_boolean_properties();
-  boolean_properties->set_is_live_region(true);
-
-  // Add child nodes.
-  SemanticsNode* node1 = event.add_node_data();
-  node1->set_node_id(1);
-  node1->set_label("text 1");
-
-  SemanticsNode* node2 = event.add_node_data();
-  node2->set_node_id(2);
-  node2->set_label("text 2");
-
-  CallNotifyAccessibilityEvent(&event);
-  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-
-  std::unique_ptr<ui::AXNodeData> data;
-  CallSerializeNode(root, &data);
-  std::string status;
-  ASSERT_TRUE(data->GetStringAttribute(
-      ax::mojom::StringAttribute::kContainerLiveStatus, &status));
-  ASSERT_EQ(status, "polite");
-
-  EXPECT_EQ(0, GetDispatchedEventCount(ax::mojom::Event::kLiveRegionChanged));
-
-  // Modify text of node1.
-  node1->set_label("modified text 1");
-  CallNotifyAccessibilityEvent(&event);
-
-  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kLiveRegionChanged));
-}
-
-TEST_F(AXTreeSourceFlutterTest, ResetFocus) {
-  //
-  // tree 1: no child tree
-  //
-  OnAccessibilityEventRequest event;
-
-  event.set_source_id(0);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-  SemanticsNode* root = event.add_node_data();
-  root->set_node_id(0);
-  Rect* bounds = root->mutable_bounds_in_screen();
-  SetRect(bounds, 0, 0, 1280, 800);
-
-  SemanticsNode* child;
-  AddChild(&event, root, 1, 0, 0, 800, 600, false);
-
-  child = AddChild(&event, root, 2, 0, 0, 400, 600, false);
-  child = AddChild(&event, root, 3, 400, 0, 400, 600, false);
-
-  CallNotifyAccessibilityEvent(&event);
-
-  // initial focus on root
-  ui::AXTreeData tree_data;
-  CallGetTreeData(&tree_data);
-  ASSERT_EQ(0, tree_data.focus_id);
-
-  //
-  // tree 2: add a node with a child tree id
-  //
-  OnAccessibilityEventRequest event2;
-
-  event2.set_source_id(0);
-  event2.set_window_id(1);
-  event2.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-  SemanticsNode* root2 = event2.add_node_data();
-  root2->set_node_id(0);
-  Rect* bounds2 = root2->mutable_bounds_in_screen();
-  SetRect(bounds2, 0, 0, 1280, 800);
-
-  AddChild(&event2, root2, 1, 0, 0, 800, 600, false);
-
-  child = AddChild(&event2, root2, 2, 0, 0, 400, 600, false);
-  child = AddChild(&event2, root2, 3, 400, 0, 400, 600, false);
-  child = AddChild(&event2, root2, 4, 0, 0, 200, 200, false);
-
-  // We need a plugin id that is the right length. Here we use
-  base::UnguessableToken token = base::UnguessableToken::Create();
-  std::string token_to_string =
-      base::UnguessableTokenToValue(token).GetString();
-  child->set_plugin_id(token_to_string);
-
-  // focus should move to node with child tree
-  CallNotifyAccessibilityEvent(&event2);
-  CallGetTreeData(&tree_data);
-  ASSERT_EQ(4, tree_data.focus_id);
-
-  //
-  // tree 2: back to initial tree
-  //
-  CallNotifyAccessibilityEvent(&event);
-  CallGetTreeData(&tree_data);
-
-  // focus back to root
-  ASSERT_EQ(0, tree_data.focus_id);
-}
-
-TEST_F(AXTreeSourceFlutterTest, NoClickable) {
-  OnAccessibilityEventRequest event;
-
-  event.set_source_id(0);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-  SemanticsNode* root = event.add_node_data();
-  root->set_node_id(0);
-  ActionProperties* action_properties = root->mutable_action_properties();
-  action_properties->set_tap(true);
-  Rect* bounds = root->mutable_bounds_in_screen();
-  SetRect(bounds, 0, 0, 1280, 800);
-
-  CallNotifyAccessibilityEvent(&event);
-  std::unique_ptr<ui::AXNodeData> data;
-  CallSerializeNode(root, &data);
-
-  // No node should get the clickable attribute.
-  ASSERT_FALSE(data->GetBoolAttribute(ax::mojom::BoolAttribute::kClickable));
-}
-
-// Tests a new node with scopes route will focus and speak
-// a child with names route set.
-TEST_F(AXTreeSourceFlutterTest, ScopesRoute) {
-  // Add node with scopes route and child with names route. Focus
-  // should move to node with names route.
-  //
-  OnAccessibilityEventRequest event;
-
-  event.set_source_id(0);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_CONTENT_CHANGED);
-
-  SemanticsNode* root = event.add_node_data();
-  root->set_node_id(0);
-
-  SemanticsNode* child1;
-  SemanticsNode* child2;
-  SemanticsNode* child3;
-  SemanticsNode* child4;
-  SemanticsNode* child5;
-  SemanticsNode* child6;
-
-  child1 = AddChild(&event, root, 1, 0, 0, 1, 1, false);
-  child2 = AddChild(&event, child1, 2, 0, 0, 1, 1, false);
-  child3 = AddChild(&event, child2, 3, 0, 0, 1, 1, false);
-  std::string child_3_label = "Speak This";
-  child3->set_label(child_3_label);
-
-  child4 = AddChild(&event, root, 4, 0, 0, 1, 1, false);
-  child5 = AddChild(&event, child4, 5, 0, 0, 1, 1, false);
-  child6 = AddChild(&event, child5, 6, 0, 0, 1, 1, false);
-  std::string child_6_label = "Speak That";
-  child6->set_label(child_6_label);
-
-  BooleanProperties* boolean_properties;
-
-  // Set scopes on child2, names on child3
-  boolean_properties = child2->mutable_boolean_properties();
-  boolean_properties->set_scopes_route(true);
-  boolean_properties = child3->mutable_boolean_properties();
-  boolean_properties->set_names_route(true);
-
-  // Set scopes on child5, names on child6
-  boolean_properties = child5->mutable_boolean_properties();
-  boolean_properties->set_scopes_route(true);
-  boolean_properties = child6->mutable_boolean_properties();
-  boolean_properties->set_names_route(true);
-
-  CallNotifyAccessibilityEvent(&event);
-
-  // focus should have moved to child 6 since that is the first
-  // node that will be found with scopes
-  ui::AXTreeData tree_data;
-  CallGetTreeData(&tree_data);
-  ASSERT_EQ(6, tree_data.focus_id);
-
-  // Same tree should not speak the same scopes_route/names_route
-  CallNotifyAccessibilityEvent(&event);
-
-  // Now setup another tree but with 5&6 removed. This should
-  // make the tree source focus (but not speak) 3
-
-  OnAccessibilityEventRequest event2;
-  event2.set_source_id(0);
-  event2.set_window_id(1);
-  event2.set_event_type(OnAccessibilityEventRequest_EventType_CONTENT_CHANGED);
-
-  root = event2.add_node_data();
-  root->set_node_id(0);
-
-  child1 = AddChild(&event2, root, 1, 0, 0, 1, 1, false);
-  child2 = AddChild(&event2, child1, 2, 0, 0, 1, 1, false);
-  child3 = AddChild(&event2, child2, 3, 0, 0, 1, 1, false);
-  child3->set_label(child_3_label);
-
-  // Set scopes on child2, names on child3
-  boolean_properties = child2->mutable_boolean_properties();
-  boolean_properties->set_scopes_route(true);
-  boolean_properties = child3->mutable_boolean_properties();
-  boolean_properties->set_names_route(true);
-
-  CallNotifyAccessibilityEvent(&event2);
-
-  // Focus moves to 3
-  CallGetTreeData(&tree_data);
-  ASSERT_EQ(3, tree_data.focus_id);
-
-  // Now step to have removed node 3 and re-add node 3 back in the tree. In this
-  // case, node 3 should be refocused and spoken.
-
-  OnAccessibilityEventRequest event3;
-  event3.set_source_id(0);
-  event3.set_window_id(1);
-  event3.set_event_type(OnAccessibilityEventRequest_EventType_CONTENT_CHANGED);
-
-  root = event3.add_node_data();
-  root->set_node_id(0);
-
-  child1 = AddChild(&event3, root, 1, 0, 0, 1, 1, false);
-  child2 = AddChild(&event3, child1, 2, 0, 0, 1, 1, false);
-
-  // Set scopes on child2
-  boolean_properties = child2->mutable_boolean_properties();
-  boolean_properties->set_scopes_route(true);
-
-  CallNotifyAccessibilityEvent(&event3);
-
-  OnAccessibilityEventRequest event4;
-  event4.set_source_id(0);
-  event4.set_window_id(1);
-  event4.set_event_type(OnAccessibilityEventRequest_EventType_CONTENT_CHANGED);
-
-  root = event4.add_node_data();
-  root->set_node_id(0);
-
-  child1 = AddChild(&event4, root, 1, 0, 0, 1, 1, false);
-  child2 = AddChild(&event4, child1, 2, 0, 0, 1, 1, false);
-  child3 = AddChild(&event4, child2, 3, 0, 0, 1, 1, false);
-  child3->set_label(child_3_label);
-
-  // Set scopes on child2, names on child3
-  boolean_properties = child2->mutable_boolean_properties();
-  boolean_properties->set_scopes_route(true);
-  boolean_properties = child3->mutable_boolean_properties();
-  boolean_properties->set_names_route(true);
-
-  CallNotifyAccessibilityEvent(&event4);
-
-  // Focus moves to 3
-  CallGetTreeData(&tree_data);
-  ASSERT_EQ(3, tree_data.focus_id);
-
-  // Finally, remove 2
-  //
-  OnAccessibilityEventRequest event5;
-  event5.set_source_id(0);
-  event5.set_window_id(1);
-  event5.set_event_type(OnAccessibilityEventRequest_EventType_CONTENT_CHANGED);
-
-  root = event5.add_node_data();
-  root->set_node_id(0);
-
-  CallNotifyAccessibilityEvent(&event5);
-
-  CallGetTreeData(&tree_data);
-  ASSERT_EQ(0, tree_data.focus_id);
-}
-
-// A test to ensure a node that had scopes route but never
-// had any names route descendant does not cause a refocus.
-TEST_F(AXTreeSourceFlutterTest, ScopesRouteNoNames) {
-  // Install a mock tts platform
-  auto* tts_controller = content::TtsController::GetInstance();
-  content::MockTtsPlatformImpl mock_tts_platform;
-  tts_controller->SetTtsPlatform(&mock_tts_platform);
-
-  // Add node with scopes route but no names route descendant.
-  OnAccessibilityEventRequest event;
-
-  event.set_source_id(0);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_CONTENT_CHANGED);
-
-  SemanticsNode* root = event.add_node_data();
-  root->set_node_id(0);
-
-  SemanticsNode* child1;
-  SemanticsNode* child2;
-
-  child1 = AddChild(&event, root, 1, 0, 0, 1, 1, false);
-  child2 = AddChild(&event, child1, 2, 0, 0, 1, 1, false);
-  std::string child_2_label = "Don't Speak This";
-  child2->set_label(child_2_label);
-
-  BooleanProperties* boolean_properties;
-
-  // Set scopes on child1 but no names on child 2
-  boolean_properties = child1->mutable_boolean_properties();
-  boolean_properties->set_scopes_route(true);
-
-  mock_tts_platform.ClearLastSpokenUtterance();
-
-  CallNotifyAccessibilityEvent(&event);
-
-  // focus should remain on root
-  ui::AXTreeData tree_data;
-  CallGetTreeData(&tree_data);
-
-  // Confirm no spoken TTS or focus change
-  ASSERT_TRUE(mock_tts_platform.GetLastSpokenUtterance() == "");
-  ASSERT_EQ(0, tree_data.focus_id);
-  EXPECT_EQ(0, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-
-  // Remove the node with scopes route. Again, no focus or spoken
-  // tts is expected.
-  OnAccessibilityEventRequest event2;
-
-  event2.set_source_id(0);
-  event2.set_window_id(1);
-  event2.set_event_type(OnAccessibilityEventRequest_EventType_CONTENT_CHANGED);
-
-  SemanticsNode* root2 = event2.add_node_data();
-  root2->set_node_id(0);
-
-  CallNotifyAccessibilityEvent(&event2);
-
-  // Again, confirm no spoken TTS or focus change
-  ASSERT_EQ(0, tree_data.focus_id);
-  ASSERT_TRUE(mock_tts_platform.GetLastSpokenUtterance() == "");
-  EXPECT_EQ(0, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-
-  // Cleanup since the mock will expire at the end of this test.
-  tts_controller->SetTtsPlatform(content::TtsPlatform::GetInstance());
-}
-
-TEST_F(AXTreeSourceFlutterTest, LeaveTheChildrenAlone) {
-  OnAccessibilityEventRequest event;
-
-  event.set_source_id(0);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-  SemanticsNode* root = event.add_node_data();
-  root->set_node_id(0);
-  Rect* bounds = root->mutable_bounds_in_screen();
-  SetRect(bounds, 0, 0, 1280, 800);
-
-  SemanticsNode* child;
-  AddChild(&event, root, 17, 0, 0, 422, 800, true);
-
-  child = AddChild(&event, root, 29, 1022, 0, 257, 800, false);
-  child = AddChild(&event, child, 30, 1022, 55, 257, 690, true);
-  AddChild(&event, child, 31, 1232, 165, 47, 150, false);
-  AddChild(&event, child, 32, 1232, 165, 47, 150, false);
-
-  child = AddChild(&event, root, 18, 422, 0, 600, 800, false);
-  child = AddChild(&event, child, 19, 422, 55, 570, 690, false);
-  AddChild(&event, child, 20, 507, 95, 445, 40, false);
-  AddChild(&event, child, 21, 463, 186, 488, 70, true);
-  AddChild(&event, child, 22, 463, 283, 488, 70, true);
-  AddChild(&event, child, 23, 463, 381, 488, 70, true);
-  AddChild(&event, child, 24, 463, 478, 488, 70, true);
-
-  CallNotifyAccessibilityEvent(&event);
-  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-  std::vector<FlutterSemanticsNode*> ordered;
-  CallGetChildren(root, &ordered);
-  ASSERT_EQ(3U, ordered.size());
-  EXPECT_EQ(17, ordered[0]->GetId());
-  EXPECT_EQ(29, ordered[1]->GetId());
-  EXPECT_EQ(18, ordered[2]->GetId());
-}
-
-TEST_F(AXTreeSourceFlutterTest, Announce) {
-  // Install a mock tts platform
-  auto* tts_controller = content::TtsController::GetInstance();
-  content::MockTtsPlatformImpl mock_tts_platform;
-  tts_controller->SetTtsPlatform(&mock_tts_platform);
-
-  // Setup an announcement event
-  OnAccessibilityEventRequest event;
-  SetAccessibilityEnabled(false);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_ANNOUNCEMENT);
-  event.set_text("Say this please");
-  CallNotifyAccessibilityEvent(&event);
-
-  // Child 3 should NOT have been spoken
-  ASSERT_EQ(mock_tts_platform.GetLastSpokenUtterance(), "");
-
-  // This time with a11y enabled.
-  SetAccessibilityEnabled(true);
-  CallNotifyAccessibilityEvent(&event);
-
-  // Child 3 should have been spoken
-  ASSERT_EQ(mock_tts_platform.GetLastSpokenUtterance(), "Say this please");
-
-  // Cleanup since the mock will expire at the end of this test.
-  tts_controller->SetTtsPlatform(content::TtsPlatform::GetInstance());
-}
-
-TEST_F(AXTreeSourceFlutterTest, KeyboardBounds) {
-  OnAccessibilityEventRequest event;
-  event.set_source_id(1);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-
-  SemanticsNode* root = event.add_node_data();
-  root->set_node_id(10);
-  root->add_child_node_ids(1);
-  root->add_child_node_ids(2);
-
-  // Add child nodes.
-  SemanticsNode* node1 = event.add_node_data();
-  node1->set_node_id(1);
-  node1->set_label("text 1");
-  Rect* bounds1 = node1->mutable_bounds_in_screen();
-  SetRect(bounds1, 0, 0, 320, 200);
-
-  SemanticsNode* node2 = event.add_node_data();
-  node2->set_node_id(2);
-  node2->set_label("text 2");
-  Rect* bounds2 = node2->mutable_bounds_in_screen();
-  SetRect(bounds2, 320, 200, 640, 400);
-
-  // No keyboard nodes.
-  CallNotifyAccessibilityEvent(&event);
-  EXPECT_EQ(gfx::Rect(), GetVirtualKeyboardBounds());
-
-  // node 1 and node 2 are keyboard nodes.
-  BooleanProperties* boolean_properties;
-  boolean_properties = node1->mutable_boolean_properties();
-  boolean_properties->set_is_lift_to_type(true);
-  boolean_properties = node2->mutable_boolean_properties();
-  boolean_properties->set_is_lift_to_type(true);
-  CallNotifyAccessibilityEvent(&event);
-  EXPECT_EQ(gfx::Rect(0, 0, 640, 400), GetVirtualKeyboardBounds());
-}
-
-// b/190749275 - Repro crash due to pointers to event
-// data that went out of scope still held on to by
-// the tree source. Triggered by reparenting children with
-// empty update in between updates.
-TEST_F(AXTreeSourceFlutterTest, ReparentedChildren) {
-  // Send in the initial tree.
-  ReparentHelperInitial();
-
-  // Send an empty update.
-  OnAccessibilityEventRequest event;
-  event.set_source_id(0);
-  event.set_window_id(1);
-  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
-  CallNotifyAccessibilityEvent(&event);
-  EXPECT_EQ(2, GetDispatchedEventCount(ax::mojom::Event::kFocus));
-
-  // Reparent node 3.
-  ReparentHelperUpdate();
-
-  // There should be an extra update from the one notification
-  // we just did in which child 3 should not appear.
-  const std::vector<ui::AXTreeUpdate>& last_updates = GetLastUpdates();
-  EXPECT_EQ(2ul, last_updates.size());
-
-  // Make sure child 3 has disappeared in the first update.
-  const ui::AXTreeUpdate& first_update = last_updates[0];
-  for (const auto& node : first_update.nodes) {
-    EXPECT_NE(3, node.id);
-  }
-}
-
-}  // namespace accessibility
-}  // namespace chromecast
diff --git a/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.cc b/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.cc
deleted file mode 100644
index 0823f29..0000000
--- a/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.cc
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.h"
-
-#include <utility>
-
-#include "base/logging.h"
-#include "chromecast/browser/accessibility/accessibility_manager.h"
-#include "chromecast/browser/accessibility/proto/gallium_server_accessibility.grpc.pb.h"
-#include "chromecast/browser/cast_browser_process.h"
-#include "components/exo/fullscreen_shell_surface.h"
-#include "components/exo/shell_surface_util.h"
-#include "components/exo/surface.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "ui/accessibility/aura/aura_window_properties.h"
-#include "ui/accessibility/ax_action_data.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/widget.h"
-
-namespace chromecast {
-namespace gallium {
-namespace accessibility {
-
-using ::gallium::castos::
-    OnAccessibilityActionRequest_AccessibilityActionType_CUSTOM_ACTION;
-using ::gallium::castos::
-    // NOLINTNEXTLINE(whitespace/line_length)
-    OnAccessibilityActionRequest_AccessibilityActionType_DID_GAIN_ACCESSIBILITY_FOCUS;
-using ::gallium::castos::
-    // NOLINTNEXTLINE(whitespace/line_length)
-    OnAccessibilityActionRequest_AccessibilityActionType_DID_LOSE_ACCESSIBILITY_FOCUS;
-using ::gallium::castos::
-    OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_DOWN;
-using ::gallium::castos::
-    OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_LEFT;
-using ::gallium::castos::
-    OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_RIGHT;
-using ::gallium::castos::
-    OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_UP;
-using ::gallium::castos::
-    OnAccessibilityActionRequest_AccessibilityActionType_SET_SELECTION;
-using ::gallium::castos::
-    OnAccessibilityActionRequest_AccessibilityActionType_SHOW_ON_SCREEN;
-using ::gallium::castos::
-    OnAccessibilityActionRequest_AccessibilityActionType_TAP;
-
-FlutterAccessibilityHelperBridge::FlutterAccessibilityHelperBridge(
-    Delegate* bridge_delegate,
-    content::BrowserContext* browser_context)
-    : tree_source_(
-          std::make_unique<AXTreeSourceFlutter>(this, browser_context)),
-      bridge_delegate_(bridge_delegate) {}
-
-FlutterAccessibilityHelperBridge::~FlutterAccessibilityHelperBridge() = default;
-
-void FlutterAccessibilityHelperBridge::AccessibilityStateChanged(bool value) {
-  tree_source_->SetAccessibilityEnabled(value);
-  if (value) {
-    aura::Window* window = chromecast::shell::CastBrowserProcess::GetInstance()
-                               ->accessibility_manager()
-                               ->window_tree_host()
-                               ->window();
-
-    // Find the full screen shell surface for the exo::Surface representing
-    // the ui.  We must ensure our tree id is the child ax tree id for
-    // that view so when the root window is serialized, the flutter ax tree
-    // will be parented by that view.
-    bool found = false;
-    if (window) {
-      for (aura::Window* child : window->children()) {
-        exo::Surface* surface = exo::GetShellRootSurface(child);
-        if (surface) {
-          views::Widget* widget =
-              views::Widget::GetWidgetForNativeWindow(child);
-          if (widget) {
-            exo::FullscreenShellSurface* full_screen_shell_surface =
-                static_cast<exo::FullscreenShellSurface*>(
-                    widget->widget_delegate());
-            full_screen_shell_surface->SetChildAxTreeId(
-                tree_source_->ax_tree_id());
-            full_screen_shell_surface->GetContentsView()
-                ->NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged,
-                                           false);
-            child->Focus();
-            found = true;
-          }
-          break;
-        }
-      }
-    }
-
-    if (!found) {
-      LOG(ERROR) << "Could not find full screen shell surface for ax tree.";
-    }
-  }
-}
-
-void FlutterAccessibilityHelperBridge::OnAccessibilityEventRequestInternal(
-    std::unique_ptr<::gallium::castos::OnAccessibilityEventRequest>
-        event_data) {
-  // Tell the tree source to serialize these changes.
-  tree_source_->NotifyAccessibilityEvent(event_data.get());
-}
-
-bool FlutterAccessibilityHelperBridge::OnAccessibilityEventRequest(
-    const ::gallium::castos::OnAccessibilityEventRequest* event_data) {
-  std::unique_ptr<::gallium::castos::OnAccessibilityEventRequest> event =
-      std::make_unique<::gallium::castos::OnAccessibilityEventRequest>(
-          *event_data);
-
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&FlutterAccessibilityHelperBridge::
-                                    OnAccessibilityEventRequestInternal,
-                                base::Unretained(this), std::move(event)));
-  return true;
-}
-
-void FlutterAccessibilityHelperBridge::OnAction(const ui::AXActionData& data) {
-  // Called by tree source to dispatch ax action to flutter. Translate this
-  // to gallium accessibility proto and forward to the delegate for
-  // dispatching.
-  ::gallium::castos::OnAccessibilityActionRequest request;
-  request.set_node_id(data.target_node_id);
-
-  switch (data.action) {
-    case ax::mojom::Action::kDoDefault:
-      request.set_action_type(
-          OnAccessibilityActionRequest_AccessibilityActionType_TAP);
-      break;
-    case ax::mojom::Action::kScrollToMakeVisible:
-      request.set_action_type(
-          OnAccessibilityActionRequest_AccessibilityActionType_SHOW_ON_SCREEN);
-      break;
-    case ax::mojom::Action::kScrollBackward:
-      request.set_action_type(
-          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_LEFT);
-      tree_source_->NotifyActionResult(data, false);
-      break;
-    case ax::mojom::Action::kScrollForward:
-      request.set_action_type(
-          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_RIGHT);
-      tree_source_->NotifyActionResult(data, false);
-      break;
-    case ax::mojom::Action::kScrollUp:
-      request.set_action_type(
-          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_UP);
-      tree_source_->NotifyActionResult(data, false);
-      break;
-    case ax::mojom::Action::kScrollDown:
-      request.set_action_type(
-          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_DOWN);
-      tree_source_->NotifyActionResult(data, false);
-      break;
-    case ax::mojom::Action::kScrollLeft:
-      request.set_action_type(
-          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_LEFT);
-      tree_source_->NotifyActionResult(data, false);
-      break;
-    case ax::mojom::Action::kScrollRight:
-      request.set_action_type(
-          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_RIGHT);
-      tree_source_->NotifyActionResult(data, false);
-      break;
-    case ax::mojom::Action::kCustomAction:
-      request.set_action_type(
-          OnAccessibilityActionRequest_AccessibilityActionType_CUSTOM_ACTION);
-      request.set_custom_action_id(data.custom_action_id);
-      break;
-    case ax::mojom::Action::kSetAccessibilityFocus:
-      request.set_action_type(
-          // NOLINTNEXTLINE(whitespace/line_length)
-          OnAccessibilityActionRequest_AccessibilityActionType_DID_GAIN_ACCESSIBILITY_FOCUS);
-      break;
-    case ax::mojom::Action::kClearAccessibilityFocus:
-      request.set_action_type(
-          // NOLINTNEXTLINE(whitespace/line_length)
-          OnAccessibilityActionRequest_AccessibilityActionType_DID_LOSE_ACCESSIBILITY_FOCUS);
-      break;
-    case ax::mojom::Action::kGetTextLocation:
-      request.set_action_type(
-          OnAccessibilityActionRequest_AccessibilityActionType_SET_SELECTION);
-      request.set_start_index(data.start_index);
-      request.set_end_index(data.end_index);
-      break;
-    default:
-      LOG(WARNING) << "Cast ax action " << data.action
-                   << " not mapped to flutter action - dropped.";
-
-      return;
-  }
-
-  bridge_delegate_->SendAccessibilityAction(request);
-}
-
-void FlutterAccessibilityHelperBridge::OnVirtualKeyboardBoundsChange(
-    const gfx::Rect& bounds) {
-  chromecast::shell::CastBrowserProcess::GetInstance()
-      ->accessibility_manager()
-      ->SetVirtualKeyboardBounds(bounds);
-}
-
-}  // namespace accessibility
-}  // namespace gallium
-}  // namespace chromecast
diff --git a/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.h b/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.h
deleted file mode 100644
index b8c6596..0000000
--- a/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_ACCESSIBILITY_HELPER_BRIDGE_H_
-#define CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_ACCESSIBILITY_HELPER_BRIDGE_H_
-
-#include <memory>
-
-#include "chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h"
-
-using chromecast::accessibility::AXTreeSourceFlutter;
-
-namespace content {
-class BrowserContext;
-}  // namespace content
-
-namespace gallium {
-namespace castos {
-class OnAccessibilityEventRequest;
-class OnAccessibilityActionRequest;
-}  // namespace castos
-}  // namespace gallium
-
-namespace chromecast {
-namespace gallium {
-namespace accessibility {
-
-// FlutterAccessibilityHelperBridge receives Flutter accessibility
-// events from gallium, translates them to chrome tree updates and dispatches
-// them to chromecast accessibility services.
-class FlutterAccessibilityHelperBridge : public AXTreeSourceFlutter::Delegate {
- public:
-  class Delegate {
-   public:
-    virtual void SendAccessibilityAction(
-        ::gallium::castos::OnAccessibilityActionRequest request) = 0;
-
-   protected:
-    virtual ~Delegate() = default;
-  };
-
-  FlutterAccessibilityHelperBridge(Delegate* bridge_delegate,
-                                   content::BrowserContext* browser_context);
-  FlutterAccessibilityHelperBridge(const FlutterAccessibilityHelperBridge&) =
-      delete;
-  ~FlutterAccessibilityHelperBridge() override;
-  FlutterAccessibilityHelperBridge& operator=(
-      const FlutterAccessibilityHelperBridge&) = delete;
-
-  // Receive an accessibility event from flutter.
-  bool OnAccessibilityEventRequest(
-      const ::gallium::castos::OnAccessibilityEventRequest* event_data);
-
-  // AXTreeSourceArc::Delegate implementation:
-  // Dispatch a chrome accessibility action to flutter.
-  void OnAction(const ui::AXActionData& data) override;
-  void OnVirtualKeyboardBoundsChange(const gfx::Rect& bounds) override;
-
-  void AccessibilityStateChanged(bool value);
-
- private:
-  void OnAccessibilityEventRequestInternal(
-      std::unique_ptr<::gallium::castos::OnAccessibilityEventRequest>
-          event_data);
-
-  std::unique_ptr<AXTreeSourceFlutter> tree_source_;
-  Delegate* bridge_delegate_;
-};
-
-}  // namespace accessibility
-}  // namespace gallium
-}  // namespace chromecast
-
-#endif  // CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_ACCESSIBILITY_HELPER_BRIDGE_H_
diff --git a/chromecast/browser/accessibility/flutter/flutter_semantics_node.h b/chromecast/browser/accessibility/flutter/flutter_semantics_node.h
deleted file mode 100644
index f9a1022..0000000
--- a/chromecast/browser/accessibility/flutter/flutter_semantics_node.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_H_
-#define CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_H_
-
-#include <string>
-#include <vector>
-
-#include "ui/gfx/geometry/rect.h"
-
-namespace ui {
-struct AXNodeData;
-}  // namespace ui
-
-namespace chromecast {
-namespace accessibility {
-
-// FlutterSemanticsNode represents a single flutter semantics object from
-// flutter. This class is used by AXTreeSourceFlutter to encapsulate
-// flutter information which maps to a single AXNodeData.
-class FlutterSemanticsNode {
- public:
-  virtual ~FlutterSemanticsNode() = default;
-
-  virtual int32_t GetId() const = 0;
-  virtual const gfx::Rect GetBounds() const = 0;
-  virtual bool IsVisibleToUser() const = 0;
-  virtual bool IsFocused() const = 0;
-  virtual bool IsLiveRegion() const = 0;
-  virtual bool HasScopesRoute() const = 0;
-  virtual bool HasNamesRoute() const = 0;
-  virtual bool IsRapidChangingSlider() const = 0;
-  virtual bool CanBeAccessibilityFocused() const = 0;
-  virtual void PopulateAXRole(ui::AXNodeData* out_data) const = 0;
-  virtual void PopulateAXState(ui::AXNodeData* out_data) const = 0;
-  virtual void Serialize(ui::AXNodeData* out_data) const = 0;
-  virtual void GetChildren(
-      std::vector<FlutterSemanticsNode*>* children) const = 0;
-  virtual void ComputeNameFromContents(
-      std::vector<std::string>* names) const = 0;
-  virtual bool HasLabelHint() const = 0;
-  virtual std::string GetLabelHint() const = 0;
-  virtual bool HasValue() const = 0;
-  virtual std::string GetValue() const = 0;
-  virtual bool IsKeyboardNode() const = 0;
-};
-
-}  // namespace accessibility
-}  // namespace chromecast
-
-#endif  // CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_H_
diff --git a/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.cc b/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.cc
deleted file mode 100644
index 07c440b..0000000
--- a/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.cc
+++ /dev/null
@@ -1,624 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h"
-
-#include "base/check.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h"
-#include "chromecast/browser/cast_web_contents.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/accessibility/ax_action_handler_registry.h"
-
-using gallium::castos::ActionProperties;
-using gallium::castos::BooleanProperties;
-
-namespace chromecast {
-namespace accessibility {
-
-FlutterSemanticsNodeWrapper::FlutterSemanticsNodeWrapper(
-    ui::AXTreeSource<FlutterSemanticsNode*>* tree_source,
-    const SemanticsNode* node)
-    : tree_source_(tree_source), node_ptr_(node) {
-  DCHECK(tree_source_);
-  DCHECK(node_ptr_);
-}
-
-int32_t FlutterSemanticsNodeWrapper::GetId() const {
-  return node_ptr_->node_id();
-}
-
-const gfx::Rect FlutterSemanticsNodeWrapper::GetBounds() const {
-  if (node_ptr_->has_bounds_in_screen()) {
-    return gfx::Rect(node_ptr_->bounds_in_screen().left(),
-                     node_ptr_->bounds_in_screen().top(),
-                     node_ptr_->bounds_in_screen().right() -
-                         node_ptr_->bounds_in_screen().left(),
-                     node_ptr_->bounds_in_screen().bottom() -
-                         node_ptr_->bounds_in_screen().top());
-  }
-  return gfx::Rect(0, 0, 0, 0);
-}
-
-bool FlutterSemanticsNodeWrapper::IsVisibleToUser() const {
-  if (node_ptr_->has_boolean_properties()) {
-    const BooleanProperties& boolean_properties =
-        node_ptr_->boolean_properties();
-    return !boolean_properties.is_hidden();
-  }
-  return true;
-}
-
-bool FlutterSemanticsNodeWrapper::IsFocused() const {
-  if (node_ptr_->has_boolean_properties()) {
-    const BooleanProperties& boolean_properties =
-        node_ptr_->boolean_properties();
-    return boolean_properties.is_focused();
-  }
-  return false;
-}
-
-bool FlutterSemanticsNodeWrapper::IsLiveRegion() const {
-  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
-  return boolean_properties.is_live_region();
-}
-
-bool FlutterSemanticsNodeWrapper::HasScopesRoute() const {
-  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
-  return boolean_properties.scopes_route();
-}
-
-bool FlutterSemanticsNodeWrapper::HasNamesRoute() const {
-  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
-  return boolean_properties.names_route();
-}
-
-bool FlutterSemanticsNodeWrapper::IsKeyboardNode() const {
-  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
-  return boolean_properties.is_lift_to_type();
-}
-
-bool FlutterSemanticsNodeWrapper::CanBeAccessibilityFocused() const {
-  // In Chrome, this means:
-  // a node with a non-generic role and:
-  // actionable nodes or top level scrollables with a name
-  ui::AXNodeData data;
-  PopulateAXRole(&data);
-  bool non_generic_role = data.role != ax::mojom::Role::kGenericContainer &&
-                          data.role != ax::mojom::Role::kGroup;
-  bool actionable = node_ptr_->action_properties().tap() ||
-                    node_ptr_->action_properties().long_press();
-  bool top_level_scrollable =
-      HasLabelHint() && (node_ptr_->action_properties().scroll_up() ||
-                         node_ptr_->action_properties().scroll_down() ||
-                         node_ptr_->action_properties().scroll_left() ||
-                         node_ptr_->action_properties().scroll_right());
-  return non_generic_role && (actionable || top_level_scrollable);
-}
-
-void FlutterSemanticsNodeWrapper::PopulateAXRole(
-    ui::AXNodeData* out_data) const {
-  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
-  const ActionProperties& action_properties = node_ptr_->action_properties();
-
-  if (boolean_properties.is_text_field()) {
-    out_data->role = ax::mojom::Role::kTextField;
-    return;
-  }
-
-  if (boolean_properties.is_header()) {
-    out_data->role = ax::mojom::Role::kHeading;
-    return;
-  }
-
-  // b/148808637: Flutter allows buttons to be containers but ChromeVox
-  // expects buttons to be atomic.  If we allow this node to be marked a
-  // button and it contains other clickable nodes, none of those nodes will
-  // be focusable by the user. This means no button that is also a
-  // container of other actionable items will ever be read as 'button'
-  // by the screen reader.  However, buttons that have no actionable
-  // descendants will still say 'Button' as expected.
-  if (boolean_properties.is_button() && !AnyChildIsActionable() &&
-      HasLabelHint() && GetLabelHint().length() > 0) {
-    out_data->role = ax::mojom::Role::kButton;
-    return;
-  }
-
-  if (boolean_properties.is_image() &&
-      node_ptr_->child_node_ids().size() == 0) {
-    out_data->role = ax::mojom::Role::kImage;
-    return;
-  }
-
-  if (action_properties.increase() || action_properties.decrease()) {
-    out_data->role = ax::mojom::Role::kSlider;
-    return;
-  }
-
-  bool has_checked_state = boolean_properties.has_checked_state();
-  bool has_toggled_state = boolean_properties.has_toggled_state();
-
-  if (has_checked_state) {
-    if (boolean_properties.is_in_mutually_exclusive_group()) {
-      out_data->role = ax::mojom::Role::kRadioButton;
-    } else {
-      out_data->role = ax::mojom::Role::kCheckBox;
-    }
-    return;
-  }
-  if (has_toggled_state) {
-    out_data->role = ax::mojom::Role::kSwitch;
-    return;
-  }
-
-  // b/149934151 : Flutter sends us nodes with labels that
-  // have children. Don't mark these as static text or
-  // no children will ever be focused properly via swipe
-  // navigation. Only nodes that have labels with no children
-  // should get the static text role. Use kHeader role
-  // instead as it is allowed to be a container.
-  if (HasLabelHint() && GetLabelHint().length() > 0) {
-    if (node_ptr_->child_node_ids().size() == 0) {
-      if (HasTapOrPress()) {
-        out_data->role = ax::mojom::Role::kButton;
-      } else {
-        out_data->role = ax::mojom::Role::kStaticText;
-      }
-    } else {
-      if (IsListItem()) {
-        out_data->role = ax::mojom::Role::kListBoxOption;
-      } else {
-        out_data->role = ax::mojom::Role::kHeader;
-      }
-    }
-    return;
-  }
-
-  std::vector<FlutterSemanticsNodeWrapper*> actionable_children;
-  GetActionableChildren(&actionable_children);
-  if (node_ptr_->scroll_children() > 0 && actionable_children.size() > 0) {
-    out_data->role = ax::mojom::Role::kList;
-    return;
-  }
-
-  out_data->role = ax::mojom::Role::kGenericContainer;
-}
-
-FlutterSemanticsNodeWrapper* FlutterSemanticsNodeWrapper::IsListItem() const {
-  // To consider it a list item, the node has to have a ancestor that has scroll
-  // children.
-  std::vector<FlutterSemanticsNodeWrapper*> ancestors;
-  FlutterSemanticsNodeWrapper* node = static_cast<FlutterSemanticsNodeWrapper*>(
-      tree_source_->GetFromId(GetId()));
-
-  while (node) {
-    FlutterSemanticsNodeWrapper* parent =
-        static_cast<FlutterSemanticsNodeWrapper*>(
-            tree_source_->GetParent(node));
-    if (parent)
-      ancestors.push_back(parent);
-    node = parent;
-  }
-
-  // |ancestors| is with order from closest ancestor to root. Find the closest
-  // ancestor that has scroll children and in between there is no actionable
-  // nodes.
-  for (FlutterSemanticsNodeWrapper* ancestor : ancestors) {
-    if (!ancestor->IsActionable()) {
-      if (ancestor->node()->scroll_children() > 0) {
-        return ancestor;
-      }
-    } else {
-      break;
-    }
-  }
-
-  return nullptr;
-}
-
-void FlutterSemanticsNodeWrapper::GetActionableChildren(
-    std::vector<FlutterSemanticsNodeWrapper*>* out_children) const {
-  std::vector<FlutterSemanticsNode*> children;
-  GetChildren(&children);
-
-  for (FlutterSemanticsNode* child : children) {
-    FlutterSemanticsNodeWrapper* child_wrapper =
-        static_cast<FlutterSemanticsNodeWrapper*>(child);
-
-    if (child_wrapper->HasTapOrPress() ||
-        child_wrapper->AnyChildIsActionable()) {
-      out_children->push_back(child_wrapper);
-    }
-  }
-}
-
-bool FlutterSemanticsNodeWrapper::IsDescendant(
-    FlutterSemanticsNodeWrapper* ancestor) const {
-  FlutterSemanticsNodeWrapper* parent =
-      static_cast<FlutterSemanticsNodeWrapper*>(
-          tree_source_->GetParent(tree_source_->GetFromId(GetId())));
-
-  while (parent) {
-    if (parent == ancestor)
-      return true;
-    parent = static_cast<FlutterSemanticsNodeWrapper*>(
-        tree_source_->GetParent(parent));
-  }
-
-  return false;
-}
-
-bool FlutterSemanticsNodeWrapper::IsRapidChangingSlider() const {
-  const float min = node_ptr_->scroll_extent_min();
-  const float max = node_ptr_->scroll_extent_max();
-  bool has_scroll_extent = IsScrollable() && (min < max);
-  return has_scroll_extent || (node_ptr_->action_properties().increase() ||
-                               node_ptr_->action_properties().decrease());
-}
-
-void FlutterSemanticsNodeWrapper::PopulateAXState(
-    ui::AXNodeData* out_data) const {
-  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
-
-  if (boolean_properties.is_obscured()) {
-    out_data->AddState(ax::mojom::State::kProtected);
-  }
-
-  if (boolean_properties.is_text_field()) {
-    out_data->AddState(ax::mojom::State::kEditable);
-  }
-
-  if (IsFocusable()) {
-    out_data->AddState(ax::mojom::State::kFocusable);
-  }
-
-  if (boolean_properties.has_checked_state()) {
-    out_data->SetCheckedState(boolean_properties.is_checked()
-                                  ? ax::mojom::CheckedState::kTrue
-                                  : ax::mojom::CheckedState::kFalse);
-  }
-
-  if (boolean_properties.has_toggled_state()) {
-    out_data->SetCheckedState(boolean_properties.is_toggled()
-                                  ? ax::mojom::CheckedState::kTrue
-                                  : ax::mojom::CheckedState::kFalse);
-  }
-
-  if (boolean_properties.has_enabled_state() &&
-      !boolean_properties.is_enabled()) {
-    out_data->SetRestriction(ax::mojom::Restriction::kDisabled);
-  }
-}
-
-void FlutterSemanticsNodeWrapper::Serialize(ui::AXNodeData* out_data) const {
-  PopulateAXState(out_data);
-
-  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
-  const ActionProperties& action_properties = node_ptr_->action_properties();
-
-  // b/162311902: For nodes that have scroll extents and can be changed rapidly,
-  // set the name as empty so that ChromeVox will skip speaking them.
-  if (IsRapidChangingSlider()) {
-    out_data->SetName("");
-  } else if (HasLabelHint()) {
-    out_data->SetName(GetLabelHint());
-  } else if (IsActionable()) {
-    // Compute the name by joining all nodes with names.
-    std::vector<std::string> names;
-    ComputeNameFromContents(&names);
-    if (!names.empty())
-      out_data->SetName(base::JoinString(names, " "));
-  }
-
-  if (HasValue()) {
-    out_data->SetValue(GetValue());
-  }
-
-  if (IsActionable()) {
-    out_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kClick);
-  }
-  out_data->AddBoolAttribute(ax::mojom::BoolAttribute::kScrollable,
-                             IsScrollable());
-
-  if (boolean_properties.is_selected()) {
-    out_data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
-  }
-
-  if (node_ptr_->has_hint()) {
-    out_data->AddStringAttribute(ax::mojom::StringAttribute::kPlaceholder,
-                                 node_ptr_->hint());
-  }
-
-  // Set bounds
-  if (tree_source_->GetRoot()->GetId() != -1) {
-    // TODO(rmrossi) Pass in nullptr for now for active window. Root node will
-    // get bounds relative to 0,0 anyway since we are full screen.  This may
-    // change if flutter is ever not full screen in which case we will have
-    // to pass in the bounds of whatever container it resides in.
-    const gfx::Rect& local_bounds = GetRelativeBounds();
-    out_data->relative_bounds.bounds.SetRect(local_bounds.x(), local_bounds.y(),
-                                             local_bounds.width(),
-                                             local_bounds.height());
-  }
-
-  if (node_ptr_->has_text_selection_base()) {
-    out_data->AddIntAttribute(ax::mojom::IntAttribute::kTextSelStart,
-                              node_ptr_->text_selection_base());
-  }
-
-  if (node_ptr_->has_text_selection_extent()) {
-    out_data->AddIntAttribute(ax::mojom::IntAttribute::kTextSelEnd,
-                              node_ptr_->text_selection_extent());
-  }
-
-  if (action_properties.has_scroll_left() ||
-      action_properties.has_scroll_up()) {
-    out_data->AddAction(ax::mojom::Action::kScrollBackward);
-  }
-
-  if (action_properties.has_scroll_right() ||
-      action_properties.has_scroll_down()) {
-    out_data->AddAction(ax::mojom::Action::kScrollForward);
-  }
-
-  if (action_properties.set_selection()) {
-    out_data->AddAction(ax::mojom::Action::kSetSelection);
-  }
-
-  if (action_properties.increase()) {
-    out_data->AddAction(ax::mojom::Action::kIncrement);
-  }
-
-  if (action_properties.decrease()) {
-    out_data->AddAction(ax::mojom::Action::kDecrement);
-  }
-
-  if (IsScrollable()) {
-    const float position = node_ptr_->scroll_position();
-    const float min = node_ptr_->scroll_extent_min();
-    const float max = node_ptr_->scroll_extent_max();
-    if (node_ptr_->action_properties().scroll_up() ||
-        node_ptr_->action_properties().scroll_down()) {
-      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollY, position);
-      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollYMin, min);
-      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollYMax, max);
-    } else if (node_ptr_->action_properties().scroll_left() ||
-               node_ptr_->action_properties().scroll_right()) {
-      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollX, position);
-      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollXMin, min);
-      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollXMax, max);
-    }
-  }
-
-  if (node_ptr_->custom_actions_size() > 0) {
-    std::vector<int32_t> ids;
-    std::vector<std::string> labels;
-    for (int i = 0; i < node_ptr_->custom_actions_size(); i++) {
-      ids.push_back(node_ptr_->custom_actions(i).id());
-      labels.push_back(node_ptr_->custom_actions(i).label());
-    }
-    out_data->AddAction(ax::mojom::Action::kCustomAction);
-    out_data->AddIntListAttribute(ax::mojom::IntListAttribute::kCustomActionIds,
-                                  ids);
-    out_data->AddStringListAttribute(
-        ax::mojom::StringListAttribute::kCustomActionDescriptions, labels);
-  }
-
-  if (node_ptr_->has_plugin_id()) {
-    std::string ax_tree_id = node_ptr_->plugin_id();
-    if (ax_tree_id.rfind("T:", 0) == 0) {
-      // This is a cast web contents id. Find the matching
-      // CastWebContents and find the ax tree id from there.
-      int web_contents_id;
-      base::StringToInt(ax_tree_id.substr(2), &web_contents_id);
-      std::vector<CastWebContents*> all_contents = CastWebContents::GetAll();
-      // There will likely only ever be one active at any time.
-      for (CastWebContents* contents : all_contents) {
-        if (contents->id() == web_contents_id) {
-          auto child_tree_id =
-              contents->web_contents()->GetMainFrame()->GetAXTreeID();
-          if (!child_tree_id.ToString().empty()) {
-            out_data->AddChildTreeId(child_tree_id);
-          }
-          break;
-        }
-      }
-    } else {
-      // Use the value as a tree id.
-      ui::AXTreeID child_ax_tree_id = ui::AXTreeID::FromString(ax_tree_id);
-      out_data->AddChildTreeId(child_ax_tree_id);
-    }
-  }
-
-  if (boolean_properties.is_live_region()) {
-    out_data->AddStringAttribute(
-        ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
-    out_data->AddStringAttribute(
-        ax::mojom::StringAttribute::kContainerLiveRelevant, "text");
-  }
-
-  if (out_data->role == ax::mojom::Role::kListBoxOption) {
-    // Find the ancestor whose role is kList.
-    FlutterSemanticsNodeWrapper* ancestor = IsListItem();
-
-    std::vector<FlutterSemanticsNodeWrapper*> ancestor_actionable_children;
-    ancestor->GetActionableChildren(&ancestor_actionable_children);
-
-    // kSetSize should be the number of actionable children that the scrollable
-    // ancestor has.
-    out_data->AddIntAttribute(ax::mojom::IntAttribute::kSetSize,
-                              ancestor_actionable_children.size());
-
-    // Find which children tree that this node is in.
-    for (size_t i = 0; i < ancestor_actionable_children.size(); ++i) {
-      if (IsDescendant(ancestor_actionable_children[i])) {
-        out_data->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, i + 1);
-        break;
-      }
-    }
-  }
-
-  if (out_data->role == ax::mojom::Role::kList) {
-    // Find the size of actionable children.
-    std::vector<FlutterSemanticsNodeWrapper*> actionable_children;
-    GetActionableChildren(&actionable_children);
-
-    out_data->AddIntAttribute(ax::mojom::IntAttribute::kSetSize,
-                              actionable_children.size());
-  }
-}
-
-void FlutterSemanticsNodeWrapper::GetChildren(
-    std::vector<FlutterSemanticsNode*>* children) const {
-  for (auto id : node_ptr_->child_node_ids()) {
-    FlutterSemanticsNode* node = tree_source_->GetFromId(id);
-    if (node) {
-      children->push_back(tree_source_->GetFromId(id));
-    } else {
-      LOG(ERROR) << "Node id present for which there is no child node given";
-    }
-  }
-}
-
-bool FlutterSemanticsNodeWrapper::AnyChildIsActionable() const {
-  // b/156940104 - If this node is host to a child tree, we
-  // can assume at least one of it's child nodes is actionable.
-  // Otherwise, none of it's descendants will be traversed by
-  // the reader.
-  if (node_ptr_->has_plugin_id()) {
-    return true;
-  }
-  for (auto child_id : node_ptr_->child_node_ids()) {
-    FlutterSemanticsNodeWrapper* child =
-        static_cast<FlutterSemanticsNodeWrapper*>(
-            tree_source_->GetFromId(child_id));
-    if (child->HasTapOrPress()) {
-      return true;
-    }
-    if (child->AnyChildIsActionable()) {
-      return true;
-    }
-  }
-  return false;
-}
-
-bool FlutterSemanticsNodeWrapper::HasTapOrPress() const {
-  return node_ptr_->boolean_properties().is_button() ||
-         node_ptr_->action_properties().tap() ||
-         node_ptr_->action_properties().long_press();
-}
-
-bool FlutterSemanticsNodeWrapper::IsActionable() const {
-  bool actionable = HasTapOrPress();
-
-  // If this node is actionable but is also the host for a child tree,
-  // don't make it actionable or else chromevox won't traverse into
-  // any child.
-  if (node_ptr_->has_plugin_id()) {
-    actionable = false;
-  }
-  return actionable;
-}
-
-bool FlutterSemanticsNodeWrapper::IsScrollable() const {
-  return node_ptr_->action_properties().scroll_up() ||
-         node_ptr_->action_properties().scroll_down() ||
-         node_ptr_->action_properties().scroll_left() ||
-         node_ptr_->action_properties().scroll_right();
-}
-
-bool FlutterSemanticsNodeWrapper::IsFocusable() const {
-  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
-  if (boolean_properties.scopes_route() && !boolean_properties.names_route())
-    return false;
-
-  bool focusable_flags =
-      boolean_properties.has_checked_state() ||
-      boolean_properties.is_checked() || boolean_properties.is_selected() ||
-      HasTapOrPress() || boolean_properties.is_text_field() ||
-      boolean_properties.is_focused() ||
-      boolean_properties.has_enabled_state() ||
-      boolean_properties.is_enabled() ||
-      boolean_properties.is_in_mutually_exclusive_group() ||
-      boolean_properties.is_header() || boolean_properties.is_obscured() ||
-      boolean_properties.names_route() ||
-      (boolean_properties.is_image() &&
-       node_ptr_->child_node_ids().size() == 0) ||
-      boolean_properties.is_live_region() ||
-      boolean_properties.has_toggled_state() || boolean_properties.is_toggled();
-
-  // b/149934151 : If a node has a label but also has children, don't
-  // mark it focusable, otherwise none of its children will be navigable
-  // via swipe nav. It's role wlil be a generic container (see above).
-  return focusable_flags || (HasLabelHint() && !GetLabelHint().empty() &&
-                             node_ptr_->child_node_ids().size() == 0);
-}
-
-bool FlutterSemanticsNodeWrapper::HasLabelHint() const {
-  return node_ptr_->has_label() || node_ptr_->has_hint();
-}
-
-std::string FlutterSemanticsNodeWrapper::GetLabelHint() const {
-  // TODO(rmrossi): Find out whether this order of precedence makes sense
-  if (node_ptr_->has_label() && node_ptr_->label().length() > 0) {
-    return node_ptr_->label();
-  }
-  if (node_ptr_->has_hint() && node_ptr_->hint().length() > 0) {
-    return node_ptr_->hint();
-  }
-  return "";
-}
-
-void FlutterSemanticsNodeWrapper::ComputeNameFromContents(
-    std::vector<std::string>* names) const {
-  DCHECK(names);
-  std::string name;
-  if (HasLabelHint()) {
-    name = GetLabelHint();
-    if (!name.empty()) {
-      names->push_back(name);
-      return;
-    }
-  }
-
-  std::vector<FlutterSemanticsNode*> children;
-  GetChildren(&children);
-  for (const FlutterSemanticsNode* child : children) {
-    child->ComputeNameFromContents(names);
-  }
-}
-
-bool FlutterSemanticsNodeWrapper::HasValue() const {
-  return node_ptr_->has_value();
-}
-
-std::string FlutterSemanticsNodeWrapper::GetValue() const {
-  return node_ptr_->value();
-}
-
-const gfx::Rect FlutterSemanticsNodeWrapper::GetRelativeBounds() const {
-  FlutterSemanticsNode* root_node = tree_source_->GetRoot();
-  DCHECK(root_node);
-
-  gfx::Rect node_bounds = GetBounds();
-
-  // TODO(rmrossi): If embedded flutter is ever not full screen, we will have
-  // to pass in the embedded object tag's screen coordinates to this function
-  // and set the offset of the root node here separately from other nodes.
-  // The bounds of the root node are supposed to be relative to its container
-  // but since we are full screen, we leave them alone.  See
-  // ax_tree_source_arc.cc for an example.
-  if (GetId() != root_node->GetId()) {
-    // Bounds of non-root node is relative to its tree's root.
-    gfx::Rect root_bounds = root_node->GetBounds();
-    node_bounds.Offset(-1 * root_bounds.x(), -1 * root_bounds.y());
-  }
-
-  return node_bounds;
-}
-
-}  // namespace accessibility
-}  // namespace chromecast
diff --git a/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h b/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h
deleted file mode 100644
index cfd51c7f..0000000
--- a/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_WRAPPER_H_
-#define CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_WRAPPER_H_
-
-#include <string>
-#include <vector>
-
-#include "chromecast/browser/accessibility/flutter/flutter_semantics_node.h"
-#include "chromecast/browser/accessibility/proto/cast_server_accessibility.pb.h"
-#include "ui/accessibility/ax_enum_util.h"
-#include "ui/accessibility/ax_tree_source.h"
-
-namespace chromecast {
-namespace accessibility {
-
-using gallium::castos::SemanticsNode;
-
-class AXTreeSourceFlutter;
-
-// A wrapper class for a SemanticsNode proto object.
-// This is used by AXTreeSourceFlutter to create accessibility tree updates
-// from semantics trees sent to us from the flutter process.
-class FlutterSemanticsNodeWrapper : public FlutterSemanticsNode {
- public:
-  FlutterSemanticsNodeWrapper(
-      ui::AXTreeSource<FlutterSemanticsNode*>* tree_source,
-      const SemanticsNode* node);
-  FlutterSemanticsNodeWrapper(const FlutterSemanticsNodeWrapper&) = delete;
-  FlutterSemanticsNodeWrapper& operator=(const FlutterSemanticsNodeWrapper&) =
-      delete;
-
-  // FlutterSemanticsNode implementation:
-  int32_t GetId() const override;
-  const gfx::Rect GetBounds() const override;
-  bool IsVisibleToUser() const override;
-  bool IsFocused() const override;
-  bool IsLiveRegion() const override;
-  bool HasScopesRoute() const override;
-  bool HasNamesRoute() const override;
-  bool IsRapidChangingSlider() const override;
-  bool CanBeAccessibilityFocused() const override;
-  void PopulateAXRole(ui::AXNodeData* out_data) const override;
-  void PopulateAXState(ui::AXNodeData* out_data) const override;
-  void Serialize(ui::AXNodeData* out_data) const override;
-  void GetChildren(std::vector<FlutterSemanticsNode*>* children) const override;
-  bool HasLabelHint() const override;
-  std::string GetLabelHint() const override;
-  bool HasValue() const override;
-  std::string GetValue() const override;
-  bool IsKeyboardNode() const override;
-
-  const SemanticsNode* node() { return node_ptr_; }
-
- private:
-  bool AnyChildIsActionable() const;
-  bool HasTapOrPress() const;
-  bool IsActionable() const;
-  bool IsScrollable() const;
-  bool IsFocusable() const;
-  void ComputeNameFromContents(std::vector<std::string>* names) const override;
-  void GetActionableChildren(
-      std::vector<FlutterSemanticsNodeWrapper*>* out_children) const;
-  // Check if this is a list item and return the node of its ancestor whose role
-  // is kList
-  FlutterSemanticsNodeWrapper* IsListItem() const;
-  bool IsDescendant(FlutterSemanticsNodeWrapper* ancestor) const;
-
-  // Returns bounds of a node which can be passed to AXNodeData.location. Bounds
-  // are returned in the following coordinates depending on whether it's root or
-  // not.
-  // - Root node is relative to its container.
-  // - Non-root node is relative to the root node of this tree.
-  const gfx::Rect GetRelativeBounds() const;
-
-  ui::AXTreeSource<FlutterSemanticsNode*>* const tree_source_;
-  const SemanticsNode* const node_ptr_;
-};
-
-}  // namespace accessibility
-}  // namespace chromecast
-
-#endif  // CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_WRAPPER_H_
diff --git a/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper_unittest.cc b/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper_unittest.cc
deleted file mode 100644
index e931f52..0000000
--- a/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper_unittest.cc
+++ /dev/null
@@ -1,524 +0,0 @@
-// Copyright 2021 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 "chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h"
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/accessibility/ax_enums.mojom.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/accessibility/ax_tree_data.h"
-#include "ui/accessibility/ax_tree_source.h"
-
-using chromecast::accessibility::FlutterSemanticsNode;
-using gallium::castos::BooleanProperties;
-using ::gallium::castos::Rect;
-using ::testing::_;
-using ::testing::Contains;
-using ::testing::Not;
-using ::testing::Return;
-using ::testing::StrictMock;
-
-namespace ui {
-
-class MockAXTreeSource : public AXTreeSource<FlutterSemanticsNode*> {
- public:
-  MOCK_METHOD(bool, GetTreeData, (AXTreeData * data), (const, override));
-  MOCK_METHOD(FlutterSemanticsNode*, GetRoot, (), (const, override));
-  MOCK_METHOD(FlutterSemanticsNode*,
-              GetFromId,
-              (int32_t id),
-              (const, override));
-  MOCK_METHOD(int32_t, GetId, (FlutterSemanticsNode * node), (const, override));
-  MOCK_METHOD(void,
-              GetChildren,
-              (FlutterSemanticsNode * node,
-               std::vector<FlutterSemanticsNode*>* out_children),
-              (const, override));
-  MOCK_METHOD(FlutterSemanticsNode*,
-              GetParent,
-              (FlutterSemanticsNode * node),
-              (const, override));
-  MOCK_METHOD(bool, IsValid, (FlutterSemanticsNode * node), (const, override));
-  MOCK_METHOD(bool,
-              IsIgnored,
-              (FlutterSemanticsNode * node),
-              (const, override));
-  MOCK_METHOD(bool,
-              IsEqual,
-              (FlutterSemanticsNode * node1, FlutterSemanticsNode* node2),
-              (const, override));
-  MOCK_METHOD(FlutterSemanticsNode*, GetNull, (), (const, override));
-  MOCK_METHOD(void,
-              SerializeNode,
-              (FlutterSemanticsNode * node, AXNodeData* out_data),
-              (const, override));
-  MOCK_METHOD(std::string,
-              GetDebugString,
-              (FlutterSemanticsNode * node),
-              (const, override));
-  MOCK_METHOD(void, SerializerClearedNode, (int32_t node_id), (override));
-};
-
-}  // namespace ui
-
-namespace chromecast {
-namespace accessibility {
-
-class FlutterSemanticsNodeWrapperTest : public testing::Test {
- public:
-  FlutterSemanticsNodeWrapperTest() = default;
-  FlutterSemanticsNodeWrapperTest(const FlutterSemanticsNodeWrapperTest&) =
-      delete;
-  ~FlutterSemanticsNodeWrapperTest() override {}
-  FlutterSemanticsNodeWrapperTest& operator=(
-      const FlutterSemanticsNodeWrapperTest&) = delete;
-
- protected:
-  void SetUp() override { Reset(); }
-
-  SemanticsNode* CreateNewSemanticsNode(int32_t node_id = kNodeId) {
-    SemanticsNode* node = event_.add_node_data();
-    node->set_node_id(node_id);
-    return node;
-  }
-
-  SemanticsNode* CreateNewRootChildSemanticsNode(int32_t child_node_id = 1) {
-    SemanticsNode* child_semantics_node;
-    FlutterSemanticsNodeWrapper* child_node;
-    CreateChildSemanticsNode(semantics_node_, node_.get(), child_semantics_node,
-                             child_node, child_node_id);
-    return child_semantics_node;
-  }
-
-  void CreateChildSemanticsNode(SemanticsNode* parent_semantics_node,
-                                FlutterSemanticsNodeWrapper* parent_node,
-                                SemanticsNode*& child_semantics_node,
-                                FlutterSemanticsNodeWrapper*& child_node,
-                                int32_t child_node_id,
-                                const std::string& node_name = {}) {
-    child_semantics_node = CreateNewSemanticsNode(child_node_id);
-    if (!node_name.empty()) {
-      child_semantics_node->set_label(node_name);
-    }
-    parent_semantics_node->add_child_node_ids(child_node_id);
-    other_nodes_[child_node_id] = std::make_unique<FlutterSemanticsNodeWrapper>(
-        &ax_tree_source_, child_semantics_node);
-    child_node = other_nodes_[child_node_id].get();
-
-    EXPECT_CALL(ax_tree_source_, GetFromId(child_node_id))
-        .WillRepeatedly(Return(other_nodes_[child_node_id].get()));
-    EXPECT_CALL(ax_tree_source_, GetParent(other_nodes_[child_node_id].get()))
-        .WillRepeatedly(Return(parent_node));
-  }
-
-  void Reset() {
-    event_.Clear();
-    other_nodes_.clear();
-    semantics_node_ = CreateNewSemanticsNode();
-    node_ = std::make_unique<FlutterSemanticsNodeWrapper>(&ax_tree_source_,
-                                                          semantics_node_);
-    ax_node_data_ = ui::AXNodeData();
-    testing::Mock::VerifyAndClearExpectations(&ax_tree_source_);
-    EXPECT_CALL(ax_tree_source_, GetFromId(kNodeId))
-        .WillRepeatedly(Return(node_.get()));
-    EXPECT_CALL(ax_tree_source_, GetParent(node_.get()))
-        .WillRepeatedly(Return(nullptr));
-    EXPECT_CALL(ax_tree_source_, GetRoot()).WillRepeatedly(Return(node_.get()));
-  }
-
-  ui::MockAXTreeSource ax_tree_source_;
-  SemanticsNode* semantics_node_;
-  static const int32_t kNodeId = 0;
-  std::unique_ptr<FlutterSemanticsNodeWrapper> node_;
-  std::unordered_map<int, std::unique_ptr<FlutterSemanticsNodeWrapper>>
-      other_nodes_;
-  ui::AXNodeData ax_node_data_;
-
- private:
-  gallium::castos::OnAccessibilityEventRequest event_;
-};
-
-TEST_F(FlutterSemanticsNodeWrapperTest, GetId) {
-  semantics_node_->set_node_id(1);
-  EXPECT_EQ(node_->GetId(), 1);
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, GetBounds) {
-  EXPECT_EQ(node_->GetBounds(), gfx::Rect(0, 0, 0, 0));
-
-  Rect* bounds = semantics_node_->mutable_bounds_in_screen();
-  bounds->set_left(100);
-  bounds->set_top(200);
-  bounds->set_right(300);
-  bounds->set_bottom(400);
-  EXPECT_EQ(node_->GetBounds(), gfx::Rect(100, 200, 200, 200));
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, IsVisibleToUser) {
-  EXPECT_EQ(node_->IsVisibleToUser(), true);
-  semantics_node_->mutable_boolean_properties()->set_is_hidden(true);
-  EXPECT_EQ(node_->IsVisibleToUser(), false);
-
-  Reset();
-  semantics_node_->mutable_boolean_properties()->set_is_hidden(false);
-  EXPECT_EQ(node_->IsVisibleToUser(), true);
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, IsFocused) {
-  EXPECT_EQ(node_->IsFocused(), false);
-  semantics_node_->mutable_boolean_properties()->set_is_focused(true);
-  EXPECT_EQ(node_->IsFocused(), true);
-
-  Reset();
-  semantics_node_->mutable_boolean_properties()->set_is_focused(false);
-  EXPECT_EQ(node_->IsFocused(), false);
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, IsLiveRegion) {
-  EXPECT_EQ(node_->IsLiveRegion(), false);
-  semantics_node_->mutable_boolean_properties()->set_is_live_region(true);
-  EXPECT_EQ(node_->IsLiveRegion(), true);
-
-  Reset();
-  semantics_node_->mutable_boolean_properties()->set_is_live_region(false);
-  EXPECT_EQ(node_->IsLiveRegion(), false);
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, HasScopesRoute) {
-  EXPECT_EQ(node_->HasScopesRoute(), false);
-  semantics_node_->mutable_boolean_properties()->set_scopes_route(true);
-  EXPECT_EQ(node_->HasScopesRoute(), true);
-
-  Reset();
-  semantics_node_->mutable_boolean_properties()->set_scopes_route(false);
-  EXPECT_EQ(node_->HasScopesRoute(), false);
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, HasNamesRoute) {
-  EXPECT_EQ(node_->HasNamesRoute(), false);
-  semantics_node_->mutable_boolean_properties()->set_names_route(true);
-  EXPECT_EQ(node_->HasNamesRoute(), true);
-
-  Reset();
-  semantics_node_->mutable_boolean_properties()->set_names_route(false);
-  EXPECT_EQ(node_->HasNamesRoute(), false);
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, IsRapidChangingSlider) {
-  EXPECT_EQ(node_->IsRapidChangingSlider(), false);
-
-  semantics_node_->mutable_action_properties()->set_scroll_up(true);
-  semantics_node_->set_scroll_extent_min(0);
-  semantics_node_->set_scroll_extent_max(10);
-  EXPECT_EQ(node_->IsRapidChangingSlider(), true);
-
-  Reset();
-  semantics_node_->mutable_action_properties()->set_scroll_down(true);
-  semantics_node_->set_scroll_extent_min(0);
-  semantics_node_->set_scroll_extent_max(10);
-  EXPECT_EQ(node_->IsRapidChangingSlider(), true);
-
-  Reset();
-  semantics_node_->mutable_action_properties()->set_scroll_left(true);
-  semantics_node_->set_scroll_extent_min(0);
-  semantics_node_->set_scroll_extent_max(10);
-  EXPECT_EQ(node_->IsRapidChangingSlider(), true);
-
-  Reset();
-  semantics_node_->mutable_action_properties()->set_scroll_right(true);
-  semantics_node_->set_scroll_extent_min(0);
-  semantics_node_->set_scroll_extent_max(10);
-  EXPECT_EQ(node_->IsRapidChangingSlider(), true);
-
-  Reset();
-  semantics_node_->mutable_action_properties()->set_scroll_down(true);
-  semantics_node_->set_scroll_extent_min(10);
-  semantics_node_->set_scroll_extent_max(10);
-  // scroll_extent_min is not less than scroll_extent_max
-  EXPECT_EQ(node_->IsRapidChangingSlider(), false);
-
-  Reset();
-  semantics_node_->mutable_action_properties()->set_increase(true);
-  EXPECT_EQ(node_->IsRapidChangingSlider(), true);
-
-  Reset();
-  semantics_node_->mutable_action_properties()->set_decrease(true);
-  EXPECT_EQ(node_->IsRapidChangingSlider(), true);
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, LabelHintAndValue) {
-  EXPECT_EQ(node_->HasLabelHint(), false);
-  EXPECT_EQ(node_->GetLabelHint(), "");
-  EXPECT_EQ(node_->HasValue(), false);
-  EXPECT_EQ(node_->GetValue(), "");
-
-  const std::string name = "dummy";
-  semantics_node_->set_label(name);
-  EXPECT_EQ(node_->HasLabelHint(), true);
-  EXPECT_EQ(node_->GetLabelHint(), name);
-
-  Reset();
-  semantics_node_->set_hint(name);
-  EXPECT_EQ(node_->HasLabelHint(), true);
-  EXPECT_EQ(node_->GetLabelHint(), name);
-
-  Reset();
-  semantics_node_->set_value(name);
-  EXPECT_EQ(node_->HasValue(), true);
-  EXPECT_EQ(node_->GetValue(), name);
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, CanBeAccessibilityFocused) {
-  // A node with a non-generic role and:
-  // actionable nodes or top level scrollables with a name.
-  EXPECT_EQ(node_->CanBeAccessibilityFocused(), false);
-
-  // Not a generic container.
-  semantics_node_->mutable_boolean_properties()->set_is_image(true);
-  // Actionable.
-  semantics_node_->mutable_action_properties()->set_tap(true);
-  EXPECT_EQ(node_->CanBeAccessibilityFocused(), true);
-
-  Reset();
-  // Not a generic container.
-  semantics_node_->mutable_boolean_properties()->set_is_image(true);
-  // scrollable.
-  semantics_node_->mutable_action_properties()->set_scroll_up(true);
-  EXPECT_EQ(node_->CanBeAccessibilityFocused(), false);
-  // Set a name.
-  semantics_node_->set_label("dummy");
-  EXPECT_EQ(node_->CanBeAccessibilityFocused(), true);
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, GetChildren) {
-  // For following structure:
-  //     0
-  //    / \
-  //   1   2
-  //  /
-  // 3
-  // GetChildren() of node 0 should returns node 1 and 2.
-  SemanticsNode *child_semantics_node1, *child_semantics_node2,
-      *child_semantics_node3;
-  FlutterSemanticsNodeWrapper *child_node1, *child_node2, *child_node3;
-
-  CreateChildSemanticsNode(semantics_node_, node_.get(), child_semantics_node1,
-                           child_node1, 1, "node1");
-  CreateChildSemanticsNode(semantics_node_, node_.get(), child_semantics_node2,
-                           child_node2, 2, "node2");
-  CreateChildSemanticsNode(child_semantics_node1, child_node1,
-                           child_semantics_node3, child_node3, 3, "node3");
-
-  std::vector<FlutterSemanticsNode*> children1;
-  node_->GetChildren(&children1);
-  EXPECT_THAT(children1, Contains(child_node1));
-  EXPECT_THAT(children1, Contains(child_node2));
-  EXPECT_THAT(children1, Not(Contains(child_node3)));
-  EXPECT_THAT(children1, Not(Contains(node_.get())));
-
-  std::vector<FlutterSemanticsNode*> children2;
-  child_node1->GetChildren(&children2);
-  EXPECT_THAT(children2, Contains(child_node3));
-  EXPECT_THAT(children2, Not(Contains(child_node1)));
-  EXPECT_THAT(children2, Not(Contains(child_node2)));
-  EXPECT_THAT(children2, Not(Contains(node_.get())));
-
-  std::vector<FlutterSemanticsNode*> children3;
-  child_node2->GetChildren(&children3);
-  EXPECT_EQ(children3.empty(), true);
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, PopulateAXRole) {
-  {
-    semantics_node_->mutable_boolean_properties()->set_is_text_field(true);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kTextField);
-  }
-
-  {
-    Reset();
-    semantics_node_->mutable_boolean_properties()->set_is_header(true);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kHeading);
-  }
-
-  {
-    Reset();
-    semantics_node_->mutable_boolean_properties()->set_is_image(true);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kImage);
-
-    // Node with children should not be marked as image.
-    CreateNewRootChildSemanticsNode();
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_NE(ax_node_data_.role, ax::mojom::Role::kImage);
-  }
-
-  {
-    Reset();
-    semantics_node_->mutable_action_properties()->set_increase(1);
-    semantics_node_->mutable_action_properties()->set_decrease(1);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kSlider);
-  }
-
-  {
-    // Nodes to be considered buttons:
-    // 1. Have labels, have taps and no children.
-    Reset();
-    semantics_node_->mutable_action_properties()->set_tap(true);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_NE(ax_node_data_.role, ax::mojom::Role::kButton);
-    semantics_node_->set_label("dummy");
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kButton);
-
-    CreateNewRootChildSemanticsNode();
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_NE(ax_node_data_.role, ax::mojom::Role::kButton);
-
-    // 2. Have labels, is_button == true and no actionable children.
-    Reset();
-    semantics_node_->mutable_boolean_properties()->set_is_button(true);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_NE(ax_node_data_.role, ax::mojom::Role::kButton);
-    semantics_node_->set_label("dummy");
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kButton);
-
-    // Create child node.
-    SemanticsNode* child_semantics_node = CreateNewRootChildSemanticsNode();
-
-    // child node is not actionable.
-    child_semantics_node->mutable_action_properties()->set_tap(false);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kButton);
-
-    // child node is actionable.
-    child_semantics_node->mutable_action_properties()->set_tap(true);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_NE(ax_node_data_.role, ax::mojom::Role::kButton);
-  }
-
-  {
-    Reset();
-    semantics_node_->mutable_boolean_properties()
-        ->set_is_in_mutually_exclusive_group(true);
-    semantics_node_->mutable_boolean_properties()->set_has_checked_state(true);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kRadioButton);
-
-    semantics_node_->mutable_boolean_properties()
-        ->set_is_in_mutually_exclusive_group(false);
-    semantics_node_->mutable_boolean_properties()->set_has_checked_state(true);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kCheckBox);
-  }
-
-  {
-    Reset();
-    semantics_node_->mutable_boolean_properties()->set_has_toggled_state(true);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kSwitch);
-  }
-
-  {
-    Reset();
-    semantics_node_->set_label("dummy");
-    semantics_node_->mutable_action_properties()->set_tap(false);
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kStaticText);
-    // kStaticText should not contain children.
-    CreateNewRootChildSemanticsNode();
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_NE(ax_node_data_.role, ax::mojom::Role::kStaticText);
-  }
-
-  {
-    Reset();
-    semantics_node_->set_label("dummy");
-    CreateNewRootChildSemanticsNode();
-    node_->PopulateAXRole(&ax_node_data_);
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kHeader);
-  }
-
-  {
-    // For following structure:
-    //     0
-    //    / \
-    //   1   2
-    //  /     \
-    // 3       4
-    // If node 0 has scroll_children, node 1 and 2 are not actionable, one of
-    // node 3 is 4 are actionable.
-    // then node0 is consider a kList, node2 and node3 are consider
-    // kListBoxOption.
-    Reset();
-
-    SemanticsNode *child_semantics_node1, *child_semantics_node2,
-        *child_semantics_node3, *child_semantics_node4;
-    FlutterSemanticsNodeWrapper *child_node1, *child_node2, *child_node3,
-        *child_node4;
-    ui::AXNodeData node_data1, node_data2, node_data3, node_data4;
-
-    CreateChildSemanticsNode(semantics_node_, node_.get(),
-                             child_semantics_node1, child_node1, 1, "node1");
-    CreateChildSemanticsNode(semantics_node_, node_.get(),
-                             child_semantics_node2, child_node2, 2, "node2");
-    CreateChildSemanticsNode(child_semantics_node1, child_node1,
-                             child_semantics_node3, child_node3, 3, "node3");
-    CreateChildSemanticsNode(child_semantics_node2, child_node2,
-                             child_semantics_node4, child_node4, 4, "node4");
-
-    semantics_node_->set_scroll_children(2);
-    child_semantics_node1->mutable_action_properties()->set_tap(false);
-    child_semantics_node2->mutable_action_properties()->set_tap(false);
-    child_semantics_node3->mutable_action_properties()->set_tap(true);
-    child_semantics_node4->mutable_action_properties()->set_tap(false);
-    node_->PopulateAXRole(&ax_node_data_);
-    child_node1->PopulateAXRole(&node_data1);
-    child_node2->PopulateAXRole(&node_data2);
-    child_node3->PopulateAXRole(&node_data3);
-    child_node4->PopulateAXRole(&node_data4);
-
-    EXPECT_EQ(ax_node_data_.role, ax::mojom::Role::kList);
-    EXPECT_EQ(node_data1.role, ax::mojom::Role::kListBoxOption);
-    EXPECT_EQ(node_data2.role, ax::mojom::Role::kListBoxOption);
-    EXPECT_NE(node_data3.role, ax::mojom::Role::kListBoxOption);
-    EXPECT_NE(node_data4.role, ax::mojom::Role::kListBoxOption);
-  }
-}
-
-TEST_F(FlutterSemanticsNodeWrapperTest, DisabledNode) {
-  BooleanProperties* boolean_properties =
-      semantics_node_->mutable_boolean_properties();
-
-  // Test has_enabled_state = false, is_enabled = false
-  boolean_properties->set_has_enabled_state(false);
-  boolean_properties->set_is_enabled(false);
-  node_->PopulateAXState(&ax_node_data_);
-  EXPECT_EQ(ax_node_data_.GetRestriction(), ax::mojom::Restriction::kNone);
-
-  // Test has_enabled_state = false, is_enabled = true
-  boolean_properties->set_has_enabled_state(false);
-  boolean_properties->set_is_enabled(true);
-  node_->PopulateAXState(&ax_node_data_);
-  EXPECT_EQ(ax_node_data_.GetRestriction(), ax::mojom::Restriction::kNone);
-
-  // Test has_enabled_state = true, is_enabled = true
-  boolean_properties->set_has_enabled_state(true);
-  boolean_properties->set_is_enabled(true);
-  node_->PopulateAXState(&ax_node_data_);
-  EXPECT_EQ(ax_node_data_.GetRestriction(), ax::mojom::Restriction::kNone);
-
-  // Test has_enabled_state = true, is_enabled = false
-  boolean_properties->set_has_enabled_state(true);
-  boolean_properties->set_is_enabled(false);
-  node_->PopulateAXState(&ax_node_data_);
-  EXPECT_EQ(ax_node_data_.GetRestriction(), ax::mojom::Restriction::kDisabled);
-}
-
-}  // namespace accessibility
-}  // namespace chromecast
diff --git a/chromecast/browser/webui/cast_webui.cc b/chromecast/browser/webui/cast_webui.cc
index 1a4d7e6..fcd22fb 100644
--- a/chromecast/browser/webui/cast_webui.cc
+++ b/chromecast/browser/webui/cast_webui.cc
@@ -52,18 +52,18 @@
 CastWebUI::~CastWebUI() {}
 
 void CastWebUI::InvokeCallback(const std::string& message,
-                               const base::ListValue* args) {
+                               const base::Value::List& args) {
   if (message_callbacks_.count(message) == 0) {
     return;
   }
-  message_callbacks_[message]->OnMessage(args->Clone());
+  message_callbacks_[message]->OnMessage(args.Clone());
 }
 
 void CastWebUI::RegisterMessageCallback(
     const std::string& message,
     mojo::PendingRemote<mojom::MessageCallback> callback) {
   message_callbacks_.emplace(message, std::move(callback));
-  web_ui()->RegisterDeprecatedMessageCallback(
+  web_ui()->RegisterMessageCallback(
       message,
       base::BindRepeating(&CastWebUI::InvokeCallback, weak_this_, message));
 }
diff --git a/chromecast/browser/webui/cast_webui.h b/chromecast/browser/webui/cast_webui.h
index cdc8fd6a..5cbbb30 100644
--- a/chromecast/browser/webui/cast_webui.h
+++ b/chromecast/browser/webui/cast_webui.h
@@ -11,6 +11,7 @@
 
 #include "base/containers/flat_map.h"
 #include "base/memory/weak_ptr.h"
+#include "base/values.h"
 #include "chromecast/browser/webui/mojom/webui.mojom.h"
 #include "chromecast/chromecast_buildflags.h"
 #include "content/public/browser/web_ui_controller.h"
@@ -45,7 +46,8 @@
  private:
   void AddWebviewSupport();
   void OnWebUIReady(const base::ListValue* args);
-  void InvokeCallback(const std::string& message, const base::ListValue* args);
+  void InvokeCallback(const std::string& message,
+                      const base::Value::List& args);
 
   // mojom::WebUI implementation:
   void RegisterMessageCallback(
diff --git a/chromecast/browser/webui/mojom/webui.mojom b/chromecast/browser/webui/mojom/webui.mojom
index 05a6c35..d6f47f6 100644
--- a/chromecast/browser/webui/mojom/webui.mojom
+++ b/chromecast/browser/webui/mojom/webui.mojom
@@ -18,7 +18,7 @@
 // Wraps a repeating callback which is invoked by the Web UI messenger.
 interface MessageCallback {
   // Receive a message with generic parameters.
-  OnMessage(mojo_base.mojom.DeprecatedListValue list);
+  OnMessage(mojo_base.mojom.ListValue list);
 };
 
 // Use this interface to control the Web UI. This interface is hosted in the
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index c957c3ac..f1b7e71 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -2665,14 +2665,14 @@
       <message name="IDS_SHIMLESS_RMA_COMPONENT_VPD_CACHE" translateable="false" desc="Name of device Vital Product Data SPI flash storage component.">
         Vpd Cached
       </message>
-      <message name="IDS_SHIMLESS_RMA_COMPONENT_NETWORK" translateable="false" desc="Name of device network component. TODO(gavindodd) clarify this.">
+      <message name="IDS_SHIMLESS_RMA_COMPONENT_NETWORK" translateable="false" desc="Name of device network component.">
         Network
       </message>
       <message name="IDS_SHIMLESS_RMA_COMPONENT_CAMERA" translateable="false" desc="Name of device camera component.">
         Camera
       </message>
-      <message name="IDS_SHIMLESS_RMA_COMPONENT_STYLUS" translateable="false" desc="Name of device stylus component. TODO(gavindodd) clarify this.">
-        Stylus
+      <message name="IDS_SHIMLESS_RMA_COMPONENT_STYLUS" translateable="false" desc="Name of device stylus support component.">
+        Stylus support
       </message>
       <message name="IDS_SHIMLESS_RMA_COMPONENT_TOUCHPAD" translateable="false" desc="Name of device touchpad component.">
         Touchpad
@@ -2683,7 +2683,7 @@
       <message name="IDS_SHIMLESS_RMA_COMPONENT_MEMORY" translateable="false" desc="Name of device memory components.">
         Memory
       </message>
-      <message name="IDS_SHIMLESS_RMA_COMPONENT_DISPLAY_PANEL" translateable="false" desc="Name of device display panel component. TODO(gavindodd) clarify this.">
+      <message name="IDS_SHIMLESS_RMA_COMPONENT_DISPLAY_PANEL" translateable="false" desc="Name of device display panel component.">
         Display
       </message>
       <message name="IDS_SHIMLESS_RMA_COMPONENT_CELLULAR" translateable="false" desc="Name of device cellular network component. Used for wireless internet service through a service provider such as Google Fi.">
@@ -2707,7 +2707,7 @@
       <message name="IDS_SHIMLESS_RMA_COMPONENT_LID_GYROSCOPE" translateable="false" desc="Name of device component in the lid (e.g. screen) of the component.">
         Lid Gyroscope
       </message>
-      <message name="IDS_SHIMLESS_RMA_COMPONENT_SCREEN" translateable="false" desc="Name of device screen component. TODO(gavindodd) clarify this.">
+      <message name="IDS_SHIMLESS_RMA_COMPONENT_SCREEN" translateable="false" desc="Name of device screen component.">
         Screen
       </message>
       <message name="IDS_SHIMLESS_RMA_COMPONENT_KEYBOARD" translateable="false" desc="Name of device keyboard component.">
@@ -2748,6 +2748,19 @@
       <message name="IDS_SHIMLESS_RMA_TRY_AGAIN_BUTTON" desc="Default text for Try Again button used to retry an action.">
         Try again
       </message>
+      <!-- Exit dialog -->
+      <message name="IDS_SHIMLESS_RMA_EXIT_DIALOG_TITLE" translateable="false" desc="Title for the exit dialog.">
+        Exit repair?
+      </message>
+      <message name="IDS_SHIMLESS_RMA_EXIT_DIALOG_DESCRIPTION" translateable="false" desc="Detailed description for the exit dialog.">
+        Are you sure you want to exit?
+      </message>
+      <message name="IDS_SHIMLESS_RMA_EXIT_DIALOG_CANCEL_BUTTON_LABEL" translateable="false" desc="Button used to close the exit dialog.">
+        Cancel
+      </message>
+      <message name="IDS_SHIMLESS_RMA_EXIT_DIALOG_CONFIRM_BUTTON_LABEL" translateable="false" desc="Button used to confirm exiting the RMA process and close the exit dialog.">
+        Confirm
+      </message>
       <!-- Landing page -->
       <message name="IDS_SHIMLESS_RMA_LANDING_PAGE_TITLE" desc="Title for the landing page at the start of RMA.">
         <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> repair
diff --git a/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_CANCEL_BUTTON_LABEL.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_CANCEL_BUTTON_LABEL.png.sha1
new file mode 100644
index 0000000..7c47222
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_CANCEL_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+8bd82a2a085b6135f764bc0323d1b3ffce58ef84
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_CONFIRM_BUTTON_LABEL.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_CONFIRM_BUTTON_LABEL.png.sha1
new file mode 100644
index 0000000..7c47222
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_CONFIRM_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+8bd82a2a085b6135f764bc0323d1b3ffce58ef84
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_DESCRIPTION.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..7c47222
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+8bd82a2a085b6135f764bc0323d1b3ffce58ef84
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_TITLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_TITLE.png.sha1
new file mode 100644
index 0000000..7c47222
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SHIMLESS_RMA_EXIT_DIALOG_TITLE.png.sha1
@@ -0,0 +1 @@
+8bd82a2a085b6135f764bc0323d1b3ffce58ef84
\ No newline at end of file
diff --git a/chromeos/components/quick_answers/quick_answers_client_unittest.cc b/chromeos/components/quick_answers/quick_answers_client_unittest.cc
index 56dd012..65daa412 100644
--- a/chromeos/components/quick_answers/quick_answers_client_unittest.cc
+++ b/chromeos/components/quick_answers/quick_answers_client_unittest.cc
@@ -131,11 +131,12 @@
     return std::move(mock_intent_generator_);
   }
 
+  base::test::TaskEnvironment task_environment_;
+
   std::unique_ptr<QuickAnswersClient> client_;
   std::unique_ptr<MockQuickAnswersDelegate> mock_delegate_;
   std::unique_ptr<MockResultLoader> mock_result_loader_;
   std::unique_ptr<MockIntentGenerator> mock_intent_generator_;
-  base::test::SingleThreadTaskEnvironment task_environment_;
   network::TestURLLoaderFactory test_url_loader_factory_;
   scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
   QuickAnswersClient::ResultLoaderFactoryCallback
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index 390a6b9..9a29a1dd 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -37,8 +37,7 @@
 
 // Controls whether to always trigger Quick Answers with single word selection.
 const base::Feature kQuickAnswersAlwaysTriggerForSingleWord{
-    "QuickAnswersAlwaysTriggerForSingleWord",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    "QuickAnswersAlwaysTriggerForSingleWord", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables Quick Answers for more locales.
 const base::Feature kQuickAnswersForMoreLocales{
diff --git a/chromeos/ui/base/file_icon_util.cc b/chromeos/ui/base/file_icon_util.cc
index e3fe038..aaf737c1 100644
--- a/chromeos/ui/base/file_icon_util.cc
+++ b/chromeos/ui/base/file_icon_util.cc
@@ -201,7 +201,9 @@
           {".CRX", IconType::kArchive},
           {".GZ", IconType::kArchive},
           {".ISO", IconType::kArchive},
+          {".LZ", IconType::kArchive},
           {".LZMA", IconType::kArchive},
+          {".LZO", IconType::kArchive},
           {".RAR", IconType::kArchive},
           {".TAR", IconType::kArchive},
           {".TAZ", IconType::kArchive},
diff --git a/chromeos/ui/base/file_icon_util_unittest.cc b/chromeos/ui/base/file_icon_util_unittest.cc
index 69a4f6eb..b80f98f 100644
--- a/chromeos/ui/base/file_icon_util_unittest.cc
+++ b/chromeos/ui/base/file_icon_util_unittest.cc
@@ -27,7 +27,9 @@
       {"/my/test/file.crx", IconType::kArchive},
       {"/my/test/file.gz", IconType::kArchive},
       {"/my/test/file.iso", IconType::kArchive},
+      {"/my/test/file.lz", IconType::kArchive},
       {"/my/test/file.lzma", IconType::kArchive},
+      {"/my/test/file.lzo", IconType::kArchive},
       {"/my/test/file.rar", IconType::kArchive},
       {"/my/test/file.tar", IconType::kArchive},
       {"/my/test/file.taz", IconType::kArchive},
diff --git a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
index 2226676..09b605d2 100644
--- a/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
+++ b/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
@@ -216,7 +216,6 @@
   if (!has_logged_suggestion_filled_) {
     Log(FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, form);
   } else if (logged_suggestion_filled_was_masked_server_card_) {
-    DCHECK_NE(current_authentication_flow_, UnmaskAuthFlowType::kNone);
     Log(FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_SUBMITTED_ONCE, form);
 
     // Log BetterAuth.FlowEvents.
diff --git a/components/autofill/core/common/logging/log_buffer.cc b/components/autofill/core/common/logging/log_buffer.cc
index 18037e67..7f2dffb 100644
--- a/components/autofill/core/common/logging/log_buffer.cc
+++ b/components/autofill/core/common/logging/log_buffer.cc
@@ -44,8 +44,8 @@
     return;
   }
 
-  base::Value::ListStorage list;
-  list.emplace_back(std::move(new_child));
+  base::Value::List list;
+  list.Append(std::move(new_child));
   parent.SetKey("children", base::Value(std::move(list)));
 }
 
@@ -75,9 +75,9 @@
 }
 
 base::Value CreateEmptyFragment() {
-  base::Value::DictStorage storage;
-  storage.try_emplace("type", "fragment");
-  return base::Value(storage);
+  base::Value::Dict dict;
+  dict.Set("type", "fragment");
+  return base::Value(std::move(dict));
 }
 
 }  // namespace
@@ -115,10 +115,10 @@
   if (!buf.active())
     return buf;
 
-  base::Value::DictStorage storage;
-  storage.try_emplace("type", "element");
-  storage.try_emplace("value", std::move(tag.name));
-  buf.buffer_.emplace_back(std::move(storage));
+  base::Value::Dict dict;
+  dict.Set("type", "element");
+  dict.Set("value", std::move(tag.name));
+  buf.buffer_.emplace_back(std::move(dict));
   return buf;
 }
 
@@ -147,8 +147,8 @@
     attributes->SetKey(std::move(attrib.name),
                        base::Value(std::move(attrib.value)));
   } else {
-    base::Value::DictStorage dict;
-    dict.try_emplace(std::move(attrib.name), std::move(attrib.value));
+    base::Value::Dict dict;
+    dict.Set(attrib.name, std::move(attrib.value));
     node.SetKey("attributes", base::Value(std::move(dict)));
   }
 
@@ -171,12 +171,12 @@
   if (TryCoalesceString(&buf.buffer_, text))
     return buf;
 
-  base::Value::DictStorage storage;
-  storage.try_emplace("type", "text");
+  base::Value::Dict dict;
+  dict.Set("type", "text");
   // This text is not HTML escaped because the rest of the frame work takes care
   // of that and it must not be escaped twice.
-  storage.try_emplace("value", text);
-  base::Value node_to_add(std::move(storage));
+  dict.Set("value", text);
+  base::Value node_to_add(std::move(dict));
   AppendChildToLastNode(&buf.buffer_, std::move(node_to_add));
   return buf;
 }
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 459e34c7..e7bf750e 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -213,14 +213,6 @@
       configs += [ ":xkbcommon" ]
     }
   }
-
-  if (is_castos) {
-    deps += [ "//ui/accessibility" ]
-    sources += [
-      "fullscreen_shell_surface.cc",
-      "fullscreen_shell_surface.h",
-    ]
-  }
 }
 
 source_set("test_support") {
@@ -366,11 +358,6 @@
       "//ui/gfx/geometry",
     ]
   }
-
-  if (is_castos) {
-    deps += [ "//ui/accessibility" ]
-    sources += [ "fullscreen_shell_surface_unittest.cc" ]
-  }
 }
 
 test("exo_unittests") {
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 02a9efdf..97d7e9d 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -368,8 +368,21 @@
     return;
   }
 
+  // When use_default_scale_cancellation_ is false, the client is scale-aware
+  // and we expect that the |bounds| has been calculated by the client based
+  // on the device_scale_factor of the display with |display_id|.
+  // If the display has been changed before |SetBounds()| is called, for some
+  // cases(eg. move ARC window between displays with shortcut), |pending_scale_|
+  // may be stale and tied the old pending_display. Therefore, we re-initialize
+  // it to 0.0 here to force an update on the value in |EnsurePendingScale()|.
+  // Also need to note that we only want to commit |pending_scale_| in the cases
+  // where it hasn't been initialized before this method call.
+  bool const commit_immediately = pending_scale_ == 0.0;
+  if (!use_default_scale_cancellation_ && display_id != pending_display_id_)
+    pending_scale_ = 0.0;
+
   SetDisplay(display_id);
-  EnsurePendingScale();
+  EnsurePendingScale(commit_immediately);
 
   const gfx::Rect bounds_dp =
       gfx::ScaleToRoundedRect(bounds, GetClientToDpPendingScale());
@@ -380,7 +393,7 @@
   TRACE_EVENT1("exo", "ClientControlledShellSurface::SetBoundsOrigin", "origin",
                origin.ToString());
 
-  EnsurePendingScale();
+  EnsurePendingScale(/*commit_immediately=*/true);
   const gfx::Point origin_dp =
       gfx::ScaleToRoundedPoint(origin, GetClientToDpPendingScale());
   pending_geometry_.set_origin(origin_dp);
@@ -395,7 +408,7 @@
     return;
   }
 
-  EnsurePendingScale();
+  EnsurePendingScale(/*commit_immediately=*/true);
   const gfx::Size size_dp =
       gfx::ScaleToRoundedSize(size, GetClientToDpPendingScale());
   pending_geometry_.set_size(size_dp);
@@ -1442,16 +1455,17 @@
       widget_->non_client_view()->frame_view());
 }
 
-void ClientControlledShellSurface::EnsurePendingScale() {
+void ClientControlledShellSurface::EnsurePendingScale(bool commit_immediately) {
   // Handle the case where we receive bounds from the client before the initial
-  // scale has been set.
+  // scale has been set or |pending_scale_| is stale due to change of displays.
   if (pending_scale_ == 0.0) {
     DCHECK(!use_default_scale_cancellation_);
     display::Display display;
     if (display::Screen::GetScreen()->GetDisplayWithDisplayId(
             pending_display_id_, &display)) {
       SetScale(display.device_scale_factor());
-      CommitPendingScale();
+      if (commit_immediately)
+        CommitPendingScale();
     }
   }
 }
diff --git a/components/exo/client_controlled_shell_surface.h b/components/exo/client_controlled_shell_surface.h
index 5ddc920..b3c407868 100644
--- a/components/exo/client_controlled_shell_surface.h
+++ b/components/exo/client_controlled_shell_surface.h
@@ -290,7 +290,7 @@
   ash::NonClientFrameViewAsh* GetFrameView();
   const ash::NonClientFrameViewAsh* GetFrameView() const;
 
-  void EnsurePendingScale();
+  void EnsurePendingScale(bool commit_immediately);
   float GetClientToDpPendingScale() const;
 
   gfx::Rect GetClientBoundsForWindowBoundsAndWindowState(
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index 72b15cfd6..5d3f773 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -2015,21 +2015,26 @@
 // is enabled or disabled.
 TEST_F(ClientControlledShellSurfaceTest,
        SetBoundsWithAndWithoutDefaultScaleCancellation) {
-  UpdateDisplay("800x600*2");
+  UpdateDisplay("800x600*2,800x600*2");
 
   const auto primary_display_id =
       display::Screen::GetScreen()->GetPrimaryDisplay().id();
+  const auto secondary_display_id =
+      display::Screen::GetScreen()->GetAllDisplays().back().id();
 
   const gfx::Size buffer_size(64, 64);
   std::unique_ptr<Buffer> buffer(
       new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
 
-  const gfx::Rect bounds(64, 64, 128, 128);
-  const gfx::Rect bounds_dp = gfx::ScaleToRoundedRect(bounds, 1.f / 2.f);
+  constexpr double kOriginalScale = 4.f;
+  const gfx::Rect bounds_dp(64, 64, 128, 128);
+  const gfx::Rect bounds_px_for_2x = gfx::ScaleToRoundedRect(bounds_dp, 2.f);
+  const gfx::Rect bounds_px_for_4x =
+      gfx::ScaleToRoundedRect(bounds_dp, kOriginalScale);
 
   for (const auto default_scale_cancellation : {true, false}) {
-    const auto bounds_to_set = default_scale_cancellation ? bounds_dp : bounds;
-
+    SCOPED_TRACE(::testing::Message() << "default_scale_cancellation: "
+                                      << default_scale_cancellation);
     {
       // Set display id, bounds origin, bounds size at the same time via
       // SetBounds method.
@@ -2037,20 +2042,40 @@
       auto shell_surface(exo_test_helper()->CreateClientControlledShellSurface(
           surface.get(), /*is_modal=*/false, default_scale_cancellation));
 
-      shell_surface->SetBounds(primary_display_id, bounds_to_set);
+      // When display doesn't change, scale stays the same
+      shell_surface->SetScale(kOriginalScale);
+      shell_surface->SetDisplay(primary_display_id);
+      shell_surface->SetBounds(primary_display_id, default_scale_cancellation
+                                                       ? bounds_dp
+                                                       : bounds_px_for_4x);
       surface->Attach(buffer.get());
       surface->Commit();
 
       EXPECT_EQ(bounds_dp,
                 shell_surface->GetWidget()->GetWindowBoundsInScreen());
-    }
 
+      // When display changes, scale gets updated by the display dsf
+      shell_surface->SetScale(kOriginalScale);
+      shell_surface->SetBounds(secondary_display_id, default_scale_cancellation
+                                                         ? bounds_dp
+                                                         : bounds_px_for_2x);
+      surface->Attach(buffer.get());
+      surface->Commit();
+
+      EXPECT_EQ(bounds_dp.width(),
+                shell_surface->GetWidget()->GetWindowBoundsInScreen().width());
+      EXPECT_EQ(bounds_dp.height(),
+                shell_surface->GetWidget()->GetWindowBoundsInScreen().height());
+    }
     {
       // Set display id, bounds origin, bounds size separately.
+      const auto bounds_to_set =
+          default_scale_cancellation ? bounds_dp : bounds_px_for_4x;
       std::unique_ptr<Surface> surface(new Surface);
       auto shell_surface(exo_test_helper()->CreateClientControlledShellSurface(
           surface.get(), /*is_modal=*/false, default_scale_cancellation));
 
+      shell_surface->SetScale(kOriginalScale);
       shell_surface->SetDisplay(primary_display_id);
       shell_surface->SetBoundsOrigin(bounds_to_set.origin());
       shell_surface->SetBoundsSize(bounds_to_set.size());
diff --git a/components/exo/fullscreen_shell_surface.cc b/components/exo/fullscreen_shell_surface.cc
deleted file mode 100644
index c6b3a74..0000000
--- a/components/exo/fullscreen_shell_surface.cc
+++ /dev/null
@@ -1,307 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/exo/fullscreen_shell_surface.h"
-
-#include "components/exo/shell_surface_util.h"
-#include "components/exo/surface.h"
-#include "components/exo/wm_helper.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "ui/accessibility/ax_enums.mojom.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_observer.h"
-#include "ui/aura/window_occlusion_tracker.h"
-#include "ui/aura/window_targeter.h"
-#include "ui/base/metadata/metadata_header_macros.h"
-#include "ui/base/metadata/metadata_impl_macros.h"
-#include "ui/compositor/compositor.h"
-#include "ui/views/accessibility/view_accessibility.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/widget.h"
-#include "ui/wm/core/window_util.h"
-
-namespace exo {
-
-class FullscreenShellSurface::FullscreenShellView : public views::View {
- public:
-  METADATA_HEADER(FullscreenShellView);
-  FullscreenShellView() = default;
-  FullscreenShellView(const FullscreenShellView&) = delete;
-  FullscreenShellView& operator=(const FullscreenShellView&) = delete;
-  ~FullscreenShellView() override = default;
-
-  // views::View:
-  void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
-    node_data->role = ax::mojom::Role::kClient;
-  }
-
-  void SetChildAxTreeId(ui::AXTreeID child_ax_tree_id) {
-    GetViewAccessibility().OverrideChildTreeID(child_ax_tree_id);
-  }
-};
-
-BEGIN_METADATA(FullscreenShellSurface, FullscreenShellView, views::View)
-END_METADATA
-
-FullscreenShellSurface::FullscreenShellSurface()
-    : SurfaceTreeHost("FullscreenShellSurfaceHost") {
-  CreateFullscreenShellSurfaceWidget(ui::SHOW_STATE_FULLSCREEN);
-  SetCanResize(false);
-  widget_->SetFullscreen(true);
-}
-
-FullscreenShellSurface::~FullscreenShellSurface() {
-  if (widget_) {
-    widget_->GetNativeWindow()->RemoveObserver(this);
-    // Remove transient children so they are not automatically destroyed.
-    for (auto* child : wm::GetTransientChildren(widget_->GetNativeWindow()))
-      wm::RemoveTransientChild(widget_->GetNativeWindow(), child);
-    if (widget_->IsVisible())
-      widget_->Hide();
-    widget_->CloseNow();
-  }
-  if (parent_)
-    parent_->RemoveObserver(this);
-  if (root_surface())
-    root_surface()->RemoveSurfaceObserver(this);
-}
-
-void FullscreenShellSurface::SetApplicationId(const char* application_id) {
-  // Store the value in |application_id_| in case the window does not exist yet.
-  if (application_id)
-    application_id_ = std::string(application_id);
-  else
-    application_id_.reset();
-
-  if (widget_ && widget_->GetNativeWindow())
-    SetShellApplicationId(widget_->GetNativeWindow(), application_id_);
-}
-
-void FullscreenShellSurface::SetStartupId(const char* startup_id) {
-  // Store the value in |startup_id_| in case the window does not exist yet.
-  if (startup_id)
-    startup_id_ = std::string(startup_id);
-  else
-    startup_id_.reset();
-
-  if (widget_ && widget_->GetNativeWindow())
-    SetShellStartupId(widget_->GetNativeWindow(), startup_id_);
-}
-
-void FullscreenShellSurface::SetSurface(Surface* surface) {
-  if (root_surface())
-    root_surface()->RemoveSurfaceObserver(this);
-  SetRootSurface(surface);
-  SetShellRootSurface(widget_->GetNativeWindow(), root_surface());
-  if (surface) {
-    surface->AddSurfaceObserver(this);
-    host_window()->Show();
-    widget_->Show();
-  } else {
-    host_window()->Hide();
-    widget_->Hide();
-  }
-}
-
-void FullscreenShellSurface::Maximize() {
-  if (!widget_)
-    return;
-
-  widget_->Maximize();
-}
-
-void FullscreenShellSurface::Minimize() {
-  if (!widget_)
-    return;
-
-  widget_->Minimize();
-}
-
-void FullscreenShellSurface::Close() {
-  if (!close_callback_.is_null())
-    close_callback_.Run();
-}
-
-void FullscreenShellSurface::OnSurfaceCommit() {
-  SurfaceTreeHost::OnSurfaceCommit();
-  if (!OnPreWidgetCommit())
-    return;
-
-  CommitWidget();
-  SubmitCompositorFrame();
-}
-
-bool FullscreenShellSurface::IsInputEnabled(Surface*) const {
-  return true;
-}
-
-void FullscreenShellSurface::OnSetFrame(SurfaceFrameType frame_type) {}
-
-void FullscreenShellSurface::OnSetFrameColors(SkColor active_color,
-                                              SkColor inactive_color) {}
-
-void FullscreenShellSurface::OnSetStartupId(const char* startup_id) {
-  SetStartupId(startup_id);
-}
-
-void FullscreenShellSurface::OnSetApplicationId(const char* application_id) {
-  SetApplicationId(application_id);
-}
-
-void FullscreenShellSurface::OnSurfaceDestroying(Surface* surface) {
-  DCHECK_EQ(root_surface(), surface);
-  surface->RemoveSurfaceObserver(this);
-  SetRootSurface(nullptr);
-
-  if (widget_)
-    SetShellRootSurface(widget_->GetNativeWindow(), nullptr);
-
-  // Hide widget before surface is destroyed. This allows hide animations to
-  // run using the current surface contents.
-  if (widget_) {
-    // Remove transient children so they are not automatically hidden.
-    for (auto* child : wm::GetTransientChildren(widget_->GetNativeWindow()))
-      wm::RemoveTransientChild(widget_->GetNativeWindow(), child);
-
-    widget_->Hide();
-  }
-
-  // Note: In its use in the Wayland server implementation, the surface
-  // destroyed callback may destroy the ShellSurface instance. This call needs
-  // to be last so that the instance can be destroyed.
-  std::move(surface_destroyed_callback_).Run();
-}
-
-bool FullscreenShellSurface::CanMaximize() const {
-  return true;
-}
-
-bool FullscreenShellSurface::CanMinimize() const {
-  return true;
-}
-
-bool FullscreenShellSurface::ShouldShowWindowTitle() const {
-  return false;
-}
-
-void FullscreenShellSurface::WindowClosing() {
-  contents_view_->SetEnabled(false);
-  contents_view_ = nullptr;
-  widget_ = nullptr;
-}
-
-views::Widget* FullscreenShellSurface::GetWidget() {
-  return widget_;
-}
-
-const views::Widget* FullscreenShellSurface::GetWidget() const {
-  return widget_;
-}
-
-views::View* FullscreenShellSurface::GetContentsView() {
-  if (!contents_view_)
-    contents_view_ = new FullscreenShellView();
-  return contents_view_;
-}
-
-bool FullscreenShellSurface::WidgetHasHitTestMask() const {
-  return true;
-}
-
-void FullscreenShellSurface::GetWidgetHitTestMask(SkPath* mask) const {
-  GetHitTestMask(mask);
-  gfx::Point origin = host_window()->bounds().origin();
-  SkMatrix matrix;
-  // TODO (sagallea) acquire scale from display
-  float scale = 1.f;
-  matrix.setScaleTranslate(
-      SkFloatToScalar(1.0f / scale), SkFloatToScalar(1.0f / scale),
-      SkIntToScalar(origin.x()), SkIntToScalar(origin.y()));
-  mask->transform(matrix);
-}
-
-void FullscreenShellSurface::OnWindowDestroying(aura::Window* window) {
-  if (window == parent_) {
-    parent_ = nullptr;
-    // |parent_| being set to null effects the ability to maximize the window.
-    if (widget_)
-      widget_->OnSizeConstraintsChanged();
-  }
-
-  window->RemoveObserver(this);
-}
-
-void FullscreenShellSurface::SetChildAxTreeId(ui::AXTreeID child_ax_tree_id) {
-  DCHECK(contents_view_);
-  contents_view_->SetChildAxTreeId(child_ax_tree_id);
-}
-
-void FullscreenShellSurface::SetEnabled(bool enabled) {
-  DCHECK(contents_view_);
-  contents_view_->SetEnabled(enabled);
-}
-
-void FullscreenShellSurface::UpdateHostWindowBounds() {
-  // This method applies multiple changes to the window tree. Use ScopedPause
-  // to ensure that occlusion isn't recomputed before all changes have been
-  // applied.
-  aura::WindowOcclusionTracker::ScopedPause pause_occlusion;
-
-  host_window()->SetBounds(
-      gfx::Rect(root_surface()->window()->bounds().size()));
-  host_window()->SetTransparent(!root_surface()->FillsBoundsOpaquely());
-}
-
-void FullscreenShellSurface::CreateFullscreenShellSurfaceWidget(
-    ui::WindowShowState show_state) {
-  DCHECK(!widget_);
-
-  views::Widget::InitParams params;
-  params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
-  params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
-  params.delegate = this;
-  params.shadow_type = views::Widget::InitParams::ShadowType::kNone;
-  params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
-  params.show_state = show_state;
-  params.activatable = views::Widget::InitParams::Activatable::kYes;
-  params.parent = WMHelper::GetInstance()->GetRootWindowForNewWindows();
-  params.bounds = gfx::Rect(params.parent->bounds().size());
-
-  widget_ = new views::Widget();
-  widget_->Init(std::move(params));
-
-  aura::Window* window = widget_->GetNativeWindow();
-  window->SetName("FullscreenShellSurface");
-  window->AddChild(host_window());
-
-  SetShellApplicationId(window, application_id_);
-  SetShellStartupId(window, startup_id_);
-  SetShellRootSurface(window, root_surface());
-
-  window->AddObserver(this);
-}
-
-void FullscreenShellSurface::CommitWidget() {
-  if (!widget_)
-    return;
-
-  // Show widget if needed.
-  if (!widget_->IsVisible()) {
-    DCHECK(!widget_->IsClosed());
-    widget_->Show();
-  }
-}
-
-bool FullscreenShellSurface::OnPreWidgetCommit() {
-  // If we have a |widget_|, then we must have a |contents_view_| as both are
-  // created together.
-  if (!widget_ && contents_view_->GetEnabled() &&
-      host_window()->bounds().IsEmpty()) {
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace exo
diff --git a/components/exo/fullscreen_shell_surface.h b/components/exo/fullscreen_shell_surface.h
deleted file mode 100644
index cb58b0c..0000000
--- a/components/exo/fullscreen_shell_surface.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_EXO_FULLSCREEN_SHELL_SURFACE_H_
-#define COMPONENTS_EXO_FULLSCREEN_SHELL_SURFACE_H_
-
-#include "components/exo/surface_observer.h"
-#include "components/exo/surface_tree_host.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/accessibility/ax_tree_id.h"
-#include "ui/aura/window_observer.h"
-#include "ui/views/widget/widget_delegate.h"
-
-namespace exo {
-class Surface;
-
-// This class implements a toplevel fullscreen surface for which position
-// and state are managed by the shell.
-class FullscreenShellSurface : public SurfaceTreeHost,
-                               public SurfaceObserver,
-                               public aura::WindowObserver,
-                               public views::WidgetDelegate {
- public:
-  FullscreenShellSurface();
-
-  FullscreenShellSurface(const FullscreenShellSurface&) = delete;
-  FullscreenShellSurface& operator=(const FullscreenShellSurface&) = delete;
-
-  ~FullscreenShellSurface() override;
-
-  // Set the callback to run when the user wants the shell surface to be closed.
-  // The receiver can chose to not close the window on this signal.
-  void set_close_callback(const base::RepeatingClosure& close_callback) {
-    close_callback_ = close_callback;
-  }
-
-  // Set the callback to run when the surface is destroyed.
-  void set_surface_destroyed_callback(
-      base::OnceClosure surface_destroyed_callback) {
-    surface_destroyed_callback_ = std::move(surface_destroyed_callback);
-  }
-
-  // Set the application ID for the surface
-  void SetApplicationId(const char* startup_id);
-
-  // Set the startup ID for the surface.
-  void SetStartupId(const char* startup_id);
-
-  // Set the Surface in use. Will replace root_surface_ if a surface is
-  // currently set. Will remove root_surface_ if |surface| is nullptr.
-  void SetSurface(Surface* surface);
-
-  void Maximize();
-  void Minimize();
-  void Close();
-
-  // SurfaceDelegate:
-  void OnSurfaceCommit() override;
-  bool IsInputEnabled(Surface* surface) const override;
-  void OnSetFrame(SurfaceFrameType type) override;
-  void OnSetFrameColors(SkColor active_color, SkColor inactive_color) override;
-  void OnSetStartupId(const char* startup_id) override;
-  void OnSetApplicationId(const char* application_id) override;
-
-  // SurfaceObserver:
-  void OnSurfaceDestroying(Surface* surface) override;
-
-  // views::WidgetDelegate:
-  bool CanMaximize() const override;
-  bool CanMinimize() const override;
-  bool ShouldShowWindowTitle() const override;
-  void WindowClosing() override;
-  views::Widget* GetWidget() override;
-  const views::Widget* GetWidget() const override;
-  views::View* GetContentsView() override;
-  bool WidgetHasHitTestMask() const override;
-  void GetWidgetHitTestMask(SkPath* mask) const override;
-
-  // aura::WindowObserver:
-  void OnWindowDestroying(aura::Window* window) override;
-
-  void SetChildAxTreeId(ui::AXTreeID child_ax_tree_id);
-  void SetEnabled(bool enabled);
-
- private:
-  class FullscreenShellView;
-  // Keep the bounds in sync with the root surface bounds.
-  void UpdateHostWindowBounds() override;
-
-  void CreateFullscreenShellSurfaceWidget(ui::WindowShowState show_state);
-  void CommitWidget();
-  bool OnPreWidgetCommit();
-
-  views::Widget* widget_ = nullptr;
-  aura::Window* parent_ = nullptr;
-  absl::optional<std::string> application_id_;
-  absl::optional<std::string> startup_id_;
-  base::RepeatingClosure close_callback_;
-  base::OnceClosure surface_destroyed_callback_;
-  FullscreenShellView* contents_view_ = nullptr;
-};
-
-}  // namespace exo
-
-#endif  // COMPONENTS_EXO_FULLSCREEN_SHELL_SURFACE_H_
diff --git a/components/exo/fullscreen_shell_surface_unittest.cc b/components/exo/fullscreen_shell_surface_unittest.cc
deleted file mode 100644
index 4ab98e0..0000000
--- a/components/exo/fullscreen_shell_surface_unittest.cc
+++ /dev/null
@@ -1,293 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/exo/fullscreen_shell_surface.h"
-
-#include "base/bind.h"
-#include "components/exo/buffer.h"
-#include "components/exo/shell_surface_util.h"
-#include "components/exo/sub_surface.h"
-#include "components/exo/surface.h"
-#include "components/exo/test/exo_test_base_views.h"
-#include "components/exo/wm_helper.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/accessibility/ax_enums.mojom.h"
-#include "ui/accessibility/ax_node_data.h"
-#include "ui/accessibility/ax_tree_id.h"
-#include "ui/aura/env.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/compositor.h"
-#include "ui/gfx/buffer_types.h"
-#include "ui/views/accessibility/view_accessibility.h"
-#include "ui/views/widget/widget.h"
-
-namespace exo {
-namespace {
-
-using FullscreenShellSurfaceTest = test::ExoTestBaseViews;
-
-std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
-    const gfx::Size& size,
-    gfx::BufferFormat format) {
-  return aura::Env::GetInstance()
-      ->context_factory()
-      ->GetGpuMemoryBufferManager()
-      ->CreateGpuMemoryBuffer(size, format, gfx::BufferUsage::GPU_READ,
-                              gpu::kNullSurfaceHandle, nullptr);
-}
-
-void DestroyFullscreenShellSurface(
-    std::unique_ptr<FullscreenShellSurface>* fullscreen_surface) {
-  fullscreen_surface->reset();
-}
-
-void Close(int* close_call_count) {
-  (*close_call_count)++;
-}
-
-TEST_F(FullscreenShellSurfaceTest, SurfaceDestroyedCallback) {
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-
-  fullscreen_surface->set_surface_destroyed_callback(base::BindOnce(
-      &DestroyFullscreenShellSurface, base::Unretained(&fullscreen_surface)));
-
-  // Change the surface so the commit has an actual change otherwise it triggers
-  // a DCHECK during frame submission.
-  surface->SetViewport(gfx::SizeF(64, 64));
-  surface->Commit();
-
-  EXPECT_TRUE(fullscreen_surface.get());
-  surface.reset();
-  EXPECT_FALSE(fullscreen_surface.get());
-}
-
-TEST_F(FullscreenShellSurfaceTest, CloseCallback) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(new Buffer(
-      CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-
-  int close_call_count = 0;
-  fullscreen_surface->set_close_callback(
-      base::BindRepeating(&Close, base::Unretained(&close_call_count)));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  EXPECT_EQ(0, close_call_count);
-  fullscreen_surface->Close();
-  EXPECT_EQ(1, close_call_count);
-}
-
-TEST_F(FullscreenShellSurfaceTest, ShouldShowWindowTitle) {
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-
-  EXPECT_FALSE(fullscreen_surface->ShouldShowWindowTitle());
-}
-
-TEST_F(FullscreenShellSurfaceTest, SetApplicationId) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(new Buffer(
-      CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-
-  EXPECT_TRUE(fullscreen_surface->GetWidget());
-  fullscreen_surface->SetApplicationId("test-id");
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-  aura::Window* window = fullscreen_surface->GetWidget()->GetNativeWindow();
-  EXPECT_EQ("test-id", *GetShellApplicationId(window));
-  fullscreen_surface->SetApplicationId("test");
-  EXPECT_EQ("test", *GetShellApplicationId(window));
-
-  fullscreen_surface->SetApplicationId(nullptr);
-  EXPECT_EQ(nullptr, GetShellApplicationId(window));
-}
-
-TEST_F(FullscreenShellSurfaceTest, SetStartupId) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(new Buffer(
-      CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-
-  EXPECT_TRUE(fullscreen_surface->GetWidget());
-  fullscreen_surface->SetStartupId("test-id");
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-  aura::Window* window = fullscreen_surface->GetWidget()->GetNativeWindow();
-  EXPECT_EQ("test-id", *GetShellStartupId(window));
-  fullscreen_surface->SetStartupId("test");
-  EXPECT_EQ("test", *GetShellStartupId(window));
-
-  fullscreen_surface->SetStartupId(nullptr);
-  EXPECT_EQ(nullptr, GetShellStartupId(window));
-}
-
-TEST_F(FullscreenShellSurfaceTest, Maximize) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(new Buffer(
-      CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-  fullscreen_surface->Maximize();
-  EXPECT_TRUE(fullscreen_surface->GetWidget()->IsMaximized());
-}
-
-TEST_F(FullscreenShellSurfaceTest, Minimize) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(new Buffer(
-      CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-  fullscreen_surface->Minimize();
-  EXPECT_TRUE(fullscreen_surface->GetWidget()->IsMinimized());
-}
-
-TEST_F(FullscreenShellSurfaceTest, Bounds) {
-  aura::Window* root_window =
-      WMHelper::GetInstance()->GetRootWindowForNewWindows();
-  gfx::Rect new_root_bounds(10, 10, 100, 100);
-  root_window->SetBounds(new_root_bounds);
-
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(new Buffer(
-      CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888)));
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-  gfx::Rect fullscreen_bounds =
-      fullscreen_surface->GetWidget()->GetWindowBoundsInScreen();
-  gfx::Rect expected_bounds(new_root_bounds.size());
-  EXPECT_EQ(fullscreen_bounds, expected_bounds);
-}
-
-TEST_F(FullscreenShellSurfaceTest, BoundsWithPartiallyOffscreenSubSurface) {
-  aura::Window* root_window =
-      WMHelper::GetInstance()->GetRootWindowForNewWindows();
-  gfx::Rect new_root_bounds(10, 10, 100, 100);
-  gfx::Rect expected_bounds(new_root_bounds.size());
-  root_window->SetBounds(new_root_bounds);
-
-  gfx::Size buffer_size(100, 100);
-  auto buffer = std::make_unique<Buffer>(
-      CreateGpuMemoryBuffer(buffer_size, gfx::BufferFormat::RGBA_8888));
-  auto parent = std::make_unique<Surface>();
-  auto fullscreen_surface = std::make_unique<FullscreenShellSurface>();
-  fullscreen_surface->SetSurface(parent.get());
-
-  parent->Attach(buffer.get());
-  parent->Commit();
-  EXPECT_EQ(fullscreen_surface->GetWidget()->GetWindowBoundsInScreen(),
-            expected_bounds);
-  EXPECT_EQ(parent->window()->bounds(), expected_bounds);
-
-  auto surface = std::make_unique<Surface>();
-  auto sub_surface = std::make_unique<SubSurface>(surface.get(), parent.get());
-  surface->Attach(buffer.get());
-  sub_surface->SetPosition(gfx::PointF(-50, -50));
-
-  parent->Commit();
-  // Make sure the sub-surface doesn't affect the Fullscreen Shell's Window
-  // size/position.
-  EXPECT_EQ(fullscreen_surface->GetWidget()->GetWindowBoundsInScreen(),
-            expected_bounds);
-  // The root surface should also have the same position/size as before.
-  EXPECT_EQ(parent->window()->bounds(), expected_bounds);
-}
-
-TEST_F(FullscreenShellSurfaceTest, SetAXChildTree) {
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-  const views::ViewAccessibility& view_accessibility =
-      fullscreen_surface->GetContentsView()->GetViewAccessibility();
-  ui::AXNodeData node_data;
-  view_accessibility.GetAccessibleNodeData(&node_data);
-  EXPECT_FALSE(
-      node_data.HasStringAttribute(ax::mojom::StringAttribute::kChildTreeId));
-
-  ui::AXTreeID tree_id = ui::AXTreeID::CreateNewAXTreeID();
-  fullscreen_surface->SetChildAxTreeId(tree_id);
-  view_accessibility.GetAccessibleNodeData(&node_data);
-  EXPECT_TRUE(
-      node_data.HasStringAttribute(ax::mojom::StringAttribute::kChildTreeId));
-}
-
-TEST_F(FullscreenShellSurfaceTest, SwapSurface) {
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-  fullscreen_surface->SetEnabled(true);
-  fullscreen_surface->set_surface_destroyed_callback(base::BindOnce(
-      &DestroyFullscreenShellSurface, base::Unretained(&fullscreen_surface)));
-  EXPECT_EQ(surface.get(), fullscreen_surface->root_surface());
-  std::unique_ptr<Surface> surface2(new Surface);
-  fullscreen_surface->SetSurface(surface2.get());
-  EXPECT_EQ(surface2.get(), fullscreen_surface->root_surface());
-  EXPECT_NE(surface.get(), fullscreen_surface->root_surface());
-  // RootWindow->FullscreenShellSurface->FullscreenShellSurfaceHost->ExoSurface
-  EXPECT_EQ(1ul, WMHelper::GetInstance()
-                     ->GetRootWindowForNewWindows()
-                     ->children()[0]
-                     ->children()[0]
-                     ->children()
-                     .size());
-}
-
-TEST_F(FullscreenShellSurfaceTest, RemoveSurface) {
-  std::unique_ptr<Surface> surface(new Surface);
-  std::unique_ptr<FullscreenShellSurface> fullscreen_surface(
-      new FullscreenShellSurface());
-  fullscreen_surface->SetSurface(surface.get());
-  fullscreen_surface->SetEnabled(true);
-  fullscreen_surface->set_surface_destroyed_callback(base::BindOnce(
-      &DestroyFullscreenShellSurface, base::Unretained(&fullscreen_surface)));
-  EXPECT_EQ(surface.get(), fullscreen_surface->root_surface());
-  fullscreen_surface->SetSurface(nullptr);
-  EXPECT_FALSE(fullscreen_surface->root_surface());
-  // RootWindow->FullscreenShellSurface->FullscreenShellSurfaceHost->null
-  EXPECT_EQ(0ul, WMHelper::GetInstance()
-                     ->GetRootWindowForNewWindows()
-                     ->children()[0]
-                     ->children()[0]
-                     ->children()
-                     .size());
-}
-
-}  // namespace
-}  // namespace exo
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index 6cf8a12..cc84d45 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -147,15 +147,6 @@
     deps += [ "//ui/events/keycodes:xkb" ]
   }
 
-  if (is_castos) {
-    defines += [ "USE_FULLSCREEN_SHELL" ]
-    sources += [
-      "zwp_fullscreen_shell.cc",
-      "zwp_fullscreen_shell.h",
-    ]
-    deps += [ "//third_party/wayland-protocols:fullscreen_shell_protocol" ]
-  }
-
   if (is_chromeos_ash) {
     sources += [
       "wayland_keyboard_delegate.cc",
diff --git a/components/exo/wayland/zwp_fullscreen_shell.cc b/components/exo/wayland/zwp_fullscreen_shell.cc
deleted file mode 100644
index 2e73a97..0000000
--- a/components/exo/wayland/zwp_fullscreen_shell.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/exo/wayland/zwp_fullscreen_shell.h"
-
-#include <fullscreen-shell-unstable-v1-server-protocol.h>
-#include <wayland-server-core.h>
-#include <wayland-server-protocol-core.h>
-
-#include "base/bind.h"
-#include "components/exo/fullscreen_shell_surface.h"
-#include "components/exo/surface.h"
-#include "components/exo/wayland/server_util.h"
-
-namespace exo {
-namespace wayland {
-
-namespace {
-
-void fullscreen_shell_release(wl_client* client, wl_resource* resource) {
-  wl_resource_destroy(resource);
-}
-
-void fullscreen_shell_present_surface(wl_client* client,
-                                      wl_resource* resource,
-                                      wl_resource* surface,
-                                      uint32_t method,
-                                      wl_resource* output) {
-  FullscreenShellSurface* fullscreen_shell_surface =
-      GetUserDataAs<FullscreenShellSurface>(resource);
-  fullscreen_shell_surface->SetSurface(surface ? GetUserDataAs<Surface>(surface)
-                                               : nullptr);
-}
-
-void fullscreen_shell_present_surface_for_mode(wl_client* client,
-                                               wl_resource* resource,
-                                               wl_resource* surface,
-                                               wl_resource* output,
-                                               int32_t framerate,
-                                               uint32_t feedback) {
-  NOTIMPLEMENTED();
-}
-
-const struct zwp_fullscreen_shell_v1_interface fullscreen_shell_implementation =
-    {fullscreen_shell_release, fullscreen_shell_present_surface,
-     fullscreen_shell_present_surface_for_mode};
-
-}  // namespace
-
-void bind_fullscreen_shell(wl_client* client,
-                           void* data,
-                           uint32_t version,
-                           uint32_t id) {
-  std::unique_ptr<FullscreenShellSurface> fullscreen_shell_surface =
-      std::make_unique<FullscreenShellSurface>();
-  fullscreen_shell_surface->SetEnabled(true);
-  wl_resource* resource =
-      wl_resource_create(client, &zwp_fullscreen_shell_v1_interface, 1, id);
-  fullscreen_shell_surface->set_surface_destroyed_callback(
-      base::BindOnce(&wl_resource_destroy, base::Unretained(resource)));
-  SetImplementation(resource, &fullscreen_shell_implementation,
-                    std::move(fullscreen_shell_surface));
-}
-
-}  // namespace wayland
-}  // namespace exo
diff --git a/components/exo/wayland/zwp_fullscreen_shell.h b/components/exo/wayland/zwp_fullscreen_shell.h
deleted file mode 100644
index 48c18c1e..0000000
--- a/components/exo/wayland/zwp_fullscreen_shell.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_EXO_WAYLAND_ZWP_FULLSCREEN_SHELL_H_
-#define COMPONENTS_EXO_WAYLAND_ZWP_FULLSCREEN_SHELL_H_
-
-#include <stdint.h>
-
-struct wl_client;
-
-namespace exo {
-namespace wayland {
-
-void bind_fullscreen_shell(wl_client* client,
-                           void* data,
-                           uint32_t version,
-                           uint32_t id);
-
-}  // namespace wayland
-}  // namespace exo
-
-#endif  // COMPONENTS_EXO_WAYLAND_ZWP_FULLSCREEN_SHELL_H_
diff --git a/components/segmentation_platform/internal/BUILD.gn b/components/segmentation_platform/internal/BUILD.gn
index ad776c33..5f12bb2 100644
--- a/components/segmentation_platform/internal/BUILD.gn
+++ b/components/segmentation_platform/internal/BUILD.gn
@@ -77,6 +77,8 @@
     "execution/processing/feature_list_query_processor.h",
     "execution/processing/feature_processor_state.cc",
     "execution/processing/feature_processor_state.h",
+    "execution/processing/input_delegate.cc",
+    "execution/processing/input_delegate.h",
     "execution/processing/query_processor.h",
     "execution/processing/sql_feature_processor.cc",
     "execution/processing/sql_feature_processor.h",
diff --git a/components/segmentation_platform/internal/execution/processing/custom_input_processor.cc b/components/segmentation_platform/internal/execution/processing/custom_input_processor.cc
index d4ad8ae..611540e7 100644
--- a/components/segmentation_platform/internal/execution/processing/custom_input_processor.cc
+++ b/components/segmentation_platform/internal/execution/processing/custom_input_processor.cc
@@ -8,6 +8,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "components/segmentation_platform/internal/database/ukm_types.h"
 #include "components/segmentation_platform/internal/execution/processing/feature_processor_state.h"
+#include "components/segmentation_platform/internal/execution/processing/input_delegate.h"
 #include "components/segmentation_platform/internal/metadata/metadata_utils.h"
 #include "components/segmentation_platform/internal/proto/model_metadata.pb.h"
 
@@ -37,15 +38,18 @@
 
 }  // namespace
 
-CustomInputProcessor::CustomInputProcessor() = default;
-
-CustomInputProcessor::CustomInputProcessor(const base::Time prediction_time)
-    : prediction_time_(prediction_time) {}
+CustomInputProcessor::CustomInputProcessor(
+    const base::Time prediction_time,
+    InputDelegateHolder* input_delegate_holder)
+    : input_delegate_holder_(input_delegate_holder),
+      prediction_time_(prediction_time) {}
 
 CustomInputProcessor::CustomInputProcessor(
     base::flat_map<FeatureIndex, proto::CustomInput>&& custom_inputs,
-    const base::Time prediction_time)
-    : custom_inputs_(std::move(custom_inputs)),
+    const base::Time prediction_time,
+    InputDelegateHolder* input_delegate_holder)
+    : input_delegate_holder_(input_delegate_holder),
+      custom_inputs_(std::move(custom_inputs)),
       prediction_time_(prediction_time) {}
 
 CustomInputProcessor::~CustomInputProcessor() = default;
@@ -77,21 +81,45 @@
 void CustomInputProcessor::Process(
     std::unique_ptr<FeatureProcessorState> feature_processor_state,
     QueryProcessorCallback callback) {
+  auto result = std::make_unique<base::flat_map<FeatureIndex, Tensor>>();
   ProcessIndexType<FeatureIndex>(std::move(custom_inputs_),
                                  std::move(feature_processor_state),
-                                 std::move(callback));
+                                 std::move(result), std::move(callback));
 }
 
 template <typename IndexType>
 void CustomInputProcessor::ProcessIndexType(
     base::flat_map<IndexType, proto::CustomInput> custom_inputs,
     std::unique_ptr<FeatureProcessorState> feature_processor_state,
+    std::unique_ptr<base::flat_map<IndexType, Tensor>> result,
     TemplateCallback<IndexType> callback) {
-  base::flat_map<IndexType, Tensor> result;
   bool success = true;
-  for (const auto& current : custom_inputs) {
+  auto it = custom_inputs.begin();
+  for (; it != custom_inputs.end(); it = custom_inputs.begin()) {
     // Get the next feature in the list to process.
-    const proto::CustomInput& custom_input = current.second;
+    const proto::CustomInput custom_input(std::move(it->second));
+    const IndexType index = it->first;
+    custom_inputs.erase(it);
+
+    InputDelegate* input_delegate = nullptr;
+    if (input_delegate_holder_) {
+      input_delegate =
+          input_delegate_holder_->GetDelegate(custom_input.fill_policy());
+    }
+    if (input_delegate) {
+      // If a delegate is available then use it to process the input. All the
+      // state in this method is moved, so it is ok even if the client ran the
+      // callback without posting it.
+      const FeatureProcessorState& state = *feature_processor_state;
+      input_delegate->Process(
+          custom_input, state,
+          base::BindOnce(
+              &CustomInputProcessor::OnGotProcessedValue<IndexType>,
+              weak_ptr_factory_.GetWeakPtr(), std::move(custom_inputs),
+              std::move(feature_processor_state), std::move(result),
+              std::move(callback), index, custom_input.tensor_length()));
+      return;
+    }
 
     // Skip custom input with tensor length of 0.
     if (custom_input.tensor_length() == 0) {
@@ -102,28 +130,61 @@
         metadata_utils::ValidationResult::kValidationSuccess) {
       success = false;
     } else {
-      result[current.first] =
+      (*result)[index] =
           ProcessSingleCustomInput(custom_input, feature_processor_state.get());
     }
   }
 
   // Processing of the feature list has completed.
-  custom_inputs_.clear();
+  DCHECK(custom_inputs.empty());
   if (!success || feature_processor_state->error()) {
-    result.clear();
+    result->clear();
     feature_processor_state->SetError();
   }
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback), std::move(feature_processor_state),
-                     std::move(result)));
+                     std::move(*result)));
 }
 
-template void CustomInputProcessor::ProcessIndexType(
-    base::flat_map<std::pair<int, int>, proto::CustomInput> custom_inputs,
+template <typename IndexType>
+void CustomInputProcessor::OnGotProcessedValue(
+    base::flat_map<IndexType, proto::CustomInput> custom_inputs,
     std::unique_ptr<FeatureProcessorState> feature_processor_state,
+    std::unique_ptr<base::flat_map<IndexType, Tensor>> result,
+    TemplateCallback<IndexType> callback,
+    IndexType current_index,
+    size_t current_tensor_length,
+    bool error,
+    Tensor current_value) {
+  if (error) {
+    feature_processor_state->SetError();
+  } else {
+    DCHECK_EQ(current_tensor_length, current_value.size());
+  }
+  (*result)[current_index] = std::move(current_value);
+  ProcessIndexType<IndexType>(std::move(custom_inputs),
+                              std::move(feature_processor_state),
+                              std::move(result), std::move(callback));
+}
+
+using SqlCustomInputIndex = std::pair<int, int>;
+template void CustomInputProcessor::ProcessIndexType(
+    base::flat_map<SqlCustomInputIndex, proto::CustomInput> custom_inputs,
+    std::unique_ptr<FeatureProcessorState> feature_processor_state,
+    std::unique_ptr<base::flat_map<SqlCustomInputIndex, Tensor>> result,
     TemplateCallback<std::pair<int, int>> callback);
 
+template void CustomInputProcessor::OnGotProcessedValue(
+    base::flat_map<SqlCustomInputIndex, proto::CustomInput> custom_inputs,
+    std::unique_ptr<FeatureProcessorState> feature_processor_state,
+    std::unique_ptr<base::flat_map<SqlCustomInputIndex, Tensor>> result,
+    TemplateCallback<SqlCustomInputIndex> callback,
+    SqlCustomInputIndex current_index,
+    size_t current_tensor_length,
+    bool success,
+    Tensor current_value);
+
 QueryProcessor::Tensor CustomInputProcessor::ProcessSingleCustomInput(
     const proto::CustomInput& custom_input,
     FeatureProcessorState* feature_processor_state) {
@@ -147,10 +208,8 @@
       feature_processor_state->SetError();
   } else if (custom_input.fill_policy() ==
              proto::CustomInput::PRICE_TRACKING_HINTS) {
-    if (!AddPriceTrackingHints(custom_input, feature_processor_state,
-                               tensor_result)) {
-      feature_processor_state->SetError();
-    }
+    feature_processor_state->SetError();
+    NOTREACHED() << "InputDelegate is not found";
   }
   return tensor_result;
 }
@@ -187,14 +246,4 @@
   return true;
 }
 
-bool CustomInputProcessor::AddPriceTrackingHints(
-    const proto::CustomInput& custom_input,
-    FeatureProcessorState* feature_processor_state,
-    std::vector<ProcessedValue>& out_tensor) {
-  // TODO: implement.
-  // This might be moved to a delegate in chrome layer to be implemented if
-  // needed.
-  return false;
-}
-
 }  // namespace segmentation_platform::processing
diff --git a/components/segmentation_platform/internal/execution/processing/custom_input_processor.h b/components/segmentation_platform/internal/execution/processing/custom_input_processor.h
index 41b0598e..447c1aa 100644
--- a/components/segmentation_platform/internal/execution/processing/custom_input_processor.h
+++ b/components/segmentation_platform/internal/execution/processing/custom_input_processor.h
@@ -14,17 +14,19 @@
 
 namespace segmentation_platform::processing {
 class FeatureProcessorState;
+class InputDelegateHolder;
 
 // CustomInputProcessor adds support to a larger variety of data type
 // (timestamps, strings mapped to enums, etc), transforming them into valid
 // input tensor to use when executing the ML model.
 class CustomInputProcessor : public QueryProcessor {
  public:
-  explicit CustomInputProcessor();
-  explicit CustomInputProcessor(const base::Time prediction_time);
-  explicit CustomInputProcessor(
+  CustomInputProcessor(const base::Time prediction_time,
+                       InputDelegateHolder* input_delegate_holder);
+  CustomInputProcessor(
       base::flat_map<FeatureIndex, proto::CustomInput>&& custom_inputs,
-      const base::Time prediction_time);
+      const base::Time prediction_time,
+      InputDelegateHolder* input_delegate_holder);
   ~CustomInputProcessor() override;
 
   using FeatureListQueryProcessorCallback =
@@ -57,16 +59,30 @@
                               base::flat_map<IndexType, Tensor>)>;
 
   // Process a data mapping with a customized index type and return the tensor
-  // values in |callback|.
+  // values in |callback|. Appends the input to the provided `result` and
+  // returns it.
   template <typename IndexType>
   void ProcessIndexType(
       base::flat_map<IndexType, proto::CustomInput> custom_inputs,
       std::unique_ptr<FeatureProcessorState> feature_processor_state,
+      std::unique_ptr<base::flat_map<IndexType, Tensor>> result,
       TemplateCallback<IndexType> callback);
 
  private:
-  // Helper function for parsing a single custom input and insert the result
-  // along with the corresponding feature index.
+  // Helper method to handle async custom inputs for `ProcessIndexType()`
+  template <typename IndexType>
+  void OnGotProcessedValue(
+      base::flat_map<IndexType, proto::CustomInput> custom_inputs,
+      std::unique_ptr<FeatureProcessorState> feature_processor_state,
+      std::unique_ptr<base::flat_map<IndexType, Tensor>> result,
+      TemplateCallback<IndexType> callback,
+      IndexType current_index,
+      size_t current_tensor_length,
+      bool error,
+      Tensor current_value);
+
+  // Helper function for parsing a single sync custom input and insert the
+  // result along with the corresponding feature index.
   QueryProcessor::Tensor ProcessSingleCustomInput(
       const proto::CustomInput& custom_input,
       FeatureProcessorState* feature_processor_state);
@@ -81,9 +97,7 @@
   bool AddTimeRangeBeforePrediction(const proto::CustomInput& custom_input,
                                     std::vector<ProcessedValue>& out_tensor);
 
-  bool AddPriceTrackingHints(const proto::CustomInput& custom_input,
-                             FeatureProcessorState* feature_processor_state,
-                             std::vector<ProcessedValue>& out_tensor);
+  const raw_ptr<InputDelegateHolder> input_delegate_holder_;
 
   // List of custom inputs to process into input tensors.
   base::flat_map<FeatureIndex, proto::CustomInput> custom_inputs_;
diff --git a/components/segmentation_platform/internal/execution/processing/custom_input_processor_unittest.cc b/components/segmentation_platform/internal/execution/processing/custom_input_processor_unittest.cc
index 70aa3cc..552b951 100644
--- a/components/segmentation_platform/internal/execution/processing/custom_input_processor_unittest.cc
+++ b/components/segmentation_platform/internal/execution/processing/custom_input_processor_unittest.cc
@@ -8,15 +8,32 @@
 
 #include "base/bind.h"
 #include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
 #include "base/test/simple_test_clock.h"
 #include "base/test/task_environment.h"
 #include "components/segmentation_platform/internal/database/ukm_types.h"
 #include "components/segmentation_platform/internal/execution/processing/feature_processor_state.h"
+#include "components/segmentation_platform/internal/execution/processing/input_delegate.h"
 #include "components/segmentation_platform/internal/execution/processing/query_processor.h"
 #include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace segmentation_platform::processing {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+
+class MockInputDelegate : public InputDelegate {
+ public:
+  MOCK_METHOD3(Process,
+               void(const proto::CustomInput& input,
+                    const FeatureProcessorState& feature_processor_state,
+                    ProcessedCallback callback));
+};
+
+}  // namespace
 
 class CustomInputProcessorTest : public testing::Test {
  public:
@@ -26,8 +43,8 @@
   void SetUp() override {
     clock_.SetNow(base::Time::Now());
     feature_processor_state_ = std::make_unique<FeatureProcessorState>();
-    custom_input_processor_sql_ =
-        std::make_unique<CustomInputProcessor>(clock_.Now());
+    custom_input_processor_sql_ = std::make_unique<CustomInputProcessor>(
+        clock_.Now(), &input_delegate_holder_);
   }
 
   void TearDown() override {
@@ -60,7 +77,8 @@
       bool expected_error,
       const base::flat_map<int, QueryProcessor::Tensor>& expected_result) {
     std::unique_ptr<CustomInputProcessor> custom_input_processor =
-        std::make_unique<CustomInputProcessor>(std::move(data), clock_.Now());
+        std::make_unique<CustomInputProcessor>(std::move(data), clock_.Now(),
+                                               &input_delegate_holder_);
     std::unique_ptr<FeatureProcessorState> feature_processor_state =
         std::make_unique<FeatureProcessorState>();
 
@@ -83,6 +101,7 @@
     base::RunLoop loop;
     custom_input_processor_sql_->ProcessIndexType<IndexType>(
         data, std::move(feature_processor_state_),
+        std::make_unique<base::flat_map<IndexType, Tensor>>(),
         base::BindOnce(
             &CustomInputProcessorTest::OnProcessingFinishedCallback<IndexType>,
             base::Unretained(this), loop.QuitClosure(), expected_error,
@@ -106,6 +125,7 @@
   base::test::TaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   base::SimpleTestClock clock_;
+  InputDelegateHolder input_delegate_holder_;
   std::unique_ptr<FeatureProcessorState> feature_processor_state_;
   std::unique_ptr<CustomInputProcessor> custom_input_processor_sql_;
 };
@@ -202,7 +222,51 @@
                              expected_result);
 }
 
+TEST_F(CustomInputProcessorTest, InputDelegateFailure) {
+  auto moved_delegate = std::make_unique<MockInputDelegate>();
+  MockInputDelegate* delegate = moved_delegate.get();
+  input_delegate_holder_.SetDelegate(proto::CustomInput::PRICE_TRACKING_HINTS,
+                                     std::move(moved_delegate));
+
+  int index = 0;
+  base::flat_map<int, proto::CustomInput> data;
+  data[index] =
+      CreateCustomInput(2, proto::CustomInput::PRICE_TRACKING_HINTS, {}, {});
+
+  EXPECT_CALL(*delegate, Process(_, _, _))
+      .WillOnce(RunOnceCallback<2>(true, Tensor()));
+  base::flat_map<int, QueryProcessor::Tensor> expected_result;
+  ExpectProcessedCustomInput(std::move(data), /*expected_error=*/true,
+                             expected_result);
+}
+
+TEST_F(CustomInputProcessorTest, InputDelegate) {
+  auto moved_delegate = std::make_unique<MockInputDelegate>();
+  MockInputDelegate* delegate = moved_delegate.get();
+  input_delegate_holder_.SetDelegate(proto::CustomInput::PRICE_TRACKING_HINTS,
+                                     std::move(moved_delegate));
+
+  int index = 0;
+  base::flat_map<int, proto::CustomInput> data;
+  data[index] =
+      CreateCustomInput(2, proto::CustomInput::PRICE_TRACKING_HINTS, {}, {});
+
+  Tensor result{ProcessedValue(1), ProcessedValue(2)};
+  EXPECT_CALL(*delegate, Process(_, _, _))
+      .WillOnce(RunOnceCallback<2>(false, result));
+  base::flat_map<int, QueryProcessor::Tensor> expected_result{{index, result}};
+  ExpectProcessedCustomInput(std::move(data), /*expected_error=*/false,
+                             expected_result);
+}
+
 TEST_F(CustomInputProcessorTest, MultipleFillTypesCustomInputs) {
+  auto moved_delegate = std::make_unique<MockInputDelegate>();
+  MockInputDelegate* delegate = moved_delegate.get();
+  input_delegate_holder_.SetDelegate(proto::CustomInput::PRICE_TRACKING_HINTS,
+                                     std::move(moved_delegate));
+  EXPECT_CALL(*delegate, Process(_, _, _))
+      .WillOnce(RunOnceCallback<2>(false, Tensor{ProcessedValue(1)}));
+
   // Create custom inputs data.
   base::flat_map<int, proto::CustomInput> data;
   data[0] =
@@ -211,6 +275,8 @@
       CreateCustomInput(2, proto::CustomInput::UNKNOWN_FILL_POLICY, {1, 2}, {});
   data[2] =
       CreateCustomInput(1, proto::CustomInput::UNKNOWN_FILL_POLICY, {3}, {});
+  data[3] =
+      CreateCustomInput(1, proto::CustomInput::PRICE_TRACKING_HINTS, {}, {});
 
   // Set expected tensor result.
   base::flat_map<int, QueryProcessor::Tensor> expected_result;
@@ -218,6 +284,7 @@
   expected_result[1] = {ProcessedValue(static_cast<float>(1)),
                         ProcessedValue(static_cast<float>(2))};
   expected_result[2] = {ProcessedValue(static_cast<float>(3))};
+  expected_result[3] = {ProcessedValue(1)};
 
   // Process the custom inputs and verify using expected result.
   ExpectProcessedCustomInput(std::move(data), /*expected_error=*/false,
diff --git a/components/segmentation_platform/internal/execution/processing/feature_list_query_processor.cc b/components/segmentation_platform/internal/execution/processing/feature_list_query_processor.cc
index 3dd3185..b15a732 100644
--- a/components/segmentation_platform/internal/execution/processing/feature_list_query_processor.cc
+++ b/components/segmentation_platform/internal/execution/processing/feature_list_query_processor.cc
@@ -13,6 +13,7 @@
 #include "components/segmentation_platform/internal/database/ukm_types.h"
 #include "components/segmentation_platform/internal/execution/processing/custom_input_processor.h"
 #include "components/segmentation_platform/internal/execution/processing/feature_processor_state.h"
+#include "components/segmentation_platform/internal/execution/processing/input_delegate.h"
 #include "components/segmentation_platform/internal/execution/processing/sql_feature_processor.h"
 #include "components/segmentation_platform/internal/execution/processing/uma_feature_processor.h"
 #include "components/segmentation_platform/internal/metadata/metadata_utils.h"
@@ -29,8 +30,10 @@
 
 FeatureListQueryProcessor::FeatureListQueryProcessor(
     StorageService* storage_service,
+    std::unique_ptr<InputDelegateHolder> input_delegate_holder,
     std::unique_ptr<FeatureAggregator> feature_aggregator)
     : storage_service_(storage_service),
+      input_delegate_holder_(std::move(input_delegate_holder)),
       feature_aggregator_(std::move(feature_aggregator)) {}
 
 FeatureListQueryProcessor::~FeatureListQueryProcessor() = default;
@@ -106,7 +109,8 @@
       base::flat_map<QueryProcessor::FeatureIndex, proto::CustomInput> queries =
           {{kIndexNotUsed, data.input_feature->custom_input()}};
       processor = std::make_unique<CustomInputProcessor>(
-          std::move(queries), feature_processor_state->prediction_time());
+          std::move(queries), feature_processor_state->prediction_time(),
+          input_delegate_holder_.get());
     } else if (data.input_feature->has_sql_feature()) {
       auto* ukm_manager = storage_service_->ukm_data_manager();
       if (!ukm_manager->IsUkmEngineEnabled()) {
@@ -119,7 +123,7 @@
           {kIndexNotUsed, data.input_feature->sql_feature()}};
       processor = std::make_unique<SqlFeatureProcessor>(
           std::move(queries), feature_processor_state->prediction_time(),
-          ukm_manager->GetUkmDatabase());
+          input_delegate_holder_.get(), ukm_manager->GetUkmDatabase());
     }
   } else {
     // Process output features
diff --git a/components/segmentation_platform/internal/execution/processing/feature_list_query_processor.h b/components/segmentation_platform/internal/execution/processing/feature_list_query_processor.h
index 608a4fd..6ade8ce5 100644
--- a/components/segmentation_platform/internal/execution/processing/feature_list_query_processor.h
+++ b/components/segmentation_platform/internal/execution/processing/feature_list_query_processor.h
@@ -25,6 +25,7 @@
 
 class FeatureAggregator;
 class FeatureProcessorState;
+class InputDelegateHolder;
 
 using proto::SegmentId;
 
@@ -35,6 +36,7 @@
  public:
   FeatureListQueryProcessor(
       StorageService* storage_service,
+      std::unique_ptr<InputDelegateHolder> input_delegate_holder,
       std::unique_ptr<FeatureAggregator> feature_aggregator);
   virtual ~FeatureListQueryProcessor();
 
@@ -90,12 +92,12 @@
   // Storage service which provides signals to process.
   const raw_ptr<StorageService> storage_service_;
 
+  // Holds InputDelegate for feature processing.
+  std::unique_ptr<InputDelegateHolder> input_delegate_holder_;
+
   // Feature aggregator that aggregates data for uma features.
   const std::unique_ptr<FeatureAggregator> feature_aggregator_;
 
-  // Feature processor for uma type of input features.
-  CustomInputProcessor custom_input_processor_;
-
   base::WeakPtrFactory<FeatureListQueryProcessor> weak_ptr_factory_{this};
 };
 
diff --git a/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc b/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc
index e3fe6488..4380ae64 100644
--- a/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc
+++ b/components/segmentation_platform/internal/execution/processing/feature_list_query_processor_unittest.cc
@@ -17,6 +17,7 @@
 #include "components/segmentation_platform/internal/database/signal_storage_config.h"
 #include "components/segmentation_platform/internal/database/storage_service.h"
 #include "components/segmentation_platform/internal/execution/default_model_manager.h"
+#include "components/segmentation_platform/internal/execution/processing/input_delegate.h"
 #include "components/segmentation_platform/internal/execution/processing/mock_feature_aggregator.h"
 #include "components/segmentation_platform/internal/mock_ukm_data_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -60,7 +61,9 @@
     auto feature_aggregator = std::make_unique<MockFeatureAggregator>();
     feature_aggregator_ = feature_aggregator.get();
     feature_list_query_processor_ = std::make_unique<FeatureListQueryProcessor>(
-        storage_service_.get(), std::move(feature_aggregator));
+        storage_service_.get(),
+        std::make_unique<processing::InputDelegateHolder>(),
+        std::move(feature_aggregator));
   }
 
   void SetBucketDuration(uint64_t bucket_duration, proto::TimeUnit time_unit) {
diff --git a/components/segmentation_platform/internal/execution/processing/feature_processor_state.h b/components/segmentation_platform/internal/execution/processing/feature_processor_state.h
index 68e0d96..befb0f4 100644
--- a/components/segmentation_platform/internal/execution/processing/feature_processor_state.h
+++ b/components/segmentation_platform/internal/execution/processing/feature_processor_state.h
@@ -63,7 +63,9 @@
 
   bool error() const { return error_; }
 
-  scoped_refptr<InputContext> input_context() { return input_context_; }
+  const scoped_refptr<InputContext> input_context() const {
+    return input_context_;
+  }
 
   // Returns and pops the next input feature or output feature, wrapped inside
   // `Data` structure. Return an empty struct if no input and output are
diff --git a/components/segmentation_platform/internal/execution/processing/input_delegate.cc b/components/segmentation_platform/internal/execution/processing/input_delegate.cc
new file mode 100644
index 0000000..c4e4df8
--- /dev/null
+++ b/components/segmentation_platform/internal/execution/processing/input_delegate.cc
@@ -0,0 +1,30 @@
+// Copyright 2022 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/segmentation_platform/internal/execution/processing/input_delegate.h"
+
+namespace segmentation_platform::processing {
+
+InputDelegate::InputDelegate() = default;
+InputDelegate::~InputDelegate() = default;
+
+InputDelegateHolder::InputDelegateHolder() = default;
+InputDelegateHolder::~InputDelegateHolder() = default;
+
+InputDelegate* InputDelegateHolder::GetDelegate(
+    proto::CustomInput::FillPolicy policy) {
+  auto it = input_delegates_.find(policy);
+  if (it != input_delegates_.end()) {
+    return it->second.get();
+  }
+  return nullptr;
+}
+
+void InputDelegateHolder::SetDelegate(proto::CustomInput::FillPolicy policy,
+                                      std::unique_ptr<InputDelegate> delegate) {
+  DCHECK(!input_delegates_.count(policy));
+  input_delegates_[policy] = std::move(delegate);
+}
+
+}  // namespace segmentation_platform::processing
diff --git a/components/segmentation_platform/internal/execution/processing/input_delegate.h b/components/segmentation_platform/internal/execution/processing/input_delegate.h
new file mode 100644
index 0000000..bf7defbc
--- /dev/null
+++ b/components/segmentation_platform/internal/execution/processing/input_delegate.h
@@ -0,0 +1,60 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_PROCESSING_INPUT_DELEGATE_H_
+#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_PROCESSING_INPUT_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/containers/flat_map.h"
+#include "components/segmentation_platform/internal/database/ukm_types.h"
+#include "components/segmentation_platform/internal/proto/model_metadata.pb.h"
+
+namespace segmentation_platform::processing {
+
+class FeatureProcessorState;
+
+// Delegate that provides inputs to the query processor that computes input and
+// output features.
+class InputDelegate {
+ public:
+  InputDelegate();
+  virtual ~InputDelegate();
+
+  InputDelegate(InputDelegate&) = delete;
+  InputDelegate& operator=(InputDelegate&) = delete;
+
+  // Processes the given `input`, and returns the result via `callback`. Should
+  // return an error if the processing failed. On success, the number of outputs
+  // in the Tensor should be equal to `input.tensor_length()`.
+  using ProcessedCallback = base::OnceCallback<void(/*error=*/bool, Tensor)>;
+  virtual void Process(const proto::CustomInput& input,
+                       const FeatureProcessorState& feature_processor_state,
+                       ProcessedCallback callback) = 0;
+};
+
+// A holder that stores the list of `InputDelegate`s used by the platform.
+class InputDelegateHolder {
+ public:
+  InputDelegateHolder();
+  ~InputDelegateHolder();
+
+  InputDelegateHolder(InputDelegateHolder&) = delete;
+  InputDelegateHolder& operator=(InputDelegateHolder&) = delete;
+
+  // Returns a delegate for the `policy` if available or nullptr otherwise.
+  InputDelegate* GetDelegate(proto::CustomInput::FillPolicy policy);
+
+  // Sets a delegate for the given `policy`. Overwrites any existing delegates
+  // for the same `policy`
+  void SetDelegate(proto::CustomInput::FillPolicy policy,
+                   std::unique_ptr<InputDelegate> delegate);
+
+ private:
+  base::flat_map<proto::CustomInput::FillPolicy, std::unique_ptr<InputDelegate>>
+      input_delegates_;
+};
+
+}  // namespace segmentation_platform::processing
+
+#endif  // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_PROCESSING_INPUT_DELEGATE_H_
diff --git a/components/segmentation_platform/internal/execution/processing/mock_feature_list_query_processor.cc b/components/segmentation_platform/internal/execution/processing/mock_feature_list_query_processor.cc
index 56ea14b6..e493f81 100644
--- a/components/segmentation_platform/internal/execution/processing/mock_feature_list_query_processor.cc
+++ b/components/segmentation_platform/internal/execution/processing/mock_feature_list_query_processor.cc
@@ -4,10 +4,12 @@
 
 #include "components/segmentation_platform/internal/execution/processing/mock_feature_list_query_processor.h"
 
+#include "components/segmentation_platform/internal/execution/processing/input_delegate.h"
+
 namespace segmentation_platform::processing {
 
 MockFeatureListQueryProcessor::MockFeatureListQueryProcessor()
-    : FeatureListQueryProcessor(nullptr, nullptr) {}
+    : FeatureListQueryProcessor(nullptr, nullptr, nullptr) {}
 
 MockFeatureListQueryProcessor::~MockFeatureListQueryProcessor() = default;
 
diff --git a/components/segmentation_platform/internal/execution/processing/sql_feature_processor.cc b/components/segmentation_platform/internal/execution/processing/sql_feature_processor.cc
index fc7f7a48..20f96f5 100644
--- a/components/segmentation_platform/internal/execution/processing/sql_feature_processor.cc
+++ b/components/segmentation_platform/internal/execution/processing/sql_feature_processor.cc
@@ -15,11 +15,14 @@
 
 namespace segmentation_platform::processing {
 
-SqlFeatureProcessor::SqlFeatureProcessor(QueryList&& queries,
-                                         base::Time prediction_time,
-                                         UkmDatabase* ukm_database)
+SqlFeatureProcessor::SqlFeatureProcessor(
+    QueryList&& queries,
+    base::Time prediction_time,
+    InputDelegateHolder* input_delegate_holder,
+    UkmDatabase* ukm_database)
     : queries_(std::move(queries)),
       prediction_time_(prediction_time),
+      input_delegate_holder_(input_delegate_holder),
       ukm_database_(ukm_database) {}
 SqlFeatureProcessor::~SqlFeatureProcessor() = default;
 
@@ -59,11 +62,12 @@
   }
 
   // Process the indexed custom inputs
-  auto custom_input_processor =
-      std::make_unique<CustomInputProcessor>(prediction_time_);
+  auto custom_input_processor = std::make_unique<CustomInputProcessor>(
+      prediction_time_, input_delegate_holder_);
   auto* custom_input_processor_ptr = custom_input_processor.get();
   custom_input_processor_ptr->ProcessIndexType<SqlFeatureAndBindValueIndices>(
       std::move(bind_values), std::move(feature_processor_state),
+      std::make_unique<base::flat_map<std::pair<int, int>, Tensor>>(),
       base::BindOnce(&SqlFeatureProcessor::OnCustomInputProcessed,
                      weak_ptr_factory_.GetWeakPtr(),
                      std::move(custom_input_processor)));
diff --git a/components/segmentation_platform/internal/execution/processing/sql_feature_processor.h b/components/segmentation_platform/internal/execution/processing/sql_feature_processor.h
index a13470a..96c3ba1 100644
--- a/components/segmentation_platform/internal/execution/processing/sql_feature_processor.h
+++ b/components/segmentation_platform/internal/execution/processing/sql_feature_processor.h
@@ -17,6 +17,7 @@
 namespace segmentation_platform::processing {
 class CustomInputProcessor;
 class FeatureProcessorState;
+class InputDelegateHolder;
 
 // SqlFeatureProcessor takes a list of SqlFeature type of input, fetches samples
 // from the UKMDatabase, and computes an input tensor to use when executing the
@@ -27,6 +28,7 @@
 
   SqlFeatureProcessor(QueryList&& queries,
                       base::Time prediction_time,
+                      InputDelegateHolder* input_delegate_holder,
                       UkmDatabase* ukm_database);
   ~SqlFeatureProcessor() override;
 
@@ -57,6 +59,8 @@
   // Time at which we expect the model execution to run.
   const base::Time prediction_time_;
 
+  const raw_ptr<InputDelegateHolder> input_delegate_holder_;
+
   // Main database for fetching data.
   const raw_ptr<UkmDatabase> ukm_database_;
 
diff --git a/components/segmentation_platform/internal/execution/processing/sql_feature_processor_unittest.cc b/components/segmentation_platform/internal/execution/processing/sql_feature_processor_unittest.cc
index 1c9f117..6f07e35 100644
--- a/components/segmentation_platform/internal/execution/processing/sql_feature_processor_unittest.cc
+++ b/components/segmentation_platform/internal/execution/processing/sql_feature_processor_unittest.cc
@@ -13,6 +13,7 @@
 #include "components/segmentation_platform/internal/database/mock_ukm_database.h"
 #include "components/segmentation_platform/internal/database/ukm_types.h"
 #include "components/segmentation_platform/internal/execution/processing/feature_processor_state.h"
+#include "components/segmentation_platform/internal/execution/processing/input_delegate.h"
 #include "components/segmentation_platform/internal/proto/model_metadata.pb.h"
 #include "components/segmentation_platform/public/proto/segmentation_platform.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -71,6 +72,7 @@
     // Initialize the sql feature processor.
     std::unique_ptr<SqlFeatureProcessor> processor =
         std::make_unique<SqlFeatureProcessor>(std::move(data), clock_.Now(),
+                                              &input_delegate_holder_,
                                               ukm_database_.get());
 
     EXPECT_CALL(*ukm_database_, RunReadonlyQueries)
@@ -107,6 +109,7 @@
   base::test::TaskEnvironment task_envåironment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   base::SimpleTestClock clock_;
+  InputDelegateHolder input_delegate_holder_;
   std::unique_ptr<FeatureProcessorState> feature_processor_state_;
   std::unique_ptr<MockUkmDatabase> ukm_database_;
 };
diff --git a/components/segmentation_platform/internal/scheduler/execution_service.cc b/components/segmentation_platform/internal/scheduler/execution_service.cc
index 26b092c..631fe77 100644
--- a/components/segmentation_platform/internal/scheduler/execution_service.cc
+++ b/components/segmentation_platform/internal/scheduler/execution_service.cc
@@ -12,6 +12,7 @@
 #include "components/segmentation_platform/internal/execution/model_executor_impl.h"
 #include "components/segmentation_platform/internal/execution/processing/feature_aggregator_impl.h"
 #include "components/segmentation_platform/internal/execution/processing/feature_list_query_processor.h"
+#include "components/segmentation_platform/internal/execution/processing/input_delegate.h"
 #include "components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.h"
 #include "components/segmentation_platform/internal/segmentation_ukm_helper.h"
 #include "components/segmentation_platform/internal/signals/signal_handler.h"
@@ -44,13 +45,14 @@
     ModelProviderFactory* model_provider_factory,
     std::vector<ModelExecutionScheduler::Observer*>&& observers,
     const PlatformOptions& platform_options,
+    std::unique_ptr<processing::InputDelegateHolder> input_delegate_holder,
     std::vector<std::unique_ptr<Config>>* configs,
     PrefService* profile_prefs) {
   storage_service_ = storage_service;
 
   feature_list_query_processor_ =
       std::make_unique<processing::FeatureListQueryProcessor>(
-          storage_service,
+          storage_service, std::move(input_delegate_holder),
           std::make_unique<processing::FeatureAggregatorImpl>());
 
   training_data_collector_ = TrainingDataCollector::Create(
diff --git a/components/segmentation_platform/internal/scheduler/execution_service.h b/components/segmentation_platform/internal/scheduler/execution_service.h
index 58ec883..7bcf5fd 100644
--- a/components/segmentation_platform/internal/scheduler/execution_service.h
+++ b/components/segmentation_platform/internal/scheduler/execution_service.h
@@ -22,6 +22,7 @@
 namespace segmentation_platform {
 namespace processing {
 class FeatureListQueryProcessor;
+class InputDelegateHolder;
 }
 
 struct Config;
@@ -57,6 +58,7 @@
       ModelProviderFactory* model_provider_factory,
       std::vector<ModelExecutionScheduler::Observer*>&& observers,
       const PlatformOptions& platform_options,
+      std::unique_ptr<processing::InputDelegateHolder> input_delegate_holder,
       std::vector<std::unique_ptr<Config>>* configs,
       PrefService* profile_prefs);
 
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
index 2b6d6b9..18680a3d 100644
--- a/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
+++ b/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
@@ -19,6 +19,7 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/segmentation_platform/internal/constants.h"
 #include "components/segmentation_platform/internal/database/storage_service.h"
+#include "components/segmentation_platform/internal/execution/processing/input_delegate.h"
 #include "components/segmentation_platform/internal/platform_options.h"
 #include "components/segmentation_platform/internal/proto/model_prediction.pb.h"
 #include "components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.h"
@@ -57,6 +58,7 @@
       task_runner_(init_params->task_runner),
       clock_(init_params->clock),
       platform_options_(PlatformOptions::CreateDefault()),
+      input_delegate_holder_(std::move(init_params->input_delegate_holder)),
       configs_(std::move(init_params->configs)),
       all_segment_ids_(GetAllSegmentIds(configs_)),
       field_trial_register_(std::move(init_params->field_trial_register)),
@@ -228,7 +230,8 @@
           &SegmentationPlatformServiceImpl::OnSegmentationModelUpdated,
           weak_ptr_factory_.GetWeakPtr()),
       task_runner_, all_segment_ids_, model_provider_factory_.get(),
-      std::move(observers), platform_options_, &configs_, profile_prefs_);
+      std::move(observers), platform_options_,
+      std::move(input_delegate_holder_), &configs_, profile_prefs_);
 
   proxy_->SetExecutionService(&execution_service_);
 
diff --git a/components/segmentation_platform/internal/segmentation_platform_service_impl.h b/components/segmentation_platform/internal/segmentation_platform_service_impl.h
index afa49dc..b270fb78 100644
--- a/components/segmentation_platform/internal/segmentation_platform_service_impl.h
+++ b/components/segmentation_platform/internal/segmentation_platform_service_impl.h
@@ -41,6 +41,10 @@
 
 namespace segmentation_platform {
 
+namespace processing {
+class InputDelegateHolder;
+}
+
 struct Config;
 class FieldTrialRegister;
 class ModelProviderFactory;
@@ -57,15 +61,18 @@
 
     bool IsValid();
 
+    // Profile data:
     leveldb_proto::ProtoDatabaseProvider* db_provider = nullptr;
     history::HistoryService* history_service = nullptr;
     base::FilePath storage_dir;
     PrefService* profile_prefs = nullptr;
 
+    // Platform configuration:
     std::unique_ptr<ModelProviderFactory> model_provider;
     UkmDataManager* ukm_data_manager = nullptr;
     std::vector<std::unique_ptr<Config>> configs;
     std::unique_ptr<FieldTrialRegister> field_trial_register;
+    std::unique_ptr<processing::InputDelegateHolder> input_delegate_holder;
 
     scoped_refptr<base::SequencedTaskRunner> task_runner;
     base::Clock* clock = nullptr;
@@ -135,6 +142,9 @@
   raw_ptr<base::Clock> clock_;
   const PlatformOptions platform_options_;
 
+  // Temporarily stored till initialization and moved to `execution_service_`.
+  std::unique_ptr<processing::InputDelegateHolder> input_delegate_holder_;
+
   // Config.
   std::vector<std::unique_ptr<Config>> configs_;
   base::flat_set<proto::SegmentId> all_segment_ids_;
diff --git a/components/services/app_service/app_service_mojom_impl.cc b/components/services/app_service/app_service_mojom_impl.cc
index c3362fa..57d2317 100644
--- a/components/services/app_service/app_service_mojom_impl.cc
+++ b/components/services/app_service/app_service_mojom_impl.cc
@@ -263,17 +263,7 @@
 void AppServiceMojomImpl::RemovePreferredApp(apps::mojom::AppType app_type,
                                              const std::string& app_id) {
   if (preferred_apps_impl_) {
-    preferred_apps_impl_->RemovePreferredApp(app_type, app_id);
-  }
-}
-
-void AppServiceMojomImpl::RemovePreferredAppForFilter(
-    apps::mojom::AppType app_type,
-    const std::string& app_id,
-    apps::mojom::IntentFilterPtr intent_filter) {
-  if (preferred_apps_impl_) {
-    preferred_apps_impl_->RemovePreferredAppForFilter(app_type, app_id,
-                                                      std::move(intent_filter));
+    preferred_apps_impl_->RemovePreferredApp(app_id);
   }
 }
 
diff --git a/components/services/app_service/app_service_mojom_impl.h b/components/services/app_service/app_service_mojom_impl.h
index 041b193..162bef0 100644
--- a/components/services/app_service/app_service_mojom_impl.h
+++ b/components/services/app_service/app_service_mojom_impl.h
@@ -109,10 +109,6 @@
                        bool from_publisher) override;
   void RemovePreferredApp(apps::mojom::AppType app_type,
                           const std::string& app_id) override;
-  void RemovePreferredAppForFilter(
-      apps::mojom::AppType app_type,
-      const std::string& app_id,
-      apps::mojom::IntentFilterPtr intent_filter) override;
   void SetSupportedLinksPreference(
       apps::mojom::AppType app_type,
       const std::string& app_id,
diff --git a/components/services/app_service/app_service_mojom_impl_unittest.cc b/components/services/app_service/app_service_mojom_impl_unittest.cc
index 2756678..d0f3308 100644
--- a/components/services/app_service/app_service_mojom_impl_unittest.cc
+++ b/components/services/app_service/app_service_mojom_impl_unittest.cc
@@ -479,19 +479,6 @@
             sub0.PreferredApps().FindPreferredAppForUrl(another_filter_url));
   EXPECT_EQ(kAppId2,
             sub1.PreferredApps().FindPreferredAppForUrl(another_filter_url));
-
-  // Test that remove setting for one filter.
-  impl.RemovePreferredAppForFilter(apps::mojom::AppType::kUnknown, kAppId2,
-                                   intent_filter->Clone());
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(absl::nullopt,
-            sub0.PreferredApps().FindPreferredAppForUrl(filter_url));
-  EXPECT_EQ(absl::nullopt,
-            sub1.PreferredApps().FindPreferredAppForUrl(filter_url));
-  EXPECT_EQ(kAppId2,
-            sub0.PreferredApps().FindPreferredAppForUrl(another_filter_url));
-  EXPECT_EQ(kAppId2,
-            sub1.PreferredApps().FindPreferredAppForUrl(another_filter_url));
 }
 
 // Tests that writing a preferred app value before the PreferredAppsList is
@@ -718,19 +705,6 @@
   EXPECT_EQ(kAppId2, sub0.PreferredApps().FindPreferredAppForUrl(filter_url_3));
   EXPECT_EQ(1U, impl.GetPreferredAppsListForTesting().GetEntrySize());
   EXPECT_EQ(1U, sub0.PreferredApps().GetEntrySize());
-
-  // Test that can remove entry with overlapped filter.
-  impl.RemovePreferredAppForFilter(apps::mojom::AppType::kArc, kAppId2,
-                                   intent_filter_1->Clone());
-  task_environment_.RunUntilIdle();
-  EXPECT_EQ(absl::nullopt,
-            sub0.PreferredApps().FindPreferredAppForUrl(filter_url_1));
-  EXPECT_EQ(absl::nullopt,
-            sub0.PreferredApps().FindPreferredAppForUrl(filter_url_2));
-  EXPECT_EQ(absl::nullopt,
-            sub0.PreferredApps().FindPreferredAppForUrl(filter_url_3));
-  EXPECT_EQ(0U, impl.GetPreferredAppsListForTesting().GetEntrySize());
-  EXPECT_EQ(0U, sub0.PreferredApps().GetEntrySize());
 }
 
 // Test that app with overlapped supported links works properly.
diff --git a/components/services/app_service/public/cpp/preferred_apps_impl.cc b/components/services/app_service/public/cpp/preferred_apps_impl.cc
index 13eac3e..4c2b38c 100644
--- a/components/services/app_service/public/cpp/preferred_apps_impl.cc
+++ b/components/services/app_service/public/cpp/preferred_apps_impl.cc
@@ -107,21 +107,10 @@
       from_publisher));
 }
 
-void PreferredAppsImpl::RemovePreferredApp(apps::mojom::AppType app_type,
-                                           const std::string& app_id) {
+void PreferredAppsImpl::RemovePreferredApp(const std::string& app_id) {
   RunAfterPreferredAppsReady(
       base::BindOnce(&PreferredAppsImpl::RemovePreferredAppImpl,
-                     weak_ptr_factory_.GetWeakPtr(), app_type, app_id));
-}
-
-void PreferredAppsImpl::RemovePreferredAppForFilter(
-    apps::mojom::AppType app_type,
-    const std::string& app_id,
-    apps::mojom::IntentFilterPtr intent_filter) {
-  RunAfterPreferredAppsReady(
-      base::BindOnce(&PreferredAppsImpl::RemovePreferredAppForFilterImpl,
-                     weak_ptr_factory_.GetWeakPtr(), app_type, app_id,
-                     std::move(intent_filter)));
+                     weak_ptr_factory_.GetWeakPtr(), app_id));
 }
 
 void PreferredAppsImpl::SetSupportedLinksPreference(
@@ -296,8 +285,7 @@
                            std::move(replaced_apps));
 }
 
-void PreferredAppsImpl::RemovePreferredAppImpl(apps::mojom::AppType app_type,
-                                               const std::string& app_id) {
+void PreferredAppsImpl::RemovePreferredAppImpl(const std::string& app_id) {
   IntentFilters removed_filters = preferred_apps_list_.DeleteAppId(app_id);
   if (!removed_filters.empty()) {
     WriteToJSON(profile_dir_, preferred_apps_list_);
@@ -308,22 +296,6 @@
   }
 }
 
-void PreferredAppsImpl::RemovePreferredAppForFilterImpl(
-    apps::mojom::AppType app_type,
-    const std::string& app_id,
-    apps::mojom::IntentFilterPtr mojom_intent_filter) {
-  IntentFilters removed_filters = preferred_apps_list_.DeletePreferredApp(
-      app_id, ConvertMojomIntentFilterToIntentFilter(mojom_intent_filter));
-
-  if (!removed_filters.empty()) {
-    WriteToJSON(profile_dir_, preferred_apps_list_);
-
-    auto changes = std::make_unique<PreferredAppChanges>();
-    changes->removed_filters[app_id] = std::move(removed_filters);
-    host_->OnPreferredAppsChanged(std::move(changes));
-  }
-}
-
 void PreferredAppsImpl::SetSupportedLinksPreferenceImpl(
     AppType app_type,
     const std::string& app_id,
diff --git a/components/services/app_service/public/cpp/preferred_apps_impl.h b/components/services/app_service/public/cpp/preferred_apps_impl.h
index 21cdc31..140a5c17 100644
--- a/components/services/app_service/public/cpp/preferred_apps_impl.h
+++ b/components/services/app_service/public/cpp/preferred_apps_impl.h
@@ -74,11 +74,7 @@
                        apps::mojom::IntentFilterPtr intent_filter,
                        apps::mojom::IntentPtr intent,
                        bool from_publisher);
-  void RemovePreferredApp(apps::mojom::AppType app_type,
-                          const std::string& app_id);
-  void RemovePreferredAppForFilter(apps::mojom::AppType app_type,
-                                   const std::string& app_id,
-                                   apps::mojom::IntentFilterPtr intent_filter);
+  void RemovePreferredApp(const std::string& app_id);
   void SetSupportedLinksPreference(AppType app_type,
                                    const std::string& app_id,
                                    IntentFilters all_link_filters);
@@ -114,12 +110,7 @@
                            apps::mojom::IntentFilterPtr intent_filter,
                            apps::mojom::IntentPtr intent,
                            bool from_publisher);
-  void RemovePreferredAppImpl(apps::mojom::AppType app_type,
-                              const std::string& app_id);
-  void RemovePreferredAppForFilterImpl(
-      apps::mojom::AppType app_type,
-      const std::string& app_id,
-      apps::mojom::IntentFilterPtr intent_filter);
+  void RemovePreferredAppImpl(const std::string& app_id);
   void SetSupportedLinksPreferenceImpl(AppType app_type,
                                        const std::string& app_id,
                                        IntentFilters all_link_filters);
diff --git a/components/services/app_service/public/mojom/app_service.mojom b/components/services/app_service/public/mojom/app_service.mojom
index 199129ed..c29f9e4 100644
--- a/components/services/app_service/public/mojom/app_service.mojom
+++ b/components/services/app_service/public/mojom/app_service.mojom
@@ -133,12 +133,6 @@
   // Removes all preferred app setting for an |app_id|.
   RemovePreferredApp(AppType app_type, string app_id);
 
-  // Resets app identified by |app_id| as preferred app for |intent_filter|.
-  RemovePreferredAppForFilter(
-      AppType app_type,
-      string app_id,
-      IntentFilter intent_filter);
-
   // Set |app_id| as preferred app for all its supported link filters. Supported
   // link filters, which have the http/https scheme and at least one host, are
   // always enabled/disabled as a group. |all_link_filters| should contain all
diff --git a/components/variations/variations_ids_provider.cc b/components/variations/variations_ids_provider.cc
index 28dfeb65..3cf51c5d 100644
--- a/components/variations/variations_ids_provider.cc
+++ b/components/variations/variations_ids_provider.cc
@@ -157,13 +157,13 @@
 VariationsIdsProvider::ForceIdsResult VariationsIdsProvider::ForceVariationIds(
     const std::vector<std::string>& variation_ids,
     const std::string& command_line_variation_ids) {
-  default_variation_ids_set_.clear();
+  force_enabled_ids_set_.clear();
 
-  if (!AddVariationIdsToSet(variation_ids, &default_variation_ids_set_))
+  if (!AddVariationIdsToSet(variation_ids, &force_enabled_ids_set_))
     return ForceIdsResult::INVALID_VECTOR_ENTRY;
 
   if (!ParseVariationIdsParameter(command_line_variation_ids,
-                                  &default_variation_ids_set_)) {
+                                  &force_enabled_ids_set_)) {
     return ForceIdsResult::INVALID_SWITCH_ENTRY;
   }
   if (variation_ids_cache_initialized_) {
@@ -207,7 +207,7 @@
   base::FieldTrialList::RemoveObserver(this);
   variation_ids_cache_initialized_ = false;
   variation_ids_set_.clear();
-  default_variation_ids_set_.clear();
+  force_enabled_ids_set_.clear();
   synthetic_variation_ids_set_.clear();
   force_disabled_ids_set_.clear();
   variations_headers_map_.clear();
@@ -471,7 +471,7 @@
 VariationsIdsProvider::GetAllVariationIds() {
   lock_.AssertAcquired();
 
-  std::set<VariationIDEntry> all_variation_ids_set = default_variation_ids_set_;
+  std::set<VariationIDEntry> all_variation_ids_set = force_enabled_ids_set_;
   for (const VariationIDEntry& entry : variation_ids_set_) {
     all_variation_ids_set.insert(entry);
   }
diff --git a/components/variations/variations_ids_provider.h b/components/variations/variations_ids_provider.h
index 29e32964..d812c43 100644
--- a/components/variations/variations_ids_provider.h
+++ b/components/variations/variations_ids_provider.h
@@ -240,8 +240,8 @@
       bool is_signed_in,
       Study_GoogleWebVisibility web_visibility);
 
-  // Returns the currently active set of variation ids, which includes any
-  // default values, synthetic variations and actual field trial variations.
+  // Returns the currently active set of variation ids, which includes ids from
+  // field trials, synthetic trials, and forced ids.
   std::set<VariationIDEntry> GetAllVariationIds();
 
   // Returns the collection of variation ids matching any of the given
@@ -265,8 +265,9 @@
   // This consists of a list of valid IDs, and the actual transmitted header.
   std::set<VariationIDEntry> variation_ids_set_;
 
-  // Provides the google experiment ids forced from command line.
-  std::set<VariationIDEntry> default_variation_ids_set_;
+  // Provides the google experiment ids that are force-enabled through
+  // ForceVariationIds().
+  std::set<VariationIDEntry> force_enabled_ids_set_;
 
   // Variations ids from synthetic field trials.
   std::set<VariationIDEntry> synthetic_variation_ids_set_;
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.h b/content/browser/accessibility/browser_accessibility_cocoa.h
index c985a139..e7aa1e7 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.h
+++ b/content/browser/accessibility/browser_accessibility_cocoa.h
@@ -113,9 +113,6 @@
 // on the characteristics of this accessibility node.
 - (content::BrowserAccessibility*)actionTarget;
 
-// Internally-used property.
-@property(nonatomic, readonly) NSPoint origin;
-
 @property(nonatomic, readonly) NSArray* children;
 @property(nonatomic, readonly) NSArray* columns;
 @property(nonatomic, readonly) NSValue* columnIndexRange;
@@ -150,7 +147,6 @@
 @property(nonatomic, readonly) NSString* selectedText;
 @property(nonatomic, readonly) NSValue* selectedTextRange;
 @property(nonatomic, readonly) id selectedTextMarkerRange;
-@property(nonatomic, readonly) NSValue* size;
 @property(nonatomic, readonly) NSString* sortDirection;
 // Returns a text marker that points to the first character in the document that
 // can be selected with Voiceover.
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 4a42f15..b71cf69 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -630,7 +630,6 @@
       {NSAccessibilitySelectedTextRangeAttribute, @"selectedTextRange"},
       {NSAccessibilitySelectedTextMarkerRangeAttribute,
        @"selectedTextMarkerRange"},
-      {NSAccessibilitySizeAttribute, @"size"},
       {NSAccessibilitySortDirectionAttribute, @"sortDirection"},
       {NSAccessibilitySubroleAttribute, @"subrole"},
       {NSAccessibilityTabsAttribute, @"tabs"},
@@ -1071,16 +1070,6 @@
   return nil;
 }
 
-// The origin of this accessibility object in the page's document.
-// This is relative to webkit's top-left origin, not Cocoa's
-// bottom-left origin.
-- (NSPoint)origin {
-  if (![self instanceActive])
-    return NSMakePoint(0, 0);
-  gfx::Rect bounds = _owner->GetClippedRootFrameBoundsRect();
-  return NSMakePoint(bounds.x(), bounds.y());
-}
-
 - (id)parent {
   if (![self instanceActive])
     return nil;
@@ -1101,10 +1090,7 @@
 - (NSValue*)position {
   if (![self instanceActive])
     return nil;
-  NSPoint origin = [self origin];
-  NSSize size = [[self size] sizeValue];
-  NSPoint pointInScreen =
-      [self rectInScreen:gfx::Rect(gfx::Point(origin), gfx::Size(size))].origin;
+  NSPoint pointInScreen = [self accessibilityFrame].origin;
   return [NSValue valueWithPoint:pointInScreen];
 }
 
@@ -1428,13 +1414,6 @@
   return AXRangeToAXTextMarkerRange(ax_range.AsBackwardRange());
 }
 
-- (NSValue*)size {
-  if (![self instanceActive])
-    return nil;
-  gfx::Rect bounds = _owner->GetClippedRootFrameBoundsRect();
-  return [NSValue valueWithSize:NSMakeSize(bounds.width(), bounds.height())];
-}
-
 - (NSString*)sortDirection {
   if (![self instanceActive])
     return nil;
@@ -2483,7 +2462,6 @@
                        NSAccessibilityRoleAttribute,
                        NSAccessibilityRoleDescriptionAttribute,
                        NSAccessibilitySelectedTextMarkerRangeAttribute,
-                       NSAccessibilitySizeAttribute,
                        NSAccessibilityStartTextMarkerAttribute,
                        NSAccessibilitySubroleAttribute,
                        NSAccessibilityTopLevelUIElementAttribute,
diff --git a/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm b/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm
index 0aaade5b..2101a30 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa_browsertest.mm
@@ -204,7 +204,8 @@
   ASSERT_NE(nil, cocoa_text);
 
   NSPoint position = [[cocoa_text position] pointValue];
-  NSSize size = [[cocoa_text size] sizeValue];
+
+  NSSize size = cocoa_text.accessibilityFrame.size;
   NSRect frame = NSMakeRect(position.x, position.y, size.width, size.height);
 
   NSPoint p0_before = position;
diff --git a/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc b/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
index 2f4a7d6..6574260 100644
--- a/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_scripts_browsertest.cc
@@ -381,6 +381,10 @@
   RunTypedTest<kMacAttributes>("ax-selected-rows.html");
 }
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXSize) {
+  RunTypedTest<kMacAttributes>("ax-size.html");
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityScriptTest, AXTitleUIElement) {
   RunTypedTest<kMacAttributes>("ax-title-ui-element.html");
 }
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index 5a0eb1e7..94d8edb6 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -33,6 +33,7 @@
 #include "content/browser/renderer_host/back_forward_cache_can_store_document_result.h"
 #include "content/browser/renderer_host/back_forward_cache_disable.h"
 #include "content/browser/renderer_host/back_forward_cache_metrics.h"
+#include "content/browser/renderer_host/frame_tree.h"
 #include "content/browser/renderer_host/navigation_entry_impl.h"
 #include "content/browser/renderer_host/navigation_request.h"
 #include "content/browser/renderer_host/navigator.h"
@@ -703,11 +704,11 @@
 Response PageHandler::GetNavigationHistory(
     int* current_index,
     std::unique_ptr<NavigationEntries>* entries) {
-  WebContentsImpl* web_contents = GetWebContents();
-  if (!web_contents)
-    return Response::InternalError();
+  Response response = AssureTopLevelActiveFrame(host_);
+  if (response.IsError())
+    return response;
 
-  NavigationController& controller = web_contents->GetController();
+  NavigationController& controller = host_->frame_tree()->controller();
   *current_index = controller.GetCurrentEntryIndex();
   *entries = std::make_unique<NavigationEntries>();
   for (int i = 0; i != controller.GetEntryCount(); ++i) {
@@ -725,11 +726,11 @@
 }
 
 Response PageHandler::NavigateToHistoryEntry(int entry_id) {
-  WebContentsImpl* web_contents = GetWebContents();
-  if (!web_contents)
-    return Response::InternalError();
+  Response response = AssureTopLevelActiveFrame(host_);
+  if (response.IsError())
+    return response;
 
-  NavigationController& controller = web_contents->GetController();
+  NavigationController& controller = host_->frame_tree()->controller();
   for (int i = 0; i != controller.GetEntryCount(); ++i) {
     if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) {
       controller.GoToIndex(i);
@@ -745,11 +746,11 @@
 }
 
 Response PageHandler::ResetNavigationHistory() {
-  WebContentsImpl* web_contents = GetWebContents();
-  if (!web_contents)
-    return Response::InternalError();
+  Response response = AssureTopLevelActiveFrame(host_);
+  if (response.IsError())
+    return response;
 
-  NavigationController& controller = web_contents->GetController();
+  NavigationController& controller = host_->frame_tree()->controller();
   controller.DeleteNavigationEntries(base::BindRepeating(&ReturnTrue));
   return Response::Success();
 }
diff --git a/content/browser/fenced_frame/fenced_frame.cc b/content/browser/fenced_frame/fenced_frame.cc
index 219c9e6..1a274605 100644
--- a/content/browser/fenced_frame/fenced_frame.cc
+++ b/content/browser/fenced_frame/fenced_frame.cc
@@ -10,6 +10,7 @@
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "third_party/blink/public/common/fenced_frame/fenced_frame_utils.h"
+#include "third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h"
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
 #include "url/gurl.h"
 
@@ -58,6 +59,9 @@
       SiteInstanceImpl::CreateForFencedFrame(
           owner_render_frame_host->GetSiteInstance());
 
+  // Set the mandatory sandbox flags from the beginning.
+  blink::FramePolicy frame_policy;
+  frame_policy.sandbox_flags = blink::kFencedFrameForcedSandboxFlags;
   // Note that even though this is happening in response to an event in the
   // renderer (i.e., the creation of a <fencedframe> element), we are still
   // putting `renderer_initiated_creation` as false. This is because that
@@ -68,8 +72,12 @@
   // apply for fenced frames, portals, and prerendered nested FrameTrees, hence
   // the decision to mark it as false.
   frame_tree_->Init(site_instance.get(), /*renderer_initiated_creation=*/false,
-                    /*main_frame_name=*/"", /*opener=*/nullptr,
-                    /*frame_policy=*/blink::FramePolicy());
+                    /*main_frame_name=*/"", /*opener_for_origin=*/nullptr,
+                    frame_policy);
+  // Note that pending frame policy will be passed as `frame_policy` in
+  // `replication_state` in `mojom::CreateFrameParams`.
+  // See `RenderFrameHostImpl::CreateRenderFrame`.
+  frame_tree_->root()->SetPendingFramePolicy(frame_policy);
 
   // TODO(crbug.com/1199679): This should be moved to FrameTree::Init.
   web_contents_->NotifySwappedFromRenderManager(
diff --git a/content/browser/media/media_canplaytype_browsertest.cc b/content/browser/media/media_canplaytype_browsertest.cc
index 142556bf..1309e233 100644
--- a/content/browser/media/media_canplaytype_browsertest.cc
+++ b/content/browser/media/media_canplaytype_browsertest.cc
@@ -71,7 +71,8 @@
   ExecuteTest("testMp3Variants()");
 }
 
-IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
+// TODO(https://crbug.com/1332367): Flaky.
+IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, DISABLED_CodecSupportTest_mp4) {
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
   ExecuteTest("testMp4Variants(true)");  // has_proprietary_codecs=true
 #else
diff --git a/content/browser/renderer_host/cross_origin_opener_policy_status.cc b/content/browser/renderer_host/cross_origin_opener_policy_status.cc
index 5ec4796..596bc8d 100644
--- a/content/browser/renderer_host/cross_origin_opener_policy_status.cc
+++ b/content/browser/renderer_host/cross_origin_opener_policy_status.cc
@@ -153,7 +153,10 @@
   // is not "unsafe-none". This ensures a COOP document does not inherit any
   // property from an opener.
   // https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e
+  // Don't apply the limitation to a fenced frame because the fenced frame
+  // has its own set of forced sandbox flags and it also supports COOP.
   if (coop.value != network::mojom::CrossOriginOpenerPolicyValue::kUnsafeNone &&
+      !frame_tree_node_->IsInFencedFrameTree() &&
       (frame_tree_node_->pending_frame_policy().sandbox_flags !=
        network::mojom::WebSandboxFlags::kNone)) {
     // Blob and Filesystem documents' cross-origin-opener-policy values are
diff --git a/content/test/data/accessibility/mac/attributes/ax-size-expected.txt b/content/test/data/accessibility/mac/attributes/ax-size-expected.txt
new file mode 100644
index 0000000..28234250
--- /dev/null
+++ b/content/test/data/accessibility/mac/attributes/ax-size-expected.txt
@@ -0,0 +1,4 @@
+div.accessibilityAttributeNames.has(AXSize)='yes'
+div.accessibilityAttributeValue(AXSize)={w: 784, h: 18}
+clipped.accessibilityAttributeNames.has(AXSize)='yes'
+clipped.accessibilityAttributeValue(AXSize)={w: 80, h: 36}
diff --git a/content/test/data/accessibility/mac/attributes/ax-size.html b/content/test/data/accessibility/mac/attributes/ax-size.html
new file mode 100644
index 0000000..d14bf83
--- /dev/null
+++ b/content/test/data/accessibility/mac/attributes/ax-size.html
@@ -0,0 +1,14 @@
+<!--
+@SCRIPT:
+  div.accessibilityAttributeNames.has(AXSize)
+  div.accessibilityAttributeValue(AXSize)
+  clipped.accessibilityAttributeNames.has(AXSize)
+  clipped.accessibilityAttributeValue(AXSize)
+-->
+<!DOCTYPE html>
+<div id="div">
+  This is a test.
+</div>
+<div id="clipped" style="width: 10ch; overflow:clip;">
+  This is a test.
+</div>
diff --git a/extensions/browser/api/system_display/system_display_apitest.cc b/extensions/browser/api/system_display/system_display_apitest.cc
index 970ee75..e0bf990 100644
--- a/extensions/browser/api/system_display/system_display_apitest.cc
+++ b/extensions/browser/api/system_display/system_display_apitest.cc
@@ -114,8 +114,7 @@
   std::unique_ptr<base::DictionaryValue> set_info_value =
       provider_->GetSetInfoValue();
   ASSERT_TRUE(set_info_value);
-  base::Value::DictStorage set_info =
-      std::move(*set_info_value).TakeDictDeprecated();
+  base::Value::Dict set_info = std::move(set_info_value->GetDict());
 
   EXPECT_TRUE(api_test_utils::GetBoolean(set_info, "isPrimary"));
   EXPECT_EQ("mirroringId",
@@ -123,8 +122,7 @@
   EXPECT_EQ(100, api_test_utils::GetInteger(set_info, "boundsOriginX"));
   EXPECT_EQ(200, api_test_utils::GetInteger(set_info, "boundsOriginY"));
   EXPECT_EQ(90, api_test_utils::GetInteger(set_info, "rotation"));
-  base::Value::DictStorage overscan =
-      api_test_utils::GetDict(set_info, "overscan");
+  base::Value::Dict overscan = api_test_utils::GetDict(set_info, "overscan");
   EXPECT_EQ(1, api_test_utils::GetInteger(overscan, "left"));
   EXPECT_EQ(2, api_test_utils::GetInteger(overscan, "top"));
   EXPECT_EQ(3, api_test_utils::GetInteger(overscan, "right"));
diff --git a/extensions/browser/api_test_utils.cc b/extensions/browser/api_test_utils.cc
index 1985750..ec7beb7 100644
--- a/extensions/browser/api_test_utils.cc
+++ b/extensions/browser/api_test_utils.cc
@@ -66,53 +66,52 @@
   return base::DictionaryValue::From(ParseJSON(data));
 }
 
-bool GetBoolean(const base::Value::DictStorage& dict, const std::string& key) {
-  auto iter = dict.find(key);
-  if (iter == dict.end() || !iter->second.is_bool()) {
+bool GetBoolean(const base::Value::Dict& dict, const std::string& key) {
+  absl::optional<bool> value = dict.FindBool(key);
+  if (!value.has_value()) {
     ADD_FAILURE() << key << " does not exist or is not a boolean.";
     return false;
   }
-  return iter->second.GetBool();
+  return *value;
 }
 
-int GetInteger(const base::Value::DictStorage& dict, const std::string& key) {
-  auto iter = dict.find(key);
-  if (iter == dict.end() || !iter->second.is_int()) {
+int GetInteger(const base::Value::Dict& dict, const std::string& key) {
+  absl::optional<int> value = dict.FindInt(key);
+  if (!value.has_value()) {
     ADD_FAILURE() << key << " does not exist or is not an integer.";
     return 0;
   }
-  return iter->second.GetInt();
+  return *value;
 }
 
-std::string GetString(const base::Value::DictStorage& dict,
-                      const std::string& key) {
-  auto iter = dict.find(key);
-  if (iter == dict.end() || !iter->second.is_string()) {
+std::string GetString(const base::Value::Dict& dict, const std::string& key) {
+  const std::string* value = dict.FindString(key);
+  if (!value) {
     ADD_FAILURE() << key << " does not exist or is not a string.";
     return "";
   }
-  return iter->second.GetString();
+  return *value;
 }
 
-std::unique_ptr<base::ListValue> GetList(const base::Value::DictStorage& dict,
+std::unique_ptr<base::ListValue> GetList(const base::Value::Dict& dict,
                                          const std::string& key) {
-  auto iter = dict.find(key);
-  if (iter == dict.end() || !iter->second.is_list()) {
+  const base::Value::List* value = dict.FindList(key);
+  if (!value) {
     ADD_FAILURE() << key << " does not exist or is not a list.";
     return std::make_unique<base::ListValue>();
   }
   return base::ListValue::From(
-      base::Value::ToUniquePtrValue(iter->second.Clone()));
+      base::Value::ToUniquePtrValue(base::Value(value->Clone())));
 }
 
-base::Value::DictStorage GetDict(const base::Value::DictStorage& dict,
-                                 const std::string& key) {
-  auto iter = dict.find(key);
-  if (iter == dict.end() || !iter->second.is_dict()) {
+base::Value::Dict GetDict(const base::Value::Dict& dict,
+                          const std::string& key) {
+  const base::Value::Dict* value = dict.FindDict(key);
+  if (!value) {
     ADD_FAILURE() << key << " does not exist or is not a dict.";
-    return base::Value::DictStorage();
+    return base::Value::Dict();
   }
-  return iter->second.Clone().TakeDictDeprecated();
+  return value->Clone();
 }
 
 std::unique_ptr<base::Value> RunFunctionWithDelegateAndReturnSingleResult(
diff --git a/extensions/browser/api_test_utils.h b/extensions/browser/api_test_utils.h
index b93473d..11caf3d 100644
--- a/extensions/browser/api_test_utils.h
+++ b/extensions/browser/api_test_utils.h
@@ -69,14 +69,12 @@
 // Get |key| from |val| as the specified type. If |key| does not exist, or is
 // not of the specified type, adds a failure to the current test and returns
 // false, 0, empty string, etc.
-bool GetBoolean(const base::Value::DictStorage& val, const std::string& key);
-int GetInteger(const base::Value::DictStorage& val, const std::string& key);
-std::string GetString(const base::Value::DictStorage& val,
-                      const std::string& key);
-std::unique_ptr<base::ListValue> GetList(const base::Value::DictStorage& val,
+bool GetBoolean(const base::Value::Dict& val, const std::string& key);
+int GetInteger(const base::Value::Dict& val, const std::string& key);
+std::string GetString(const base::Value::Dict& val, const std::string& key);
+std::unique_ptr<base::ListValue> GetList(const base::Value::Dict& val,
                                          const std::string& key);
-base::Value::DictStorage GetDict(const base::Value::DictStorage& val,
-                                 const std::string& key);
+base::Value::Dict GetDict(const base::Value::Dict& val, const std::string& key);
 
 // Run |function| with |args| and return the result. Adds an error to the
 // current test if |function| returns an error. Takes ownership of
diff --git a/extensions/common/permissions/permissions_data.h b/extensions/common/permissions/permissions_data.h
index 4a516d9..919d9be 100644
--- a/extensions/common/permissions/permissions_data.h
+++ b/extensions/common/permissions/permissions_data.h
@@ -258,30 +258,21 @@
     return *withheld_permissions_unsafe_;
   }
 
-  // Returns list of hosts this extension may not interact with by policy.
+  // Returns the default list of hosts that the enterprise policy has explicitly
+  // blocked or allowed extensions to run on.
   // This should only be used for 1. Serialization when initializing renderers
   // or 2. Called from utility methods above. For all other uses, call utility
   // methods instead (e.g. CanAccessPage()).
   static URLPatternSet GetDefaultPolicyBlockedHosts(int context_id);
-
-  // Returns list of hosts this extension may interact with regardless of
-  // what is defined by policy_blocked_hosts().
-  // This should only be used for 1. Serialization when initializing renderers
-  // or 2. Called from utility methods above. For all other uses, call utility
-  // methods instead (e.g. CanAccessPage()).
   static URLPatternSet GetDefaultPolicyAllowedHosts(int context_id);
 
-  // Returns list of hosts this extension may not interact with by policy.
+  // Returns list of hosts for *this* extension that enterprise policy has
+  // explicitly blocked or allowed extensions to run on. If the extension uses
+  // the default set, this will fall back to `GetDefaultPolicy*Hosts()`.
   // This should only be used for 1. Serialization when initializing renderers
   // or 2. Called from utility methods above. For all other uses, call utility
   // methods instead (e.g. CanAccessPage()).
   URLPatternSet policy_blocked_hosts() const;
-
-  // Returns list of hosts this extension may interact with regardless of
-  // what is defined by policy_blocked_hosts().
-  // This should only be used for 1. Serialization when initializing renderers
-  // or 2. Called from utility methods above. For all other uses, call utility
-  // methods instead (e.g. CanAccessPage()).
   URLPatternSet policy_allowed_hosts() const;
 
   // Check if a specific URL is blocked by policy from extension use at runtime.
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 51e5647..42846d6 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -213,7 +213,7 @@
 // object. A context_id needs to be passed because each browser context can have
 // different values for default_policy_blocked/allowed_hosts.
 // (see extension_util.cc#GetBrowserContextId)
-scoped_refptr<extensions::Extension> ConvertToExtension(
+scoped_refptr<Extension> ConvertToExtension(
     mojom::ExtensionLoadedParamsPtr params,
     int context_id,
     std::string* error) {
@@ -228,12 +228,11 @@
   if (!extension.get())
     return extension;
 
-  const extensions::PermissionsData* permissions_data =
-      extension->permissions_data();
+  const PermissionsData* permissions_data = extension->permissions_data();
   permissions_data->SetPermissions(
-      std::make_unique<const extensions::PermissionSet>(
+      std::make_unique<const PermissionSet>(
           std::move(params->active_permissions)),
-      std::make_unique<const extensions::PermissionSet>(
+      std::make_unique<const PermissionSet>(
           std::move(params->withheld_permissions)));
   permissions_data->SetContextId(context_id);
 
@@ -349,7 +348,7 @@
 
 void Dispatcher::OnRenderThreadStarted(content::RenderThread* thread) {
   blink::WebScriptController::RegisterExtension(
-      extensions::SafeBuiltins::CreateV8Extension());
+      SafeBuiltins::CreateV8Extension());
 }
 
 void Dispatcher::OnRenderFrameCreated(content::RenderFrame* render_frame) {
@@ -959,9 +958,8 @@
       "runtime",
       std::unique_ptr<NativeHandler>(new RuntimeCustomBindings(context)));
   module_system->RegisterNativeHandler(
-      "automationInternal",
-      std::make_unique<extensions::AutomationInternalCustomBindings>(
-          context, bindings_system));
+      "automationInternal", std::make_unique<AutomationInternalCustomBindings>(
+                                context, bindings_system));
 }
 
 bool Dispatcher::OnControlMessageReceived(const IPC::Message& message) {
@@ -1053,8 +1051,8 @@
   for (auto& param : loaded_extensions) {
     std::string error;
     std::string id = param->id;
-    absl::optional<::extensions::ActivationSequence>
-        worker_activation_sequence = param->worker_activation_sequence;
+    absl::optional<ActivationSequence> worker_activation_sequence =
+        param->worker_activation_sequence;
 
     scoped_refptr<const Extension> extension =
         ConvertToExtension(std::move(param), kRendererProfileId, &error);
@@ -1235,9 +1233,8 @@
     return;
 
   extension->permissions_data()->UpdateTabSpecificPermissions(
-      tab_id, extensions::PermissionSet(extensions::APIPermissionSet(),
-                                        extensions::ManifestPermissionSet(),
-                                        new_hosts.Clone(), new_hosts.Clone()));
+      tab_id, PermissionSet(APIPermissionSet(), ManifestPermissionSet(),
+                            new_hosts.Clone(), new_hosts.Clone()));
 
   if (update_origin_allowlist)
     UpdateOriginPermissions(*extension);
@@ -1385,10 +1382,8 @@
   }
 
   extension->permissions_data()->SetPermissions(
-      std::make_unique<const extensions::PermissionSet>(
-          std::move(active_permissions)),
-      std::make_unique<const extensions::PermissionSet>(
-          std::move(withheld_permissions)));
+      std::make_unique<const PermissionSet>(std::move(active_permissions)),
+      std::make_unique<const PermissionSet>(std::move(withheld_permissions)));
 
   UpdateOriginPermissions(*extension);
 
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h
index 722a765..2a49d7a8 100644
--- a/extensions/renderer/dispatcher.h
+++ b/extensions/renderer/dispatcher.h
@@ -229,8 +229,8 @@
   // mojom::Renderer implementation:
   void ActivateExtension(const std::string& extension_id) override;
   void SetActivityLoggingEnabled(bool enabled) override;
-  void LoadExtensions(std::vector<extensions::mojom::ExtensionLoadedParamsPtr>
-                          loaded_extensions) override;
+  void LoadExtensions(
+      std::vector<mojom::ExtensionLoadedParamsPtr> loaded_extensions) override;
   void UnloadExtension(const std::string& extension_id) override;
   void SuspendExtension(
       const std::string& extension_id,
@@ -254,10 +254,10 @@
                          URLPatternSet policy_allowed_hosts,
                          bool uses_default_policy_host_restrictions) override;
   void UpdateDefaultPolicyHostRestrictions(
-      extensions::URLPatternSet default_policy_blocked_hosts,
-      extensions::URLPatternSet default_policy_allowed_hosts) override;
+      URLPatternSet default_policy_blocked_hosts,
+      URLPatternSet default_policy_allowed_hosts) override;
   void UpdateTabSpecificPermissions(const std::string& extension_id,
-                                    extensions::URLPatternSet new_hosts,
+                                    URLPatternSet new_hosts,
                                     int tab_id,
                                     bool update_origin_allowlist) override;
   void UpdateUserScripts(base::ReadOnlySharedMemoryRegion shared_memory,
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 969862df..9fa43bc 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -647,6 +647,10 @@
     ]
   }
 
+  if (use_dawn) {
+    sources += [ "command_buffer/service/dawn_caching_interface_unittest.cc" ]
+  }
+
   configs += [ "//build/config:precompiled_headers" ]
 
   deps = [
@@ -700,6 +704,15 @@
     ]
   }
 
+  if (use_dawn) {
+    deps += [
+      "//net:test_support",
+      "//third_party/dawn/src/dawn:cpp",
+      "//third_party/dawn/src/dawn:proc",
+      "//third_party/dawn/src/dawn/native",
+    ]
+  }
+
   if (use_ozone) {
     deps += [ "//ui/ozone" ]
   }
diff --git a/gpu/DEPS b/gpu/DEPS
index 8651145..42958434 100644
--- a/gpu/DEPS
+++ b/gpu/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+net",
   "+third_party/angle",
   "+third_party/amd",
   "+third_party/nvml",
diff --git a/gpu/PRESUBMIT.py b/gpu/PRESUBMIT.py
index 5f0aeb5..7fab9f8 100644
--- a/gpu/PRESUBMIT.py
+++ b/gpu/PRESUBMIT.py
@@ -21,7 +21,14 @@
     sys.path = [
         input_api.PresubmitLocalPath()
     ] + sys.path
-    output.extend(input_api.canned_checks.RunPylint(input_api, output_api))
+    pylint_checks = input_api.canned_checks.GetPylint(
+        input_api,
+        output_api,
+        version='2.7')
+    # TODO(crbug.com/1329829): Re-enable pylint once all the code under this
+    # directory is on the same Python version and existing warnings have been
+    # cleaned up.
+    # output.extend(input_api.RunTests(pylint_checks))
   finally:
     sys.path = sys_path_backup
 
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 3bbca4e..639348e 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -284,6 +284,8 @@
   if (use_dawn) {
     deps += [ "//gpu/webgpu:common" ]
     sources += [
+      "dawn_caching_interface.cc",
+      "dawn_caching_interface.h",
       "dawn_instance.cc",
       "dawn_instance.h",
       "dawn_platform.cc",
@@ -430,6 +432,7 @@
 
   if (use_dawn) {
     deps += [
+      "//net",
       "//third_party/dawn/src/dawn:proc",
       "//third_party/dawn/src/dawn/native",
       "//third_party/dawn/src/dawn/platform",
diff --git a/gpu/command_buffer/service/DEPS b/gpu/command_buffer/service/DEPS
index 84c89fe..8fa24e9 100644
--- a/gpu/command_buffer/service/DEPS
+++ b/gpu/command_buffer/service/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+cc/paint",
+  "+net",
   "+skia",
   "+third_party/libyuv/include/libyuv/planar_functions.h",
   "+third_party/skia",
diff --git a/gpu/command_buffer/service/dawn_caching_interface.cc b/gpu/command_buffer/service/dawn_caching_interface.cc
new file mode 100644
index 0000000..ebc9cfcd
--- /dev/null
+++ b/gpu/command_buffer/service/dawn_caching_interface.cc
@@ -0,0 +1,348 @@
+// Copyright 2022 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 "gpu/command_buffer/service/dawn_caching_interface.h"
+
+#include <cstring>
+#include <string>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/task/thread_pool.h"
+#include "base/time/time.h"
+#include "net/base/io_buffer.h"
+
+namespace gpu::webgpu {
+
+namespace {
+// TODO(dawn:549) Tune this timeout once we have some more data on what it
+// should be.
+static constexpr base::TimeDelta kCacheOpTimeout = base::Milliseconds(50);
+}  // namespace
+
+// Custom deleter used for entries to close them on the internal backend thread.
+struct OnTaskRunnerEntryDeleter {
+  explicit OnTaskRunnerEntryDeleter(
+      scoped_refptr<base::SequencedTaskRunner> task_runner)
+      : task_runner_(task_runner) {}
+  ~OnTaskRunnerEntryDeleter() = default;
+
+  OnTaskRunnerEntryDeleter(OnTaskRunnerEntryDeleter&&) = default;
+  OnTaskRunnerEntryDeleter& operator=(OnTaskRunnerEntryDeleter&&) = default;
+
+  void operator()(disk_cache::Entry* ptr) {
+    if (ptr) {
+      task_runner_->PostTask(
+          FROM_HERE,
+          base::BindOnce(&disk_cache::Entry::Close, base::Unretained(ptr)));
+    }
+  }
+
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+};
+
+using ScopedEntryPtr =
+    std::unique_ptr<disk_cache::Entry, OnTaskRunnerEntryDeleter>;
+
+class DawnCacheOperation
+    : public base::RefCountedThreadSafe<DawnCacheOperation> {
+ public:
+  enum Type {
+    kRead,
+    kWrite,
+  };
+
+  DawnCacheOperation(scoped_refptr<base::SingleThreadTaskRunner> backend_thread,
+                     Type type,
+                     size_t buffer_size);
+
+  // Runs this operation with the given key on the given backend.
+  void Run(const std::string& key, disk_cache::Backend* backend);
+
+  // Waits for the completion of this operation up to the timeout. Returns true
+  // iff the operation completed before the timeout.
+  bool TimedWait(base::TimeDelta timeout) { return signal_.TimedWait(timeout); }
+
+  // Returns the result of the operation. If the operation is not complete, this
+  // always returns 0.
+  size_t Result() const { return result_size_; }
+  void* Data() { return buffer_->data(); }
+
+ private:
+  friend class base::RefCountedThreadSafe<DawnCacheOperation>;
+  ~DawnCacheOperation() = default;
+
+  // Returns the entry size or clamps errors (negative values) to 0.
+  size_t GetEntrySize() const;
+
+  // Callback to handle when an entry has been opened.
+  void OnOpenedEntry(disk_cache::EntryResult entry);
+
+  // Callback to handle when an operation has completed with a status. Note that
+  // statuses in the backend API are ints. Non-negative values indicate the size
+  // of the result while negative results are used to indicate some sort of
+  // error. For negative values, this will be a call to OnOpCompleteSize with 0
+  // as the argument.
+  void OnOpCompleteStatus(int status);
+
+  // Callback to handle a valid entry size (or 0 when the operation did not
+  // complete successfully) and save it to the result of this operation.
+  void OnOpCompleteSize(size_t size);
+
+  scoped_refptr<base::SingleThreadTaskRunner> backend_thread_;
+  Type type_;
+  scoped_refptr<net::IOBuffer> buffer_;
+  size_t buffer_size_;
+  ScopedEntryPtr entry_;
+  size_t result_size_ = 0;
+  base::WaitableEvent signal_;
+};
+
+DawnCacheOperation::DawnCacheOperation(
+    scoped_refptr<base::SingleThreadTaskRunner> backend_thread,
+    Type type,
+    size_t buffer_size)
+    : backend_thread_(backend_thread),
+      type_(type),
+      buffer_(buffer_size > 0
+                  ? base::WrapRefCounted(new net::IOBuffer(buffer_size))
+                  : nullptr),
+      buffer_size_(buffer_size),
+      entry_(nullptr, OnTaskRunnerEntryDeleter(backend_thread_)),
+      signal_(base::WaitableEvent::ResetPolicy::MANUAL,
+              base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+void DawnCacheOperation::Run(const std::string& key,
+                             disk_cache::Backend* backend) {
+  disk_cache::EntryResult entry = backend->OpenOrCreateEntry(
+      key, net::RequestPriority::DEFAULT_PRIORITY,
+      base::BindOnce(&DawnCacheOperation::OnOpenedEntry, this));
+  if (entry.net_error() == net::Error::OK) {
+    backend_thread_->PostTask(
+        FROM_HERE, base::BindOnce(&DawnCacheOperation::OnOpenedEntry, this,
+                                  std::move(entry)));
+  }
+}
+
+size_t DawnCacheOperation::GetEntrySize() const {
+  if (entry_ != nullptr) {
+    int tmp = entry_->GetDataSize(0);
+    if (tmp > 0) {
+      return size_t(tmp);
+    }
+  }
+  return 0u;
+}
+
+void DawnCacheOperation::OnOpenedEntry(disk_cache::EntryResult entry) {
+  // Check if we are pending since this function may be scheduled twice if the
+  // return value was asynchronous.
+  if (entry.net_error() == net::ERR_IO_PENDING) {
+    return;
+  }
+
+  // Backend cache implementation uses integers as both a status and a return
+  // value. Non-negative values represent successful operation and doubles as
+  // the size read/written depending on the operation.
+  int status = 0;
+  entry_.reset(entry.ReleaseEntry());
+  if (entry_ == nullptr) {
+    OnOpCompleteStatus(status);
+    return;
+  }
+
+  switch (type_) {
+    case Type::kRead: {
+      if (buffer_size_ == 0) {
+        // Size-read case.
+        OnOpCompleteSize(GetEntrySize());
+        return;
+      } else {
+        if (buffer_size_ != GetEntrySize()) {
+          // If we are reading the actual data, the buffer size must equal the
+          // entry size, otherwise we would not be able to copy the data out
+          // anyways so we can just skip and return 0 to indicate that the read
+          // did no occur.
+          OnOpCompleteSize(0u);
+          return;
+        }
+        buffer_ = base::WrapRefCounted(new net::IOBuffer(buffer_size_));
+        status = entry_->ReadData(
+            0, 0, buffer_.get(), buffer_size_,
+            base::BindOnce(&DawnCacheOperation::OnOpCompleteStatus, this));
+      }
+      break;
+    }
+    case Type::kWrite: {
+      status = entry_->WriteData(
+          0, 0, buffer_.get(), buffer_size_,
+          base::BindOnce(&DawnCacheOperation::OnOpCompleteStatus, this), false);
+      break;
+    }
+  }
+
+  // Both ReadData and StoreData will call OnOpCompleteStatus as a callback if
+  // the returned 'status' is ERR_IO_PENDING. Otherwise, the calls will not call
+  // their callback so we need to call it here, passing 'status' as the
+  // argument.
+  if (status != net::ERR_IO_PENDING) {
+    OnOpCompleteStatus(status);
+  }
+}
+
+void DawnCacheOperation::OnOpCompleteSize(size_t size) {
+  result_size_ = size;
+  switch (type_) {
+    case Type::kRead: {
+      // No-op since we already set the result.
+      break;
+    }
+    case Type::kWrite: {
+      // If the write wasn't complete (didn't write the full buffer out), we
+      // mark the entry as doomed for deletion. In general, this shouldn't
+      // happen, but may occur in shutdown or error scenarios.
+      if (entry_ != nullptr && result_size_ != buffer_size_) {
+        entry_->Doom();
+      }
+      break;
+    }
+  }
+  signal_.Signal();
+}
+
+void DawnCacheOperation::OnOpCompleteStatus(int status) {
+  // Any errors are negative, and we mask the status here to 0 size to indicate
+  // read/write failed.
+  OnOpCompleteSize(status > 0 ? size_t(status) : 0u);
+}
+
+DawnCachingInterface::DawnCachingInterface(net::CacheType cache_type,
+                                           int64_t cache_size,
+                                           const base::FilePath& path)
+    : DawnCachingInterface(
+          base::BindOnce(&DawnCachingInterface::DefaultCacheBackendFactory,
+                         cache_type,
+                         cache_size,
+                         std::move(path))) {}
+
+DawnCachingInterface::DawnCachingInterface(CacheBackendFactory factory)
+    : factory_(std::move(factory)),
+      backend_thread_(base::ThreadPool::CreateSingleThreadTaskRunner(
+          {base::MayBlock()},
+          base::SingleThreadTaskRunnerThreadMode::DEDICATED)),
+      backend_(nullptr, base::OnTaskRunnerDeleter(backend_thread_)) {}
+
+net::Error DawnCachingInterface::Init() {
+  // Initialization blocks until either a valid backend is returned or an error
+  // occurs.
+  std::unique_ptr<disk_cache::Backend> backend;
+  base::WaitableEvent signal;
+  net::Error error;
+  backend_thread_->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(factory_), base::Unretained(&backend),
+                     base::Unretained(&signal), base::Unretained(&error)));
+  signal.Wait();
+  backend_.reset(backend.release());
+  return error;
+}
+
+// static
+std::unique_ptr<DawnCachingInterface> DawnCachingInterface::CreateForTesting(
+    CacheBackendFactory factory) {
+  return std::unique_ptr<DawnCachingInterface>(
+      new DawnCachingInterface(std::move(factory)));
+}
+
+DawnCachingInterface::~DawnCachingInterface() = default;
+
+size_t DawnCachingInterface::LoadData(const void* key,
+                                      size_t key_size,
+                                      void* value_out,
+                                      size_t value_size) {
+  if (backend_ == nullptr) {
+    return 0u;
+  }
+  std::string key_str(static_cast<const char*>(key), key_size);
+
+  // Check if the call is a size/existence check.
+  bool size_only = value_size == 0 && value_out == nullptr;
+
+  auto op = base::WrapRefCounted(new DawnCacheOperation(
+      backend_thread_, DawnCacheOperation::Type::kRead, value_size));
+
+  backend_thread_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&DawnCacheOperation::Run, op, std::move(key_str),
+                     base::Unretained(backend_.get())));
+
+  // For loading data, to appear synchronous, we block, but for a max timeout.
+  if (!op->TimedWait(kCacheOpTimeout)) {
+    return 0u;
+  }
+
+  // Copy the read memory into the actual destination buffer if we did not time
+  // out reading the entry.
+  if (!size_only) {
+    std::memcpy(value_out, op->Data(), value_size);
+  }
+  return op->Result();
+}
+
+void DawnCachingInterface::StoreData(const void* key,
+                                     size_t key_size,
+                                     const void* value,
+                                     size_t value_size) {
+  if (backend_ == nullptr || value == nullptr || value_size <= 0) {
+    return;
+  }
+  std::string key_str(static_cast<const char*>(key), key_size);
+
+  auto op = base::WrapRefCounted(new DawnCacheOperation(
+      backend_thread_, DawnCacheOperation::Type::kWrite, value_size));
+
+  // Copy the contents of buffer into the internal buffer that will live for the
+  // duration of the async operation.
+  std::memcpy(op->Data(), value, value_size);
+
+  backend_thread_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&DawnCacheOperation::Run, op, std::move(key_str),
+                     base::Unretained(backend_.get())));
+}
+
+namespace {
+
+void BackendInitCallback(base::WaitableEvent* signal,
+                         net::Error* error,
+                         int rv) {
+  *error = static_cast<net::Error>(rv);
+  signal->Signal();
+}
+
+}  // namespace
+
+// static
+void DawnCachingInterface::DefaultCacheBackendFactory(
+    net::CacheType cache_type,
+    int64_t cache_size,
+    const base::FilePath& path,
+    std::unique_ptr<disk_cache::Backend>* backend,
+    base::WaitableEvent* signal,
+    net::Error* error) {
+  *error = disk_cache::CreateCacheBackend(
+      cache_type, net::CACHE_BACKEND_BLOCKFILE,
+      /*file_operations=*/nullptr, path,
+      /*max_bytes=*/cache_size, disk_cache::ResetHandling::kNeverReset,
+      /*net_log=*/nullptr, backend,
+      base::BindOnce(&BackendInitCallback, base::Unretained(signal),
+                     base::Unretained(error)));
+  if (*error == net::ERR_IO_PENDING) {
+    return;
+  }
+  signal->Signal();
+}
+
+}  // namespace gpu::webgpu
diff --git a/gpu/command_buffer/service/dawn_caching_interface.h b/gpu/command_buffer/service/dawn_caching_interface.h
new file mode 100644
index 0000000..f8b30bf
--- /dev/null
+++ b/gpu/command_buffer/service/dawn_caching_interface.h
@@ -0,0 +1,96 @@
+// Copyright 2022 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 GPU_COMMAND_BUFFER_SERVICE_DAWN_CACHING_INTERFACE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_DAWN_CACHING_INTERFACE_H_
+
+#include <dawn_platform/DawnPlatform.h>
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/single_thread_task_runner.h"
+#include "gpu/gpu_gles2_export.h"
+#include "net/disk_cache/disk_cache.h"
+
+namespace gpu::webgpu {
+
+class GPU_GLES2_EXPORT DawnCachingInterface
+    : public dawn::platform::CachingInterface {
+ public:
+  // Default constructor takes a valid cache type (either disk or memory at the
+  // moment), a maximum cache size in bytes (0 can be passed for default), and a
+  // file path to locate the cache files.
+  DawnCachingInterface(net::CacheType cache_type,
+                       int64_t cache_size,
+                       const base::FilePath& path);
+
+  // Factory for backend injection. Note that to inject a backend, we need to
+  // pass a factory to the constructor and not the direct Backend because the
+  // Backend must be created inside the thread owned by the caching interface in
+  // order for it to be usable. By passing a factory, we can post the factory to
+  // the thread. The signal should be signalled once the backend initialization
+  // has completed.
+  using CacheBackendFactory =
+      base::OnceCallback<void(std::unique_ptr<disk_cache::Backend>*,
+                              base::WaitableEvent* signal,
+                              net::Error* error)>;
+  static std::unique_ptr<DawnCachingInterface> CreateForTesting(
+      CacheBackendFactory factory);
+
+  ~DawnCachingInterface() override;
+
+  // Returns a non net::OK error code if a failure occurs during initialization.
+  net::Error Init();
+
+  // Synchronously loads from the cache. Blocks for a timeout to wait for the
+  // asynchronous backend, returning early if we were unable to complete the
+  // request. If we return due to a timeout, we always return 0 to indicate no
+  // reading occurred, and nothing should be written to `value_out`.
+  size_t LoadData(const void* key,
+                  size_t key_size,
+                  void* value_out,
+                  size_t value_size) override;
+
+  // Posts a task to write out to the cache that may run asynchronously.
+  void StoreData(const void* key,
+                 size_t key_size,
+                 const void* value,
+                 size_t value_size) override;
+
+ private:
+  static void DefaultCacheBackendFactory(
+      net::CacheType cache_type,
+      int64_t cache_size,
+      const base::FilePath& path,
+      std::unique_ptr<disk_cache::Backend>* backend,
+      base::WaitableEvent* signal,
+      net::Error* error);
+
+  // Factory constructor. Note this is exposed externally for testing via
+  // CreateForTesting.
+  explicit DawnCachingInterface(CacheBackendFactory factory);
+
+  // Temporarily saves the factory so that we can use it when we call Init.
+  CacheBackendFactory factory_;
+
+  // Background thread owned by the caching interface used to post tasks to the
+  // disk_cache::Backend. Note that this additional thread is necessary because
+  // the backends expect the thread they are created on to not block, however we
+  // are blocking to appear synchronous. Without this, we can cause a deadlock
+  // when waiting.
+  scoped_refptr<base::SingleThreadTaskRunner> backend_thread_;
+
+  // Caching interface owns the backend. Note that backends initialized using
+  // the same backing file path will block on one another at initialization.
+  // This means that only one such backend will successfully be created, and
+  // thus users should be careful to avoid creating the same backend arguments
+  // unintentionally.
+  std::unique_ptr<disk_cache::Backend, base::OnTaskRunnerDeleter> backend_;
+};
+
+}  // namespace gpu::webgpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_DAWN_CACHING_INTERFACE_H_
diff --git a/gpu/command_buffer/service/dawn_caching_interface_unittest.cc b/gpu/command_buffer/service/dawn_caching_interface_unittest.cc
new file mode 100644
index 0000000..f0d09d74
--- /dev/null
+++ b/gpu/command_buffer/service/dawn_caching_interface_unittest.cc
@@ -0,0 +1,560 @@
+// Copyright 2022 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 "gpu/command_buffer/service/dawn_caching_interface.h"
+
+#include <string>
+#include <tuple>
+#include <unordered_map>
+
+#include "base/bind.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/notreached.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/thread_pool.h"
+#include "base/test/bind.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "net/base/io_buffer.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/disk_cache/mock/mock_backend_impl.h"
+#include "net/disk_cache/mock/mock_entry_impl.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace gpu::webgpu {
+namespace {
+
+using ::testing::_;
+using ::testing::ByMove;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::TestParamInfo;
+using ::testing::Values;
+using ::testing::WithParamInterface;
+
+namespace internal {
+
+// Based on RunOnceCallbackImpl in base/test/gmock_callback_support.h (see for
+// more details). Modified to return a value earlier and run the callback
+// on the designated runner (asynchronously) in order to test caching
+// implementation. Specifically, this was necessary because
+// disk_cache::EntryResult is a move-only type, and OpenOrCreateEntry can return
+// early. Since this is based on the move-only type implementation of
+// RunOnceCallbackImpl, it is not safe to reuse the Action or arguments.
+template <size_t I, typename RetValue, typename Tuple>
+auto ReturnAndRunOnceCallbackAfterImpl(RetValue&& ret, Tuple&& tuple) {
+  auto ret_ptr = base::MakeRefCounted<base::RefCountedData<RetValue>>(
+      std::forward<RetValue>(ret));
+  auto tuple_ptr = base::MakeRefCounted<base::RefCountedData<Tuple>>(
+      std::forward<Tuple>(tuple));
+  return [ret_ptr = std::move(ret_ptr), tuple_ptr = std::move(tuple_ptr)](
+             auto&&... args) mutable -> decltype(auto) {
+    // Modified to pull the callback out from the arguments so that we can
+    // create a lambda callback to send to run asynchronously.
+    auto cb = std::move(base::internal::get<I>(args...));
+    base::ThreadPool::PostTask(
+        FROM_HERE,
+        base::BindLambdaForTesting(
+            [cb = std::move(cb), tuple_ptr = std::move(tuple_ptr)]() mutable {
+              base::internal::RunImpl(
+                  std::move(cb),
+                  std::move(std::exchange(tuple_ptr, nullptr)->data));
+            }));
+    return std::move(std::exchange(ret_ptr, nullptr)->data);
+  };
+}
+
+}  // namespace internal
+
+// Extension of RunOnceCallback test helper in
+// base/test/gmock_callback_support.h, but allows specifying the value to return
+// from the call, and run the callback asynchronously after.
+template <size_t I, typename RetValue, typename... RunArgs>
+auto ReturnAndRunOnceCallbackAfter(RetValue&& ret, RunArgs&&... run_args) {
+  return internal::ReturnAndRunOnceCallbackAfterImpl<I>(
+      std::forward<RetValue>(ret),
+      std::make_tuple(std::forward<RunArgs>(run_args)...));
+}
+
+TEST(DawnCachingInterfaceNoOpTest, LoadData) {
+  // Without a backend, we should just passthrough return 0 for LoadData, and
+  // not produce any errors.
+  base::test::TaskEnvironment task_environment;
+  std::unique_ptr<DawnCachingInterface> cache =
+      DawnCachingInterface::CreateForTesting(base::BindLambdaForTesting(
+          [](std::unique_ptr<disk_cache::Backend>* backend,
+             base::WaitableEvent* signal, net::Error* error) -> void {
+            backend->reset(nullptr);
+            *error = net::OK;
+            signal->Signal();
+          }));
+  ASSERT_EQ(cache->Init(), net::OK);
+  EXPECT_EQ(0u, cache->LoadData(nullptr, 0, nullptr, 0));
+}
+
+TEST(DawnCachingInterfaceNoOpTest, StoreData) {
+  // Without a backend, we should just passthrough for StoreData, and not
+  // produce any errors.
+  base::test::TaskEnvironment task_environment;
+  std::unique_ptr<DawnCachingInterface> cache =
+      DawnCachingInterface::CreateForTesting(base::BindLambdaForTesting(
+          [](std::unique_ptr<disk_cache::Backend>* backend,
+             base::WaitableEvent* signal, net::Error* error) -> void {
+            backend->reset(nullptr);
+            *error = net::OK;
+            signal->Signal();
+          }));
+  ASSERT_EQ(cache->Init(), net::OK);
+  cache->StoreData(nullptr, 0, nullptr, 0);
+}
+
+class DawnCachingInterfaceMockTest : public testing::Test {
+ protected:
+  DawnCachingInterfaceMockTest()
+      : backend_mock_(new disk_cache::BackendMock(net::CacheType::DISK_CACHE)) {
+    cache_ = DawnCachingInterface::CreateForTesting(base::BindLambdaForTesting(
+        [this](std::unique_ptr<disk_cache::Backend>* backend,
+               base::WaitableEvent* signal, net::Error* error) -> void {
+          backend->reset(this->backend_mock_);
+          *error = net::OK;
+          signal->Signal();
+        }));
+    CHECK_EQ(cache_->Init(), net::OK);
+  }
+  ~DawnCachingInterfaceMockTest() override = default;
+
+  // Wrapper around calling StoreData that synchronizes threads because
+  // otherwise test expectations can race with the async nature of the write
+  // operations.
+  void StoreData(const void* key,
+                 size_t key_size,
+                 const void* value,
+                 size_t value_size) {
+    cache_->StoreData(key, key_size, value, value_size);
+    task_environment_.RunUntilIdle();
+  }
+
+  // Constants that are reused throughout the tests
+  static constexpr std::string_view kKey = "cache key";
+  static constexpr size_t kDataSize = 10;
+
+  // Temporary buffer used in tests.
+  char buffer_[kDataSize];
+
+  base::test::TaskEnvironment task_environment_;
+
+  // Mocks initialized for the tests. Note that the backend mock is actually
+  // owned and managed by the caching interface after initialization. We keep a
+  // raw pointer to it though in order to set expectations.
+  std::unique_ptr<DawnCachingInterface> cache_ = nullptr;
+  // Owned by `cache_`.
+  raw_ptr<disk_cache::BackendMock> backend_mock_ = nullptr;
+};
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataSizeSyncNominal) {
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, GetDataSize(0)).WillOnce(Return(kDataSize));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeCreated(entry.release()))));
+
+  EXPECT_EQ(kDataSize, cache_->LoadData(kKey.data(), kKey.size(), nullptr, 0));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataSizeSyncErrorEntry) {
+  // Error from entry should return 0 for data size.
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeError(net::Error::ERR_FAILED))));
+
+  EXPECT_EQ(0u, cache_->LoadData(kKey.data(), kKey.size(), nullptr, 0));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataSizeSyncErrorRead) {
+  // Error from data size read should cause us to return 0 for size.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, GetDataSize(0)).WillOnce(Return(net::Error::ERR_FAILED));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeCreated(entry.release()))));
+
+  EXPECT_EQ(0u, cache_->LoadData(kKey.data(), kKey.size(), nullptr, 0));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataSizeAsyncNominal) {
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, GetDataSize(0)).WillOnce(Return(kDataSize));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<2>(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING),
+          disk_cache::EntryResult::MakeCreated(entry.release())));
+
+  EXPECT_EQ(kDataSize, cache_->LoadData(kKey.data(), kKey.size(), nullptr, 0));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataSizeAsyncErrorEntry) {
+  // Error from entry should return 0 for data size.
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<2>(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING),
+          disk_cache::EntryResult::MakeError(net::Error::ERR_FAILED)));
+
+  EXPECT_EQ(0u, cache_->LoadData(kKey.data(), kKey.size(), nullptr, 0));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataSizeAsyncTimeout) {
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(ByMove(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING))));
+
+  EXPECT_EQ(0u, cache_->LoadData(kKey.data(), kKey.size(), nullptr, 0));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataSyncNominal) {
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, GetDataSize(0)).WillOnce(Return(kDataSize));
+  EXPECT_CALL(*entry, ReadData(0, 0, _, kDataSize, _))
+      .WillOnce(Return(kDataSize));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeCreated(entry.release()))));
+
+  EXPECT_EQ(kDataSize,
+            cache_->LoadData(kKey.data(), kKey.size(), buffer_, kDataSize));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataAsyncNominal) {
+  // Async on both the entry, and the read call.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, GetDataSize(0)).WillOnce(Return(kDataSize));
+  EXPECT_CALL(*entry, ReadData(0, 0, _, kDataSize, _))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<4>(net::Error::ERR_IO_PENDING,
+                                                 int(kDataSize)));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<2>(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING),
+          disk_cache::EntryResult::MakeCreated(entry.release())));
+
+  EXPECT_EQ(kDataSize,
+            cache_->LoadData(kKey.data(), kKey.size(), buffer_, kDataSize));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataAsyncEntry) {
+  // Sync return on the read, but async on the entry.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, GetDataSize(0)).WillOnce(Return(kDataSize));
+  EXPECT_CALL(*entry, ReadData(0, 0, _, kDataSize, _))
+      .WillOnce(Return(kDataSize));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<2>(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING),
+          disk_cache::EntryResult::MakeCreated(entry.release())));
+
+  EXPECT_EQ(kDataSize,
+            cache_->LoadData(kKey.data(), kKey.size(), buffer_, kDataSize));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataAsyncRead) {
+  // Sync return on the entry, but async on the actual read call.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, GetDataSize(0)).WillOnce(Return(kDataSize));
+  EXPECT_CALL(*entry, ReadData(0, 0, _, kDataSize, _))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<4>(net::Error::ERR_IO_PENDING,
+                                                 int(kDataSize)));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeCreated(entry.release()))));
+
+  EXPECT_EQ(kDataSize,
+            cache_->LoadData(kKey.data(), kKey.size(), buffer_, kDataSize));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataAsyncTimeoutEntry) {
+  // Timeout on getting the entry.
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(ByMove(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING))));
+
+  EXPECT_EQ(0u, cache_->LoadData(kKey.data(), kKey.size(), buffer_, kDataSize));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, LoadDataAsyncTimeoutRead) {
+  // Timeout on the read call.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, GetDataSize(0)).WillOnce(Return(kDataSize));
+  EXPECT_CALL(*entry, ReadData(0, 0, _, kDataSize, _))
+      .WillOnce(Return(net::Error::ERR_IO_PENDING));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<2>(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING),
+          disk_cache::EntryResult::MakeCreated(entry.release())));
+
+  EXPECT_EQ(0u, cache_->LoadData(kKey.data(), kKey.size(), buffer_, kDataSize));
+}
+
+TEST_F(DawnCachingInterfaceMockTest, StoreDataSyncNominal) {
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, WriteData(0, 0, _, kDataSize, _, false))
+      .WillOnce(Return(kDataSize));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeCreated(entry.release()))));
+
+  StoreData(kKey.data(), kKey.size(), buffer_, kDataSize);
+}
+
+TEST_F(DawnCachingInterfaceMockTest, StoreDataAsyncNominal) {
+  // Async on both the entry, and the read call.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, WriteData(0, 0, _, kDataSize, _, false))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<4>(net::Error::ERR_IO_PENDING,
+                                                 int(kDataSize)));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<2>(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING),
+          disk_cache::EntryResult::MakeCreated(entry.release())));
+
+  StoreData(kKey.data(), kKey.size(), buffer_, kDataSize);
+}
+
+TEST_F(DawnCachingInterfaceMockTest, StoreDataAsyncEntry) {
+  // Sync return on the write, but async on the entry.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, WriteData(0, 0, _, kDataSize, _, false))
+      .WillOnce(Return(kDataSize));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<2>(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING),
+          disk_cache::EntryResult::MakeCreated(entry.release())));
+
+  StoreData(kKey.data(), kKey.size(), buffer_, kDataSize);
+}
+
+TEST_F(DawnCachingInterfaceMockTest, StoreDataAsyncWrite) {
+  // Sync return on the entry, but async on the actual write call.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, WriteData(0, 0, _, kDataSize, _, false))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<4>(net::Error::ERR_IO_PENDING,
+                                                 int(kDataSize)));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeCreated(entry.release()))));
+
+  StoreData(kKey.data(), kKey.size(), buffer_, kDataSize);
+}
+
+TEST_F(DawnCachingInterfaceMockTest, StoreDataAsyncEntryNonblocking) {
+  // Verifies that if the callback never runs for async entry, we do not block
+  // running thread.
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(ByMove(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING))));
+
+  StoreData(kKey.data(), kKey.size(), buffer_, kDataSize);
+}
+
+TEST_F(DawnCachingInterfaceMockTest, StoreDataAsyncWriteNonblocking) {
+  // Verifies that if the callback never runs for async write, we do not block
+  // running thread.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, WriteData(0, 0, _, kDataSize, _, false))
+      .WillOnce(Return(net::Error::ERR_IO_PENDING));
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<2>(
+          disk_cache::EntryResult::MakeError(net::Error::ERR_IO_PENDING),
+          disk_cache::EntryResult::MakeCreated(entry.release())));
+
+  StoreData(kKey.data(), kKey.size(), buffer_, kDataSize);
+}
+
+TEST_F(DawnCachingInterfaceMockTest, StoreDataDoomSyncIncompleteWrite) {
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, WriteData(0, 0, _, kDataSize, _, false))
+      .WillOnce(Return(kDataSize - 1));
+  EXPECT_CALL(*entry, Doom).Times(1);
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeCreated(entry.release()))));
+
+  StoreData(kKey.data(), kKey.size(), buffer_, kDataSize);
+}
+
+TEST_F(DawnCachingInterfaceMockTest, StoreDataDoomSyncErrorWrite) {
+  // Sync case where we get an error on the write.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, WriteData(0, 0, _, kDataSize, _, false))
+      .WillOnce(Return(net::Error::ERR_FAILED));
+  EXPECT_CALL(*entry, Doom).Times(1);
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeCreated(entry.release()))));
+
+  StoreData(kKey.data(), kKey.size(), buffer_, kDataSize);
+}
+
+TEST_F(DawnCachingInterfaceMockTest, StoreDataDoomAsyncIncompleteWrite) {
+  // Async case where we are unable to write the full data out.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, WriteData(0, 0, _, kDataSize, _, false))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<4>(net::Error::ERR_IO_PENDING,
+                                                 int(kDataSize - 1)));
+  EXPECT_CALL(*entry, Doom).Times(1);
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeCreated(entry.release()))));
+
+  StoreData(kKey.data(), kKey.size(), buffer_, kDataSize);
+}
+
+TEST_F(DawnCachingInterfaceMockTest, StoreDataDoomAsyncErrorWrite) {
+  // Async case where we get an error on the write.
+  std::unique_ptr<disk_cache::EntryMock> entry =
+      std::make_unique<disk_cache::EntryMock>();
+  EXPECT_CALL(*entry, WriteData(0, 0, _, kDataSize, _, false))
+      .WillOnce(ReturnAndRunOnceCallbackAfter<4>(net::Error::ERR_IO_PENDING,
+                                                 net::Error::ERR_FAILED));
+  EXPECT_CALL(*entry, Doom).Times(1);
+
+  EXPECT_CALL(*backend_mock_, OpenOrCreateEntry(StrEq(kKey), _, _))
+      .WillOnce(Return(
+          ByMove(disk_cache::EntryResult::MakeCreated(entry.release()))));
+
+  StoreData(kKey.data(), kKey.size(), buffer_, kDataSize);
+}
+
+class DawnCachingInterfaceTest : public PlatformTest,
+                                 public WithParamInterface<net::CacheType> {
+ protected:
+  void SetUp() override {
+    CHECK(temp_dir_.CreateUniqueTempDir());
+    const base::FilePath path = temp_dir_.GetPath().AppendASCII("cache");
+
+    const net::CacheType cache_type = GetParam();
+    switch (cache_type) {
+      case net::CacheType::DISK_CACHE:
+      case net::CacheType::MEMORY_CACHE:
+        break;
+      default:
+        // Other modes are not supported.
+        NOTREACHED();
+    }
+    dawn_cache_ = std::make_unique<DawnCachingInterface>(cache_type, 0, path);
+    ASSERT_EQ(dawn_cache_->Init(), net::OK);
+  }
+
+  base::test::TaskEnvironment task_environment_;
+  base::ScopedTempDir temp_dir_;
+  std::unique_ptr<DawnCachingInterface> dawn_cache_;
+};
+
+TEST_P(DawnCachingInterfaceTest, NominalUsage) {
+  static constexpr std::array<size_t, 5> kKeySizes = {64, 128, 256, 512, 1024};
+  static constexpr std::array<size_t, 5> kValueSizes = {256, 512, 1024, 2048,
+                                                        4096};
+
+  // Generate and save all key/value pairs in memory to validate (using strings
+  // for simplicity).
+  std::unordered_map<std::string, std::string> key_values;
+  char id = 1;
+  for (size_t key_size : kKeySizes) {
+    for (size_t value_size : kValueSizes) {
+      char key[key_size];
+      memset(key, id, key_size);
+      char value[value_size];
+      memset(value, id, value_size);
+      key_values[std::string(key, key_size)] = std::string(value, value_size);
+      id++;
+    }
+  }
+
+  // Add all pairs into the cache.
+  for (const auto& [key, value] : key_values) {
+    dawn_cache_->StoreData(key.data(), key.size(), value.data(), value.size());
+  }
+
+  // Since write ops can be async, we need to "flush" to make sure they occur.
+  // As of writing this, it seems to work without running the loop two times,
+  // however, it may become flaky without the double-flushing because the task
+  // environment cannot flush the dedicated cache thread managed by the backend.
+  // Because write/store operations are actually two separate tasks (open entry
+  // and read/store), it could be possible that the first flush leaves lingering
+  // read/store tasks that are not completed, hence the second one to confirm.
+  for (int i = 0; i < 2; i++) {
+    task_environment_.RunUntilIdle();
+    base::RunLoop run_loop;
+    disk_cache::FlushCacheThreadAsynchronouslyForTesting(
+        base::BindLambdaForTesting([&run_loop]() { run_loop.Quit(); }));
+    run_loop.Run();
+  }
+
+  // Verify that all pairs can be read back out from the cache.
+  for (const auto& [key, value] : key_values) {
+    // Verify that the size is the expected size.
+    EXPECT_EQ(value.size(),
+              dawn_cache_->LoadData(key.data(), key.size(), nullptr, 0));
+
+    // Verify the actual contents.
+    char buffer[value.size()];
+    memset(buffer, 0, value.size());
+    EXPECT_EQ(value.size(), dawn_cache_->LoadData(key.data(), key.size(),
+                                                  buffer, value.size()));
+    EXPECT_EQ(0, memcmp(buffer, value.data(), value.size()));
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    DawnCachingInterfaceTests,
+    DawnCachingInterfaceTest,
+    Values(net::CacheType::DISK_CACHE, net::CacheType::MEMORY_CACHE),
+    [](const TestParamInfo<DawnCachingInterfaceTest::ParamType>& info) {
+      switch (info.param) {
+        case net::CacheType::DISK_CACHE:
+          return "DiskCache";
+        case net::CacheType::MEMORY_CACHE:
+          return "MemoryCache";
+        default:
+          return "UnknownCache";
+      }
+    });
+
+}  // namespace
+}  // namespace gpu::webgpu
diff --git a/gpu/command_buffer/service/raster_decoder_unittest.cc b/gpu/command_buffer/service/raster_decoder_unittest.cc
index 62616ab..4b935793 100644
--- a/gpu/command_buffer/service/raster_decoder_unittest.cc
+++ b/gpu/command_buffer/service/raster_decoder_unittest.cc
@@ -239,6 +239,11 @@
     client_texture_mailbox_ =
         CreateMailbox(viz::ResourceFormat::RGBA_8888, /*width=*/2,
                       /*height=*/2, /*cleared=*/false);
+
+    // When creating the mailbox, we create a WrappedSkImage shared image which
+    // sets this flag to true. Some tests expect this flag to be false when
+    // testing so we reset it back here to false.
+    context_state_->set_need_context_state_reset(/*reset=*/false);
   }
   void TearDown() override {
     context_state_->MakeCurrent(nullptr);
@@ -301,7 +306,8 @@
     if (cleared) {
       SharedImageRepresentationFactory repr_factory(shared_image_manager(),
                                                     nullptr);
-      auto representation = repr_factory.ProduceGLTexture(mailbox);
+      auto representation =
+          repr_factory.ProduceSkia(mailbox, context_state_.get());
       representation->SetCleared();
     }
 
@@ -382,8 +388,8 @@
 
   SharedImageRepresentationFactory repr_factory(shared_image_manager(),
                                                 nullptr);
-  auto representation = repr_factory.ProduceGLTexture(client_texture_mailbox_);
-  gles2::Texture* dest_texture = representation->GetTexture();
+  auto representation =
+      repr_factory.ProduceSkia(client_texture_mailbox_, context_state_.get());
 
   {
     // This will initialize the bottom right corner of destination.
@@ -391,8 +397,7 @@
     cmd.Init(1, 1, 0, 0, 1, 1, false, mailboxes);
     EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(mailboxes)));
     EXPECT_EQ(GL_NO_ERROR, GetGLError());
-    EXPECT_EQ(dest_texture->GetLevelClearedRect(GL_TEXTURE_2D, 0),
-              gfx::Rect(1, 1, 1, 1));
+    EXPECT_EQ(representation->ClearedRect(), gfx::Rect(1, 1, 1, 1));
   }
 
   {
@@ -401,8 +406,7 @@
     cmd.Init(2, 2, 0, 0, 1, 1, false, mailboxes);
     EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(mailboxes)));
     EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
-    EXPECT_EQ(dest_texture->GetLevelClearedRect(GL_TEXTURE_2D, 0),
-              gfx::Rect(1, 1, 1, 1));
+    EXPECT_EQ(representation->ClearedRect(), gfx::Rect(1, 1, 1, 1));
   }
 
   {
@@ -411,8 +415,7 @@
     cmd.Init(0, 0, 0, 0, 2, 2, false, mailboxes);
     EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(mailboxes)));
     EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
-    EXPECT_EQ(dest_texture->GetLevelClearedRect(GL_TEXTURE_2D, 0),
-              gfx::Rect(1, 1, 1, 1));
+    EXPECT_EQ(representation->ClearedRect(), gfx::Rect(1, 1, 1, 1));
   }
 }
 
@@ -428,7 +431,8 @@
 
   SharedImageRepresentationFactory repr_factory(shared_image_manager(),
                                                 nullptr);
-  auto representation = repr_factory.ProduceGLTexture(client_texture_mailbox_);
+  auto representation =
+      repr_factory.ProduceSkia(client_texture_mailbox_, context_state_.get());
   EXPECT_FALSE(representation->IsCleared());
 
   // This will initialize the top half of destination.
@@ -464,7 +468,8 @@
 
   SharedImageRepresentationFactory repr_factory(shared_image_manager(),
                                                 nullptr);
-  auto representation = repr_factory.ProduceGLTexture(client_texture_mailbox_);
+  auto representation =
+      repr_factory.ProduceSkia(client_texture_mailbox_, context_state_.get());
   EXPECT_FALSE(representation->IsCleared());
 
   // This will initialize the top half of destination.
diff --git a/gpu/command_buffer/service/wrapped_sk_image.cc b/gpu/command_buffer/service/wrapped_sk_image.cc
index 1458e46..1d6530d 100644
--- a/gpu/command_buffer/service/wrapped_sk_image.cc
+++ b/gpu/command_buffer/service/wrapped_sk_image.cc
@@ -597,17 +597,7 @@
   auto kWrappedSkImageUsage = SHARED_IMAGE_USAGE_DISPLAY |
                               SHARED_IMAGE_USAGE_RASTER |
                               SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
-
-  if (gr_context_type != GrContextType::kGL) {
-    // For SkiaRenderer/Vulkan+Dawn use WrappedSkImage if the usage is only
-    // raster and/or display.
-    return (usage & kWrappedSkImageUsage) && !(usage & ~kWrappedSkImageUsage);
-  } else {
-    // For SkiaRenderer/GL only use WrappedSkImages for OOP-R because
-    // CopySubTexture() doesn't use Skia. https://crbug.com/984045
-    return (usage == kWrappedSkImageUsage) ||
-           (usage == SHARED_IMAGE_USAGE_DISPLAY);
-  }
+  return (usage & kWrappedSkImageUsage) && !(usage & ~kWrappedSkImageUsage);
 }
 
 bool WrappedSkImageFactory::IsSupported(uint32_t usage,
@@ -630,6 +620,13 @@
     return false;
   }
 
+  // Currently, WrappedSkImage does not support LUMINANCE_8 format and this
+  // format is used for single channel planes. See https://crbug.com/1252502 for
+  // more details.
+  if (format == viz::LUMINANCE_8) {
+    return false;
+  }
+
   if (!CanUseWrappedSkImage(usage, gr_context_type)) {
     return false;
   }
diff --git a/gpu/config/build_workaround_header.py b/gpu/config/build_workaround_header.py
index 91094be..7f007c9 100755
--- a/gpu/config/build_workaround_header.py
+++ b/gpu/config/build_workaround_header.py
@@ -1,13 +1,13 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright (c) 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.
 """code generator for gpu workaround definitions"""
 
+import argparse
 import os
-import os.path
 import sys
-from optparse import OptionParser
+import typing
 
 _LICENSE = """// Copyright 2018 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
@@ -19,7 +19,7 @@
   "//    //gpu/config/build_workaround_header.py\n" +
   "// DO NOT EDIT!\n\n")
 
-def merge_files_into_workarounds(files):
+def merge_files_into_workarounds(files: typing.List[str]) -> typing.List[str]:
   workarounds = set()
   for filename in files:
     with open(filename, 'r') as f:
@@ -27,7 +27,7 @@
   return sorted(list(workarounds))
 
 
-def write_header(filename, workarounds):
+def write_header(filename: str, workarounds: typing.List[str]) -> None:
   max_workaround_len = len(max(workarounds, key=len))
 
   with open(filename, 'w') as f:
@@ -51,18 +51,21 @@
 
 
 def main(argv):
-  usage = "usage: %prog [options] file1 file2 file3 etc"
-  parser = OptionParser(usage=usage)
-  parser.add_option(
+  parser = argparse.ArgumentParser(
+      description='Generate GPU workaround definitions')
+  parser.add_argument(
       "--output-file",
-      dest="output_file",
       default="gpu_driver_bug_workaround_autogen.h",
       help="the name of the header file to write")
+  parser.add_argument(
+      'files',
+      nargs='+',
+      help='1 or more files to process')
 
-  (options, _) = parser.parse_args(args=argv)
+  args = parser.parse_args()
 
-  workarounds = merge_files_into_workarounds(parser.largs)
-  write_header(options.output_file, workarounds)
+  workarounds = merge_files_into_workarounds(args.files)
+  write_header(args.output_file, workarounds)
 
 
 if __name__ == '__main__':
diff --git a/headless/app/headless_shell_switches.cc b/headless/app/headless_shell_switches.cc
index bd16bb31..a6934b4 100644
--- a/headless/app/headless_shell_switches.cc
+++ b/headless/app/headless_shell_switches.cc
@@ -60,6 +60,9 @@
 // Do not display header and footer in the pdf file.
 const char kPrintToPDFNoHeader[] = "print-to-pdf-no-header";
 
+// Do not emit tags when printing PDFs.
+const char kDisablePDFTagging[] = "disable-pdf-tagging";
+
 // Specifies a list of hosts for whom we bypass proxy settings and use direct
 // connections. Ignored unless --proxy-server is also specified. This is a
 // comma-separated list of bypass rules. See:
diff --git a/headless/app/headless_shell_switches.h b/headless/app/headless_shell_switches.h
index 7d0ecb3..96b2957 100644
--- a/headless/app/headless_shell_switches.h
+++ b/headless/app/headless_shell_switches.h
@@ -24,6 +24,7 @@
 HEADLESS_EXPORT extern const char kPasswordStore[];
 HEADLESS_EXPORT extern const char kPrintToPDF[];
 HEADLESS_EXPORT extern const char kPrintToPDFNoHeader[];
+HEADLESS_EXPORT extern const char kDisablePDFTagging[];
 HEADLESS_EXPORT extern const char kProxyBypassList[];
 HEADLESS_EXPORT extern const char kProxyServer[];
 HEADLESS_EXPORT extern const char kNoSystemProxyConfigService[];
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index 51be17a..024dc8e 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -216,6 +216,9 @@
   }
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
+  if (old_command_line.HasSwitch(switches::kDisablePDFTagging))
+    command_line->AppendSwitch(switches::kDisablePDFTagging);
+
   // If we're spawning a renderer, then override the language switch.
   std::string process_type =
       command_line->GetSwitchValueASCII(::switches::kProcessType);
diff --git a/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc b/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc
index 7903872..6db896f 100644
--- a/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc
+++ b/headless/lib/renderer/headless_print_render_frame_helper_delegate.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "headless/lib/renderer/headless_print_render_frame_helper_delegate.h"
+#include "base/command_line.h"
+#include "headless/app/headless_shell_switches.h"
 #include "third_party/blink/public/web/web_element.h"
 
 namespace headless {
@@ -23,8 +25,8 @@
 }
 
 bool HeadlessPrintRenderFrameHelperDelegate::ShouldGenerateTaggedPDF() {
-  // Always generate tagged PDF, see: https://crbug.com/607777
-  return true;
+  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
+      headless::switches::kDisablePDFTagging);
 }
 
 bool HeadlessPrintRenderFrameHelperDelegate::OverridePrint(
diff --git a/headless/test/headless_web_contents_browsertest.cc b/headless/test/headless_web_contents_browsertest.cc
index aadcfe87..b569bb4e 100644
--- a/headless/test/headless_web_contents_browsertest.cc
+++ b/headless/test/headless_web_contents_browsertest.cc
@@ -652,10 +652,9 @@
      kExpectedImageRoleOnlyStructTreeJSON},
 };
 
-class HeadlessWebContentsTaggedPDFTest
+class HeadlessWebContentsTaggedPDFTestBase
     : public HeadlessAsyncDevTooledBrowserTest,
-      public page::Observer,
-      public ::testing::WithParamInterface<TaggedPDFTestData> {
+      public page::Observer {
  public:
   void RunDevTooledTest() override {
     EXPECT_TRUE(embedded_test_server()->Start());
@@ -667,7 +666,7 @@
     run_loop.Run();
 
     devtools_client_->GetPage()->Navigate(
-        embedded_test_server()->GetURL(GetParam().url).spec());
+        embedded_test_server()->GetURL(GetUrl()).spec());
   }
 
   void OnLoadEventFired(const page::LoadEventFiredParams&) override {
@@ -681,7 +680,7 @@
             .SetMarginLeft(0)
             .SetMarginRight(0)
             .Build(),
-        base::BindOnce(&HeadlessWebContentsTaggedPDFTest::OnPDFCreated,
+        base::BindOnce(&HeadlessWebContentsTaggedPDFTestBase::OnPDFCreated,
                        base::Unretained(this)));
   }
 
@@ -694,9 +693,24 @@
     EXPECT_TRUE(chrome_pdf::GetPDFDocInfo(pdf_span, &num_pages, nullptr));
     EXPECT_EQ(1, num_pages);
 
+    CheckPDF(pdf_span);
+
+    FinishAsynchronousTest();
+  }
+
+  virtual const char* GetUrl() = 0;
+  virtual void CheckPDF(base::span<const uint8_t> pdf_span) = 0;
+};
+
+class HeadlessWebContentsTaggedPDFTest
+    : public HeadlessWebContentsTaggedPDFTestBase,
+      public ::testing::WithParamInterface<TaggedPDFTestData> {
+ public:
+  const char* GetUrl() override { return GetParam().url; }
+
+  void CheckPDF(base::span<const uint8_t> pdf_span) override {
     absl::optional<bool> tagged = chrome_pdf::IsPDFDocTagged(pdf_span);
-    ASSERT_TRUE(tagged.has_value());
-    EXPECT_TRUE(tagged.value());
+    EXPECT_THAT(tagged, testing::Optional(true));
 
     constexpr int kFirstPage = 0;
     base::Value struct_tree =
@@ -708,8 +722,6 @@
     base::RemoveChars(json, "\r", &json);
 
     EXPECT_EQ(GetParam().expected_json, json);
-
-    FinishAsynchronousTest();
   }
 };
 
@@ -719,6 +731,29 @@
                          HeadlessWebContentsTaggedPDFTest,
                          ::testing::ValuesIn(kTaggedPDFTestData));
 
+class HeadlessWebContentsTaggedPDFDisabledTest
+    : public HeadlessWebContentsTaggedPDFTestBase,
+      public ::testing::WithParamInterface<TaggedPDFTestData> {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    HeadlessWebContentsTaggedPDFTestBase::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kDisablePDFTagging);
+  }
+
+  const char* GetUrl() override { return GetParam().url; }
+
+  void CheckPDF(base::span<const uint8_t> pdf_span) override {
+    absl::optional<bool> tagged = chrome_pdf::IsPDFDocTagged(pdf_span);
+    EXPECT_THAT(tagged, testing::Optional(false));
+  }
+};
+
+HEADLESS_ASYNC_DEVTOOLED_TEST_P(HeadlessWebContentsTaggedPDFDisabledTest);
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         HeadlessWebContentsTaggedPDFDisabledTest,
+                         ::testing::ValuesIn(kTaggedPDFTestData));
+
 #endif  // BUILDFLAG(ENABLE_TAGGED_PDF)
 
 #endif  // BUILDFLAG(ENABLE_PRINTING) && BUILDFLAG(ENABLE_PDF)
diff --git a/infra/config/generated/builders/ci/win-pixel-builder-rel/properties.json b/infra/config/generated/builders/ci/win-pixel-builder-rel/properties.json
deleted file mode 100644
index c5b49c9..0000000
--- a/infra/config/generated/builders/ci/win-pixel-builder-rel/properties.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "$build/reclient": {
-    "instance": "rbe-chromium-trusted",
-    "jobs": 80,
-    "metrics_project": "chromium-reclient-metrics"
-  },
-  "$recipe_engine/resultdb/test_presentation": {
-    "column_keys": [],
-    "grouping_keys": [
-      "status",
-      "v.test_suite"
-    ]
-  },
-  "builder_group": "chromium.fyi",
-  "recipe": "chromium"
-}
\ No newline at end of file
diff --git a/infra/config/generated/builders/ci/win-pixel-tester-rel/properties.json b/infra/config/generated/builders/ci/win-pixel-tester-rel/properties.json
deleted file mode 100644
index ef42b767..0000000
--- a/infra/config/generated/builders/ci/win-pixel-tester-rel/properties.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "$recipe_engine/resultdb/test_presentation": {
-    "column_keys": [],
-    "grouping_keys": [
-      "status",
-      "v.test_suite"
-    ]
-  },
-  "builder_group": "chromium.fyi",
-  "recipe": "chromium"
-}
\ No newline at end of file
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 08c6ab29..221d135 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -39596,163 +39596,6 @@
       }
     }
     builders {
-      name: "win-pixel-builder-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builder:win-pixel-builder-rel"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows-10"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/chromium/bootstrapper/${platform}"
-        cipd_version: "latest"
-        cmd: "bootstrapper"
-      }
-      properties:
-        '{'
-        '  "$bootstrap/exe": {'
-        '    "exe": {'
-        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
-        '      "cipd_version": "refs/heads/main",'
-        '      "cmd": ['
-        '        "luciexe"'
-        '      ]'
-        '    }'
-        '  },'
-        '  "$bootstrap/properties": {'
-        '    "properties_file": "infra/config/generated/builders/ci/win-pixel-builder-rel/properties.json",'
-        '    "top_level_project": {'
-        '      "ref": "refs/heads/main",'
-        '      "repo": {'
-        '        "host": "chromium.googlesource.com",'
-        '        "project": "chromium/src"'
-        '      }'
-        '    }'
-        '  },'
-        '  "builder_group": "chromium.fyi",'
-        '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
-        '}'
-      execution_timeout_secs: 36000
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "luci.recipes.use_python3"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "gpu_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
-            }
-          }
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "blink_web_tests_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://[^/]*blink_web_tests/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
-      name: "win-pixel-tester-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/chromium/bootstrapper/${platform}"
-        cipd_version: "latest"
-        cmd: "bootstrapper"
-      }
-      properties:
-        '{'
-        '  "$bootstrap/exe": {'
-        '    "exe": {'
-        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
-        '      "cipd_version": "refs/heads/main",'
-        '      "cmd": ['
-        '        "luciexe"'
-        '      ]'
-        '    }'
-        '  },'
-        '  "$bootstrap/properties": {'
-        '    "properties_file": "infra/config/generated/builders/ci/win-pixel-tester-rel/properties.json",'
-        '    "top_level_project": {'
-        '      "ref": "refs/heads/main",'
-        '      "repo": {'
-        '        "host": "chromium.googlesource.com",'
-        '        "project": "chromium/src"'
-        '      }'
-        '    }'
-        '  },'
-        '  "builder_group": "chromium.fyi",'
-        '  "led_builder_is_bootstrapped": true,'
-        '  "recipe": "chromium"'
-        '}'
-      execution_timeout_secs: 36000
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "luci.recipes.use_python3"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "gpu_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
-            }
-          }
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "blink_web_tests_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://[^/]*blink_web_tests/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
       name: "win-swangle-chromium-x86"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index 85d04372..200a684 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -7848,14 +7848,6 @@
     category: "win10"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/win-pixel-builder-rel"
-    category: "win10"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/win-pixel-tester-rel"
-    category: "win10"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/win32-arm64-rel"
     category: "win32|arm64"
   }
diff --git a/infra/config/generated/luci/luci-scheduler.cfg b/infra/config/generated/luci/luci-scheduler.cfg
index 2ddeb554..295433ee7 100644
--- a/infra/config/generated/luci/luci-scheduler.cfg
+++ b/infra/config/generated/luci/luci-scheduler.cfg
@@ -6458,30 +6458,6 @@
   }
 }
 job {
-  id: "win-pixel-builder-rel"
-  realm: "ci"
-  acl_sets: "ci"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "ci"
-    builder: "win-pixel-builder-rel"
-  }
-}
-job {
-  id: "win-pixel-tester-rel"
-  realm: "ci"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "ci"
-    builder: "win-pixel-tester-rel"
-  }
-}
-job {
   id: "win-swangle-chromium-x86"
   realm: "ci"
   acl_sets: "ci"
@@ -7100,7 +7076,6 @@
   triggers: "win-backuprefptr-x86-fyi-rel"
   triggers: "win-fieldtrial-rel"
   triggers: "win-official"
-  triggers: "win-pixel-builder-rel"
   triggers: "win-swangle-chromium-x86"
   triggers: "win-swangle-tot-swiftshader-x64"
   triggers: "win-swangle-tot-swiftshader-x86"
diff --git a/infra/config/generated/luci/realms.cfg b/infra/config/generated/luci/realms.cfg
index de55bb4..ba4c2fa3 100644
--- a/infra/config/generated/luci/realms.cfg
+++ b/infra/config/generated/luci/realms.cfg
@@ -163,7 +163,6 @@
         values: "mac11.0-updater-tester-dbg"
         values: "mac11.0-updater-tester-rel"
         values: "win-celab-tester-rel"
-        values: "win-pixel-tester-rel"
         values: "win10-updater-tester-dbg"
         values: "win10-updater-tester-dbg-uac"
         values: "win10-updater-tester-rel"
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star
index 1491267..1472fa7 100644
--- a/infra/config/subprojects/chromium/ci/chromium.fyi.star
+++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -732,25 +732,6 @@
 )
 
 ci.builder(
-    name = "win-pixel-builder-rel",
-    console_view_entry = consoles.console_view_entry(
-        category = "win10",
-    ),
-    os = os.WINDOWS_10,
-    goma_backend = None,
-    reclient_jobs = rbe_jobs.LOW_JOBS_FOR_CI,
-    reclient_instance = rbe_instance.DEFAULT,
-)
-
-ci.thin_tester(
-    name = "win-pixel-tester-rel",
-    console_view_entry = consoles.console_view_entry(
-        category = "win10",
-    ),
-    triggered_by = ["win-pixel-builder-rel"],
-)
-
-ci.builder(
     name = "linux-upload-perfetto",
     console_view_entry = consoles.console_view_entry(
         category = "perfetto",
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h
index 9222c1f..9c88b2f 100644
--- a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h
+++ b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h
@@ -32,7 +32,7 @@
   // Notifies the receiver that the most recent tab was removed.
   virtual void MostRecentTabRemoved(web::WebState* web_state) {}
   // Notifies the receiver that the favicon for the current page of the most
-  // recent tab was updated to |image|.
+  // recent tab was updated to `image`.
   virtual void MostRecentTabFaviconUpdated(UIImage* image) {}
 
  protected:
@@ -92,11 +92,11 @@
   // A list of observers notified when the most recent tab is removed. Weak
   // references.
   base::ObserverList<StartSurfaceRecentTabObserver, true>::Unchecked observers_;
-  // Manages observation relationship between |this| and favicon::FaviconDriver.
+  // Manages observation relationship between `this` and favicon::FaviconDriver.
   base::ScopedObservation<favicon::FaviconDriver,
                           favicon::FaviconDriverObserver>
       favicon_driver_observer_{this};
-  // Manages observation relationship between |this| and web::WebState.
+  // Manages observation relationship between `this` and web::WebState.
   base::ScopedObservation<web::WebState, web::WebStateObserver>
       web_state_observation_{this};
   // The most recent tab managed by this Browser Agent.
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.h b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.h
index 802048b..64080b20 100644
--- a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.h
+++ b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.h
@@ -20,7 +20,7 @@
 // Notifies the receiver that the most recent tab was removed.
 - (void)mostRecentTabWasRemoved:(web::WebState*)web_state;
 // Notifies the receiver that the favicon for the current page of the most
-// recent tab was updated with |image|.
+// recent tab was updated with `image`.
 - (void)mostRecentTabFaviconUpdatedWithImage:(UIImage*)image;
 @end
 
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm b/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm
index 298c29e..580489a1 100644
--- a/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm
+++ b/ios/chrome/browser/ui/start_surface/start_surface_scene_agent.mm
@@ -95,7 +95,7 @@
   }
 
   // If there is no active tab, a NTP will be added, and since there is no
-  // recent tab, there is no need to mark |modifytVisibleNTPForStartSurface|.
+  // recent tab, there is no need to mark `modifytVisibleNTPForStartSurface`.
   // Keep showing the last active NTP tab no matter whether the Start Surface is
   // enabled or not by design.
   // Note that activeWebState could only be nullptr when the Tab grid is active
@@ -132,7 +132,7 @@
       /*inherit_opener=*/false, /*should_show_start_surface=*/true);
 }
 
-// Removes duplicate NTP tabs in |browser|'s WebStateList.
+// Removes duplicate NTP tabs in `browser`'s WebStateList.
 - (void)removeExcessNTPsInBrowser:(Browser*)browser {
   WebStateList* webStateList = browser->GetWebStateList();
   web::WebState* activeWebState =
@@ -146,11 +146,11 @@
     web::WebState* webState = webStateList->GetWebStateAt(i);
     if (IsURLNtp(webState->GetVisibleURL())) {
       // Check if there is navigation history for this WebState that is showing
-      // the NTP. If there is, then set |keepOneNTP| to NO, indicating that all
+      // the NTP. If there is, then set `keepOneNTP` to NO, indicating that all
       // WebStates in NTPs with no navigation history will get removed.
       if (webState->GetNavigationItemCount() == 1) {
         // Keep track if active WebState is showing an NTP and has no navigation
-        // history since it may get removed if |keepOneNTP| is NO.
+        // history since it may get removed if `keepOneNTP` is NO.
         if (i == activeWebStateIndex) {
           activeWebStateIsEmptyNTP = YES;
         }
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_scene_agent_unittest.mm b/ios/chrome/browser/ui/start_surface/start_surface_scene_agent_unittest.mm
index 007b5b4..a2fa711b 100644
--- a/ios/chrome/browser/ui/start_surface/start_surface_scene_agent_unittest.mm
+++ b/ios/chrome/browser/ui/start_surface/start_surface_scene_agent_unittest.mm
@@ -98,7 +98,7 @@
   StartSurfaceSceneAgent* agent_;
   std::unique_ptr<base::HistogramTester> histogram_tester_;
 
-  // Create WebState at |index| with |url| as the current url.
+  // Create WebState at `index` with `url` as the current url.
   void InsertNewWebState(int index, WebStateOpener opener, GURL url) {
     auto test_web_state = std::make_unique<web::FakeWebState>();
     test_web_state->SetCurrentURL(url);
@@ -111,8 +111,8 @@
                                    WebStateList::INSERT_FORCE_INDEX, opener);
   }
 
-  // Create a WebState that has a navigation history of more than one at |index|
-  // with |url| as the current url.
+  // Create a WebState that has a navigation history of more than one at `index`
+  // with `url` as the current url.
   void InsertNewWebStateWithNavigationHistory(int index,
                                               WebStateOpener opener,
                                               GURL url) {
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index f0c68ec..959234bc 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-aed135a538cfc589609f2a24aa52f0815a956cf5
\ No newline at end of file
+d34ea74ee7f6918eb0449593d2980db29330a011
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 71d8b722..495b3bb3 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-fd48a5ae58ac79edc0800872ccbfdea534c65ab7
\ No newline at end of file
+e91dd682e3f3c5abbea1fc56f21275e3615c73ac
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 1c9a442..4e9f6ef2 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-5e24d9053d8b0839b890e688e1f32fa9b700c980
\ No newline at end of file
+0446aca7d4398e6abdf334adbbef4880df24a91d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index da294c0..5d8f5b5b 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-765fdea9618b963b796ab84f7af35e2b6cb3f5db
\ No newline at end of file
+b339ee9a31341f700bfd2d236495af991bebd732
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index ada9420..7ff2d60 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-5e495c00c7f02a285230c65e2c58ca416345159e
\ No newline at end of file
+92e681f78663b7a192b8916944cfd2935e6be22e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index 1d5df17..9012fc57 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-ba8e64563ce15b8128dca4a7b5a0e07aa47dfe8c
\ No newline at end of file
+9082561cacac6faa00fb27c4e5cb346f4fe0456b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index f509873..c5e9a53 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-f0312c0cc263fb33708150519c64c82426f6dd91
\ No newline at end of file
+542cc3d6ce1340b03823e0798b9a0cf6a951402b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 625ee86..af7cac58 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-50ec00fb010f00ad5460d4c52a92bd42981a9c76
\ No newline at end of file
+2511ff961201b91e3917059dd4ef672051369de2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 435abd0..4689965b 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-d2065749519926382eff8ca1036165b875cae5f6
\ No newline at end of file
+d9246801b771979357ea96750a9e9daa61f3c5b4
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 460636a..0857492 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-42c302c1b99344aeb833f407f15c68828e40189c
\ No newline at end of file
+254f5a0f6fd0c2990860c34e2b84f332fea72acd
\ No newline at end of file
diff --git a/media/mojo/common/audio_data_s16_converter.cc b/media/mojo/common/audio_data_s16_converter.cc
index add32e1..7d1a07b28 100644
--- a/media/mojo/common/audio_data_s16_converter.cc
+++ b/media/mojo/common/audio_data_s16_converter.cc
@@ -10,6 +10,7 @@
 #include "media/base/audio_bus.h"
 #include "media/base/audio_timestamp_helper.h"
 #include "media/base/channel_mixer.h"
+#include "media/mojo/mojom/audio_data.mojom.h"
 #include "media/mojo/mojom/media_types.mojom.h"
 
 namespace media {
@@ -117,4 +118,4 @@
   }
 }
 
-}  // namespace media
\ No newline at end of file
+}  // namespace media
diff --git a/media/mojo/mojom/BUILD.gn b/media/mojo/mojom/BUILD.gn
index 008e0bc9..5b76359 100644
--- a/media/mojo/mojom/BUILD.gn
+++ b/media/mojo/mojom/BUILD.gn
@@ -73,6 +73,7 @@
   }
 
   public_deps = [
+    ":audio_data",
     ":encryption_pattern",
     "//gpu/ipc/common:interfaces",
     "//media/learning/mojo/public/mojom",
@@ -730,6 +731,11 @@
   export_header_blink = "third_party/blink/public/platform/web_common.h"
 }
 
+mojom("audio_data") {
+  generate_java = true
+  sources = [ "audio_data.mojom" ]
+}
+
 mojom("encryption_pattern") {
   generate_java = true
   sources = [ "encryption_pattern.mojom" ]
diff --git a/media/mojo/mojom/audio_data.mojom b/media/mojo/mojom/audio_data.mojom
new file mode 100644
index 0000000..8d48cfc
--- /dev/null
+++ b/media/mojo/mojom/audio_data.mojom
@@ -0,0 +1,24 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module media.mojom;
+
+// This defines a mojo transport format for an interleaved, signed
+// 16-bit audio buffer.
+// Marked [Stable], enabling its use across the LaCrOS/Ash boundary as part of
+// the speech recognition API.
+[Stable]
+struct AudioDataS16 {
+  // Number of channels.
+  int32 channel_count;
+
+  // Sample rate of the buffer.
+  int32 sample_rate;
+
+  // Number of frames in the buffer.
+  int32 frame_count;
+
+  // Channel data.
+  array<int16> data;
+};
diff --git a/media/mojo/mojom/media_types.mojom b/media/mojo/mojom/media_types.mojom
index e5ff8d6..ba8b55be 100644
--- a/media/mojo/mojom/media_types.mojom
+++ b/media/mojo/mojom/media_types.mojom
@@ -6,6 +6,7 @@
 
 import "gpu/ipc/common/mailbox_holder.mojom";
 import "gpu/ipc/common/vulkan_ycbcr_info.mojom";
+import "media/mojo/mojom/audio_data.mojom";
 import "media/mojo/mojom/encryption_pattern.mojom";
 import "mojo/public/mojom/base/shared_memory.mojom";
 import "mojo/public/mojom/base/time.mojom";
@@ -273,22 +274,6 @@
   array<uint8> data;
 };
 
-// This defines a mojo transport format for an interleaved, signed
-// 16-bit audio buffer.
-struct AudioDataS16 {
-  // Number of channels.
-  int32 channel_count;
-
-  // Sample rate of the buffer.
-  int32 sample_rate;
-
-  // Number of frames in the buffer.
-  int32 frame_count;
-
-  // Channel data.
-  array<int16> data;
-};
-
 // See media/base/video_frame_metadata.h for a description of fields.
 // TODO(crbug.com/657632): Remove |has_*| values and use nullable types.
 struct VideoFrameMetadata {
diff --git a/media/mojo/mojom/speech_recognition_service.mojom b/media/mojo/mojom/speech_recognition_service.mojom
index cd161cb..1fbbe888e 100644
--- a/media/mojo/mojom/speech_recognition_service.mojom
+++ b/media/mojo/mojom/speech_recognition_service.mojom
@@ -4,6 +4,7 @@
 
 module media.mojom;
 
+import "media/mojo/mojom/audio_data.mojom";
 import "media/mojo/mojom/audio_parameters.mojom";
 import "media/mojo/mojom/audio_stream_factory.mojom";
 import "media/mojo/mojom/media_types.mojom";
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 698d0fd..f34c1a9c 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -2084,6 +2084,10 @@
     "disk_cache/disk_cache_test_base.h",
     "disk_cache/disk_cache_test_util.cc",
     "disk_cache/disk_cache_test_util.h",
+    "disk_cache/mock/mock_backend_impl.cc",
+    "disk_cache/mock/mock_backend_impl.h",
+    "disk_cache/mock/mock_entry_impl.cc",
+    "disk_cache/mock/mock_entry_impl.h",
     "filter/filter_source_stream_test_util.cc",
     "filter/filter_source_stream_test_util.h",
     "filter/mock_source_stream.cc",
diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc
index f10ab4040..cb40c44 100644
--- a/net/cert/cert_verify_proc.cc
+++ b/net/cert/cert_verify_proc.cc
@@ -812,7 +812,7 @@
         continue;
       base::StringPiece suffix =
           base::StringPiece(dns_name).substr(dns_name.size() - domain.size());
-      if (!base::LowerCaseEqualsASCII(suffix, domain))
+      if (!base::EqualsCaseInsensitiveASCII(suffix, domain))
         continue;
       ok = true;
       break;
diff --git a/net/disk_cache/mock/mock_backend_impl.cc b/net/disk_cache/mock/mock_backend_impl.cc
new file mode 100644
index 0000000..51fab72
--- /dev/null
+++ b/net/disk_cache/mock/mock_backend_impl.cc
@@ -0,0 +1,12 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/disk_cache/mock/mock_backend_impl.h"
+
+namespace disk_cache {
+
+BackendMock::BackendMock(net::CacheType cache_type) : Backend(cache_type) {}
+BackendMock::~BackendMock() = default;
+
+}  // namespace disk_cache
diff --git a/net/disk_cache/mock/mock_backend_impl.h b/net/disk_cache/mock/mock_backend_impl.h
new file mode 100644
index 0000000..63d35f4
--- /dev/null
+++ b/net/disk_cache/mock/mock_backend_impl.h
@@ -0,0 +1,83 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_DISK_CACHE_MOCK_MOCK_BACKEND_IMPL_H_
+#define NET_DISK_CACHE_MOCK_MOCK_BACKEND_IMPL_H_
+
+#include "net/disk_cache/disk_cache.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace disk_cache {
+
+class BackendMock : public Backend {
+ public:
+  explicit BackendMock(net::CacheType cache_type);
+  ~BackendMock() override;
+
+  MOCK_METHOD(int32_t, GetEntryCount, (), (const, override));
+  MOCK_METHOD(EntryResult,
+              OpenOrCreateEntry,
+              (const std::string& key,
+               net::RequestPriority priority,
+               EntryResultCallback callback),
+              (override));
+  MOCK_METHOD(EntryResult,
+              OpenEntry,
+              (const std::string& key,
+               net::RequestPriority priority,
+               EntryResultCallback),
+              (override));
+  MOCK_METHOD(EntryResult,
+              CreateEntry,
+              (const std::string& key,
+               net::RequestPriority priority,
+               EntryResultCallback callback),
+              (override));
+  MOCK_METHOD(net::Error,
+              DoomEntry,
+              (const std::string& key,
+               net::RequestPriority priority,
+               CompletionOnceCallback callback),
+              (override));
+  MOCK_METHOD(net::Error,
+              DoomAllEntries,
+              (CompletionOnceCallback callback),
+              (override));
+  MOCK_METHOD(net::Error,
+              DoomEntriesBetween,
+              (base::Time initial_time,
+               base::Time end_time,
+               CompletionOnceCallback callback),
+              (override));
+  MOCK_METHOD(net::Error,
+              DoomEntriesSince,
+              (base::Time initial_time, CompletionOnceCallback callback),
+              (override));
+  MOCK_METHOD(int64_t,
+              CalculateSizeOfAllEntries,
+              (Int64CompletionOnceCallback callback),
+              (override));
+  MOCK_METHOD(int64_t,
+              CalculateSizeOfEntriesBetween,
+              (base::Time initial_time,
+               base::Time end_time,
+               Int64CompletionOnceCallback callback),
+              (override));
+  MOCK_METHOD(std::unique_ptr<Iterator>, CreateIterator, (), (override));
+  MOCK_METHOD(void, GetStats, (base::StringPairs * stats), (override));
+  MOCK_METHOD(void, OnExternalCacheHit, (const std::string& key), (override));
+  MOCK_METHOD(uint8_t,
+              GetEntryInMemoryData,
+              (const std::string& key),
+              (override));
+  MOCK_METHOD(void,
+              SetEntryInMemoryData,
+              (const std::string& key, uint8_t data),
+              (override));
+  MOCK_METHOD(int64_t, MaxFileSize, (), (const, override));
+};
+
+}  // namespace disk_cache
+
+#endif  // NET_DISK_CACHE_MOCK_MOCK_BACKEND_IMPL_H_
diff --git a/net/disk_cache/mock/mock_entry_impl.cc b/net/disk_cache/mock/mock_entry_impl.cc
new file mode 100644
index 0000000..0d8c155
--- /dev/null
+++ b/net/disk_cache/mock/mock_entry_impl.cc
@@ -0,0 +1,12 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/disk_cache/mock/mock_entry_impl.h"
+
+namespace disk_cache {
+
+EntryMock::EntryMock() = default;
+EntryMock::~EntryMock() = default;
+
+}  // namespace disk_cache
diff --git a/net/disk_cache/mock/mock_entry_impl.h b/net/disk_cache/mock/mock_entry_impl.h
new file mode 100644
index 0000000..8f747b2a
--- /dev/null
+++ b/net/disk_cache/mock/mock_entry_impl.h
@@ -0,0 +1,73 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_DISK_CACHE_MOCK_MOCK_ENTRY_IMPL_H_
+#define NET_DISK_CACHE_MOCK_MOCK_ENTRY_IMPL_H_
+
+#include "net/disk_cache/disk_cache.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace disk_cache {
+
+class EntryMock : public Entry {
+ public:
+  EntryMock();
+  ~EntryMock() override;
+
+  // Manual override of the Close function because the Entry interface expects
+  // the Close override to cleanup the class (including deleting itself).
+  void Close() override { delete this; }
+
+  MOCK_METHOD(void, Doom, (), (override));
+  MOCK_METHOD(std::string, GetKey, (), (const, override));
+  MOCK_METHOD(base::Time, GetLastUsed, (), (const, override));
+  MOCK_METHOD(base::Time, GetLastModified, (), (const, override));
+  MOCK_METHOD(int32_t, GetDataSize, (int index), (const, override));
+  MOCK_METHOD(int,
+              ReadData,
+              (int index,
+               int offset,
+               IOBuffer* buf,
+               int buf_len,
+               CompletionOnceCallback callback),
+              (override));
+  MOCK_METHOD(int,
+              WriteData,
+              (int index,
+               int offset,
+               IOBuffer* buf,
+               int buf_len,
+               CompletionOnceCallback callback,
+               bool truncate),
+              (override));
+  MOCK_METHOD(int,
+              ReadSparseData,
+              (int64_t offset,
+               IOBuffer* buf,
+               int buf_len,
+               CompletionOnceCallback callback),
+              (override));
+  MOCK_METHOD(int,
+              WriteSparseData,
+              (int64_t offset,
+               IOBuffer* buf,
+               int buf_len,
+               CompletionOnceCallback callback),
+              (override));
+  MOCK_METHOD(RangeResult,
+              GetAvailableRange,
+              (int64_t offset, int len, RangeResultCallback callback),
+              (override));
+  MOCK_METHOD(bool, CouldBeSparse, (), (const, override));
+  MOCK_METHOD(void, CancelSparseIO, (), (override));
+  MOCK_METHOD(net::Error,
+              ReadyForSparseIO,
+              (CompletionOnceCallback callback),
+              (override));
+  MOCK_METHOD(void, SetLastUsedTimeForTest, (base::Time time), (override));
+};
+
+}  // namespace disk_cache
+
+#endif  // NET_DISK_CACHE_MOCK_MOCK_ENTRY_IMPL_H_
diff --git a/net/quic/platform/impl/quic_test_flags_utils.cc b/net/quic/platform/impl/quic_test_flags_utils.cc
index 12e4d3f..3c268bd 100644
--- a/net/quic/platform/impl/quic_test_flags_utils.cc
+++ b/net/quic/platform/impl/quic_test_flags_utils.cc
@@ -12,7 +12,7 @@
 #include "net/third_party/quiche/src/quiche/quic/platform/api/quic_flags.h"
 
 QuicFlagSaverImpl::QuicFlagSaverImpl() {
-#define QUIC_FLAG(flag, value) saved_##flag##_ = flag;
+#define QUIC_FLAG(flag, value) saved_##flag##_ = FLAGS_##flag;
 #include "net/third_party/quiche/src/quiche/quic/core/quic_flags_list.h"
 #undef QUIC_FLAG
 #define QUIC_PROTOCOL_FLAG(type, flag, ...) saved_##flag##_ = FLAGS_##flag;
@@ -21,7 +21,7 @@
 }
 
 QuicFlagSaverImpl::~QuicFlagSaverImpl() {
-#define QUIC_FLAG(flag, value) flag = saved_##flag##_;
+#define QUIC_FLAG(flag, value) FLAGS_##flag = saved_##flag##_;
 #include "net/third_party/quiche/src/quiche/quic/core/quic_flags_list.h"
 #undef QUIC_FLAG
 #define QUIC_PROTOCOL_FLAG(type, flag, ...) FLAGS_##flag = saved_##flag##_;
@@ -31,7 +31,7 @@
 
 QuicFlagChecker::QuicFlagChecker() {
 #define QUIC_FLAG(flag, value)                                            \
-  CHECK_EQ(value, flag)                                                   \
+  CHECK_EQ(value, FLAGS_##flag)                                           \
       << "Flag set to an unexpected value.  A prior test is likely "      \
       << "setting a flag without using a QuicFlagSaver. Use QuicTest to " \
          "avoid this issue.";
diff --git a/net/quic/set_quic_flag.cc b/net/quic/set_quic_flag.cc
index f023a655..960f115 100644
--- a/net/quic/set_quic_flag.cc
+++ b/net/quic/set_quic_flag.cc
@@ -45,10 +45,10 @@
 }  // namespace
 
 void SetQuicFlagByName(const std::string& flag_name, const std::string& value) {
-#define QUIC_FLAG(flag, default_value)    \
-  if (flag_name == #flag) {               \
-    SetQuicFlagByName_bool(&flag, value); \
-    return;                               \
+#define QUIC_FLAG(flag, default_value)            \
+  if (flag_name == "FLAGS_" #flag) {              \
+    SetQuicFlagByName_bool(&FLAGS_##flag, value); \
+    return;                                       \
   }
 #include "net/third_party/quiche/src/quiche/quic/core/quic_flags_list.h"
 #undef QUIC_FLAG
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc
index c1f6e94..430ff97 100644
--- a/net/socket/transport_client_socket_pool.cc
+++ b/net/socket/transport_client_socket_pool.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/auto_reset.h"
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -266,9 +267,9 @@
 
   request->net_log().BeginEvent(NetLogEventType::SOCKET_POOL);
 
-  int rv = CheckedRequestSocketInternal(
-      group_id, *request,
-      /*preconnect_done_closure=*/base::OnceClosure());
+  int rv =
+      RequestSocketInternal(group_id, *request,
+                            /*preconnect_done_closure=*/base::OnceClosure());
   if (rv != ERR_IO_PENDING) {
     if (rv == OK) {
       request->handle()->socket()->ApplySocketTag(request->socket_tag());
@@ -341,8 +342,7 @@
   for (int num_iterations_left = num_sockets;
        group->NumActiveSocketSlots() < num_sockets && num_iterations_left > 0;
        num_iterations_left--) {
-    rv = CheckedRequestSocketInternal(group_id, request,
-                                      preconnect_done_closure);
+    rv = RequestSocketInternal(group_id, request, preconnect_done_closure);
     if (rv == ERR_IO_PENDING) {
       ++pending_connect_job_count;
     }
@@ -385,6 +385,11 @@
     const GroupId& group_id,
     const Request& request,
     base::OnceClosure preconnect_done_closure) {
+#if DCHECK_IS_ON()
+  DCHECK(!request_in_process_);
+  base::AutoReset<bool> auto_reset(&request_in_process_, true);
+#endif  // DCHECK_IS_ON()
+
   ClientSocketHandle* const handle = request.handle();
   const bool preconnecting = !handle;
   DCHECK_EQ(preconnecting, !!preconnect_done_closure);
@@ -491,25 +496,6 @@
   return rv;
 }
 
-int TransportClientSocketPool::CheckedRequestSocketInternal(
-    const GroupId& group_id,
-    const Request& request,
-    base::OnceClosure preconnect_done_closure) {
-#if DCHECK_IS_ON()
-  DCHECK(!request_in_process_);
-  request_in_process_ = true;
-#endif  // DCHECK_IS_ON()
-
-  int ret = RequestSocketInternal(group_id, request,
-                                  std::move(preconnect_done_closure));
-
-#if DCHECK_IS_ON()
-  request_in_process_ = false;
-#endif  // DCHECK_IS_ON()
-
-  return ret;
-}
-
 bool TransportClientSocketPool::AssignIdleSocketToRequest(
     const Request& request,
     Group* group) {
@@ -1174,9 +1160,9 @@
     return;
   }
 
-  int rv = CheckedRequestSocketInternal(
-      group_id, *next_request,
-      /*preconnect_done_closure=*/base::OnceClosure());
+  int rv =
+      RequestSocketInternal(group_id, *next_request,
+                            /*preconnect_done_closure=*/base::OnceClosure());
   if (rv != ERR_IO_PENDING) {
     std::unique_ptr<Request> request = group->PopNextUnboundRequest();
     DCHECK(request);
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h
index 21b37d9..92cec633 100644
--- a/net/socket/transport_client_socket_pool.h
+++ b/net/socket/transport_client_socket_pool.h
@@ -696,11 +696,6 @@
                             const Request& request,
                             base::OnceClosure preconnect_done_closure);
 
-  // Wrapper around RequestSocketInternal that adds a reentrancy guard.
-  int CheckedRequestSocketInternal(const GroupId& group_id,
-                                   const Request& request,
-                                   base::OnceClosure preconnect_done_closure);
-
   // Assigns an idle socket for the group to the request.
   // Returns |true| if an idle socket is available, false otherwise.
   bool AssignIdleSocketToRequest(const Request& request, Group* group);
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 31a7041..60885c5 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -8240,15 +8240,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M102/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M102/out/Release",
           "--client-version=102",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -8274,7 +8274,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.93"
+              "revision": "version:102.0.5005.94"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -8325,15 +8325,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -8359,7 +8359,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.34"
+              "revision": "version:103.0.5060.35"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -8750,15 +8750,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--implementation-outdir",
           "../../weblayer_instrumentation_test_M102/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
           "--impl-version=102",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -8784,7 +8784,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.93"
+              "revision": "version:102.0.5005.94"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -8835,15 +8835,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--implementation-outdir",
           "../../weblayer_instrumentation_test_M103/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -8869,7 +8869,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.34"
+              "revision": "version:103.0.5060.35"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 6bef602..3eeb071 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -46214,15 +46214,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M102/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M102/out/Release",
           "--client-version=102",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -46248,7 +46248,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.93"
+              "revision": "version:102.0.5005.94"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46299,15 +46299,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -46333,7 +46333,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.34"
+              "revision": "version:103.0.5060.35"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46724,15 +46724,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--implementation-outdir",
           "../../weblayer_instrumentation_test_M102/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
           "--impl-version=102",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -46758,7 +46758,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.93"
+              "revision": "version:102.0.5005.94"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46809,15 +46809,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--implementation-outdir",
           "../../weblayer_instrumentation_test_M103/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -46843,7 +46843,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.34"
+              "revision": "version:103.0.5060.35"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47238,15 +47238,15 @@
       {
         "args": [
           "--additional-apk=apks/ChromePublic.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M102/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M102/out/Release",
           "--client-version=102",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -47272,7 +47272,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.93"
+              "revision": "version:102.0.5005.94"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47323,15 +47323,15 @@
       {
         "args": [
           "--additional-apk=apks/ChromePublic.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -47357,7 +47357,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.34"
+              "revision": "version:103.0.5060.35"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47748,15 +47748,15 @@
       {
         "args": [
           "--additional-apk=apks/ChromePublic.apk",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--implementation-outdir",
           "../../weblayer_instrumentation_test_M102/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
           "--impl-version=102",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -47782,7 +47782,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.93"
+              "revision": "version:102.0.5005.94"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47833,15 +47833,15 @@
       {
         "args": [
           "--additional-apk=apks/ChromePublic.apk",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--implementation-outdir",
           "../../weblayer_instrumentation_test_M103/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -47867,7 +47867,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.34"
+              "revision": "version:103.0.5060.35"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48330,15 +48330,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M102/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M102/out/Release",
           "--client-version=102",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -48364,7 +48364,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.93"
+              "revision": "version:102.0.5005.94"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48415,15 +48415,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -48449,7 +48449,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.34"
+              "revision": "version:103.0.5060.35"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48840,15 +48840,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--implementation-outdir",
           "../../weblayer_instrumentation_test_M102/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
           "--impl-version=102",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -48874,7 +48874,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.93"
+              "revision": "version:102.0.5005.94"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48925,15 +48925,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--implementation-outdir",
           "../../weblayer_instrumentation_test_M103/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -48959,7 +48959,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.34"
+              "revision": "version:103.0.5060.35"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49422,15 +49422,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M102/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M102/out/Release",
           "--client-version=102",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -49456,7 +49456,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.93"
+              "revision": "version:102.0.5005.94"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49507,15 +49507,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -49541,7 +49541,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.34"
+              "revision": "version:103.0.5060.35"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49932,15 +49932,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--implementation-outdir",
           "../../weblayer_instrumentation_test_M102/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
           "--impl-version=102",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -49966,7 +49966,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M102",
-              "revision": "version:102.0.5005.93"
+              "revision": "version:102.0.5005.94"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50017,15 +50017,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
+          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--test-expectations",
-          "../../weblayer/browser/android/javatests/skew/expectations.txt",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--implementation-outdir",
           "../../weblayer_instrumentation_test_M103/out/Release",
+          "--test-expectations",
+          "../../weblayer/browser/android/javatests/skew/expectations.txt",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -50051,7 +50051,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M103",
-              "revision": "version:103.0.5060.34"
+              "revision": "version:103.0.5060.35"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 265aa6e..ed3b564 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5661,21 +5661,21 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5097.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "dimension_sets": [
@@ -5688,7 +5688,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "isolate_profile_data": true,
@@ -5826,21 +5826,21 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5097.0",
+        "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "dimension_sets": [
@@ -5852,7 +5852,7 @@
         },
         "test": "lacros_chrome_browsertests",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "args": [
@@ -5972,21 +5972,21 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5097.0",
+        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "dimension_sets": [
@@ -5998,7 +5998,7 @@
         },
         "test": "lacros_chrome_browsertests_run_in_series",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "isolate_profile_data": true,
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index d3858f6..2ad3f0cb 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -85363,21 +85363,21 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5097.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -85385,7 +85385,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "isolate_profile_data": true,
@@ -85498,28 +85498,28 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5097.0",
+        "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "lacros_chrome_browsertests",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "args": [
@@ -85619,28 +85619,28 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5097.0",
+        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "lacros_chrome_browsertests_run_in_series",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "isolate_profile_data": true,
@@ -86978,20 +86978,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5097.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "dimension_sets": [
@@ -87005,7 +87005,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "merge": {
@@ -87143,20 +87143,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5097.0",
+        "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "dimension_sets": [
@@ -87169,7 +87169,7 @@
         },
         "test": "lacros_chrome_browsertests",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "args": [
@@ -87289,20 +87289,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5097.0",
+        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "dimension_sets": [
@@ -87315,7 +87315,7 @@
         },
         "test": "lacros_chrome_browsertests_run_in_series",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "merge": {
@@ -88811,20 +88811,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5097.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "dimension_sets": [
@@ -88838,7 +88838,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "merge": {
@@ -88976,20 +88976,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5097.0",
+        "name": "lacros_chrome_browsertests Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "dimension_sets": [
@@ -89002,7 +89002,7 @@
         },
         "test": "lacros_chrome_browsertests",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "args": [
@@ -89122,20 +89122,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5097.0",
+        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "dimension_sets": [
@@ -89148,7 +89148,7 @@
         },
         "test": "lacros_chrome_browsertests_run_in_series",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       },
       {
         "merge": {
@@ -89883,20 +89883,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5097.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 104.0.5100.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v104.0.5097.0",
-              "revision": "version:104.0.5097.0"
+              "location": "lacros_version_skew_tests_v104.0.5100.0",
+              "revision": "version:104.0.5100.0"
             }
           ],
           "dimension_sets": [
@@ -89909,7 +89909,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 104.0.5097.0"
+        "variant_id": "Lacros version skew testing ash 104.0.5100.0"
       }
     ]
   },
@@ -98366,74 +98366,6 @@
       }
     ]
   },
-  "win-pixel-tester-rel": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--browser-ui-tests-verify-pixels",
-          "--enable-pixel-output-in-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/pixel_tests.filter",
-          "--git-revision=${got_revision}"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "pixel_browser_tests",
-        "non_precommit_args": [
-          "--test-launcher-retry-limit=0"
-        ],
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10-19042"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--browser-ui-tests-verify-pixels",
-          "--enable-pixel-output-in-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/pixel_tests.filter",
-          "--git-revision=${got_revision}"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "pixel_interactive_ui_tests",
-        "non_precommit_args": [
-          "--test-launcher-retry-limit=0"
-        ],
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Windows-10-19042"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      }
-    ]
-  },
   "win-upload-perfetto": {
     "additional_compile_targets": [
       "trace_processor_shell"
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index de59777..52e3b7e9 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -1070,23 +1070,6 @@
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
-        "test": "cast_accessibility_unittests",
-        "test_id_prefix": "ninja://chromecast/browser/accessibility/flutter:cast_accessibility_unittests/"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
         "test": "cast_audio_backend_unittests",
         "test_id_prefix": "ninja://chromecast/media/cma/backend:cast_audio_backend_unittests/"
       },
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index d63b81a..e11a5a8 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -318,10 +318,6 @@
     "label": "//media/capture:capture_unittests",
     "type": "windowed_test_launcher",
   },
-  "cast_accessibility_unittests": {
-    "label": "//chromecast/browser/accessibility/flutter:cast_accessibility_unittests",
-    "type": "console_test_launcher",
-  },
   "cast_display_settings_unittests": {
     "label": "//chromecast/ui/display_settings:cast_display_settings_unittests",
     "type": "console_test_launcher",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 2ffeafab..c8803192c 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2537,32 +2537,6 @@
       },
     },
   },
-  'pixel_browser_tests': {
-    'modifications': {
-      'win-pixel-tester-rel': {
-        'non_precommit_args': [
-          # Do not allow retry or it will break the bulk approval process.
-          # When retry with fail-pass pattern, the passing test will overwrite the previously
-          # seen flaky version on the trace. We can triage the image using the printed link,
-          # but it will not show on the Skia Gold search page.
-          '--test-launcher-retry-limit=0',
-        ],
-      },
-    },
-  },
-  'pixel_interactive_ui_tests': {
-    'modifications': {
-      'win-pixel-tester-rel': {
-        'non_precommit_args': [
-          # Do not allow retry or it will break the bulk approval process.
-          # When retry with fail-pass pattern, the passing test will overwrite the previously
-          # seen flaky version on the trace. We can triage the image using the printed link,
-          # but it will not show on the Skia Gold search page.
-          '--test-launcher-retry-limit=0',
-        ],
-      },
-    },
-  },
   'pixel_skia_gold_passthrough_test': {
     'modifications': {
       'Android FYI Release (Pixel 4)': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 95a85d7..255d14fd 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -470,7 +470,6 @@
     },
 
     'cast_video_specific_chromium_gtests': {
-      'cast_accessibility_unittests': {},
       'cast_display_settings_unittests': {
         'experiment_percentage': 100,
       },
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 597f363..378fda3 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -22,15 +22,15 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5097.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v104.0.5100.0/test_ash_chrome',
     ],
-    'identifier': 'Lacros version skew testing ash 104.0.5097.0',
+    'identifier': 'Lacros version skew testing ash 104.0.5100.0',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v104.0.5097.0',
-          'revision': 'version:104.0.5097.0',
+          'location': 'lacros_version_skew_tests_v104.0.5100.0',
+          'revision': 'version:104.0.5100.0',
         },
       ],
     },
@@ -402,16 +402,16 @@
   },
   'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MILESTONE': {
     'args': [
+      '--webview-apk-path=apks/AOSP_SystemWebView.apk',
       '--test-runner-outdir',
       '.',
       '--client-outdir',
       '.',
-      '--test-expectations',
-      '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--webview-apk-path=apks/AOSP_SystemWebView.apk',
       '--implementation-outdir',
       '../../weblayer_instrumentation_test_M103/out/Release',
-      '--impl-version=103'
+      '--test-expectations',
+      '../../weblayer/browser/android/javatests/skew/expectations.txt',
+      '--impl-version=103',
     ],
     'identifier': 'with_impl_from_103',
     'swarming': {
@@ -419,23 +419,23 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M103',
-          'revision': 'version:103.0.5060.34'
+          'revision': 'version:103.0.5060.35',
         }
-      ]
-    }
+      ],
+    },
   },
   'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
+      '--webview-apk-path=apks/AOSP_SystemWebView.apk',
       '--test-runner-outdir',
       '.',
       '--client-outdir',
       '.',
-      '--test-expectations',
-      '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--webview-apk-path=apks/AOSP_SystemWebView.apk',
       '--implementation-outdir',
       '../../weblayer_instrumentation_test_M102/out/Release',
-      '--impl-version=102'
+      '--test-expectations',
+      '../../weblayer/browser/android/javatests/skew/expectations.txt',
+      '--impl-version=102',
     ],
     'identifier': 'with_impl_from_102',
     'swarming': {
@@ -443,10 +443,10 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M102',
-          'revision': 'version:102.0.5005.93'
+          'revision': 'version:102.0.5005.94',
         }
-      ]
-    }
+      ],
+    },
   },
   'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
@@ -546,16 +546,16 @@
   },
   'WEBLAYER_IMPL_SKEW_TESTS_NTH_MILESTONE': {
     'args': [
+      '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
       '--client-outdir',
       '.',
-      '--test-expectations',
-      '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--webview-apk-path=apks/SystemWebView.apk',
       '--implementation-outdir',
       '../../weblayer_instrumentation_test_M103/out/Release',
-      '--impl-version=103'
+      '--test-expectations',
+      '../../weblayer/browser/android/javatests/skew/expectations.txt',
+      '--impl-version=103',
     ],
     'identifier': 'with_impl_from_103',
     'swarming': {
@@ -563,23 +563,23 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M103',
-          'revision': 'version:103.0.5060.34'
+          'revision': 'version:103.0.5060.35',
         }
-      ]
-    }
+      ],
+    },
   },
   'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
+      '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
       '--client-outdir',
       '.',
-      '--test-expectations',
-      '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--webview-apk-path=apks/SystemWebView.apk',
       '--implementation-outdir',
       '../../weblayer_instrumentation_test_M102/out/Release',
-      '--impl-version=102'
+      '--test-expectations',
+      '../../weblayer/browser/android/javatests/skew/expectations.txt',
+      '--impl-version=102',
     ],
     'identifier': 'with_impl_from_102',
     'swarming': {
@@ -587,10 +587,10 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M102',
-          'revision': 'version:102.0.5005.93'
+          'revision': 'version:102.0.5005.94',
         }
-      ]
-    }
+      ],
+    },
   },
   'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
@@ -690,16 +690,16 @@
   },
   'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MILESTONE': {
     'args': [
+      '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
+      '--client-outdir',
+      '../../weblayer_instrumentation_test_M103/out/Release',
       '--implementation-outdir',
       '.',
       '--test-expectations',
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--webview-apk-path=apks/SystemWebView.apk',
-      '--client-outdir',
-      '../../weblayer_instrumentation_test_M103/out/Release',
-      '--client-version=103'
+      '--client-version=103',
     ],
     'identifier': 'with_client_from_103',
     'swarming': {
@@ -707,23 +707,23 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M103',
-          'revision': 'version:103.0.5060.34'
+          'revision': 'version:103.0.5060.35',
         }
-      ]
-    }
+      ],
+    },
   },
   'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
+      '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
+      '--client-outdir',
+      '../../weblayer_instrumentation_test_M102/out/Release',
       '--implementation-outdir',
       '.',
       '--test-expectations',
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--webview-apk-path=apks/SystemWebView.apk',
-      '--client-outdir',
-      '../../weblayer_instrumentation_test_M102/out/Release',
-      '--client-version=102'
+      '--client-version=102',
     ],
     'identifier': 'with_client_from_102',
     'swarming': {
@@ -731,10 +731,10 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M102',
-          'revision': 'version:102.0.5005.93'
+          'revision': 'version:102.0.5005.94',
         }
-      ]
-    }
+      ],
+    },
   },
   'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 72e1ec4..e663c23 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -3786,14 +3786,6 @@
           'isolated_scripts': 'fieldtrial_isolated_scripts',
         },
       },
-      'win-pixel-tester-rel': {
-        'mixins': [
-            'win10',
-        ],
-        'test_suites': {
-          'gtest_tests': 'pixel_browser_tests_gtests',
-        }
-      },
       'win-upload-perfetto': {
         'additional_compile_targets': [ 'trace_processor_shell' ],
         'test_suites': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c8f306c..86fcdd3 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1552,6 +1552,24 @@
             ]
         }
     ],
+    "BFCachePerformanceManagerPolicy": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "BFCachePerformanceManagerPolicy"
+                    ]
+                }
+            ]
+        }
+    ],
     "BackForwardCache": [
         {
             "platforms": [
@@ -4493,6 +4511,21 @@
             ]
         }
     ],
+    "IOSGhostCards": [
+        {
+            "platforms": [
+                "ios"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "DiscoverFeedGhostCardsEnabled"
+                    ]
+                }
+            ]
+        }
+    ],
     "IOSKeepsRenderProcessAlive": [
         {
             "platforms": [
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.cc b/third_party/blink/renderer/core/css/css_math_expression_node.cc
index 80fc2e52..01e6d95 100644
--- a/third_party/blink/renderer/core/css/css_math_expression_node.cc
+++ b/third_party/blink/renderer/core/css/css_math_expression_node.cc
@@ -204,9 +204,6 @@
 CSSMathExpressionNumericLiteral* CSSMathExpressionNumericLiteral::Create(
     double value,
     CSSPrimitiveValue::UnitType type) {
-  if (!RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled() &&
-      (std::isnan(value) || std::isinf(value)))
-    return nullptr;
   return MakeGarbageCollected<CSSMathExpressionNumericLiteral>(
       CSSNumericLiteralValue::Create(value, type));
 }
@@ -231,23 +228,11 @@
   PixelsAndPercent value(0, 0);
   switch (category_) {
     case kCalcLength:
-      // When CSSCalcInfinityAndNaN is enabled, we allow infinity and NaN in
-      // PixelsAndPercent. Therefore, we need to use a function that doesn't
-      // internally clamp the result to the float range.
-      if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
-        value.pixels = value_->ComputeLengthPx(length_resolver);
-      else
-        value.pixels = value_->ComputeLength<float>(length_resolver);
+      value.pixels = value_->ComputeLengthPx(length_resolver);
       break;
     case kCalcPercent:
       DCHECK(value_->IsPercentage());
-      // When CSSCalcInfinityAndNaN is enabled, we allow infinity and NaN in
-      // PixelsAndPercent. Therefore, we need to use a function that doesn't
-      // internally clamp the result to the float range.
-      if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
-        value.percent = value_->GetDoubleValueWithoutClamping();
-      else
-        value.percent = value_->GetFloatValue();
+      value.percent = value_->GetDoubleValueWithoutClamping();
       break;
     case kCalcNumber:
       // TODO(alancutter): Stop treating numbers like pixels unconditionally
@@ -300,12 +285,7 @@
     const CSSLengthResolver& length_resolver) const {
   switch (category_) {
     case kCalcLength:
-      // When CSSCalcInfinityAndNaN is enabled, we allow infinity and NaN in
-      // PixelsAndPercent. Therefore, we need to use a function that doesn't
-      // internally clamp the result to the float range.
-      if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
-        return value_->ComputeLengthPx(length_resolver);
-      return value_->ComputeLength<double>(length_resolver);
+      return value_->ComputeLengthPx(length_resolver);
     case kCalcNumber:
     case kCalcPercent:
     case kCalcAngle:
@@ -404,9 +384,7 @@
         return kCalcOther;
       return left_category == kCalcNumber ? right_category : left_category;
     case CSSMathOperator::kDivide:
-      if (right_category != kCalcNumber ||
-          (!RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled() &&
-           right_side.IsZero()))
+      if (right_category != kCalcNumber)
         return kCalcOther;
       return left_category;
     default:
@@ -531,13 +509,6 @@
 
     double number = number_side->DoubleValue();
 
-    if (!RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
-      if (std::isnan(number) || std::isinf(number))
-        return nullptr;
-      if (op == CSSMathOperator::kDivide && !number)
-        return nullptr;
-    }
-
     CSSPrimitiveValue::UnitType other_type = other_side->ResolvedUnitType();
     if (HasDoubleValue(other_type)) {
       return CSSMathExpressionNumericLiteral::Create(
@@ -969,26 +940,16 @@
   switch (op) {
     case CSSMathOperator::kAdd:
       DCHECK_EQ(operands.size(), 2u);
-      if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
-        return operands[0] + operands[1];
-      return ClampTo<double>(operands[0] + operands[1]);
+      return operands[0] + operands[1];
     case CSSMathOperator::kSubtract:
       DCHECK_EQ(operands.size(), 2u);
-      if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
-        return operands[0] - operands[1];
-      return ClampTo<double>(operands[0] - operands[1]);
+      return operands[0] - operands[1];
     case CSSMathOperator::kMultiply:
       DCHECK_EQ(operands.size(), 2u);
-      if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
-        return operands[0] * operands[1];
-      return ClampTo<double>(operands[0] * operands[1]);
+      return operands[0] * operands[1];
     case CSSMathOperator::kDivide:
       DCHECK(operands.size() == 1u || operands.size() == 2u);
-      if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
-        return operands[0] / operands[1];
-      if (operands[1])
-        return ClampTo<double>(operands[0] / operands[1]);
-      return std::numeric_limits<double>::quiet_NaN();
+      return operands[0] / operands[1];
     case CSSMathOperator::kMin: {
       if (operands.IsEmpty())
         return std::numeric_limits<double>::quiet_NaN();
@@ -1248,22 +1209,20 @@
  private:
   CSSMathExpressionNode* ParseValue(CSSParserTokenRange& tokens) {
     CSSParserToken token = tokens.ConsumeIncludingWhitespace();
-    if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
-      if (token.Id() == CSSValueID::kInfinity) {
-        return CSSMathExpressionNumericLiteral::Create(
-            std::numeric_limits<double>::infinity(),
-            CSSPrimitiveValue::UnitType::kNumber);
-      }
-      if (token.Id() == CSSValueID::kNegativeInfinity) {
-        return CSSMathExpressionNumericLiteral::Create(
-            -std::numeric_limits<double>::infinity(),
-            CSSPrimitiveValue::UnitType::kNumber);
-      }
-      if (token.Id() == CSSValueID::kNan) {
-        return CSSMathExpressionNumericLiteral::Create(
-            std::numeric_limits<double>::quiet_NaN(),
-            CSSPrimitiveValue::UnitType::kNumber);
-      }
+    if (token.Id() == CSSValueID::kInfinity) {
+      return CSSMathExpressionNumericLiteral::Create(
+          std::numeric_limits<double>::infinity(),
+          CSSPrimitiveValue::UnitType::kNumber);
+    }
+    if (token.Id() == CSSValueID::kNegativeInfinity) {
+      return CSSMathExpressionNumericLiteral::Create(
+          -std::numeric_limits<double>::infinity(),
+          CSSPrimitiveValue::UnitType::kNumber);
+    }
+    if (token.Id() == CSSValueID::kNan) {
+      return CSSMathExpressionNumericLiteral::Create(
+          std::numeric_limits<double>::quiet_NaN(),
+          CSSPrimitiveValue::UnitType::kNumber);
     }
     if (!(token.GetType() == kNumberToken ||
           token.GetType() == kPercentageToken ||
@@ -1409,13 +1368,10 @@
   }
 
   auto value = ToCalculationExpression(length_resolver);
-  if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
-    absl::optional<PixelsAndPercent> evaluated_value =
-        EvaluateValueIfNaNorInfinity(value,
-                                     allows_negative_percentage_reference);
-    if (evaluated_value.has_value()) {
-      return CalculationValue::Create(evaluated_value.value(), range);
-    }
+  absl::optional<PixelsAndPercent> evaluated_value =
+      EvaluateValueIfNaNorInfinity(value, allows_negative_percentage_reference);
+  if (evaluated_value.has_value()) {
+    return CalculationValue::Create(evaluated_value.value(), range);
   }
   return CalculationValue::CreateSimplified(value, range);
 }
diff --git a/third_party/blink/renderer/core/css/css_numeric_literal_value.cc b/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
index eb5fe81a..869b36c 100644
--- a/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
+++ b/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
@@ -24,8 +24,6 @@
 
 CSSNumericLiteralValue::CSSNumericLiteralValue(double num, UnitType type)
     : CSSPrimitiveValue(kNumericLiteralClass), num_(num) {
-  DCHECK(RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled() ||
-         std::isfinite(num));
   DCHECK_NE(UnitType::kUnknown, type);
   numeric_literal_unit_type_ = static_cast<unsigned>(type);
 }
@@ -36,15 +34,9 @@
   if (value < 0 || value > CSSValuePool::kMaximumCacheableIntegerValue)
     return MakeGarbageCollected<CSSNumericLiteralValue>(value, type);
 
-  if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
-    // Value can be NaN.
-    if (std::isnan(value))
-      return MakeGarbageCollected<CSSNumericLiteralValue>(value, type);
-  } else {
-    // TODO(timloh): This looks wrong.
-    if (std::isinf(value))
-      value = 0;
-  }
+  // Value can be NaN.
+  if (std::isnan(value))
+    return MakeGarbageCollected<CSSNumericLiteralValue>(value, type);
 
   int int_value = ClampTo<int>(value);
   if (value != int_value)
@@ -257,13 +249,11 @@
       // If the value is small integer, go the fast path.
       if (value < kMinInteger || value > kMaxInteger ||
           std::trunc(value) != value) {
-        if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled() &&
-            (std::isinf(value) || std::isnan(value))) {
+        if (std::isinf(value) || std::isnan(value)) {
           text = FormatInfinityOrNaN(value, UnitTypeToString(GetType()));
         } else {
           text = FormatNumber(value, UnitTypeToString(GetType()));
         }
-
       } else {
         StringBuilder builder;
         int int_value = value;
diff --git a/third_party/blink/renderer/core/css/css_primitive_value.cc b/third_party/blink/renderer/core/css/css_primitive_value.cc
index 85463a3..b085b11 100644
--- a/third_party/blink/renderer/core/css/css_primitive_value.cc
+++ b/third_party/blink/renderer/core/css/css_primitive_value.cc
@@ -59,10 +59,8 @@
   // TODO(crbug.com/1133390): ClampTo function could occur the DECHECK failure
   // for NaN value. Therefore, infinity and NaN values should not be clamped
   // here.
-  if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
-    value = CSSValueClampingUtils::ClampLength(value);
-  }
-  return ClampTo<float>(value, kMinValueForCssLength, kMaxValueForCssLength);
+  return ClampTo<float>(CSSValueClampingUtils::ClampLength(value),
+                        kMinValueForCssLength, kMaxValueForCssLength);
 }
 
 Length::ValueRange CSSPrimitiveValue::ConversionToLengthValueRange(
@@ -255,19 +253,14 @@
   double result = IsCalculated()
                       ? To<CSSMathFunctionValue>(this)->ComputeSeconds()
                       : To<CSSNumericLiteralValue>(this)->ComputeSeconds();
-  if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled())
-    result = CSSValueClampingUtils::ClampTime(result);
-  return result;
+  return CSSValueClampingUtils::ClampTime(result);
 }
 
 double CSSPrimitiveValue::ComputeDegrees() const {
   double result = IsCalculated()
                       ? To<CSSMathFunctionValue>(this)->ComputeDegrees()
                       : To<CSSNumericLiteralValue>(this)->ComputeDegrees();
-  if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
-    result = CSSValueClampingUtils::ClampAngle(result);
-  }
-  return result;
+  return CSSValueClampingUtils::ClampAngle(result);
 }
 
 double CSSPrimitiveValue::ComputeDotsPerPixel() const {
@@ -321,21 +314,15 @@
 template <>
 float CSSPrimitiveValue::ComputeLength(
     const CSSLengthResolver& length_resolver) const {
-  double value = ComputeLengthDouble(length_resolver);
-  if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
-    value = CSSValueClampingUtils::ClampLength(value);
-  }
-  return ClampTo<float>(value);
+  return ClampTo<float>(
+      CSSValueClampingUtils::ClampLength(ComputeLengthDouble(length_resolver)));
 }
 
 template <>
 double CSSPrimitiveValue::ComputeLength(
     const CSSLengthResolver& length_resolver) const {
-  double value = ComputeLengthDouble(length_resolver);
-  if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
-    return CSSValueClampingUtils::ClampLength(value);
-  }
-  return value;
+  return CSSValueClampingUtils::ClampLength(
+      ComputeLengthDouble(length_resolver));
 }
 
 double CSSPrimitiveValue::ComputeLengthDouble(
@@ -428,11 +415,8 @@
   if (IsPercentage()) {
     if (IsNumericLiteralValue() ||
         !To<CSSMathFunctionValue>(this)->AllowsNegativePercentageReference()) {
-      double value = GetDoubleValueWithoutClamping();
-      if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
-        value = CSSValueClampingUtils::ClampLength(value);
-      }
-      return Length::Percent(value);
+      return Length::Percent(
+          CSSValueClampingUtils::ClampLength(GetDoubleValueWithoutClamping()));
     }
   }
   DCHECK(IsCalculated());
diff --git a/third_party/blink/renderer/core/css/css_primitive_value_test.cc b/third_party/blink/renderer/core/css/css_primitive_value_test.cc
index b3a0111..ea349a3 100644
--- a/third_party/blink/renderer/core/css/css_primitive_value_test.cc
+++ b/third_party/blink/renderer/core/css/css_primitive_value_test.cc
@@ -11,13 +11,11 @@
 #include "third_party/blink/renderer/core/css/css_test_helpers.h"
 #include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 
 namespace blink {
 namespace {
 
-class CSSPrimitiveValueTest : public PageTestBase,
-                              private ScopedCSSCalcInfinityAndNaNForTest {
+class CSSPrimitiveValueTest : public PageTestBase {
  public:
   bool HasContainerRelativeUnits(const char* text) {
     return To<CSSPrimitiveValue>(
@@ -25,7 +23,7 @@
         ->HasContainerRelativeUnits();
   }
 
-  CSSPrimitiveValueTest() : ScopedCSSCalcInfinityAndNaNForTest(true) {}
+  CSSPrimitiveValueTest() = default;
 };
 
 using UnitType = CSSPrimitiveValue::UnitType;
diff --git a/third_party/blink/renderer/core/css/cssom/css_math_invert.cc b/third_party/blink/renderer/core/css/cssom/css_math_invert.cc
index 68e2617..5b44d71 100644
--- a/third_party/blink/renderer/core/css/cssom/css_math_invert.cc
+++ b/third_party/blink/renderer/core/css/cssom/css_math_invert.cc
@@ -18,9 +18,7 @@
 
 absl::optional<CSSNumericSumValue> CSSMathInvert::SumValue() const {
   auto sum = value_->SumValue();
-  if (!sum.has_value() || sum->terms.size() != 1 ||
-      (!RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled() &&
-       sum->terms[0].value == 0))
+  if (!sum.has_value() || sum->terms.size() != 1)
     return absl::nullopt;
 
   for (auto& unit_exponent : sum->terms[0].units)
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index 5e21ca3..b29fdea 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -1129,18 +1129,13 @@
 static CSSPrimitiveValue* ConsumeMathFunctionAngle(
     CSSParserTokenRange& range,
     const CSSParserContext& context) {
-  if (RuntimeEnabledFeatures::CSSCalcInfinityAndNaNEnabled()) {
-    MathFunctionParser math_parser(range, context,
-                                   CSSPrimitiveValue::ValueRange::kAll);
-    if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
-      if (calculation->Category() != kCalcAngle)
-        return nullptr;
-    }
-    return math_parser.ConsumeValue();
+  MathFunctionParser math_parser(range, context,
+                                 CSSPrimitiveValue::ValueRange::kAll);
+  if (const CSSMathFunctionValue* calculation = math_parser.Value()) {
+    if (calculation->Category() != kCalcAngle)
+      return nullptr;
   }
-  return ConsumeMathFunctionAngle(range, context,
-                                  std::numeric_limits<double>::lowest(),
-                                  std::numeric_limits<double>::max());
+  return math_parser.ConsumeValue();
 }
 
 CSSPrimitiveValue* ConsumeAngle(
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
index 67d16f0..dfa291dd 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
+++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -35,7 +35,6 @@
 #include <utility>
 
 #include "base/memory/scoped_refptr.h"
-#include "base/metrics/histogram_functions.h"
 #include "mojo/public/cpp/system/wait.h"
 #include "third_party/blink/public/common/blob/blob_utils.h"
 #include "third_party/blink/public/platform/web_url_request.h"
@@ -94,7 +93,7 @@
   mojo::ScopedDataPipeProducerHandle producer_handle;
   MojoResult rv = CreateDataPipe(&options, producer_handle, consumer_handle_);
   if (rv != MOJO_RESULT_OK) {
-    Failed(FileErrorCode::kNotReadableErr, FailureType::kMojoPipeCreation);
+    Failed(FileErrorCode::kNotReadableErr);
     return;
   }
 
@@ -108,16 +107,14 @@
     if (received_on_complete_)
       return;
     if (!received_all_data_) {
-      Failed(FileErrorCode::kNotReadableErr,
-             FailureType::kSyncDataNotAllLoaded);
+      Failed(FileErrorCode::kNotReadableErr);
       return;
     }
 
     // Wait for OnComplete
     receiver_.WaitForIncomingCall();
     if (!received_on_complete_) {
-      Failed(FileErrorCode::kNotReadableErr,
-             FailureType::kSyncOnCompleteNotReceived);
+      Failed(FileErrorCode::kNotReadableErr);
     }
   }
 }
@@ -211,13 +208,11 @@
   }
 }
 
-void FileReaderLoader::Failed(FileErrorCode error_code, FailureType type) {
+void FileReaderLoader::Failed(FileErrorCode error_code) {
   // If an error was already reported, don't report this error again.
   if (error_code_ != FileErrorCode::kOK)
     return;
   error_code_ = error_code;
-  base::UmaHistogramEnumeration("Storage.Blob.FileReaderLoader.FailureType",
-                                type);
   Cleanup();
   if (client_)
     client_->DidFail(error_code_);
@@ -233,7 +228,7 @@
     // so to call ArrayBuffer's create function.
     // FIXME: Support reading more than the current size limit of ArrayBuffer.
     if (total_bytes > std::numeric_limits<unsigned>::max()) {
-      Failed(FileErrorCode::kNotReadableErr, FailureType::kTotalBytesTooLarge);
+      Failed(FileErrorCode::kNotReadableErr);
       return;
     }
 
@@ -241,8 +236,7 @@
                                     ArrayBufferContents::kNotShared,
                                     ArrayBufferContents::kDontInitialize);
     if (!raw_data_.IsValid()) {
-      Failed(FileErrorCode::kNotReadableErr,
-             FailureType::kArrayBufferBuilderCreation);
+      Failed(FileErrorCode::kNotReadableErr);
       return;
     }
   }
@@ -275,8 +269,7 @@
   if (bytes_loaded_ + data_length > raw_data_.DataLength()) {
     raw_data_.Reset();
     bytes_loaded_ = 0;
-    Failed(FileErrorCode::kNotReadableErr,
-           FailureType::kArrayBufferBuilderAppend);
+    Failed(FileErrorCode::kNotReadableErr);
     return;
   }
   memcpy(static_cast<char*>(raw_data_.Data()) + bytes_loaded_, data,
@@ -326,18 +319,14 @@
 }
 
 void FileReaderLoader::OnComplete(int32_t status, uint64_t data_length) {
-  base::UmaHistogramSparse("Storage.Blob.FileReaderLoader.ReadError",
-                           std::max(0, -net_error_));
-
   if (status != net::OK) {
     net_error_ = status;
     Failed(status == net::ERR_FILE_NOT_FOUND ? FileErrorCode::kNotFoundErr
-                                             : FileErrorCode::kNotReadableErr,
-           FailureType::kBackendReadError);
+                                             : FileErrorCode::kNotReadableErr);
     return;
   }
   if (data_length != total_bytes_) {
-    Failed(FileErrorCode::kNotReadableErr, FailureType::kReadSizesIncorrect);
+    Failed(FileErrorCode::kNotReadableErr);
     return;
   }
 
@@ -349,8 +338,7 @@
 void FileReaderLoader::OnDataPipeReadable(MojoResult result) {
   if (result != MOJO_RESULT_OK) {
     if (!received_all_data_) {
-      Failed(FileErrorCode::kNotReadableErr,
-             FailureType::kDataPipeNotReadableWithBytesLeft);
+      Failed(FileErrorCode::kNotReadableErr);
     }
     return;
   }
@@ -372,14 +360,12 @@
     if (pipe_result == MOJO_RESULT_FAILED_PRECONDITION) {
       // Pipe closed.
       if (!received_all_data_) {
-        Failed(FileErrorCode::kNotReadableErr,
-               FailureType::kMojoPipeClosedEarly);
+        Failed(FileErrorCode::kNotReadableErr);
       }
       return;
     }
     if (pipe_result != MOJO_RESULT_OK) {
-      Failed(FileErrorCode::kNotReadableErr,
-             FailureType::kMojoPipeUnexpectedReadError);
+      Failed(FileErrorCode::kNotReadableErr);
       return;
     }
 
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.h b/third_party/blink/renderer/core/fileapi/file_reader_loader.h
index 2f6c4c9..592c916e 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader_loader.h
+++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.h
@@ -109,28 +109,8 @@
   bool HasFinishedLoading() const { return finished_loading_; }
 
  private:
-  // These values are persisted to logs. Entries should not be renumbered and
-  // numeric values should never be reused.
-  enum class FailureType {
-    kMojoPipeCreation = 0,
-    kSyncDataNotAllLoaded = 1,
-    kSyncOnCompleteNotReceived = 2,
-    kTotalBytesTooLarge = 3,
-    kArrayBufferBuilderCreation = 4,
-    kArrayBufferBuilderAppend = 5,
-    kBackendReadError = 6,
-    kReadSizesIncorrect = 7,
-    kDataPipeNotReadableWithBytesLeft = 8,
-    kMojoPipeClosedEarly = 9,
-    // Any MojoResult error we aren't expecting during data pipe reading falls
-    // into this bucket. If there are a large number of errors reported here,
-    // then there can be a new enumeration reported for mojo pipe errors.
-    kMojoPipeUnexpectedReadError = 10,
-    kMaxValue = kMojoPipeUnexpectedReadError,
-  };
-
   void Cleanup();
-  void Failed(FileErrorCode, FailureType type);
+  void Failed(FileErrorCode);
 
   void OnStartLoading(uint64_t total_bytes);
   void OnReceivedData(const char* data, unsigned data_length);
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 0131a695..9dcc4bcc 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -100,6 +100,7 @@
 #include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
 #include "third_party/blink/public/common/context_menu_data/context_menu_params_builder.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h"
 #include "third_party/blink/public/common/page_state/page_state.h"
 #include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink.h"
 #include "third_party/blink/public/mojom/fenced_frame/fenced_frame.mojom-blink.h"
@@ -1974,10 +1975,12 @@
   network::mojom::blink::WebSandboxFlags sandbox_flags =
       network::mojom::blink::WebSandboxFlags::kNone;
   PermissionsPolicyFeatureState feature_state;
-  if (!previous_frame->Owner()) {
+  if (!previous_frame->Owner() || previous_frame->IsFencedFrameRoot()) {
     // Provisional main frames need to force sandbox flags.  This is necessary
     // to inherit sandbox flags when a sandboxed frame does a window.open()
     // which triggers a cross-process navigation.
+    // Fenced frames also need to force special initial sandbox flags that are
+    // passed via frame_policy.
     sandbox_flags = frame_policy.sandbox_flags;
   }
   // Note: this *always* temporarily sets a frame owner, even for main frames!
@@ -2115,13 +2118,22 @@
   // New documents are either:
   // 1. The initial empty document:
   //   a. In a new iframe.
-  //   b. In a new popup.
+  //   b. In a new fencedframe.
+  //   c. In a new popup.
   // 2. A document replacing the previous, one via a navigation.
   //
-  // This is about 1.b. This is used to define sandbox flags for the initial
-  // empty document in a new popup.
-  if (frame_->IsMainFrame())
+  // 1.b. will get the special sandbox flags. See:
+  // https://docs.google.com/document/d/1RO4NkQk_XaEE7vuysM9LJilZYsoOhydfh93sOvrPQxU/edit
+  // For 1.c., this is used to define sandbox flags for
+  // the initial empty document in a new popup.
+  if (frame_->IsMainFrame()) {
+    DCHECK(!frame_->IsInFencedFrameTree() ||
+           ((sandbox_flags & blink::kFencedFrameForcedSandboxFlags) ==
+            blink::kFencedFrameForcedSandboxFlags))
+        << "An MPArch fencedframe must be configured with its forced sandbox "
+        << "flags:" << sandbox_flags;
     frame_->SetOpenerSandboxFlags(sandbox_flags);
+  }
 
   Frame* opener_frame = opener ? ToCoreFrame(*opener) : nullptr;
 
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
index 2351514..0968f78 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -3742,13 +3742,11 @@
     end_offset =
         TrackEndOffset(track_collection, item_placement.range_index.end,
                        item_placement.offset_in_range.end);
-    *size = end_offset - *start_offset;
-  } else {
-    // |start_offset| can be greater than |end_offset| if the track sizes from
-    // the grid overflow the container's respective size.
-    *size = (end_offset - *start_offset).ClampNegativeToZero();
   }
-  DCHECK(*size >= 0 || *size == kIndefiniteSize);
+
+  // |start_offset| can be greater than |end_offset| if the used track sizes or
+  // gutter size saturated the set offsets of the track collection.
+  *size = (end_offset - *start_offset).ClampNegativeToZero();
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
index e763af6a..3fb98a7 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
@@ -522,8 +522,8 @@
       /* inline_context */ nullptr,
       /* selection_text_decoration */ absl::nullopt, &scaled_font,
       kMinimumThicknessIsOne);
-  NGTextDecorationOffset decoration_offset(decoration_info.TargetStyle(), style,
-                                           nullptr);
+  NGTextDecorationOffset decoration_offset(decoration_info.TargetStyle(),
+                                           style);
   const Vector<AppliedTextDecoration>& decorations =
       style.AppliedTextDecorations();
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.cc b/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.cc
index 4f564ff..70130fb7 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.cc
@@ -16,31 +16,21 @@
     const SimpleFontData* font_data,
     float text_decoration_thickness,
     FontVerticalPositionType position_type) const {
-  LayoutUnit offset = LayoutUnit::Max();
   const ComputedStyle& style = text_style_;
   FontBaseline baseline_type = style.GetFontBaseline();
 
   LayoutUnit style_underline_offset_pixels = LayoutUnit::FromFloatRound(
       StyleUnderlineOffsetToPixels(style_underline_offset, computed_font_size));
-  if (IsLineOverSide(position_type)) {
+  if (IsLineOverSide(position_type))
     style_underline_offset_pixels = -style_underline_offset_pixels;
-  }
 
-  if (decorating_box_) {
-    offset = decorating_box_->Baseline().value_or(offset) +
-             style_underline_offset_pixels;
-  }
-
-  if (offset == LayoutUnit::Max()) {
-    // TODO(layout-dev): How do we compute the baseline offset with a
-    // decorating_box?
-    if (!font_data)
-      return 0;
-    offset = LayoutUnit::FromFloatRound(
-                 font_data->GetFontMetrics().FloatAscent(baseline_type)) -
-             font_data->VerticalPosition(position_type, baseline_type) +
-             style_underline_offset_pixels;
-  }
+  if (!font_data)
+    return 0;
+  const LayoutUnit offset =
+      LayoutUnit::FromFloatRound(
+          font_data->GetFontMetrics().FloatAscent(baseline_type)) -
+      font_data->VerticalPosition(position_type, baseline_type) +
+      style_underline_offset_pixels;
 
   // Compute offset to the farthest position of the decorating box.
   // TODO(layout-dev): This does not take farthest offset within the decorating
diff --git a/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h b/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h
index 154069f..1f3c041 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h
@@ -11,7 +11,6 @@
 namespace blink {
 
 class ComputedStyle;
-class NGPhysicalBoxFragment;
 
 // Class for computing the decoration offset for text fragments in LayoutNG.
 class CORE_EXPORT NGTextDecorationOffset : public TextDecorationOffsetBase {
@@ -19,11 +18,8 @@
 
  public:
   NGTextDecorationOffset(const ComputedStyle& style,
-                         const ComputedStyle& text_style,
-                         const NGPhysicalBoxFragment* decorating_box)
-      : TextDecorationOffsetBase(style),
-        text_style_(text_style),
-        decorating_box_(decorating_box) {}
+                         const ComputedStyle& text_style)
+      : TextDecorationOffsetBase(style), text_style_(text_style) {}
   ~NGTextDecorationOffset() = default;
 
   int ComputeUnderlineOffsetForUnder(const Length& style_underline_offset,
@@ -34,7 +30,6 @@
 
  private:
   const ComputedStyle& text_style_;
-  const NGPhysicalBoxFragment* decorating_box_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_combine_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_combine_painter.cc
index 9eb2528f..625f196 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_text_combine_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_text_combine_painter.cc
@@ -101,7 +101,7 @@
       text_frame_rect_.offset, text_frame_rect_.size.width, style_,
       /* inline_context */ nullptr, selection_text_decoration);
 
-  const NGTextDecorationOffset decoration_offset(style_, style_, nullptr);
+  const NGTextDecorationOffset decoration_offset(style_, style_);
   const auto& applied_text_decorations = style_.AppliedTextDecorations();
 
   // Paint text decorations except line through
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
index 7d1d87c0..f766e26 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
@@ -268,7 +268,7 @@
   *has_line_through_decoration = false;
 
   const NGTextDecorationOffset decoration_offset(decoration_info.TargetStyle(),
-                                                 text_item.Style(), nullptr);
+                                                 text_item.Style());
 
   if (svg_text_paint_state_.has_value()) {
     GraphicsContextStateSaver state_saver(paint_info.context, false);
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 82f668fd..3b54400 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -515,11 +515,6 @@
       status: "test",
     },
     {
-      // https://github.com/DevSDK/calc-infinity-and-NaN/blob/master/explainer.md
-      name: "CSSCalcInfinityAndNaN",
-      status: "stable",
-    },
-    {
       // Support CSS Values Level 4 calc simplification and serialization
       // as specified in the specs below.
       // https://drafts.csswg.org/css-values-4/#calc-simplification
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index db771a2..af6706a7 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -492,6 +492,9 @@
 crbug.com/1045599 fast/css-grid-layout/grid-auto-repeat-huge-grid-014.html [ Failure ]
 crbug.com/1045599 fast/css-grid-layout/grid-auto-repeat-huge-grid-015.html [ Failure ]
 crbug.com/1045599 fast/css-grid-layout/grid-auto-repeat-huge-grid-016.html [ Failure ]
+crbug.com/1045599 fast/css-grid-layout/grid-auto-repeat-huge-grid-017.html [ Failure ]
+crbug.com/1045599 fast/css-grid-layout/grid-auto-repeat-huge-grid-018.html [ Failure ]
+crbug.com/1045599 fast/css-grid-layout/grid-auto-repeat-huge-grid-019.html [ Failure ]
 crbug.com/1045599 fast/css-grid-layout/grid-item-spanning-and-orthogonal-flows.html [ Failure ]
 crbug.com/1045599 fast/css-grid-layout/grid-track-sizing-with-orthogonal-flows.html [ Failure ]
 crbug.com/1045599 fast/css-grid-layout/maximize-tracks-definite-indefinite-height.html [ Failure ]
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index c2eeca9..62ee817a 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -329,6 +329,25 @@
 crbug.com/874695 fast/canvas-api/canvas-layerBridgeCrashTest.html [ Slow ]
 crbug.com/874695 fast/canvas/canvas-drawImage-animated-images.html [ Slow ]
 crbug.com/874695 fast/css-grid-layout/crash-large-positions.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-001.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-002.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-003.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-004.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-005.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-006.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-007.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-008.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-009.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-010.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-011.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-012.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-013.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-014.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-015.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-016.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-017.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-018.html [ Slow ]
+crbug.com/874695 fast/css-grid-layout/grid-auto-repeat-huge-grid-019.html [ Slow ]
 crbug.com/874695 fast/dnd/dropEffect-for-link.html [ Slow ]
 crbug.com/874695 fast/dom/HTMLLinkElement/link-preload-unused.html [ Slow ]
 crbug.com/874695 fast/dom/timer-throttling-hidden-page.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 66cf0c45..af83956c 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3484,13 +3484,6 @@
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/websockets/unload-a-document/005.html?wpt_flags=h2 [ Skip Timeout ]
 crbug.com/626703 external/wpt/css/css-values/cap-unit-001.html [ Failure ]
 crbug.com/626703 external/wpt/selection/textcontrols/onselectionchange-content-attribute.html [ Timeout ]
-crbug.com/626703 [ Linux ] virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/cap-unit-001.html [ Failure ]
-crbug.com/626703 [ Mac10.13 ] virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/cap-unit-001.html [ Failure ]
-crbug.com/626703 [ Mac10.14 ] virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/cap-unit-001.html [ Failure ]
-crbug.com/626703 [ Mac10.15 ] virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/cap-unit-001.html [ Failure ]
-crbug.com/626703 [ Mac11 ] virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/cap-unit-001.html [ Failure ]
-crbug.com/626703 [ Win ] virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/cap-unit-001.html [ Failure ]
-crbug.com/626703 [ Mac11-arm64 ] virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/cap-unit-001.html [ Crash Failure ]
 crbug.com/626703 external/wpt/infrastructure/channels/test_call.html [ Timeout ]
 crbug.com/626703 external/wpt/infrastructure/channels/test_postMessage.html [ Timeout ]
 crbug.com/626703 external/wpt/infrastructure/channels/test_serialize.html [ Timeout ]
@@ -3502,7 +3495,6 @@
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc/RTCPeerConnection-capture-video.https.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html [ Skip Timeout ]
 crbug.com/626703 [ Mac11-arm64 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDataChannel-send.html [ Skip Timeout ]
-crbug.com/626703 [ Mac11-arm64 ] virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/ch-unit-011.html [ Failure ]
 crbug.com/626703 [ Mac11-arm64 ] external/wpt/navigation-timing/nav2_test_response_end_and_duration_before_during_and_after_load_event.html [ Skip Timeout ]
 crbug.com/626703 [ Mac12-arm64 ] external/wpt/navigation-timing/nav2_test_response_end_and_duration_before_during_and_after_load_event.html [ Skip Timeout ]
 crbug.com/1270841 [ Mac ] external/wpt/media-capabilities/encodingInfo.any.worker.html [ Crash ]
@@ -7091,18 +7083,10 @@
 crbug.com/1322004 http/tests/inspector-protocol/attribution-reporting/insecure-subresource.js [ Pass Timeout ]
 crbug.com/1329596 virtual/gpu-rasterization/images/jpeg-with-non-interleaved-dc-channels.html [ Failure Pass ]
 
-# Sheriff 2022-05-27
-crbug.com/1325307 fast/css-grid-layout/grid-auto-repeat-huge-grid-003.html [ Skip ]
-crbug.com/1325307 fast/css-grid-layout/grid-auto-repeat-huge-grid-009.html [ Skip ]
-crbug.com/1325307 fast/css-grid-layout/grid-auto-repeat-huge-grid-010.html [ Skip ]
-
 # Sheriff 2022-05-30
 crbug.com/1330238 [ Mac ] http/tests/devtools/elements/styles-3/styles-computed-trace.js [ Failure Pass Timeout ]
 
 # Sheriff 2022-05-31
-crbug.com/1330300 fast/css-grid-layout/grid-auto-repeat-huge-grid-006.html [ Pass Timeout ]
-
-# Sheriff 2022-05-31
 crbug.com/1330555 external/wpt/service-workers/service-worker/resource-timing-fetch-variants.https.html [ Failure Pass ]
 
 # fast/canvas/OffscreenCanvas-2d-drawImage.html
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index ada0d2a..75086663 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -642,17 +642,6 @@
     "args": ["--enable-blink-features=CSSModules", "--js-flags=--harmony-import-assertions"]
   },
   {
-    "prefix": "css-calc-infinity-and-nan-disabled",
-    "platforms": ["Linux", "Mac", "Win"],
-    "bases": ["external/wpt/html/rendering/non-replaced-elements/the-page/crashtests/",
-              "external/wpt/css/css-values/",
-              "external/wpt/css/css-transforms/parsing/",
-              "external/wpt/css/css-transforms/crashtests/",
-              "external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/crashtests",
-              "external/wpt/css/css-transitions/crashtests/transition-large-word-spacing-001.html"],
-    "args": ["--disable-blink-features=CSSCalcInfinityAndNaN"]
-  },
-  {
     "prefix": "import-assertions",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": ["external/wpt/html/semantics/scripting-1/the-script-element/import-assertions"],
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/crash-grid-gap-large-oof-children.html b/third_party/blink/web_tests/fast/css-grid-layout/crash-grid-gap-large-oof-children-1.html
similarity index 100%
rename from third_party/blink/web_tests/fast/css-grid-layout/crash-grid-gap-large-oof-children.html
rename to third_party/blink/web_tests/fast/css-grid-layout/crash-grid-gap-large-oof-children-1.html
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/crash-grid-gap-large-oof-children-2.html b/third_party/blink/web_tests/fast/css-grid-layout/crash-grid-gap-large-oof-children-2.html
new file mode 100644
index 0000000..4afd962
--- /dev/null
+++ b/third_party/blink/web_tests/fast/css-grid-layout/crash-grid-gap-large-oof-children-2.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>Test using a large grid gap and size containment and out of flow children.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/grid-definitions-parsing-utils.js"></script>
+<style>
+.grid {
+    border: 100px double;
+    contain: size layout;
+    display: inline-grid;
+    grid-row-gap: 1000000000vw;
+    grid-template-rows: 150px 100px;
+}
+.grid > div {
+    grid-row: auto / -1;
+    position: absolute;
+}
+</style>
+<div class="grid">
+  <div id="item">X</div>
+</div>
+<script>
+  test(function () {
+    testGridPositionDefinitionsValues(document.getElementById("item"), "auto", "-1", "auto", "auto");
+  }, "Tests that setting grid gap to a huge value is properly clamped and does not make the renderer crash.");
+ </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-003.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-003.html
index 9bcb8716..5a80702 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-003.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-003.html
@@ -11,27 +11,16 @@
 <script src="resources/grid-tracks-length.js"></script>
 
 <div id="autoFillGrid" class="grid tallGrid lotsOfFixedRepeatWithAutoFillRows"></div>
-<div id="autoFitGrid" class="grid tallGrid lotsOfFixedRepeatWithAutoFitRows">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastRow">Item3</div>
-</div>
 
 <script>
 
 test(function() {
      var autoFillGrid = testElement("autoFillGrid", "grid-template-rows", 3570505);
-     var autoFitGrid = testElement("autoFitGrid", "grid-template-rows", 5034005);
 
      assert_equals(autoFillGrid[3570505 - 1], "1px");
      assert_equals(autoFillGrid[3570505 - 2], "1px");
      assert_equals(autoFillGrid[0], "10px");
      assert_equals(autoFillGrid[1], "2px");
-
-     assert_equals(autoFitGrid[5034005 - 1], "1px");
-     assert_equals(autoFitGrid[5034005 - 2], "1px");
-     assert_equals(autoFitGrid[0], "10px");
-     assert_equals(autoFitGrid[1], "2px");
 }, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids (normal tracks clamped).");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-004.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-004.html
index 1bb70d1..f4f9c4c 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-004.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-004.html
@@ -10,15 +10,7 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="wideAutoFillGridFewRepetitions" class="grid wideGrid lotsOfAutoRepeatWithAutoFillCols"></div>
-<div id="wideAutoFitGridFewRepetitions" class="grid wideGrid lotsOfAutoRepeatWithAutoFitCols">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastColumn">Item3</div>
-</div>
-
-<div id="tallAutoFillGridFewRepetitions" class="grid tallGrid lotsOfAutoRepeatWithAutoFillRows"></div>
-<div id="tallAutoFitGridFewRepetitions" class="grid tallGrid lotsOfAutoRepeatWithAutoFitRows">
+<div id="autoFitGrid" class="grid tallGrid lotsOfFixedRepeatWithAutoFitRows">
     <div>Item1</div>
     <div>Item2</div>
     <div class="lastRow">Item3</div>
@@ -27,53 +19,12 @@
 <script>
 
 test(function() {
-     var fillGridElement = document.getElementById("wideAutoFillGridFewRepetitions");
-     var fitGridElement = document.getElementById("wideAutoFitGridFewRepetitions");
+     var autoFitGrid = testElement("autoFitGrid", "grid-template-rows", 5034005);
 
-     fillGridElement.style.gridGap = "100px";
-     fitGridElement.style.gridGap = "100px";
-
-     var autoFillGrid = testElement("wideAutoFillGridFewRepetitions", "grid-template-columns", 306710);
-     var autoFitGrid = testElement("wideAutoFitGridFewRepetitions", "grid-template-columns", 314572);
-
-     assert_equals(autoFillGrid[306710 - 1], "1px");
-     assert_equals(autoFillGrid[306710 - 2], "1px");
-     assert_equals(autoFitGrid[314572 - 1], "1px");
-     assert_equals(autoFitGrid[314572 - 2], "1px");
-
-     fillGridElement.style.gridGap = "1000000px";
-     fitGridElement.style.gridGap = "1000000px";
-
-     testElement("wideAutoFillGridFewRepetitions", "grid-template-columns", 30);
-     testElement("wideAutoFitGridFewRepetitions", "grid-template-columns", 34);
-
-     fillGridElement.style.gridGap = "0px";
-     fitGridElement.style.gridGap = "0px";
-}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids with gaps.");
-
-test(function() {
-     var autoFillGridElement = document.getElementById("tallAutoFillGridFewRepetitions");
-     var autoFitGridElement = document.getElementById("tallAutoFitGridFewRepetitions");
-
-     autoFillGridElement.style.gridGap = "100px";
-     autoFitGridElement.style.gridGap = "100px";
-
-     var autoFillGrid = testElement("tallAutoFillGridFewRepetitions", "grid-template-rows", 306710);
-     var autoFitGrid = testElement("tallAutoFitGridFewRepetitions", "grid-template-rows", 314572);
-
-     assert_equals(autoFillGrid[306710 - 1], "1px");
-     assert_equals(autoFillGrid[306710 - 2], "1px");
-     assert_equals(autoFitGrid[314572 - 1], "1px");
-     assert_equals(autoFitGrid[314572 - 2], "1px");
-
-     autoFillGridElement.style.gridGap = "1000000px";
-     autoFitGridElement.style.gridGap = "1000000px";
-
-     testElement("tallAutoFillGridFewRepetitions", "grid-template-rows", 30);
-     testElement("tallAutoFitGridFewRepetitions", "grid-template-rows", 34);
-
-     autoFillGridElement.style.gridGap = "0px";
-     autoFitGridElement.style.gridGap = "0px";
-}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids with gaps.");
+     assert_equals(autoFitGrid[5034005 - 1], "1px");
+     assert_equals(autoFitGrid[5034005 - 2], "1px");
+     assert_equals(autoFitGrid[0], "10px");
+     assert_equals(autoFitGrid[1], "2px");
+}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids (normal tracks clamped).");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-005.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-005.html
index 30c62d4..1bb70d1 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-005.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-005.html
@@ -10,18 +10,70 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="wideAutoFillGridReversed" class="grid wideGrid lotsOfFixedRepeatWithAutoFillColsReversed"></div>
+<div id="wideAutoFillGridFewRepetitions" class="grid wideGrid lotsOfAutoRepeatWithAutoFillCols"></div>
+<div id="wideAutoFitGridFewRepetitions" class="grid wideGrid lotsOfAutoRepeatWithAutoFitCols">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastColumn">Item3</div>
+</div>
+
+<div id="tallAutoFillGridFewRepetitions" class="grid tallGrid lotsOfAutoRepeatWithAutoFillRows"></div>
+<div id="tallAutoFitGridFewRepetitions" class="grid tallGrid lotsOfAutoRepeatWithAutoFitRows">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastRow">Item3</div>
+</div>
 
 <script>
 
 test(function() {
-     var autoFillGrid = testElement("wideAutoFillGridReversed", "grid-template-columns", 3570505);
+     var fillGridElement = document.getElementById("wideAutoFillGridFewRepetitions");
+     var fitGridElement = document.getElementById("wideAutoFitGridFewRepetitions");
 
-     assert_equals(autoFillGrid[3570505 - 1], "20px");
-     assert_equals(autoFillGrid[3570505 - 2], "7px");
-     assert_equals(autoFillGrid[0], "1px");
-     assert_equals(autoFillGrid[1], "1px");
+     fillGridElement.style.gridGap = "100px";
+     fitGridElement.style.gridGap = "100px";
 
-}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids (auto repeat tracks clamped).");
+     var autoFillGrid = testElement("wideAutoFillGridFewRepetitions", "grid-template-columns", 306710);
+     var autoFitGrid = testElement("wideAutoFitGridFewRepetitions", "grid-template-columns", 314572);
+
+     assert_equals(autoFillGrid[306710 - 1], "1px");
+     assert_equals(autoFillGrid[306710 - 2], "1px");
+     assert_equals(autoFitGrid[314572 - 1], "1px");
+     assert_equals(autoFitGrid[314572 - 2], "1px");
+
+     fillGridElement.style.gridGap = "1000000px";
+     fitGridElement.style.gridGap = "1000000px";
+
+     testElement("wideAutoFillGridFewRepetitions", "grid-template-columns", 30);
+     testElement("wideAutoFitGridFewRepetitions", "grid-template-columns", 34);
+
+     fillGridElement.style.gridGap = "0px";
+     fitGridElement.style.gridGap = "0px";
+}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids with gaps.");
+
+test(function() {
+     var autoFillGridElement = document.getElementById("tallAutoFillGridFewRepetitions");
+     var autoFitGridElement = document.getElementById("tallAutoFitGridFewRepetitions");
+
+     autoFillGridElement.style.gridGap = "100px";
+     autoFitGridElement.style.gridGap = "100px";
+
+     var autoFillGrid = testElement("tallAutoFillGridFewRepetitions", "grid-template-rows", 306710);
+     var autoFitGrid = testElement("tallAutoFitGridFewRepetitions", "grid-template-rows", 314572);
+
+     assert_equals(autoFillGrid[306710 - 1], "1px");
+     assert_equals(autoFillGrid[306710 - 2], "1px");
+     assert_equals(autoFitGrid[314572 - 1], "1px");
+     assert_equals(autoFitGrid[314572 - 2], "1px");
+
+     autoFillGridElement.style.gridGap = "1000000px";
+     autoFitGridElement.style.gridGap = "1000000px";
+
+     testElement("tallAutoFillGridFewRepetitions", "grid-template-rows", 30);
+     testElement("tallAutoFitGridFewRepetitions", "grid-template-rows", 34);
+
+     autoFillGridElement.style.gridGap = "0px";
+     autoFitGridElement.style.gridGap = "0px";
+}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids with gaps.");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-006.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-006.html
index f149811..30c62d4 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-006.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-006.html
@@ -10,21 +10,18 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="wideAutoFitGridReversed" class="grid wideGrid lotsOfFixedRepeatWithAutoFitColsReversed">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastColumn">Item3</div>
-</div>
+<div id="wideAutoFillGridReversed" class="grid wideGrid lotsOfFixedRepeatWithAutoFillColsReversed"></div>
 
 <script>
 
 test(function() {
-     var autoFitGrid = testElement("wideAutoFitGridReversed", "grid-template-columns", 5034005);
+     var autoFillGrid = testElement("wideAutoFillGridReversed", "grid-template-columns", 3570505);
 
-     assert_equals(autoFitGrid[5034005 - 1], "8px");
-     assert_equals(autoFitGrid[5034005 - 2], "0px");
-     assert_equals(autoFitGrid[0], "1px");
-     assert_equals(autoFitGrid[1], "1px");
+     assert_equals(autoFillGrid[3570505 - 1], "20px");
+     assert_equals(autoFillGrid[3570505 - 2], "7px");
+     assert_equals(autoFillGrid[0], "1px");
+     assert_equals(autoFillGrid[1], "1px");
+
 }, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids (auto repeat tracks clamped).");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-007.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-007.html
index 2530fe5..f149811 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-007.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-007.html
@@ -10,18 +10,21 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="tallAutoFillGridReversed" class="grid tallGrid lotsOfFixedRepeatWithAutoFillRowsReversed"></div>
+<div id="wideAutoFitGridReversed" class="grid wideGrid lotsOfFixedRepeatWithAutoFitColsReversed">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastColumn">Item3</div>
+</div>
 
 <script>
 
 test(function() {
-     var autoFillGrid = testElement("tallAutoFillGridReversed", "grid-template-rows", 3570505);
+     var autoFitGrid = testElement("wideAutoFitGridReversed", "grid-template-columns", 5034005);
 
-     assert_equals(autoFillGrid[3570505 - 1], "20px");
-     assert_equals(autoFillGrid[3570505 - 2], "7px");
-     assert_equals(autoFillGrid[0], "1px");
-     assert_equals(autoFillGrid[1], "1px");
-
-}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids (auto repeat tracks clamped).");
+     assert_equals(autoFitGrid[5034005 - 1], "8px");
+     assert_equals(autoFitGrid[5034005 - 2], "0px");
+     assert_equals(autoFitGrid[0], "1px");
+     assert_equals(autoFitGrid[1], "1px");
+}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids (auto repeat tracks clamped).");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-008.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-008.html
index 9e9d030b..2530fe5 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-008.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-008.html
@@ -10,21 +10,18 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="tallAutoFitGridReversed" class="grid tallGrid lotsOfFixedRepeatWithAutoFitRowsReversed">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastRow">Item3</div>
-</div>
+<div id="tallAutoFillGridReversed" class="grid tallGrid lotsOfFixedRepeatWithAutoFillRowsReversed"></div>
 
 <script>
 
 test(function() {
-     var autoFitGrid = testElement("tallAutoFitGridReversed", "grid-template-rows", 5034005);
+     var autoFillGrid = testElement("tallAutoFillGridReversed", "grid-template-rows", 3570505);
 
-     assert_equals(autoFitGrid[5034005 - 1], "8px");
-     assert_equals(autoFitGrid[5034005 - 2], "0px");
-     assert_equals(autoFitGrid[0], "1px");
-     assert_equals(autoFitGrid[1], "1px");
+     assert_equals(autoFillGrid[3570505 - 1], "20px");
+     assert_equals(autoFillGrid[3570505 - 2], "7px");
+     assert_equals(autoFillGrid[0], "1px");
+     assert_equals(autoFillGrid[1], "1px");
+
 }, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids (auto repeat tracks clamped).");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-009.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-009.html
index bba078a..9e9d030b 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-009.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-009.html
@@ -10,24 +10,21 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="wideAutoFillGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFillCols minSizeWideGrid min-content"></div>
-<div id="wideAutoFitGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFitCols minSizeWideGrid min-content">
+<div id="tallAutoFitGridReversed" class="grid tallGrid lotsOfFixedRepeatWithAutoFitRowsReversed">
     <div>Item1</div>
     <div>Item2</div>
-    <div class="lastColumn">Item3</div>
+    <div class="lastRow">Item3</div>
 </div>
 
 <script>
 
 test(function() {
-     var autoFillCols = testElement("wideAutoFillGridFewRepetitionsMinSize", "grid-template-columns", 3569630);
-     var autoFitCols = testElement("wideAutoFitGridFewRepetitionsMinSize", "grid-template-columns", 5033170);
+     var autoFitGrid = testElement("tallAutoFitGridReversed", "grid-template-rows", 5034005);
 
-     /* Check that clamping auto repetitions does not reduce the amount of the other tracks. */
-     assert_equals(autoFillCols[3569630 - 1], "0.390625px");
-     assert_equals(autoFillCols[3569630 - 2], "0.390625px");
-     assert_equals(autoFitCols[5033170 - 1], "1px");
-     assert_equals(autoFitCols[5033170 - 2], "1px");
-}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids with gaps and min-width.");
+     assert_equals(autoFitGrid[5034005 - 1], "8px");
+     assert_equals(autoFitGrid[5034005 - 2], "0px");
+     assert_equals(autoFitGrid[0], "1px");
+     assert_equals(autoFitGrid[1], "1px");
+}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids (auto repeat tracks clamped).");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-010.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-010.html
index 4906f9e..b70c2d5 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-010.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-010.html
@@ -10,23 +10,16 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="tallAutoFillGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFillRows minSizeTallGrid min-content"></div>
-<div id="tallAutoFitGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFitRows minSizeTallGrid min-content">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastRow">Item3</div>
-</div>
+<div id="wideAutoFillGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFillCols minSizeWideGrid min-content"></div>
 
 <script>
 
 test(function() {
-     var autoFillRows = testElement("tallAutoFillGridFewRepetitionsMinSize", "grid-template-rows", 3569630);
-     var autoFitRows = testElement("tallAutoFitGridFewRepetitionsMinSize", "grid-template-rows", 5033173);
+     var autoFillCols = testElement("wideAutoFillGridFewRepetitionsMinSize", "grid-template-columns", 3569630);
 
-     assert_equals(autoFillRows[3569630 - 1], "0.390625px");
-     assert_equals(autoFillRows[3569630 - 2], "0.390625px");
-     assert_equals(autoFitRows[5033173 - 1], "1px");
-     assert_equals(autoFitRows[5033173 - 2], "1px");
-}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids with gaps and min-height.");
+     /* Check that clamping auto repetitions does not reduce the amount of the other tracks. */
+     assert_equals(autoFillCols[3569630 - 1], "0.390625px");
+     assert_equals(autoFillCols[3569630 - 2], "0.390625px");
+}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids with gaps and min-width.");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-011.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-011.html
index 3f5a5df..1349fbf 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-011.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-011.html
@@ -10,55 +10,7 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="twoThousandAutoFillRows" class="grid height25k autoFillRows25px"></div>
-<div id="fourThousandAutoFitRows" class="grid height25k autoFitRows25px">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastRow">Item3</div>
-</div>
-
-<div id="twoThousandAutoFillCols" class="grid width25k autoFillCols25px"></div>
-<div id="fourThousandAutoFitCols" class="grid width25k autoFitCols25px">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastColumn">Item3</div>
-</div>
-
-<div id="moreThanAThousandAutoFillAndFixedRows" class="grid height25k autoFillRows205pxFixed5px"></div>
-<div id="moreThanAThousandAutoFitAndFixedRows" class="grid height25k autoFitRows205pxFixed5px">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastRow">Item3</div>
-</div>
-
-<div id="moreThanAThousandAutoFillAndFixedCols" class="grid width25k autoFillCols205pxFixed5px"></div>
-<div id="moreThanAThousandAutoFitAndFixedCols" class="grid width25k autoFitCols205pxFixed5px">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastColumn">Item3</div>
-</div>
-
-<div id="aThousandFixedZeroAutoFillRows" class="grid height25k autoFillAndAThousandFixedRows"></div>
-<div id="aThousandFixedZeroAutoFitRows" class="grid height25k autoFitAndAThousandFixedRows">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastRow">Item3</div>
-</div>
-
-<div id="aThousandFixedZeroAutoFillCols" class="grid width25k autoFillAndAThousandFixedCols"></div>
-<div id="aThousandFixedZeroAutoFitCols" class="grid width25k autoFitAndAThousandFixedCols">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastColumn">Item3</div>
-</div>
-
-<div id="aHundredThousandFixedZeroAutoFitRowsFreeSpace" class="grid tallGrid autoFitAndAThousandFixedRows">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastRow">Item3</div>
-</div>
-
-<div id="aHundredThousandFixedZeroAutoFitColsFreeSpace" class="grid wideGrid autoFitAndAThousandFixedCols">
+<div id="wideAutoFitGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFitCols minSizeWideGrid min-content">
     <div>Item1</div>
     <div>Item2</div>
     <div class="lastColumn">Item3</div>
@@ -67,77 +19,11 @@
 <script>
 
 test(function() {
-     var autoFillRows = testElement("twoThousandAutoFillRows", "grid-template-rows", 2000);
-     var autoFitRows = testElement("fourThousandAutoFitRows", "grid-template-rows", 4000);
+     var autoFitCols = testElement("wideAutoFitGridFewRepetitionsMinSize", "grid-template-columns", 5033170);
 
-     assert_equals(autoFillRows[2000 - 1], "8px");
-     assert_equals(autoFillRows[2000 - 2], "17px");
-     assert_equals(autoFitRows[4000 - 1], "5px");
-     assert_equals(autoFitRows[4000 - 2], "0px");
-}, "Test that we don't crash when there are exactly kGridMaxTracks auto repeat rows on very tall grids.");
-
-test(function() {
-     var autoFillCols = testElement("twoThousandAutoFillCols", "grid-template-columns", 2000);
-     var autoFitCols = testElement("fourThousandAutoFitCols", "grid-template-columns", 4000);
-
-     assert_equals(autoFillCols[2000 - 1], "23px");
-     assert_equals(autoFillCols[2000 - 2], "2px");
-     assert_equals(autoFitCols[4000 - 1], "5px");
-     assert_equals(autoFitCols[4000 - 2], "0px");
-}, "Test that we don't crash when there are exactly kGridMaxTracks auto repeat columns on very wide grids.");
-
-test(function() {
-     var autoFillRows = testElement("moreThanAThousandAutoFillAndFixedRows", "grid-template-rows", 1100);
-     var autoFitRows = testElement("moreThanAThousandAutoFitAndFixedRows", "grid-template-rows", 1400);
-
-     assert_equals(autoFillRows[1100 - 1], "5px");
-     assert_equals(autoFillRows[1100 - 2], "200px");
-     assert_equals(autoFitRows[1400 - 1], "72px");
-     assert_equals(autoFitRows[1400 - 2], "0px");
-}, "Test that we don't crash when there are exactly kGridMaxTracks (normal and auto-repeat) rows on very tall grids.");
-
-test(function() {
-     var autoFillCols = testElement("moreThanAThousandAutoFillAndFixedCols", "grid-template-columns", 1100);
-     var autoFitCols = testElement("moreThanAThousandAutoFitAndFixedCols", "grid-template-columns", 1400);
-
-     assert_equals(autoFillCols[1100 - 1], "5px");
-     assert_equals(autoFillCols[1100 - 2], "200px");
-     assert_equals(autoFitCols[1400 - 1], "72px");
-     assert_equals(autoFitCols[1400 - 2], "0px");
-}, "Test that we don't crash when there are exactly kGridMaxTracks (normal and auto-repeat) columns on very wide grids.");
-
-test(function() {
-     var autoFillGrid = testElement("aThousandFixedZeroAutoFillRows", "grid-template-rows", 1001);
-     var autoFitGrid = testElement("aThousandFixedZeroAutoFitRows", "grid-template-rows", 1003);
-
-     assert_equals(autoFillGrid[1001 - 1], "37px");
-     assert_equals(autoFillGrid[0], "2px");
-     assert_equals(autoFitGrid[1003 - 1], "37px");
-     assert_equals(autoFitGrid[0], "20px");
-}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat rows on very tall grids.");
-
-test(function() {
-     var autoFillGrid = testElement("aThousandFixedZeroAutoFillCols", "grid-template-columns", 1001);
-     var autoFitGrid = testElement("aThousandFixedZeroAutoFitCols", "grid-template-columns", 1003);
-
-     assert_equals(autoFillGrid[1001 - 1], "37px");
-     assert_equals(autoFillGrid[0], "2px");
-     assert_equals(autoFitGrid[1003 - 1], "37px");
-     assert_equals(autoFitGrid[0], "20px");
-}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat columns on very wide grids.");
-
-test(function() {
-     var autoFitGrid = testElement("aHundredThousandFixedZeroAutoFitRowsFreeSpace", "grid-template-rows", 709114);
-
-     assert_equals(autoFitGrid[709114 - 1], "37px");
-     assert_equals(autoFitGrid[0], "20px");
-}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat rows on very tall grids with enough room for auto repetitions.");
-
-test(function() {
-     var autoFitGrid = testElement("aHundredThousandFixedZeroAutoFitColsFreeSpace", "grid-template-columns", 709114);
-
-     assert_equals(autoFitGrid[709114 - 1], "37px");
-     assert_equals(autoFitGrid[0], "20px");
-}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat columns on very wide grids with enough room for auto repetitions.");
+     /* Check that clamping auto repetitions does not reduce the amount of the other tracks. */
+     assert_equals(autoFitCols[5033170 - 1], "1px");
+     assert_equals(autoFitCols[5033170 - 2], "1px");
+}, "Test that we don't get more than kGridMaxTracks repetitions even on very wide grids with gaps and min-width.");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-012.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-012.html
index 955f49a..4fabb58 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-012.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-012.html
@@ -10,40 +10,15 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="moreThanAThousandFixedZeroAutoFillRows" class="grid height25k autoFillAndMoreThanThousandFixedRows"></div>
-<div id="moreThanAThousandFixedZeroAutoFitRows" class="grid height25k autoFitAndMoreThanThousandFixedRows">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastRow">Item3</div>
-</div>
-
-<div id="moreThanAThousandFixedZeroAutoFillCols" class="grid width25k autoFillAndMoreThanThousandFixedCols"></div>
-<div id="moreThanAThousandFixedZeroAutoFitCols" class="grid width25k autoFitAndMoreThanThousandFixedCols">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastColumn">Item3</div>
-</div>
+<div id="tallAutoFillGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFillRows minSizeTallGrid min-content"></div>
 
 <script>
 
 test(function() {
-     var autoFillGrid = testElement("moreThanAThousandFixedZeroAutoFillRows", "grid-template-rows", 1648);
-     var autoFitGrid = testElement("moreThanAThousandFixedZeroAutoFitRows", "grid-template-rows", 1630);
+     var autoFillRows = testElement("tallAutoFillGridFewRepetitionsMinSize", "grid-template-rows", 3569630);
 
-     assert_equals(autoFillGrid[1648 - 1], "6px");
-     assert_equals(autoFillGrid[0], "7px");
-     assert_equals(autoFitGrid[1630 - 1], "6px");
-     assert_equals(autoFitGrid[0], "7px");
-}, "Test that we don't crash when there are more than kGridMaxTracks non auto-repeat rows on very tall grids.");
-
-test(function() {
-     var autoFillGrid = testElement("moreThanAThousandFixedZeroAutoFillCols", "grid-template-columns", 1648);
-     var autoFitGrid = testElement("moreThanAThousandFixedZeroAutoFitCols", "grid-template-columns", 1630);
-
-     assert_equals(autoFillGrid[1648 - 1], "6px");
-     assert_equals(autoFillGrid[0], "7px");
-     assert_equals(autoFitGrid[1630 - 1], "6px");
-     assert_equals(autoFitGrid[0], "7px");
-}, "Test that we don't crash when there are more than kGridMaxTracks non auto-repeat columns on very wide grids.");
+     assert_equals(autoFillRows[3569630 - 1], "0.390625px");
+     assert_equals(autoFillRows[3569630 - 2], "0.390625px");
+}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids with gaps and min-height.");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-013.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-013.html
index d76d0004..554e0444 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-013.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-013.html
@@ -10,15 +10,19 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="handMadeAutoFillRows" class="grid tallGrid handMadeMoreThanThousandAutoFillRows"></div>
+<div id="tallAutoFitGridFewRepetitionsMinSize" class="grid lotsOfAutoRepeatWithAutoFitRows minSizeTallGrid min-content">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastRow">Item3</div>
+</div>
 
 <script>
 
 test(function() {
-     var autoFillGrid = testElement("handMadeAutoFillRows", "grid-template-rows", 4601597);
+     var autoFitRows = testElement("tallAutoFitGridFewRepetitionsMinSize", "grid-template-rows", 5033173);
 
-     assert_equals(autoFillGrid[4601597 - 1], "999px");
-     assert_equals(autoFillGrid[0], "10px");
-}, "Test that we don't crash when there are more than kGridMaxTracks rows in the auto repeat <track-list>.");
+     assert_equals(autoFitRows[5033173 - 1], "1px");
+     assert_equals(autoFitRows[5033173 - 2], "1px");
+}, "Test that we don't get more than kGridMaxTracks repetitions even on very tall grids with gaps and min-height.");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-014.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-014.html
index 77bd7ea..3f5a5df 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-014.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-014.html
@@ -10,19 +10,134 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="handMadeAutoFitRows" class="grid tallGrid handMadeMoreThanThousandAutoFitRows">
+<div id="twoThousandAutoFillRows" class="grid height25k autoFillRows25px"></div>
+<div id="fourThousandAutoFitRows" class="grid height25k autoFitRows25px">
     <div>Item1</div>
     <div>Item2</div>
     <div class="lastRow">Item3</div>
 </div>
 
+<div id="twoThousandAutoFillCols" class="grid width25k autoFillCols25px"></div>
+<div id="fourThousandAutoFitCols" class="grid width25k autoFitCols25px">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastColumn">Item3</div>
+</div>
+
+<div id="moreThanAThousandAutoFillAndFixedRows" class="grid height25k autoFillRows205pxFixed5px"></div>
+<div id="moreThanAThousandAutoFitAndFixedRows" class="grid height25k autoFitRows205pxFixed5px">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastRow">Item3</div>
+</div>
+
+<div id="moreThanAThousandAutoFillAndFixedCols" class="grid width25k autoFillCols205pxFixed5px"></div>
+<div id="moreThanAThousandAutoFitAndFixedCols" class="grid width25k autoFitCols205pxFixed5px">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastColumn">Item3</div>
+</div>
+
+<div id="aThousandFixedZeroAutoFillRows" class="grid height25k autoFillAndAThousandFixedRows"></div>
+<div id="aThousandFixedZeroAutoFitRows" class="grid height25k autoFitAndAThousandFixedRows">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastRow">Item3</div>
+</div>
+
+<div id="aThousandFixedZeroAutoFillCols" class="grid width25k autoFillAndAThousandFixedCols"></div>
+<div id="aThousandFixedZeroAutoFitCols" class="grid width25k autoFitAndAThousandFixedCols">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastColumn">Item3</div>
+</div>
+
+<div id="aHundredThousandFixedZeroAutoFitRowsFreeSpace" class="grid tallGrid autoFitAndAThousandFixedRows">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastRow">Item3</div>
+</div>
+
+<div id="aHundredThousandFixedZeroAutoFitColsFreeSpace" class="grid wideGrid autoFitAndAThousandFixedCols">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastColumn">Item3</div>
+</div>
+
 <script>
 
 test(function() {
-     var autoFitGrid = testElement("handMadeAutoFitRows", "grid-template-rows", 4601597);
+     var autoFillRows = testElement("twoThousandAutoFillRows", "grid-template-rows", 2000);
+     var autoFitRows = testElement("fourThousandAutoFitRows", "grid-template-rows", 4000);
 
-     assert_equals(autoFitGrid[4601597 - 1], "999px");
-     assert_equals(autoFitGrid[0], "10px");
-}, "Test that we don't crash when there are more than kGridMaxTracks rows in the auto repeat <track-list>.");
+     assert_equals(autoFillRows[2000 - 1], "8px");
+     assert_equals(autoFillRows[2000 - 2], "17px");
+     assert_equals(autoFitRows[4000 - 1], "5px");
+     assert_equals(autoFitRows[4000 - 2], "0px");
+}, "Test that we don't crash when there are exactly kGridMaxTracks auto repeat rows on very tall grids.");
+
+test(function() {
+     var autoFillCols = testElement("twoThousandAutoFillCols", "grid-template-columns", 2000);
+     var autoFitCols = testElement("fourThousandAutoFitCols", "grid-template-columns", 4000);
+
+     assert_equals(autoFillCols[2000 - 1], "23px");
+     assert_equals(autoFillCols[2000 - 2], "2px");
+     assert_equals(autoFitCols[4000 - 1], "5px");
+     assert_equals(autoFitCols[4000 - 2], "0px");
+}, "Test that we don't crash when there are exactly kGridMaxTracks auto repeat columns on very wide grids.");
+
+test(function() {
+     var autoFillRows = testElement("moreThanAThousandAutoFillAndFixedRows", "grid-template-rows", 1100);
+     var autoFitRows = testElement("moreThanAThousandAutoFitAndFixedRows", "grid-template-rows", 1400);
+
+     assert_equals(autoFillRows[1100 - 1], "5px");
+     assert_equals(autoFillRows[1100 - 2], "200px");
+     assert_equals(autoFitRows[1400 - 1], "72px");
+     assert_equals(autoFitRows[1400 - 2], "0px");
+}, "Test that we don't crash when there are exactly kGridMaxTracks (normal and auto-repeat) rows on very tall grids.");
+
+test(function() {
+     var autoFillCols = testElement("moreThanAThousandAutoFillAndFixedCols", "grid-template-columns", 1100);
+     var autoFitCols = testElement("moreThanAThousandAutoFitAndFixedCols", "grid-template-columns", 1400);
+
+     assert_equals(autoFillCols[1100 - 1], "5px");
+     assert_equals(autoFillCols[1100 - 2], "200px");
+     assert_equals(autoFitCols[1400 - 1], "72px");
+     assert_equals(autoFitCols[1400 - 2], "0px");
+}, "Test that we don't crash when there are exactly kGridMaxTracks (normal and auto-repeat) columns on very wide grids.");
+
+test(function() {
+     var autoFillGrid = testElement("aThousandFixedZeroAutoFillRows", "grid-template-rows", 1001);
+     var autoFitGrid = testElement("aThousandFixedZeroAutoFitRows", "grid-template-rows", 1003);
+
+     assert_equals(autoFillGrid[1001 - 1], "37px");
+     assert_equals(autoFillGrid[0], "2px");
+     assert_equals(autoFitGrid[1003 - 1], "37px");
+     assert_equals(autoFitGrid[0], "20px");
+}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat rows on very tall grids.");
+
+test(function() {
+     var autoFillGrid = testElement("aThousandFixedZeroAutoFillCols", "grid-template-columns", 1001);
+     var autoFitGrid = testElement("aThousandFixedZeroAutoFitCols", "grid-template-columns", 1003);
+
+     assert_equals(autoFillGrid[1001 - 1], "37px");
+     assert_equals(autoFillGrid[0], "2px");
+     assert_equals(autoFitGrid[1003 - 1], "37px");
+     assert_equals(autoFitGrid[0], "20px");
+}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat columns on very wide grids.");
+
+test(function() {
+     var autoFitGrid = testElement("aHundredThousandFixedZeroAutoFitRowsFreeSpace", "grid-template-rows", 709114);
+
+     assert_equals(autoFitGrid[709114 - 1], "37px");
+     assert_equals(autoFitGrid[0], "20px");
+}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat rows on very tall grids with enough room for auto repetitions.");
+
+test(function() {
+     var autoFitGrid = testElement("aHundredThousandFixedZeroAutoFitColsFreeSpace", "grid-template-columns", 709114);
+
+     assert_equals(autoFitGrid[709114 - 1], "37px");
+     assert_equals(autoFitGrid[0], "20px");
+}, "Test that we don't crash when there are exactly kGridMaxTracks non auto-repeat columns on very wide grids with enough room for auto repetitions.");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-015.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-015.html
index 082e562f..955f49a 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-015.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-015.html
@@ -10,15 +10,40 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="handMadeAutoFillCols" class="grid wideGrid handMadeMoreThanThousandAutoFillCols"></div>
+<div id="moreThanAThousandFixedZeroAutoFillRows" class="grid height25k autoFillAndMoreThanThousandFixedRows"></div>
+<div id="moreThanAThousandFixedZeroAutoFitRows" class="grid height25k autoFitAndMoreThanThousandFixedRows">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastRow">Item3</div>
+</div>
+
+<div id="moreThanAThousandFixedZeroAutoFillCols" class="grid width25k autoFillAndMoreThanThousandFixedCols"></div>
+<div id="moreThanAThousandFixedZeroAutoFitCols" class="grid width25k autoFitAndMoreThanThousandFixedCols">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastColumn">Item3</div>
+</div>
 
 <script>
 
 test(function() {
-     var autoFillGrid = testElement("handMadeAutoFillCols", "grid-template-columns", 4601597);
+     var autoFillGrid = testElement("moreThanAThousandFixedZeroAutoFillRows", "grid-template-rows", 1648);
+     var autoFitGrid = testElement("moreThanAThousandFixedZeroAutoFitRows", "grid-template-rows", 1630);
 
-     assert_equals(autoFillGrid[4601597 - 1], "999px");
-     assert_equals(autoFillGrid[0], "10px");
-}, "Test that we don't crash when there are more than kGridMaxTracks columns in the auto repeat <track-list>.");
+     assert_equals(autoFillGrid[1648 - 1], "6px");
+     assert_equals(autoFillGrid[0], "7px");
+     assert_equals(autoFitGrid[1630 - 1], "6px");
+     assert_equals(autoFitGrid[0], "7px");
+}, "Test that we don't crash when there are more than kGridMaxTracks non auto-repeat rows on very tall grids.");
+
+test(function() {
+     var autoFillGrid = testElement("moreThanAThousandFixedZeroAutoFillCols", "grid-template-columns", 1648);
+     var autoFitGrid = testElement("moreThanAThousandFixedZeroAutoFitCols", "grid-template-columns", 1630);
+
+     assert_equals(autoFillGrid[1648 - 1], "6px");
+     assert_equals(autoFillGrid[0], "7px");
+     assert_equals(autoFitGrid[1630 - 1], "6px");
+     assert_equals(autoFitGrid[0], "7px");
+}, "Test that we don't crash when there are more than kGridMaxTracks non auto-repeat columns on very wide grids.");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-016.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-016.html
index 8ae65e64..d76d0004 100644
--- a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-016.html
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-016.html
@@ -10,20 +10,15 @@
 <script src="resources/grid-definitions-parsing-utils.js"></script>
 <script src="resources/grid-tracks-length.js"></script>
 
-<div id="handMadeAutoFillCols" class="grid wideGrid handMadeMoreThanThousandAutoFillCols"></div>
-<div id="handMadeAutoFitCols" class="grid wideGrid handMadeMoreThanThousandAutoFitCols">
-    <div>Item1</div>
-    <div>Item2</div>
-    <div class="lastColumn">Item3</div>
-</div>
+<div id="handMadeAutoFillRows" class="grid tallGrid handMadeMoreThanThousandAutoFillRows"></div>
 
 <script>
 
 test(function() {
-     var autoFitGrid = testElement("handMadeAutoFitCols", "grid-template-columns", 4601597);
+     var autoFillGrid = testElement("handMadeAutoFillRows", "grid-template-rows", 4601597);
 
-     assert_equals(autoFitGrid[4601597 - 1], "999px");
-     assert_equals(autoFitGrid[0], "10px");
-}, "Test that we don't crash when there are more than kGridMaxTracks columns in the auto repeat <track-list>.");
+     assert_equals(autoFillGrid[4601597 - 1], "999px");
+     assert_equals(autoFillGrid[0], "10px");
+}, "Test that we don't crash when there are more than kGridMaxTracks rows in the auto repeat <track-list>.");
 
 </script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-017.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-017.html
new file mode 100644
index 0000000..77bd7ea
--- /dev/null
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-017.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Test for auto-fit and auto-fill with huge grids (lots of tracks)</title>
+<link href="resources/grid.css" rel="stylesheet">
+<link href="../css-intrinsic-dimensions/resources/width-keyword-classes.css" rel="stylesheet">
+<link href="../css-intrinsic-dimensions/resources/height-keyword-classes.css" rel="stylesheet">
+<link href="resources/huge-grids.css" rel="stylesheet">
+
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/grid-definitions-parsing-utils.js"></script>
+<script src="resources/grid-tracks-length.js"></script>
+
+<div id="handMadeAutoFitRows" class="grid tallGrid handMadeMoreThanThousandAutoFitRows">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastRow">Item3</div>
+</div>
+
+<script>
+
+test(function() {
+     var autoFitGrid = testElement("handMadeAutoFitRows", "grid-template-rows", 4601597);
+
+     assert_equals(autoFitGrid[4601597 - 1], "999px");
+     assert_equals(autoFitGrid[0], "10px");
+}, "Test that we don't crash when there are more than kGridMaxTracks rows in the auto repeat <track-list>.");
+
+</script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-018.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-018.html
new file mode 100644
index 0000000..082e562f
--- /dev/null
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-018.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>Test for auto-fit and auto-fill with huge grids (lots of tracks)</title>
+<link href="resources/grid.css" rel="stylesheet">
+<link href="../css-intrinsic-dimensions/resources/width-keyword-classes.css" rel="stylesheet">
+<link href="../css-intrinsic-dimensions/resources/height-keyword-classes.css" rel="stylesheet">
+<link href="resources/huge-grids.css" rel="stylesheet">
+
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/grid-definitions-parsing-utils.js"></script>
+<script src="resources/grid-tracks-length.js"></script>
+
+<div id="handMadeAutoFillCols" class="grid wideGrid handMadeMoreThanThousandAutoFillCols"></div>
+
+<script>
+
+test(function() {
+     var autoFillGrid = testElement("handMadeAutoFillCols", "grid-template-columns", 4601597);
+
+     assert_equals(autoFillGrid[4601597 - 1], "999px");
+     assert_equals(autoFillGrid[0], "10px");
+}, "Test that we don't crash when there are more than kGridMaxTracks columns in the auto repeat <track-list>.");
+
+</script>
diff --git a/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-019.html b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-019.html
new file mode 100644
index 0000000..8ae65e64
--- /dev/null
+++ b/third_party/blink/web_tests/fast/css-grid-layout/grid-auto-repeat-huge-grid-019.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Test for auto-fit and auto-fill with huge grids (lots of tracks)</title>
+<link href="resources/grid.css" rel="stylesheet">
+<link href="../css-intrinsic-dimensions/resources/width-keyword-classes.css" rel="stylesheet">
+<link href="../css-intrinsic-dimensions/resources/height-keyword-classes.css" rel="stylesheet">
+<link href="resources/huge-grids.css" rel="stylesheet">
+
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/grid-definitions-parsing-utils.js"></script>
+<script src="resources/grid-tracks-length.js"></script>
+
+<div id="handMadeAutoFillCols" class="grid wideGrid handMadeMoreThanThousandAutoFillCols"></div>
+<div id="handMadeAutoFitCols" class="grid wideGrid handMadeMoreThanThousandAutoFitCols">
+    <div>Item1</div>
+    <div>Item2</div>
+    <div class="lastColumn">Item3</div>
+</div>
+
+<script>
+
+test(function() {
+     var autoFitGrid = testElement("handMadeAutoFitCols", "grid-template-columns", 4601597);
+
+     assert_equals(autoFitGrid[4601597 - 1], "999px");
+     assert_equals(autoFitGrid[0], "10px");
+}, "Test that we don't crash when there are more than kGridMaxTracks columns in the auto repeat <track-list>.");
+
+</script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/fenced-frame/history-fenced-frame.https.js b/third_party/blink/web_tests/http/tests/inspector-protocol/fenced-frame/history-fenced-frame.https.js
new file mode 100644
index 0000000..f7c6070
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/fenced-frame/history-fenced-frame.https.js
@@ -0,0 +1,42 @@
+(async function(testRunner) {
+  const {session, dp} = await testRunner.startURL(
+      'resources/page-with-fenced-frame.php',
+      'Tests that Page.GetNavigationHistory(), ' +
+          'Page.NavigateToHistoryEntry(), and Page.ResetNavigationHistory() ' +
+          'in a fenced frame are not allowed.');
+  await dp.Page.enable();
+  await dp.Runtime.enable();
+
+  dp.Target.setAutoAttach(
+      {autoAttach: true, waitForDebuggerOnStart: false, flatten: true});
+  let {sessionId} = (await dp.Target.onceAttachedToTarget()).params;
+
+  let childSession = session.createChild(sessionId);
+  let ffdp = childSession.protocol;
+
+  // Wait for FF to finish loading.
+  await ffdp.Page.enable();
+  ffdp.Page.setLifecycleEventsEnabled({enabled: true});
+  await ffdp.Page.onceLifecycleEvent(event => event.params.name === 'load');
+
+  await ffdp.page.navigate(
+      'http://localhost:8000/inspector-protocol/bfcache/resources/page-with-embed.html');
+
+  const result =
+      await childSession.sendCommand('Page.getNavigationHistory', {});
+  testRunner.log(
+      'Page.getNavigationHistory() from a fenced frame:\n' +
+      (result.error ? 'PASS: ' + result.error.message : 'FAIL: no error'));
+
+  await ffdp.Page.navigateToHistoryEntry({});
+  testRunner.log(
+      'Page.navigateToHistoryEntry() from a fenced frame:\n' +
+      (result.error ? 'PASS: ' + result.error.message : 'FAIL: no error'));
+
+  await ffdp.Page.ResetNavigationHistory({});
+  testRunner.log(
+      'Page.ResetNavigationHistory() from a fenced frame:\n' +
+      (result.error ? 'PASS: ' + result.error.message : 'FAIL: no error'));
+
+  testRunner.completeTest();
+});
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/fenced-frame/history-fenced-frame.https-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/fenced-frame/history-fenced-frame.https-expected.txt
new file mode 100644
index 0000000..c956345
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/fenced-frame/history-fenced-frame.https-expected.txt
@@ -0,0 +1,8 @@
+Tests that Page.GetNavigationHistory(), Page.NavigateToHistoryEntry(), and Page.ResetNavigationHistory() in a fenced frame are not allowed.
+Page.getNavigationHistory() from a fenced frame:
+PASS: Command can only be executed on top-level targets
+Page.navigateToHistoryEntry() from a fenced frame:
+PASS: Command can only be executed on top-level targets
+Page.ResetNavigationHistory() from a fenced frame:
+PASS: Command can only be executed on top-level targets
+
diff --git a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/acos-asin-atan-atan2-serialize-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/acos-asin-atan-atan2-serialize-expected.txt
deleted file mode 100644
index 4dca642..0000000
--- a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/acos-asin-atan-atan2-serialize-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This is a testharness.js-based test.
-FAIL 'rotate(acos(0))' as a specified value should serialize as 'rotate(calc(90deg))'. assert_not_equals: 'rotate(acos(0))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(acos(0))' as a computed value should serialize as 'matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)'. assert_equals: 'rotate(acos(0))' and 'matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)' should serialize the same in computed values. expected "matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)" but got "none"
-FAIL 'rotate(asin(1))' as a specified value should serialize as 'rotate(calc(90deg))'. assert_not_equals: 'rotate(asin(1))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(asin(1))' as a computed value should serialize as 'matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)'. assert_equals: 'rotate(asin(1))' and 'matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)' should serialize the same in computed values. expected "matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)" but got "none"
-FAIL 'rotate(calc(acos(pi - pi)))' as a specified value should serialize as 'rotate(calc(90deg))'. assert_not_equals: 'rotate(calc(acos(pi - pi)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(acos(pi - pi)))' as a computed value should serialize as 'matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)'. assert_equals: 'rotate(calc(acos(pi - pi)))' and 'matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)' should serialize the same in computed values. expected "matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)" but got "none"
-FAIL 'rotate(calc(asin(pi - pi + 1)))' as a specified value should serialize as 'rotate(calc(90deg))'. assert_not_equals: 'rotate(calc(asin(pi - pi + 1)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(asin(pi - pi + 1)))' as a computed value should serialize as 'matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)'. assert_equals: 'rotate(calc(asin(pi - pi + 1)))' and 'matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)' should serialize the same in computed values. expected "matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)" but got "none"
-FAIL 'rotate(calc(atan(infinity)))' as a specified value should serialize as 'rotate(calc(90deg))'. assert_not_equals: 'rotate(calc(atan(infinity)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(atan(infinity)))' as a computed value should serialize as 'matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)'. assert_equals: 'rotate(calc(atan(infinity)))' and 'matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)' should serialize the same in computed values. expected "matrix(6.12323e-17, 1, -1, 6.12323e-17, 0, 0)" but got "none"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/animations/calc-interpolation-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/animations/calc-interpolation-expected.txt
deleted file mode 100644
index f003b9b..0000000
--- a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/animations/calc-interpolation-expected.txt
+++ /dev/null
@@ -1,144 +0,0 @@
-This is a testharness.js-based test.
-Found 140 tests; 112 PASS, 28 FAIL, 0 TIMEOUT, 0 NOTRUN.
-FAIL CSS Transitions: property <left> from [0px] to [calc(infinity * 1px)] at (-0.25) should be [-8388600px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions: property <left> from [0px] to [calc(infinity * 1px)] at (0) should be [0px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions: property <left> from [0px] to [calc(infinity * 1px)] at (0.25) should be [8388600px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions: property <left> from [0px] to [calc(infinity * 1px)] at (0.5) should be [16777200px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions: property <left> from [0px] to [calc(infinity * 1px)] at (0.75) should be [25165800px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions: property <left> from [0px] to [calc(infinity * 1px)] at (1) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions: property <left> from [0px] to [calc(infinity * 1px)] at (1.25) should be [41943000px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions with transition: all: property <left> from [0px] to [calc(infinity * 1px)] at (-0.25) should be [-8388600px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions with transition: all: property <left> from [0px] to [calc(infinity * 1px)] at (0) should be [0px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions with transition: all: property <left> from [0px] to [calc(infinity * 1px)] at (0.25) should be [8388600px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions with transition: all: property <left> from [0px] to [calc(infinity * 1px)] at (0.5) should be [16777200px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions with transition: all: property <left> from [0px] to [calc(infinity * 1px)] at (0.75) should be [25165800px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions with transition: all: property <left> from [0px] to [calc(infinity * 1px)] at (1) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Transitions with transition: all: property <left> from [0px] to [calc(infinity * 1px)] at (1.25) should be [41943000px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Animations: property <left> from [0px] to [calc(infinity * 1px)] at (-0.25) should be [-33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Animations: property <left> from [0px] to [calc(infinity * 1px)] at (0) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Animations: property <left> from [0px] to [calc(infinity * 1px)] at (0.25) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Animations: property <left> from [0px] to [calc(infinity * 1px)] at (0.5) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Animations: property <left> from [0px] to [calc(infinity * 1px)] at (0.75) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Animations: property <left> from [0px] to [calc(infinity * 1px)] at (1) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL CSS Animations: property <left> from [0px] to [calc(infinity * 1px)] at (1.25) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL Web Animations: property <left> from [0px] to [calc(infinity * 1px)] at (-0.25) should be [-33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL Web Animations: property <left> from [0px] to [calc(infinity * 1px)] at (0) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL Web Animations: property <left> from [0px] to [calc(infinity * 1px)] at (0.25) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL Web Animations: property <left> from [0px] to [calc(infinity * 1px)] at (0.5) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL Web Animations: property <left> from [0px] to [calc(infinity * 1px)] at (0.75) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL Web Animations: property <left> from [0px] to [calc(infinity * 1px)] at (1) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-FAIL Web Animations: property <left> from [0px] to [calc(infinity * 1px)] at (1.25) should be [33554400px] assert_true: 'to' value should be supported expected true got false
-PASS CSS Transitions: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (-0.25) should be [-10px]
-PASS CSS Transitions: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0) should be [0px]
-PASS CSS Transitions: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.25) should be [10px]
-PASS CSS Transitions: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.5) should be [20px]
-PASS CSS Transitions: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.75) should be [30px]
-PASS CSS Transitions: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1) should be [40px]
-PASS CSS Transitions: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1.25) should be [50px]
-PASS CSS Transitions with transition: all: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (-0.25) should be [-10px]
-PASS CSS Transitions with transition: all: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0) should be [0px]
-PASS CSS Transitions with transition: all: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.25) should be [10px]
-PASS CSS Transitions with transition: all: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.5) should be [20px]
-PASS CSS Transitions with transition: all: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.75) should be [30px]
-PASS CSS Transitions with transition: all: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1) should be [40px]
-PASS CSS Transitions with transition: all: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1.25) should be [50px]
-PASS CSS Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (-0.25) should be [-10px]
-PASS CSS Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0) should be [0px]
-PASS CSS Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.25) should be [10px]
-PASS CSS Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.5) should be [20px]
-PASS CSS Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.75) should be [30px]
-PASS CSS Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1) should be [40px]
-PASS CSS Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1.25) should be [50px]
-PASS Web Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (-0.25) should be [-10px]
-PASS Web Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0) should be [0px]
-PASS Web Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.25) should be [10px]
-PASS Web Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.5) should be [20px]
-PASS Web Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.75) should be [30px]
-PASS Web Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1) should be [40px]
-PASS Web Animations: property <left> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1.25) should be [50px]
-PASS CSS Transitions: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (-0.25) should be [calc(((50% - 25px) * 1.25) + ((100% - 10px) * -0.25))]
-PASS CSS Transitions: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0) should be [calc(50% - 25px)]
-PASS CSS Transitions: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.25) should be [calc(((50% - 25px) * 0.75) + ((100% - 10px) * 0.25))]
-PASS CSS Transitions: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.5) should be [calc(((50% - 25px) * 0.5) + ((100% - 10px) * 0.5))]
-PASS CSS Transitions: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.75) should be [calc(((50% - 25px) * 0.25) + ((100% - 10px) * 0.75))]
-PASS CSS Transitions: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1) should be [calc(100% - 10px)]
-PASS CSS Transitions: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1.25) should be [calc(((50% - 25px) * -0.25) + ((100% - 10px) * 1.25))]
-PASS CSS Transitions with transition: all: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (-0.25) should be [calc(((50% - 25px) * 1.25) + ((100% - 10px) * -0.25))]
-PASS CSS Transitions with transition: all: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0) should be [calc(50% - 25px)]
-PASS CSS Transitions with transition: all: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.25) should be [calc(((50% - 25px) * 0.75) + ((100% - 10px) * 0.25))]
-PASS CSS Transitions with transition: all: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.5) should be [calc(((50% - 25px) * 0.5) + ((100% - 10px) * 0.5))]
-PASS CSS Transitions with transition: all: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.75) should be [calc(((50% - 25px) * 0.25) + ((100% - 10px) * 0.75))]
-PASS CSS Transitions with transition: all: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1) should be [calc(100% - 10px)]
-PASS CSS Transitions with transition: all: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1.25) should be [calc(((50% - 25px) * -0.25) + ((100% - 10px) * 1.25))]
-PASS CSS Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (-0.25) should be [calc(((50% - 25px) * 1.25) + ((100% - 10px) * -0.25))]
-PASS CSS Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0) should be [calc(50% - 25px)]
-PASS CSS Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.25) should be [calc(((50% - 25px) * 0.75) + ((100% - 10px) * 0.25))]
-PASS CSS Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.5) should be [calc(((50% - 25px) * 0.5) + ((100% - 10px) * 0.5))]
-PASS CSS Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.75) should be [calc(((50% - 25px) * 0.25) + ((100% - 10px) * 0.75))]
-PASS CSS Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1) should be [calc(100% - 10px)]
-PASS CSS Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1.25) should be [calc(((50% - 25px) * -0.25) + ((100% - 10px) * 1.25))]
-PASS Web Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (-0.25) should be [calc(((50% - 25px) * 1.25) + ((100% - 10px) * -0.25))]
-PASS Web Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0) should be [calc(50% - 25px)]
-PASS Web Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.25) should be [calc(((50% - 25px) * 0.75) + ((100% - 10px) * 0.25))]
-PASS Web Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.5) should be [calc(((50% - 25px) * 0.5) + ((100% - 10px) * 0.5))]
-PASS Web Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (0.75) should be [calc(((50% - 25px) * 0.25) + ((100% - 10px) * 0.75))]
-PASS Web Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1) should be [calc(100% - 10px)]
-PASS Web Animations: property <text-indent> from [calc(50% - 25px)] to [calc(100% - 10px)] at (1.25) should be [calc(((50% - 25px) * -0.25) + ((100% - 10px) * 1.25))]
-PASS CSS Transitions: property <text-indent> from [0em] to [100px] at (-0.25) should be [-25px]
-PASS CSS Transitions: property <text-indent> from [0em] to [100px] at (0) should be [0em]
-PASS CSS Transitions: property <text-indent> from [0em] to [100px] at (0.25) should be [25px]
-PASS CSS Transitions: property <text-indent> from [0em] to [100px] at (0.5) should be [50px]
-PASS CSS Transitions: property <text-indent> from [0em] to [100px] at (0.75) should be [75px]
-PASS CSS Transitions: property <text-indent> from [0em] to [100px] at (1) should be [100px]
-PASS CSS Transitions: property <text-indent> from [0em] to [100px] at (1.25) should be [125px]
-PASS CSS Transitions with transition: all: property <text-indent> from [0em] to [100px] at (-0.25) should be [-25px]
-PASS CSS Transitions with transition: all: property <text-indent> from [0em] to [100px] at (0) should be [0em]
-PASS CSS Transitions with transition: all: property <text-indent> from [0em] to [100px] at (0.25) should be [25px]
-PASS CSS Transitions with transition: all: property <text-indent> from [0em] to [100px] at (0.5) should be [50px]
-PASS CSS Transitions with transition: all: property <text-indent> from [0em] to [100px] at (0.75) should be [75px]
-PASS CSS Transitions with transition: all: property <text-indent> from [0em] to [100px] at (1) should be [100px]
-PASS CSS Transitions with transition: all: property <text-indent> from [0em] to [100px] at (1.25) should be [125px]
-PASS CSS Animations: property <text-indent> from [0em] to [100px] at (-0.25) should be [-25px]
-PASS CSS Animations: property <text-indent> from [0em] to [100px] at (0) should be [0em]
-PASS CSS Animations: property <text-indent> from [0em] to [100px] at (0.25) should be [25px]
-PASS CSS Animations: property <text-indent> from [0em] to [100px] at (0.5) should be [50px]
-PASS CSS Animations: property <text-indent> from [0em] to [100px] at (0.75) should be [75px]
-PASS CSS Animations: property <text-indent> from [0em] to [100px] at (1) should be [100px]
-PASS CSS Animations: property <text-indent> from [0em] to [100px] at (1.25) should be [125px]
-PASS Web Animations: property <text-indent> from [0em] to [100px] at (-0.25) should be [-25px]
-PASS Web Animations: property <text-indent> from [0em] to [100px] at (0) should be [0em]
-PASS Web Animations: property <text-indent> from [0em] to [100px] at (0.25) should be [25px]
-PASS Web Animations: property <text-indent> from [0em] to [100px] at (0.5) should be [50px]
-PASS Web Animations: property <text-indent> from [0em] to [100px] at (0.75) should be [75px]
-PASS Web Animations: property <text-indent> from [0em] to [100px] at (1) should be [100px]
-PASS Web Animations: property <text-indent> from [0em] to [100px] at (1.25) should be [125px]
-PASS CSS Transitions: property <text-indent> from [0%] to [100px] at (-0.25) should be [calc(0% + -25px)]
-PASS CSS Transitions: property <text-indent> from [0%] to [100px] at (0) should be [0%]
-PASS CSS Transitions: property <text-indent> from [0%] to [100px] at (0.25) should be [calc(0% + 25px)]
-PASS CSS Transitions: property <text-indent> from [0%] to [100px] at (0.5) should be [calc(0% + 50px)]
-PASS CSS Transitions: property <text-indent> from [0%] to [100px] at (0.75) should be [calc(0% + 75px)]
-PASS CSS Transitions: property <text-indent> from [0%] to [100px] at (1) should be [calc(0% + 100px)]
-PASS CSS Transitions: property <text-indent> from [0%] to [100px] at (1.25) should be [calc(0% + 125px)]
-PASS CSS Transitions with transition: all: property <text-indent> from [0%] to [100px] at (-0.25) should be [calc(0% + -25px)]
-PASS CSS Transitions with transition: all: property <text-indent> from [0%] to [100px] at (0) should be [0%]
-PASS CSS Transitions with transition: all: property <text-indent> from [0%] to [100px] at (0.25) should be [calc(0% + 25px)]
-PASS CSS Transitions with transition: all: property <text-indent> from [0%] to [100px] at (0.5) should be [calc(0% + 50px)]
-PASS CSS Transitions with transition: all: property <text-indent> from [0%] to [100px] at (0.75) should be [calc(0% + 75px)]
-PASS CSS Transitions with transition: all: property <text-indent> from [0%] to [100px] at (1) should be [calc(0% + 100px)]
-PASS CSS Transitions with transition: all: property <text-indent> from [0%] to [100px] at (1.25) should be [calc(0% + 125px)]
-PASS CSS Animations: property <text-indent> from [0%] to [100px] at (-0.25) should be [calc(0% + -25px)]
-PASS CSS Animations: property <text-indent> from [0%] to [100px] at (0) should be [0%]
-PASS CSS Animations: property <text-indent> from [0%] to [100px] at (0.25) should be [calc(0% + 25px)]
-PASS CSS Animations: property <text-indent> from [0%] to [100px] at (0.5) should be [calc(0% + 50px)]
-PASS CSS Animations: property <text-indent> from [0%] to [100px] at (0.75) should be [calc(0% + 75px)]
-PASS CSS Animations: property <text-indent> from [0%] to [100px] at (1) should be [calc(0% + 100px)]
-PASS CSS Animations: property <text-indent> from [0%] to [100px] at (1.25) should be [calc(0% + 125px)]
-PASS Web Animations: property <text-indent> from [0%] to [100px] at (-0.25) should be [calc(0% + -25px)]
-PASS Web Animations: property <text-indent> from [0%] to [100px] at (0) should be [0%]
-PASS Web Animations: property <text-indent> from [0%] to [100px] at (0.25) should be [calc(0% + 25px)]
-PASS Web Animations: property <text-indent> from [0%] to [100px] at (0.5) should be [calc(0% + 50px)]
-PASS Web Animations: property <text-indent> from [0%] to [100px] at (0.75) should be [calc(0% + 75px)]
-PASS Web Animations: property <text-indent> from [0%] to [100px] at (1) should be [calc(0% + 100px)]
-PASS Web Animations: property <text-indent> from [0%] to [100px] at (1.25) should be [calc(0% + 125px)]
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-catch-divide-by-0-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-catch-divide-by-0-expected.txt
deleted file mode 100644
index 90ae123b..0000000
--- a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-catch-divide-by-0-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-This is a testharness.js-based test.
-FAIL 'calc(100px * 0 / 0)' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(100px * 0 / 0)' should be valid in width. got disallowed value ""
-FAIL 'calc(100px / 0)' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(100px / 0)' should be valid in width. got disallowed value ""
-FAIL 'calc(100px / (0))' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(100px / (0))' should be valid in width. got disallowed value ""
-FAIL 'calc(100px / (2 - 2))' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(100px / (2 - 2))' should be valid in width. got disallowed value ""
-FAIL 'calc(100px / (2 - (-62 + 64)))' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(100px / (2 - (-62 + 64)))' should be valid in width. got disallowed value ""
-FAIL 'calc(100px * (1 / 0))' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(100px * (1 / 0))' should be valid in width. got disallowed value ""
-FAIL 'calc(100px * (1 / (0)))' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(100px * (1 / (0)))' should be valid in width. got disallowed value ""
-FAIL 'calc(100px * (1 / (2 - 2)))' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(100px * (1 / (2 - 2)))' should be valid in width. got disallowed value ""
-FAIL 'calc(100px * (1 / (2 - (-62 + 64))))' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(100px * (1 / (2 - (-62 + 64))))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * max(1/0, 0))' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(1px * max(1/0, 0))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * min(1/0, 0))' as a specified value should serialize as 'calc(0px)'. assert_not_equals: 'calc(1px * min(1/0, 0))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * max(0/0, 0))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * max(0/0, 0))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * min(0/0, 0))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * min(0/0, 0))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * max(0/0, min(0,10)))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * max(0/0, min(0,10)))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * clamp(0/0, 0, 10))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * clamp(0/0, 0, 10))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * max(0, min(10, 0/0)))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * max(0, min(10, 0/0)))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * clamp(0, 10, 0/0))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * clamp(0, 10, 0/0))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * max(0, min(0/0, 10)))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * max(0, min(0/0, 10)))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * clamp(0, 0/0, 10))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * clamp(0, 0/0, 10))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * clamp(-1/0, 0, 1/0))' as a specified value should serialize as 'calc(0px)'. assert_not_equals: 'calc(1px * clamp(-1/0, 0, 1/0))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * clamp(-1/0, 1/0, 10))' as a specified value should serialize as 'calc(10px)'. assert_not_equals: 'calc(1px * clamp(-1/0, 1/0, 10))' should be valid in width. got disallowed value ""
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-computed-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-computed-expected.txt
deleted file mode 100644
index 80962bd..0000000
--- a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-computed-expected.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-This is a testharness.js-based test.
-FAIL Property width value 'calc(NaN * 1px)' assert_true: 'calc(NaN * 1px)' is a supported value for width. expected true got false
-FAIL Property width value 'calc(infinity * 1px)' assert_true: 'calc(infinity * 1px)' is a supported value for width. expected true got false
-FAIL Property width value 'calc(infinity * 1cm)' assert_true: 'calc(infinity * 1cm)' is a supported value for width. expected true got false
-FAIL Property width value 'calc(NaN * 1rem)' assert_true: 'calc(NaN * 1rem)' is a supported value for width. expected true got false
-FAIL Property width value 'calc(10.135262721212548pc - 199pt / NaN)' assert_true: 'calc(10.135262721212548pc - 199pt / NaN)' is a supported value for width. expected true got false
-FAIL Property width value 'max(15px, NaN * 1px)' assert_true: 'max(15px, NaN * 1px)' is a supported value for width. expected true got false
-FAIL Property width value 'max(NaN * 1px, 15px)' assert_true: 'max(NaN * 1px, 15px)' is a supported value for width. expected true got false
-FAIL Property width value 'min(15px, NaN * 1px)' assert_true: 'min(15px, NaN * 1px)' is a supported value for width. expected true got false
-FAIL Property width value 'min(NaN * 1px, 15px)' assert_true: 'min(NaN * 1px, 15px)' is a supported value for width. expected true got false
-FAIL Property width value 'calc(infinity * 1px - infinity * 1%)' assert_true: 'calc(infinity * 1px - infinity * 1%)' is a supported value for width. expected true got false
-FAIL Property width value 'calc(infinity * 1px + infinity * 1%)' assert_true: 'calc(infinity * 1px + infinity * 1%)' is a supported value for width. expected true got false
-FAIL Property width value 'calc(min(NaN * 1px, infinity * 1px) + max(infinity * 1px, -infinity * 1px))' assert_true: 'calc(min(NaN * 1px, infinity * 1px) + max(infinity * 1px, -infinity * 1px))' is a supported value for width. expected true got false
-FAIL Property width value 'calc(infinity * 1px - max(infinity * 1%, 0%))' assert_true: 'calc(infinity * 1px - max(infinity * 1%, 0%))' is a supported value for width. expected true got false
-FAIL Property width value 'calc(max(infinity * 1px, 10px))' assert_true: 'calc(max(infinity * 1px, 10px))' is a supported value for width. expected true got false
-FAIL Property margin-left value 'calc(-infinity * 1px)' assert_true: 'calc(-infinity * 1px)' is a supported value for margin-left. expected true got false
-FAIL Property margin-left value 'calc(min(1px, -infinity * 1%))' assert_true: 'calc(min(1px, -infinity * 1%))' is a supported value for margin-left. expected true got false
-FAIL Property margin-left value 'calc(-infinity * 1%)' assert_true: 'calc(-infinity * 1%)' is a supported value for margin-left. expected true got false
-FAIL Property margin-left value 'calc(max(10000px, 0px) + min(-infinity * 1px, infinity * 1px))' assert_true: 'calc(max(10000px, 0px) + min(-infinity * 1px, infinity * 1px))' is a supported value for margin-left. expected true got false
-FAIL Property margin-left value 'calc(-infinity * 1px - infinity * 1px)' assert_true: 'calc(-infinity * 1px - infinity * 1px)' is a supported value for margin-left. expected true got false
-FAIL Property margin-left value 'calc(min(-infinity * 1px, 10px))' assert_true: 'calc(min(-infinity * 1px, 10px))' is a supported value for margin-left. expected true got false
-FAIL Property animation-duration value 'calc(NaN * 1s)' assert_true: 'calc(NaN * 1s)' is a supported value for animation-duration. expected true got false
-FAIL Property animation-duration value 'calc(infinity * 1s)' assert_true: 'calc(infinity * 1s)' is a supported value for animation-duration. expected true got false
-FAIL Property animation-duration value 'calc(1 / 0 * 1s)' assert_true: 'calc(1 / 0 * 1s)' is a supported value for animation-duration. expected true got false
-FAIL Property animation-duration value 'calc(max(infinity * 1s, 10s)' assert_true: 'calc(max(infinity * 1s, 10s)' is a supported value for animation-duration. expected true got false
-FAIL Property transition-delay value 'calc(-infinity* 1s)' assert_true: 'calc(-infinity* 1s)' is a supported value for transition-delay. expected true got false
-FAIL Property transition-delay value 'calc(max(10000s, 0s) + min(-infinity * 1s, infinity * 1s))' assert_true: 'calc(max(10000s, 0s) + min(-infinity * 1s, infinity * 1s))' is a supported value for transition-delay. expected true got false
-FAIL Property transition-delay value 'calc(min(-infinity * 1s, 10s))' assert_true: 'calc(min(-infinity * 1s, 10s))' is a supported value for transition-delay. expected true got false
-FAIL Property rotate(calc(infinity * 1deg)) value expected same with rotate(0deg) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(-infinity * 1deg)) value expected same with rotate(0deg) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(NaN * 1deg)) value expected same with rotate(0deg) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(infinity * 1turn)) value expected same with rotate(0turn) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(-infinity * 1turn)) value expected same with rotate(0turn) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(NaN * 1turn)) value expected same with rotate(0turn) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(infinity * 1rad)) value expected same with rotate(0rad) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(-infinity * 1rad)) value expected same with rotate(0rad) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(NaN * 1rad)) value expected same with rotate(0rad) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(infinity * 1grad)) value expected same with rotate(0grad) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(-infinity * 1grad)) value expected same with rotate(0grad) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-FAIL Property rotate(calc(NaN * 1grad)) value expected same with rotate(0grad) in +/-0.0001 assert_array_approx_equals: property 0, expected 1 +/- 0.0001, expected 1 but got NaN
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-serialize-angle-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-serialize-angle-expected.txt
deleted file mode 100644
index 1325e47..0000000
--- a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-serialize-angle-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-This is a testharness.js-based test.
-FAIL 'rotate(calc(1deg * NaN))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * NaN))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1rad * NaN))' as a specified value should serialize as 'rotate(calc(NaN * 1rad))'. assert_not_equals: 'rotate(calc(1rad * NaN))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1turn * NaN))' as a specified value should serialize as 'rotate(calc(NaN * 1turn))'. assert_not_equals: 'rotate(calc(1turn * NaN))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1grad * nan))' as a specified value should serialize as 'rotate(calc(NaN * 1grad))'. assert_not_equals: 'rotate(calc(1grad * nan))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * infinity / infinity))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * infinity / infinity))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * 0 * infinity))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * 0 * infinity))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * (infinity + -infinity)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * (infinity + -infinity)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * (-infinity + infinity)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * (-infinity + infinity)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * (infinity - infinity)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * (infinity - infinity)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * infinity))' as a specified value should serialize as 'rotate(calc(infinity * 1deg))'. assert_not_equals: 'rotate(calc(1deg * infinity))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * -infinity))' as a specified value should serialize as 'rotate(calc(-infinity * 1deg))'. assert_not_equals: 'rotate(calc(1deg * -infinity))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * iNFinIty))' as a specified value should serialize as 'rotate(calc(infinity * 1deg))'. assert_not_equals: 'rotate(calc(1deg * iNFinIty))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * (infinity + infinity)))' as a specified value should serialize as 'rotate(calc(infinity * 1deg))'. assert_not_equals: 'rotate(calc(1deg * (infinity + infinity)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * (-infinity + -infinity)))' as a specified value should serialize as 'rotate(calc(-infinity * 1deg))'. assert_not_equals: 'rotate(calc(1deg * (-infinity + -infinity)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * 1/infinity))' as a specified value should serialize as 'rotate(calc(0deg))'. assert_not_equals: 'rotate(calc(1deg * 1/infinity))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * infinity * infinity))' as a specified value should serialize as 'rotate(calc(infinity * 1deg))'. assert_not_equals: 'rotate(calc(1deg * infinity * infinity))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * -infinity * -infinity))' as a specified value should serialize as 'rotate(calc(infinity * 1deg))'. assert_not_equals: 'rotate(calc(1deg * -infinity * -infinity))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1 * max(INFinity*3deg, 0deg)))' as a specified value should serialize as 'rotate(calc(infinity * 1deg))'. assert_not_equals: 'rotate(calc(1 * max(INFinity*3deg, 0deg)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1 * min(inFInity*4deg, 0deg)))' as a specified value should serialize as 'rotate(calc(0deg))'. assert_not_equals: 'rotate(calc(1 * min(inFInity*4deg, 0deg)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1 * max(nAn*2deg, 0deg)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1 * max(nAn*2deg, 0deg)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1 * min(nan*3deg, 0deg)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1 * min(nan*3deg, 0deg)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1 * clamp(-INFINITY*20deg, 0deg, infiniTY*10deg)))' as a specified value should serialize as 'rotate(calc(0deg))'. assert_not_equals: 'rotate(calc(1 * clamp(-INFINITY*20deg, 0deg, infiniTY*10deg)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * max(NaN, min(0,10))))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * max(NaN, min(0,10))))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * clamp(NaN, 0, 10)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * clamp(NaN, 0, 10)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * max(0, min(10, NaN))))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * max(0, min(10, NaN))))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * clamp(0, 10, NaN)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * clamp(0, 10, NaN)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * max(0, min(NaN, 10))))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * max(0, min(NaN, 10))))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * clamp(0, NaN, 10)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. assert_not_equals: 'rotate(calc(1deg * clamp(0, NaN, 10)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * clamp(-Infinity, 0, infinity)))' as a specified value should serialize as 'rotate(calc(0deg))'. assert_not_equals: 'rotate(calc(1deg * clamp(-Infinity, 0, infinity)))' should be valid in transform. got disallowed value ""
-FAIL 'rotate(calc(1deg * clamp(-inFinity, infinity, 10)))' as a specified value should serialize as 'rotate(calc(10deg))'. assert_not_equals: 'rotate(calc(1deg * clamp(-inFinity, infinity, 10)))' should be valid in transform. got disallowed value ""
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-serialize-length-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-serialize-length-expected.txt
deleted file mode 100644
index 648823e..0000000
--- a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-serialize-length-expected.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-This is a testharness.js-based test.
-FAIL 'calc(1px * NaN)' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * NaN)' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * nan)' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * nan)' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * infinity / infinity)' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * infinity / infinity)' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * 0 * infinity)' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * 0 * infinity)' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * (infinity + -infinity))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * (infinity + -infinity))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * (-infinity + infinity))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * (-infinity + infinity))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * (infinity - infinity))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * (infinity - infinity))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * infinity)' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(1px * infinity)' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * -infinity)' as a specified value should serialize as 'calc(-infinity * 1px)'. assert_not_equals: 'calc(1px * -infinity)' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * iNFinIty)' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(1px * iNFinIty)' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * (infinity + infinity))' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(1px * (infinity + infinity))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * (-infinity + -infinity))' as a specified value should serialize as 'calc(-infinity * 1px)'. assert_not_equals: 'calc(1px * (-infinity + -infinity))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * 1/infinity)' as a specified value should serialize as 'calc(0px)'. assert_not_equals: 'calc(1px * 1/infinity)' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * infinity * infinity)' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(1px * infinity * infinity)' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * -infinity * -infinity)' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(1px * -infinity * -infinity)' should be valid in width. got disallowed value ""
-FAIL 'calc(1 * max(INFinity*3px, 0px))' as a specified value should serialize as 'calc(infinity * 1px)'. assert_not_equals: 'calc(1 * max(INFinity*3px, 0px))' should be valid in width. got disallowed value ""
-FAIL 'calc(1 * min(inFInity*4px, 0px))' as a specified value should serialize as 'calc(0px)'. assert_not_equals: 'calc(1 * min(inFInity*4px, 0px))' should be valid in width. got disallowed value ""
-FAIL 'calc(1 * max(nAn*2px, 0px))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1 * max(nAn*2px, 0px))' should be valid in width. got disallowed value ""
-FAIL 'calc(1 * min(nan*3px, 0px))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1 * min(nan*3px, 0px))' should be valid in width. got disallowed value ""
-FAIL 'calc(1 * clamp(-INFINITY*20px, 0px, infiniTY*10px))' as a specified value should serialize as 'calc(0px)'. assert_not_equals: 'calc(1 * clamp(-INFINITY*20px, 0px, infiniTY*10px))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * max(NaN, min(0,10)))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * max(NaN, min(0,10)))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * clamp(NaN, 0, 10))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * clamp(NaN, 0, 10))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * max(0, min(10, NaN)))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * max(0, min(10, NaN)))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * clamp(0, 10, NaN))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * clamp(0, 10, NaN))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * max(0, min(NaN, 10)))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * max(0, min(NaN, 10)))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * clamp(0, NaN, 10))' as a specified value should serialize as 'calc(NaN * 1px)'. assert_not_equals: 'calc(1px * clamp(0, NaN, 10))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * clamp(-Infinity, 0, infinity))' as a specified value should serialize as 'calc(0px)'. assert_not_equals: 'calc(1px * clamp(-Infinity, 0, infinity))' should be valid in width. got disallowed value ""
-FAIL 'calc(1px * clamp(-inFinity, infinity, 10))' as a specified value should serialize as 'calc(10px)'. assert_not_equals: 'calc(1px * clamp(-inFinity, infinity, 10))' should be valid in width. got disallowed value ""
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-serialize-time-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-serialize-time-expected.txt
deleted file mode 100644
index c10236e..0000000
--- a/third_party/blink/web_tests/platform/generic/virtual/css-calc-infinity-and-nan-disabled/external/wpt/css/css-values/calc-infinity-nan-serialize-time-expected.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-This is a testharness.js-based test.
-FAIL 'calc(1s * NaN)' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * NaN)' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * nan)' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * nan)' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * infinity / infinity)' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * infinity / infinity)' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * 0 * infinity)' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * 0 * infinity)' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * (infinity + -infinity))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * (infinity + -infinity))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * (-infinity + infinity))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * (-infinity + infinity))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * (infinity - infinity))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * (infinity - infinity))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * infinity)' as a specified value should serialize as 'calc(infinity * 1s)'. assert_not_equals: 'calc(1s * infinity)' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * -infinity)' as a specified value should serialize as 'calc(-infinity * 1s)'. assert_not_equals: 'calc(1s * -infinity)' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * iNFinIty)' as a specified value should serialize as 'calc(infinity * 1s)'. assert_not_equals: 'calc(1s * iNFinIty)' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * (infinity + infinity))' as a specified value should serialize as 'calc(infinity * 1s)'. assert_not_equals: 'calc(1s * (infinity + infinity))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * (-infinity + -infinity))' as a specified value should serialize as 'calc(-infinity * 1s)'. assert_not_equals: 'calc(1s * (-infinity + -infinity))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * 1/infinity)' as a specified value should serialize as 'calc(0s)'. assert_not_equals: 'calc(1s * 1/infinity)' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * infinity * infinity)' as a specified value should serialize as 'calc(infinity * 1s)'. assert_not_equals: 'calc(1s * infinity * infinity)' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * -infinity * -infinity)' as a specified value should serialize as 'calc(infinity * 1s)'. assert_not_equals: 'calc(1s * -infinity * -infinity)' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1 * max(INFinity*3s, 0s))' as a specified value should serialize as 'calc(infinity * 1s)'. assert_not_equals: 'calc(1 * max(INFinity*3s, 0s))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1 * min(inFInity*4s, 0s))' as a specified value should serialize as 'calc(0s)'. assert_not_equals: 'calc(1 * min(inFInity*4s, 0s))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1 * max(nAn*2s, 0s))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1 * max(nAn*2s, 0s))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1 * min(nan*3s, 0s))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1 * min(nan*3s, 0s))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1 * clamp(-INFINITY*20s, 0s, infiniTY*10s))' as a specified value should serialize as 'calc(0s)'. assert_not_equals: 'calc(1 * clamp(-INFINITY*20s, 0s, infiniTY*10s))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * max(NaN, min(0,10)))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * max(NaN, min(0,10)))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * clamp(NaN, 0, 10))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * clamp(NaN, 0, 10))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * max(0, min(10, NaN)))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * max(0, min(10, NaN)))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * clamp(0, 10, NaN))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * clamp(0, 10, NaN))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * max(0, min(NaN, 10)))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * max(0, min(NaN, 10)))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * clamp(0, NaN, 10))' as a specified value should serialize as 'calc(NaN * 1s)'. assert_not_equals: 'calc(1s * clamp(0, NaN, 10))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * clamp(-Infinity, 0, infinity))' as a specified value should serialize as 'calc(0s)'. assert_not_equals: 'calc(1s * clamp(-Infinity, 0, infinity))' should be valid in animationDuration. got disallowed value ""
-FAIL 'calc(1s * clamp(-inFinity, infinity, 10))' as a specified value should serialize as 'calc(10s)'. assert_not_equals: 'calc(1s * clamp(-inFinity, infinity, 10))' should be valid in animationDuration. got disallowed value ""
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/virtual/css-calc-infinity-and-nan-disabled/README.md b/third_party/blink/web_tests/virtual/css-calc-infinity-and-nan-disabled/README.md
deleted file mode 100644
index 4437fc8d..0000000
--- a/third_party/blink/web_tests/virtual/css-calc-infinity-and-nan-disabled/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-This suite runs the tests with
---disable-blink-features=CSSCalcInfinityAndNaN
\ No newline at end of file
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js
index c12612e..c659a4c 100644
--- a/third_party/closure_compiler/externs/file_manager_private.js
+++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -311,6 +311,7 @@
   IN_PROGRESS: 'in_progress',
   SUCCESS: 'success',
   ERROR: 'error',
+  NEED_PASSWORD: 'need_password',
   CANCELLED: 'cancelled',
 };
 
@@ -684,6 +685,7 @@
 /**
  * @typedef {{
  *   destinationFolder: (DirectoryEntry|undefined),
+ *   password: (string|undefined),
  * }}
  */
 chrome.fileManagerPrivate.IOTaskParams;
diff --git a/third_party/mako/README.chromium b/third_party/mako/README.chromium
index 7e8337ba..307da9d 100644
--- a/third_party/mako/README.chromium
+++ b/third_party/mako/README.chromium
@@ -1,8 +1,8 @@
 Name: Mako Templates for Python
 Short Name: python-mako
 URL: https://www.makotemplates.org
-Version: 1.1.4
-Date: Junuary 15, 2021
+Version: 1.2.0
+Date: March 11, 2022
 License: MIT
 License File: NOT_SHIPPED
 Security Critical: no
@@ -10,12 +10,11 @@
 Description:
 Template engine in Python, used for code generation in Blink.
 
-Source: https://files.pythonhosted.org/packages/5c/db/2d2d88b924aa4674a080aae83b59ea19d593250bfe5ed789947c21736785/Mako-1.1.4.tar.gz
-SHA-512: 4844c1d6c8d0d474b4ca4e1b31d3557747fc7e30f70a1976163a26b46b1b45c4c96ca6101fbef252b4e3bb4a61635d2a2c6d1c2933fde5b82bb1a1306f31ff84
-SHA-256: 17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab
+Source: https://files.pythonhosted.org/packages/50/ec/1d687348f0954bda388bfd1330c158ba8d7dea4044fc160e74e080babdb9/Mako-1.2.0.tar.gz
+SHA-256: 9a7c7e922b87db3686210cf49d5d767033a41d4010b284e747682c92bddd8b39
 
 Local Modifications:
 * add DIR_METADATA, OWNERS, README.chromium, and .gitattributes files in this directory.
 * run following commands to pass PRESUBMIT.
-  $ rm -rf mako/doc/ mako/example/
+  $ rm -rf mako/doc/ mako/example/ mako/Mako.egg-info mako/PKG-INFO
   $ chmod -x mako/mako/cmd.py
diff --git a/third_party/mako/mako/LICENSE b/third_party/mako/mako/LICENSE
index 1f835e9..2342a9d3 100644
--- a/third_party/mako/mako/LICENSE
+++ b/third_party/mako/mako/LICENSE
@@ -1,4 +1,4 @@
-Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>.
+Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
diff --git a/third_party/mako/mako/MANIFEST.in b/third_party/mako/mako/MANIFEST.in
index 2a2dc6c..25324e3 100644
--- a/third_party/mako/mako/MANIFEST.in
+++ b/third_party/mako/mako/MANIFEST.in
@@ -1,6 +1,6 @@
 recursive-include doc *.html *.css *.txt *.js *.png *.py Makefile *.rst *.mako
 recursive-include examples *.py *.xml *.mako *.myt *.kid *.tmpl
-recursive-include test *.py *.html *.mako
+recursive-include test *.py *.html *.mako *.cfg
 
 include README* AUTHORS LICENSE CHANGES* tox.ini
 
diff --git a/third_party/mako/mako/Mako.egg-info/PKG-INFO b/third_party/mako/mako/Mako.egg-info/PKG-INFO
deleted file mode 100644
index f69071c..0000000
--- a/third_party/mako/mako/Mako.egg-info/PKG-INFO
+++ /dev/null
@@ -1,80 +0,0 @@
-Metadata-Version: 2.1
-Name: Mako
-Version: 1.1.4
-Summary: A super-fast templating language that borrows the  best ideas from the existing templating languages.
-Home-page: https://www.makotemplates.org/
-Author: Mike Bayer
-Author-email: mike@zzzcomputing.com
-License: MIT
-Project-URL: Documentation, https://docs.makotemplates.org
-Project-URL: Issue Tracker, https://github.com/sqlalchemy/mako
-Description: =========================
-        Mako Templates for Python
-        =========================
-        
-        Mako is a template library written in Python. It provides a familiar, non-XML 
-        syntax which compiles into Python modules for maximum performance. Mako's 
-        syntax and API borrows from the best ideas of many others, including Django
-        templates, Cheetah, Myghty, and Genshi. Conceptually, Mako is an embedded 
-        Python (i.e. Python Server Page) language, which refines the familiar ideas
-        of componentized layout and inheritance to produce one of the most 
-        straightforward and flexible models available, while also maintaining close 
-        ties to Python calling and scoping semantics.
-        
-        Nutshell
-        ========
-        
-        ::
-        
-            <%inherit file="base.html"/>
-            <%
-                rows = [[v for v in range(0,10)] for row in range(0,10)]
-            %>
-            <table>
-                % for row in rows:
-                    ${makerow(row)}
-                % endfor
-            </table>
-        
-            <%def name="makerow(row)">
-                <tr>
-                % for name in row:
-                    <td>${name}</td>\
-                % endfor
-                </tr>
-            </%def>
-        
-        Philosophy
-        ===========
-        
-        Python is a great scripting language. Don't reinvent the wheel...your templates can handle it !
-        
-        Documentation
-        ==============
-        
-        See documentation for Mako at https://docs.makotemplates.org/en/latest/
-        
-        License
-        ========
-        
-        Mako is licensed under an MIT-style license (see LICENSE).
-        Other incorporated projects may be licensed under different licenses.
-        All licenses allow for non-commercial and commercial use.
-        
-Keywords: templates
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Environment :: Web Environment
-Classifier: Intended Audience :: Developers
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
-Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
-Provides-Extra: babel
-Provides-Extra: lingua
diff --git a/third_party/mako/mako/Mako.egg-info/SOURCES.txt b/third_party/mako/mako/Mako.egg-info/SOURCES.txt
deleted file mode 100644
index f8d4f9ec5..0000000
--- a/third_party/mako/mako/Mako.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,161 +0,0 @@
-AUTHORS
-CHANGES
-LICENSE
-MANIFEST.in
-README.rst
-setup.cfg
-setup.py
-tox.ini
-Mako.egg-info/PKG-INFO
-Mako.egg-info/SOURCES.txt
-Mako.egg-info/dependency_links.txt
-Mako.egg-info/entry_points.txt
-Mako.egg-info/not-zip-safe
-Mako.egg-info/requires.txt
-Mako.egg-info/top_level.txt
-doc/caching.html
-doc/changelog.html
-doc/defs.html
-doc/filtering.html
-doc/genindex.html
-doc/index.html
-doc/inheritance.html
-doc/namespaces.html
-doc/runtime.html
-doc/search.html
-doc/searchindex.js
-doc/syntax.html
-doc/unicode.html
-doc/usage.html
-doc/_static/basic.css
-doc/_static/changelog.css
-doc/_static/docs.css
-doc/_static/doctools.js
-doc/_static/documentation_options.js
-doc/_static/file.png
-doc/_static/jquery-3.5.1.js
-doc/_static/jquery.js
-doc/_static/language_data.js
-doc/_static/minus.png
-doc/_static/plus.png
-doc/_static/pygments.css
-doc/_static/searchtools.js
-doc/_static/sphinx_paramlinks.css
-doc/_static/underscore-1.3.1.js
-doc/_static/underscore.js
-doc/build/Makefile
-doc/build/caching.rst
-doc/build/changelog.rst
-doc/build/conf.py
-doc/build/defs.rst
-doc/build/filtering.rst
-doc/build/index.rst
-doc/build/inheritance.rst
-doc/build/namespaces.rst
-doc/build/requirements.txt
-doc/build/runtime.rst
-doc/build/syntax.rst
-doc/build/unicode.rst
-doc/build/usage.rst
-doc/build/unreleased/README.txt
-examples/bench/basic.py
-examples/bench/cheetah/footer.tmpl
-examples/bench/cheetah/header.tmpl
-examples/bench/cheetah/template.tmpl
-examples/bench/django/templatetags/__init__.py
-examples/bench/django/templatetags/bench.py
-examples/bench/kid/base.kid
-examples/bench/kid/template.kid
-examples/bench/myghty/base.myt
-examples/bench/myghty/template.myt
-examples/wsgi/run_wsgi.py
-mako/__init__.py
-mako/_ast_util.py
-mako/ast.py
-mako/cache.py
-mako/cmd.py
-mako/codegen.py
-mako/compat.py
-mako/exceptions.py
-mako/filters.py
-mako/lexer.py
-mako/lookup.py
-mako/parsetree.py
-mako/pygen.py
-mako/pyparser.py
-mako/runtime.py
-mako/template.py
-mako/util.py
-mako/ext/__init__.py
-mako/ext/autohandler.py
-mako/ext/babelplugin.py
-mako/ext/beaker_cache.py
-mako/ext/extract.py
-mako/ext/linguaplugin.py
-mako/ext/preprocessors.py
-mako/ext/pygmentplugin.py
-mako/ext/turbogears.py
-test/__init__.py
-test/sample_module_namespace.py
-test/test_ast.py
-test/test_block.py
-test/test_cache.py
-test/test_call.py
-test/test_cmd.py
-test/test_decorators.py
-test/test_def.py
-test/test_exceptions.py
-test/test_filters.py
-test/test_inheritance.py
-test/test_lexer.py
-test/test_lookup.py
-test/test_loop.py
-test/test_lru.py
-test/test_namespace.py
-test/test_pygen.py
-test/test_runtime.py
-test/test_template.py
-test/test_tgplugin.py
-test/test_util.py
-test/util.py
-test/ext/__init__.py
-test/ext/test_babelplugin.py
-test/ext/test_linguaplugin.py
-test/foo/__init__.py
-test/foo/mod_no_encoding.py
-test/foo/test_ns.py
-test/templates/badbom.html
-test/templates/bom.html
-test/templates/bommagic.html
-test/templates/chs_unicode.html
-test/templates/chs_unicode_py3k.html
-test/templates/chs_utf8.html
-test/templates/cmd_good.mako
-test/templates/cmd_runtime.mako
-test/templates/cmd_syntax.mako
-test/templates/crlf.html
-test/templates/gettext.mako
-test/templates/gettext_cp1251.mako
-test/templates/gettext_utf8.mako
-test/templates/index.html
-test/templates/internationalization.html
-test/templates/modtest.html
-test/templates/read_unicode.html
-test/templates/read_unicode_py3k.html
-test/templates/runtimeerr.html
-test/templates/runtimeerr_py3k.html
-test/templates/unicode.html
-test/templates/unicode_arguments.html
-test/templates/unicode_arguments_py3k.html
-test/templates/unicode_code.html
-test/templates/unicode_code_py3k.html
-test/templates/unicode_expr.html
-test/templates/unicode_expr_py3k.html
-test/templates/unicode_runtime_error.html
-test/templates/unicode_syntax_error.html
-test/templates/foo/modtest.html.py
-test/templates/othersubdir/foo.html
-test/templates/subdir/incl.html
-test/templates/subdir/index.html
-test/templates/subdir/modtest.html
-test/templates/subdir/foo/modtest.html.py
\ No newline at end of file
diff --git a/third_party/mako/mako/Mako.egg-info/dependency_links.txt b/third_party/mako/mako/Mako.egg-info/dependency_links.txt
deleted file mode 100644
index 8b13789..0000000
--- a/third_party/mako/mako/Mako.egg-info/dependency_links.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/third_party/mako/mako/Mako.egg-info/entry_points.txt b/third_party/mako/mako/Mako.egg-info/entry_points.txt
deleted file mode 100644
index 8e033c00..0000000
--- a/third_party/mako/mako/Mako.egg-info/entry_points.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-
-      [python.templating.engines]
-      mako = mako.ext.turbogears:TGPlugin
-
-      [pygments.lexers]
-      mako = mako.ext.pygmentplugin:MakoLexer
-      html+mako = mako.ext.pygmentplugin:MakoHtmlLexer
-      xml+mako = mako.ext.pygmentplugin:MakoXmlLexer
-      js+mako = mako.ext.pygmentplugin:MakoJavascriptLexer
-      css+mako = mako.ext.pygmentplugin:MakoCssLexer
-
-      [babel.extractors]
-      mako = mako.ext.babelplugin:extract [babel]
-
-      [lingua.extractors]
-      mako = mako.ext.linguaplugin:LinguaMakoExtractor [lingua]
-
-      [console_scripts]
-      mako-render = mako.cmd:cmdline
-      
\ No newline at end of file
diff --git a/third_party/mako/mako/Mako.egg-info/not-zip-safe b/third_party/mako/mako/Mako.egg-info/not-zip-safe
deleted file mode 100644
index 8b13789..0000000
--- a/third_party/mako/mako/Mako.egg-info/not-zip-safe
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/third_party/mako/mako/Mako.egg-info/requires.txt b/third_party/mako/mako/Mako.egg-info/requires.txt
deleted file mode 100644
index 191643fa..0000000
--- a/third_party/mako/mako/Mako.egg-info/requires.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-MarkupSafe>=0.9.2
-
-[babel]
-Babel
-
-[lingua]
-lingua
diff --git a/third_party/mako/mako/Mako.egg-info/top_level.txt b/third_party/mako/mako/Mako.egg-info/top_level.txt
deleted file mode 100644
index 2951cdd..0000000
--- a/third_party/mako/mako/Mako.egg-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-mako
diff --git a/third_party/mako/mako/PKG-INFO b/third_party/mako/mako/PKG-INFO
deleted file mode 100644
index f69071c..0000000
--- a/third_party/mako/mako/PKG-INFO
+++ /dev/null
@@ -1,80 +0,0 @@
-Metadata-Version: 2.1
-Name: Mako
-Version: 1.1.4
-Summary: A super-fast templating language that borrows the  best ideas from the existing templating languages.
-Home-page: https://www.makotemplates.org/
-Author: Mike Bayer
-Author-email: mike@zzzcomputing.com
-License: MIT
-Project-URL: Documentation, https://docs.makotemplates.org
-Project-URL: Issue Tracker, https://github.com/sqlalchemy/mako
-Description: =========================
-        Mako Templates for Python
-        =========================
-        
-        Mako is a template library written in Python. It provides a familiar, non-XML 
-        syntax which compiles into Python modules for maximum performance. Mako's 
-        syntax and API borrows from the best ideas of many others, including Django
-        templates, Cheetah, Myghty, and Genshi. Conceptually, Mako is an embedded 
-        Python (i.e. Python Server Page) language, which refines the familiar ideas
-        of componentized layout and inheritance to produce one of the most 
-        straightforward and flexible models available, while also maintaining close 
-        ties to Python calling and scoping semantics.
-        
-        Nutshell
-        ========
-        
-        ::
-        
-            <%inherit file="base.html"/>
-            <%
-                rows = [[v for v in range(0,10)] for row in range(0,10)]
-            %>
-            <table>
-                % for row in rows:
-                    ${makerow(row)}
-                % endfor
-            </table>
-        
-            <%def name="makerow(row)">
-                <tr>
-                % for name in row:
-                    <td>${name}</td>\
-                % endfor
-                </tr>
-            </%def>
-        
-        Philosophy
-        ===========
-        
-        Python is a great scripting language. Don't reinvent the wheel...your templates can handle it !
-        
-        Documentation
-        ==============
-        
-        See documentation for Mako at https://docs.makotemplates.org/en/latest/
-        
-        License
-        ========
-        
-        Mako is licensed under an MIT-style license (see LICENSE).
-        Other incorporated projects may be licensed under different licenses.
-        All licenses allow for non-commercial and commercial use.
-        
-Keywords: templates
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Environment :: Web Environment
-Classifier: Intended Audience :: Developers
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
-Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
-Provides-Extra: babel
-Provides-Extra: lingua
diff --git a/third_party/mako/mako/mako/__init__.py b/third_party/mako/mako/mako/__init__.py
index bd1a1c9..5ae55011 100644
--- a/third_party/mako/mako/mako/__init__.py
+++ b/third_party/mako/mako/mako/__init__.py
@@ -1,8 +1,8 @@
 # mako/__init__.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 
-__version__ = '1.1.4'
+__version__ = "1.2.0"
diff --git a/third_party/mako/mako/mako/_ast_util.py b/third_party/mako/mako/mako/_ast_util.py
index bdcdbf6..b861533 100644
--- a/third_party/mako/mako/mako/_ast_util.py
+++ b/third_party/mako/mako/mako/_ast_util.py
@@ -1,5 +1,5 @@
 # mako/_ast_util.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -47,7 +47,6 @@
 from _ast import UAdd
 from _ast import USub
 
-from mako.compat import arg_stringname
 
 BOOLOP_SYMBOLS = {And: "and", Or: "or"}
 
@@ -94,9 +93,7 @@
 
 def iter_fields(node):
     """Iterate over all fields of a node, only yielding existing fields."""
-    # CPython 2.5 compat
-    if not hasattr(node, "_fields") or not node._fields:
-        return
+
     for field in node._fields:
         try:
             yield field, getattr(node, field)
@@ -104,7 +101,7 @@
             pass
 
 
-class NodeVisitor(object):
+class NodeVisitor:
 
     """
     Walks the abstract syntax tree and call visitor functions for every node
@@ -266,10 +263,10 @@
                 self.visit(default)
         if node.vararg is not None:
             write_comma()
-            self.write("*" + arg_stringname(node.vararg))
+            self.write("*" + node.vararg.arg)
         if node.kwarg is not None:
             write_comma()
-            self.write("**" + arg_stringname(node.kwarg))
+            self.write("**" + node.kwarg.arg)
 
     def decorators(self, node):
         for decorator in node.decorator_list:
diff --git a/third_party/mako/mako/mako/ast.py b/third_party/mako/mako/mako/ast.py
index cfae280..f879e8b 100644
--- a/third_party/mako/mako/mako/ast.py
+++ b/third_party/mako/mako/mako/ast.py
@@ -1,5 +1,5 @@
 # mako/ast.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -9,12 +9,11 @@
 
 import re
 
-from mako import compat
 from mako import exceptions
 from mako import pyparser
 
 
-class PythonCode(object):
+class PythonCode:
 
     """represents information about a string containing Python code"""
 
@@ -39,7 +38,7 @@
         # - AST is less likely to break with version changes
         # (for example, the behavior of co_names changed a little bit
         # in python version 2.5)
-        if isinstance(code, compat.string_types):
+        if isinstance(code, str):
             expr = pyparser.parse(code.lstrip(), "exec", **exception_kwargs)
         else:
             expr = code
@@ -48,7 +47,7 @@
         f.visit(expr)
 
 
-class ArgumentList(object):
+class ArgumentList:
 
     """parses a fragment of code as a comma-separated list of expressions"""
 
@@ -57,7 +56,7 @@
         self.args = []
         self.declared_identifiers = set()
         self.undeclared_identifiers = set()
-        if isinstance(code, compat.string_types):
+        if isinstance(code, str):
             if re.match(r"\S", code) and not re.match(r",\s*$", code):
                 # if theres text and no trailing comma, insure its parsed
                 # as a tuple by adding a trailing comma
@@ -88,7 +87,7 @@
         if not m:
             raise exceptions.CompileException(
                 "Fragment '%s' is not a partial control statement" % code,
-                **exception_kwargs
+                **exception_kwargs,
             )
         if m.group(3):
             code = code[: m.start(3)]
@@ -97,7 +96,7 @@
             code = code + "pass"
         elif keyword == "try":
             code = code + "pass\nexcept:pass"
-        elif keyword == "elif" or keyword == "else":
+        elif keyword in ["elif", "else"]:
             code = "if False:pass\n" + code + "pass"
         elif keyword == "except":
             code = "try:pass\n" + code + "pass"
@@ -106,12 +105,12 @@
         else:
             raise exceptions.CompileException(
                 "Unsupported control keyword: '%s'" % keyword,
-                **exception_kwargs
+                **exception_kwargs,
             )
-        super(PythonFragment, self).__init__(code, **exception_kwargs)
+        super().__init__(code, **exception_kwargs)
 
 
-class FunctionDecl(object):
+class FunctionDecl:
 
     """function declaration"""
 
@@ -124,13 +123,13 @@
         if not hasattr(self, "funcname"):
             raise exceptions.CompileException(
                 "Code '%s' is not a function declaration" % code,
-                **exception_kwargs
+                **exception_kwargs,
             )
         if not allow_kwargs and self.kwargs:
             raise exceptions.CompileException(
                 "'**%s' keyword argument not allowed here"
                 % self.kwargnames[-1],
-                **exception_kwargs
+                **exception_kwargs,
             )
 
     def get_argument_expressions(self, as_call=False):
@@ -200,6 +199,4 @@
     """the argument portion of a function declaration"""
 
     def __init__(self, code, **kwargs):
-        super(FunctionArgs, self).__init__(
-            "def ANON(%s):pass" % code, **kwargs
-        )
+        super().__init__("def ANON(%s):pass" % code, **kwargs)
diff --git a/third_party/mako/mako/mako/cache.py b/third_party/mako/mako/mako/cache.py
index 26aa93e..d77be27 100644
--- a/third_party/mako/mako/mako/cache.py
+++ b/third_party/mako/mako/mako/cache.py
@@ -1,10 +1,9 @@
 # mako/cache.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-from mako import compat
 from mako import util
 
 _cache_plugins = util.PluginLoader("mako.cache")
@@ -13,7 +12,7 @@
 register_plugin("beaker", "mako.ext.beaker_cache", "BeakerCacheImpl")
 
 
-class Cache(object):
+class Cache:
 
     """Represents a data content cache made available to the module
     space of a specific :class:`.Template` object.
@@ -66,7 +65,7 @@
     def __init__(self, template, *args):
         # check for a stale template calling the
         # constructor
-        if isinstance(template, compat.string_types) and args:
+        if isinstance(template, str) and args:
             return
         self.template = template
         self.id = template.module.__name__
@@ -181,7 +180,7 @@
         return tmpl_kw
 
 
-class CacheImpl(object):
+class CacheImpl:
 
     """Provide a cache implementation for use by :class:`.Cache`."""
 
diff --git a/third_party/mako/mako/mako/cmd.py b/third_party/mako/mako/mako/cmd.py
index c0f2c75..7592fb27 100644
--- a/third_party/mako/mako/mako/cmd.py
+++ b/third_party/mako/mako/mako/cmd.py
@@ -1,10 +1,9 @@
 # mako/cmd.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 from argparse import ArgumentParser
-import io
 from os.path import dirname
 from os.path import isfile
 import sys
@@ -85,16 +84,14 @@
         except:
             _exit()
 
-    kw = dict([varsplit(var) for var in options.var])
+    kw = dict(varsplit(var) for var in options.var)
     try:
         rendered = template.render(**kw)
     except:
         _exit()
     else:
         if output_file:
-            io.open(output_file, "wt", encoding=output_encoding).write(
-                rendered
-            )
+            open(output_file, "wt", encoding=output_encoding).write(rendered)
         else:
             sys.stdout.write(rendered)
 
diff --git a/third_party/mako/mako/mako/codegen.py b/third_party/mako/mako/mako/codegen.py
index a9ae55b..c897f0f 100644
--- a/third_party/mako/mako/mako/codegen.py
+++ b/third_party/mako/mako/mako/codegen.py
@@ -1,5 +1,5 @@
 # mako/codegen.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -12,7 +12,6 @@
 import time
 
 from mako import ast
-from mako import compat
 from mako import exceptions
 from mako import filters
 from mako import parsetree
@@ -25,8 +24,8 @@
 # names which are hardwired into the
 # template and are not accessed via the
 # context itself
-TOPLEVEL_DECLARED = set(["UNDEFINED", "STOP_RENDERING"])
-RESERVED_NAMES = set(["context", "loop"]).union(TOPLEVEL_DECLARED)
+TOPLEVEL_DECLARED = {"UNDEFINED", "STOP_RENDERING"}
+RESERVED_NAMES = {"context", "loop"}.union(TOPLEVEL_DECLARED)
 
 
 def compile(  # noqa
@@ -39,20 +38,12 @@
     future_imports=None,
     source_encoding=None,
     generate_magic_comment=True,
-    disable_unicode=False,
     strict_undefined=False,
     enable_loop=True,
     reserved_names=frozenset(),
 ):
     """Generate module source code given a parsetree node,
-      uri, and optional source filename"""
-
-    # if on Py2K, push the "source_encoding" string to be
-    # a bytestring itself, as we will be embedding it into
-    # the generated source and we don't want to coerce the
-    # result into a unicode object, in "disable_unicode" mode
-    if not compat.py3k and isinstance(source_encoding, compat.text_type):
-        source_encoding = source_encoding.encode(source_encoding)
+    uri, and optional source filename"""
 
     buf = util.FastEncodingBuffer()
 
@@ -68,7 +59,6 @@
             future_imports,
             source_encoding,
             generate_magic_comment,
-            disable_unicode,
             strict_undefined,
             enable_loop,
             reserved_names,
@@ -78,7 +68,7 @@
     return buf.getvalue()
 
 
-class _CompileContext(object):
+class _CompileContext:
     def __init__(
         self,
         uri,
@@ -89,7 +79,6 @@
         future_imports,
         source_encoding,
         generate_magic_comment,
-        disable_unicode,
         strict_undefined,
         enable_loop,
         reserved_names,
@@ -102,16 +91,15 @@
         self.future_imports = future_imports
         self.source_encoding = source_encoding
         self.generate_magic_comment = generate_magic_comment
-        self.disable_unicode = disable_unicode
         self.strict_undefined = strict_undefined
         self.enable_loop = enable_loop
         self.reserved_names = reserved_names
 
 
-class _GenerateRenderMethod(object):
+class _GenerateRenderMethod:
 
     """A template visitor object which generates the
-       full module source for a template.
+    full module source for a template.
 
     """
 
@@ -196,7 +184,7 @@
 
         self.compiler.pagetag = None
 
-        class FindTopLevel(object):
+        class FindTopLevel:
             def visitInheritTag(s, node):
                 inherit.append(node)
 
@@ -392,7 +380,7 @@
                 identifiers = self.compiler.identifiers.branch(node)
                 self.in_def = True
 
-                class NSDefVisitor(object):
+                class NSDefVisitor:
                     def visitDefTag(s, node):
                         s.visitDefOrBase(node)
 
@@ -404,7 +392,7 @@
                             raise exceptions.CompileException(
                                 "Can't put anonymous blocks inside "
                                 "<%namespace>",
-                                **node.exception_kwargs
+                                **node.exception_kwargs,
                             )
                         self.write_inline_def(node, identifiers, nested=False)
                         export.append(node.funcname)
@@ -481,7 +469,7 @@
         """
 
         # collection of all defs available to us in this scope
-        comp_idents = dict([(c.funcname, c) for c in identifiers.defs])
+        comp_idents = {c.funcname: c for c in identifiers.defs}
         to_write = set()
 
         # write "context.get()" for all variables we are going to
@@ -714,7 +702,7 @@
         toplevel=False,
     ):
         """write a post-function decorator to replace a rendering
-            callable with a cached version of itself."""
+        callable with a cached version of itself."""
 
         self.printer.writeline("__M_%s = %s" % (name, name))
         cachekey = node_or_pagetag.parsed_attributes.get(
@@ -794,8 +782,6 @@
         def locate_encode(name):
             if re.match(r"decode\..+", name):
                 return "filters." + name
-            elif self.compiler.disable_unicode:
-                return filters.NON_UNICODE_ESCAPES.get(name, name)
             else:
                 return filters.DEFAULT_ESCAPES.get(name, name)
 
@@ -859,11 +845,11 @@
             #          and end control lines, and
             #    3) any control line with no content other than comments
             if not children or (
-                compat.all(
+                all(
                     isinstance(c, (parsetree.Comment, parsetree.ControlLine))
                     for c in children
                 )
-                and compat.all(
+                and all(
                     (node.is_ternary(c.keyword) or c.isend)
                     for c in children
                     if isinstance(c, parsetree.ControlLine)
@@ -969,7 +955,7 @@
 
         self.identifier_stack.append(body_identifiers)
 
-        class DefVisitor(object):
+        class DefVisitor:
             def visitDefTag(s, node):
                 s.visitDefOrBase(node)
 
@@ -1025,7 +1011,7 @@
         )
 
 
-class _Identifiers(object):
+class _Identifiers:
 
     """tracks the status of identifier names as template code is rendered."""
 
@@ -1098,7 +1084,7 @@
 
     def branch(self, node, **kwargs):
         """create a new Identifiers for a new Node, with
-          this Identifiers as the parent."""
+        this Identifiers as the parent."""
 
         return _Identifiers(self.compiler, node, self, **kwargs)
 
@@ -1123,7 +1109,7 @@
 
     def check_declared(self, node):
         """update the state of this Identifiers with the undeclared
-            and declared identifiers of the given node."""
+        and declared identifiers of the given node."""
 
         for ident in node.undeclared_identifiers():
             if ident != "context" and ident not in self.declared.union(
@@ -1170,7 +1156,7 @@
             raise exceptions.CompileException(
                 "%%def or %%block named '%s' already "
                 "exists in this template." % node.funcname,
-                **node.exception_kwargs
+                **node.exception_kwargs,
             )
 
     def visitDefTag(self, node):
@@ -1200,7 +1186,7 @@
                 raise exceptions.CompileException(
                     "Named block '%s' not allowed inside of def '%s'"
                     % (node.name, self.node.name),
-                    **node.exception_kwargs
+                    **node.exception_kwargs,
                 )
             elif isinstance(
                 self.node, (parsetree.CallTag, parsetree.CallNamespaceTag)
@@ -1208,7 +1194,7 @@
                 raise exceptions.CompileException(
                     "Named block '%s' not allowed inside of <%%call> tag"
                     % (node.name,),
-                    **node.exception_kwargs
+                    **node.exception_kwargs,
                 )
 
         for ident in node.undeclared_identifiers():
@@ -1293,7 +1279,7 @@
     return text
 
 
-class LoopVariable(object):
+class LoopVariable:
 
     """A node visitor which looks for the name 'loop' within undeclared
     identifiers."""
diff --git a/third_party/mako/mako/mako/compat.py b/third_party/mako/mako/mako/compat.py
index 06bb8d99..68bc03b 100644
--- a/third_party/mako/mako/mako/compat.py
+++ b/third_party/mako/mako/mako/compat.py
@@ -1,19 +1,17 @@
 # mako/compat.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 import collections
+from importlib import util
 import inspect
 import sys
 
-py3k = sys.version_info >= (3, 0)
-py2k = sys.version_info < (3,)
-py27 = sys.version_info >= (2, 7)
-jython = sys.platform.startswith("java")
 win32 = sys.platform.startswith("win")
 pypy = hasattr(sys, "pypy_version_info")
+py38 = sys.version_info >= (3, 8)
 
 ArgSpec = collections.namedtuple(
     "ArgSpec", ["args", "varargs", "keywords", "defaults"]
@@ -26,15 +24,15 @@
     if inspect.ismethod(func):
         func = func.__func__
     if not inspect.isfunction(func):
-        raise TypeError("{!r} is not a Python function".format(func))
+        raise TypeError(f"{func!r} is not a Python function")
 
     co = func.__code__
     if not inspect.iscode(co):
-        raise TypeError("{!r} is not a code object".format(co))
+        raise TypeError(f"{co!r} is not a code object")
 
     nargs = co.co_argcount
     names = co.co_varnames
-    nkwargs = co.co_kwonlyargcount if py3k else 0
+    nkwargs = co.co_kwonlyargcount
     args = list(names[:nargs])
 
     nargs += nkwargs
@@ -49,129 +47,30 @@
     return ArgSpec(args, varargs, varkw, func.__defaults__)
 
 
-if py3k:
-    from io import StringIO
-    import builtins as compat_builtins
-    from urllib.parse import quote_plus, unquote_plus
-    from html.entities import codepoint2name, name2codepoint
-
-    string_types = (str,)
-    binary_type = bytes
-    text_type = str
-
-    from io import BytesIO as byte_buffer
-
-    def u(s):
-        return s
-
-    def b(s):
-        return s.encode("latin-1")
-
-    def octal(lit):
-        return eval("0o" + lit)
-
-
-else:
-    import __builtin__ as compat_builtins  # noqa
-
-    try:
-        from cStringIO import StringIO
-    except:
-        from StringIO import StringIO
-
-    byte_buffer = StringIO
-
-    from urllib import quote_plus, unquote_plus  # noqa
-    from htmlentitydefs import codepoint2name, name2codepoint  # noqa
-
-    string_types = (basestring,)  # noqa
-    binary_type = str
-    text_type = unicode  # noqa
-
-    def u(s):
-        return unicode(s, "utf-8")  # noqa
-
-    def b(s):
-        return s
-
-    def octal(lit):
-        return eval("0" + lit)
-
-
-if py3k:
-    from importlib import machinery, util
-
-    if hasattr(util, 'module_from_spec'):
-        # Python 3.5+
-        def load_module(module_id, path):
-            spec = util.spec_from_file_location(module_id, path)
-            module = util.module_from_spec(spec)
-            spec.loader.exec_module(module)
-            return module
-    else:
-        def load_module(module_id, path):
-            module = machinery.SourceFileLoader(module_id, path).load_module()
-            del sys.modules[module_id]
-            return module
-
-else:
-    import imp
-
-    def load_module(module_id, path):
-        fp = open(path, "rb")
-        try:
-            module = imp.load_source(module_id, path, fp)
-            del sys.modules[module_id]
-            return module
-        finally:
-            fp.close()
-
-
-if py3k:
-
-    def reraise(tp, value, tb=None, cause=None):
-        if cause is not None:
-            value.__cause__ = cause
-        if value.__traceback__ is not tb:
-            raise value.with_traceback(tb)
-        raise value
-
-
-else:
-    exec(
-        "def reraise(tp, value, tb=None, cause=None):\n"
-        "    raise tp, value, tb\n"
-    )
+def load_module(module_id, path):
+    spec = util.spec_from_file_location(module_id, path)
+    module = util.module_from_spec(spec)
+    spec.loader.exec_module(module)
+    return module
 
 
 def exception_as():
     return sys.exc_info()[1]
 
 
-all = all  # noqa
-
-
 def exception_name(exc):
     return exc.__class__.__name__
 
 
-################################################
-# cross-compatible metaclass implementation
-# Copyright (c) 2010-2012 Benjamin Peterson
-def with_metaclass(meta, base=object):
-    """Create a base class with a metaclass."""
-    return meta("%sBase" % meta.__name__, (base,), {})
+if py38:
+    from importlib import metadata as importlib_metadata
+else:
+    import importlib_metadata  # noqa
 
 
-################################################
-
-
-def arg_stringname(func_arg):
-    """Gets the string name of a kwarg or vararg
-    In Python3.4 a function's args are
-    of _ast.arg type not _ast.name
-    """
-    if hasattr(func_arg, "arg"):
-        return func_arg.arg
+def importlib_metadata_get(group):
+    ep = importlib_metadata.entry_points()
+    if hasattr(ep, "select"):
+        return ep.select(group=group)
     else:
-        return str(func_arg)
+        return ep.get(group, ())
diff --git a/third_party/mako/mako/mako/exceptions.py b/third_party/mako/mako/mako/exceptions.py
index ea7b20d..a0a5fec 100644
--- a/third_party/mako/mako/mako/exceptions.py
+++ b/third_party/mako/mako/mako/exceptions.py
@@ -1,5 +1,5 @@
 # mako/exceptions.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -68,7 +68,7 @@
     pass
 
 
-class RichTraceback(object):
+class RichTraceback:
 
     """Pull the current exception from the ``sys`` traceback and extracts
     Mako-specific template information.
@@ -106,7 +106,7 @@
     def _init_message(self):
         """Find a unicode representation of self.error"""
         try:
-            self.message = compat.text_type(self.error)
+            self.message = str(self.error)
         except UnicodeError:
             try:
                 self.message = str(self.error)
@@ -114,8 +114,8 @@
                 # Fallback to args as neither unicode nor
                 # str(Exception(u'\xe6')) work in Python < 2.6
                 self.message = self.error.args[0]
-        if not isinstance(self.message, compat.text_type):
-            self.message = compat.text_type(self.message, "ascii", "replace")
+        if not isinstance(self.message, str):
+            self.message = str(self.message, "ascii", "replace")
 
     def _get_reformatted_records(self, records):
         for rec in records:
@@ -139,8 +139,7 @@
 
     @property
     def reverse_traceback(self):
-        """Return the same data as traceback, except in reverse order.
-        """
+        """Return the same data as traceback, except in reverse order."""
 
         return list(self._get_reformatted_records(self.reverse_records))
 
@@ -170,17 +169,6 @@
                     )
                 except KeyError:
                     # A normal .py file (not a Template)
-                    if not compat.py3k:
-                        try:
-                            fp = open(filename, "rb")
-                            encoding = util.parse_encoding(fp)
-                            fp.close()
-                        except IOError:
-                            encoding = None
-                        if encoding:
-                            line = line.decode(encoding)
-                        else:
-                            line = line.decode("ascii", "replace")
                     new_trcback.append(
                         (
                             filename,
@@ -236,13 +224,12 @@
                 if new_trcback:
                     try:
                         # A normal .py file (not a Template)
-                        fp = open(new_trcback[-1][0], "rb")
-                        encoding = util.parse_encoding(fp)
-                        if compat.py3k and not encoding:
-                            encoding = "utf-8"
-                        fp.seek(0)
-                        self.source = fp.read()
-                        fp.close()
+                        with open(new_trcback[-1][0], "rb") as fp:
+                            encoding = util.parse_encoding(fp)
+                            if not encoding:
+                                encoding = "utf-8"
+                            fp.seek(0)
+                            self.source = fp.read()
                         if encoding:
                             self.source = self.source.decode(encoding)
                     except IOError:
diff --git a/third_party/mako/mako/mako/ext/autohandler.py b/third_party/mako/mako/mako/ext/autohandler.py
index 8b1324ef..e8fdac8 100644
--- a/third_party/mako/mako/mako/ext/autohandler.py
+++ b/third_party/mako/mako/mako/ext/autohandler.py
@@ -1,5 +1,5 @@
 # ext/autohandler.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
diff --git a/third_party/mako/mako/mako/ext/babelplugin.py b/third_party/mako/mako/mako/ext/babelplugin.py
index 76bbc5b..f015ec2 100644
--- a/third_party/mako/mako/mako/ext/babelplugin.py
+++ b/third_party/mako/mako/mako/ext/babelplugin.py
@@ -1,10 +1,10 @@
 # ext/babelplugin.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-"""gettext message extraction via Babel: http://babel.edgewall.org/"""
+"""gettext message extraction via Babel: https://pypi.org/project/Babel/"""
 from babel.messages.extract import extract_python
 
 from mako.ext.extract import MessageExtractor
@@ -15,12 +15,12 @@
         self.keywords = keywords
         self.options = options
         self.config = {
-            "comment-tags": u" ".join(comment_tags),
+            "comment-tags": " ".join(comment_tags),
             "encoding": options.get(
                 "input_encoding", options.get("encoding", None)
             ),
         }
-        super(BabelMakoExtractor, self).__init__()
+        super().__init__()
 
     def __call__(self, fileobj):
         return self.process_file(fileobj)
@@ -54,5 +54,4 @@
     :rtype: ``iterator``
     """
     extractor = BabelMakoExtractor(keywords, comment_tags, options)
-    for message in extractor(fileobj):
-        yield message
+    yield from extractor(fileobj)
diff --git a/third_party/mako/mako/mako/ext/beaker_cache.py b/third_party/mako/mako/mako/ext/beaker_cache.py
index f65ce43..a40b09c 100644
--- a/third_party/mako/mako/mako/ext/beaker_cache.py
+++ b/third_party/mako/mako/mako/ext/beaker_cache.py
@@ -1,5 +1,5 @@
 # ext/beaker_cache.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -40,7 +40,7 @@
                 _beaker_cache = cache.template.cache_args["manager"]
             else:
                 _beaker_cache = beaker_cache.CacheManager()
-        super(BeakerCacheImpl, self).__init__(cache)
+        super().__init__(cache)
 
     def _get_cache(self, **kw):
         expiretime = kw.pop("timeout", None)
diff --git a/third_party/mako/mako/mako/ext/extract.py b/third_party/mako/mako/mako/ext/extract.py
index ad2348a..74d067d 100644
--- a/third_party/mako/mako/mako/ext/extract.py
+++ b/third_party/mako/mako/mako/ext/extract.py
@@ -1,23 +1,25 @@
 # ext/extract.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
+from io import BytesIO
+from io import StringIO
 import re
 
-from mako import compat
 from mako import lexer
 from mako import parsetree
 
 
-class MessageExtractor(object):
+class MessageExtractor:
+    use_bytes = True
+
     def process_file(self, fileobj):
         template_node = lexer.Lexer(
             fileobj.read(), input_encoding=self.config["encoding"]
         ).parse()
-        for extracted in self.extract_nodes(template_node.get_children()):
-            yield extracted
+        yield from self.extract_nodes(template_node.get_children())
 
     def extract_nodes(self, nodes):
         translator_comments = []
@@ -90,7 +92,7 @@
                 comment[1] for comment in translator_comments
             ]
 
-            if isinstance(code, compat.text_type):
+            if isinstance(code, str) and self.use_bytes:
                 code = code.encode(input_encoding, "backslashreplace")
 
             used_translator_comments = False
@@ -99,7 +101,10 @@
             # input string of the input is non-ascii)
             # Also, because we added it, we have to subtract one from
             # node.lineno
-            code = compat.byte_buffer(compat.b("\n") + code)
+            if self.use_bytes:
+                code = BytesIO(b"\n" + code)
+            else:
+                code = StringIO("\n" + code)
 
             for message in self.process_python(
                 code, node.lineno - 1, translator_strings
@@ -112,8 +117,7 @@
             in_translator_comments = False
 
             if child_nodes:
-                for extracted in self.extract_nodes(child_nodes):
-                    yield extracted
+                yield from self.extract_nodes(child_nodes)
 
     @staticmethod
     def _split_comment(lineno, comment):
diff --git a/third_party/mako/mako/mako/ext/linguaplugin.py b/third_party/mako/mako/mako/ext/linguaplugin.py
index c40fa74..4cce626 100644
--- a/third_party/mako/mako/mako/ext/linguaplugin.py
+++ b/third_party/mako/mako/mako/ext/linguaplugin.py
@@ -1,23 +1,23 @@
 # ext/linguaplugin.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
+import contextlib
 import io
 
 from lingua.extractors import Extractor
 from lingua.extractors import get_extractor
 from lingua.extractors import Message
 
-from mako import compat
 from mako.ext.extract import MessageExtractor
 
 
 class LinguaMakoExtractor(Extractor, MessageExtractor):
-
     """Mako templates"""
 
+    use_bytes = False
     extensions = [".mako"]
     default_config = {"encoding": "utf-8", "comment-tags": ""}
 
@@ -26,29 +26,21 @@
         self.filename = filename
         self.python_extractor = get_extractor("x.py")
         if fileobj is None:
-            fileobj = open(filename, "rb")
-            must_close = True
+            ctx = open(filename, "r")
         else:
-            must_close = False
-        try:
-            for message in self.process_file(fileobj):
-                yield message
-        finally:
-            if must_close:
-                fileobj.close()
+            ctx = contextlib.nullcontext(fileobj)
+        with ctx as file_:
+            yield from self.process_file(file_)
 
     def process_python(self, code, code_lineno, translator_strings):
         source = code.getvalue().strip()
-        if source.endswith(compat.b(":")):
-            if source in (
-                compat.b("try:"),
-                compat.b("else:"),
-            ) or source.startswith(compat.b("except")):
-                source = compat.b("")  # Ignore try/except and else
-            elif source.startswith(compat.b("elif")):
+        if source.endswith(":"):
+            if source in ("try:", "else:") or source.startswith("except"):
+                source = ""  # Ignore try/except and else
+            elif source.startswith("elif"):
                 source = source[2:]  # Replace "elif" with "if"
-            source += compat.b("pass")
-        code = io.BytesIO(source)
+            source += "pass"
+        code = io.StringIO(source)
         for msg in self.python_extractor(
             self.filename, self.options, code, code_lineno - 1
         ):
@@ -58,7 +50,7 @@
                     msg.msgid,
                     msg.msgid_plural,
                     msg.flags,
-                    compat.u(" ").join(translator_strings + [msg.comment]),
+                    " ".join(translator_strings + [msg.comment]),
                     msg.tcomment,
                     msg.location,
                 )
diff --git a/third_party/mako/mako/mako/ext/preprocessors.py b/third_party/mako/mako/mako/ext/preprocessors.py
index 9cc06214..6855eeb 100644
--- a/third_party/mako/mako/mako/ext/preprocessors.py
+++ b/third_party/mako/mako/mako/ext/preprocessors.py
@@ -1,5 +1,5 @@
 # ext/preprocessors.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
diff --git a/third_party/mako/mako/mako/ext/pygmentplugin.py b/third_party/mako/mako/mako/ext/pygmentplugin.py
index 943a67a..38d6a71 100644
--- a/third_party/mako/mako/mako/ext/pygmentplugin.py
+++ b/third_party/mako/mako/mako/ext/pygmentplugin.py
@@ -1,5 +1,5 @@
 # ext/pygmentplugin.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -25,8 +25,6 @@
 from pygments.token import String
 from pygments.token import Text
 
-from mako import compat
-
 
 class MakoLexer(RegexLexer):
     name = "Mako"
@@ -108,7 +106,7 @@
     aliases = ["html+mako"]
 
     def __init__(self, **options):
-        super(MakoHtmlLexer, self).__init__(HtmlLexer, MakoLexer, **options)
+        super().__init__(HtmlLexer, MakoLexer, **options)
 
 
 class MakoXmlLexer(DelegatingLexer):
@@ -116,7 +114,7 @@
     aliases = ["xml+mako"]
 
     def __init__(self, **options):
-        super(MakoXmlLexer, self).__init__(XmlLexer, MakoLexer, **options)
+        super().__init__(XmlLexer, MakoLexer, **options)
 
 
 class MakoJavascriptLexer(DelegatingLexer):
@@ -124,9 +122,7 @@
     aliases = ["js+mako", "javascript+mako"]
 
     def __init__(self, **options):
-        super(MakoJavascriptLexer, self).__init__(
-            JavascriptLexer, MakoLexer, **options
-        )
+        super().__init__(JavascriptLexer, MakoLexer, **options)
 
 
 class MakoCssLexer(DelegatingLexer):
@@ -134,7 +130,7 @@
     aliases = ["css+mako"]
 
     def __init__(self, **options):
-        super(MakoCssLexer, self).__init__(CssLexer, MakoLexer, **options)
+        super().__init__(CssLexer, MakoLexer, **options)
 
 
 pygments_html_formatter = HtmlFormatter(
@@ -144,10 +140,7 @@
 
 def syntax_highlight(filename="", language=None):
     mako_lexer = MakoLexer()
-    if compat.py3k:
-        python_lexer = Python3Lexer()
-    else:
-        python_lexer = PythonLexer()
+    python_lexer = Python3Lexer()
     if filename.startswith("memory:") or language == "mako":
         return lambda string: highlight(
             string, mako_lexer, pygments_html_formatter
diff --git a/third_party/mako/mako/mako/ext/turbogears.py b/third_party/mako/mako/mako/ext/turbogears.py
index 722a6b4..413d9f7 100644
--- a/third_party/mako/mako/mako/ext/turbogears.py
+++ b/third_party/mako/mako/mako/ext/turbogears.py
@@ -1,5 +1,5 @@
 # ext/turbogears.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -9,7 +9,7 @@
 from mako.template import Template
 
 
-class TGPlugin(object):
+class TGPlugin:
 
     """TurboGears compatible Template Plugin."""
 
@@ -51,7 +51,7 @@
     def render(
         self, info, format="html", fragment=False, template=None  # noqa
     ):
-        if isinstance(template, compat.string_types):
+        if isinstance(template, str):
             template = self.load_template(template)
 
         # Load extra vars func if provided
diff --git a/third_party/mako/mako/mako/filters.py b/third_party/mako/mako/mako/filters.py
index 0ae33ff48..26edd8e 100644
--- a/third_party/mako/mako/mako/filters.py
+++ b/third_party/mako/mako/mako/filters.py
@@ -1,18 +1,19 @@
 # mako/filters.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 
 import codecs
+from html.entities import codepoint2name
+from html.entities import name2codepoint
 import re
+from urllib.parse import quote_plus
 
-from mako import compat
-from mako.compat import codepoint2name
-from mako.compat import name2codepoint
-from mako.compat import quote_plus
-from mako.compat import unquote_plus
+import markupsafe
+
+html_escape = markupsafe.escape
 
 xml_escapes = {
     "&": "&amp;",
@@ -22,27 +23,6 @@
     "'": "&#39;",  # also &apos; in html-only
 }
 
-# XXX: &quot; is valid in HTML and XML
-#      &apos; is not valid HTML, but is valid XML
-
-
-def legacy_html_escape(s):
-    """legacy HTML escape for non-unicode mode."""
-    s = s.replace("&", "&amp;")
-    s = s.replace(">", "&gt;")
-    s = s.replace("<", "&lt;")
-    s = s.replace('"', "&#34;")
-    s = s.replace("'", "&#39;")
-    return s
-
-
-try:
-    import markupsafe
-
-    html_escape = markupsafe.escape
-except ImportError:
-    html_escape = legacy_html_escape
-
 
 def xml_escape(string):
     return re.sub(r'([&<"\'>])', lambda m: xml_escapes[m.group()], string)
@@ -54,31 +34,19 @@
     return quote_plus(string)
 
 
-def legacy_url_escape(string):
-    # convert into a list of octets
-    return quote_plus(string)
-
-
-def url_unescape(string):
-    text = unquote_plus(string)
-    if not is_ascii_str(text):
-        text = text.decode("utf8")
-    return text
-
-
 def trim(string):
     return string.strip()
 
 
-class Decode(object):
+class Decode:
     def __getattr__(self, key):
         def decode(x):
-            if isinstance(x, compat.text_type):
+            if isinstance(x, str):
                 return x
-            elif not isinstance(x, compat.binary_type):
+            elif not isinstance(x, bytes):
                 return decode(str(x))
             else:
-                return compat.text_type(x, encoding=key)
+                return str(x, encoding=key)
 
         return decode
 
@@ -86,24 +54,11 @@
 decode = Decode()
 
 
-_ASCII_re = re.compile(r"\A[\x00-\x7f]*\Z")
-
-
-def is_ascii_str(text):
-    return isinstance(text, str) and _ASCII_re.match(text)
-
-
-################################################################
-
-
-class XMLEntityEscaper(object):
+class XMLEntityEscaper:
     def __init__(self, codepoint2name, name2codepoint):
-        self.codepoint2entity = dict(
-            [
-                (c, compat.text_type("&%s;" % n))
-                for c, n in codepoint2name.items()
-            ]
-        )
+        self.codepoint2entity = {
+            c: str("&%s;" % n) for c, n in codepoint2name.items()
+        }
         self.name2codepoint = name2codepoint
 
     def escape_entities(self, text):
@@ -111,7 +66,7 @@
 
         Only characters corresponding to a named entity are replaced.
         """
-        return compat.text_type(text).translate(self.codepoint2entity)
+        return str(text).translate(self.codepoint2entity)
 
     def __escape(self, m):
         codepoint = ord(m.group())
@@ -131,9 +86,7 @@
 
         The return value is guaranteed to be ASCII.
         """
-        return self.__escapable.sub(
-            self.__escape, compat.text_type(text)
-        ).encode("ascii")
+        return self.__escapable.sub(self.__escape, str(text)).encode("ascii")
 
     # XXX: This regexp will not match all valid XML entity names__.
     # (It punts on details involving involving CombiningChars and Extenders.)
@@ -183,37 +136,28 @@
     characters with HTML entities, or, if no HTML entity exists for
     the character, XML character references::
 
-        >>> u'The cost was \u20ac12.'.encode('latin1', 'htmlentityreplace')
+        >>> 'The cost was \u20ac12.'.encode('latin1', 'htmlentityreplace')
         'The cost was &euro;12.'
     """
     if isinstance(ex, UnicodeEncodeError):
         # Handle encoding errors
         bad_text = ex.object[ex.start : ex.end]
         text = _html_entities_escaper.escape(bad_text)
-        return (compat.text_type(text), ex.end)
+        return (str(text), ex.end)
     raise ex
 
 
 codecs.register_error("htmlentityreplace", htmlentityreplace_errors)
 
 
-# TODO: options to make this dynamic per-compilation will be added in a later
-# release
 DEFAULT_ESCAPES = {
     "x": "filters.xml_escape",
     "h": "filters.html_escape",
     "u": "filters.url_escape",
     "trim": "filters.trim",
     "entity": "filters.html_entities_escape",
-    "unicode": "unicode",
+    "unicode": "str",
     "decode": "decode",
     "str": "str",
     "n": "n",
 }
-
-if compat.py3k:
-    DEFAULT_ESCAPES.update({"unicode": "str"})
-
-NON_UNICODE_ESCAPES = DEFAULT_ESCAPES.copy()
-NON_UNICODE_ESCAPES["h"] = "filters.legacy_html_escape"
-NON_UNICODE_ESCAPES["u"] = "filters.legacy_url_escape"
diff --git a/third_party/mako/mako/mako/lexer.py b/third_party/mako/mako/mako/lexer.py
index 6226e26..527c4b51 100644
--- a/third_party/mako/mako/mako/lexer.py
+++ b/third_party/mako/mako/mako/lexer.py
@@ -1,5 +1,5 @@
 # mako/lexer.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -9,7 +9,6 @@
 import codecs
 import re
 
-from mako import compat
 from mako import exceptions
 from mako import parsetree
 from mako.pygen import adjust_whitespace
@@ -17,14 +16,9 @@
 _regexp_cache = {}
 
 
-class Lexer(object):
+class Lexer:
     def __init__(
-        self,
-        text,
-        filename=None,
-        disable_unicode=False,
-        input_encoding=None,
-        preprocessor=None,
+        self, text, filename=None, input_encoding=None, preprocessor=None
     ):
         self.text = text
         self.filename = filename
@@ -36,14 +30,8 @@
         self.tag = []
         self.control_line = []
         self.ternary_stack = []
-        self.disable_unicode = disable_unicode
         self.encoding = input_encoding
 
-        if compat.py3k and disable_unicode:
-            raise exceptions.UnsupportedError(
-                "Mako for Python 3 does not " "support disabling Unicode"
-            )
-
         if preprocessor is None:
             self.preprocessor = []
         elif not hasattr(preprocessor, "__iter__"):
@@ -66,10 +54,7 @@
         try:
             reg = _regexp_cache[(regexp, flags)]
         except KeyError:
-            if flags:
-                reg = re.compile(regexp, flags)
-            else:
-                reg = re.compile(regexp)
+            reg = re.compile(regexp, flags) if flags else re.compile(regexp)
             _regexp_cache[(regexp, flags)] = reg
 
         return self.match_reg(reg)
@@ -87,10 +72,7 @@
         match = reg.match(self.text, self.match_position)
         if match:
             (start, end) = match.span()
-            if end == start:
-                self.match_position = end + 1
-            else:
-                self.match_position = end
+            self.match_position = end + 1 if end == start else end
             self.matched_lineno = self.lineno
             lines = re.findall(r"\n", self.text[mp : self.match_position])
             cp = mp - 1
@@ -98,10 +80,6 @@
                 cp -= 1
             self.matched_charpos = mp - cp
             self.lineno += len(lines)
-            # print "MATCHED:", match.group(0), "LINE START:",
-            # self.matched_lineno, "LINE END:", self.lineno
-        # print "MATCH:", regexp, "\n", self.text[mp : mp + 15], \
-        #          (match and "TRUE" or "FALSE")
         return match
 
     def parse_until_text(self, watch_nesting, *text):
@@ -161,12 +139,15 @@
         if self.control_line:
             control_frame = self.control_line[-1]
             control_frame.nodes.append(node)
-            if not (
-                isinstance(node, parsetree.ControlLine)
-                and control_frame.is_ternary(node.keyword)
+            if (
+                not (
+                    isinstance(node, parsetree.ControlLine)
+                    and control_frame.is_ternary(node.keyword)
+                )
+                and self.ternary_stack
+                and self.ternary_stack[-1]
             ):
-                if self.ternary_stack and self.ternary_stack[-1]:
-                    self.ternary_stack[-1][-1].nodes.append(node)
+                self.ternary_stack[-1][-1].nodes.append(node)
         if isinstance(node, parsetree.Tag):
             if len(self.tag):
                 node.parent = self.tag[-1]
@@ -188,18 +169,18 @@
                 raise exceptions.SyntaxException(
                     "Keyword '%s' not a legal ternary for keyword '%s'"
                     % (node.keyword, self.control_line[-1].keyword),
-                    **self.exception_kwargs
+                    **self.exception_kwargs,
                 )
 
     _coding_re = re.compile(r"#.*coding[:=]\s*([-\w.]+).*\r?\n")
 
     def decode_raw_stream(self, text, decode_raw, known_encoding, filename):
         """given string/unicode or bytes/string, determine encoding
-           from magic encoding comment, return body as unicode
-           or raw if decode_raw=False
+        from magic encoding comment, return body as unicode
+        or raw if decode_raw=False
 
         """
-        if isinstance(text, compat.text_type):
+        if isinstance(text, str):
             m = self._coding_re.match(text)
             encoding = m and m.group(1) or known_encoding or "utf-8"
             return encoding, text
@@ -219,11 +200,7 @@
                 )
         else:
             m = self._coding_re.match(text.decode("utf-8", "ignore"))
-            if m:
-                parsed_encoding = m.group(1)
-            else:
-                parsed_encoding = known_encoding or "utf-8"
-
+            parsed_encoding = m.group(1) if m else known_encoding or "utf-8"
         if decode_raw:
             try:
                 text = text.decode(parsed_encoding)
@@ -241,7 +218,7 @@
 
     def parse(self):
         self.encoding, self.text = self.decode_raw_stream(
-            self.text, not self.disable_unicode, self.encoding, self.filename
+            self.text, True, self.encoding, self.filename
         )
 
         for preproc in self.preprocessor:
@@ -276,12 +253,13 @@
 
             if self.match_position > self.textlength:
                 break
-            raise exceptions.CompileException("assertion failed")
+            # TODO: no coverage here
+            raise exceptions.MakoException("assertion failed")
 
         if len(self.tag):
             raise exceptions.SyntaxException(
                 "Unclosed tag: <%%%s>" % self.tag[-1].keyword,
-                **self.exception_kwargs
+                **self.exception_kwargs,
             )
         if len(self.control_line):
             raise exceptions.SyntaxException(
@@ -312,35 +290,34 @@
             re.I | re.S | re.X,
         )
 
-        if match:
-            keyword, attr, isend = match.groups()
-            self.keyword = keyword
-            attributes = {}
-            if attr:
-                for att in re.findall(
-                    r"\s*(\w+)\s*=\s*(?:'([^']*)'|\"([^\"]*)\")", attr
-                ):
-                    key, val1, val2 = att
-                    text = val1 or val2
-                    text = text.replace("\r\n", "\n")
-                    attributes[key] = text
-            self.append_node(parsetree.Tag, keyword, attributes)
-            if isend:
-                self.tag.pop()
-            else:
-                if keyword == "text":
-                    match = self.match(r"(.*?)(?=\</%text>)", re.S)
-                    if not match:
-                        raise exceptions.SyntaxException(
-                            "Unclosed tag: <%%%s>" % self.tag[-1].keyword,
-                            **self.exception_kwargs
-                        )
-                    self.append_node(parsetree.Text, match.group(1))
-                    return self.match_tag_end()
-            return True
-        else:
+        if not match:
             return False
 
+        keyword, attr, isend = match.groups()
+        self.keyword = keyword
+        attributes = {}
+        if attr:
+            for att in re.findall(
+                r"\s*(\w+)\s*=\s*(?:'([^']*)'|\"([^\"]*)\")", attr
+            ):
+                key, val1, val2 = att
+                text = val1 or val2
+                text = text.replace("\r\n", "\n")
+                attributes[key] = text
+        self.append_node(parsetree.Tag, keyword, attributes)
+        if isend:
+            self.tag.pop()
+        elif keyword == "text":
+            match = self.match(r"(.*?)(?=\</%text>)", re.S)
+            if not match:
+                raise exceptions.SyntaxException(
+                    "Unclosed tag: <%%%s>" % self.tag[-1].keyword,
+                    **self.exception_kwargs,
+                )
+            self.append_node(parsetree.Text, match.group(1))
+            return self.match_tag_end()
+        return True
+
     def match_tag_end(self):
         match = self.match(r"\</%[\t ]*(.+?)[\t ]*>")
         if match:
@@ -348,13 +325,13 @@
                 raise exceptions.SyntaxException(
                     "Closing tag without opening tag: </%%%s>"
                     % match.group(1),
-                    **self.exception_kwargs
+                    **self.exception_kwargs,
                 )
             elif self.tag[-1].keyword != match.group(1):
                 raise exceptions.SyntaxException(
                     "Closing tag </%%%s> does not match tag: <%%%s>"
                     % (match.group(1), self.tag[-1].keyword),
-                    **self.exception_kwargs
+                    **self.exception_kwargs,
                 )
             self.tag.pop()
             return True
@@ -363,15 +340,15 @@
 
     def match_end(self):
         match = self.match(r"\Z", re.S)
-        if match:
-            string = match.group()
-            if string:
-                return string
-            else:
-                return True
-        else:
+        if not match:
             return False
 
+        string = match.group()
+        if string:
+            return string
+        else:
+            return True
+
     def match_text(self):
         match = self.match(
             r"""
@@ -422,64 +399,63 @@
 
     def match_expression(self):
         match = self.match(r"\${")
-        if match:
-            line, pos = self.matched_lineno, self.matched_charpos
-            text, end = self.parse_until_text(True, r"\|", r"}")
-            if end == "|":
-                escapes, end = self.parse_until_text(True, r"}")
-            else:
-                escapes = ""
-            text = text.replace("\r\n", "\n")
-            self.append_node(
-                parsetree.Expression,
-                text,
-                escapes.strip(),
-                lineno=line,
-                pos=pos,
-            )
-            return True
-        else:
+        if not match:
             return False
 
+        line, pos = self.matched_lineno, self.matched_charpos
+        text, end = self.parse_until_text(True, r"\|", r"}")
+        if end == "|":
+            escapes, end = self.parse_until_text(True, r"}")
+        else:
+            escapes = ""
+        text = text.replace("\r\n", "\n")
+        self.append_node(
+            parsetree.Expression,
+            text,
+            escapes.strip(),
+            lineno=line,
+            pos=pos,
+        )
+        return True
+
     def match_control_line(self):
         match = self.match(
-            r"(?<=^)[\t ]*(%(?!%)|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)"
+            r"(?<=^)[\t ]*(%(?!%)|##)[\t ]*((?:(?:\\\r?\n)|[^\r\n])*)"
             r"(?:\r?\n|\Z)",
             re.M,
         )
-        if match:
-            operator = match.group(1)
-            text = match.group(2)
-            if operator == "%":
-                m2 = re.match(r"(end)?(\w+)\s*(.*)", text)
-                if not m2:
-                    raise exceptions.SyntaxException(
-                        "Invalid control line: '%s'" % text,
-                        **self.exception_kwargs
-                    )
-                isend, keyword = m2.group(1, 2)
-                isend = isend is not None
-
-                if isend:
-                    if not len(self.control_line):
-                        raise exceptions.SyntaxException(
-                            "No starting keyword '%s' for '%s'"
-                            % (keyword, text),
-                            **self.exception_kwargs
-                        )
-                    elif self.control_line[-1].keyword != keyword:
-                        raise exceptions.SyntaxException(
-                            "Keyword '%s' doesn't match keyword '%s'"
-                            % (text, self.control_line[-1].keyword),
-                            **self.exception_kwargs
-                        )
-                self.append_node(parsetree.ControlLine, keyword, isend, text)
-            else:
-                self.append_node(parsetree.Comment, text)
-            return True
-        else:
+        if not match:
             return False
 
+        operator = match.group(1)
+        text = match.group(2)
+        if operator == "%":
+            m2 = re.match(r"(end)?(\w+)\s*(.*)", text)
+            if not m2:
+                raise exceptions.SyntaxException(
+                    "Invalid control line: '%s'" % text,
+                    **self.exception_kwargs,
+                )
+            isend, keyword = m2.group(1, 2)
+            isend = isend is not None
+
+            if isend:
+                if not len(self.control_line):
+                    raise exceptions.SyntaxException(
+                        "No starting keyword '%s' for '%s'" % (keyword, text),
+                        **self.exception_kwargs,
+                    )
+                elif self.control_line[-1].keyword != keyword:
+                    raise exceptions.SyntaxException(
+                        "Keyword '%s' doesn't match keyword '%s'"
+                        % (text, self.control_line[-1].keyword),
+                        **self.exception_kwargs,
+                    )
+            self.append_node(parsetree.ControlLine, keyword, isend, text)
+        else:
+            self.append_node(parsetree.Comment, text)
+        return True
+
     def match_comment(self):
         """matches the multiline version of a comment"""
         match = self.match(r"<%doc>(.*?)</%doc>", re.S)
diff --git a/third_party/mako/mako/mako/lookup.py b/third_party/mako/mako/mako/lookup.py
index 476326d..7afe242 100644
--- a/third_party/mako/mako/mako/lookup.py
+++ b/third_party/mako/mako/mako/lookup.py
@@ -1,5 +1,5 @@
 # mako/lookup.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -8,18 +8,14 @@
 import posixpath
 import re
 import stat
+import threading
 
 from mako import exceptions
 from mako import util
 from mako.template import Template
 
-try:
-    import threading
-except:
-    import dummy_threading as threading
 
-
-class TemplateCollection(object):
+class TemplateCollection:
 
     """Represent a collection of :class:`.Template` objects,
     identifiable via URI.
@@ -34,7 +30,7 @@
     :class:`.TemplateCollection` is an abstract class,
     with the usual default implementation being :class:`.TemplateLookup`.
 
-     """
+    """
 
     def has_template(self, uri):
         """Return ``True`` if this :class:`.TemplateLookup` is
@@ -68,7 +64,7 @@
 
     def filename_to_uri(self, uri, filename):
         """Convert the given ``filename`` to a URI relative to
-           this :class:`.TemplateCollection`."""
+        this :class:`.TemplateCollection`."""
 
         return uri
 
@@ -161,8 +157,6 @@
         collection_size=-1,
         format_exceptions=False,
         error_handler=None,
-        disable_unicode=False,
-        bytestring_passthrough=False,
         output_encoding=None,
         encoding_errors="strict",
         cache_args=None,
@@ -207,8 +201,6 @@
             "format_exceptions": format_exceptions,
             "error_handler": error_handler,
             "include_error_handler": include_error_handler,
-            "disable_unicode": disable_unicode,
-            "bytestring_passthrough": bytestring_passthrough,
             "output_encoding": output_encoding,
             "cache_impl": cache_impl,
             "encoding_errors": encoding_errors,
@@ -249,7 +241,7 @@
                 return self._check(uri, self._collection[uri])
             else:
                 return self._collection[uri]
-        except KeyError:
+        except KeyError as e:
             u = re.sub(r"^\/+", "", uri)
             for dir_ in self.directories:
                 # make sure the path seperators are posix - os.altsep is empty
@@ -260,8 +252,8 @@
                     return self._load(srcfile, uri)
             else:
                 raise exceptions.TopLevelLookupException(
-                    "Cant locate template for uri %r" % uri
-                )
+                    "Can't locate template for uri %r" % uri
+                ) from e
 
     def adjust_uri(self, uri, relativeto):
         """Adjust the given ``uri`` based on the given relative URI."""
@@ -270,20 +262,19 @@
         if key in self._uri_cache:
             return self._uri_cache[key]
 
-        if uri[0] != "/":
-            if relativeto is not None:
-                v = self._uri_cache[key] = posixpath.join(
-                    posixpath.dirname(relativeto), uri
-                )
-            else:
-                v = self._uri_cache[key] = "/" + uri
-        else:
+        if uri[0] == "/":
             v = self._uri_cache[key] = uri
+        elif relativeto is not None:
+            v = self._uri_cache[key] = posixpath.join(
+                posixpath.dirname(relativeto), uri
+            )
+        else:
+            v = self._uri_cache[key] = "/" + uri
         return v
 
     def filename_to_uri(self, filename):
         """Convert the given ``filename`` to a URI relative to
-           this :class:`.TemplateCollection`."""
+        this :class:`.TemplateCollection`."""
 
         try:
             return self._uri_cache[filename]
@@ -294,7 +285,7 @@
 
     def _relativeize(self, filename):
         """Return the portion of a filename that is 'relative'
-           to the directories in this lookup.
+        to the directories in this lookup.
 
         """
 
@@ -324,7 +315,7 @@
                     filename=posixpath.normpath(filename),
                     lookup=self,
                     module_filename=module_filename,
-                    **self.template_args
+                    **self.template_args,
                 )
                 return template
             except:
@@ -342,16 +333,15 @@
 
         try:
             template_stat = os.stat(template.filename)
-            if template.module._modified_time < template_stat[stat.ST_MTIME]:
-                self._collection.pop(uri, None)
-                return self._load(template.filename, uri)
-            else:
+            if template.module._modified_time >= template_stat[stat.ST_MTIME]:
                 return template
-        except OSError:
+            self._collection.pop(uri, None)
+            return self._load(template.filename, uri)
+        except OSError as e:
             self._collection.pop(uri, None)
             raise exceptions.TemplateLookupException(
-                "Cant locate template for uri %r" % uri
-            )
+                "Can't locate template for uri %r" % uri
+            ) from e
 
     def put_string(self, uri, text):
         """Place a new :class:`.Template` object into this
diff --git a/third_party/mako/mako/mako/parsetree.py b/third_party/mako/mako/mako/parsetree.py
index 801e48a..2135769f 100644
--- a/third_party/mako/mako/mako/parsetree.py
+++ b/third_party/mako/mako/mako/parsetree.py
@@ -1,5 +1,5 @@
 # mako/parsetree.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -9,13 +9,12 @@
 import re
 
 from mako import ast
-from mako import compat
 from mako import exceptions
 from mako import filters
 from mako import util
 
 
-class Node(object):
+class Node:
 
     """base class for a Node in the parse tree."""
 
@@ -51,7 +50,7 @@
     """a 'container' node that stores the overall collection of nodes."""
 
     def __init__(self, filename):
-        super(TemplateNode, self).__init__("", 0, 0, filename)
+        super().__init__("", 0, 0, filename)
         self.nodes = []
         self.page_attributes = {}
 
@@ -80,7 +79,7 @@
     has_loop_context = False
 
     def __init__(self, keyword, isend, text, **kwargs):
-        super(ControlLine, self).__init__(**kwargs)
+        super().__init__(**kwargs)
         self.text = text
         self.keyword = keyword
         self.isend = isend
@@ -107,11 +106,13 @@
         """return true if the given keyword is a ternary keyword
         for this ControlLine"""
 
-        return keyword in {
-            "if": set(["else", "elif"]),
-            "try": set(["except", "finally"]),
-            "for": set(["else"]),
-        }.get(self.keyword, [])
+        cases = {
+            "if": {"else", "elif"},
+            "try": {"except", "finally"},
+            "for": {"else"},
+        }
+
+        return keyword in cases.get(self.keyword, set())
 
     def __repr__(self):
         return "ControlLine(%r, %r, %r, %r)" % (
@@ -123,11 +124,10 @@
 
 
 class Text(Node):
-
     """defines plain text in the template."""
 
     def __init__(self, content, **kwargs):
-        super(Text, self).__init__(**kwargs)
+        super().__init__(**kwargs)
         self.content = content
 
     def __repr__(self):
@@ -135,7 +135,6 @@
 
 
 class Code(Node):
-
     """defines a Python code block, either inline or module level.
 
     e.g.::
@@ -153,7 +152,7 @@
     """
 
     def __init__(self, text, ismodule, **kwargs):
-        super(Code, self).__init__(**kwargs)
+        super().__init__(**kwargs)
         self.text = text
         self.ismodule = ismodule
         self.code = ast.PythonCode(text, **self.exception_kwargs)
@@ -173,7 +172,6 @@
 
 
 class Comment(Node):
-
     """defines a comment line.
 
     # this is a comment
@@ -181,7 +179,7 @@
     """
 
     def __init__(self, text, **kwargs):
-        super(Comment, self).__init__(**kwargs)
+        super().__init__(**kwargs)
         self.text = text
 
     def __repr__(self):
@@ -189,7 +187,6 @@
 
 
 class Expression(Node):
-
     """defines an inline expression.
 
     ${x+y}
@@ -197,7 +194,7 @@
     """
 
     def __init__(self, text, escapes, **kwargs):
-        super(Expression, self).__init__(**kwargs)
+        super().__init__(**kwargs)
         self.text = text
         self.escapes = escapes
         self.escapes_code = ast.ArgumentList(escapes, **self.exception_kwargs)
@@ -210,7 +207,7 @@
         # TODO: make the "filter" shortcut list configurable at parse/gen time
         return self.code.undeclared_identifiers.union(
             self.escapes_code.undeclared_identifiers.difference(
-                set(filters.DEFAULT_ESCAPES.keys())
+                filters.DEFAULT_ESCAPES
             )
         ).difference(self.code.declared_identifiers)
 
@@ -223,7 +220,6 @@
 
 
 class _TagMeta(type):
-
     """metaclass to allow Tag to produce a subclass according to
     its keyword"""
 
@@ -232,7 +228,7 @@
     def __init__(cls, clsname, bases, dict_):
         if getattr(cls, "__keyword__", None) is not None:
             cls._classmap[cls.__keyword__] = cls
-        super(_TagMeta, cls).__init__(clsname, bases, dict_)
+        super().__init__(clsname, bases, dict_)
 
     def __call__(cls, keyword, attributes, **kwargs):
         if ":" in keyword:
@@ -254,7 +250,7 @@
         return type.__call__(cls, keyword, attributes, **kwargs)
 
 
-class Tag(compat.with_metaclass(_TagMeta, Node)):
+class Tag(Node, metaclass=_TagMeta):
     """abstract base class for tags.
 
     e.g.::
@@ -276,7 +272,7 @@
         expressions,
         nonexpressions,
         required,
-        **kwargs
+        **kwargs,
     ):
         r"""construct a new Tag instance.
 
@@ -297,17 +293,20 @@
          other arguments passed to the Node superclass (lineno, pos)
 
         """
-        super(Tag, self).__init__(**kwargs)
+        super().__init__(**kwargs)
         self.keyword = keyword
         self.attributes = attributes
         self._parse_attributes(expressions, nonexpressions)
         missing = [r for r in required if r not in self.parsed_attributes]
         if len(missing):
             raise exceptions.CompileException(
-                "Missing attribute(s): %s"
-                % ",".join([repr(m) for m in missing]),
-                **self.exception_kwargs
+                (
+                    "Missing attribute(s): %s"
+                    % ",".join(repr(m) for m in missing)
+                ),
+                **self.exception_kwargs,
             )
+
         self.parent = None
         self.nodes = []
 
@@ -339,23 +338,22 @@
                             code.undeclared_identifiers
                         )
                         expr.append("(%s)" % m.group(1))
-                    else:
-                        if x:
-                            expr.append(repr(x))
+                    elif x:
+                        expr.append(repr(x))
                 self.parsed_attributes[key] = " + ".join(expr) or repr("")
             elif key in nonexpressions:
                 if re.search(r"\${.+?}", self.attributes[key]):
                     raise exceptions.CompileException(
-                        "Attibute '%s' in tag '%s' does not allow embedded "
+                        "Attribute '%s' in tag '%s' does not allow embedded "
                         "expressions" % (key, self.keyword),
-                        **self.exception_kwargs
+                        **self.exception_kwargs,
                     )
                 self.parsed_attributes[key] = repr(self.attributes[key])
             else:
                 raise exceptions.CompileException(
                     "Invalid attribute for tag '%s': '%s'"
                     % (self.keyword, key),
-                    **self.exception_kwargs
+                    **self.exception_kwargs,
                 )
         self.expression_undeclared_identifiers = undeclared_identifiers
 
@@ -379,13 +377,13 @@
     __keyword__ = "include"
 
     def __init__(self, keyword, attributes, **kwargs):
-        super(IncludeTag, self).__init__(
+        super().__init__(
             keyword,
             attributes,
             ("file", "import", "args"),
             (),
             ("file",),
-            **kwargs
+            **kwargs,
         )
         self.page_args = ast.PythonCode(
             "__DUMMY(%s)" % attributes.get("args", ""), **self.exception_kwargs
@@ -396,24 +394,22 @@
 
     def undeclared_identifiers(self):
         identifiers = self.page_args.undeclared_identifiers.difference(
-            set(["__DUMMY"])
+            {"__DUMMY"}
         ).difference(self.page_args.declared_identifiers)
-        return identifiers.union(
-            super(IncludeTag, self).undeclared_identifiers()
-        )
+        return identifiers.union(super().undeclared_identifiers())
 
 
 class NamespaceTag(Tag):
     __keyword__ = "namespace"
 
     def __init__(self, keyword, attributes, **kwargs):
-        super(NamespaceTag, self).__init__(
+        super().__init__(
             keyword,
             attributes,
             ("file",),
             ("name", "inheritable", "import", "module"),
             (),
-            **kwargs
+            **kwargs,
         )
 
         self.name = attributes.get("name", "__anon_%s" % hex(abs(id(self))))
@@ -421,12 +417,12 @@
             raise exceptions.CompileException(
                 "'name' and/or 'import' attributes are required "
                 "for <%namespace>",
-                **self.exception_kwargs
+                **self.exception_kwargs,
             )
         if "file" in attributes and "module" in attributes:
             raise exceptions.CompileException(
                 "<%namespace> may only have one of 'file' or 'module'",
-                **self.exception_kwargs
+                **self.exception_kwargs,
             )
 
     def declared_identifiers(self):
@@ -437,9 +433,7 @@
     __keyword__ = "text"
 
     def __init__(self, keyword, attributes, **kwargs):
-        super(TextTag, self).__init__(
-            keyword, attributes, (), ("filter"), (), **kwargs
-        )
+        super().__init__(keyword, attributes, (), ("filter"), (), **kwargs)
         self.filter_args = ast.ArgumentList(
             attributes.get("filter", ""), **self.exception_kwargs
         )
@@ -458,13 +452,13 @@
             c for c in attributes if c.startswith("cache_")
         ]
 
-        super(DefTag, self).__init__(
+        super().__init__(
             keyword,
             attributes,
             expressions,
             ("name", "filter", "decorator"),
             ("name",),
-            **kwargs
+            **kwargs,
         )
         name = attributes["name"]
         if re.match(r"^[\w_]+$", name):
@@ -521,19 +515,19 @@
             c for c in attributes if c.startswith("cache_")
         ]
 
-        super(BlockTag, self).__init__(
+        super().__init__(
             keyword,
             attributes,
             expressions,
             ("name", "filter", "decorator"),
             (),
-            **kwargs
+            **kwargs,
         )
         name = attributes.get("name")
         if name and not re.match(r"^[\w_]+$", name):
             raise exceptions.CompileException(
                 "%block may not specify an argument signature",
-                **self.exception_kwargs
+                **self.exception_kwargs,
             )
         if not name and attributes.get("args", None):
             raise exceptions.CompileException(
@@ -577,7 +571,7 @@
     __keyword__ = "call"
 
     def __init__(self, keyword, attributes, **kwargs):
-        super(CallTag, self).__init__(
+        super().__init__(
             keyword, attributes, ("args"), ("expr",), ("expr",), **kwargs
         )
         self.expression = attributes["expr"]
@@ -597,26 +591,25 @@
 
 class CallNamespaceTag(Tag):
     def __init__(self, namespace, defname, attributes, **kwargs):
-        super(CallNamespaceTag, self).__init__(
+        super().__init__(
             namespace + ":" + defname,
             attributes,
             tuple(attributes.keys()) + ("args",),
             (),
             (),
-            **kwargs
+            **kwargs,
         )
 
         self.expression = "%s.%s(%s)" % (
             namespace,
             defname,
             ",".join(
-                [
-                    "%s=%s" % (k, v)
-                    for k, v in self.parsed_attributes.items()
-                    if k != "args"
-                ]
+                "%s=%s" % (k, v)
+                for k, v in self.parsed_attributes.items()
+                if k != "args"
             ),
         )
+
         self.code = ast.PythonCode(self.expression, **self.exception_kwargs)
         self.body_decl = ast.FunctionArgs(
             attributes.get("args", ""), **self.exception_kwargs
@@ -635,7 +628,7 @@
     __keyword__ = "inherit"
 
     def __init__(self, keyword, attributes, **kwargs):
-        super(InheritTag, self).__init__(
+        super().__init__(
             keyword, attributes, ("file",), (), ("file",), **kwargs
         )
 
@@ -651,9 +644,7 @@
             "enable_loop",
         ] + [c for c in attributes if c.startswith("cache_")]
 
-        super(PageTag, self).__init__(
-            keyword, attributes, expressions, (), (), **kwargs
-        )
+        super().__init__(keyword, attributes, expressions, (), (), **kwargs)
         self.body_decl = ast.FunctionArgs(
             attributes.get("args", ""), **self.exception_kwargs
         )
diff --git a/third_party/mako/mako/mako/pygen.py b/third_party/mako/mako/mako/pygen.py
index 947721f..46b0b52 100644
--- a/third_party/mako/mako/mako/pygen.py
+++ b/third_party/mako/mako/mako/pygen.py
@@ -1,5 +1,5 @@
 # mako/pygen.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -11,7 +11,7 @@
 from mako import exceptions
 
 
-class PythonPrinter(object):
+class PythonPrinter:
     def __init__(self, stream):
         # indentation counter
         self.indent = 0
@@ -96,18 +96,19 @@
         is_comment = line and len(line) and line[0] == "#"
 
         # see if this line should decrease the indentation level
-        if not is_comment and (not hastext or self._is_unindentor(line)):
-
-            if self.indent > 0:
-                self.indent -= 1
-                # if the indent_detail stack is empty, the user
-                # probably put extra closures - the resulting
-                # module wont compile.
-                if len(self.indent_detail) == 0:
-                    raise exceptions.SyntaxException(
-                        "Too many whitespace closures"
-                    )
-                self.indent_detail.pop()
+        if (
+            not is_comment
+            and (not hastext or self._is_unindentor(line))
+            and self.indent > 0
+        ):
+            self.indent -= 1
+            # if the indent_detail stack is empty, the user
+            # probably put extra closures - the resulting
+            # module wont compile.
+            if len(self.indent_detail) == 0:
+                # TODO: no coverage here
+                raise exceptions.MakoException("Too many whitespace closures")
+            self.indent_detail.pop()
 
         if line is None:
             return
@@ -167,13 +168,10 @@
         # if the current line doesnt have one of the "unindentor" keywords,
         # return False
         match = re.match(r"^\s*(else|elif|except|finally).*\:", line)
-        if not match:
-            return False
-
-        # whitespace matches up, we have a compound indentor,
+        # if True, whitespace matches up, we have a compound indentor,
         # and this line has an unindentor, this
         # is probably good enough
-        return True
+        return bool(match)
 
         # should we decide that its not good enough, heres
         # more stuff to check.
@@ -218,11 +216,7 @@
 
         current_state = self.backslashed or self.triplequoted
 
-        if re.search(r"\\$", line):
-            self.backslashed = True
-        else:
-            self.backslashed = False
-
+        self.backslashed = bool(re.search(r"\\$", line))
         triples = len(re.findall(r"\"\"\"|\'\'\'", line))
         if triples == 1 or triples % 2 != 0:
             self.triplequoted = not self.triplequoted
diff --git a/third_party/mako/mako/mako/pyparser.py b/third_party/mako/mako/mako/pyparser.py
index b16672d..5c55505 100644
--- a/third_party/mako/mako/mako/pyparser.py
+++ b/third_party/mako/mako/mako/pyparser.py
@@ -1,5 +1,5 @@
 # mako/pyparser.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -18,22 +18,13 @@
 from mako import compat
 from mako import exceptions
 from mako import util
-from mako.compat import arg_stringname
 
-if compat.py3k:
-    # words that cannot be assigned to (notably
-    # smaller than the total keys in __builtins__)
-    reserved = set(["True", "False", "None", "print"])
+# words that cannot be assigned to (notably
+# smaller than the total keys in __builtins__)
+reserved = {"True", "False", "None", "print"}
 
-    # the "id" attribute on a function node
-    arg_id = operator.attrgetter("arg")
-else:
-    # words that cannot be assigned to (notably
-    # smaller than the total keys in __builtins__)
-    reserved = set(["True", "False", "None"])
-
-    # the "id" attribute on a function node
-    arg_id = operator.attrgetter("id")
+# the "id" attribute on a function node
+arg_id = operator.attrgetter("arg")
 
 util.restore__ast(_ast)
 
@@ -43,7 +34,7 @@
 
     try:
         return _ast_util.parse(code, "<unknown>", mode)
-    except Exception:
+    except Exception as e:
         raise exceptions.SyntaxException(
             "(%s) %s (%r)"
             % (
@@ -51,8 +42,8 @@
                 compat.exception_as(),
                 code[0:50],
             ),
-            **exception_kwargs
-        )
+            **exception_kwargs,
+        ) from e
 
 
 class FindIdentifiers(_ast_util.NodeVisitor):
@@ -85,18 +76,13 @@
             self.visit(n)
         self.in_assign_targets = in_a
 
-    if compat.py3k:
-
-        # ExceptHandler is in Python 2, but this block only works in
-        # Python 3 (and is required there)
-
-        def visit_ExceptHandler(self, node):
-            if node.name is not None:
-                self._add_declared(node.name)
-            if node.type is not None:
-                self.visit(node.type)
-            for statement in node.body:
-                self.visit(statement)
+    def visit_ExceptHandler(self, node):
+        if node.name is not None:
+            self._add_declared(node.name)
+        if node.type is not None:
+            self.visit(node.type)
+        for statement in node.body:
+            self.visit(statement)
 
     def visit_Lambda(self, node, *args):
         self._visit_function(node, True)
@@ -108,8 +94,7 @@
     def _expand_tuples(self, args):
         for arg in args:
             if isinstance(arg, _ast.Tuple):
-                for n in arg.elts:
-                    yield n
+                yield from arg.elts
             else:
                 yield arg
 
@@ -170,15 +155,15 @@
         for name in node.names:
             if name.asname is not None:
                 self._add_declared(name.asname)
+            elif name.name == "*":
+                raise exceptions.CompileException(
+                    "'import *' is not supported, since all identifier "
+                    "names must be explicitly declared.  Please use the "
+                    "form 'from <modulename> import <name1>, <name2>, "
+                    "...' instead.",
+                    **self.exception_kwargs,
+                )
             else:
-                if name.name == "*":
-                    raise exceptions.CompileException(
-                        "'import *' is not supported, since all identifier "
-                        "names must be explicitly declared.  Please use the "
-                        "form 'from <modulename> import <name1>, <name2>, "
-                        "...' instead.",
-                        **self.exception_kwargs
-                    )
                 self._add_declared(name.name)
 
 
@@ -213,27 +198,20 @@
 
         argnames = [arg_id(arg) for arg in node.args.args]
         if node.args.vararg:
-            argnames.append(arg_stringname(node.args.vararg))
+            argnames.append(node.args.vararg.arg)
 
-        if compat.py2k:
-            # kw-only args don't exist in Python 2
-            kwargnames = []
-        else:
-            kwargnames = [arg_id(arg) for arg in node.args.kwonlyargs]
+        kwargnames = [arg_id(arg) for arg in node.args.kwonlyargs]
         if node.args.kwarg:
-            kwargnames.append(arg_stringname(node.args.kwarg))
+            kwargnames.append(node.args.kwarg.arg)
         self.listener.argnames = argnames
         self.listener.defaults = node.args.defaults  # ast
         self.listener.kwargnames = kwargnames
-        if compat.py2k:
-            self.listener.kwdefaults = []
-        else:
-            self.listener.kwdefaults = node.args.kw_defaults
+        self.listener.kwdefaults = node.args.kw_defaults
         self.listener.varargs = node.args.vararg
         self.listener.kwargs = node.args.kwarg
 
 
-class ExpressionGenerator(object):
+class ExpressionGenerator:
     def __init__(self, astnode):
         self.generator = _ast_util.SourceGenerator(" " * 4)
         self.generator.visit(astnode)
diff --git a/third_party/mako/mako/mako/runtime.py b/third_party/mako/mako/mako/runtime.py
index 465908e6..6d7fa684 100644
--- a/third_party/mako/mako/mako/runtime.py
+++ b/third_party/mako/mako/mako/runtime.py
@@ -7,16 +7,16 @@
 """provides runtime services for templates, including Context,
 Namespace, and various helper functions."""
 
+import builtins
 import functools
 import sys
 
 from mako import compat
 from mako import exceptions
 from mako import util
-from mako.compat import compat_builtins
 
 
-class Context(object):
+class Context:
 
     """Provides runtime namespace, output buffer, and various
     callstacks for templates.
@@ -24,7 +24,7 @@
     See :ref:`runtime_toplevel` for detail on the usage of
     :class:`.Context`.
 
-     """
+    """
 
     def __init__(self, buffer, **data):
         self._buffer_stack = [buffer]
@@ -103,7 +103,7 @@
         if key in self._data:
             return self._data[key]
         else:
-            return compat_builtins.__dict__[key]
+            return builtins.__dict__[key]
 
     def _push_writer(self):
         """push a capturing buffer onto this Context and return
@@ -135,7 +135,7 @@
     def get(self, key, default=None):
         """Return a value from this :class:`.Context`."""
 
-        return self._data.get(key, compat_builtins.__dict__.get(key, default))
+        return self._data.get(key, builtins.__dict__.get(key, default))
 
     def write(self, string):
         """Write a string to this :class:`.Context` object's
@@ -216,7 +216,7 @@
         self.nextcaller = self.pop()
 
 
-class Undefined(object):
+class Undefined:
 
     """Represents an undefined value in a template.
 
@@ -240,7 +240,7 @@
 STOP_RENDERING = ""
 
 
-class LoopStack(object):
+class LoopStack:
 
     """a stack for LoopContexts that implements the context manager protocol
     to automatically pop off the top of the stack on context exit
@@ -280,7 +280,7 @@
         return iter(self._top)
 
 
-class LoopContext(object):
+class LoopContext:
 
     """A magic loop variable.
     Automatically accessible in any ``% for`` block.
@@ -339,14 +339,13 @@
         return bool(self.index % 2)
 
     def cycle(self, *values):
-        """Cycle through values as the loop progresses.
-        """
+        """Cycle through values as the loop progresses."""
         if not values:
             raise ValueError("You must provide values to cycle through")
         return values[self.index % len(values)]
 
 
-class _NSAttr(object):
+class _NSAttr:
     def __init__(self, parent):
         self.__parent = parent
 
@@ -360,22 +359,22 @@
         raise AttributeError(key)
 
 
-class Namespace(object):
+class Namespace:
 
     """Provides access to collections of rendering methods, which
-      can be local, from other templates, or from imported modules.
+    can be local, from other templates, or from imported modules.
 
-      To access a particular rendering method referenced by a
-      :class:`.Namespace`, use plain attribute access:
+    To access a particular rendering method referenced by a
+    :class:`.Namespace`, use plain attribute access:
 
-      .. sourcecode:: mako
+    .. sourcecode:: mako
 
-        ${some_namespace.foo(x, y, z)}
+      ${some_namespace.foo(x, y, z)}
 
-      :class:`.Namespace` also contains several built-in attributes
-      described here.
+    :class:`.Namespace` also contains several built-in attributes
+    described here.
 
-      """
+    """
 
     def __init__(
         self,
@@ -390,7 +389,7 @@
         self.context = context
         self.inherits = inherits
         if callables is not None:
-            self.callables = dict([(c.__name__, c) for c in callables])
+            self.callables = {c.__name__: c for c in callables}
 
     callables = ()
 
@@ -482,15 +481,14 @@
         key = (self, uri)
         if key in self.context.namespaces:
             return self.context.namespaces[key]
-        else:
-            ns = TemplateNamespace(
-                uri,
-                self.context._copy(),
-                templateuri=uri,
-                calling_uri=self._templateuri,
-            )
-            self.context.namespaces[key] = ns
-            return ns
+        ns = TemplateNamespace(
+            uri,
+            self.context._copy(),
+            templateuri=uri,
+            calling_uri=self._templateuri,
+        )
+        self.context.namespaces[key] = ns
+        return ns
 
     def get_template(self, uri):
         """Return a :class:`.Template` from the given ``uri``.
@@ -574,7 +572,7 @@
         self.context = context
         self.inherits = inherits
         if callables is not None:
-            self.callables = dict([(c.__name__, c) for c in callables])
+            self.callables = {c.__name__: c for c in callables}
 
         if templateuri is not None:
             self.template = _lookup_template(context, templateuri, calling_uri)
@@ -666,7 +664,7 @@
         self.context = context
         self.inherits = inherits
         if callables is not None:
-            self.callables = dict([(c.__name__, c) for c in callables])
+            self.callables = {c.__name__: c for c in callables}
 
         mod = __import__(module)
         for token in module.split(".")[1:]:
@@ -790,7 +788,7 @@
         except Exception:
             result = template.include_error_handler(ctx, compat.exception_as())
             if not result:
-                compat.reraise(*sys.exc_info())
+                raise
     else:
         callable_(ctx, **kwargs)
 
@@ -837,8 +835,10 @@
     uri = lookup.adjust_uri(uri, relativeto)
     try:
         return lookup.get_template(uri)
-    except exceptions.TopLevelLookupException:
-        raise exceptions.TemplateLookupException(str(compat.exception_as()))
+    except exceptions.TopLevelLookupException as e:
+        raise exceptions.TemplateLookupException(
+            str(compat.exception_as())
+        ) from e
 
 
 def _populate_self_namespace(context, template, self_ns=None):
@@ -862,14 +862,10 @@
     output of the given template and template callable."""
 
     if as_unicode:
-        buf = util.FastEncodingBuffer(as_unicode=True)
-    elif template.bytestring_passthrough:
-        buf = compat.StringIO()
+        buf = util.FastEncodingBuffer()
     else:
         buf = util.FastEncodingBuffer(
-            as_unicode=as_unicode,
-            encoding=template.output_encoding,
-            errors=template.encoding_errors,
+            encoding=template.output_encoding, errors=template.encoding_errors
         )
     context = Context(buf, **data)
     context._outputting_as_unicode = as_unicode
@@ -880,7 +876,7 @@
         callable_,
         context,
         *args,
-        **_kwargs_for_callable(callable_, data)
+        **_kwargs_for_callable(callable_, data),
     )
     return context._pop_buffer().getvalue()
 
@@ -951,13 +947,15 @@
     if template.error_handler:
         result = template.error_handler(context, error)
         if not result:
-            compat.reraise(*sys.exc_info())
+            tp, value, tb = sys.exc_info()
+            if value and tb:
+                raise value.with_traceback(tb)
+            else:
+                raise error
     else:
         error_template = exceptions.html_error_template()
         if context._outputting_as_unicode:
-            context._buffer_stack[:] = [
-                util.FastEncodingBuffer(as_unicode=True)
-            ]
+            context._buffer_stack[:] = [util.FastEncodingBuffer()]
         else:
             context._buffer_stack[:] = [
                 util.FastEncodingBuffer(
diff --git a/third_party/mako/mako/mako/template.py b/third_party/mako/mako/mako/template.py
index 5ed232046..bbbe73c 100644
--- a/third_party/mako/mako/mako/template.py
+++ b/third_party/mako/mako/mako/template.py
@@ -1,5 +1,5 @@
 # mako/template.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -25,7 +25,7 @@
 from mako.lexer import Lexer
 
 
-class Template(object):
+class Template:
 
     r"""Represents a compiled template.
 
@@ -53,17 +53,6 @@
      of return-valued ``%def``\ s "opt out" of that filtering via
      passing special attributes or objects.
 
-    :param bytestring_passthrough: When ``True``, and ``output_encoding`` is
-     set to ``None``, and :meth:`.Template.render` is used to render,
-     the `StringIO` or `cStringIO` buffer will be used instead of the
-     default "fast" buffer.   This allows raw bytestrings in the
-     output stream, such as in expressions, to pass straight
-     through to the buffer.  This flag is forced
-     to ``True`` if ``disable_unicode`` is also configured.
-
-     .. versionadded:: 0.4
-        Added to provide the same behavior as that of the previous series.
-
     :param cache_args: Dictionary of cache configuration arguments that
      will be passed to the :class:`.CacheImpl`.   See :ref:`caching_toplevel`.
 
@@ -94,9 +83,6 @@
     :param default_filters: List of string filter names that will
      be applied to all expressions.  See :ref:`filtering_default_filters`.
 
-    :param disable_unicode: Disables all awareness of Python Unicode
-     objects.  See :ref:`unicode_disabled`.
-
     :param enable_loop: When ``True``, enable the ``loop`` context variable.
      This can be set to ``False`` to support templates that may
      be making usage of the name "``loop``".   Individual templates can
@@ -255,9 +241,7 @@
         cache_url=None,
         module_filename=None,
         input_encoding=None,
-        disable_unicode=False,
         module_writer=None,
-        bytestring_passthrough=False,
         default_filters=None,
         buffer_filters=(),
         strict_undefined=False,
@@ -294,26 +278,12 @@
         self.input_encoding = input_encoding
         self.output_encoding = output_encoding
         self.encoding_errors = encoding_errors
-        self.disable_unicode = disable_unicode
-        self.bytestring_passthrough = bytestring_passthrough or disable_unicode
         self.enable_loop = enable_loop
         self.strict_undefined = strict_undefined
         self.module_writer = module_writer
 
-        if compat.py3k and disable_unicode:
-            raise exceptions.UnsupportedError(
-                "Mako for Python 3 does not " "support disabling Unicode"
-            )
-        elif output_encoding and disable_unicode:
-            raise exceptions.UnsupportedError(
-                "output_encoding must be set to "
-                "None when disable_unicode is used."
-            )
         if default_filters is None:
-            if compat.py3k or self.disable_unicode:
-                self.default_filters = ["str"]
-            else:
-                self.default_filters = ["unicode"]
+            self.default_filters = ["str"]
         else:
             self.default_filters = default_filters
         self.buffer_filters = buffer_filters
@@ -387,11 +357,7 @@
     ):
         self.cache_impl = cache_impl
         self.cache_enabled = cache_enabled
-        if cache_args:
-            self.cache_args = cache_args
-        else:
-            self.cache_args = {}
-
+        self.cache_args = cache_args or {}
         # transfer deprecated cache_* args
         if cache_type:
             self.cache_args["type"] = cache_type
@@ -463,7 +429,7 @@
 
         If the template specifies an output encoding, the string
         will be encoded accordingly, else the output is raw (raw
-        output uses `cStringIO` and can't handle multibyte
+        output uses `StringIO` and can't handle multibyte
         characters). A :class:`.Context` object is created corresponding
         to the given data. Arguments that are explicitly declared
         by this template's internal rendering method are also
@@ -517,17 +483,17 @@
 
     """A Template which is constructed given an existing Python module.
 
-       e.g.::
+    e.g.::
 
-            t = Template("this is a template")
-            f = file("mymodule.py", "w")
-            f.write(t.code)
-            f.close()
+         t = Template("this is a template")
+         f = file("mymodule.py", "w")
+         f.write(t.code)
+         f.close()
 
-            import mymodule
+         import mymodule
 
-            t = ModuleTemplate(mymodule)
-            print(t.render())
+         t = ModuleTemplate(mymodule)
+         print(t.render())
 
     """
 
@@ -541,8 +507,6 @@
         template_source=None,
         output_encoding=None,
         encoding_errors="strict",
-        disable_unicode=False,
-        bytestring_passthrough=False,
         format_exceptions=False,
         error_handler=None,
         lookup=None,
@@ -559,20 +523,8 @@
         self.input_encoding = module._source_encoding
         self.output_encoding = output_encoding
         self.encoding_errors = encoding_errors
-        self.disable_unicode = disable_unicode
-        self.bytestring_passthrough = bytestring_passthrough or disable_unicode
         self.enable_loop = module._enable_loop
 
-        if compat.py3k and disable_unicode:
-            raise exceptions.UnsupportedError(
-                "Mako for Python 3 does not " "support disabling Unicode"
-            )
-        elif output_encoding and disable_unicode:
-            raise exceptions.UnsupportedError(
-                "output_encoding must be set to "
-                "None when disable_unicode is used."
-            )
-
         self.module = module
         self.filename = template_filename
         ModuleInfo(
@@ -616,19 +568,18 @@
         self.include_error_handler = parent.include_error_handler
         self.enable_loop = parent.enable_loop
         self.lookup = parent.lookup
-        self.bytestring_passthrough = parent.bytestring_passthrough
 
     def get_def(self, name):
         return self.parent.get_def(name)
 
 
-class ModuleInfo(object):
+class ModuleInfo:
 
     """Stores information about a module currently loaded into
     memory, provides reverse lookups of template source, module
     source code based on a module's identifier.
 
-     """
+    """
 
     _modules = weakref.WeakValueDictionary()
 
@@ -658,9 +609,9 @@
             r"__M_BEGIN_METADATA(.+?)__M_END_METADATA", module_source, re.S
         ).group(1)
         source_map = json.loads(source_map)
-        source_map["line_map"] = dict(
-            (int(k), int(v)) for k, v in source_map["line_map"].items()
-        )
+        source_map["line_map"] = {
+            int(k): int(v) for k, v in source_map["line_map"].items()
+        }
         if full_line_map:
             f_line_map = source_map["full_line_map"] = []
             line_map = source_map["line_map"]
@@ -681,28 +632,25 @@
 
     @property
     def source(self):
-        if self.template_source is not None:
-            if self.module._source_encoding and not isinstance(
-                self.template_source, compat.text_type
-            ):
-                return self.template_source.decode(
-                    self.module._source_encoding
-                )
-            else:
-                return self.template_source
-        else:
+        if self.template_source is None:
             data = util.read_file(self.template_filename)
             if self.module._source_encoding:
                 return data.decode(self.module._source_encoding)
             else:
                 return data
 
+        elif self.module._source_encoding and not isinstance(
+            self.template_source, str
+        ):
+            return self.template_source.decode(self.module._source_encoding)
+        else:
+            return self.template_source
+
 
 def _compile(template, text, filename, generate_magic_comment):
     lexer = template.lexer_cls(
         text,
         filename,
-        disable_unicode=template.disable_unicode,
         input_encoding=template.input_encoding,
         preprocessor=template.preprocessor,
     )
@@ -717,7 +665,6 @@
         future_imports=template.future_imports,
         source_encoding=lexer.encoding,
         generate_magic_comment=generate_magic_comment,
-        disable_unicode=template.disable_unicode,
         strict_undefined=template.strict_undefined,
         enable_loop=template.enable_loop,
         reserved_names=template.reserved_names,
@@ -728,15 +675,10 @@
 def _compile_text(template, text, filename):
     identifier = template.module_id
     source, lexer = _compile(
-        template,
-        text,
-        filename,
-        generate_magic_comment=template.disable_unicode,
+        template, text, filename, generate_magic_comment=False
     )
 
     cid = identifier
-    if not compat.py3k and isinstance(cid, compat.text_type):
-        cid = cid.encode()
     module = types.ModuleType(cid)
     code = compile(source, cid, "exec")
 
@@ -750,7 +692,7 @@
         template, text, filename, generate_magic_comment=True
     )
 
-    if isinstance(source, compat.text_type):
+    if isinstance(source, str):
         source = source.encode(lexer.encoding or "ascii")
 
     if module_writer:
@@ -767,10 +709,7 @@
 
 
 def _get_module_info_from_callable(callable_):
-    if compat.py3k:
-        return _get_module_info(callable_.__globals__["__name__"])
-    else:
-        return _get_module_info(callable_.func_globals["__name__"])
+    return _get_module_info(callable_.__globals__["__name__"])
 
 
 def _get_module_info(filename):
diff --git a/third_party/mako/mako/mako/testing/__init__.py b/third_party/mako/mako/mako/testing/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/mako/mako/mako/testing/__init__.py
diff --git a/third_party/mako/mako/mako/testing/_config.py b/third_party/mako/mako/mako/testing/_config.py
new file mode 100644
index 0000000..4ee3d0a
--- /dev/null
+++ b/third_party/mako/mako/mako/testing/_config.py
@@ -0,0 +1,128 @@
+import configparser
+import dataclasses
+from dataclasses import dataclass
+from pathlib import Path
+from typing import Callable
+from typing import ClassVar
+from typing import Optional
+from typing import Union
+
+from .helpers import make_path
+
+
+class ConfigError(BaseException):
+    pass
+
+
+class MissingConfig(ConfigError):
+    pass
+
+
+class MissingConfigSection(ConfigError):
+    pass
+
+
+class MissingConfigItem(ConfigError):
+    pass
+
+
+class ConfigValueTypeError(ConfigError):
+    pass
+
+
+class _GetterDispatch:
+    def __init__(self, initialdata, default_getter: Callable):
+        self.default_getter = default_getter
+        self.data = initialdata
+
+    def get_fn_for_type(self, type_):
+        return self.data.get(type_, self.default_getter)
+
+    def get_typed_value(self, type_, name):
+        get_fn = self.get_fn_for_type(type_)
+        return get_fn(name)
+
+
+def _parse_cfg_file(filespec: Union[Path, str]):
+    cfg = configparser.ConfigParser()
+    try:
+        filepath = make_path(filespec, check_exists=True)
+    except FileNotFoundError as e:
+        raise MissingConfig(f"No config file found at {filespec}") from e
+    else:
+        with open(filepath, encoding="utf-8") as f:
+            cfg.read_file(f)
+        return cfg
+
+
+def _build_getter(cfg_obj, cfg_section, method, converter=None):
+    def caller(option, **kwargs):
+        try:
+            rv = getattr(cfg_obj, method)(cfg_section, option, **kwargs)
+        except configparser.NoSectionError as nse:
+            raise MissingConfigSection(
+                f"No config section named {cfg_section}"
+            ) from nse
+        except configparser.NoOptionError as noe:
+            raise MissingConfigItem(f"No config item for {option}") from noe
+        except ValueError as ve:
+            # ConfigParser.getboolean, .getint, .getfloat raise ValueError
+            # on bad types
+            raise ConfigValueTypeError(
+                f"Wrong value type for {option}"
+            ) from ve
+        else:
+            if converter:
+                try:
+                    rv = converter(rv)
+                except Exception as e:
+                    raise ConfigValueTypeError(
+                        f"Wrong value type for {option}"
+                    ) from e
+            return rv
+
+    return caller
+
+
+def _build_getter_dispatch(cfg_obj, cfg_section, converters=None):
+    converters = converters or {}
+
+    default_getter = _build_getter(cfg_obj, cfg_section, "get")
+
+    # support ConfigParser builtins
+    getters = {
+        int: _build_getter(cfg_obj, cfg_section, "getint"),
+        bool: _build_getter(cfg_obj, cfg_section, "getboolean"),
+        float: _build_getter(cfg_obj, cfg_section, "getfloat"),
+        str: default_getter,
+    }
+
+    # use ConfigParser.get and convert value
+    getters.update(
+        {
+            type_: _build_getter(
+                cfg_obj, cfg_section, "get", converter=converter_fn
+            )
+            for type_, converter_fn in converters.items()
+        }
+    )
+
+    return _GetterDispatch(getters, default_getter)
+
+
+@dataclass
+class ReadsCfg:
+    section_header: ClassVar[str]
+    converters: ClassVar[Optional[dict]] = None
+
+    @classmethod
+    def from_cfg_file(cls, filespec: Union[Path, str]):
+        cfg = _parse_cfg_file(filespec)
+        dispatch = _build_getter_dispatch(
+            cfg, cls.section_header, converters=cls.converters
+        )
+        kwargs = {
+            field.name: dispatch.get_typed_value(field.type, field.name)
+            for field in dataclasses.fields(cls)
+        }
+        return cls(**kwargs)
diff --git a/third_party/mako/mako/mako/testing/assertions.py b/third_party/mako/mako/mako/testing/assertions.py
new file mode 100644
index 0000000..14ea635
--- /dev/null
+++ b/third_party/mako/mako/mako/testing/assertions.py
@@ -0,0 +1,167 @@
+import contextlib
+import re
+import sys
+
+
+def eq_(a, b, msg=None):
+    """Assert a == b, with repr messaging on failure."""
+    assert a == b, msg or "%r != %r" % (a, b)
+
+
+def ne_(a, b, msg=None):
+    """Assert a != b, with repr messaging on failure."""
+    assert a != b, msg or "%r == %r" % (a, b)
+
+
+def in_(a, b, msg=None):
+    """Assert a in b, with repr messaging on failure."""
+    assert a in b, msg or "%r not in %r" % (a, b)
+
+
+def not_in(a, b, msg=None):
+    """Assert a in not b, with repr messaging on failure."""
+    assert a not in b, msg or "%r is in %r" % (a, b)
+
+
+def _assert_proper_exception_context(exception):
+    """assert that any exception we're catching does not have a __context__
+    without a __cause__, and that __suppress_context__ is never set.
+
+    Python 3 will report nested as exceptions as "during the handling of
+    error X, error Y occurred". That's not what we want to do. We want
+    these exceptions in a cause chain.
+
+    """
+
+    if (
+        exception.__context__ is not exception.__cause__
+        and not exception.__suppress_context__
+    ):
+        assert False, (
+            "Exception %r was correctly raised but did not set a cause, "
+            "within context %r as its cause."
+            % (exception, exception.__context__)
+        )
+
+
+def _assert_proper_cause_cls(exception, cause_cls):
+    """assert that any exception we're catching does not have a __context__
+    without a __cause__, and that __suppress_context__ is never set.
+
+    Python 3 will report nested as exceptions as "during the handling of
+    error X, error Y occurred". That's not what we want to do. We want
+    these exceptions in a cause chain.
+
+    """
+    assert isinstance(exception.__cause__, cause_cls), (
+        "Exception %r was correctly raised but has cause %r, which does not "
+        "have the expected cause type %r."
+        % (exception, exception.__cause__, cause_cls)
+    )
+
+
+def assert_raises(except_cls, callable_, *args, **kw):
+    return _assert_raises(except_cls, callable_, args, kw)
+
+
+def assert_raises_with_proper_context(except_cls, callable_, *args, **kw):
+    return _assert_raises(except_cls, callable_, args, kw, check_context=True)
+
+
+def assert_raises_with_given_cause(
+    except_cls, cause_cls, callable_, *args, **kw
+):
+    return _assert_raises(except_cls, callable_, args, kw, cause_cls=cause_cls)
+
+
+def assert_raises_message(except_cls, msg, callable_, *args, **kwargs):
+    return _assert_raises(except_cls, callable_, args, kwargs, msg=msg)
+
+
+def assert_raises_message_with_proper_context(
+    except_cls, msg, callable_, *args, **kwargs
+):
+    return _assert_raises(
+        except_cls, callable_, args, kwargs, msg=msg, check_context=True
+    )
+
+
+def assert_raises_message_with_given_cause(
+    except_cls, msg, cause_cls, callable_, *args, **kwargs
+):
+    return _assert_raises(
+        except_cls, callable_, args, kwargs, msg=msg, cause_cls=cause_cls
+    )
+
+
+def _assert_raises(
+    except_cls,
+    callable_,
+    args,
+    kwargs,
+    msg=None,
+    check_context=False,
+    cause_cls=None,
+):
+
+    with _expect_raises(except_cls, msg, check_context, cause_cls) as ec:
+        callable_(*args, **kwargs)
+    return ec.error
+
+
+class _ErrorContainer:
+    error = None
+
+
+@contextlib.contextmanager
+def _expect_raises(except_cls, msg=None, check_context=False, cause_cls=None):
+    ec = _ErrorContainer()
+    if check_context:
+        are_we_already_in_a_traceback = sys.exc_info()[0]
+    try:
+        yield ec
+        success = False
+    except except_cls as err:
+        ec.error = err
+        success = True
+        if msg is not None:
+            # I'm often pdbing here, and "err" above isn't
+            # in scope, so assign the string explicitly
+            error_as_string = str(err)
+            assert re.search(msg, error_as_string, re.UNICODE), "%r !~ %s" % (
+                msg,
+                error_as_string,
+            )
+        if cause_cls is not None:
+            _assert_proper_cause_cls(err, cause_cls)
+        if check_context and not are_we_already_in_a_traceback:
+            _assert_proper_exception_context(err)
+        print(str(err).encode("utf-8"))
+
+    # it's generally a good idea to not carry traceback objects outside
+    # of the except: block, but in this case especially we seem to have
+    # hit some bug in either python 3.10.0b2 or greenlet or both which
+    # this seems to fix:
+    # https://github.com/python-greenlet/greenlet/issues/242
+    del ec
+
+    # assert outside the block so it works for AssertionError too !
+    assert success, "Callable did not raise an exception"
+
+
+def expect_raises(except_cls, check_context=False):
+    return _expect_raises(except_cls, check_context=check_context)
+
+
+def expect_raises_message(except_cls, msg, check_context=False):
+    return _expect_raises(except_cls, msg=msg, check_context=check_context)
+
+
+def expect_raises_with_proper_context(except_cls, check_context=True):
+    return _expect_raises(except_cls, check_context=check_context)
+
+
+def expect_raises_message_with_proper_context(
+    except_cls, msg, check_context=True
+):
+    return _expect_raises(except_cls, msg=msg, check_context=check_context)
diff --git a/third_party/mako/mako/mako/testing/config.py b/third_party/mako/mako/mako/testing/config.py
new file mode 100644
index 0000000..b77d0c0
--- /dev/null
+++ b/third_party/mako/mako/mako/testing/config.py
@@ -0,0 +1,17 @@
+from dataclasses import dataclass
+from pathlib import Path
+
+from ._config import ReadsCfg
+from .helpers import make_path
+
+
+@dataclass
+class Config(ReadsCfg):
+    module_base: Path
+    template_base: Path
+
+    section_header = "mako_testing"
+    converters = {Path: make_path}
+
+
+config = Config.from_cfg_file("./setup.cfg")
diff --git a/third_party/mako/mako/mako/testing/exclusions.py b/third_party/mako/mako/mako/testing/exclusions.py
new file mode 100644
index 0000000..37b2d14a
--- /dev/null
+++ b/third_party/mako/mako/mako/testing/exclusions.py
@@ -0,0 +1,80 @@
+import pytest
+
+from mako.ext.beaker_cache import has_beaker
+from mako.util import update_wrapper
+
+
+try:
+    import babel.messages.extract as babel
+except ImportError:
+    babel = None
+
+
+try:
+    import lingua
+except ImportError:
+    lingua = None
+
+
+try:
+    import dogpile.cache  # noqa
+except ImportError:
+    has_dogpile_cache = False
+else:
+    has_dogpile_cache = True
+
+
+requires_beaker = pytest.mark.skipif(
+    not has_beaker, reason="Beaker is required for these tests."
+)
+
+
+requires_babel = pytest.mark.skipif(
+    babel is None, reason="babel not installed: skipping babelplugin test"
+)
+
+
+requires_lingua = pytest.mark.skipif(
+    lingua is None, reason="lingua not installed: skipping linguaplugin test"
+)
+
+
+requires_dogpile_cache = pytest.mark.skipif(
+    not has_dogpile_cache,
+    reason="dogpile.cache is required to run these tests",
+)
+
+
+def _pygments_version():
+    try:
+        import pygments
+
+        version = pygments.__version__
+    except:
+        version = "0"
+    return version
+
+
+requires_pygments_14 = pytest.mark.skipif(
+    _pygments_version() < "1.4", reason="Requires pygments 1.4 or greater"
+)
+
+
+# def requires_pygments_14(fn):
+
+#     return skip_if(
+#         lambda: version < "1.4", "Requires pygments 1.4 or greater"
+#     )(fn)
+
+
+def requires_no_pygments_exceptions(fn):
+    def go(*arg, **kw):
+        from mako import exceptions
+
+        exceptions._install_fallback()
+        try:
+            return fn(*arg, **kw)
+        finally:
+            exceptions._install_highlighting()
+
+    return update_wrapper(go, fn)
diff --git a/third_party/mako/mako/mako/testing/fixtures.py b/third_party/mako/mako/mako/testing/fixtures.py
new file mode 100644
index 0000000..c9379c0
--- /dev/null
+++ b/third_party/mako/mako/mako/testing/fixtures.py
@@ -0,0 +1,109 @@
+import os
+
+from mako.cache import CacheImpl
+from mako.cache import register_plugin
+from mako.template import Template
+from .assertions import eq_
+from .config import config
+
+
+class TemplateTest:
+    def _file_template(self, filename, **kw):
+        filepath = self._file_path(filename)
+        return Template(
+            uri=filename,
+            filename=filepath,
+            module_directory=config.module_base,
+            **kw,
+        )
+
+    def _file_path(self, filename):
+        name, ext = os.path.splitext(filename)
+        py3k_path = os.path.join(config.template_base, name + "_py3k" + ext)
+        if os.path.exists(py3k_path):
+            return py3k_path
+
+        return os.path.join(config.template_base, filename)
+
+    def _do_file_test(
+        self,
+        filename,
+        expected,
+        filters=None,
+        unicode_=True,
+        template_args=None,
+        **kw,
+    ):
+        t1 = self._file_template(filename, **kw)
+        self._do_test(
+            t1,
+            expected,
+            filters=filters,
+            unicode_=unicode_,
+            template_args=template_args,
+        )
+
+    def _do_memory_test(
+        self,
+        source,
+        expected,
+        filters=None,
+        unicode_=True,
+        template_args=None,
+        **kw,
+    ):
+        t1 = Template(text=source, **kw)
+        self._do_test(
+            t1,
+            expected,
+            filters=filters,
+            unicode_=unicode_,
+            template_args=template_args,
+        )
+
+    def _do_test(
+        self,
+        template,
+        expected,
+        filters=None,
+        template_args=None,
+        unicode_=True,
+    ):
+        if template_args is None:
+            template_args = {}
+        if unicode_:
+            output = template.render_unicode(**template_args)
+        else:
+            output = template.render(**template_args)
+
+        if filters:
+            output = filters(output)
+        eq_(output, expected)
+
+
+class PlainCacheImpl(CacheImpl):
+    """Simple memory cache impl so that tests which
+    use caching can run without beaker."""
+
+    def __init__(self, cache):
+        self.cache = cache
+        self.data = {}
+
+    def get_or_create(self, key, creation_function, **kw):
+        if key in self.data:
+            return self.data[key]
+        else:
+            self.data[key] = data = creation_function(**kw)
+            return data
+
+    def put(self, key, value, **kw):
+        self.data[key] = value
+
+    def get(self, key, **kw):
+        return self.data[key]
+
+    def invalidate(self, key, **kw):
+        del self.data[key]
+
+
+register_plugin("plain", __name__, "PlainCacheImpl")
diff --git a/third_party/mako/mako/mako/testing/helpers.py b/third_party/mako/mako/mako/testing/helpers.py
new file mode 100644
index 0000000..77cca36
--- /dev/null
+++ b/third_party/mako/mako/mako/testing/helpers.py
@@ -0,0 +1,67 @@
+import contextlib
+import pathlib
+from pathlib import Path
+import re
+import time
+from typing import Union
+from unittest import mock
+
+
+def flatten_result(result):
+    return re.sub(r"[\s\r\n]+", " ", result).strip()
+
+
+def result_lines(result):
+    return [
+        x.strip()
+        for x in re.split(r"\r?\n", re.sub(r" +", " ", result))
+        if x.strip() != ""
+    ]
+
+
+def make_path(
+    filespec: Union[Path, str],
+    make_absolute: bool = True,
+    check_exists: bool = False,
+) -> Path:
+    path = Path(filespec)
+    if make_absolute:
+        path = path.resolve(strict=check_exists)
+    if check_exists and (not path.exists()):
+        raise FileNotFoundError(f"No file or directory at {filespec}")
+    return path
+
+
+def _unlink_path(path, missing_ok=False):
+    # Replicate 3.8+ functionality in 3.7
+    cm = contextlib.nullcontext()
+    if missing_ok:
+        cm = contextlib.suppress(FileNotFoundError)
+
+    with cm:
+        path.unlink()
+
+
+def replace_file_with_dir(pathspec):
+    path = pathlib.Path(pathspec)
+    _unlink_path(path, missing_ok=True)
+    path.mkdir(exist_ok=True)
+    return path
+
+
+def file_with_template_code(filespec):
+    with open(filespec, "w") as f:
+        f.write(
+            """
+i am an artificial template just for you
+"""
+        )
+    return filespec
+
+
+@contextlib.contextmanager
+def rewind_compile_time(hours=1):
+    rewound = time.time() - (hours * 3_600)
+    with mock.patch("mako.codegen.time") as codegen_time:
+        codegen_time.time.return_value = rewound
+        yield
diff --git a/third_party/mako/mako/mako/util.py b/third_party/mako/mako/mako/util.py
index 16e3c72..74c8b9e 100644
--- a/third_party/mako/mako/mako/util.py
+++ b/third_party/mako/mako/mako/util.py
@@ -1,10 +1,8 @@
 # mako/util.py
-# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
+# Copyright 2006-2021 the Mako authors and contributors <see AUTHORS file>
 #
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
-from __future__ import absolute_import
-
 from ast import parse
 import codecs
 import collections
@@ -13,7 +11,7 @@
 import re
 import timeit
 
-from mako import compat
+from .compat import importlib_metadata_get
 
 
 def update_wrapper(decorated, fn):
@@ -22,7 +20,7 @@
     return decorated
 
 
-class PluginLoader(object):
+class PluginLoader:
     def __init__(self, group):
         self.group = group
         self.impls = {}
@@ -30,18 +28,17 @@
     def load(self, name):
         if name in self.impls:
             return self.impls[name]()
-        else:
-            import pkg_resources
 
-            for impl in pkg_resources.iter_entry_points(self.group, name):
+        for impl in importlib_metadata_get(self.group):
+            if impl.name == name:
                 self.impls[name] = impl.load
                 return impl.load()
-            else:
-                from mako import exceptions
 
-                raise exceptions.RuntimeException(
-                    "Can't load plugin %s %s" % (self.group, name)
-                )
+        from mako import exceptions
+
+        raise exceptions.RuntimeException(
+            "Can't load plugin %s %s" % (self.group, name)
+        )
 
     def register(self, name, modulepath, objname):
         def load():
@@ -61,7 +58,7 @@
     while not os.path.exists(dir_):
         try:
             tries += 1
-            os.makedirs(dir_, compat.octal("0775"))
+            os.makedirs(dir_, 0o755)
         except:
             if tries > 5:
                 raise
@@ -76,7 +73,7 @@
         return x
 
 
-class memoized_property(object):
+class memoized_property:
 
     """A read-only @property that is only evaluated once."""
 
@@ -92,7 +89,7 @@
         return result
 
 
-class memoized_instancemethod(object):
+class memoized_instancemethod:
 
     """Decorate a method memoize its return value.
 
@@ -140,19 +137,15 @@
         return x
 
 
-class FastEncodingBuffer(object):
+class FastEncodingBuffer:
 
     """a very rudimentary buffer that is faster than StringIO,
-    but doesn't crash on unicode data like cStringIO."""
+    and supports unicode data."""
 
-    def __init__(self, encoding=None, errors="strict", as_unicode=False):
+    def __init__(self, encoding=None, errors="strict"):
         self.data = collections.deque()
         self.encoding = encoding
-        if as_unicode:
-            self.delim = compat.u("")
-        else:
-            self.delim = ""
-        self.as_unicode = as_unicode
+        self.delim = ""
         self.errors = errors
         self.write = self.data.append
 
@@ -179,7 +172,7 @@
     is inexact.
     """
 
-    class _Item(object):
+    class _Item:
         def __init__(self, key, value):
             self.key = key
             self.value = value
@@ -203,9 +196,8 @@
     def setdefault(self, key, value):
         if key in self:
             return self[key]
-        else:
-            self[key] = value
-            return value
+        self[key] = value
+        return value
 
     def __setitem__(self, key, value):
         item = dict.get(self, key)
@@ -295,7 +287,7 @@
     """
     keys = list(d.keys())
     keys.sort()
-    return "{" + ", ".join(["%r: %r" % (k, d[k]) for k in keys]) + "}"
+    return "{" + ", ".join("%r: %r" % (k, d[k]) for k in keys) + "}"
 
 
 def restore__ast(_ast):
@@ -308,7 +300,7 @@
     m = compile(
         """\
 def foo(): pass
-class Bar(object): pass
+class Bar: pass
 if False: pass
 baz = 'mako'
 1 + 2 - 3 * 4 / 5
@@ -380,12 +372,8 @@
 
 
 def read_file(path, mode="rb"):
-    fp = open(path, mode)
-    try:
-        data = fp.read()
-        return data
-    finally:
-        fp.close()
+    with open(path, mode) as fp:
+        return fp.read()
 
 
 def read_python_file(path):
diff --git a/third_party/mako/mako/pyproject.toml b/third_party/mako/mako/pyproject.toml
new file mode 100644
index 0000000..b3193b91
--- /dev/null
+++ b/third_party/mako/mako/pyproject.toml
@@ -0,0 +1,7 @@
+[build-system]
+build-backend = 'setuptools.build_meta'
+requires = ['setuptools >= 47', 'wheel']
+
+[tool.black]
+line-length = 79
+target-version = ['py37']
diff --git a/third_party/mako/mako/setup.cfg b/third_party/mako/mako/setup.cfg
index 5ec681bb..b7272db 100644
--- a/third_party/mako/mako/setup.cfg
+++ b/third_party/mako/mako/setup.cfg
@@ -1,3 +1,69 @@
+[metadata]
+name = Mako
+version = attr: mako.__version__
+description = A super-fast templating language that borrows the best ideas from the existing templating languages.
+long_description = file: README.rst
+long_description_content_type = text/x-rst
+url = https://www.makotemplates.org/
+author = Mike Bayer
+author_email = mike@zzzcomputing.com
+license = MIT
+license_file = LICENSE
+classifiers = 
+	Development Status :: 5 - Production/Stable
+	License :: OSI Approved :: MIT License
+	Environment :: Web Environment
+	Intended Audience :: Developers
+	Programming Language :: Python
+	Programming Language :: Python :: 3
+	Programming Language :: Python :: 3.7
+	Programming Language :: Python :: 3.8
+	Programming Language :: Python :: 3.9
+	Programming Language :: Python :: 3.10
+	Programming Language :: Python :: Implementation :: CPython
+	Programming Language :: Python :: Implementation :: PyPy
+	Topic :: Internet :: WWW/HTTP :: Dynamic Content
+project_urls = 
+	Documentation=https://docs.makotemplates.org
+	Issue Tracker=https://github.com/sqlalchemy/mako
+
+[options]
+packages = find:
+python_requires = >=3.7
+zip_safe = false
+install_requires = 
+	MarkupSafe >= 0.9.2
+	importlib-metadata;python_version<"3.8"
+
+[options.packages.find]
+exclude = 
+	test*
+	examples*
+
+[options.extras_require]
+testing = 
+	pytest
+babel = 
+	Babel
+lingua = 
+	lingua
+
+[options.entry_points]
+python.templating.engines = 
+	mako = mako.ext.turbogears:TGPlugin
+pygments.lexers = 
+	mako = mako.ext.pygmentplugin:MakoLexer
+	html+mako = mako.ext.pygmentplugin:MakoHtmlLexer
+	xml+mako = mako.ext.pygmentplugin:MakoXmlLexer
+	js+mako = mako.ext.pygmentplugin:MakoJavascriptLexer
+	css+mako = mako.ext.pygmentplugin:MakoCssLexer
+babel.extractors = 
+	mako = mako.ext.babelplugin:extract [babel]
+lingua.extractors = 
+	mako = mako.ext.linguaplugin:LinguaMakoExtractor [lingua]
+console_scripts = 
+	mako-render = mako.cmd:cmdline
+
 [egg_info]
 tag_build = 
 tag_date = 0
@@ -5,10 +71,11 @@
 [tool:pytest]
 addopts = --tb native -v -r fxX -W error
 python_files = test/*test_*.py
+python_classes = *Test
 
 [upload]
 sign = 1
-identity = C4DAFEE1
+identity = 4BFDF51E
 
 [flake8]
 show-source = true
@@ -24,6 +91,7 @@
 import-order-style = google
 application-import-names = mako,test
 
-[bdist_wheel]
-universal = 1
+[mako_testing]
+module_base = ./test/templates/modules
+template_base = ./test/templates/
 
diff --git a/third_party/mako/mako/setup.py b/third_party/mako/mako/setup.py
index cc5127d..6068493 100644
--- a/third_party/mako/mako/setup.py
+++ b/third_party/mako/mako/setup.py
@@ -1,99 +1,3 @@
-import os
-import re
-import sys
-
-from setuptools import find_packages
 from setuptools import setup
-from setuptools.command.test import test as TestCommand
 
-v = open(os.path.join(os.path.dirname(__file__), "mako", "__init__.py"))
-VERSION = (
-    re.compile(r".*__version__ = [\"'](.*?)[\"']", re.S)
-    .match(v.read())
-    .group(1)
-)
-v.close()
-
-readme = os.path.join(os.path.dirname(__file__), "README.rst")
-
-install_requires = ["MarkupSafe>=0.9.2"]
-
-
-class UseTox(TestCommand):
-    RED = 31
-    RESET_SEQ = "\033[0m"
-    BOLD_SEQ = "\033[1m"
-    COLOR_SEQ = "\033[1;%dm"
-
-    def run_tests(self):
-        sys.stderr.write(
-            "%s%spython setup.py test is deprecated by PyPA.  Please invoke "
-            "'tox' with no arguments for a basic test run.\n%s"
-            % (self.COLOR_SEQ % self.RED, self.BOLD_SEQ, self.RESET_SEQ)
-        )
-        sys.exit(1)
-
-
-setup(
-    name="Mako",
-    version=VERSION,
-    description="A super-fast templating language that borrows the \
- best ideas from the existing templating languages.",
-    long_description=open(readme).read(),
-    python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "License :: OSI Approved :: MIT License",
-        "Environment :: Web Environment",
-        "Intended Audience :: Developers",
-        "Programming Language :: Python",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.6",
-        "Programming Language :: Python :: 3.7",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: Implementation :: CPython",
-        "Programming Language :: Python :: Implementation :: PyPy",
-        "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
-    ],
-    keywords="templates",
-    author="Mike Bayer",
-    author_email="mike@zzzcomputing.com",
-    url="https://www.makotemplates.org/",
-    project_urls={
-        "Documentation": "https://docs.makotemplates.org",
-        "Issue Tracker": "https://github.com/sqlalchemy/mako",
-    },
-    license="MIT",
-    packages=find_packages(".", exclude=["examples*", "test*"]),
-    cmdclass={"test": UseTox},
-    zip_safe=False,
-    install_requires=install_requires,
-    entry_points="""
-      [python.templating.engines]
-      mako = mako.ext.turbogears:TGPlugin
-
-      [pygments.lexers]
-      mako = mako.ext.pygmentplugin:MakoLexer
-      html+mako = mako.ext.pygmentplugin:MakoHtmlLexer
-      xml+mako = mako.ext.pygmentplugin:MakoXmlLexer
-      js+mako = mako.ext.pygmentplugin:MakoJavascriptLexer
-      css+mako = mako.ext.pygmentplugin:MakoCssLexer
-
-      [babel.extractors]
-      mako = mako.ext.babelplugin:extract [babel]
-
-      [lingua.extractors]
-      mako = mako.ext.linguaplugin:LinguaMakoExtractor [lingua]
-
-      [console_scripts]
-      mako-render = mako.cmd:cmdline
-      """,
-    extras_require={
-        'babel': [
-            'Babel',
-        ],
-        'lingua': [
-            'lingua',
-        ],
-    },
-)
+setup()
diff --git a/third_party/mako/mako/test/__init__.py b/third_party/mako/mako/test/__init__.py
index 1770962..e69de29 100644
--- a/third_party/mako/mako/test/__init__.py
+++ b/third_party/mako/mako/test/__init__.py
@@ -1,211 +0,0 @@
-import contextlib
-import os
-import re
-import unittest
-
-from mako import compat
-from mako.cache import CacheImpl
-from mako.cache import register_plugin
-from mako.compat import py3k
-from mako.template import Template
-from mako.util import update_wrapper
-
-template_base = os.path.join(os.path.dirname(__file__), "templates")
-module_base = os.path.join(template_base, "modules")
-
-
-class TemplateTest(unittest.TestCase):
-    def _file_template(self, filename, **kw):
-        filepath = self._file_path(filename)
-        return Template(
-            uri=filename, filename=filepath, module_directory=module_base, **kw
-        )
-
-    def _file_path(self, filename):
-        name, ext = os.path.splitext(filename)
-
-        if py3k:
-            py3k_path = os.path.join(template_base, name + "_py3k" + ext)
-            if os.path.exists(py3k_path):
-                return py3k_path
-
-        return os.path.join(template_base, filename)
-
-    def _do_file_test(
-        self,
-        filename,
-        expected,
-        filters=None,
-        unicode_=True,
-        template_args=None,
-        **kw
-    ):
-        t1 = self._file_template(filename, **kw)
-        self._do_test(
-            t1,
-            expected,
-            filters=filters,
-            unicode_=unicode_,
-            template_args=template_args,
-        )
-
-    def _do_memory_test(
-        self,
-        source,
-        expected,
-        filters=None,
-        unicode_=True,
-        template_args=None,
-        **kw
-    ):
-        t1 = Template(text=source, **kw)
-        self._do_test(
-            t1,
-            expected,
-            filters=filters,
-            unicode_=unicode_,
-            template_args=template_args,
-        )
-
-    def _do_test(
-        self,
-        template,
-        expected,
-        filters=None,
-        template_args=None,
-        unicode_=True,
-    ):
-        if template_args is None:
-            template_args = {}
-        if unicode_:
-            output = template.render_unicode(**template_args)
-        else:
-            output = template.render(**template_args)
-
-        if filters:
-            output = filters(output)
-        eq_(output, expected)
-
-
-def eq_(a, b, msg=None):
-    """Assert a == b, with repr messaging on failure."""
-    assert a == b, msg or "%r != %r" % (a, b)
-
-
-def teardown():
-    import shutil
-
-    shutil.rmtree(module_base, True)
-
-
-if py3k:
-    from unittest import mock  # noqa
-else:
-    import mock  # noqa
-
-
-@contextlib.contextmanager
-def raises(except_cls, message=None):
-    try:
-        yield
-        success = False
-    except except_cls as e:
-        if message:
-            assert re.search(
-                message, compat.text_type(e), re.UNICODE
-            ), "%r !~ %s" % (message, e)
-            print(compat.text_type(e).encode("utf-8"))
-        success = True
-
-    # assert outside the block so it works for AssertionError too !
-    assert success, "Callable did not raise an exception"
-
-
-def assert_raises(except_cls, callable_, *args, **kw):
-    with raises(except_cls):
-        return callable_(*args, **kw)
-
-
-def assert_raises_message(except_cls, msg, callable_, *args, **kwargs):
-    with raises(except_cls, msg):
-        return callable_(*args, **kwargs)
-
-
-def skip_if(predicate, reason=None):
-    """Skip a test if predicate is true."""
-    reason = reason or predicate.__name__
-
-    def decorate(fn):
-        fn_name = fn.__name__
-
-        def maybe(*args, **kw):
-            if predicate():
-                msg = "'%s' skipped: %s" % (fn_name, reason)
-                raise unittest.SkipTest(msg)
-            else:
-                return fn(*args, **kw)
-
-        return update_wrapper(maybe, fn)
-
-    return decorate
-
-
-def requires_python_3(fn):
-    return skip_if(lambda: not py3k, "Requires Python 3.xx")(fn)
-
-
-def requires_python_2(fn):
-    return skip_if(lambda: py3k, "Requires Python 2.xx")(fn)
-
-
-def requires_pygments_14(fn):
-    try:
-        import pygments
-
-        version = pygments.__version__
-    except:
-        version = "0"
-    return skip_if(
-        lambda: version < "1.4", "Requires pygments 1.4 or greater"
-    )(fn)
-
-
-def requires_no_pygments_exceptions(fn):
-    def go(*arg, **kw):
-        from mako import exceptions
-
-        exceptions._install_fallback()
-        try:
-            return fn(*arg, **kw)
-        finally:
-            exceptions._install_highlighting()
-
-    return update_wrapper(go, fn)
-
-
-class PlainCacheImpl(CacheImpl):
-    """Simple memory cache impl so that tests which
-    use caching can run without beaker.  """
-
-    def __init__(self, cache):
-        self.cache = cache
-        self.data = {}
-
-    def get_or_create(self, key, creation_function, **kw):
-        if key in self.data:
-            return self.data[key]
-        else:
-            self.data[key] = data = creation_function(**kw)
-            return data
-
-    def put(self, key, value, **kw):
-        self.data[key] = value
-
-    def get(self, key, **kw):
-        return self.data[key]
-
-    def invalidate(self, key, **kw):
-        del self.data[key]
-
-
-register_plugin("plain", __name__, "PlainCacheImpl")
diff --git a/third_party/mako/mako/test/ext/test_babelplugin.py b/third_party/mako/mako/test/ext/test_babelplugin.py
index ca12444..de3e461 100644
--- a/third_party/mako/mako/test/ext/test_babelplugin.py
+++ b/third_party/mako/mako/test/ext/test_babelplugin.py
@@ -1,123 +1,103 @@
 import io
 import os
-import unittest
 
-from mako import compat
-from .. import skip_if
-from .. import template_base
-from .. import TemplateTest
-
-try:
-    import babel.messages.extract as babel
-    from mako.ext.babelplugin import extract
-
-except ImportError:
-    babel = None
+from mako.ext.babelplugin import extract
+from mako.testing.assertions import eq_
+from mako.testing.config import config
+from mako.testing.exclusions import requires_babel
+from mako.testing.fixtures import TemplateTest
 
 
-def skip():
-    return skip_if(
-        lambda: not babel, "babel not installed: skipping babelplugin test"
-    )
-
-
-class Test_extract(unittest.TestCase):
-    @skip()
+@requires_babel
+class PluginExtractTest:
     def test_parse_python_expression(self):
-        input_ = io.BytesIO(compat.b('<p>${_("Message")}</p>'))
+        input_ = io.BytesIO(b'<p>${_("Message")}</p>')
         messages = list(extract(input_, ["_"], [], {}))
-        self.assertEqual(messages, [(1, "_", compat.u("Message"), [])])
+        eq_(messages, [(1, "_", ("Message"), [])])
 
-    @skip()
     def test_python_gettext_call(self):
-        input_ = io.BytesIO(compat.b('<p>${_("Message")}</p>'))
+        input_ = io.BytesIO(b'<p>${_("Message")}</p>')
         messages = list(extract(input_, ["_"], [], {}))
-        self.assertEqual(messages, [(1, "_", compat.u("Message"), [])])
+        eq_(messages, [(1, "_", ("Message"), [])])
 
-    @skip()
     def test_translator_comment(self):
         input_ = io.BytesIO(
-            compat.b(
-                """
+            b"""
         <p>
           ## TRANSLATORS: This is a comment.
           ${_("Message")}
         </p>"""
-            )
         )
         messages = list(extract(input_, ["_"], ["TRANSLATORS:"], {}))
-        self.assertEqual(
+        eq_(
             messages,
             [
                 (
                     4,
                     "_",
-                    compat.u("Message"),
-                    [compat.u("TRANSLATORS: This is a comment.")],
+                    ("Message"),
+                    [("TRANSLATORS: This is a comment.")],
                 )
             ],
         )
 
 
-class ExtractMakoTestCase(TemplateTest):
-    @skip()
+@requires_babel
+class MakoExtractTest(TemplateTest):
     def test_extract(self):
-        mako_tmpl = open(os.path.join(template_base, "gettext.mako"))
-        self.addCleanup(mako_tmpl.close)
-        messages = list(
-            extract(
-                mako_tmpl,
-                {"_": None, "gettext": None, "ungettext": (1, 2)},
-                ["TRANSLATOR:"],
-                {},
+        with open(
+            os.path.join(config.template_base, "gettext.mako")
+        ) as mako_tmpl:
+            messages = list(
+                extract(
+                    mako_tmpl,
+                    {"_": None, "gettext": None, "ungettext": (1, 2)},
+                    ["TRANSLATOR:"],
+                    {},
+                )
             )
-        )
-        expected = [
-            (1, "_", "Page arg 1", []),
-            (1, "_", "Page arg 2", []),
-            (10, "gettext", "Begin", []),
-            (14, "_", "Hi there!", ["TRANSLATOR: Hi there!"]),
-            (19, "_", "Hello", []),
-            (22, "_", "Welcome", []),
-            (25, "_", "Yo", []),
-            (36, "_", "The", ["TRANSLATOR: Ensure so and", "so, thanks"]),
-            (36, "ungettext", ("bunny", "bunnies", None), []),
-            (41, "_", "Goodbye", ["TRANSLATOR: Good bye"]),
-            (44, "_", "Babel", []),
-            (45, "ungettext", ("hella", "hellas", None), []),
-            (62, "_", "The", ["TRANSLATOR: Ensure so and", "so, thanks"]),
-            (62, "ungettext", ("bunny", "bunnies", None), []),
-            (68, "_", "Goodbye, really!", ["TRANSLATOR: HTML comment"]),
-            (71, "_", "P.S. byebye", []),
-            (77, "_", "Top", []),
-            (83, "_", "foo", []),
-            (83, "_", "hoho", []),
-            (85, "_", "bar", []),
-            (92, "_", "Inside a p tag", ["TRANSLATOR: <p> tag is ok?"]),
-            (95, "_", "Later in a p tag", ["TRANSLATOR: also this"]),
-            (99, "_", "No action at a distance.", []),
-        ]
-        self.assertEqual(expected, messages)
+            expected = [
+                (1, "_", "Page arg 1", []),
+                (1, "_", "Page arg 2", []),
+                (10, "gettext", "Begin", []),
+                (14, "_", "Hi there!", ["TRANSLATOR: Hi there!"]),
+                (19, "_", "Hello", []),
+                (22, "_", "Welcome", []),
+                (25, "_", "Yo", []),
+                (36, "_", "The", ["TRANSLATOR: Ensure so and", "so, thanks"]),
+                (36, "ungettext", ("bunny", "bunnies", None), []),
+                (41, "_", "Goodbye", ["TRANSLATOR: Good bye"]),
+                (44, "_", "Babel", []),
+                (45, "ungettext", ("hella", "hellas", None), []),
+                (62, "_", "The", ["TRANSLATOR: Ensure so and", "so, thanks"]),
+                (62, "ungettext", ("bunny", "bunnies", None), []),
+                (68, "_", "Goodbye, really!", ["TRANSLATOR: HTML comment"]),
+                (71, "_", "P.S. byebye", []),
+                (77, "_", "Top", []),
+                (83, "_", "foo", []),
+                (83, "_", "hoho", []),
+                (85, "_", "bar", []),
+                (92, "_", "Inside a p tag", ["TRANSLATOR: <p> tag is ok?"]),
+                (95, "_", "Later in a p tag", ["TRANSLATOR: also this"]),
+                (99, "_", "No action at a distance.", []),
+            ]
+        eq_(expected, messages)
 
-    @skip()
     def test_extract_utf8(self):
-        mako_tmpl = open(
-            os.path.join(template_base, "gettext_utf8.mako"), "rb"
-        )
-        self.addCleanup(mako_tmpl.close)
-        message = next(
-            extract(mako_tmpl, set(["_", None]), [], {"encoding": "utf-8"})
-        )
-        assert message == (1, "_", u"K\xf6ln", [])
+        with open(
+            os.path.join(config.template_base, "gettext_utf8.mako"), "rb"
+        ) as mako_tmpl:
+            message = next(
+                extract(mako_tmpl, {"_", None}, [], {"encoding": "utf-8"})
+            )
+            assert message == (1, "_", "K\xf6ln", [])
 
-    @skip()
     def test_extract_cp1251(self):
-        mako_tmpl = open(
-            os.path.join(template_base, "gettext_cp1251.mako"), "rb"
-        )
-        self.addCleanup(mako_tmpl.close)
-        message = next(
-            extract(mako_tmpl, set(["_", None]), [], {"encoding": "cp1251"})
-        )
-        # "test" in Rusian. File encoding is cp1251 (aka "windows-1251")
-        assert message == (1, "_", u"\u0442\u0435\u0441\u0442", [])
+        with open(
+            os.path.join(config.template_base, "gettext_cp1251.mako"), "rb"
+        ) as mako_tmpl:
+            message = next(
+                extract(mako_tmpl, {"_", None}, [], {"encoding": "cp1251"})
+            )
+            # "test" in Rusian. File encoding is cp1251 (aka "windows-1251")
+            assert message == (1, "_", "\u0442\u0435\u0441\u0442", [])
diff --git a/third_party/mako/mako/test/ext/test_linguaplugin.py b/third_party/mako/mako/test/ext/test_linguaplugin.py
index a563969..ae24f675 100644
--- a/third_party/mako/mako/test/ext/test_linguaplugin.py
+++ b/third_party/mako/mako/test/ext/test_linguaplugin.py
@@ -1,40 +1,38 @@
 import os
 
-from .. import skip_if
-from .. import template_base
-from .. import TemplateTest
+import pytest
 
-try:
-    import lingua
-except:
-    lingua = None
-
-if lingua is not None:
-    from mako.ext.linguaplugin import LinguaMakoExtractor
-    from lingua.extractors import register_extractors
+from mako.ext.linguaplugin import LinguaMakoExtractor
+from mako.testing.assertions import eq_
+from mako.testing.config import config
+from mako.testing.exclusions import requires_lingua
+from mako.testing.fixtures import TemplateTest
 
 
 class MockOptions:
     keywords = []
     domain = None
+    comment_tag = True
 
 
-def skip():
-    return skip_if(
-        lambda: not lingua, "lingua not installed: skipping linguaplugin test"
-    )
+@requires_lingua
+class MakoExtractTest(TemplateTest):
+    @pytest.fixture(autouse=True)
+    def register_lingua_extractors(self):
+        from lingua.extractors import register_extractors
 
-
-class ExtractMakoTestCase(TemplateTest):
-    @skip()
-    def test_extract(self):
         register_extractors()
+
+    def test_extract(self):
         plugin = LinguaMakoExtractor({"comment-tags": "TRANSLATOR"})
         messages = list(
-            plugin(os.path.join(template_base, "gettext.mako"), MockOptions())
+            plugin(
+                os.path.join(config.template_base, "gettext.mako"),
+                MockOptions(),
+            )
         )
         msgids = [(m.msgid, m.msgid_plural) for m in messages]
-        self.assertEqual(
+        eq_(
             msgids,
             [
                 ("Page arg 1", None),
@@ -54,9 +52,9 @@
                 ("Goodbye, really!", None),
                 ("P.S. byebye", None),
                 ("Top", None),
-                (u"foo", None),
+                ("foo", None),
                 ("hoho", None),
-                (u"bar", None),
+                ("bar", None),
                 ("Inside a p tag", None),
                 ("Later in a p tag", None),
                 ("No action at a distance.", None),
diff --git a/third_party/mako/mako/test/module_to_import.py b/third_party/mako/mako/test/module_to_import.py
new file mode 100644
index 0000000..11ffb986
--- /dev/null
+++ b/third_party/mako/mako/test/module_to_import.py
@@ -0,0 +1,2 @@
+def some_function():
+    pass
diff --git a/third_party/mako/mako/test/templates/chs_unicode.html b/third_party/mako/mako/test/templates/chs_unicode.html
deleted file mode 100644
index 7b897e90..0000000
--- a/third_party/mako/mako/test/templates/chs_unicode.html
+++ /dev/null
@@ -1,11 +0,0 @@
-## -*- coding:utf-8 -*-
-<%
- msg = u'新中国的主席'
-%>
-
-<%def name="welcome(who, place=u'北京')">
-Welcome ${who} to ${place}.
-</%def>
-
-${name} 是 ${msg}<br/>
-${welcome(u'你')}
diff --git a/third_party/mako/mako/test/templates/foo/modtest.html.py b/third_party/mako/mako/test/templates/foo/modtest.html.py
index e6fc8d8..c35420f 100644
--- a/third_party/mako/mako/test/templates/foo/modtest.html.py
+++ b/third_party/mako/mako/test/templates/foo/modtest.html.py
@@ -1,25 +1,25 @@
-from mako import runtime, filters, cache
+from mako import cache
+from mako import runtime
+
 UNDEFINED = runtime.UNDEFINED
 __M_dict_builtin = dict
 __M_locals_builtin = locals
 _magic_number = 5
 _modified_time = 1267565427.7968459
-_template_filename='/Users/classic/dev/mako/test/templates/modtest.html'
-_template_uri='/modtest.html'
-_template_cache=cache.Cache(__name__, _modified_time)
-_source_encoding=None
+_template_filename = "/Users/classic/dev/mako/test/templates/modtest.html"
+_template_uri = "/modtest.html"
+_template_cache = cache.Cache(__name__, _modified_time)
+_source_encoding = None
 _exports = []
 
 
-def render_body(context,**pageargs):
+def render_body(context, **pageargs):
     context.caller_stack._push_frame()
     try:
         __M_locals = __M_dict_builtin(pageargs=pageargs)
         __M_writer = context.writer()
         # SOURCE LINE 1
-        __M_writer('this is a test')
-        return ''
+        __M_writer("this is a test")
+        return ""
     finally:
         context.caller_stack._pop_frame()
-
-
diff --git a/third_party/mako/mako/test/templates/read_unicode.html b/third_party/mako/mako/test/templates/read_unicode.html
deleted file mode 100644
index 50f00c3..0000000
--- a/third_party/mako/mako/test/templates/read_unicode.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<% 
-try:
-    file_content = open(path)
-except:
-    raise "Should never execute here"
-doc_content = ''.join(file_content.readlines())
-file_content.close()
-%>
-
-${unicode(doc_content, encoding='utf-8')}
diff --git a/third_party/mako/mako/test/templates/runtimeerr.html b/third_party/mako/mako/test/templates/runtimeerr.html
deleted file mode 100644
index 6b36b956..0000000
--- a/third_party/mako/mako/test/templates/runtimeerr.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<%
-    print y
-    y = 10
-%>
\ No newline at end of file
diff --git a/third_party/mako/mako/test/templates/subdir/foo/modtest.html.py b/third_party/mako/mako/test/templates/subdir/foo/modtest.html.py
index b0f50c76..9df72e01 100644
--- a/third_party/mako/mako/test/templates/subdir/foo/modtest.html.py
+++ b/third_party/mako/mako/test/templates/subdir/foo/modtest.html.py
@@ -1,25 +1,27 @@
-from mako import runtime, filters, cache
+from mako import cache
+from mako import runtime
+
 UNDEFINED = runtime.UNDEFINED
 __M_dict_builtin = dict
 __M_locals_builtin = locals
 _magic_number = 5
 _modified_time = 1267565427.799504
-_template_filename='/Users/classic/dev/mako/test/templates/subdir/modtest.html'
-_template_uri='/subdir/modtest.html'
-_template_cache=cache.Cache(__name__, _modified_time)
-_source_encoding=None
+_template_filename = (
+    "/Users/classic/dev/mako/test/templates/subdir/modtest.html"
+)
+_template_uri = "/subdir/modtest.html"
+_template_cache = cache.Cache(__name__, _modified_time)
+_source_encoding = None
 _exports = []
 
 
-def render_body(context,**pageargs):
+def render_body(context, **pageargs):
     context.caller_stack._push_frame()
     try:
         __M_locals = __M_dict_builtin(pageargs=pageargs)
         __M_writer = context.writer()
         # SOURCE LINE 1
-        __M_writer('this is a test')
-        return ''
+        __M_writer("this is a test")
+        return ""
     finally:
         context.caller_stack._pop_frame()
-
-
diff --git a/third_party/mako/mako/test/templates/unicode_arguments.html b/third_party/mako/mako/test/templates/unicode_arguments.html
deleted file mode 100644
index e6d7c2ca..0000000
--- a/third_party/mako/mako/test/templates/unicode_arguments.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-<%def name="my_def(x)">
-    x is: ${x}
-</%def>
-
-${my_def(u'drôle de petite voix m’a réveillé')}
-<%self:my_def x='drôle de petite voix m’a réveillé'/>
-<%self:my_def x="${u'drôle de petite voix m’a réveillé'}"/>
-<%call expr="my_def(u'drôle de petite voix m’a réveillé')"/>
diff --git a/third_party/mako/mako/test/templates/unicode_code.html b/third_party/mako/mako/test/templates/unicode_code.html
deleted file mode 100644
index 700c043e..0000000
--- a/third_party/mako/mako/test/templates/unicode_code.html
+++ /dev/null
@@ -1,7 +0,0 @@
-## -*- coding: utf-8 -*-
-<%
-    x = u"drôle de petite voix m’a réveillé."
-%>
-% if x==u"drôle de petite voix m’a réveillé.":
-    hi, ${x}
-% endif
diff --git a/third_party/mako/mako/test/templates/unicode_expr.html b/third_party/mako/mako/test/templates/unicode_expr.html
deleted file mode 100644
index cad75226..0000000
--- a/third_party/mako/mako/test/templates/unicode_expr.html
+++ /dev/null
@@ -1,2 +0,0 @@
-## -*- coding: utf-8 -*-
-${u"Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"}
diff --git a/third_party/mako/mako/test/test_ast.py b/third_party/mako/mako/test/test_ast.py
index ce6c082..6b3a3e2 100644
--- a/third_party/mako/mako/test/test_ast.py
+++ b/third_party/mako/mako/test/test_ast.py
@@ -1,17 +1,13 @@
-import unittest
-
 from mako import ast
-from mako import compat
 from mako import exceptions
 from mako import pyparser
-from test import eq_
-from test import requires_python_2
-from test import requires_python_3
+from mako.testing.assertions import assert_raises
+from mako.testing.assertions import eq_
 
 exception_kwargs = {"source": "", "lineno": 0, "pos": 0, "filename": ""}
 
 
-class AstParseTest(unittest.TestCase):
+class AstParseTest:
     def test_locate_identifiers(self):
         """test the location of identifiers in a python code string"""
         code = """
@@ -30,17 +26,15 @@
         parsed = ast.PythonCode(code, **exception_kwargs)
         eq_(
             parsed.declared_identifiers,
-            set(
-                ["a", "b", "c", "g", "h", "i", "u", "k", "j", "gh", "lar", "x"]
-            ),
+            {"a", "b", "c", "g", "h", "i", "u", "k", "j", "gh", "lar", "x"},
         )
         eq_(
             parsed.undeclared_identifiers,
-            set(["x", "q", "foo", "gah", "blah"]),
+            {"x", "q", "foo", "gah", "blah"},
         )
 
         parsed = ast.PythonCode("x + 5 * (y-z)", **exception_kwargs)
-        assert parsed.undeclared_identifiers == set(["x", "y", "z"])
+        assert parsed.undeclared_identifiers == {"x", "y", "z"}
         assert parsed.declared_identifiers == set()
 
     def test_locate_identifiers_2(self):
@@ -54,10 +48,10 @@
     result.append(x+7)
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.undeclared_identifiers, set(["get_data"]))
+        eq_(parsed.undeclared_identifiers, {"get_data"})
         eq_(
             parsed.declared_identifiers,
-            set(["result", "data", "x", "hoho", "foobar", "foo", "yaya"]),
+            {"result", "data", "x", "hoho", "foobar", "foo", "yaya"},
         )
 
     def test_locate_identifiers_3(self):
@@ -71,7 +65,7 @@
 (q for q in range (1, q))
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.undeclared_identifiers, set(["x", "y", "z", "q", "range"]))
+        eq_(parsed.undeclared_identifiers, {"x", "y", "z", "q", "range"})
 
     def test_locate_identifiers_4(self):
         code = """
@@ -81,8 +75,8 @@
     print("mda is", mydefarg)
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.undeclared_identifiers, set(["y"]))
-        eq_(parsed.declared_identifiers, set(["mydef", "x"]))
+        eq_(parsed.undeclared_identifiers, {"y"})
+        eq_(parsed.declared_identifiers, {"mydef", "x"})
 
     def test_locate_identifiers_5(self):
         code = """
@@ -92,7 +86,7 @@
     print(y)
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.undeclared_identifiers, set(["x", "y"]))
+        eq_(parsed.undeclared_identifiers, {"x", "y"})
 
     def test_locate_identifiers_6(self):
         code = """
@@ -100,7 +94,7 @@
     return bar()
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.undeclared_identifiers, set(["bar"]))
+        eq_(parsed.undeclared_identifiers, {"bar"})
 
         code = """
 def lala(x, y):
@@ -108,8 +102,8 @@
 print(x)
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.undeclared_identifiers, set(["z", "x"]))
-        eq_(parsed.declared_identifiers, set(["lala"]))
+        eq_(parsed.undeclared_identifiers, {"z", "x"})
+        eq_(parsed.declared_identifiers, {"lala"})
 
         code = """
 def lala(x, y):
@@ -119,26 +113,26 @@
 print(z)
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.undeclared_identifiers, set(["z"]))
-        eq_(parsed.declared_identifiers, set(["lala"]))
+        eq_(parsed.undeclared_identifiers, {"z"})
+        eq_(parsed.declared_identifiers, {"lala"})
 
     def test_locate_identifiers_7(self):
         code = """
 import foo.bar
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.declared_identifiers, set(["foo"]))
+        eq_(parsed.declared_identifiers, {"foo"})
         eq_(parsed.undeclared_identifiers, set())
 
     def test_locate_identifiers_8(self):
         code = """
-class Hi(object):
+class Hi:
     foo = 7
     def hoho(self):
         x = 5
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.declared_identifiers, set(["Hi"]))
+        eq_(parsed.declared_identifiers, {"Hi"})
         eq_(parsed.undeclared_identifiers, set())
 
     def test_locate_identifiers_9(self):
@@ -146,15 +140,15 @@
     ",".join([t for t in ("a", "b", "c")])
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.declared_identifiers, set(["t"]))
-        eq_(parsed.undeclared_identifiers, set(["t"]))
+        eq_(parsed.declared_identifiers, {"t"})
+        eq_(parsed.undeclared_identifiers, {"t"})
 
         code = """
     [(val, name) for val, name in x]
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.declared_identifiers, set(["val", "name"]))
-        eq_(parsed.undeclared_identifiers, set(["val", "name", "x"]))
+        eq_(parsed.declared_identifiers, {"val", "name"})
+        eq_(parsed.undeclared_identifiers, {"val", "name", "x"})
 
     def test_locate_identifiers_10(self):
         code = """
@@ -170,7 +164,7 @@
     return q + 5
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.declared_identifiers, set(["x"]))
+        eq_(parsed.declared_identifiers, {"x"})
         eq_(parsed.undeclared_identifiers, set())
 
     def test_locate_identifiers_12(self):
@@ -181,44 +175,32 @@
         t = s
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.declared_identifiers, set(["foo"]))
+        eq_(parsed.declared_identifiers, {"foo"})
         eq_(parsed.undeclared_identifiers, set())
 
     def test_locate_identifiers_13(self):
         code = """
 def foo():
-    class Bat(object):
+    class Bat:
         pass
     Bat
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.declared_identifiers, set(["foo"]))
+        eq_(parsed.declared_identifiers, {"foo"})
         eq_(parsed.undeclared_identifiers, set())
 
     def test_locate_identifiers_14(self):
         code = """
 def foo():
-    class Bat(object):
+    class Bat:
         pass
     Bat
 
 print(Bat)
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.declared_identifiers, set(["foo"]))
-        eq_(parsed.undeclared_identifiers, set(["Bat"]))
-
-    @requires_python_2
-    def test_locate_identifiers_15(self):
-        code = """
-def t1((x,y)):
-    return x+5, y+4
-
-t2 = lambda (x,y):(x+5, y+4)
-"""
-        parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.declared_identifiers, set(["t1", "t2"]))
-        eq_(parsed.undeclared_identifiers, set())
+        eq_(parsed.declared_identifiers, {"foo"})
+        eq_(parsed.undeclared_identifiers, {"Bat"})
 
     def test_locate_identifiers_16(self):
         code = """
@@ -228,7 +210,7 @@
     print(y)
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.undeclared_identifiers, set(["x", "y", "Exception"]))
+        eq_(parsed.undeclared_identifiers, {"x", "y", "Exception"})
 
     def test_locate_identifiers_17(self):
         code = """
@@ -238,43 +220,38 @@
     print(y)
 """
         parsed = ast.PythonCode(code, **exception_kwargs)
-        eq_(parsed.undeclared_identifiers, set(["x", "y", "Foo", "Bar"]))
+        eq_(parsed.undeclared_identifiers, {"x", "y", "Foo", "Bar"})
 
     def test_no_global_imports(self):
         code = """
 from foo import *
 import x as bar
 """
-        self.assertRaises(
+        assert_raises(
             exceptions.CompileException,
             ast.PythonCode,
             code,
-            **exception_kwargs
+            **exception_kwargs,
         )
 
     def test_python_fragment(self):
         parsed = ast.PythonFragment("for x in foo:", **exception_kwargs)
-        eq_(parsed.declared_identifiers, set(["x"]))
-        eq_(parsed.undeclared_identifiers, set(["foo"]))
+        eq_(parsed.declared_identifiers, {"x"})
+        eq_(parsed.undeclared_identifiers, {"foo"})
 
         parsed = ast.PythonFragment("try:", **exception_kwargs)
 
-        if compat.py3k:
-            parsed = ast.PythonFragment(
-                "except MyException as e:", **exception_kwargs
-            )
-        else:
-            parsed = ast.PythonFragment(
-                "except MyException, e:", **exception_kwargs
-            )
-        eq_(parsed.declared_identifiers, set(["e"]))
-        eq_(parsed.undeclared_identifiers, set(["MyException"]))
+        parsed = ast.PythonFragment(
+            "except MyException as e:", **exception_kwargs
+        )
+        eq_(parsed.declared_identifiers, {"e"})
+        eq_(parsed.undeclared_identifiers, {"MyException"})
 
     def test_argument_list(self):
         parsed = ast.ArgumentList(
             "3, 5, 'hi', x+5, " "context.get('lala')", **exception_kwargs
         )
-        eq_(parsed.undeclared_identifiers, set(["x", "context"]))
+        eq_(parsed.undeclared_identifiers, {"x", "context"})
         eq_(
             [x for x in parsed.args],
             ["3", "5", "'hi'", "(x + 5)", "context.get('lala')"],
@@ -299,7 +276,6 @@
         eq_(parsed.argnames, ["a", "b", "c", "args"])
         eq_(parsed.kwargnames, ["kwargs"])
 
-    @requires_python_3
     def test_function_decl_3(self):
         """test getting the arguments from a fancy py3k function"""
         code = "def foo(a, b, *c, d, e, **f):pass"
@@ -313,7 +289,7 @@
         x = 1
         y = 2
 
-        class F(object):
+        class F:
             def bar(self, a, b):
                 return a + b
 
diff --git a/third_party/mako/mako/test/test_block.py b/third_party/mako/mako/test/test_block.py
index 0cbe3473..be2fbf71 100644
--- a/third_party/mako/mako/test/test_block.py
+++ b/third_party/mako/mako/test/test_block.py
@@ -1,9 +1,9 @@
 from mako import exceptions
 from mako.lookup import TemplateLookup
 from mako.template import Template
-from test import assert_raises_message
-from test import TemplateTest
-from test.util import result_lines
+from mako.testing.assertions import assert_raises_message
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import result_lines
 
 
 class BlockTest(TemplateTest):
diff --git a/third_party/mako/mako/test/test_cache.py b/third_party/mako/mako/test/test_cache.py
index d662872..dd415d49 100644
--- a/third_party/mako/mako/test/test_cache.py
+++ b/third_party/mako/mako/test/test_cache.py
@@ -1,23 +1,21 @@
 import time
-import unittest
 
 from mako import lookup
 from mako.cache import CacheImpl
 from mako.cache import register_plugin
-from mako.compat import py27
-from mako.ext import beaker_cache
 from mako.lookup import TemplateLookup
 from mako.template import Template
-from test import eq_
-from test import module_base
-from test import TemplateTest
-from test.util import result_lines
-
-if beaker_cache.has_beaker:
-    import beaker
+from mako.testing.assertions import eq_
+from mako.testing.config import config
+from mako.testing.exclusions import requires_beaker
+from mako.testing.exclusions import requires_dogpile_cache
+from mako.testing.helpers import result_lines
 
 
-class SimpleBackend(object):
+module_base = str(config.module_base)
+
+
+class SimpleBackend:
     def __init__(self):
         self.cache = {}
 
@@ -33,9 +31,9 @@
     def get_or_create(self, key, creation_function, **kw):
         if key in self.cache:
             return self.cache[key]
-        else:
-            self.cache[key] = value = creation_function()
-            return value
+
+        self.cache[key] = value = creation_function()
+        return value
 
 
 class MockCacheImpl(CacheImpl):
@@ -81,7 +79,7 @@
 register_plugin("mock", __name__, "MockCacheImpl")
 
 
-class CacheTest(TemplateTest):
+class CacheTest:
 
     real_backend = "simple"
 
@@ -601,7 +599,7 @@
         assert m.kwargs["context"].get("x") == "bar"
 
 
-class RealBackendTest(object):
+class RealBackendMixin:
     def test_cache_uses_current_context(self):
         t = Template(
             """
@@ -644,23 +642,17 @@
         eq_(r3, ["short term 6", "long term 5", "none 7"])
 
 
-class BeakerCacheTest(RealBackendTest, CacheTest):
+@requires_beaker
+class BeakerCacheTest(RealBackendMixin, CacheTest):
     real_backend = "beaker"
 
-    def setUp(self):
-        if not beaker_cache.has_beaker:
-            raise unittest.SkipTest("Beaker is required for these tests.")
-        if not py27:
-            raise unittest.SkipTest("newer beakers not working w/ py26")
-
     def _install_mock_cache(self, template, implname=None):
         template.cache_args["manager"] = self._regions()
-        impl = super(BeakerCacheTest, self)._install_mock_cache(
-            template, implname
-        )
-        return impl
+        return super()._install_mock_cache(template, implname)
 
     def _regions(self):
+        import beaker
+
         return beaker.cache.CacheManager(
             cache_regions={
                 "short": {"expire": 1, "type": "memory"},
@@ -669,24 +661,14 @@
         )
 
 
-class DogpileCacheTest(RealBackendTest, CacheTest):
+@requires_dogpile_cache
+class DogpileCacheTest(RealBackendMixin, CacheTest):
     real_backend = "dogpile.cache"
 
-    def setUp(self):
-        try:
-            import dogpile.cache  # noqa
-        except ImportError:
-            raise unittest.SkipTest(
-                "dogpile.cache is required to run these tests"
-            )
-
     def _install_mock_cache(self, template, implname=None):
         template.cache_args["regions"] = self._regions()
         template.cache_args.setdefault("region", "short")
-        impl = super(DogpileCacheTest, self)._install_mock_cache(
-            template, implname
-        )
-        return impl
+        return super()._install_mock_cache(template, implname)
 
     def _regions(self):
         from dogpile.cache import make_region
diff --git a/third_party/mako/mako/test/test_call.py b/third_party/mako/mako/test/test_call.py
index 36d15dcc..4dea2b35 100644
--- a/third_party/mako/mako/test/test_call.py
+++ b/third_party/mako/mako/test/test_call.py
@@ -1,8 +1,8 @@
 from mako.template import Template
-from test import eq_
-from test import TemplateTest
-from test.util import flatten_result
-from test.util import result_lines
+from mako.testing.assertions import eq_
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import flatten_result
+from mako.testing.helpers import result_lines
 
 
 class CallTest(TemplateTest):
diff --git a/third_party/mako/mako/test/test_cmd.py b/third_party/mako/mako/test/test_cmd.py
index ac0db25..785c652 100644
--- a/third_party/mako/mako/test/test_cmd.py
+++ b/third_party/mako/mako/test/test_cmd.py
@@ -1,14 +1,13 @@
-from __future__ import with_statement
-
 from contextlib import contextmanager
 import os
+from unittest import mock
 
 from mako.cmd import cmdline
-from test import eq_
-from test import mock
-from test import raises
-from test import template_base
-from test import TemplateTest
+from mako.testing.assertions import eq_
+from mako.testing.assertions import expect_raises
+from mako.testing.assertions import expect_raises_message
+from mako.testing.config import config
+from mako.testing.fixtures import TemplateTest
 
 
 class CmdTest(TemplateTest):
@@ -32,7 +31,7 @@
             "sys.stdin", mock.Mock(read=mock.Mock(return_value="${x"))
         ):
             with self._capture_output_fixture("stderr") as stderr:
-                with raises(SystemExit):
+                with expect_raises(SystemExit):
                     cmdline(["--var", "x=5", "-"])
 
             assert (
@@ -45,7 +44,7 @@
             "sys.stdin", mock.Mock(read=mock.Mock(return_value="${q}"))
         ):
             with self._capture_output_fixture("stderr") as stderr:
-                with raises(SystemExit):
+                with expect_raises(SystemExit):
                     cmdline(["--var", "x=5", "-"])
 
             assert "NameError: Undefined" in stderr.write.mock_calls[0][1][0]
@@ -54,19 +53,23 @@
     def test_file_success(self):
         with self._capture_output_fixture() as stdout:
             cmdline(
-                ["--var", "x=5", os.path.join(template_base, "cmd_good.mako")]
+                [
+                    "--var",
+                    "x=5",
+                    os.path.join(config.template_base, "cmd_good.mako"),
+                ]
             )
 
         eq_(stdout.write.mock_calls[0][1][0], "hello world 5")
 
     def test_file_syntax_err(self):
         with self._capture_output_fixture("stderr") as stderr:
-            with raises(SystemExit):
+            with expect_raises(SystemExit):
                 cmdline(
                     [
                         "--var",
                         "x=5",
-                        os.path.join(template_base, "cmd_syntax.mako"),
+                        os.path.join(config.template_base, "cmd_syntax.mako"),
                     ]
                 )
 
@@ -75,12 +78,12 @@
 
     def test_file_rt_err(self):
         with self._capture_output_fixture("stderr") as stderr:
-            with raises(SystemExit):
+            with expect_raises(SystemExit):
                 cmdline(
                     [
                         "--var",
                         "x=5",
-                        os.path.join(template_base, "cmd_runtime.mako"),
+                        os.path.join(config.template_base, "cmd_runtime.mako"),
                     ]
                 )
 
@@ -88,5 +91,7 @@
         assert "Traceback" in stderr.write.mock_calls[0][1][0]
 
     def test_file_notfound(self):
-        with raises(SystemExit, "error: can't find fake.lalala"):
+        with expect_raises_message(
+            SystemExit, "error: can't find fake.lalala"
+        ):
             cmdline(["--var", "x=5", "fake.lalala"])
diff --git a/third_party/mako/mako/test/test_decorators.py b/third_party/mako/mako/test/test_decorators.py
index 195a636..68ea903 100644
--- a/third_party/mako/mako/test/test_decorators.py
+++ b/third_party/mako/mako/test/test_decorators.py
@@ -1,10 +1,8 @@
-import unittest
-
 from mako.template import Template
-from test.util import flatten_result
+from mako.testing.helpers import flatten_result
 
 
-class DecoratorTest(unittest.TestCase):
+class DecoratorTest:
     def test_toplevel(self):
         template = Template(
             """
diff --git a/third_party/mako/mako/test/test_def.py b/third_party/mako/mako/test/test_def.py
index 99b929d..fd96433 100644
--- a/third_party/mako/mako/test/test_def.py
+++ b/third_party/mako/mako/test/test_def.py
@@ -1,12 +1,10 @@
-from mako import compat
 from mako import lookup
 from mako.template import Template
-from test import assert_raises
-from test import eq_
-from test import requires_python_3
-from test import TemplateTest
-from test.util import flatten_result
-from test.util import result_lines
+from mako.testing.assertions import assert_raises
+from mako.testing.assertions import eq_
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import flatten_result
+from mako.testing.helpers import result_lines
 
 
 class DefTest(TemplateTest):
@@ -49,7 +47,6 @@
             """hello mycomp hi, 5, 6""",
         )
 
-    @requires_python_3
     def test_def_py3k_args(self):
         template = Template(
             """
@@ -86,12 +83,8 @@
 """
         )
         # check that "a" is declared in "b", but not in "c"
-        if compat.py3k:
-            assert "a" not in template.module.render_c.__code__.co_varnames
-            assert "a" in template.module.render_b.__code__.co_varnames
-        else:
-            assert "a" not in template.module.render_c.func_code.co_varnames
-            assert "a" in template.module.render_b.func_code.co_varnames
+        assert "a" not in template.module.render_c.__code__.co_varnames
+        assert "a" in template.module.render_b.__code__.co_varnames
 
         # then test output
         eq_(flatten_result(template.render()), "im b and heres a: im a")
diff --git a/third_party/mako/mako/test/test_exceptions.py b/third_party/mako/mako/test/test_exceptions.py
index 2ec46cf..b1930c5 100644
--- a/third_party/mako/mako/test/test_exceptions.py
+++ b/third_party/mako/mako/test/test_exceptions.py
@@ -1,15 +1,12 @@
-# -*- coding: utf-8 -*-
 import sys
 
-from mako import compat
 from mako import exceptions
-from mako.compat import u
 from mako.lookup import TemplateLookup
 from mako.template import Template
-from test import requires_no_pygments_exceptions
-from test import requires_pygments_14
-from test import TemplateTest
-from test.util import result_lines
+from mako.testing.exclusions import requires_no_pygments_exceptions
+from mako.testing.exclusions import requires_pygments_14
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import result_lines
 
 
 class ExceptionsTest(TemplateTest):
@@ -68,53 +65,28 @@
         """test the html_error_template with a Template containing UTF-8
         chars"""
 
-        if compat.py3k:
-            code = """# -*- coding: utf-8 -*-
+        code = """# -*- coding: utf-8 -*-
 % if 2 == 2: /an error
 ${'привет'}
 % endif
 """
-        else:
-            code = """# -*- coding: utf-8 -*-
-% if 2 == 2: /an error
-${u'привет'}
-% endif
-"""
         try:
             template = Template(code)
             template.render_unicode()
         except exceptions.CompileException:
             html_error = exceptions.html_error_template().render()
-            if compat.py3k:
-                assert (
-                    (
-                        "CompileException: Fragment &#39;if 2 == 2: /an "
-                        "error&#39; is not a partial control statement "
-                        "at line: 2 char: 1"
-                    ).encode(sys.getdefaultencoding(), "htmlentityreplace")
-                    in html_error
-                )
-            else:
-                assert (
-                    "CompileException: Fragment &#39;if 2 == 2: /an "
-                    "error&#39; is not a partial control statement "
-                    "at line: 2 char: 1"
-                ) in html_error
+            assert (
+                "CompileException: Fragment &#39;if 2 == 2: /an "
+                "error&#39; is not a partial control statement "
+                "at line: 2 char: 1"
+            ).encode(
+                sys.getdefaultencoding(), "htmlentityreplace"
+            ) in html_error
 
-            if compat.py3k:
-                assert (
-                    "".encode(sys.getdefaultencoding(), "htmlentityreplace")
-                    in html_error
-                )
-            else:
-                assert (
-                    "&#39;"
-                    "&#x43F;&#x440;&#x438;&#x432;&#x435;&#x442;"
-                    '&#39;</span><span class="cp">}</span>'.encode(
-                        sys.getdefaultencoding(), "htmlentityreplace"
-                    )
-                    in html_error
-                )
+            assert (
+                "".encode(sys.getdefaultencoding(), "htmlentityreplace")
+                in html_error
+            )
         else:
             assert False, (
                 "This function should trigger a CompileException, "
@@ -126,53 +98,29 @@
         """test the html_error_template with a Template containing UTF-8
         chars"""
 
-        if compat.py3k:
-            code = """# -*- coding: utf-8 -*-
+        code = """# -*- coding: utf-8 -*-
 % if 2 == 2: /an error
 ${'привет'}
 % endif
 """
-        else:
-            code = """# -*- coding: utf-8 -*-
-% if 2 == 2: /an error
-${u'привет'}
-% endif
-"""
         try:
             template = Template(code)
             template.render_unicode()
         except exceptions.CompileException:
             html_error = exceptions.html_error_template().render()
-            if compat.py3k:
-                assert (
-                    (
-                        "CompileException: Fragment &#39;if 2 == 2: /an "
-                        "error&#39; is not a partial control statement "
-                        "at line: 2 char: 1"
-                    ).encode(sys.getdefaultencoding(), "htmlentityreplace")
-                    in html_error
+            assert (
+                "CompileException: Fragment &#39;if 2 == 2: /an "
+                "error&#39; is not a partial control statement "
+                "at line: 2 char: 1"
+            ).encode(
+                sys.getdefaultencoding(), "htmlentityreplace"
+            ) in html_error
+            assert (
+                "${&#39;привет&#39;}".encode(
+                    sys.getdefaultencoding(), "htmlentityreplace"
                 )
-            else:
-                assert (
-                    "CompileException: Fragment &#39;if 2 == 2: /an "
-                    "error&#39; is not a partial control statement "
-                    "at line: 2 char: 1"
-                ) in html_error
-
-            if compat.py3k:
-                assert (
-                    "${&#39;привет&#39;}".encode(
-                        sys.getdefaultencoding(), "htmlentityreplace"
-                    )
-                    in html_error
-                )
-            else:
-                assert (
-                    u("${u&#39;привет&#39;}").encode(
-                        sys.getdefaultencoding(), "htmlentityreplace"
-                    )
-                    in html_error
-                )
+                in html_error
+            )
         else:
             assert False, (
                 "This function should trigger a CompileException, "
@@ -189,30 +137,21 @@
 
     def test_py_utf8_html_error_template(self):
         try:
-            foo = u("日本")  # noqa
+            foo = "日本"  # noqa
             raise RuntimeError("test")
         except:
             html_error = exceptions.html_error_template().render()
-            if compat.py3k:
-                assert "RuntimeError: test" in html_error.decode("utf-8")
-                assert "foo = u(&quot;日本&quot;)" in html_error.decode(
-                    "utf-8"
-                ) or "foo = u(&#34;日本&#34;)" in html_error.decode("utf-8")
-            else:
-                assert "RuntimeError: test" in html_error
-                assert (
-                    "foo = u(&quot;&#x65E5;&#x672C;&quot;)" in html_error
-                    or "foo = u(&#34;&#x65E5;&#x672C;&#34;)" in html_error
-                )
+            assert "RuntimeError: test" in html_error.decode("utf-8")
+            assert "foo = &quot;日本&quot;" in html_error.decode(
+                "utf-8"
+            ) or "foo = &#34;日本&#34;" in html_error.decode("utf-8")
 
     def test_py_unicode_error_html_error_template(self):
         try:
-            raise RuntimeError(u("日本"))
+            raise RuntimeError("日本")
         except:
             html_error = exceptions.html_error_template().render()
-            assert (
-                u("RuntimeError: 日本").encode("ascii", "ignore") in html_error
-            )
+            assert "RuntimeError: 日本".encode("ascii", "ignore") in html_error
 
     @requires_pygments_14
     def test_format_exceptions_pygments(self):
@@ -264,60 +203,33 @@
     @requires_pygments_14
     def test_utf8_format_exceptions_pygments(self):
         """test that htmlentityreplace formatting is applied to
-           exceptions reported with format_exceptions=True"""
+        exceptions reported with format_exceptions=True"""
 
         l = TemplateLookup(format_exceptions=True)
-        if compat.py3k:
-            l.put_string(
-                "foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}"""
-            )
-        else:
-            l.put_string(
-                "foo.html",
-                """# -*- coding: utf-8 -*-\n${u'привет' + foobar}""",
-            )
+        l.put_string(
+            "foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}"""
+        )
 
-        if compat.py3k:
-            assert "&#39;привет&#39;</span>" in l.get_template(
-                "foo.html"
-            ).render().decode("utf-8")
-        else:
-            assert (
-                "&#39;&#x43F;&#x440;&#x438;&#x432;"
-                "&#x435;&#x442;&#39;</span>"
-            ) in l.get_template("foo.html").render().decode("utf-8")
+        assert "&#39;привет&#39;</span>" in l.get_template(
+            "foo.html"
+        ).render().decode("utf-8")
 
     @requires_no_pygments_exceptions
     def test_utf8_format_exceptions_no_pygments(self):
         """test that htmlentityreplace formatting is applied to
-           exceptions reported with format_exceptions=True"""
+        exceptions reported with format_exceptions=True"""
 
         l = TemplateLookup(format_exceptions=True)
-        if compat.py3k:
-            l.put_string(
-                "foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}"""
-            )
-        else:
-            l.put_string(
-                "foo.html",
-                """# -*- coding: utf-8 -*-\n${u'привет' + foobar}""",
-            )
+        l.put_string(
+            "foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}"""
+        )
 
-        if compat.py3k:
-            assert (
-                '<div class="sourceline">${&#39;привет&#39; + foobar}</div>'
-                in result_lines(
-                    l.get_template("foo.html").render().decode("utf-8")
-                )
+        assert (
+            '<div class="sourceline">${&#39;привет&#39; + foobar}</div>'
+            in result_lines(
+                l.get_template("foo.html").render().decode("utf-8")
             )
-        else:
-            assert (
-                "${u&#39;&#x43F;&#x440;&#x438;&#x432;&#x435;"
-                "&#x442;&#39; + foobar}"
-                in result_lines(
-                    l.get_template("foo.html").render().decode("utf-8")
-                )
-            )
+        )
 
     def test_mod_no_encoding(self):
 
@@ -358,10 +270,6 @@
         except:
             t, v, tback = sys.exc_info()
 
-        if not compat.py3k:
-            # blow away tracebaack info
-            sys.exc_clear()
-
         # and don't even send what we have.
         html_error = exceptions.html_error_template().render_unicode(
             error=v, traceback=None
@@ -457,7 +365,8 @@
             t.render()
         except:
             text_error = exceptions.text_error_template().render_unicode()
-            assert """
+            assert (
+                """
   File "base.html", line 5, in render_body
     %> body starts here
   File "foo.html", line 4, in render_foo
@@ -466,6 +375,8 @@
     ${broken()}
   File "base.html", line 4, in broken
     raise RuntimeError("Something went wrong.")
-""" in text_error
+"""
+                in text_error
+            )
         else:
             assert False
diff --git a/third_party/mako/mako/test/test_filters.py b/third_party/mako/mako/test/test_filters.py
index a58a01f..726f5d74 100644
--- a/third_party/mako/mako/test/test_filters.py
+++ b/third_party/mako/mako/test/test_filters.py
@@ -1,15 +1,8 @@
-# -*- coding: utf-8 -*-
-
-import unittest
-
-from mako import compat
-from mako.compat import u
 from mako.template import Template
-from test import eq_
-from test import requires_python_2
-from test import TemplateTest
-from test.util import flatten_result
-from test.util import result_lines
+from mako.testing.assertions import eq_
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import flatten_result
+from mako.testing.helpers import result_lines
 
 
 class FilterTest(TemplateTest):
@@ -77,7 +70,7 @@
         )
 
         eq_(
-            flatten_result(t.render(bar=u"酒吧bar")),
+            flatten_result(t.render(bar="酒吧bar")),
             "http://example.com/?bar=%E9%85%92%E5%90%A7bar&v=1",
         )
 
@@ -88,36 +81,6 @@
             "foo &lt;'some bar'&gt;",
         )
 
-    @requires_python_2
-    def test_quoting_non_unicode(self):
-        t = Template(
-            """
-            foo ${bar | h}
-        """,
-            disable_unicode=True,
-            output_encoding=None,
-        )
-
-        eq_(
-            flatten_result(t.render(bar="<'привет'>")),
-            "foo &lt;&#39;привет&#39;&gt;",
-        )
-
-    @requires_python_2
-    def test_url_escaping_non_unicode(self):
-        t = Template(
-            """
-            http://example.com/?bar=${bar | u}&v=1
-        """,
-            disable_unicode=True,
-            output_encoding=None,
-        )
-
-        eq_(
-            flatten_result(t.render(bar="酒吧bar")),
-            "http://example.com/?bar=%E9%85%92%E5%90%A7bar&v=1",
-        )
-
     def test_def(self):
         t = Template(
             """
@@ -176,8 +139,8 @@
             default_filters=["decode.utf8"],
         )
         eq_(
-            t.render_unicode(x=u("voix m’a réveillé")).strip(),
-            u("some stuff.... voix m’a réveillé"),
+            t.render_unicode(x="voix m’a réveillé").strip(),
+            "some stuff.... voix m’a réveillé",
         )
 
     def test_encode_filter_non_str(self):
@@ -187,21 +150,7 @@
         """,
             default_filters=["decode.utf8"],
         )
-        eq_(t.render_unicode(x=3).strip(), u("some stuff.... 3"))
-
-    @requires_python_2
-    def test_encode_filter_non_str_we_return_bytes(self):
-        class Foo(object):
-            def __str__(self):
-                return compat.b("å")
-
-        t = Template(
-            """# coding: utf-8
-            some stuff.... ${x}
-        """,
-            default_filters=["decode.utf8"],
-        )
-        eq_(t.render_unicode(x=Foo()).strip(), u("some stuff.... å"))
+        eq_(t.render_unicode(x=3).strip(), "some stuff.... 3")
 
     def test_custom_default(self):
         t = Template(
@@ -347,7 +296,7 @@
         t = Template(
             """
         <%!
-            class Foo(object):
+            class Foo:
                 foo = True
                 def __str__(self):
                     return "this is a"
@@ -412,7 +361,7 @@
         )
 
 
-class BufferTest(unittest.TestCase):
+class BufferTest:
     def test_buffered_def(self):
         t = Template(
             """
diff --git a/third_party/mako/mako/test/test_inheritance.py b/third_party/mako/mako/test/test_inheritance.py
index e8ed74e2..15bd54b 100644
--- a/third_party/mako/mako/test/test_inheritance.py
+++ b/third_party/mako/mako/test/test_inheritance.py
@@ -1,11 +1,8 @@
-import unittest
-
-from mako import compat
 from mako import lookup
-from test.util import result_lines
+from mako.testing.helpers import result_lines
 
 
-class InheritanceTest(unittest.TestCase):
+class InheritanceTest:
     def test_basic(self):
         collection = lookup.TemplateLookup()
 
@@ -257,22 +254,13 @@
         """,
         )
 
-        if compat.py3k:
-            assert result_lines(
-                collection.get_template("index").render_unicode(x=5, y=10)
-            ) == [
-                "this is the base.",
-                "pageargs: (type: <class 'dict'>) [('x', 5), ('y', 10)]",
-                "print 5, 10, 7",
-            ]
-        else:
-            assert result_lines(
-                collection.get_template("index").render_unicode(x=5, y=10)
-            ) == [
-                "this is the base.",
-                "pageargs: (type: <type 'dict'>) [('x', 5), ('y', 10)]",
-                "print 5, 10, 7",
-            ]
+        assert result_lines(
+            collection.get_template("index").render_unicode(x=5, y=10)
+        ) == [
+            "this is the base.",
+            "pageargs: (type: <class 'dict'>) [('x', 5), ('y', 10)]",
+            "print 5, 10, 7",
+        ]
 
     def test_pageargs_2(self):
         collection = lookup.TemplateLookup()
diff --git a/third_party/mako/mako/test/test_lexer.py b/third_party/mako/mako/test/test_lexer.py
index 9807961..255c128f 100644
--- a/third_party/mako/mako/test/test_lexer.py
+++ b/third_party/mako/mako/test/test_lexer.py
@@ -6,10 +6,11 @@
 from mako import util
 from mako.lexer import Lexer
 from mako.template import Template
-from test import assert_raises_message
-from test import eq_
-from test import TemplateTest
-from test.util import flatten_result
+from mako.testing.assertions import assert_raises
+from mako.testing.assertions import assert_raises_message
+from mako.testing.assertions import eq_
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import flatten_result
 
 # create fake parsetree classes which are constructed
 # exactly as the repr() of a real parsetree object.
@@ -25,13 +26,12 @@
 
 
 def _as_unicode(arg):
-    if isinstance(arg, compat.string_types):
-        return compat.text_type(arg)
-    elif isinstance(arg, dict):
-        return dict((_as_unicode(k), _as_unicode(v)) for k, v in arg.items())
+    if isinstance(arg, dict):
+        return {k: _as_unicode(v) for k, v in arg.items()}
     else:
         return arg
 
+
 Node = None
 TemplateNode = None
 ControlLine = None
@@ -59,7 +59,7 @@
         exec(
             (
                 """
-class %s(object):
+class %s:
     def __init__(self, *args):
         self.args = [_as_unicode(arg) for arg in args]
     def __repr__(self):
@@ -138,13 +138,13 @@
 
             hi.
         """
-        self.assertRaises(exceptions.SyntaxException, Lexer(template).parse)
+        assert_raises(exceptions.SyntaxException, Lexer(template).parse)
 
     def test_noexpr_allowed(self):
         template = """
             <%namespace name="${foo}"/>
         """
-        self.assertRaises(exceptions.CompileException, Lexer(template).parse)
+        assert_raises(exceptions.CompileException, Lexer(template).parse)
 
     def test_unmatched_tag(self):
         template = """
@@ -157,13 +157,13 @@
 
         hi.
 """
-        self.assertRaises(exceptions.SyntaxException, Lexer(template).parse)
+        assert_raises(exceptions.SyntaxException, Lexer(template).parse)
 
     def test_nonexistent_tag(self):
         template = """
             <%lala x="5"/>
         """
-        self.assertRaises(exceptions.CompileException, Lexer(template).parse)
+        assert_raises(exceptions.CompileException, Lexer(template).parse)
 
     def test_wrongcase_tag(self):
         template = """
@@ -171,7 +171,7 @@
             </%def>
 
         """
-        self.assertRaises(exceptions.CompileException, Lexer(template).parse)
+        assert_raises(exceptions.CompileException, Lexer(template).parse)
 
     def test_percent_escape(self):
         template = """
@@ -247,7 +247,7 @@
                                 " % more code\n            "
                                 "<%illegal compionent>/></>\n"
                                 '            <%def name="laal()">def</%def>'
-                                '\n\n\n        ',
+                                "\n\n\n        ",
                                 (6, 16),
                             )
                         ],
@@ -274,7 +274,7 @@
             hi
         </%def>
 """
-        self.assertRaises(exceptions.CompileException, Lexer(template).parse)
+        assert_raises(exceptions.CompileException, Lexer(template).parse)
 
     def test_def_syntax_2(self):
         template = """
@@ -282,7 +282,7 @@
             hi
         </%def>
     """
-        self.assertRaises(exceptions.CompileException, Lexer(template).parse)
+        assert_raises(exceptions.CompileException, Lexer(template).parse)
 
     def test_whitespace_equals(self):
         template = """
@@ -515,10 +515,8 @@
             ),
         )
 
-    if compat.py3k:
-
-        def test_code(self):
-            template = """text
+    def test_code(self):
+        template = """text
     <%
         print("hi")
         for x in range(1,5):
@@ -529,59 +527,25 @@
         import foo
     %>
 """
-            nodes = Lexer(template).parse()
-            self._compare(
-                nodes,
-                TemplateNode(
-                    {},
-                    [
-                        Text("text\n    ", (1, 1)),
-                        Code(
-                            '\nprint("hi")\nfor x in range(1,5):\n    '
-                            "print(x)\n    \n",
-                            False,
-                            (2, 5),
-                        ),
-                        Text("\nmore text\n    ", (6, 7)),
-                        Code("\nimport foo\n    \n", True, (8, 5)),
-                        Text("\n", (10, 7)),
-                    ],
-                ),
-            )
-
-    else:
-
-        def test_code(self):
-            template = """text
-    <%
-        print "hi"
-        for x in range(1,5):
-            print x
-    %>
-more text
-    <%!
-        import foo
-    %>
-"""
-            nodes = Lexer(template).parse()
-            self._compare(
-                nodes,
-                TemplateNode(
-                    {},
-                    [
-                        Text("text\n    ", (1, 1)),
-                        Code(
-                            '\nprint "hi"\nfor x in range(1,5):\n    '
-                            "print x\n    \n",
-                            False,
-                            (2, 5),
-                        ),
-                        Text("\nmore text\n    ", (6, 7)),
-                        Code("\nimport foo\n    \n", True, (8, 5)),
-                        Text("\n", (10, 7)),
-                    ],
-                ),
-            )
+        nodes = Lexer(template).parse()
+        self._compare(
+            nodes,
+            TemplateNode(
+                {},
+                [
+                    Text("text\n    ", (1, 1)),
+                    Code(
+                        '\nprint("hi")\nfor x in range(1,5):\n    '
+                        "print(x)\n    \n",
+                        False,
+                        (2, 5),
+                    ),
+                    Text("\nmore text\n    ", (6, 7)),
+                    Code("\nimport foo\n    \n", True, (8, 5)),
+                    Text("\n", (10, 7)),
+                ],
+            ),
+        )
 
     def test_code_and_tags(self):
         template = """
@@ -741,20 +705,11 @@
         )
 
     def test_tricky_code(self):
-        if compat.py3k:
-            template = """<% print('hi %>') %>"""
-            nodes = Lexer(template).parse()
-            self._compare(
-                nodes,
-                TemplateNode({}, [Code("print('hi %>') \n", False, (1, 1))]),
-            )
-        else:
-            template = """<% print 'hi %>' %>"""
-            nodes = Lexer(template).parse()
-            self._compare(
-                nodes,
-                TemplateNode({}, [Code("print 'hi %>' \n", False, (1, 1))]),
-            )
+        template = """<% print('hi %>') %>"""
+        nodes = Lexer(template).parse()
+        self._compare(
+            nodes, TemplateNode({}, [Code("print('hi %>') \n", False, (1, 1))])
+        )
 
     def test_tricky_code_2(self):
         template = """<%
@@ -780,77 +735,42 @@
             ),
         )
 
-    if compat.py3k:
-
-        def test_tricky_code_3(self):
-            template = """<%
-            print('hi')
-            # this is a comment
-            # another comment
-            x = 7 # someone's '''comment
-            print('''
-        there
-        ''')
-            # someone else's comment
+    def test_tricky_code_3(self):
+        template = """<%
+        print('hi')
+        # this is a comment
+        # another comment
+        x = 7 # someone's '''comment
+        print('''
+    there
+    ''')
+        # someone else's comment
 %> '''and now some text '''"""
-            nodes = Lexer(template).parse()
-            self._compare(
-                nodes,
-                TemplateNode(
-                    {},
-                    [
-                        Code(
-                            """
+        nodes = Lexer(template).parse()
+        self._compare(
+            nodes,
+            TemplateNode(
+                {},
+                [
+                    Code(
+                        """
 print('hi')
 # this is a comment
 # another comment
 x = 7 # someone's '''comment
 print('''
-        there
-        ''')
+    there
+    ''')
 # someone else's comment
 
 """,
-                            False,
-                            (1, 1),
-                        ),
-                        Text(" '''and now some text '''", (10, 3)),
-                    ],
-                ),
-            )
-
-    else:
-
-        def test_tricky_code_3(self):
-            template = """<%
-            print 'hi'
-            # this is a comment
-            # another comment
-            x = 7 # someone's '''comment
-            print '''
-        there
-        '''
-            # someone else's comment
-%> '''and now some text '''"""
-            nodes = Lexer(template).parse()
-            self._compare(
-                nodes,
-                TemplateNode(
-                    {},
-                    [
-                        Code(
-                            """\nprint 'hi'\n# this is a comment\n"""
-                            """# another comment\nx = 7 """
-                            """# someone's '''comment\nprint '''\n        """
-                            """there\n        '''\n# someone else's """
-                            """comment\n\n""",
-                            False,
-                            (1, 1),
-                        ),
-                        Text(" '''and now some text '''", (10, 3)),
-                    ],
-                ),
-            )
+                        False,
+                        (1, 1),
+                    ),
+                    Text(" '''and now some text '''", (10, 3)),
+                ],
+            ),
+        )
 
     def test_tricky_code_4(self):
         template = """<% foo = "\\"\\\\" %>"""
diff --git a/third_party/mako/mako/test/test_lookup.py b/third_party/mako/mako/test/test_lookup.py
index 0dacfbb7..6a797d7 100644
--- a/third_party/mako/mako/test/test_lookup.py
+++ b/third_party/mako/mako/test/test_lookup.py
@@ -1,21 +1,23 @@
 import os
-import unittest
+import tempfile
 
-from mako import compat
 from mako import exceptions
 from mako import lookup
 from mako import runtime
 from mako.template import Template
+from mako.testing.assertions import assert_raises_message
+from mako.testing.assertions import assert_raises_with_given_cause
+from mako.testing.config import config
+from mako.testing.helpers import file_with_template_code
+from mako.testing.helpers import replace_file_with_dir
+from mako.testing.helpers import result_lines
+from mako.testing.helpers import rewind_compile_time
 from mako.util import FastEncodingBuffer
-from test import assert_raises_message
-from test import eq_
-from test import template_base
-from test.util import result_lines
 
-tl = lookup.TemplateLookup(directories=[template_base])
+tl = lookup.TemplateLookup(directories=[config.template_base])
 
 
-class LookupTest(unittest.TestCase):
+class LookupTest:
     def test_basic(self):
         t = tl.get_template("index.html")
         assert result_lines(t.render()) == ["this is index"]
@@ -43,21 +45,22 @@
         """test that hitting an existent directory still raises
         LookupError."""
 
-        self.assertRaises(
-            exceptions.TopLevelLookupException, tl.get_template, "/subdir"
+        assert_raises_with_given_cause(
+            exceptions.TopLevelLookupException,
+            KeyError,
+            tl.get_template,
+            "/subdir",
         )
 
     def test_no_lookup(self):
         t = Template("hi <%include file='foo.html'/>")
-        try:
-            t.render()
-            assert False
-        except exceptions.TemplateLookupException:
-            eq_(
-                str(compat.exception_as()),
-                "Template 'memory:%s' has no TemplateLookup associated"
-                % hex(id(t)),
-            )
+
+        assert_raises_message(
+            exceptions.TemplateLookupException,
+            "Template 'memory:%s' has no TemplateLookup associated"
+            % hex(id(t)),
+            t.render,
+        )
 
     def test_uri_adjust(self):
         tl = lookup.TemplateLookup(directories=["/foo/bar"])
@@ -82,8 +85,11 @@
         f = tl.get_template("foo")
         assert f.uri in tl._collection
         f.filename = "nonexistent"
-        self.assertRaises(
-            exceptions.TemplateLookupException, tl.get_template, "foo"
+        assert_raises_with_given_cause(
+            exceptions.TemplateLookupException,
+            FileNotFoundError,
+            tl.get_template,
+            "foo",
         )
         assert f.uri not in tl._collection
 
@@ -91,7 +97,7 @@
         """test the mechanics of an include where
         the include goes outside of the path"""
         tl = lookup.TemplateLookup(
-            directories=[os.path.join(template_base, "subdir")]
+            directories=[os.path.join(config.template_base, "subdir")]
         )
         index = tl.get_template("index.html")
 
@@ -120,3 +126,25 @@
 
         # this is OK since the .. cancels out
         runtime._lookup_template(ctx, "foo/../index.html", index.uri)
+
+    def test_checking_against_bad_filetype(self):
+        with tempfile.TemporaryDirectory() as tempdir:
+            tl = lookup.TemplateLookup(directories=[tempdir])
+            index_file = file_with_template_code(
+                os.path.join(tempdir, "index.html")
+            )
+
+            with rewind_compile_time():
+                tmpl = Template(filename=index_file)
+
+            tl.put_template("index.html", tmpl)
+
+            replace_file_with_dir(index_file)
+
+            assert_raises_with_given_cause(
+                exceptions.TemplateLookupException,
+                OSError,
+                tl._check,
+                "index.html",
+                tl._collection["index.html"],
+            )
diff --git a/third_party/mako/mako/test/test_loop.py b/third_party/mako/mako/test/test_loop.py
index 8104e49..19d40b54 100644
--- a/third_party/mako/mako/test/test_loop.py
+++ b/third_party/mako/mako/test/test_loop.py
@@ -1,5 +1,4 @@
 import re
-import unittest
 
 from mako import exceptions
 from mako.codegen import _FOR_LOOP
@@ -7,12 +6,12 @@
 from mako.runtime import LoopContext
 from mako.runtime import LoopStack
 from mako.template import Template
-from test import assert_raises_message
-from test import TemplateTest
-from test.util import flatten_result
+from mako.testing.assertions import assert_raises_message
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import flatten_result
 
 
-class TestLoop(unittest.TestCase):
+class TestLoop:
     def test__FOR_LOOP(self):
         for statement, target_list, expression_list in (
             ("for x in y:", "x", "y"),
@@ -137,7 +136,7 @@
         )
 
 
-class TestLoopStack(unittest.TestCase):
+class TestLoopStack:
     def setUp(self):
         self.stack = LoopStack()
         self.bottom = "spam"
@@ -180,7 +179,7 @@
         assert before == (after + 1), "Exiting a context pops the stack"
 
 
-class TestLoopContext(unittest.TestCase):
+class TestLoopContext:
     def setUp(self):
         self.iterable = [1, 2, 3]
         self.ctx = LoopContext(self.iterable)
@@ -199,7 +198,7 @@
 
     def test_reverse_index(self):
         length = len(self.iterable)
-        expected = tuple([length - i - 1 for i in range(length)])
+        expected = tuple(length - i - 1 for i in range(length))
         actual = tuple(self.ctx.reverse_index for i in self.ctx)
         print(expected, actual)
         assert expected == actual, (
diff --git a/third_party/mako/mako/test/test_lru.py b/third_party/mako/mako/test/test_lru.py
index 72815379..f54bd15 100644
--- a/third_party/mako/mako/test/test_lru.py
+++ b/third_party/mako/mako/test/test_lru.py
@@ -1,5 +1,3 @@
-import unittest
-
 from mako.util import LRUCache
 
 
@@ -11,7 +9,7 @@
         return "item id %d" % self.id
 
 
-class LRUTest(unittest.TestCase):
+class LRUTest:
     def testlru(self):
         l = LRUCache(10, threshold=0.2)
 
diff --git a/third_party/mako/mako/test/test_namespace.py b/third_party/mako/mako/test/test_namespace.py
index 8d223d5..b6b0544 100644
--- a/third_party/mako/mako/test/test_namespace.py
+++ b/third_party/mako/mako/test/test_namespace.py
@@ -1,9 +1,12 @@
+from mako import exceptions
 from mako import lookup
 from mako.template import Template
-from test import eq_
-from test import TemplateTest
-from test.util import flatten_result
-from test.util import result_lines
+from mako.testing.assertions import assert_raises
+from mako.testing.assertions import assert_raises_message_with_given_cause
+from mako.testing.assertions import eq_
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import flatten_result
+from mako.testing.helpers import result_lines
 
 
 class NamespaceTest(TemplateTest):
@@ -584,7 +587,7 @@
         """,
         )
 
-        self.assertRaises(AttributeError, l.get_template("bar.html").render)
+        assert_raises(AttributeError, l.get_template("bar.html").render)
 
     def test_custom_tag_1(self):
         template = Template(
@@ -994,3 +997,35 @@
             "this is lala",
             "this is foo",
         ]
+
+    def test_nonexistent_namespace_uri(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string(
+            "main.html",
+            """
+            <%namespace name="defs" file="eefs.html"/>
+
+            this is main.  ${defs.def1("hi")}
+            ${defs.def2("there")}
+""",
+        )
+
+        collection.put_string(
+            "defs.html",
+            """
+        <%def name="def1(s)">
+            def1: ${s}
+        </%def>
+
+        <%def name="def2(x)">
+            def2: ${x}
+        </%def>
+""",
+        )
+
+        assert_raises_message_with_given_cause(
+            exceptions.TemplateLookupException,
+            "Can't locate template for uri 'eefs.html",
+            exceptions.TopLevelLookupException,
+            collection.get_template("main.html").render,
+        )
diff --git a/third_party/mako/mako/test/test_pygen.py b/third_party/mako/mako/test/test_pygen.py
index daa76dea..8adc142 100644
--- a/third_party/mako/mako/test/test_pygen.py
+++ b/third_party/mako/mako/test/test_pygen.py
@@ -1,12 +1,11 @@
-import unittest
+from io import StringIO
 
-from mako.compat import StringIO
 from mako.pygen import adjust_whitespace
 from mako.pygen import PythonPrinter
-from test import eq_
+from mako.testing.assertions import eq_
 
 
-class GeneratePythonTest(unittest.TestCase):
+class GeneratePythonTest:
     def test_generate_normal(self):
         stream = StringIO()
         printer = PythonPrinter(stream)
@@ -165,7 +164,7 @@
         )
 
 
-class WhitespaceTest(unittest.TestCase):
+class WhitespaceTest:
     def test_basic(self):
         text = """
         for x in range(0,15):
diff --git a/third_party/mako/mako/test/test_runtime.py b/third_party/mako/mako/test/test_runtime.py
index d87d264..0d6fce37 100644
--- a/third_party/mako/mako/test/test_runtime.py
+++ b/third_party/mako/mako/test/test_runtime.py
@@ -1,12 +1,10 @@
 """Assorted runtime unit tests
 """
-import unittest
-
 from mako import runtime
-from test import eq_
+from mako.testing.assertions import eq_
 
 
-class ContextTest(unittest.TestCase):
+class ContextTest:
     def test_locals_kwargs(self):
         c = runtime.Context(None, foo="bar")
         eq_(c.kwargs, {"foo": "bar"})
diff --git a/third_party/mako/mako/test/test_template.py b/third_party/mako/mako/test/test_template.py
index 40fd10cc..fc1aeca 100644
--- a/third_party/mako/mako/test/test_template.py
+++ b/third_party/mako/mako/test/test_template.py
@@ -1,30 +1,23 @@
-# -*- coding: utf-8 -*-
-
 import os
-import unittest
 
-from mako import compat
 from mako import exceptions
 from mako import runtime
 from mako import util
-from mako.compat import u
 from mako.ext.preprocessors import convert_comments
 from mako.lookup import TemplateLookup
 from mako.template import ModuleInfo
 from mako.template import ModuleTemplate
 from mako.template import Template
-from test import assert_raises
-from test import assert_raises_message
-from test import eq_
-from test import module_base
-from test import requires_python_2
-from test import template_base
-from test import TemplateTest
-from test.util import flatten_result
-from test.util import result_lines
+from mako.testing.assertions import assert_raises
+from mako.testing.assertions import assert_raises_message
+from mako.testing.assertions import eq_
+from mako.testing.config import config
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import flatten_result
+from mako.testing.helpers import result_lines
 
 
-class ctx(object):
+class ctx:
     def __init__(self, a, b):
         pass
 
@@ -35,6 +28,23 @@
         pass
 
 
+class MiscTest(TemplateTest):
+    def test_crlf_linebreaks(self):
+
+        crlf = r"""
+<%
+    foo = True
+    bar = True
+%>
+% if foo and \
+     bar:
+     foo and bar
+%endif
+"""
+        crlf = crlf.replace("\n", "\r\n")
+        self._do_test(Template(crlf), "\r\n\r\n     foo and bar\r\n")
+
+
 class EncodingTest(TemplateTest):
     def test_escapes_html_tags(self):
         from mako.exceptions import html_error_template
@@ -51,34 +61,23 @@
         except:
             # <h3>Exception: <span style="color:red">Foobar</span></h3>
             markup = html_error_template().render(full=False, css=False)
-            if compat.py3k:
-                assert (
-                    '<span style="color:red">Foobar</span></h3>'.encode(
-                        "ascii"
-                    )
-                    not in markup
-                )
-                assert (
-                    "&lt;span style=&#34;color:red&#34;"
-                    "&gt;Foobar&lt;/span&gt;".encode("ascii") in markup
-                )
-            else:
-                assert (
-                    '<span style="color:red">Foobar</span></h3>' not in markup
-                )
-                assert (
-                    "&lt;span style=&#34;color:red&#34;"
-                    "&gt;Foobar&lt;/span&gt;" in markup
-                )
+            assert (
+                '<span style="color:red">Foobar</span></h3>'.encode("ascii")
+                not in markup
+            )
+            assert (
+                "&lt;span style=&#34;color:red&#34;"
+                "&gt;Foobar&lt;/span&gt;".encode("ascii") in markup
+            )
 
     def test_unicode(self):
         self._do_memory_test(
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
             ),
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
@@ -87,12 +86,12 @@
 
     def test_encoding_doesnt_conflict(self):
         self._do_memory_test(
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
             ),
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
@@ -101,14 +100,14 @@
         )
 
     def test_unicode_arg(self):
-        val = u(
+        val = (
             "Alors vous imaginez ma surprise, au lever du jour, quand "
             "une drôle de petite voix m’a réveillé. Elle disait: "
             "« S’il vous plaît… dessine-moi un mouton! »"
         )
         self._do_memory_test(
             "${val}",
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
@@ -119,7 +118,7 @@
     def test_unicode_file(self):
         self._do_file_test(
             "unicode.html",
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
@@ -129,29 +128,26 @@
     def test_unicode_file_code(self):
         self._do_file_test(
             "unicode_code.html",
-            u("""hi, drôle de petite voix m’a réveillé."""),
+            ("""hi, drôle de petite voix m’a réveillé."""),
             filters=flatten_result,
         )
 
     def test_unicode_file_lookup(self):
         lookup = TemplateLookup(
-            directories=[template_base],
+            directories=[config.template_base],
             output_encoding="utf-8",
             default_filters=["decode.utf8"],
         )
-        if compat.py3k:
-            template = lookup.get_template("/chs_unicode_py3k.html")
-        else:
-            template = lookup.get_template("/chs_unicode.html")
+        template = lookup.get_template("/chs_unicode_py3k.html")
         eq_(
             flatten_result(template.render_unicode(name="毛泽东")),
-            u("毛泽东 是 新中国的主席<br/> Welcome 你 to 北京."),
+            ("毛泽东 是 新中国的主席<br/> Welcome 你 to 北京."),
         )
 
     def test_unicode_bom(self):
         self._do_file_test(
             "bom.html",
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
@@ -160,29 +156,29 @@
 
         self._do_file_test(
             "bommagic.html",
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
             ),
         )
 
-        self.assertRaises(
+        assert_raises(
             exceptions.CompileException,
             Template,
             filename=self._file_path("badbom.html"),
-            module_directory=module_base,
+            module_directory=config.module_base,
         )
 
     def test_unicode_memory(self):
-        val = u(
+        val = (
             "Alors vous imaginez ma surprise, au lever du jour, quand "
             "une drôle de petite voix m’a réveillé. Elle disait: "
             "« S’il vous plaît… dessine-moi un mouton! »"
         )
         self._do_memory_test(
             ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"),
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
@@ -190,14 +186,14 @@
         )
 
     def test_unicode_text(self):
-        val = u(
+        val = (
             "<%text>Alors vous imaginez ma surprise, au lever du jour, quand "
             "une drôle de petite voix m’a réveillé. Elle disait: "
             "« S’il vous plaît… dessine-moi un mouton! »</%text>"
         )
         self._do_memory_test(
             ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"),
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
@@ -205,8 +201,7 @@
         )
 
     def test_unicode_text_ccall(self):
-        val = u(
-            """
+        val = """
         <%def name="foo()">
             ${capture(caller.body)}
         </%def>
@@ -215,10 +210,9 @@
 quand une drôle de petite voix m’a réveillé. Elle disait:
 « S’il vous plaît… dessine-moi un mouton! »</%text>
         </%call>"""
-        )
         self._do_memory_test(
             ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"),
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
@@ -227,43 +221,26 @@
         )
 
     def test_unicode_literal_in_expr(self):
-        if compat.py3k:
-            self._do_memory_test(
-                u(
-                    "## -*- coding: utf-8 -*-\n"
-                    '${"Alors vous imaginez ma surprise, au lever du jour, '
-                    "quand une drôle de petite voix m’a réveillé. "
-                    "Elle disait: "
-                    '« S’il vous plaît… dessine-moi un mouton! »"}\n'
-                ).encode("utf-8"),
-                u(
-                    "Alors vous imaginez ma surprise, au lever du jour, "
-                    "quand une drôle de petite voix m’a réveillé. "
-                    "Elle disait: « S’il vous plaît… dessine-moi un mouton! »"
-                ),
-                filters=lambda s: s.strip(),
-            )
-        else:
-            self._do_memory_test(
-                u(
-                    "## -*- coding: utf-8 -*-\n"
-                    '${u"Alors vous imaginez ma surprise, au lever du jour, '
-                    "quand une drôle de petite voix m’a réveillé. "
-                    "Elle disait: « S’il vous plaît… dessine-moi un "
-                    'mouton! »"}'
-                ).encode("utf-8"),
-                u(
-                    "Alors vous imaginez ma surprise, au lever du jour, "
-                    "quand une drôle de petite voix m’a réveillé. "
-                    "Elle disait: « S’il vous plaît… dessine-moi un mouton! »"
-                ),
-                filters=lambda s: s.strip(),
-            )
+        self._do_memory_test(
+            (
+                "## -*- coding: utf-8 -*-\n"
+                '${"Alors vous imaginez ma surprise, au lever du jour, '
+                "quand une drôle de petite voix m’a réveillé. "
+                "Elle disait: "
+                '« S’il vous plaît… dessine-moi un mouton! »"}\n'
+            ).encode("utf-8"),
+            (
+                "Alors vous imaginez ma surprise, au lever du jour, "
+                "quand une drôle de petite voix m’a réveillé. "
+                "Elle disait: « S’il vous plaît… dessine-moi un mouton! »"
+            ),
+            filters=lambda s: s.strip(),
+        )
 
     def test_unicode_literal_in_expr_file(self):
         self._do_file_test(
             "unicode_expr.html",
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, "
                 "quand une drôle de petite voix m’a réveillé. "
                 "Elle disait: « S’il vous plaît… dessine-moi un mouton! »"
@@ -272,85 +249,49 @@
         )
 
     def test_unicode_literal_in_code(self):
-        if compat.py3k:
-            self._do_memory_test(
-                u(
-                    """## -*- coding: utf-8 -*-
-                <%
-                    context.write("Alors vous imaginez ma surprise, au """
-                    """lever du jour, quand une drôle de petite voix m’a """
-                    """réveillé. Elle disait: """
-                    """« S’il vous plaît… dessine-moi un mouton! »")
-                %>
-                """
-                ).encode("utf-8"),
-                u(
-                    "Alors vous imaginez ma surprise, au lever du jour, "
-                    "quand une drôle de petite voix m’a réveillé. "
-                    "Elle disait: « S’il vous plaît… dessine-moi un mouton! »"
-                ),
-                filters=lambda s: s.strip(),
-            )
-        else:
-            self._do_memory_test(
-                u(
-                    """## -*- coding: utf-8 -*-
-                <%
-                    context.write(u"Alors vous imaginez ma surprise, """
-                    """au lever du jour, quand une drôle de petite voix """
-                    """m’a réveillé. Elle disait: « S’il vous plaît… """
-                    """dessine-moi un mouton! »")
-                %>
-                """
-                ).encode("utf-8"),
-                u(
-                    "Alors vous imaginez ma surprise, au lever du jour, "
-                    "quand une drôle de petite voix m’a réveillé. "
-                    "Elle disait: « S’il vous plaît… dessine-moi un mouton! »"
-                ),
-                filters=lambda s: s.strip(),
-            )
+        self._do_memory_test(
+            (
+                """## -*- coding: utf-8 -*-
+            <%
+                context.write("Alors vous imaginez ma surprise, au """
+                """lever du jour, quand une drôle de petite voix m’a """
+                """réveillé. Elle disait: """
+                """« S’il vous plaît… dessine-moi un mouton! »")
+            %>
+            """
+            ).encode("utf-8"),
+            (
+                "Alors vous imaginez ma surprise, au lever du jour, "
+                "quand une drôle de petite voix m’a réveillé. "
+                "Elle disait: « S’il vous plaît… dessine-moi un mouton! »"
+            ),
+            filters=lambda s: s.strip(),
+        )
 
     def test_unicode_literal_in_controlline(self):
-        if compat.py3k:
-            self._do_memory_test(
-                u(
-                    """## -*- coding: utf-8 -*-
-                <%
-                    x = "drôle de petite voix m’a réveillé."
-                %>
-                % if x=="drôle de petite voix m’a réveillé.":
-                    hi, ${x}
-                % endif
-                """
-                ).encode("utf-8"),
-                u("""hi, drôle de petite voix m’a réveillé."""),
-                filters=lambda s: s.strip(),
-            )
-        else:
-            self._do_memory_test(
-                u(
-                    """## -*- coding: utf-8 -*-
-                <%
-                    x = u"drôle de petite voix m’a réveillé."
-                %>
-                % if x==u"drôle de petite voix m’a réveillé.":
-                    hi, ${x}
-                % endif
-                """
-                ).encode("utf-8"),
-                u("""hi, drôle de petite voix m’a réveillé."""),
-                filters=lambda s: s.strip(),
-            )
+        self._do_memory_test(
+            (
+                """## -*- coding: utf-8 -*-
+            <%
+                x = "drôle de petite voix m’a réveillé."
+            %>
+            % if x=="drôle de petite voix m’a réveillé.":
+                hi, ${x}
+            % endif
+            """
+            ).encode("utf-8"),
+            ("""hi, drôle de petite voix m’a réveillé."""),
+            filters=lambda s: s.strip(),
+        )
 
     def test_unicode_literal_in_tag(self):
         self._do_file_test(
             "unicode_arguments.html",
             [
-                u("x is: drôle de petite voix m’a réveillé"),
-                u("x is: drôle de petite voix m’a réveillé"),
-                u("x is: drôle de petite voix m’a réveillé"),
-                u("x is: drôle de petite voix m’a réveillé"),
+                ("x is: drôle de petite voix m’a réveillé"),
+                ("x is: drôle de petite voix m’a réveillé"),
+                ("x is: drôle de petite voix m’a réveillé"),
+                ("x is: drôle de petite voix m’a réveillé"),
             ],
             filters=result_lines,
         )
@@ -358,148 +299,75 @@
         self._do_memory_test(
             util.read_file(self._file_path("unicode_arguments.html")),
             [
-                u("x is: drôle de petite voix m’a réveillé"),
-                u("x is: drôle de petite voix m’a réveillé"),
-                u("x is: drôle de petite voix m’a réveillé"),
-                u("x is: drôle de petite voix m’a réveillé"),
+                ("x is: drôle de petite voix m’a réveillé"),
+                ("x is: drôle de petite voix m’a réveillé"),
+                ("x is: drôle de petite voix m’a réveillé"),
+                ("x is: drôle de petite voix m’a réveillé"),
             ],
             filters=result_lines,
         )
 
     def test_unicode_literal_in_def(self):
-        if compat.py3k:
-            self._do_memory_test(
-                u(
-                    """## -*- coding: utf-8 -*-
-                <%def name="bello(foo, bar)">
-                Foo: ${ foo }
-                Bar: ${ bar }
-                </%def>
-                <%call expr="bello(foo='árvíztűrő tükörfúrógép', """
-                    """bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
-                </%call>"""
-                ).encode("utf-8"),
-                u(
-                    """Foo: árvíztűrő tükörfúrógép """
-                    """Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""
-                ),
-                filters=flatten_result,
-            )
+        self._do_memory_test(
+            (
+                """## -*- coding: utf-8 -*-
+            <%def name="bello(foo, bar)">
+            Foo: ${ foo }
+            Bar: ${ bar }
+            </%def>
+            <%call expr="bello(foo='árvíztűrő tükörfúrógép', """
+                """bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
+            </%call>"""
+            ).encode("utf-8"),
+            (
+                """Foo: árvíztűrő tükörfúrógép """
+                """Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""
+            ),
+            filters=flatten_result,
+        )
 
-            self._do_memory_test(
-                u(
-                    "## -*- coding: utf-8 -*-\n"
-                    """<%def name="hello(foo='árvíztűrő tükörfúrógép', """
-                    """bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">\n"""
-                    "Foo: ${ foo }\n"
-                    "Bar: ${ bar }\n"
-                    "</%def>\n"
-                    "${ hello() }"
-                ).encode("utf-8"),
-                u(
-                    """Foo: árvíztűrő tükörfúrógép Bar: """
-                    """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""
-                ),
-                filters=flatten_result,
-            )
-        else:
-            self._do_memory_test(
-                u(
-                    """## -*- coding: utf-8 -*-
-                <%def name="bello(foo, bar)">
-                Foo: ${ foo }
-                Bar: ${ bar }
-                </%def>
-                <%call expr="bello(foo=u'árvíztűrő tükörfúrógép', """
-                    """bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
-                </%call>"""
-                ).encode("utf-8"),
-                u(
-                    """Foo: árvíztűrő tükörfúrógép Bar: """
-                    """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""
-                ),
-                filters=flatten_result,
-            )
-
-            self._do_memory_test(
-                u(
-                    """## -*- coding: utf-8 -*-
-                <%def name="hello(foo=u'árvíztűrő tükörfúrógép', """
-                    """bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
-                Foo: ${ foo }
-                Bar: ${ bar }
-                </%def>
-                ${ hello() }"""
-                ).encode("utf-8"),
-                u(
-                    """Foo: árvíztűrő tükörfúrógép Bar: """
-                    """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""
-                ),
-                filters=flatten_result,
-            )
+        self._do_memory_test(
+            (
+                "## -*- coding: utf-8 -*-\n"
+                """<%def name="hello(foo='árvíztűrő tükörfúrógép', """
+                """bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">\n"""
+                "Foo: ${ foo }\n"
+                "Bar: ${ bar }\n"
+                "</%def>\n"
+                "${ hello() }"
+            ).encode("utf-8"),
+            (
+                """Foo: árvíztűrő tükörfúrógép Bar: """
+                """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""
+            ),
+            filters=flatten_result,
+        )
 
     def test_input_encoding(self):
         """test the 'input_encoding' flag on Template, and that unicode
-            objects arent double-decoded"""
-
-        if compat.py3k:
-            self._do_memory_test(
-                u("hello ${f('śląsk')}"),
-                u("hello śląsk"),
-                input_encoding="utf-8",
-                template_args={"f": lambda x: x},
-            )
-
-            self._do_memory_test(
-                u("## -*- coding: utf-8 -*-\nhello ${f('śląsk')}"),
-                u("hello śląsk"),
-                template_args={"f": lambda x: x},
-            )
-        else:
-            self._do_memory_test(
-                u("hello ${f(u'śląsk')}"),
-                u("hello śląsk"),
-                input_encoding="utf-8",
-                template_args={"f": lambda x: x},
-            )
-
-            self._do_memory_test(
-                u("## -*- coding: utf-8 -*-\nhello ${f(u'śląsk')}"),
-                u("hello śląsk"),
-                template_args={"f": lambda x: x},
-            )
-
-    def test_raw_strings(self):
-        """test that raw strings go straight thru with default_filters
-        turned off, bytestring_passthrough enabled.
-
-        """
+        objects arent double-decoded"""
 
         self._do_memory_test(
-            u("## -*- coding: utf-8 -*-\nhello ${x}"),
-            "hello śląsk",
-            default_filters=[],
-            template_args={"x": "śląsk"},
-            unicode_=False,
-            bytestring_passthrough=True,
-            output_encoding=None,  # 'ascii'
+            ("hello ${f('śląsk')}"),
+            ("hello śląsk"),
+            input_encoding="utf-8",
+            template_args={"f": lambda x: x},
         )
 
-        # now, the way you *should* be doing it....
         self._do_memory_test(
-            u("## -*- coding: utf-8 -*-\nhello ${x}"),
-            u("hello śląsk"),
-            template_args={"x": u("śląsk")},
+            ("## -*- coding: utf-8 -*-\nhello ${f('śląsk')}"),
+            ("hello śląsk"),
+            template_args={"f": lambda x: x},
         )
 
     def test_encoding(self):
         self._do_memory_test(
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
             ),
-            u(
+            (
                 "Alors vous imaginez ma surprise, au lever du jour, quand "
                 "une drôle de petite voix m’a réveillé. Elle disait: "
                 "« S’il vous plaît… dessine-moi un mouton! »"
@@ -510,13 +378,13 @@
 
     def test_encoding_errors(self):
         self._do_memory_test(
-            u(
+            (
                 """KGB (transliteration of "КГБ") is the Russian-language """
                 """abbreviation for Committee for State Security, """
                 """(Russian: Комит́ет Госуд́арственной Безоп́асности """
                 """(help·info); Komitet Gosudarstvennoy Bezopasnosti)"""
             ),
-            u(
+            (
                 """KGB (transliteration of "КГБ") is the Russian-language """
                 """abbreviation for Committee for State Security, """
                 """(Russian: Комит́ет Госуд́арственной Безоп́асности """
@@ -529,79 +397,17 @@
 
     def test_read_unicode(self):
         lookup = TemplateLookup(
-            directories=[template_base],
+            directories=[config.template_base],
             filesystem_checks=True,
             output_encoding="utf-8",
         )
-        if compat.py3k:
-            template = lookup.get_template("/read_unicode_py3k.html")
-        else:
-            template = lookup.get_template("/read_unicode.html")
+        template = lookup.get_template("/read_unicode_py3k.html")
         # TODO: I've no idea what encoding this file is, Python 3.1.2
         # won't read the file even with open(...encoding='utf-8') unless
         # errors is specified.   or if there's some quirk in 3.1.2
         # since I'm pretty sure this test worked with py3k when I wrote it.
         template.render(path=self._file_path("internationalization.html"))
 
-    @requires_python_2
-    def test_bytestring_passthru(self):
-        self._do_file_test(
-            "chs_utf8.html",
-            "毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.",
-            default_filters=[],
-            disable_unicode=True,
-            output_encoding=None,
-            template_args={"name": "毛泽东"},
-            filters=flatten_result,
-            unicode_=False,
-        )
-
-        self._do_file_test(
-            "chs_utf8.html",
-            "毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.",
-            disable_unicode=True,
-            output_encoding=None,
-            template_args={"name": "毛泽东"},
-            filters=flatten_result,
-            unicode_=False,
-        )
-
-        template = self._file_template(
-            "chs_utf8.html", output_encoding=None, disable_unicode=True
-        )
-        self.assertRaises(
-            UnicodeDecodeError, template.render_unicode, name="毛泽东"
-        )
-
-        template = Template(
-            "${'Alors vous imaginez ma surprise, au lever"
-            " du jour, quand une drôle de petite voix m’a "
-            "réveillé. Elle disait: « S’il vous plaît… "
-            "dessine-moi un mouton! »'}",
-            output_encoding=None,
-            disable_unicode=True,
-            input_encoding="utf-8",
-        )
-        assert (
-            template.render() == "Alors vous imaginez ma surprise, "
-            "au lever du jour, quand une drôle de petite "
-            "voix m’a réveillé. Elle disait: « S’il vous "
-            "plaît… dessine-moi un mouton! »"
-        )
-        template = Template(
-            "${'Alors vous imaginez ma surprise, au "
-            "lever du jour, quand une drôle de petite "
-            "voix m’a réveillé. Elle disait: « S’il "
-            "vous plaît… dessine-moi un mouton! »'}",
-            input_encoding="utf8",
-            output_encoding="utf8",
-            disable_unicode=False,
-            default_filters=[],
-        )
-        # raises because expression contains an encoded bytestring which cannot
-        # be decoded
-        self.assertRaises(UnicodeDecodeError, template.render)
-
 
 class PageArgsTest(TemplateTest):
     def test_basic(self):
@@ -1094,7 +900,7 @@
                 exceptions.NameConflictError,
                 r"Reserved words passed to render\(\): %s" % name,
                 Template("x").render,
-                **{name: "foo"}
+                **{name: "foo"},
             )
 
     def test_names_in_template(self):
@@ -1134,15 +940,18 @@
     %endfor
 """
         )
-        assert result_lines(
-            t.render(
-                y=[
-                    {"test": "one"},
-                    {"foo": "bar"},
-                    {"foo": "bar", "test": "two"},
-                ]
+        assert (
+            result_lines(
+                t.render(
+                    y=[
+                        {"test": "one"},
+                        {"foo": "bar"},
+                        {"foo": "bar", "test": "two"},
+                    ]
+                )
             )
-        ) == ["yes x has test", "no x does not have test", "yes x has test"]
+            == ["yes x has test", "no x does not have test", "yes x has test"]
+        )
 
     def test_blank_control_1(self):
         self._do_memory_test(
@@ -1358,15 +1167,16 @@
 
 class RichTracebackTest(TemplateTest):
     def _do_test_traceback(self, utf8, memory, syntax):
+
         if memory:
             if syntax:
-                source = u(
+                source = (
                     '## coding: utf-8\n<% print "m’a réveillé. '
                     "Elle disait: « S’il vous plaît… dessine-moi "
                     "un mouton! » %>"
                 )
             else:
-                source = u(
+                source = (
                     '## coding: utf-8\n<% print u"m’a réveillé. '
                     "Elle disait: « S’il vous plaît… dessine-moi un "
                     'mouton! »" + str(5/0) %>'
@@ -1416,40 +1226,47 @@
 
 
 class ModuleDirTest(TemplateTest):
-    def tearDown(self):
+    def teardown_method(self):
         import shutil
 
-        shutil.rmtree(module_base, True)
+        shutil.rmtree(config.module_base, True)
 
     def test_basic(self):
         t = self._file_template("modtest.html")
         t2 = self._file_template("subdir/modtest.html")
 
-        eq_(t.module.__file__, os.path.join(module_base, "modtest.html.py"))
+        eq_(
+            t.module.__file__,
+            os.path.join(config.module_base, "modtest.html.py"),
+        )
         eq_(
             t2.module.__file__,
-            os.path.join(module_base, "subdir", "modtest.html.py"),
+            os.path.join(config.module_base, "subdir", "modtest.html.py"),
         )
 
     def test_callable(self):
         def get_modname(filename, uri):
             return os.path.join(
-                module_base,
+                config.module_base,
                 os.path.dirname(uri)[1:],
                 "foo",
                 os.path.basename(filename) + ".py",
             )
 
-        lookup = TemplateLookup(template_base, modulename_callable=get_modname)
+        lookup = TemplateLookup(
+            config.template_base, modulename_callable=get_modname
+        )
         t = lookup.get_template("/modtest.html")
         t2 = lookup.get_template("/subdir/modtest.html")
         eq_(
             t.module.__file__,
-            os.path.join(module_base, "foo", "modtest.html.py"),
+            os.path.join(config.module_base, "foo", "modtest.html.py"),
         )
         eq_(
             t2.module.__file__,
-            os.path.join(module_base, "subdir", "foo", "modtest.html.py"),
+            os.path.join(
+                config.module_base, "subdir", "foo", "modtest.html.py"
+            ),
         )
 
     def test_custom_writer(self):
@@ -1462,17 +1279,17 @@
             f.close()
 
         lookup = TemplateLookup(
-            template_base,
+            config.template_base,
             module_writer=write_module,
-            module_directory=module_base,
+            module_directory=config.module_base,
         )
         lookup.get_template("/modtest.html")
         lookup.get_template("/subdir/modtest.html")
         eq_(
             canary,
             [
-                os.path.join(module_base, "modtest.html.py"),
-                os.path.join(module_base, "subdir", "modtest.html.py"),
+                os.path.join(config.module_base, "modtest.html.py"),
+                os.path.join(config.module_base, "subdir", "modtest.html.py"),
             ],
         )
 
@@ -1626,7 +1443,7 @@
         ]
 
 
-class TestTemplateAPI(unittest.TestCase):
+class TestTemplateAPI:
     def test_metadata(self):
         t = Template(
             """
@@ -1816,7 +1633,7 @@
     def _fixture(self):
         from mako.parsetree import TemplateNode, Text
 
-        class MyLexer(object):
+        class MyLexer:
             encoding = "ascii"
 
             def __init__(self, *arg, **kw):
diff --git a/third_party/mako/mako/test/test_tgplugin.py b/third_party/mako/mako/test/test_tgplugin.py
index df95d00..38998c2 100644
--- a/third_party/mako/mako/test/test_tgplugin.py
+++ b/third_party/mako/mako/test/test_tgplugin.py
@@ -1,10 +1,11 @@
-from mako import compat
 from mako.ext.turbogears import TGPlugin
-from test import template_base
-from test import TemplateTest
-from test.util import result_lines
+from mako.testing.config import config
+from mako.testing.fixtures import TemplateTest
+from mako.testing.helpers import result_lines
 
-tl = TGPlugin(options=dict(directories=[template_base]), extension="html")
+tl = TGPlugin(
+    options=dict(directories=[config.template_base]), extension="html"
+)
 
 
 class TestTGPlugin(TemplateTest):
@@ -47,6 +48,6 @@
         assert result_lines(tl.render({}, template="/index.html")) == [
             "this is index"
         ]
-        assert result_lines(
-            tl.render({}, template=compat.u("/index.html"))
-        ) == ["this is index"]
+        assert result_lines(tl.render({}, template=("/index.html"))) == [
+            "this is index"
+        ]
diff --git a/third_party/mako/mako/test/test_util.py b/third_party/mako/mako/test/test_util.py
index e40390f7..95c1cb4 100644
--- a/third_party/mako/mako/test/test_util.py
+++ b/third_party/mako/mako/test/test_util.py
@@ -1,19 +1,19 @@
-# -*- coding: utf-8 -*-
-
 import os
 import sys
-import unittest
+
+import pytest
 
 from mako import compat
 from mako import exceptions
 from mako import util
-from mako.compat import u
-from test import assert_raises_message
-from test import eq_
-from test import skip_if
+from mako.testing.assertions import assert_raises_message
+from mako.testing.assertions import eq_
+from mako.testing.assertions import in_
+from mako.testing.assertions import ne_
+from mako.testing.assertions import not_in
 
 
-class UtilTest(unittest.TestCase):
+class UtilTest:
     def test_fast_buffer_write(self):
         buf = util.FastEncodingBuffer()
         buf.write("string a ")
@@ -30,7 +30,7 @@
         eq_(buf.getvalue(), "string c string d")
 
     def test_fast_buffer_encoded(self):
-        s = u("drôl m’a rée « S’il")
+        s = "drôl m’a rée « S’il"
         buf = util.FastEncodingBuffer(encoding="utf-8")
         buf.write(s[0:10])
         buf.write(s[10:])
@@ -39,18 +39,18 @@
     def test_read_file(self):
         fn = os.path.join(os.path.dirname(__file__), "test_util.py")
         data = util.read_file(fn, "rb")
-        assert "test_util" in str(data)  # str() for py3k
+        assert b"test_util" in data
 
-    @skip_if(lambda: compat.pypy, "Pypy does this differently")
+    @pytest.mark.skipif(compat.pypy, reason="Pypy does this differently")
     def test_load_module(self):
-        fn = os.path.join(os.path.dirname(__file__), "test_util.py")
-        sys.modules.pop("mako.template")
-        module = compat.load_module("mako.template", fn)
-        self.assertNotIn("mako.template", sys.modules)
-        self.assertIn("UtilTest", dir(module))
-        import mako.template
+        path = os.path.join(os.path.dirname(__file__), "module_to_import.py")
+        some_module = compat.load_module("test.module_to_import", path)
 
-        self.assertNotEqual(module, mako.template)
+        not_in("test.module_to_import", sys.modules)
+        in_("some_function", dir(some_module))
+        import test.module_to_import
+
+        ne_(some_module, test.module_to_import)
 
     def test_load_plugin_failure(self):
         loader = util.PluginLoader("fakegroup")
diff --git a/third_party/mako/mako/test/testing/dummy.cfg b/third_party/mako/mako/test/testing/dummy.cfg
new file mode 100644
index 0000000..39644a3
--- /dev/null
+++ b/third_party/mako/mako/test/testing/dummy.cfg
@@ -0,0 +1,25 @@
+[boolean_values]
+yes = yes
+one = 1
+true = true
+on = on
+no = no
+zero = 0
+false = false
+off = off
+
+[additional_types]
+decimal_value = 100001.01
+datetime_value = 2021-12-04 00:05:23.283
+
+[type_mismatch]
+int_value = foo
+
+[missing_item]
+present_item = HERE
+
+[basic_values]
+int_value = 15421
+bool_value = true
+float_value = 14.01
+str_value = Ceci n'est pas une chaîne
diff --git a/third_party/mako/mako/test/testing/test_config.py b/third_party/mako/mako/test/testing/test_config.py
new file mode 100644
index 0000000..680d7a4
--- /dev/null
+++ b/third_party/mako/mako/test/testing/test_config.py
@@ -0,0 +1,176 @@
+import configparser
+from dataclasses import dataclass
+from datetime import datetime
+from decimal import Decimal
+from pathlib import Path
+
+import pytest
+
+from mako.testing._config import ConfigValueTypeError
+from mako.testing._config import MissingConfig
+from mako.testing._config import MissingConfigItem
+from mako.testing._config import MissingConfigSection
+from mako.testing._config import ReadsCfg
+from mako.testing.assertions import assert_raises_message_with_given_cause
+from mako.testing.assertions import assert_raises_with_given_cause
+
+PATH_TO_TEST_CONFIG = Path(__file__).parent / "dummy.cfg"
+
+
+@dataclass
+class BasicConfig(ReadsCfg):
+    int_value: int
+    bool_value: bool
+    float_value: float
+    str_value: str
+
+    section_header = "basic_values"
+
+
+@dataclass
+class BooleanConfig(ReadsCfg):
+    yes: bool
+    one: bool
+    true: bool
+    on: bool
+    no: bool
+    zero: bool
+    false: bool
+    off: bool
+
+    section_header = "boolean_values"
+
+
+@dataclass
+class UnsupportedTypesConfig(ReadsCfg):
+    decimal_value: Decimal
+    datetime_value: datetime
+
+    section_header = "additional_types"
+
+
+@dataclass
+class SupportedTypesConfig(ReadsCfg):
+    decimal_value: Decimal
+    datetime_value: datetime
+
+    section_header = "additional_types"
+    converters = {
+        Decimal: lambda v: Decimal(str(v)),
+        datetime: lambda v: datetime.fromisoformat(v),
+    }
+
+
+@dataclass
+class NonexistentSectionConfig(ReadsCfg):
+    some_value: str
+    another_value: str
+
+    section_header = "i_dont_exist"
+
+
+@dataclass
+class TypeMismatchConfig(ReadsCfg):
+    int_value: int
+
+    section_header = "type_mismatch"
+
+
+@dataclass
+class MissingItemConfig(ReadsCfg):
+    present_item: str
+    missing_item: str
+
+    section_header = "missing_item"
+
+
+class BasicConfigTest:
+    @pytest.fixture(scope="class")
+    def config(self):
+        return BasicConfig.from_cfg_file(PATH_TO_TEST_CONFIG)
+
+    def test_coercions(self, config):
+        assert isinstance(config.int_value, int)
+        assert isinstance(config.bool_value, bool)
+        assert isinstance(config.float_value, float)
+        assert isinstance(config.str_value, str)
+
+    def test_values(self, config):
+        assert config.int_value == 15421
+        assert config.bool_value == True
+        assert config.float_value == 14.01
+        assert config.str_value == "Ceci n'est pas une chaîne"
+
+    def test_error_on_loading_from_nonexistent_file(self):
+        assert_raises_with_given_cause(
+            MissingConfig,
+            FileNotFoundError,
+            BasicConfig.from_cfg_file,
+            "./n/o/f/i/l/e/h.ere",
+        )
+
+    def test_error_on_loading_from_nonexistent_section(self):
+        assert_raises_with_given_cause(
+            MissingConfigSection,
+            configparser.NoSectionError,
+            NonexistentSectionConfig.from_cfg_file,
+            PATH_TO_TEST_CONFIG,
+        )
+
+
+class BooleanConfigTest:
+    @pytest.fixture(scope="class")
+    def config(self):
+        return BooleanConfig.from_cfg_file(PATH_TO_TEST_CONFIG)
+
+    def test_values(self, config):
+        assert config.yes is True
+        assert config.one is True
+        assert config.true is True
+        assert config.on is True
+        assert config.no is False
+        assert config.zero is False
+        assert config.false is False
+        assert config.off is False
+
+
+class UnsupportedTypesConfigTest:
+    @pytest.fixture(scope="class")
+    def config(self):
+        return UnsupportedTypesConfig.from_cfg_file(PATH_TO_TEST_CONFIG)
+
+    def test_values(self, config):
+        assert config.decimal_value == "100001.01"
+        assert config.datetime_value == "2021-12-04 00:05:23.283"
+
+
+class SupportedTypesConfigTest:
+    @pytest.fixture(scope="class")
+    def config(self):
+        return SupportedTypesConfig.from_cfg_file(PATH_TO_TEST_CONFIG)
+
+    def test_values(self, config):
+        assert config.decimal_value == Decimal("100001.01")
+        assert config.datetime_value == datetime(2021, 12, 4, 0, 5, 23, 283000)
+
+
+class TypeMismatchConfigTest:
+    def test_error_on_load(self):
+        assert_raises_message_with_given_cause(
+            ConfigValueTypeError,
+            "Wrong value type for int_value",
+            ValueError,
+            TypeMismatchConfig.from_cfg_file,
+            PATH_TO_TEST_CONFIG,
+        )
+
+
+class MissingItemConfigTest:
+    def test_error_on_load(self):
+        assert_raises_message_with_given_cause(
+            MissingConfigItem,
+            "No config item for missing_item",
+            configparser.NoOptionError,
+            MissingItemConfig.from_cfg_file,
+            PATH_TO_TEST_CONFIG,
+        )
diff --git a/third_party/mako/mako/test/util.py b/third_party/mako/mako/test/util.py
deleted file mode 100644
index 29225e23..0000000
--- a/third_party/mako/mako/test/util.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import re
-
-
-def flatten_result(result):
-    return re.sub(r"[\s\r\n]+", " ", result).strip()
-
-
-def result_lines(result):
-    return [
-        x.strip()
-        for x in re.split(r"\r?\n", re.sub(r" +", " ", result))
-        if x.strip() != ""
-    ]
diff --git a/third_party/mako/mako/tox.ini b/third_party/mako/mako/tox.ini
index d3ef981..d8edd3cb 100644
--- a/third_party/mako/mako/tox.ini
+++ b/third_party/mako/mako/tox.ini
@@ -5,7 +5,6 @@
 cov_args=--cov=mako --cov-report term --cov-report xml
 
 deps=pytest>=3.1.0
-     mock
      beaker
      markupsafe
      pygments
@@ -17,7 +16,7 @@
 setenv=
     cov: COVERAGE={[testenv]cov_args}
 
-commands=py.test {env:COVERAGE:} {posargs}
+commands=pytest {env:COVERAGE:} {posargs}
 
 
 [testenv:pep8]
@@ -31,4 +30,7 @@
       pydocstyle<4.0.0
       # used by flake8-rst-docstrings
       pygments
-commands = flake8 ./mako/ ./test/ setup.py --exclude test/templates,test/foo  {posargs}
+      black==21.9b0
+commands =
+    flake8 ./mako/ ./test/ setup.py --exclude test/templates,test/foo  {posargs}
+    black --check .
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 6f7d3ba9..3bc11b8a 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -432,7 +432,6 @@
       'win-backuprefptr-x86-fyi-rel': 'release_trybot_backuprefptr_x86_reclient',
       'win-celab-builder-rel': 'release_bot_minimal_symbols_reclient',
       'win-fieldtrial-rel': 'gpu_tests_release_bot_minimal_symbols_reclient',
-      'win-pixel-builder-rel': 'release_bot_reclient',
       'win-upload-perfetto': 'release_bot_perfetto_zlib_reclient',
       'win10-code-coverage': 'clang_code_coverage_reclient',
       'win32-archive-rel-goma-rbe-canary': 'release_bot_x86_minimal_symbols_enable_archive_compression',
@@ -1040,6 +1039,8 @@
 
     'tryserver.chromium.fuchsia': {
       'fuchsia-arm64-cast': 'release_trybot_fuchsia_arm64_cast',
+      'fuchsia-binary-size': 'release_fuchsia_arm64',
+      'fuchsia-clang-tidy-rel': 'release_trybot_fuchsia',
       'fuchsia-compile-x64-dbg': 'debug_bot_fuchsia_compile_only',
       'fuchsia-deterministic-dbg': 'debug_bot_fuchsia',
       'fuchsia-fyi-arm64-dbg': 'debug_bot_fuchsia_arm64',
@@ -1056,8 +1057,6 @@
       'cast_shell_linux_arm64': 'cast_arm64_release_bot',
       'cast_shell_linux_dbg': 'cast_debug_bot',
       'chromium_presubmit': 'presubmit',
-      'fuchsia-binary-size': 'release_fuchsia_arm64',
-      'fuchsia-clang-tidy-rel': 'release_trybot_fuchsia',
       'fuchsia-fyi-arm64-rel': 'release_trybot_fuchsia_arm64',
       'fuchsia-fyi-x64-rel': 'release_trybot_fuchsia',
       'gpu-fyi-try-lacros-amd-rel': 'gpu_tests_ozone_linux_non_x11_release_trybot',
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index 634c33ccb..47328e2 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -1382,15 +1382,6 @@
       "use_remoteexec": true
     }
   },
-  "win-pixel-builder-rel": {
-    "gn_args": {
-      "dcheck_always_on": false,
-      "is_component_build": false,
-      "is_debug": false,
-      "use_rbe": true,
-      "use_remoteexec": true
-    }
-  },
   "win-upload-perfetto": {
     "gn_args": {
       "dcheck_always_on": false,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.fuchsia.json b/tools/mb/mb_config_expectations/tryserver.chromium.fuchsia.json
index 4c438485d..82f4529 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.fuchsia.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.fuchsia.json
@@ -11,6 +11,26 @@
       "use_goma": true
     }
   },
+  "fuchsia-binary-size": {
+    "gn_args": {
+      "dcheck_always_on": false,
+      "is_debug": false,
+      "is_official_build": true,
+      "target_cpu": "arm64",
+      "target_os": "fuchsia",
+      "use_goma": true
+    }
+  },
+  "fuchsia-clang-tidy-rel": {
+    "gn_args": {
+      "dcheck_always_on": true,
+      "is_component_build": false,
+      "is_debug": false,
+      "symbol_level": 0,
+      "target_os": "fuchsia",
+      "use_goma": true
+    }
+  },
   "fuchsia-compile-x64-dbg": {
     "gn_args": {
       "is_component_build": true,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
index 610320ed..2ddfaec 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.linux.json
@@ -50,26 +50,6 @@
       "use_goma": true
     }
   },
-  "fuchsia-binary-size": {
-    "gn_args": {
-      "dcheck_always_on": false,
-      "is_debug": false,
-      "is_official_build": true,
-      "target_cpu": "arm64",
-      "target_os": "fuchsia",
-      "use_goma": true
-    }
-  },
-  "fuchsia-clang-tidy-rel": {
-    "gn_args": {
-      "dcheck_always_on": true,
-      "is_component_build": false,
-      "is_debug": false,
-      "symbol_level": 0,
-      "target_os": "fuchsia",
-      "use_goma": true
-    }
-  },
   "fuchsia-fyi-arm64-rel": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 8f5c963..3d36a86 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -21141,6 +21141,8 @@
   <int value="16" label="Z">Z-compressed File</int>
   <int value="17" label="TAR.ZST">Zstandard-compressed TAR</int>
   <int value="18" label="ZST">Zstandard-compressed File</int>
+  <int value="19" label="TAR.LZ">LZIP-compressed TAR</int>
+  <int value="20" label="LZ">LZIP-compressed File</int>
 </enum>
 
 <enum name="CrosDisksClientFormatError">
@@ -42049,22 +42051,6 @@
   </int>
 </enum>
 
-<enum name="FileReaderLoaderFailureType">
-  <int value="0" label="Mojo pipe creation failed"/>
-  <int value="1" label="Data incomplete after synchronous reading"/>
-  <int value="2" label="OnComplete never called after synchronous reading"/>
-  <int value="3" label="The blob's total size too large for FileReaderLoader"/>
-  <int value="4" label="Failed to create the ArrayBufferBuilder"/>
-  <int value="5" label="Failed to append to the ArrayBufferBuilder"/>
-  <int value="6"
-      label="Backend read error, see Storage.Blob.FileReaderLoader.ReadError"/>
-  <int value="7" label="The size read does not match the size reported"/>
-  <int value="8"
-      label="The data pipe is not readable and there are bytes left to read"/>
-  <int value="9" label="The data pipe closed early"/>
-  <int value="10" label="Data pipe reading failed with an unexpected error"/>
-</enum>
-
 <enum name="FileReaderSyncWorkerType">
   <int value="0" label="Other"/>
   <int value="1" label="Dedicated Worker"/>
@@ -53441,6 +53427,8 @@
   <int value="10" label="kAtomics"/>
   <int value="11" label="kBulkMemory"/>
   <int value="12" label="kNonTrappingFloatToInt"/>
+  <int value="13" label="kGC"/>
+  <int value="14" label="kRelaxedSimd"/>
   <int value="20" label="kOtherReason"/>
 </enum>
 
@@ -57100,6 +57088,7 @@
   <int value="-535662704" label="BundledConnectionHelp:enabled"/>
   <int value="-535208779" label="enable-native-cups"/>
   <int value="-534722229" label="LauncherNudgeShortInterval:enabled"/>
+  <int value="-534525820" label="MediaAppPhotosIntegrationImage:enabled"/>
   <int value="-534470003" label="OmniboxOnDeviceHeadProviderIncognito:enabled"/>
   <int value="-534221085" label="LazyImageLoading:disabled"/>
   <int value="-533552313"
@@ -58033,6 +58022,7 @@
   <int value="89758831" label="FontAccessChooser:enabled"/>
   <int value="89785725"
       label="DataReductionProxyEnabledWithNetworkService:disabled"/>
+  <int value="89934221" label="MediaAppPhotosIntegrationImage:disabled"/>
   <int value="90551098" label="UseWallpaperStagingUrl:enabled"/>
   <int value="91916443" label="ManagedConfiguration:disabled"/>
   <int value="91938915" label="enable-suggestions-service"/>
@@ -59324,6 +59314,7 @@
   <int value="948085015" label="WebFilterInterstitialRefresh:disabled"/>
   <int value="948351976" label="WallpaperWebUI:disabled"/>
   <int value="948521531" label="StylusHandwriting:disabled"/>
+  <int value="951111587" label="MediaAppPhotosIntegrationVideo:disabled"/>
   <int value="952558794" label="enable-remote-assistance"/>
   <int value="955340765" label="ChromeHomeOptOutSnackbar:enabled"/>
   <int value="955425932" label="EnterpriseReportingInChromeOS:enabled"/>
@@ -59818,6 +59809,7 @@
   <int value="1266886673" label="delay-reload-stop-button-change"/>
   <int value="1268470658" label="disable-android-password-link"/>
   <int value="1268678442" label="KerberosSettingsSection:disabled"/>
+  <int value="1269216922" label="MediaAppPhotosIntegrationVideo:enabled"/>
   <int value="1269940659" label="EnumerateAudioDevices:enabled"/>
   <int value="1269952439" label="AndroidAIAFetching:disabled"/>
   <int value="1271871811" label="LegacyTLSEnforced:enabled"/>
@@ -93913,32 +93905,36 @@
 </enum>
 
 <enum name="TranslateBubbleUiEvent">
-  <int value="1" label="Switch to Options page"/>
-  <int value="2" label="Leave Options page"/>
+  <int value="1" label="[DEPRECATED] Switch to Options page"/>
+  <int value="2" label="[DEPRECATED] Leave Options page"/>
   <int value="3" label="[DEPRECATED] Advanced Link clicked"/>
   <int value="4" label="Always Translate checked"/>
   <int value="5" label="Always Translate unchecked"/>
   <int value="6" label="[DEPRECATED] Nope menu clicked"/>
   <int value="7" label="Never Translate Language menu clicked"/>
   <int value="8" label="Never Translate This Site menu clicked"/>
-  <int value="9" label="Translate button clicked"/>
+  <int value="9" label="Triggered translation by clicking target language tab"/>
   <int value="10" label="Done button clicked"/>
-  <int value="11" label="Cancel button clicked"/>
+  <int value="11" label="[DEPRECATED] Cancel button clicked"/>
   <int value="12" label="Close button clicked"/>
   <int value="13" label="Try Again button clicked"/>
-  <int value="14" label="Show Original button clicked"/>
+  <int value="14" label="Reverted translation by clicking source language tab"/>
   <int value="15" label="[DEPRECATED] Language Settings link clicked"/>
-  <int value="16" label="Source Language menu clicked"/>
-  <int value="17" label="Target Language menu clicked"/>
-  <int value="18" label="Page Action icon activated"/>
-  <int value="19" label="Page Action icon deactivated"/>
+  <int value="16" label="Language selected in source language combobox"/>
+  <int value="17" label="Language selected in target language combobox"/>
+  <int value="18" label="[DEPRECATED] Page Action icon activated"/>
+  <int value="19" label="[DEPRECATED] Page Action icon deactivated"/>
   <int value="20" label="Bubble was shown"/>
-  <int value="21" label="Bubble not shown: window is no longer valid"/>
+  <int value="21"
+      label="[DEPRECATED] Bubble not shown: window is no longer valid"/>
   <int value="22" label="Bubble not shown: window is minimized"/>
-  <int value="23" label="Bubble not shown: window is not active"/>
-  <int value="24" label="Bubble not shown: web contents not active"/>
+  <int value="23" label="[DEPRECATED] Bubble not shown: window is not active"/>
+  <int value="24"
+      label="[DEPRECATED] Bubble not shown: web contents not active"/>
   <int value="25" label="Bubble not shown: editable field is active"/>
-  <int value="26" label="Advanced menu item clicked"/>
+  <int value="26"
+      label="Page is Not in {Source Language} item, or Choose Another
+             Language item, in options menu clicked"/>
   <int value="27" label="[DEPRECATED] Advanced menu button clicked"/>
 </enum>
 
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index f184dc20..defa7c6 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -22,6 +22,12 @@
 
 <histograms>
 
+<variants name="AmbientModeThemes">
+  <variant name="FeelTheBreeze" summary="Feel the breeze"/>
+  <variant name="FloatOnBy" summary="Float on by"/>
+  <variant name="SlideShow" summary="Slide show"/>
+</variants>
+
 <variants name="DeviceActiveClientState">
   <variant name="CheckingIn"
       summary="The device active reporting client is in Checking In State"/>
@@ -181,11 +187,23 @@
   <owner>xiaohuic@chromium.org</owner>
   <summary>
     Among eligible users with ambient mode enabled, records the length of each
-    session. The metric is uploaded when ambient mode is ended.
+    session. The metric is emitted when ambient mode is ended. 2 new animated
+    ambient mode themes have been added started in M104.
   </summary>
   <token key="TabletOrClamshell" variants="DisplayModes"/>
 </histogram>
 
+<histogram name="Ash.AmbientMode.EngagementTime.{Theme}" units="ms"
+    expires_after="2022-12-01">
+  <owner>cowmoo@google.com</owner>
+  <owner>esum@google.com</owner>
+  <summary>
+    Among eligible users with ambient mode enabled, records the length of each
+    session for {Theme}. The metric is emitted when ambient mode is ended.
+  </summary>
+  <token key="Theme" variants="AmbientModeThemes"/>
+</histogram>
+
 <histogram name="Ash.AmbientMode.PhotoSource" enum="AmbientModePhotoSource"
     expires_after="2022-12-01">
   <owner>cowmoo@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/crostini/histograms.xml b/tools/metrics/histograms/metadata/crostini/histograms.xml
index 834051980..8bb1601 100644
--- a/tools/metrics/histograms/metadata/crostini/histograms.xml
+++ b/tools/metrics/histograms/metadata/crostini/histograms.xml
@@ -302,12 +302,33 @@
 </histogram>
 
 <histogram name="Crostini.RestarterResult" enum="CrostiniResult"
-    expires_after="2022-11-20">
+    expires_after="2023-05-01">
   <owner>davidmunro@google.com</owner>
   <owner>clumptini@google.com</owner>
   <summary>
-    The result of a single run of CrostiniRestarter. This is recorded any time
-    the crostini restart flow is triggered except during the initial install.
+    The result of a single run of CrostiniRestarter. This is recorded every time
+    the crostini restart flow is triggered except for the initial install and
+    (from M104) multi-container creation.
+  </summary>
+</histogram>
+
+<histogram name="Crostini.RestarterResult.Installer" enum="CrostiniResult"
+    expires_after="2023-05-01">
+  <owner>timloh@google.com</owner>
+  <owner>clumptini@google.com</owner>
+  <summary>
+    The result of a single run of CrostiniRestarter. This is recorded once for
+    each restart triggered by the Crostini installer.
+  </summary>
+</histogram>
+
+<histogram name="Crostini.RestarterResult.MultiContainerCreation"
+    enum="CrostiniResult" expires_after="2023-05-01">
+  <owner>timloh@google.com</owner>
+  <owner>clumptini@google.com</owner>
+  <summary>
+    The result of a single run of CrostiniRestarter. This is recorded once for
+    each restart triggered for multi-container creation.
   </summary>
 </histogram>
 
@@ -383,7 +404,8 @@
   <owner>clumptini@google.com</owner>
   <summary>
     Recorded each time the user completes the Crostini setup UI, recording the
-    result of the setup.
+    result of the setup. From M104, Crostini.RestartResult.Installer provides
+    more granular failures metrics.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/file/histograms.xml b/tools/metrics/histograms/metadata/file/histograms.xml
index ab3533cb..1745426 100644
--- a/tools/metrics/histograms/metadata/file/histograms.xml
+++ b/tools/metrics/histograms/metadata/file/histograms.xml
@@ -115,6 +115,7 @@
     <variant name="crx"/>
     <variant name="gz"/>
     <variant name="iso"/>
+    <variant name="lz"/>
     <variant name="lzma"/>
     <variant name="rar"/>
     <variant name="tar"/>
diff --git a/tools/metrics/histograms/metadata/storage/histograms.xml b/tools/metrics/histograms/metadata/storage/histograms.xml
index 81064b3..554920f 100644
--- a/tools/metrics/histograms/metadata/storage/histograms.xml
+++ b/tools/metrics/histograms/metadata/storage/histograms.xml
@@ -257,30 +257,6 @@
   </summary>
 </histogram>
 
-<histogram name="Storage.Blob.FileReaderLoader.FailureType"
-    enum="FileReaderLoaderFailureType" expires_after="M95">
-  <owner>mek@chromium.org</owner>
-  <owner>dmurph@chromium.org</owner>
-  <summary>
-    Recorded when an error occurs in the FileReaderLoader, which is used to load
-    blobs in the Renderer. FileReaderUser is mostly used for Javascript's
-    'FileReader', but can also be used to read blobs for the IndexedDB
-    renderer-side implementation. For the read error category, see
-    Storage.Blob.FileReaderLoader.ReadError for a breakdown of the specific read
-    error reasons.
-  </summary>
-</histogram>
-
-<histogram name="Storage.Blob.FileReaderLoader.ReadError" enum="NetErrorCodes"
-    expires_after="M95">
-  <owner>mek@chromium.org</owner>
-  <owner>dmurph@chromium.org</owner>
-  <summary>
-    The error code reported by the blob system while trying to read a blob in
-    the FileReaderLoader.
-  </summary>
-</histogram>
-
 <histogram name="Storage.FileSystemAccess.PersistedPermissions.Age.{Type}"
     units="ms" expires_after="2023-01-01">
   <owner>asully@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/uma/histograms.xml b/tools/metrics/histograms/metadata/uma/histograms.xml
index 0dddb2be..5a6d198 100644
--- a/tools/metrics/histograms/metadata/uma/histograms.xml
+++ b/tools/metrics/histograms/metadata/uma/histograms.xml
@@ -103,14 +103,17 @@
 </histogram>
 
 <histogram name="UMA.CleanExitBeacon.BeaconFileConsistency"
-    enum="UmaCleanExitConsistency2" expires_after="2022-10-04">
+    enum="UmaCleanExitConsistency2" expires_after="2023-05-31">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
-    Emitted by clients in the |kEnabledGroup| of the Extended Variations Safe
-    Mode experiment when the CleanExitBeacon is initialized. Reports the
-    combined state of distinct beacons stored the beacon file and in Local
-    State.
+    The combined state of distinct beacons stored in the beacon file and in
+    Local State. Emitted once during startup when the CleanExitBeacon is
+    initialized.
+
+    As of M102 for desktop and iOS and M103 for Android Chrome, any client may
+    emit this metric. Prior to this, the metric was emitted by only clients in
+    an enabled group that used the beacon file.
   </summary>
 </histogram>
 
@@ -148,7 +151,7 @@
 </histogram>
 
 <histogram name="UMA.CleanExitBeaconConsistency2"
-    enum="UmaCleanExitConsistency2" expires_after="2022-10-04">
+    enum="UmaCleanExitConsistency2" expires_after="2023-05-31">
   <owner>asvitkine@chromium.org</owner>
   <owner>justincohen@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
@@ -166,19 +169,22 @@
 </histogram>
 
 <histogram name="UMA.CleanExitBeaconConsistency3"
-    enum="UmaCleanExitConsistency3" expires_after="2022-10-16">
+    enum="UmaCleanExitConsistency3" expires_after="2023-05-31">
   <owner>caitlinfischer@google.com</owner>
   <owner>justincohen@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
-    Recorded when the CleanExitBeacon is initialized for clients in the Extended
-    Variations Safe Mode enabled group on Windows and iOS. Reports the combined
-    state of distinct beacons stored in the beacon file and in a
+    The combined state of distinct beacons stored in the beacon file and in a
     platform-specific location (e.g. the Windows registry or NSUserDefaults on
-    iOS). They are normally expected to be identical.
+    iOS). They are normally expected to be identical. Recorded when the
+    CleanExitBeacon is initialized on Windows and iOS.
 
     Unlike UMA.CleanExitBeaconConsistency2, this histogram excludes the Local
     State beacon.
+
+    As of M102 for desktop and iOS and M103 for Android Chrome, any client may
+    emit this metric. Prior to this, the metric was emitted by only clients in
+    an enabled group that used the beacon file.
   </summary>
 </histogram>
 
@@ -629,7 +635,9 @@
 </histogram>
 
 <histogram name="UMA.ProfileSignInStatusV2" enum="ProfileSignInStatus"
-    expires_after="2023-05-04">
+    expires_after="never">
+<!-- expires-never: powers UMA dashboard filter -->
+
   <owner>mpearson@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -663,7 +671,9 @@
 </histogram>
 
 <histogram name="UMA.ProfileSyncStatusV2" enum="ProfileSyncStatus"
-    expires_after="2023-03-04">
+    expires_after="never">
+<!-- expires-never: powers UMA dashboard filter -->
+
   <owner>mpearson@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -678,7 +688,7 @@
     reflected in this histogram.
 
     Sync status indicates the profile has consented to sync and has a valid
-    credentials for the account (i.e., is signed-in), meaning sync in principle
+    credential for the account (i.e., is signed-in), meaning sync in principle
     should be working. For example, if the user signs out of the web, their
     credentials will be put into an error state; they will not be valid. The
     profile will not be considered to be syncing. It is possible that the user
diff --git a/tools/metrics/histograms/metadata/variations/histograms.xml b/tools/metrics/histograms/metadata/variations/histograms.xml
index 60f795b..7fa7d01c 100644
--- a/tools/metrics/histograms/metadata/variations/histograms.xml
+++ b/tools/metrics/histograms/metadata/variations/histograms.xml
@@ -23,7 +23,7 @@
 <histograms>
 
 <histogram name="Variations.AppliedSeed.Size" units="bytes"
-    expires_after="2022-11-20">
+    expires_after="2023-05-31">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -35,7 +35,7 @@
 </histogram>
 
 <histogram name="Variations.AppliedSeed.StudyCount" units="studies"
-    expires_after="2022-11-20">
+    expires_after="2023-05-31">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -63,7 +63,7 @@
 </histogram>
 
 <histogram name="Variations.ExtendedSafeMode.BeaconFileDeserializationError"
-    enum="JsonDeserializationError" expires_after="2022-10-09">
+    enum="JsonDeserializationError" expires_after="2023-05-31">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <component>Internals&gt;Metrics&gt;Variations</component>
@@ -72,34 +72,43 @@
     during CleanExitBeacon initialization when the beacon file cannot be
     deserialized. In other words, it is emitted whenever the &quot;Not
     deserializable&quot; bucket of the BeaconFileStateAtStartup histogram is
-    emitted. Note that this file is used by only one branch of the Extended
-    Variations Safe Mode experiment.
+    emitted.
+
+    As of M102 for desktop and iOS and M103 for Android Chrome, any client may
+    emit this metric. Prior to this, the metric was emitted by only clients in
+    an enabled group that used the beacon file.
   </summary>
 </histogram>
 
 <histogram name="Variations.ExtendedSafeMode.BeaconFileStateAtStartup"
-    enum="BeaconFileState" expires_after="2022-10-09">
+    enum="BeaconFileState" expires_after="2023-05-31">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <component>Internals&gt;Metrics&gt;Variations</component>
   <summary>
     The state of the beacon file and its contents, e.g. readable or not
     deserializable. See the BeaconFileDeserializationError histogram for more
-    details on why the file was not deserializable. Note that this file is used
-    by only one branch of the Extended Variations Safe Mode experiment. Recorded
-    when the CleanExitBeacon is initialized.
+    details on why the file was not deserializable. Emitted when the
+    CleanExitBeacon is initialized.
+
+    As of M102 for desktop and iOS and M103 for Android Chrome, any client may
+    emit this metric. Prior to this, the metric was emitted by only clients in
+    an enabled group that used the beacon file.
   </summary>
 </histogram>
 
 <histogram name="Variations.ExtendedSafeMode.BeaconFileWrite"
-    enum="BooleanSuccess" expires_after="2022-10-09">
+    enum="BooleanSuccess" expires_after="2023-05-31">
   <owner>caitlinfischer@google.com</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <component>Internals&gt;Metrics&gt;Variations</component>
   <summary>
-    Denotes whether the beacon file was successfully written. Note that this
-    file is used by only one branch of the Extended Variations Safe Mode
-    experiment. Recorded immediately after Chrome tries to write the file.
+    Denotes whether the beacon file was successfully written. Recorded
+    immediately after Chrome tries to write the file.
+
+    As of M102 for desktop and iOS and M103 for Android Chrome, any client may
+    emit this metric. Prior to this, the metric was emitted by only clients in
+    an enabled group that used the beacon file.
   </summary>
 </histogram>
 
@@ -353,7 +362,7 @@
 </histogram>
 
 <histogram name="Variations.SafeMode.Streak.Crashes" units="crashes"
-    expires_after="2022-11-13">
+    expires_after="2023-05-31">
   <owner>isherman@chromium.org</owner>
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -367,7 +376,7 @@
 </histogram>
 
 <histogram name="Variations.SafeMode.Streak.FetchFailures" units="failures"
-    expires_after="2022-11-13">
+    expires_after="2023-05-31">
   <owner>isherman@chromium.org</owner>
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
@@ -511,7 +520,7 @@
 </histogram>
 
 <histogram name="Variations.SeedProcessingTime" units="ms"
-    expires_after="2022-11-20">
+    expires_after="2023-05-31">
   <owner>isherman@chromium.org</owner>
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
diff --git a/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm b/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm
index 4cd9a05..2a5a5b0 100644
--- a/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm
+++ b/ui/accessibility/platform/inspect/ax_inspect_utils_mac.mm
@@ -82,6 +82,7 @@
        NSAccessibilityRequiredAttribute,
        NSAccessibilityRoleDescriptionAttribute,
        NSAccessibilitySelectedAttribute,
+       NSAccessibilitySizeAttribute,
        NSAccessibilityTitleAttribute,
        NSAccessibilityTitleUIElementAttribute,
        NSAccessibilityURLAttribute,
diff --git a/ui/base/ime/linux/fake_input_method_context.cc b/ui/base/ime/linux/fake_input_method_context.cc
index 1c8ed77..79c95d4 100644
--- a/ui/base/ime/linux/fake_input_method_context.cc
+++ b/ui/base/ime/linux/fake_input_method_context.cc
@@ -22,11 +22,9 @@
 void FakeInputMethodContext::Reset() {
 }
 
-void FakeInputMethodContext::Focus() {
-}
-
-void FakeInputMethodContext::Blur() {
-}
+void FakeInputMethodContext::UpdateFocus(bool has_client,
+                                         TextInputType old_type,
+                                         TextInputType new_type) {}
 
 void FakeInputMethodContext::SetCursorLocation(const gfx::Rect& rect) {
 }
diff --git a/ui/base/ime/linux/fake_input_method_context.h b/ui/base/ime/linux/fake_input_method_context.h
index c173682..7e5746e 100644
--- a/ui/base/ime/linux/fake_input_method_context.h
+++ b/ui/base/ime/linux/fake_input_method_context.h
@@ -23,8 +23,9 @@
   bool DispatchKeyEvent(const ui::KeyEvent& key_event) override;
   bool IsPeekKeyEvent(const ui::KeyEvent& key_event) override;
   void Reset() override;
-  void Focus() override;
-  void Blur() override;
+  void UpdateFocus(bool has_client,
+                   TextInputType old_type,
+                   TextInputType new_type) override;
   void SetCursorLocation(const gfx::Rect& rect) override;
   void SetSurroundingText(const std::u16string& text,
                           const gfx::Range& selection_range) override;
diff --git a/ui/base/ime/linux/input_method_auralinux.cc b/ui/base/ime/linux/input_method_auralinux.cc
index dc624ee..7293030a 100644
--- a/ui/base/ime/linux/input_method_auralinux.cc
+++ b/ui/base/ime/linux/input_method_auralinux.cc
@@ -344,25 +344,14 @@
 }
 
 void InputMethodAuraLinux::UpdateContextFocusState() {
-  bool old_text_input_type = text_input_type_;
+  auto old_text_input_type = text_input_type_;
   text_input_type_ = GetTextInputType();
 
-  // We only focus in |context_| when the focus is in a textfield.
-  if (old_text_input_type != TEXT_INPUT_TYPE_NONE) {
-    context_->Blur();
-  }
-  if (text_input_type_ != TEXT_INPUT_TYPE_NONE) {
-    context_->Focus();
-  }
-
-  // |context_simple_| can be used in any textfield, including password box, and
-  // even if the focused text input client's text input type is
-  // ui::TEXT_INPUT_TYPE_NONE.
   auto* client = GetTextInputClient();
-  if (client)
-    context_simple_->Focus();
-  else
-    context_simple_->Blur();
+  bool has_client = client != nullptr;
+  context_->UpdateFocus(has_client, old_text_input_type, text_input_type_);
+  context_simple_->UpdateFocus(has_client, old_text_input_type,
+                               text_input_type_);
 
   LinuxInputMethodContext* context =
       text_input_type_ != TEXT_INPUT_TYPE_NONE &&
diff --git a/ui/base/ime/linux/input_method_auralinux_unittest.cc b/ui/base/ime/linux/input_method_auralinux_unittest.cc
index e9f3759..5e80ec17 100644
--- a/ui/base/ime/linux/input_method_auralinux_unittest.cc
+++ b/ui/base/ime/linux/input_method_auralinux_unittest.cc
@@ -60,8 +60,10 @@
 class LinuxInputMethodContextForTesting : public LinuxInputMethodContext {
  public:
   explicit LinuxInputMethodContextForTesting(
-      LinuxInputMethodContextDelegate* delegate)
+      LinuxInputMethodContextDelegate* delegate,
+      bool is_simple)
       : delegate_(delegate),
+        is_simple_(is_simple),
         is_sync_mode_(false),
         eat_key_(false),
         focused_(false) {}
@@ -142,9 +144,15 @@
 
   void Reset() override {}
 
-  void Focus() override { focused_ = true; }
-
-  void Blur() override { focused_ = false; }
+  void UpdateFocus(bool has_client,
+                   TextInputType old_type,
+                   TextInputType new_type) override {
+    if (is_simple_) {
+      focused_ = has_client;
+    } else {
+      focused_ = new_type != TEXT_INPUT_TYPE_NONE;
+    }
+  }
 
   void SetCursorLocation(const gfx::Rect& rect) override {
     cursor_position_ = rect;
@@ -175,6 +183,7 @@
  private:
   LinuxInputMethodContextDelegate* delegate_;
   VirtualKeyboardControllerStub virtual_keyboard_controller_;
+  const bool is_simple_;
   std::vector<std::u16string> actions_;
   bool is_sync_mode_;
   bool eat_key_;
@@ -199,8 +208,8 @@
   std::unique_ptr<LinuxInputMethodContext> CreateInputMethodContext(
       LinuxInputMethodContextDelegate* delegate,
       bool is_simple) const override {
-    return std::unique_ptr<ui::LinuxInputMethodContext>(
-        new LinuxInputMethodContextForTesting(delegate));
+    return std::make_unique<LinuxInputMethodContextForTesting>(delegate,
+                                                               is_simple);
   }
 };
 
diff --git a/ui/base/ime/linux/linux_input_method_context.h b/ui/base/ime/linux/linux_input_method_context.h
index 3073d32..b34965c 100644
--- a/ui/base/ime/linux/linux_input_method_context.h
+++ b/ui/base/ime/linux/linux_input_method_context.h
@@ -58,11 +58,10 @@
   // before calling DispatchKeyEvent().
   virtual void Reset() = 0;
 
-  // Focuses the context.
-  virtual void Focus() = 0;
-
-  // Blurs the context.
-  virtual void Blur() = 0;
+  // Called when text input focus is changed.
+  virtual void UpdateFocus(bool has_client,
+                           TextInputType old_type,
+                           TextInputType new_type) = 0;
 
   // Returns the corresponding VirtualKeyboardController instance.
   // Or nullptr, if not supported.
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index 7ffd42f..35a4838 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -377,7 +377,13 @@
 }
 
 const base::Feature kWaylandScreenCoordinatesEnabled{
-    "WaylandScreenCoordinatesEnabled", base::FEATURE_DISABLED_BY_DEFAULT};
+  "WaylandScreenCoordinatesEnabled",
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+      base::FEATURE_ENABLED_BY_DEFAULT
+#else
+      base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
 
 bool IsWaylandScreenCoordinatesEnabled() {
   return base::FeatureList::IsEnabled(kWaylandScreenCoordinatesEnabled);
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index fe1c1fd..4b319db 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -1297,8 +1297,8 @@
   <message name="IDS_FILE_BROWSER_HTML_DOCUMENT_FILE_TYPE" desc="HTML document file type">
     HTML document
   </message>
-  <message name="IDS_FILE_BROWSER_ZIP_ARCHIVE_FILE_TYPE" desc="Zip archive file type">
-    Zip archive
+  <message name="IDS_FILE_BROWSER_ZIP_ARCHIVE_FILE_TYPE" desc="ZIP archive file type">
+    ZIP archive
   </message>
   <message name="IDS_FILE_BROWSER_RAR_ARCHIVE_FILE_TYPE" desc="RAR archive file type">
     RAR archive
@@ -1306,48 +1306,36 @@
   <message name="IDS_FILE_BROWSER_ISO_ARCHIVE_FILE_TYPE" desc="ISO archive file type">
     ISO image
   </message>
-  <message name="IDS_FILE_BROWSER_7Z_ARCHIVE_FILE_TYPE" desc="7z archive file type">
-    7z archive
+  <message name="IDS_FILE_BROWSER_7Z_ARCHIVE_FILE_TYPE" desc="7-Zip archive file type">
+    7-Zip archive
   </message>
   <message name="IDS_FILE_BROWSER_CRX_ARCHIVE_FILE_TYPE" desc="CRX archive file type">
     Chrome extension
   </message>
-  <message name="IDS_FILE_BROWSER_TAR_ARCHIVE_FILE_TYPE" desc="Tar archive file type">
-    Tar archive
+  <message name="IDS_FILE_BROWSER_TAR_ARCHIVE_FILE_TYPE" desc="TAR archive file type">
+    TAR archive
   </message>
-  <message name="IDS_FILE_BROWSER_TAR_BZIP2_ARCHIVE_FILE_TYPE" desc="Bzip2 compressed tar archive file type">
-    Bzip2 compressed tar archive
+  <message name="IDS_FILE_BROWSER_BZIP2_ARCHIVE_FILE_TYPE" desc="BZIP2 compressed archive file type">
+    BZIP2 compressed archive
   </message>
-  <message name="IDS_FILE_BROWSER_BZIP2_ARCHIVE_FILE_TYPE" desc="Bzip2 compressed archive file type">
-    Bzip2 compressed archive
-  </message>
-  <message name="IDS_FILE_BROWSER_TAR_GZIP_ARCHIVE_FILE_TYPE" desc="Gzip compressed tar archive file type">
-    Gzip compressed tar archive
-  </message>
-  <message name="IDS_FILE_BROWSER_GZIP_ARCHIVE_FILE_TYPE" desc="Gzip compressed archive file type">
-    Gzip compressed archive
-  </message>
-  <message name="IDS_FILE_BROWSER_TAR_LZMA_ARCHIVE_FILE_TYPE" desc="LZMA compressed tar archive file type">
-    LZMA compressed tar archive
+  <message name="IDS_FILE_BROWSER_GZIP_ARCHIVE_FILE_TYPE" desc="GZIP compressed archive file type">
+    GZIP compressed archive
   </message>
   <message name="IDS_FILE_BROWSER_LZMA_ARCHIVE_FILE_TYPE" desc="LZMA compressed archive file type">
     LZMA compressed archive
   </message>
-  <message name="IDS_FILE_BROWSER_TAR_XZ_ARCHIVE_FILE_TYPE" desc="XZ compressed tar archive file type">
-    XZ compressed tar archive
+  <message name="IDS_FILE_BROWSER_LZIP_ARCHIVE_FILE_TYPE" desc="LZIP compressed archive file type">
+    LZIP compressed archive
+  </message>
+  <message name="IDS_FILE_BROWSER_LZOP_ARCHIVE_FILE_TYPE" desc="LZOP compressed archive file type">
+    LZOP compressed archive
   </message>
   <message name="IDS_FILE_BROWSER_XZ_ARCHIVE_FILE_TYPE" desc="XZ compressed archive file type">
     XZ compressed archive
   </message>
-  <message name="IDS_FILE_BROWSER_TAR_Z_ARCHIVE_FILE_TYPE" desc="Z compressed tar archive file type">
-    Z compressed tar archive
-  </message>
   <message name="IDS_FILE_BROWSER_Z_ARCHIVE_FILE_TYPE" desc="Z compressed archive file type">
     Z compressed archive
   </message>
-  <message name="IDS_FILE_BROWSER_TAR_ZSTD_ARCHIVE_FILE_TYPE" desc="ZSTD compressed tar archive file type">
-    Zstandard compressed tar archive
-  </message>
   <message name="IDS_FILE_BROWSER_ZSTD_ARCHIVE_FILE_TYPE" desc="ZSTD compressed archive file type">
     Zstandard compressed archive
   </message>
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_7Z_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_7Z_ARCHIVE_FILE_TYPE.png.sha1
index 9c6a2e3..41ceb09a 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_7Z_ARCHIVE_FILE_TYPE.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_7Z_ARCHIVE_FILE_TYPE.png.sha1
@@ -1 +1 @@
-4000906aa4c53562a0add25c4057cad140eaa2e1
\ No newline at end of file
+0ff9af612be21043a0ebd7539c930d2e627e4a9d
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BZIP2_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BZIP2_ARCHIVE_FILE_TYPE.png.sha1
index 7cd20d3..9398fac 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BZIP2_ARCHIVE_FILE_TYPE.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_BZIP2_ARCHIVE_FILE_TYPE.png.sha1
@@ -1 +1 @@
-5477db81c9b9ccf17589b1318482a09eec39eaf7
\ No newline at end of file
+423b1856516f930142a5e545ea250854fb192c26
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_GZIP_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_GZIP_ARCHIVE_FILE_TYPE.png.sha1
index 2d15558..07b0fd5 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_GZIP_ARCHIVE_FILE_TYPE.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_GZIP_ARCHIVE_FILE_TYPE.png.sha1
@@ -1 +1 @@
-f2b234995381c20f81a00b43372cca156a8ce6b7
\ No newline at end of file
+c18a09d2a1490574dac0cf258c0f9961b215363c
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_LZIP_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_LZIP_ARCHIVE_FILE_TYPE.png.sha1
new file mode 100644
index 0000000..e037cba
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_LZIP_ARCHIVE_FILE_TYPE.png.sha1
@@ -0,0 +1 @@
+c5392520ba52bca8fb920a368bd87ae49ad8848f
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_LZOP_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_LZOP_ARCHIVE_FILE_TYPE.png.sha1
new file mode 100644
index 0000000..1e4eb49
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_LZOP_ARCHIVE_FILE_TYPE.png.sha1
@@ -0,0 +1 @@
+272f690b6ceb19ff8964445f59d19f3299bd9710
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_ARCHIVE_FILE_TYPE.png.sha1
new file mode 100644
index 0000000..0d61ba8
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_ARCHIVE_FILE_TYPE.png.sha1
@@ -0,0 +1 @@
+132b007757b1e7f2829c10e223decae2133daf62
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_LZMA_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_LZMA_ARCHIVE_FILE_TYPE.png.sha1
deleted file mode 100644
index bbe1c7d..0000000
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_LZMA_ARCHIVE_FILE_TYPE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-6df019adecf41507b2ce35c358702000ec1f587e
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_XZ_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_XZ_ARCHIVE_FILE_TYPE.png.sha1
deleted file mode 100644
index 7b3e5d84..0000000
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_XZ_ARCHIVE_FILE_TYPE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e5f09f107b7ebfcdbb707a840bb2691a13e2fd4f
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_ZSTD_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_ZSTD_ARCHIVE_FILE_TYPE.png.sha1
deleted file mode 100644
index c6c2106..0000000
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_ZSTD_ARCHIVE_FILE_TYPE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-5255d4e5b26204ec29da3486a1debc786dc17283
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_Z_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_Z_ARCHIVE_FILE_TYPE.png.sha1
deleted file mode 100644
index c6c2106..0000000
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_TAR_Z_ARCHIVE_FILE_TYPE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-5255d4e5b26204ec29da3486a1debc786dc17283
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_ZIP_ARCHIVE_FILE_TYPE.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_ZIP_ARCHIVE_FILE_TYPE.png.sha1
new file mode 100644
index 0000000..c43c7c38
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_ZIP_ARCHIVE_FILE_TYPE.png.sha1
@@ -0,0 +1 @@
+bc0b37618a1cfb748b1d0409a6d698f2c5c97429
\ No newline at end of file
diff --git a/ui/events/ozone/device/device_event.cc b/ui/events/ozone/device/device_event.cc
index e20079a7..7303803a 100644
--- a/ui/events/ozone/device/device_event.cc
+++ b/ui/events/ozone/device/device_event.cc
@@ -8,9 +8,13 @@
 
 DeviceEvent::DeviceEvent(DeviceType type,
                          ActionType action,
-                         const base::FilePath& path)
+                         const base::FilePath& path,
+                         const PropertyMap& property_map)
     : device_type_(type),
       action_type_(action),
-      path_(path) {}
+      path_(path),
+      properties_(property_map) {}
+
+DeviceEvent::~DeviceEvent() = default;
 
 }  // namespace ui
diff --git a/ui/events/ozone/device/device_event.h b/ui/events/ozone/device/device_event.h
index c2d6618..14f45f8 100644
--- a/ui/events/ozone/device/device_event.h
+++ b/ui/events/ozone/device/device_event.h
@@ -6,9 +6,15 @@
 #define UI_EVENTS_OZONE_DEVICE_DEVICE_EVENT_H_
 
 #include "base/component_export.h"
+#include "base/containers/flat_map.h"
 #include "base/files/file_path.h"
 
 namespace ui {
+namespace {
+
+using PropertyMap = base::flat_map<std::string, std::string>;
+
+}  // namespace
 
 class COMPONENT_EXPORT(EVENTS_OZONE) DeviceEvent {
  public:
@@ -23,19 +29,25 @@
     CHANGE,
   };
 
-  DeviceEvent(DeviceType type, ActionType action, const base::FilePath& path);
+  DeviceEvent(DeviceType type,
+              ActionType action,
+              const base::FilePath& path,
+              const PropertyMap& property_map = PropertyMap());
 
   DeviceEvent(const DeviceEvent&) = delete;
   DeviceEvent& operator=(const DeviceEvent&) = delete;
+  ~DeviceEvent();
 
   DeviceType device_type() const { return device_type_; }
   ActionType action_type() const { return action_type_; }
   base::FilePath path() const { return path_; }
+  const PropertyMap properties() const { return properties_; }
 
  private:
   DeviceType device_type_;
   ActionType action_type_;
   base::FilePath path_;
+  const PropertyMap properties_;
 };
 
 }  // namespace ui
diff --git a/ui/events/ozone/device/udev/device_manager_udev.cc b/ui/events/ozone/device/udev/device_manager_udev.cc
index e3e2132..8deeea2 100644
--- a/ui/events/ozone/device/udev/device_manager_udev.cc
+++ b/ui/events/ozone/device/udev/device_manager_udev.cc
@@ -5,12 +5,15 @@
 #include "ui/events/ozone/device/udev/device_manager_udev.h"
 
 #include <stddef.h>
+#include <string>
 
 #include "base/logging.h"
 #include "base/observer_list.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/current_thread.h"
 #include "base/trace_event/trace_event.h"
+#include "device/udev_linux/udev.h"
+#include "device/udev_linux/udev_loader.h"
 #include "ui/events/ozone/device/device_event.h"
 #include "ui/events/ozone/device/device_event_observer.h"
 
@@ -159,10 +162,8 @@
 std::unique_ptr<DeviceEvent> DeviceManagerUdev::ProcessMessage(
     udev_device* device) {
   const char* path = device::udev_device_get_devnode(device);
-  const char* action = device::udev_device_get_action(device);
   const char* subsystem =
       device::udev_device_get_property_value(device, "SUBSYSTEM");
-
   if (!path || !subsystem)
     return nullptr;
 
@@ -177,6 +178,7 @@
   else
     return nullptr;
 
+  const char* action = device::udev_device_get_action(device);
   DeviceEvent::ActionType action_type;
   if (!action || !strcmp(action, "add"))
     action_type = DeviceEvent::ADD;
@@ -187,8 +189,19 @@
   else
     return nullptr;
 
+  PropertyMap property_map;
+  udev_list_entry* property_list =
+      device::udev_device_get_properties_list_entry(device);
+  udev_list_entry* entry;
+  udev_list_entry_foreach(entry, property_list) {
+    const std::string key(device::udev_list_entry_get_name(entry));
+    const std::string value(
+        device::udev_device_get_property_value(device, key.c_str()));
+    property_map.insert({key, value});
+  }
+
   return std::make_unique<DeviceEvent>(device_type, action_type,
-                                       base::FilePath(path));
+                                       base::FilePath(path), property_map);
 }
 
 }  // namespace ui
diff --git a/ui/file_manager/base/gn/file_types.json5 b/ui/file_manager/base/gn/file_types.json5
index dd85d9a36..d832dbaa 100644
--- a/ui/file_manager/base/gn/file_types.json5
+++ b/ui/file_manager/base/gn/file_types.json5
@@ -324,7 +324,7 @@
   {
     "type": "archive",
     "translationKey": "7Z_ARCHIVE_FILE_TYPE",
-    "subtype": "7Z",
+    "subtype": "7ZIP",
     "extensions": [".7z"],
     "mime": "application/x-7z-compressed"
   },
@@ -344,86 +344,58 @@
   },
   {
     "type": "archive",
-    "translationKey": "TAR_BZIP2_ARCHIVE_FILE_TYPE",
-    "subtype": "TBZ2",
-    "extensions": [".tar.bz2", ".tar.bz", ".tbz", ".tbz2", ".tz2", ".tb2"],
-    "mime": "application/x-bzip2"
-  },
-  {
-    "type": "archive",
     "translationKey": "BZIP2_ARCHIVE_FILE_TYPE",
-    "subtype": "BZ2",
-    "extensions": [".bz2", ".bz"],
+    "subtype": "BZIP2",
+    "extensions": [".bz2", ".bz", ".tbz", ".tbz2", ".tz2", ".tb2"],
     "mime": "application/x-bzip2"
   },
   {
     "type": "archive",
-    "translationKey": "TAR_GZIP_ARCHIVE_FILE_TYPE",
-    "subtype": "TGZ",
-    "extensions": [".tar.gz", ".tgz"],
-    "mime": "application/x-gzip"
-  },
-  {
-    "type": "archive",
     "translationKey": "GZIP_ARCHIVE_FILE_TYPE",
-    "subtype": "GZ",
-    "extensions": [".gz"],
+    "subtype": "GZIP",
+    "extensions": [".gz", ".tgz"],
     "mime": "application/x-gzip"
   },
   {
     "type": "archive",
-    "translationKey": "TAR_LZMA_ARCHIVE_FILE_TYPE",
-    "subtype": "TLZMA",
-    "extensions": [".tar.lzma", ".tlzma", ".tlz"],
-    "mime": "application/x-lzma"
+    "translationKey": "LZIP_ARCHIVE_FILE_TYPE",
+    "subtype": "LZIP",
+    "extensions": [".lz"],
+    "mime": "application/x-lzip"
+  },
+  {
+    "type": "archive",
+    "translationKey": "LZOP_ARCHIVE_FILE_TYPE",
+    "subtype": "LZOP",
+    "extensions": [".lzo"],
+    "mime": "application/x-lzop"
   },
   {
     "type": "archive",
     "translationKey": "LZMA_ARCHIVE_FILE_TYPE",
     "subtype": "LZMA",
-    "extensions": [".lzma"],
+    "extensions": [".lzma", ".tlzma", ".tlz"],
     "mime": "application/x-lzma"
   },
   {
     "type": "archive",
-    "translationKey": "TAR_XZ_ARCHIVE_FILE_TYPE",
-    "subtype": "TXZ",
-    "extensions": [".tar.xz", ".txz"],
-    "mime": "application/x-xz"
-  },
-  {
-    "type": "archive",
     "translationKey": "XZ_ARCHIVE_FILE_TYPE",
     "subtype": "XZ",
-    "extensions": [".xz"],
+    "extensions": [".xz", ".txz"],
     "mime": "application/x-xz"
   },
   {
     "type": "archive",
-    "translationKey": "TAR_Z_ARCHIVE_FILE_TYPE",
-    "subtype": "TZ",
-    "extensions": [".tar.z", ".taz", ".tz"],
-    "mime": "application/x-compress"
-  },
-  {
-    "type": "archive",
     "translationKey": "Z_ARCHIVE_FILE_TYPE",
     "subtype": "Z",
-    "extensions": [".z"],
+    "extensions": [".z", ".taz", ".tz"],
     "mime": "application/x-compress"
   },
   {
     "type": "archive",
-    "translationKey": "TAR_ZSTD_ARCHIVE_FILE_TYPE",
-    "subtype": "TZST",
-    "extensions": [".tar.zst", ".tzst"],
-    "mime": "application/zstd"
-  },
-  {
-    "type": "archive",
     "translationKey": "ZSTD_ARCHIVE_FILE_TYPE",
-    "subtype": "ZST",
-    "extensions": [".zst"],
+    "subtype": "ZSTD",
+    "extensions": [".tar.zst", ".tzst", ".zst"],
     "mime": "application/zstd"
   },
 
diff --git a/ui/file_manager/file_manager/background/js/file_operation_handler.js b/ui/file_manager/file_manager/background/js/file_operation_handler.js
index 2de319c..aef3718 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_handler.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_handler.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {assert} from 'chrome://resources/js/assert.m.js';
+
 import {FileOperationProgressEvent} from '../../common/js/file_operation_common.js';
 import {ProgressCenterItem, ProgressItemState, ProgressItemType} from '../../common/js/progress_center_common.js';
 import {str, strf, util} from '../../common/js/util.js';
@@ -108,6 +110,16 @@
         } else {
           item.state = ProgressItemState.ERROR;
         }
+        // Extract IOTask details are only stored while an operation is active.
+        if (item.type == ProgressItemType.EXTRACT) {
+          this.fileOperationManager_.notifyExtractDone(event.taskId);
+        }
+        break;
+      case chrome.fileManagerPrivate.IOTaskState.NEED_PASSWORD:
+        // Set state to canceled so notification doesn't display.
+        item.state = ProgressItemState.CANCELED;
+        assert(item.type == ProgressItemType.EXTRACT);
+        this.fileOperationManager_.handleMissingPassword(event.taskId);
         break;
       default:
         console.error(`Invalid IOTaskState: ${event.state}`);
diff --git a/ui/file_manager/file_manager/background/js/file_operation_manager.js b/ui/file_manager/file_manager/background/js/file_operation_manager.js
index 7d2cf6d..2912563 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_manager.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_manager.js
@@ -28,6 +28,12 @@
 export class FileOperationManagerImpl {
   constructor() {
     /**
+     * TODO(crbug.com/953256) Add closure annotation.
+     * @private
+     */
+    this.fileManager_ = null;
+
+    /**
      * @private {VolumeManager}
      */
     this.volumeManager_ = null;
@@ -70,6 +76,16 @@
   }
 
   /**
+   * Store a reference to our owning File Manager.
+   * @param {Object} fileManager reference to the 'foreground' app.
+   */
+  setFileManager(fileManager) {
+    if (window.isSWA) {
+      this.fileManager_ = fileManager;
+    }
+  }
+
+  /**
    * Adds an event listener for the tasks.
    * @param {string} type The name of the event.
    * @param {EventListener|function(!Event):*} handler The handler for the
@@ -670,6 +686,31 @@
   }
 
   /**
+   * Notifies File Manager that an extraction operation has finished.
+   *
+   * @param {number} taskId The unique task id for the IO operation.
+   * @suppress {missingProperties}
+   */
+  notifyExtractDone(taskId) {
+    if (window.isSWA) {
+      // TODO(crbug.com/953256) Add closure annotation.
+      this.fileManager_.taskController.deleteExtractTaskDetails(taskId);
+    }
+  }
+
+  /**
+   * Called when an IOTask finished with a NEED_PASSWORD status.
+   * Delegate it to the task controller to deal with it.
+   *
+   * @param {number} taskId The unique task id for the IO operation.
+   * @suppress {missingProperties}
+   */
+  handleMissingPassword(taskId) {
+    // TODO(crbug.com/953256) Add closure annotation.
+    this.fileManager_.taskController.handleMissingPassword(taskId);
+  }
+
+  /**
    * Writes file to destination dir. This function is called when an image is
    * dragged from a web page. In this case there is no FileSystem Entry to copy
    * or move, just the JS File object with attached Blob. This operation does
diff --git a/ui/file_manager/file_manager/background/js/mock_file_operation_manager.js b/ui/file_manager/file_manager/background/js/mock_file_operation_manager.js
index 8a292ff2..bacbeae 100644
--- a/ui/file_manager/file_manager/background/js/mock_file_operation_manager.js
+++ b/ui/file_manager/file_manager/background/js/mock_file_operation_manager.js
@@ -109,6 +109,9 @@
   emptyTrash() {}
   zipSelection() {}
   cancelZip() {}
+  setFileManager() {}
+  notifyExtractDone() {}
+  handleMissingPassword() {}
   /** @return {!Promise<!FileEntry>} */
   async writeFile(file, destination) {
     throw new Error('Not implemented');
diff --git a/ui/file_manager/file_manager/common/js/file_type_unittest.m.js b/ui/file_manager/file_manager/common/js/file_type_unittest.m.js
index 1690c84..06ebebaf 100644
--- a/ui/file_manager/file_manager/common/js/file_type_unittest.m.js
+++ b/ui/file_manager/file_manager/common/js/file_type_unittest.m.js
@@ -61,13 +61,42 @@
     {name: '/amr/foo.oga', want: {type: 'audio', subtype: 'OGG'}},
     {name: '/wav/dir/foo.ogg', want: {type: 'audio', subtype: 'OGG'}},
     {name: '/mp3/amr/foo.opus', want: {type: 'audio', subtype: 'OGG'}},
-    // Distinguish double dot extension from single dot extension.
-    {name: '/dir/foo.tar.gz', want: {type: 'archive', subtype: 'TGZ'}},
-    {name: '/dir/foo.gz', want: {type: 'archive', subtype: 'GZ'}},
+    // Archive types.
+    {name: '/dir/foo.7z', want: {type: 'archive', subtype: '7ZIP'}},
+    {name: '/dir/foo.crx', want: {type: 'archive', subtype: 'CRX'}},
+    {name: '/dir/foo.iso', want: {type: 'archive', subtype: 'ISO'}},
+    {name: '/dir/foo.rar', want: {type: 'archive', subtype: 'RAR'}},
+    {name: '/dir/foo.tar', want: {type: 'archive', subtype: 'TAR'}},
+    {name: '/dir/foo.zip', want: {type: 'archive', subtype: 'ZIP'}},
+    {name: '/dir/foo.gz', want: {type: 'archive', subtype: 'GZIP'}},
+    {name: '/dir/foo.tar.gz', want: {type: 'archive', subtype: 'GZIP'}},
+    {name: '/dir/foo.tgz', want: {type: 'archive', subtype: 'GZIP'}},
+    {name: '/dir/foo.lz', want: {type: 'archive', subtype: 'LZIP'}},
+    {name: '/dir/foo.tar.lz', want: {type: 'archive', subtype: 'LZIP'}},
+    {name: '/dir/foo.lzo', want: {type: 'archive', subtype: 'LZOP'}},
+    {name: '/dir/foo.tar.lzo', want: {type: 'archive', subtype: 'LZOP'}},
     {name: '/dir/foo.lzma', want: {type: 'archive', subtype: 'LZMA'}},
-    {name: '/dir/foo.tar.lzma', want: {type: 'archive', subtype: 'TLZMA'}},
-    {name: '/dir/foo.tar1.gz', want: {type: 'archive', subtype: 'GZ'}},
-    {name: 'tar.gz', want: {type: 'archive', subtype: 'GZ'}},
+    {name: '/dir/foo.tar.lzma', want: {type: 'archive', subtype: 'LZMA'}},
+    {name: '/dir/foo.tlzma', want: {type: 'archive', subtype: 'LZMA'}},
+    {name: '/dir/foo.tlz', want: {type: 'archive', subtype: 'LZMA'}},
+    {name: '/dir/foo.bz', want: {type: 'archive', subtype: 'BZIP2'}},
+    {name: '/dir/foo.bz2', want: {type: 'archive', subtype: 'BZIP2'}},
+    {name: '/dir/foo.tar.bz', want: {type: 'archive', subtype: 'BZIP2'}},
+    {name: '/dir/foo.tar.bz2', want: {type: 'archive', subtype: 'BZIP2'}},
+    {name: '/dir/foo.tbz2', want: {type: 'archive', subtype: 'BZIP2'}},
+    {name: '/dir/foo.tbz', want: {type: 'archive', subtype: 'BZIP2'}},
+    {name: '/dir/foo.tb2', want: {type: 'archive', subtype: 'BZIP2'}},
+    {name: '/dir/foo.tz2', want: {type: 'archive', subtype: 'BZIP2'}},
+    {name: '/dir/foo.xz', want: {type: 'archive', subtype: 'XZ'}},
+    {name: '/dir/foo.txz', want: {type: 'archive', subtype: 'XZ'}},
+    {name: '/dir/foo.tar.xz', want: {type: 'archive', subtype: 'XZ'}},
+    {name: '/dir/foo.Z', want: {type: 'archive', subtype: 'Z'}},
+    {name: '/dir/foo.tar.Z', want: {type: 'archive', subtype: 'Z'}},
+    {name: '/dir/foo.taZ', want: {type: 'archive', subtype: 'Z'}},
+    {name: '/dir/foo.tZ', want: {type: 'archive', subtype: 'Z'}},
+    {name: '/dir/foo.zst', want: {type: 'archive', subtype: 'ZSTD'}},
+    {name: '/dir/foo.tar.zst', want: {type: 'archive', subtype: 'ZSTD'}},
+    {name: '/dir/foo.tzst', want: {type: 'archive', subtype: 'ZSTD'}},
     // Support upper case file name.
     {name: '/dir/foo.JPG', want: {type: 'image', subtype: 'JPEG'}},
     // Unknown files.
diff --git a/ui/file_manager/file_manager/externs/background/file_operation_manager.js b/ui/file_manager/file_manager/externs/background/file_operation_manager.js
index e9ed991..e07f602 100644
--- a/ui/file_manager/file_manager/externs/background/file_operation_manager.js
+++ b/ui/file_manager/file_manager/externs/background/file_operation_manager.js
@@ -14,6 +14,12 @@
  */
 export class FileOperationManager extends EventTarget {
   /**
+   * Store a reference to our owning File Manager.
+   * @param {Object} fileManager reference to the 'foreground' app.
+   */
+  setFileManager(fileManager) {}
+
+  /**
    * Says if there are any tasks in the queue.
    * @return {boolean} True, if there are any tasks.
    */
@@ -91,6 +97,21 @@
   zipSelection(selectionEntries, dirEntry) {}
 
   /**
+   * Notifies File Manager that an extraction operation has finished.
+   *
+   * @param {number} taskId The unique task id for the IO operation.
+   */
+  notifyExtractDone(taskId) {}
+
+  /**
+   * Called when an IOTask finished with a NEED_PASSWORD status.
+   * Delegate it to the task controller to deal with it.
+   *
+   * @param {number} taskId The unique task id for the IO operation.
+   */
+  handleMissingPassword(taskId) {}
+
+  /**
    * Writes file to destination dir.
    *
    * @param {!File} file The file entry to be written.
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 5ea72f5..91b91e2 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -1013,6 +1013,9 @@
     }
     this.fileOperationManager_ =
         this.fileBrowserBackground_.fileOperationManager;
+    if (window.isSWA) {
+      this.fileOperationManager_.setFileManager(this);
+    }
     this.mediaImportHandler_ = this.fileBrowserBackground_.mediaImportHandler;
     this.mediaScanner_ = this.fileBrowserBackground_.mediaScanner;
     this.historyLoader_ = this.fileBrowserBackground_.historyLoader;
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index 2fee3d4..d442666b 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -2103,9 +2103,20 @@
       if (fileManager.directoryModel.isReadOnly()) {
         dirEntry = fileManager.directoryModel.getMyFiles();
       }
-      startIOTask(
+      this.startExtractTask(fileManager, selectionEntries, dirEntry);
+    }
+  }
+
+  async startExtractTask(fileManager, selectionEntries, dirEntry) {
+    let taskId;
+    try {
+      taskId = await startIOTask(
           chrome.fileManagerPrivate.IOTaskType.EXTRACT, selectionEntries,
           {destinationFolder: /** @type {!DirectoryEntry} */ (dirEntry)});
+      fileManager.taskController.storeExtractTaskDetails(
+          taskId, selectionEntries, {destinationFolder: dirEntry});
+    } catch (e) {
+      console.warn('Error getting extract taskID', e);
     }
   }
 
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js
index db10fd1..f214cfb 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -6,6 +6,7 @@
 import {Command} from 'chrome://resources/js/cr/ui/command.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 
+import {startIOTask} from '../../common/js/api.js';
 import {DialogType} from '../../common/js/dialog_type.js';
 import {strf, util} from '../../common/js/util.js';
 import {Crostini} from '../../externs/background/crostini.js';
@@ -150,6 +151,12 @@
     this.tasksEntries_ = [];
 
     /**
+     * Map used to track extract IOTasks in progress.
+     * @private @const {Map}
+     */
+    this.extractTasks_ = new Map();
+
+    /**
      * Selected entries from the last time onSelectionChanged_ was called.
      * @private {!Array<!Entry>}
      */
@@ -510,4 +517,57 @@
       tasks.executeDefault();
     });
   }
+
+  /**
+   * Stores the task ID and parameters for an extract archive task.
+   */
+  storeExtractTaskDetails(taskId, selectionEntries, parameters) {
+    this.extractTasks_.set(
+        taskId, {'entries': selectionEntries, 'params': parameters});
+  }
+
+  /**
+   * Removes information about an extract archive task.
+   */
+  deleteExtractTaskDetails(taskId) {
+    this.extractTasks_.delete(taskId);
+  }
+
+  async startGetPasswordThenExtractTask(selectionEntries, params) {
+    /** @type {?string} */ let password = null;
+    // Ask for password.
+    try {
+      password = await this.ui_.passwordDialog.askForPassword(
+          selectionEntries[0].fullPath, password);
+    } catch (error) {
+      console.warn('User cancelled password fetch ', error);
+      return;
+    }
+
+    params['password'] = password;
+    let taskId;
+    try {
+      taskId = await startIOTask(
+          chrome.fileManagerPrivate.IOTaskType.EXTRACT, selectionEntries,
+          params);
+      this.storeExtractTaskDetails(taskId, selectionEntries, params);
+    } catch (e) {
+      console.warn('Error getting extract taskID', e);
+    }
+  }
+
+  /**
+   * If an extract operation has finished due to missing password,
+   * see if we have the operation stored and if so, pop up a password
+   * dialog and try to restart another IO operation for it.
+   */
+  handleMissingPassword(taskId) {
+    const existingOperation = this.extractTasks_.get(taskId);
+    if (existingOperation) {
+      this.startGetPasswordThenExtractTask(
+          existingOperation['entries'], existingOperation['params']);
+    }
+    // Remove the failed operation reference since it's finished.
+    this.deleteExtractTaskDetails(taskId);
+  }
 }
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json
index 60dadf1..73dd16c6 100644
--- a/ui/file_manager/file_manager/manifest.json
+++ b/ui/file_manager/file_manager/manifest.json
@@ -68,6 +68,7 @@
         "crx",
         "gz",
         "iso",
+        "lz",
         "lzma",
         "rar",
         "tar",
diff --git a/ui/file_manager/integration_tests/file_manager/zip_files.js b/ui/file_manager/integration_tests/file_manager/zip_files.js
index 4b8c2a5..e4079d3 100644
--- a/ui/file_manager/integration_tests/file_manager/zip_files.js
+++ b/ui/file_manager/integration_tests/file_manager/zip_files.js
@@ -175,7 +175,7 @@
 function getZipSelectionFileListRowEntries() {
   return [
     ['photos', '--', 'Folder', 'Jan 1, 1980, 11:59 PM'],
-    ['photos.zip', '134 bytes', 'Zip archive', 'Oct 21, 1983, 11:55 AM']
+    ['photos.zip', '134 bytes', 'ZIP archive', 'Oct 21, 1983, 11:55 AM']
   ];
 }
 
diff --git a/ui/file_manager/integration_tests/test_util.js b/ui/file_manager/integration_tests/test_util.js
index 37af31a2..73f5a52 100644
--- a/ui/file_manager/integration_tests/test_util.js
+++ b/ui/file_manager/integration_tests/test_util.js
@@ -1074,7 +1074,7 @@
     lastModifiedTime: 'Jan 1, 2014, 1:00 AM',
     nameText: 'archive.zip',
     sizeText: '743 bytes',
-    typeText: 'Zip archive'
+    typeText: 'ZIP archive'
   }),
 
   zipSJISArchive: new TestEntryInfo({
@@ -1085,7 +1085,7 @@
     lastModifiedTime: 'Apr 6, 2022, 1:00 AM',
     nameText: 'sjis.zip',
     sizeText: '479 bytes',
-    typeText: 'Zip archive'
+    typeText: 'ZIP archive'
   }),
 
   zipExtArchive: new TestEntryInfo({
@@ -1096,7 +1096,7 @@
     lastModifiedTime: 'Apr 6, 2022, 1:00 AM',
     nameText: 'tera.zip',
     sizeText: '250 bytes',
-    typeText: 'Zip archive'
+    typeText: 'ZIP archive'
   }),
 
   debPackage: new TestEntryInfo({
diff --git a/ui/gtk/input_method_context_impl_gtk.cc b/ui/gtk/input_method_context_impl_gtk.cc
index 6d6e2e9..a1d0dcb6 100644
--- a/ui/gtk/input_method_context_impl_gtk.cc
+++ b/ui/gtk/input_method_context_impl_gtk.cc
@@ -174,6 +174,26 @@
   }
 }
 
+void InputMethodContextImplGtk::UpdateFocus(bool has_client,
+                                            ui::TextInputType old_type,
+                                            ui::TextInputType new_type) {
+  if (is_simple_) {
+    // simple context can be used in any textfield, including password box, and
+    // even if the focused text input client's text input type is
+    // ui::TEXT_INPUT_TYPE_NONE.
+    if (has_client)
+      Focus();
+    else
+      Blur();
+  } else {
+    // Otherwise We only focus when the focus is in a textfield.
+    if (old_type != ui::TEXT_INPUT_TYPE_NONE)
+      Blur();
+    if (new_type != ui::TEXT_INPUT_TYPE_NONE)
+      Focus();
+  }
+}
+
 void InputMethodContextImplGtk::Focus() {
   gtk_im_context_focus_in(gtk_context_);
   has_focus_ = true;
diff --git a/ui/gtk/input_method_context_impl_gtk.h b/ui/gtk/input_method_context_impl_gtk.h
index e501519..53d82e1 100644
--- a/ui/gtk/input_method_context_impl_gtk.h
+++ b/ui/gtk/input_method_context_impl_gtk.h
@@ -35,8 +35,9 @@
   bool IsPeekKeyEvent(const ui::KeyEvent& key_event) override;
   void SetCursorLocation(const gfx::Rect& rect) override;
   void Reset() override;
-  void Focus() override;
-  void Blur() override;
+  void UpdateFocus(bool has_client,
+                   ui::TextInputType old_type,
+                   ui::TextInputType new_type) override;
   void SetSurroundingText(const std::u16string& text,
                           const gfx::Range& selection_range) override;
   void SetContentType(ui::TextInputType type,
@@ -66,6 +67,12 @@
                      OnPreeditStart,
                      GtkIMContext*);
 
+  // Called on getting focus.
+  void Focus();
+
+  // Called on loosing focus.
+  void Blur();
+
   // Only used on GTK3.
   void SetContextClientWindow(GdkWindow* window);
 
diff --git a/ui/ozone/platform/drm/common/display_types.h b/ui/ozone/platform/drm/common/display_types.h
index c7cb3ef..f9da290 100644
--- a/ui/ozone/platform/drm/common/display_types.h
+++ b/ui/ozone/platform/drm/common/display_types.h
@@ -6,6 +6,9 @@
 #define UI_OZONE_PLATFORM_DRM_COMMON_DISPLAY_TYPES_H_
 
 #include <memory>
+#include <string>
+
+#include "base/containers/flat_map.h"
 
 namespace display {
 class DisplaySnapshot;
@@ -16,6 +19,8 @@
 using MovableDisplaySnapshots =
     std::vector<std::unique_ptr<display::DisplaySnapshot>>;
 
+using EventPropertyMap = base::flat_map<std::string, std::string>;
+
 }  // namespace ui
 
 #endif  // UI_OZONE_PLATFORM_DRM_COMMON_DISPLAY_TYPES_H_
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
index a30e33b..7958340 100644
--- a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.cc
@@ -5,12 +5,15 @@
 #include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h"
 
 #include <stddef.h>
+#include <cstring>
 #include <memory>
+#include <string>
 #include <utility>
 
 #include "base/containers/flat_map.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/strings/string_number_conversions.h"
 #include "ui/display/types/display_mode.h"
 #include "ui/display/types/display_snapshot.h"
 #include "ui/display/types/gamma_ramp_rgb_entry.h"
@@ -29,6 +32,10 @@
 using MapDisplayIdToIndexAndSnapshotPair =
     base::flat_map<int64_t, display::DisplaySnapshot*>;
 
+// A list of property names that are blocked from issuing a full display
+// configuration (modeset) via a udev display CHANGE event.
+const char* kBlockedEventsByTriggerProperty[] = {"Content Protection"};
+
 class DisplayComparator {
  public:
   explicit DisplayComparator(const DrmDisplay* display)
@@ -98,6 +105,15 @@
   return mode_found;
 }
 
+std::string GetEventPropertyByKey(const std::string& key,
+                                  const EventPropertyMap event_props) {
+  const auto it = event_props.find(key);
+  if (it == event_props.end())
+    return std::string();
+
+  return std::string(it->second);
+}
+
 }  // namespace
 
 DrmGpuDisplayManager::DrmGpuDisplayManager(ScreenManager* screen_manager,
@@ -200,6 +216,55 @@
     drm->DropMaster();
 }
 
+bool DrmGpuDisplayManager::ShouldDisplayEventTriggerConfiguration(
+    const EventPropertyMap& event_props) {
+  DCHECK(!event_props.empty());
+
+  const std::string event_seq_num =
+      GetEventPropertyByKey("SEQNUM", event_props);
+  std::string log_prefix =
+      "Display event CHANGE" +
+      (event_seq_num.empty() ? "" : "(SEQNUM:" + event_seq_num + ") ");
+  std::string trigger_prop_log;
+
+  const std::string event_dev_path =
+      GetEventPropertyByKey("DEVPATH", event_props);
+  const DrmDeviceVector& devices = drm_device_manager_->GetDrmDevices();
+  for (const auto& drm : devices) {
+    if (drm->device_path().value().find(event_dev_path) == std::string::npos)
+      continue;
+
+    // Get the trigger property's ID and convert to an int.
+    const std::string trigger_prop_id_str =
+        GetEventPropertyByKey("PROPERTY", event_props);
+    if (trigger_prop_id_str.empty())
+      break;
+
+    uint32_t trigger_prop_id;
+    const bool conversion_success =
+        base::StringToUint(trigger_prop_id_str, &trigger_prop_id);
+    DCHECK(conversion_success);
+
+    // Fetch the name of the property from the device.
+    ScopedDrmPropertyPtr drm_property(drm->GetProperty(trigger_prop_id));
+    DCHECK(drm_property);
+    trigger_prop_log =
+        "[trigger property: " + std::string(drm_property->name) + "] ";
+    for (const char* blocked_prop : kBlockedEventsByTriggerProperty) {
+      if (strcmp(drm_property->name, blocked_prop) == 0) {
+        VLOG(1) << log_prefix << trigger_prop_log
+                << "resolution: blocked; display configuration task "
+                   "rejected.";
+        return false;
+      }
+    }
+  }
+
+  VLOG(1) << log_prefix << trigger_prop_log
+          << "resolution: allowed; display configuration task triggered.";
+  return true;
+}
+
 bool DrmGpuDisplayManager::ConfigureDisplays(
     const std::vector<display::DisplayConfigurationParams>& config_requests) {
   ScreenManager::ControllerConfigsList controllers_to_configure;
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
index 009f0fb..8bc7f5c 100644
--- a/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h
@@ -54,6 +54,11 @@
   bool TakeDisplayControl();
   void RelinquishDisplayControl();
 
+  // Whether or not a udev display change event triggered by a DRM property
+  // should go through or get blocked.
+  bool ShouldDisplayEventTriggerConfiguration(
+      const EventPropertyMap& event_props);
+
   bool ConfigureDisplays(
       const std::vector<display::DisplayConfigurationParams>& config_requests);
   bool GetHDCPState(int64_t display_id,
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.cc b/ui/ozone/platform/drm/gpu/drm_thread.cc
index db852e8..c114489 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -409,6 +409,16 @@
   std::move(callback).Run(true);
 }
 
+void DrmThread::ShouldDisplayEventTriggerConfiguration(
+    const EventPropertyMap& event_props,
+    base::OnceCallback<void(bool)> callback) {
+  TRACE_EVENT0("drm", "DrmThread::ShouldDisplayEventTriggerConfiguration");
+  const bool should_trigger =
+      display_manager_->ShouldDisplayEventTriggerConfiguration(event_props);
+
+  std::move(callback).Run(should_trigger);
+}
+
 void DrmThread::AddGraphicsDevice(const base::FilePath& path, base::File file) {
   TRACE_EVENT0("drm", "DrmThread::AddGraphicsDevice");
   device_manager_->AddDrmDevice(path, std::move(file));
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.h b/ui/ozone/platform/drm/gpu/drm_thread.h
index d2063eea4..44a2262 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.h
+++ b/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -152,6 +152,9 @@
   void TakeDisplayControl(base::OnceCallback<void(bool)> callback) override;
   void RelinquishDisplayControl(
       base::OnceCallback<void(bool)> callback) override;
+  void ShouldDisplayEventTriggerConfiguration(
+      const EventPropertyMap& event_props,
+      base::OnceCallback<void(bool)> callback) override;
   void RefreshNativeDisplays(
       base::OnceCallback<void(MovableDisplaySnapshots)> callback) override;
   void AddGraphicsDevice(const base::FilePath& path, base::File file) override;
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
index f8cc4fc..bb5d36d 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.cc
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -225,6 +225,19 @@
   proxy_->RemoveGpuThreadObserver(this);
 }
 
+DrmDisplayHostManager::DisplayEvent::DisplayEvent(
+    DeviceEvent::ActionType action_type,
+    const base::FilePath& path,
+    const EventPropertyMap& properties)
+    : action_type(action_type), path(path), display_event_props(properties) {}
+
+DrmDisplayHostManager::DisplayEvent::DisplayEvent(const DisplayEvent&) =
+    default;
+DrmDisplayHostManager::DisplayEvent&
+DrmDisplayHostManager::DisplayEvent::operator=(const DisplayEvent&) = default;
+
+DrmDisplayHostManager::DisplayEvent::~DisplayEvent() = default;
+
 DrmDisplayHost* DrmDisplayHostManager::GetDisplay(int64_t display_id) {
   auto it = std::find_if(displays_.begin(), displays_.end(),
                          FindDrmDisplayHostById(display_id));
@@ -313,7 +326,8 @@
   if (event.device_type() != DeviceEvent::DISPLAY)
     return;
 
-  event_queue_.push(DisplayEvent(event.action_type(), event.path()));
+  event_queue_.push(
+      DisplayEvent(event.action_type(), event.path(), event.properties()));
   ProcessEvent();
 }
 
@@ -321,8 +335,12 @@
   while (!event_queue_.empty() && !task_pending_) {
     DisplayEvent event = event_queue_.front();
     event_queue_.pop();
+    auto seqnum_it = event.display_event_props.find("SEQNUM");
+    const std::string seqnum = seqnum_it == event.display_event_props.end()
+                                   ? ""
+                                   : ("(SEQNUM:" + seqnum_it->second + ")");
     VLOG(1) << "Got display event " << kDisplayActionString[event.action_type]
-            << " for " << event.path.value();
+            << seqnum << " for " << event.path.value();
     switch (event.action_type) {
       case DeviceEvent::ADD:
         if (drm_devices_.find(event.path) == drm_devices_.end()) {
@@ -342,7 +360,8 @@
         task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
             FROM_HERE,
             base::BindOnce(&DrmDisplayHostManager::OnUpdateGraphicsDevice,
-                           weak_ptr_factory_.GetWeakPtr()));
+                           weak_ptr_factory_.GetWeakPtr(),
+                           event.display_event_props));
         break;
       case DeviceEvent::REMOVE:
         DCHECK(event.path != primary_graphics_card_path_)
@@ -374,10 +393,9 @@
   ProcessEvent();
 }
 
-void DrmDisplayHostManager::OnUpdateGraphicsDevice() {
-  NotifyDisplayDelegate();
-  task_pending_ = false;
-  ProcessEvent();
+void DrmDisplayHostManager::OnUpdateGraphicsDevice(
+    const EventPropertyMap& udev_event_props) {
+  proxy_->GpuShouldDisplayEventTriggerConfiguration(udev_event_props);
 }
 
 void DrmDisplayHostManager::OnRemoveGraphicsDevice(
@@ -533,6 +551,15 @@
   display_control_change_pending_ = false;
 }
 
+void DrmDisplayHostManager::GpuShouldDisplayEventTriggerConfiguration(
+    bool should_trigger) {
+  if (should_trigger)
+    NotifyDisplayDelegate();
+
+  task_pending_ = false;
+  ProcessEvent();
+}
+
 void DrmDisplayHostManager::RunUpdateDisplaysCallback(
     display::GetDisplaysCallback callback) const {
   std::vector<display::DisplaySnapshot*> snapshots;
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.h b/ui/ozone/platform/drm/host/drm_display_host_manager.h
index 8559e4f..1c72804 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.h
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.h
@@ -75,15 +75,20 @@
   void GpuUpdatedHDCPState(int64_t display_id, bool status);
   void GpuTookDisplayControl(bool status);
   void GpuRelinquishedDisplayControl(bool status);
+  void GpuShouldDisplayEventTriggerConfiguration(bool should_trigger);
 
  private:
   struct DisplayEvent {
     DisplayEvent(DeviceEvent::ActionType action_type,
-                 const base::FilePath& path)
-        : action_type(action_type), path(path) {}
+                 const base::FilePath& path,
+                 const EventPropertyMap& properties);
+    DisplayEvent(const DisplayEvent&);
+    DisplayEvent& operator=(const DisplayEvent&);
+    ~DisplayEvent();
 
     DeviceEvent::ActionType action_type;
     base::FilePath path;
+    EventPropertyMap display_event_props;
   };
 
   // Handle hotplug events sequentially.
@@ -94,7 +99,7 @@
   void OnAddGraphicsDevice(const base::FilePath& path,
                            const base::FilePath& sysfs_path,
                            std::unique_ptr<DrmDeviceHandle> handle);
-  void OnUpdateGraphicsDevice();
+  void OnUpdateGraphicsDevice(const EventPropertyMap& udev_event_props);
   void OnRemoveGraphicsDevice(const base::FilePath& path);
 
   void RunUpdateDisplaysCallback(display::GetDisplaysCallback callback) const;
diff --git a/ui/ozone/platform/drm/host/gpu_thread_adapter.h b/ui/ozone/platform/drm/host/gpu_thread_adapter.h
index 91cb251..eea97b1 100644
--- a/ui/ozone/platform/drm/host/gpu_thread_adapter.h
+++ b/ui/ozone/platform/drm/host/gpu_thread_adapter.h
@@ -12,6 +12,7 @@
 #include "ui/display/types/native_display_delegate.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/platform/drm/common/display_types.h"
 
 namespace base {
 class FilePath;
@@ -44,6 +45,8 @@
   virtual void GpuAddGraphicsDevice(const base::FilePath& path,
                                     base::ScopedFD fd) = 0;
   virtual bool GpuRemoveGraphicsDevice(const base::FilePath& path) = 0;
+  virtual void GpuShouldDisplayEventTriggerConfiguration(
+      const EventPropertyMap& event_props) = 0;
 
   // Services needed by DrmDisplayHost
   virtual void GpuConfigureNativeDisplays(
diff --git a/ui/ozone/platform/drm/host/host_drm_device.cc b/ui/ozone/platform/drm/host/host_drm_device.cc
index 7bcc12b..ce0b642 100644
--- a/ui/ozone/platform/drm/host/host_drm_device.cc
+++ b/ui/ozone/platform/drm/host/host_drm_device.cc
@@ -186,6 +186,23 @@
   return true;
 }
 
+void HostDrmDevice::GpuShouldDisplayEventTriggerConfiguration(
+    const EventPropertyMap& event_props) {
+  DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_);
+
+  // No connection to DRM device. Block the event since the entire configuration
+  // will most likely fail.
+  if (!IsConnected()) {
+    GpuShouldDisplayEventTriggerConfigurationCallback(/*should_trigger=*/false);
+    return;
+  }
+
+  auto callback = base::BindOnce(
+      &HostDrmDevice::GpuShouldDisplayEventTriggerConfigurationCallback, this);
+  drm_device_->ShouldDisplayEventTriggerConfiguration(event_props,
+                                                      std::move(callback));
+}
+
 bool HostDrmDevice::GpuGetHDCPState(int64_t display_id) {
   DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_);
   if (!IsConnected())
@@ -264,6 +281,12 @@
   display_manager_->GpuRelinquishedDisplayControl(success);
 }
 
+void HostDrmDevice::GpuShouldDisplayEventTriggerConfigurationCallback(
+    bool should_trigger) const {
+  DCHECK_CALLED_ON_VALID_THREAD(on_ui_thread_);
+  display_manager_->GpuShouldDisplayEventTriggerConfiguration(should_trigger);
+}
+
 void HostDrmDevice::GpuGetHDCPStateCallback(
     int64_t display_id,
     bool success,
diff --git a/ui/ozone/platform/drm/host/host_drm_device.h b/ui/ozone/platform/drm/host/host_drm_device.h
index 988ea61..d34dfb6 100644
--- a/ui/ozone/platform/drm/host/host_drm_device.h
+++ b/ui/ozone/platform/drm/host/host_drm_device.h
@@ -62,6 +62,8 @@
   void GpuAddGraphicsDevice(const base::FilePath& path,
                             base::ScopedFD fd) override;
   bool GpuRemoveGraphicsDevice(const base::FilePath& path) override;
+  void GpuShouldDisplayEventTriggerConfiguration(
+      const EventPropertyMap& event_props) override;
 
   // Services needed by DrmDisplayHost
   void GpuConfigureNativeDisplays(
@@ -100,6 +102,8 @@
   void GpuRefreshNativeDisplaysCallback(MovableDisplaySnapshots displays) const;
   void GpuTakeDisplayControlCallback(bool success) const;
   void GpuRelinquishDisplayControlCallback(bool success) const;
+  void GpuShouldDisplayEventTriggerConfigurationCallback(
+      bool should_trigger) const;
   void GpuGetHDCPStateCallback(
       int64_t display_id,
       bool success,
diff --git a/ui/ozone/platform/drm/mojom/drm_device.mojom b/ui/ozone/platform/drm/mojom/drm_device.mojom
index 012928e..cd64106 100644
--- a/ui/ozone/platform/drm/mojom/drm_device.mojom
+++ b/ui/ozone/platform/drm/mojom/drm_device.mojom
@@ -51,6 +51,13 @@
   // Instructs the GPU to abandon a DRM device.
   RemoveGraphicsDevice(mojo_base.mojom.FilePath path);
 
+  // Asks whether or not an incoming udev change event is blocked.
+  // |event_props| is a map of a display UDEV event's property name and its
+  // value. The list of a UDEV event's properties can be seen when running
+  // $ udevadm monitor --property on a DUT.
+  ShouldDisplayEventTriggerConfiguration(map<string, string> event_props) =>
+      (bool should_trigger);
+
   // Configures (Enables/Disables) DRM displays, returns whether or not the
   // configuration was successful.
   ConfigureNativeDisplays(
diff --git a/ui/ozone/platform/wayland/host/wayland_input_method_context.cc b/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
index b9d392b..54c4c61 100644
--- a/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
+++ b/ui/ozone/platform/wayland/host/wayland_input_method_context.cc
@@ -206,6 +206,27 @@
     text_input_->Reset();
 }
 
+void WaylandInputMethodContext::UpdateFocus(bool has_client,
+                                            TextInputType old_type,
+                                            TextInputType new_type) {
+  // TODO(b/226781965): Known issue that this does not work.
+  if (is_simple_) {
+    // simple context can be used in any textfield, including password box, and
+    // even if the focused text input client's text input type is
+    // ui::TEXT_INPUT_TYPE_NONE.
+    if (has_client)
+      Focus();
+    else
+      Blur();
+  } else {
+    // Otherwise We only focus when the focus is in a textfield.
+    if (old_type != TEXT_INPUT_TYPE_NONE)
+      Blur();
+    if (new_type != TEXT_INPUT_TYPE_NONE)
+      Focus();
+  }
+}
+
 void WaylandInputMethodContext::Focus() {
   focused_ = true;
   MaybeUpdateActivated();
diff --git a/ui/ozone/platform/wayland/host/wayland_input_method_context.h b/ui/ozone/platform/wayland/host/wayland_input_method_context.h
index c3d3171f..e195453 100644
--- a/ui/ozone/platform/wayland/host/wayland_input_method_context.h
+++ b/ui/ozone/platform/wayland/host/wayland_input_method_context.h
@@ -52,9 +52,10 @@
                       TextInputMode mode,
                       uint32_t flags,
                       bool should_do_learning) override;
+  void UpdateFocus(bool has_client,
+                   TextInputType old_type,
+                   TextInputType new_type) override;
   void Reset() override;
-  void Focus() override;
-  void Blur() override;
   VirtualKeyboardController* GetVirtualKeyboardController() override;
 
   // VirtualKeyboardController overrides:
@@ -81,6 +82,8 @@
   void OnModifiersMap(std::vector<std::string> modifiers_map) override;
 
  private:
+  void Focus();
+  void Blur();
   void UpdatePreeditText(const std::u16string& preedit_text);
   void MaybeUpdateActivated();
 
diff --git a/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc b/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc
index 435cf71a..13bc3a3 100644
--- a/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_input_method_context_unittest.cc
@@ -159,7 +159,8 @@
 
   EXPECT_CALL(*zwp_text_input_, Activate(surface_->resource())).Times(0);
   EXPECT_CALL(*zwp_text_input_, ShowInputPanel()).Times(0);
-  input_method_context_->Focus();
+  input_method_context_->UpdateFocus(true, ui::TEXT_INPUT_TYPE_NONE,
+                                     ui::TEXT_INPUT_TYPE_TEXT);
   connection_->ScheduleFlush();
   Sync();
   Mock::VerifyAndClearExpectations(zwp_text_input_);
@@ -181,7 +182,8 @@
 
   EXPECT_CALL(*zwp_text_input_, Deactivate()).Times(0);
   EXPECT_CALL(*zwp_text_input_, HideInputPanel()).Times(0);
-  input_method_context_->Blur();
+  input_method_context_->UpdateFocus(true, ui::TEXT_INPUT_TYPE_TEXT,
+                                     ui::TEXT_INPUT_TYPE_NONE);
   connection_->ScheduleFlush();
   Sync();
   Mock::VerifyAndClearExpectations(zwp_text_input_);
@@ -198,14 +200,16 @@
 
   EXPECT_CALL(*zwp_text_input_, Activate(surface_->resource()));
   EXPECT_CALL(*zwp_text_input_, ShowInputPanel());
-  input_method_context_->Focus();
+  input_method_context_->UpdateFocus(true, ui::TEXT_INPUT_TYPE_NONE,
+                                     ui::TEXT_INPUT_TYPE_TEXT);
   connection_->ScheduleFlush();
   Sync();
   Mock::VerifyAndClearExpectations(zwp_text_input_);
 
   EXPECT_CALL(*zwp_text_input_, Deactivate());
   EXPECT_CALL(*zwp_text_input_, HideInputPanel());
-  input_method_context_->Blur();
+  input_method_context_->UpdateFocus(true, ui::TEXT_INPUT_TYPE_TEXT,
+                                     ui::TEXT_INPUT_TYPE_NONE);
   connection_->ScheduleFlush();
   Sync();
   Mock::VerifyAndClearExpectations(zwp_text_input_);
@@ -558,14 +562,16 @@
 
   EXPECT_CALL(*zwp_text_input_, Activate(surface_->resource()));
   EXPECT_CALL(*zwp_text_input_, ShowInputPanel());
-  input_method_context_->Focus();
+  input_method_context_->UpdateFocus(true, ui::TEXT_INPUT_TYPE_NONE,
+                                     ui::TEXT_INPUT_TYPE_TEXT);
   connection_->ScheduleFlush();
   Sync();
   Mock::VerifyAndClearExpectations(zwp_text_input_);
 
   EXPECT_CALL(*zwp_text_input_, Deactivate());
   EXPECT_CALL(*zwp_text_input_, HideInputPanel());
-  input_method_context_->Blur();
+  input_method_context_->UpdateFocus(false, ui::TEXT_INPUT_TYPE_TEXT,
+                                     ui::TEXT_INPUT_TYPE_NONE);
   connection_->ScheduleFlush();
   Sync();
   Mock::VerifyAndClearExpectations(zwp_text_input_);
diff --git a/ui/webui/resources/cr_components/app_management/BUILD.gn b/ui/webui/resources/cr_components/app_management/BUILD.gn
index bcf4f49..69436d0 100644
--- a/ui/webui/resources/cr_components/app_management/BUILD.gn
+++ b/ui/webui/resources/cr_components/app_management/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//tools/grit/preprocess_if_expr.gni")
-import("//tools/polymer/html_to_js.gni")
+import("//tools/polymer/css_to_wrapper.gni")
 import("//tools/polymer/html_to_wrapper.gni")
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
@@ -16,12 +16,12 @@
 preprocess_folder =
     "$root_gen_dir/ui/webui/resources/preprocessed/cr_components/app_management"
 
-html_to_js("css_wrapper_files") {
-  js_files = css_wrapper_files
+css_to_wrapper("css_wrapper_files") {
+  in_files = css_files
 }
 
 html_to_wrapper("html_wrapper_files") {
-  in_files = html_files
+  in_files = html_files + html_icons_files
 }
 
 mojom("mojo_bindings") {
diff --git a/ui/webui/resources/cr_components/app_management/app_management.gni b/ui/webui/resources/cr_components/app_management/app_management.gni
index a373833..5e65f32 100644
--- a/ui/webui/resources/cr_components/app_management/app_management.gni
+++ b/ui/webui/resources/cr_components/app_management/app_management.gni
@@ -18,9 +18,11 @@
   html_files += [ string_replace(f, ".ts", ".html") ]
 }
 
+html_icons_files = [ "icons.html" ]
+
 # Files that are generated by html_to_wrapper().
 html_wrapper_files = []
-foreach(f, html_files) {
+foreach(f, html_files + html_icons_files) {
   html_wrapper_files += [ f + ".ts" ]
 }
 
@@ -37,10 +39,16 @@
   "types.mojom-webui.js",
 ]
 
-ts_files = _web_component_files + _non_web_component_files
-
-css_wrapper_files = [
-  "icons.ts",
-  "shared_style.ts",
-  "shared_vars.ts",
+# Files that are passed as input to css_to_wrapper().
+css_files = [
+  "app_management_shared_style.css",
+  "shared_vars.css",
 ]
+
+# Files that are generated by css_to_wrapper().
+css_wrapper_files = []
+foreach(f, css_files) {
+  css_wrapper_files += [ f + ".ts" ]
+}
+
+ts_files = _web_component_files + _non_web_component_files
diff --git a/ui/webui/resources/cr_components/app_management/app_management_shared_style.css b/ui/webui/resources/cr_components/app_management/app_management_shared_style.css
new file mode 100644
index 0000000..d96b57e
--- /dev/null
+++ b/ui/webui/resources/cr_components/app_management/app_management_shared_style.css
@@ -0,0 +1,157 @@
+/* Copyright 2022 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. */
+
+/* #css_wrapper_metadata_start
+ * #type=style
+ * #import=./shared_vars.css.js
+ * #import=//resources/cr_elements/shared_style_css.m.js
+ * #import=//resources/cr_elements/shared_vars_css.m.js
+ * #include=cr-shared-style
+ * #css_wrapper_metadata_end */
+
+.card-container {
+  border-radius: var(--cr-card-border-radius);
+  box-shadow: var(--cr-card-shadow);
+  display: flex;
+  flex-direction: column;
+  margin: 24px auto;
+  max-width: var(--card-max-width);
+  min-width: var(--card-min-width);
+}
+
+.separated-row {
+  align-items: center;
+  display: inline-flex;
+  justify-content: space-between;
+}
+
+.card-row {
+  border-top: var(--card-separator);
+  padding: 0 24px;
+}
+
+.permission-card-row {
+  border-bottom: var(--card-separator);
+  padding: 0 20px;
+}
+
+.permission-text-row {
+  border-top: var(--card-separator);
+  display: flex;
+  flex-direction: column;
+  height: var(--text-permission-list-row-height);
+  justify-content: center;
+}
+
+.permission-section-header {
+  line-height: 48px;
+}
+
+.clickable {
+  cursor: pointer;
+}
+
+.permission-card-row:last-child {
+  border-style: none;
+}
+
+.permission-card-row[hide-bottom-border] {
+  border-bottom: none;
+}
+
+.header-text {
+  color: var(--header-text-color);
+  font-weight: var(--header-font-weight);
+}
+
+.permission-row-controls {
+  align-items: center;
+  display: inline-flex;
+}
+
+.permission-list {
+  display: flex;
+  flex-direction: column;
+}
+
+.permission-list > * {
+  flex: 0 0 var(--permission-list-item-height);
+}
+
+.row-with-description {
+  flex: 0 0 var(--permission-list-item-with-description-height);
+}
+
+.native-settings-icon {
+  display: flex;
+  margin-inline-start: 0;
+}
+
+.subpermission-row {
+  border-bottom: var(--card-separator);
+  height: 48px;
+}
+
+.subpermission-row[available_]:last-of-type {
+  border-bottom: none;
+}
+
+.secondary-text {
+  color: var(--secondary-text-color);
+  font-weight: var(--secondary-font-weight);
+}
+
+.expand-button {
+  height: 36px;
+  margin-inline-end: 12px;
+  width: 36px;
+}
+
+.horizontal-align {
+  align-items: center;
+  display: flex;
+}
+
+.expander-list-row {
+  align-items: center;
+  border-top: var(--card-separator);
+  color: var(--secondary-text-color);
+  display: flex;
+  height: 50px;
+  justify-content: space-between;
+  padding-inline-end: 8px;
+  padding-inline-start: 24px;
+}
+
+.page-title {
+  flex: 1;
+  font-size: 16px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.indented-permission-block {
+  padding-inline-start: 36px;
+}
+
+.info-text-row {
+  display: flex;
+  flex: 0 0 var(--info-text-row-height);
+}
+
+#info-icon {
+  float: inline-block;
+  height: var(--help-icon-size);
+  padding-inline-end: var(--help-icon-padding);
+  width: var(--help-icon-size);
+}
+
+#info-text {
+  float: inline-block;
+  overflow-wrap: break-word;
+}
+
+.indented-app-details {
+  margin-inline-start: 20px;
+}
diff --git a/ui/webui/resources/cr_components/app_management/file_handling_item.html b/ui/webui/resources/cr_components/app_management/file_handling_item.html
index b235cc0..fb8ffa4 100644
--- a/ui/webui/resources/cr_components/app_management/file_handling_item.html
+++ b/ui/webui/resources/cr_components/app_management/file_handling_item.html
@@ -1,4 +1,4 @@
-<style include="app-management-shared-css">
+<style include="app-management-shared-style">
   :host(:not([available_])) {
     display: none;
   }
diff --git a/ui/webui/resources/cr_components/app_management/file_handling_item.ts b/ui/webui/resources/cr_components/app_management/file_handling_item.ts
index 42cd6b6..a7834d6 100644
--- a/ui/webui/resources/cr_components/app_management/file_handling_item.ts
+++ b/ui/webui/resources/cr_components/app_management/file_handling_item.ts
@@ -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 './shared_style.js';
+import './app_management_shared_style.css.js';
 import './toggle_row.js';
 
 import {assert} from '//resources/js/assert.m.js';
diff --git a/ui/webui/resources/cr_components/app_management/icons.ts b/ui/webui/resources/cr_components/app_management/icons.ts
deleted file mode 100644
index 643939e5..0000000
--- a/ui/webui/resources/cr_components/app_management/icons.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import '//resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
-
-import {html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-const template = html`{__html_template__}`;
-document.head.appendChild(template.content);
diff --git a/ui/webui/resources/cr_components/app_management/more_permissions_item.html b/ui/webui/resources/cr_components/app_management/more_permissions_item.html
index c6b9f26..fc5ec78 100644
--- a/ui/webui/resources/cr_components/app_management/more_permissions_item.html
+++ b/ui/webui/resources/cr_components/app_management/more_permissions_item.html
@@ -1,4 +1,4 @@
-<style include="app-management-shared-css">
+<style include="app-management-shared-style">
   :host {
     align-items: center;
     cursor: pointer;
diff --git a/ui/webui/resources/cr_components/app_management/more_permissions_item.ts b/ui/webui/resources/cr_components/app_management/more_permissions_item.ts
index bdf6aa9b..3210571 100644
--- a/ui/webui/resources/cr_components/app_management/more_permissions_item.ts
+++ b/ui/webui/resources/cr_components/app_management/more_permissions_item.ts
@@ -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 './shared_style.js';
+import './app_management_shared_style.css.js';
 import '//resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
 
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/ui/webui/resources/cr_components/app_management/permission_item.html b/ui/webui/resources/cr_components/app_management/permission_item.html
index e786762..6ae933666 100644
--- a/ui/webui/resources/cr_components/app_management/permission_item.html
+++ b/ui/webui/resources/cr_components/app_management/permission_item.html
@@ -1,4 +1,4 @@
-<style include="app-management-shared-css">
+<style include="app-management-shared-style">
   :host {
     align-items: center;
     display: flex;
diff --git a/ui/webui/resources/cr_components/app_management/permission_item.ts b/ui/webui/resources/cr_components/app_management/permission_item.ts
index ccdbc02..60959a72 100644
--- a/ui/webui/resources/cr_components/app_management/permission_item.ts
+++ b/ui/webui/resources/cr_components/app_management/permission_item.ts
@@ -1,7 +1,7 @@
 // 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.
-import './shared_style.js';
+import './app_management_shared_style.css.js';
 import './toggle_row.js';
 
 import {assert, assertNotReached} from '//resources/js/assert.m.js';
diff --git a/ui/webui/resources/cr_components/app_management/run_on_os_login_item.ts b/ui/webui/resources/cr_components/app_management/run_on_os_login_item.ts
index 217e40f..24553a9 100644
--- a/ui/webui/resources/cr_components/app_management/run_on_os_login_item.ts
+++ b/ui/webui/resources/cr_components/app_management/run_on_os_login_item.ts
@@ -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 './shared_style.js';
+import './app_management_shared_style.css.js';
 import './toggle_row.js';
 
 import {assert, assertNotReached} from '//resources/js/assert.m.js';
diff --git a/ui/webui/resources/cr_components/app_management/shared_style.html b/ui/webui/resources/cr_components/app_management/shared_style.html
deleted file mode 100644
index 415dffe..0000000
--- a/ui/webui/resources/cr_components/app_management/shared_style.html
+++ /dev/null
@@ -1,149 +0,0 @@
-<template>
-  <style include="cr-shared-style">
-    .card-container {
-      border-radius: var(--cr-card-border-radius);
-      box-shadow: var(--cr-card-shadow);
-      display: flex;
-      flex-direction: column;
-      margin: 24px auto;
-      max-width: var(--card-max-width);
-      min-width: var(--card-min-width);
-    }
-
-    .separated-row {
-      align-items: center;
-      display: inline-flex;
-      justify-content: space-between;
-    }
-
-    .card-row {
-      border-top: var(--card-separator);
-      padding: 0 24px;
-    }
-
-    .permission-card-row {
-      border-bottom: var(--card-separator);
-      padding: 0 20px;
-    }
-
-    .permission-text-row {
-      border-top: var(--card-separator);
-      display: flex;
-      flex-direction: column;
-      height: var(--text-permission-list-row-height);
-      justify-content: center;
-    }
-
-    .permission-section-header {
-      line-height: 48px;
-    }
-
-    .clickable {
-      cursor: pointer;
-    }
-
-    .permission-card-row:last-child {
-      border-style: none;
-    }
-
-    .permission-card-row[hide-bottom-border] {
-      border-bottom: none;
-    }
-
-    .header-text {
-      color: var(--header-text-color);
-      font-weight: var(--header-font-weight);
-    }
-
-    .permission-row-controls {
-      align-items: center;
-      display: inline-flex;
-    }
-
-    .permission-list {
-      display: flex;
-      flex-direction: column;
-    }
-
-    .permission-list > * {
-      flex: 0 0 var(--permission-list-item-height);
-    }
-
-    .row-with-description {
-      flex: 0 0 var(--permission-list-item-with-description-height);
-    }
-
-    .native-settings-icon {
-      display: flex;
-      margin-inline-start: 0;
-    }
-
-    .subpermission-row {
-      border-bottom: var(--card-separator);
-      height: 48px;
-    }
-
-    .subpermission-row[available_]:last-of-type {
-      border-bottom: none;
-    }
-
-    .secondary-text {
-      color: var(--secondary-text-color);
-      font-weight: var(--secondary-font-weight);
-    }
-
-    .expand-button {
-      height: 36px;
-      margin-inline-end: 12px;
-      width: 36px;
-    }
-
-    .horizontal-align {
-      align-items: center;
-      display: flex;
-    }
-
-    .expander-list-row {
-      align-items: center;
-      border-top: var(--card-separator);
-      color: var(--secondary-text-color);
-      display: flex;
-      height: 50px;
-      justify-content: space-between;
-      padding-inline-end: 8px;
-      padding-inline-start: 24px;
-    }
-
-    .page-title {
-      flex: 1;
-      font-size: 16px;
-      overflow: hidden;
-      text-overflow: ellipsis;
-    }
-
-    .indented-permission-block {
-      padding-inline-start: 36px;
-    }
-
-    .info-text-row {
-      display: flex;
-      flex: 0 0 var(--info-text-row-height);
-    }
-
-    #info-icon {
-      float: inline-block;
-      height: var(--help-icon-size);
-      padding-inline-end: var(--help-icon-padding);
-      width: var(--help-icon-size);
-    }
-
-    #info-text {
-      float: inline-block;
-      overflow-wrap: break-word;
-    }
-
-    .indented-app-details {
-      margin-inline-start: 20px;
-    }
-  </style>
-</template>
diff --git a/ui/webui/resources/cr_components/app_management/shared_style.ts b/ui/webui/resources/cr_components/app_management/shared_style.ts
deleted file mode 100644
index 88882cf..0000000
--- a/ui/webui/resources/cr_components/app_management/shared_style.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import './shared_vars.js';
-import '//resources/cr_elements/shared_style_css.m.js';
-import '//resources/cr_elements/shared_vars_css.m.js';
-
-const styleMod = document.createElement('dom-module');
-styleMod.innerHTML = `{__html_template__}`;
-styleMod.register('app-management-shared-css');
diff --git a/ui/webui/resources/cr_components/app_management/shared_vars.css b/ui/webui/resources/cr_components/app_management/shared_vars.css
new file mode 100644
index 0000000..7555d1d
--- /dev/null
+++ b/ui/webui/resources/cr_components/app_management/shared_vars.css
@@ -0,0 +1,32 @@
+/* Copyright 2022 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. */
+
+/* #css_wrapper_metadata_start
+ * #type=vars
+ * #import=//resources/cr_elements/shared_vars_css.m.js
+ * #css_wrapper_metadata_end */
+
+html {
+  --app-management-font-size: 13px;
+  --app-management-line-height: 1.54; /* 20px */
+  --card-max-width: 676px;
+  --card-min-width: 550px;
+  --card-separator: 1px solid var(--cr-separator-color);
+  --expanded-permission-row-height: 48px;
+  --header-font-weight: 500;
+  --header-text-color: var(--cr-title-text-color);
+  --permission-icon-padding: 20px;
+  --permission-list-item-height: 48px;
+  --permission-list-item-with-description-height: 64px;
+  --primary-text-color: var(--cr-primary-text-color);
+  --row-item-icon-padding: 12px;
+  --row-item-vertical-padding: 16px;
+  --secondary-font-weight: 400;
+  --secondary-text-color: var(--cr-secondary-text-color);
+  --text-permission-list-row-height: 40px;
+  --help-icon-padding: 6px;
+  --info-text-row-height: 48px;
+  --help-icon-size: 20px;
+  --app-management-controlled-by-spacing: var(--cr-controlled-by-spacing);
+}
diff --git a/ui/webui/resources/cr_components/app_management/shared_vars.html b/ui/webui/resources/cr_components/app_management/shared_vars.html
deleted file mode 100644
index f34fa3a..0000000
--- a/ui/webui/resources/cr_components/app_management/shared_vars.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<custom-style>
-<style>
-  html {
-    --app-management-font-size: 13px;
-    --app-management-line-height: 1.54; /* 20px */
-    --card-max-width: 676px;
-    --card-min-width: 550px;
-    --card-separator: 1px solid var(--cr-separator-color);
-    --expanded-permission-row-height: 48px;
-    --header-font-weight: 500;
-    --header-text-color: var(--cr-title-text-color);
-    --permission-icon-padding: 20px;
-    --permission-list-item-height: 48px;
-    --permission-list-item-with-description-height: 64px;
-    --primary-text-color: var(--cr-primary-text-color);
-    --row-item-icon-padding: 12px;
-    --row-item-vertical-padding: 16px;
-    --secondary-font-weight: 400;
-    --secondary-text-color: var(--cr-secondary-text-color);
-    --text-permission-list-row-height: 40px;
-    --help-icon-padding: 6px;
-    --info-text-row-height: 48px;
-    --help-icon-size: 20px;
-    --app-management-controlled-by-spacing: var(--cr-controlled-by-spacing);
-  }
-</style>
-</custom-style>
diff --git a/ui/webui/resources/cr_components/app_management/shared_vars.ts b/ui/webui/resources/cr_components/app_management/shared_vars.ts
deleted file mode 100644
index d2a1a49..0000000
--- a/ui/webui/resources/cr_components/app_management/shared_vars.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import '//resources/cr_elements/shared_vars_css.m.js';
-
-const $_documentContainer = document.createElement('template');
-$_documentContainer.innerHTML = `{__html_template__}`;
-document.head.appendChild($_documentContainer.content);
diff --git a/ui/webui/resources/cr_components/app_management/toggle_row.html b/ui/webui/resources/cr_components/app_management/toggle_row.html
index a08ca34..dcd704d 100644
--- a/ui/webui/resources/cr_components/app_management/toggle_row.html
+++ b/ui/webui/resources/cr_components/app_management/toggle_row.html
@@ -1,4 +1,4 @@
-<style include="app-management-shared-css">
+<style include="app-management-shared-style">
   :host {
     align-items: center;
     display: flex;
diff --git a/ui/webui/resources/cr_components/app_management/toggle_row.ts b/ui/webui/resources/cr_components/app_management/toggle_row.ts
index 2c5dd17..f5f8c6d 100644
--- a/ui/webui/resources/cr_components/app_management/toggle_row.ts
+++ b/ui/webui/resources/cr_components/app_management/toggle_row.ts
@@ -1,7 +1,7 @@
 // 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 './shared_style.js';
+import './app_management_shared_style.css.js';
 import '//resources/cr_elements/cr_toggle/cr_toggle.m.js';
 import '//resources/cr_elements/policy/cr_policy_indicator.m.js';
 import '//resources/cr_elements/icons.m.js';
diff --git a/ui/webui/resources/cr_components/app_management/uninstall_button.html b/ui/webui/resources/cr_components/app_management/uninstall_button.html
index 07eff61b..b9cb5ce 100644
--- a/ui/webui/resources/cr_components/app_management/uninstall_button.html
+++ b/ui/webui/resources/cr_components/app_management/uninstall_button.html
@@ -1,4 +1,4 @@
-<style include="app-management-shared-css">
+<style include="app-management-shared-style">
   :host {
     align-items: center;
     display: flex;
diff --git a/ui/webui/resources/cr_components/app_management/uninstall_button.ts b/ui/webui/resources/cr_components/app_management/uninstall_button.ts
index b92e458..95af842 100644
--- a/ui/webui/resources/cr_components/app_management/uninstall_button.ts
+++ b/ui/webui/resources/cr_components/app_management/uninstall_button.ts
@@ -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 './shared_style.js';
+import './app_management_shared_style.css.js';
 import '//resources/cr_elements/cr_button/cr_button.m.js';
 import '//resources/cr_elements/policy/cr_tooltip_icon.m.js';
 
diff --git a/ui/webui/resources/cr_components/app_management/window_mode_item.ts b/ui/webui/resources/cr_components/app_management/window_mode_item.ts
index afd4b925..12736123 100644
--- a/ui/webui/resources/cr_components/app_management/window_mode_item.ts
+++ b/ui/webui/resources/cr_components/app_management/window_mode_item.ts
@@ -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 './shared_style.js';
+import './app_management_shared_style.css.js';
 import './toggle_row.js';
 
 import {assert, assertNotReached} from '//resources/js/assert.m.js';