diff --git a/DEPS b/DEPS
index 838d5ed..a066c6f6 100644
--- a/DEPS
+++ b/DEPS
@@ -222,11 +222,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'c1478d6d32d841dac75f99baf6fb79f76ce65728',
+  'skia_revision': '6c2764b93c06f9f1052c2dd438ee90a6078d7225',
   # 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': 'aeb6c869fb5f6717192f021238c1cd2277f056d5',
+  'v8_revision': 'c698872624bae2861671f8b5573de671c813a8ca',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -242,7 +242,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'fa49ce808596a75499e2f63ad0a4ac225679c2a8',
+  'pdfium_revision': 'ee64a8518eaebbcdee771f08eeacbb1ad1198223',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -301,7 +301,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': '32fc9653cb6345bf98d0ec94cfaa72c08c3032ff',
+  'devtools_frontend_revision': '8b8c67e57fb6b53670382ab9f6aa413d82005b5b',
   # 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.
@@ -738,7 +738,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'j1av4wGC5BvTRPzU3WnROMwFRUSekTHSjPTBm_Ud594C',
+          'version': '_LKV6brUkzjMrW14NMWFjfj_r6ivlu8sDlRiEfRmsO4C',
       },
     ],
     'condition': 'checkout_android',
@@ -1360,7 +1360,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '71d582b360331087630937eaec1d194f0c0b78fb',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'd04538362330bd3ae3d534c542fb71ead7b8f28a',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1551,7 +1551,7 @@
   },
 
   'src/third_party/usrsctp/usrsctplib':
-    Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'fc5cba21a01b60977d277b0e6b5b72146383dcf6',
+    Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '1ade45cbadfd19298d2c47dc538962d4425ad2dd',
 
   'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@36456846a4affb738fc3f012cc8f1c8c86ef0595',
 
@@ -1592,7 +1592,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'e2aeec9de7a742ae131b2f56fc22de6b17b8d0e1',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '813a087e84e42f2d0e23d502ac7c98a4d65fb253',
+    Var('webrtc_git') + '/src.git' + '@' + '63078098186ae1191b7f3a3e410aea02d33a399e',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1653,7 +1653,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@146562014e1cec446b4ed3c71ea627f40d5eade7',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c3449215be2c0b688da367c3f6b7d5875dd2967d',
     'condition': 'checkout_src_internal',
   },
 
@@ -1661,7 +1661,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/eche_app/app',
-        'version': 'kG2kLjG-qa6xbUHokVwPT3YeV5-h581elsnbyCJs3nAC',
+        'version': '8Mr_f3p8_lzS1Z43mqqG_cARPT619IEqhhdiQrtlQIQC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1683,7 +1683,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'NTg5qBASgzJXpjE2M2rmgR5ppVHJ_an1VJWMuOgqf0YC',
+        'version': '8OlY1Eg5cnFEdto94hB8UEyg7-I2O6lm7e_AS6CKR9UC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 7a16e62d..be80b54 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -295,6 +295,10 @@
 // Enables or disables Crostini using Buster container images.
 const base::Feature kCrostiniUseBusterImage{"CrostiniUseBusterImage",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
+// Use DLC instead of component updater for managing the Termina image if set
+// (and component updater instead of DLC if not).
+const base::Feature kCrostiniUseDlc{"CrostiniUseDlc",
+                                    base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables or disables using Cryptauth's GetDevicesActivityStatus API.
 const base::Feature kCryptAuthV2DeviceActivityStatus{
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 0e244b0..a9d3b9f 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -114,6 +114,9 @@
 extern const base::Feature kCompositingBasedThrottling;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kContextualNudges;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kCroshSWA;
+COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kCrostiniUseDlc;
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kDiagnosticsApp;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kCrostiniDiskResizing;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kCrostiniGpuSupport;
diff --git a/ash/display/display_prefs.cc b/ash/display/display_prefs.cc
index 4fea9a54..0903f65 100644
--- a/ash/display/display_prefs.cc
+++ b/ash/display/display_prefs.cc
@@ -189,7 +189,6 @@
 
   return *user_type == user_manager::USER_TYPE_REGULAR ||
          *user_type == user_manager::USER_TYPE_CHILD ||
-         *user_type == user_manager::USER_TYPE_SUPERVISED_DEPRECATED ||
          *user_type == user_manager::USER_TYPE_KIOSK_APP ||
          (*user_type == user_manager::USER_TYPE_PUBLIC_ACCOUNT &&
           Shell::Get()->local_state()->GetBoolean(
diff --git a/ash/session/session_controller_impl.cc b/ash/session/session_controller_impl.cc
index ef7d4ae..bcb031ca 100644
--- a/ash/session/session_controller_impl.cc
+++ b/ash/session/session_controller_impl.cc
@@ -154,15 +154,6 @@
   return (*it).get();
 }
 
-bool SessionControllerImpl::IsUserChildOrDeprecatedSupervised() const {
-  if (!IsActiveUserSessionStarted())
-    return false;
-
-  user_manager::UserType active_user_type = GetUserSession(0)->user_info.type;
-  return active_user_type == user_manager::USER_TYPE_SUPERVISED_DEPRECATED ||
-         active_user_type == user_manager::USER_TYPE_CHILD;
-}
-
 bool SessionControllerImpl::IsUserChild() const {
   if (!IsActiveUserSessionStarted())
     return false;
@@ -534,7 +525,7 @@
       return LoginStatus::LOCKED;
 
     case SessionState::LOGIN_SECONDARY:
-      // TODO: There is no LoginStatus for this.
+      // TODO(jamescook): There is no LoginStatus for this.
       return LoginStatus::USER;
   }
   NOTREACHED();
@@ -562,12 +553,11 @@
     case user_manager::USER_TYPE_ARC_KIOSK_APP:
       return LoginStatus::KIOSK_APP;
     case user_manager::USER_TYPE_ACTIVE_DIRECTORY:
-      // TODO: There is no LoginStatus for this.
+      // TODO(jamescook): There is no LoginStatus for this.
       return LoginStatus::USER;
     case user_manager::USER_TYPE_WEB_KIOSK_APP:
       return LoginStatus::KIOSK_APP;
     case user_manager::NUM_USER_TYPES:
-    case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
       // Avoid having a "default" case so the compiler catches new enum values.
       NOTREACHED();
       return LoginStatus::USER;
diff --git a/ash/session/session_controller_impl.h b/ash/session/session_controller_impl.h
index c660681..3efeb6fa 100644
--- a/ash/session/session_controller_impl.h
+++ b/ash/session/session_controller_impl.h
@@ -106,11 +106,6 @@
   // Gets the primary user session.
   const UserSession* GetPrimaryUserSession() const;
 
-  // Returns true if the current user is supervised: has deprecated legacy
-  // supervised account or kid account.
-  // TODO(crbug/1155729): Remove and replace all calls with IsUserChild().
-  bool IsUserChildOrDeprecatedSupervised() const;
-
   // Returns true if the current user is a child account.
   bool IsUserChild() const;
 
diff --git a/ash/session/session_controller_impl_unittest.cc b/ash/session/session_controller_impl_unittest.cc
index f656a2c..f4abed6 100644
--- a/ash/session/session_controller_impl_unittest.cc
+++ b/ash/session/session_controller_impl_unittest.cc
@@ -266,7 +266,7 @@
       {SessionState::LOGIN_PRIMARY, LoginStatus::NOT_LOGGED_IN},
       {SessionState::LOGGED_IN_NOT_ACTIVE, LoginStatus::NOT_LOGGED_IN},
       {SessionState::LOCKED, LoginStatus::LOCKED},
-      // TODO: Add LOGIN_SECONDARY if we added a status for it.
+      // TODO(jamescook): Add LOGIN_SECONDARY if we added a status for it.
   };
 
   SessionInfo info;
@@ -298,7 +298,8 @@
       {user_manager::USER_TYPE_CHILD, LoginStatus::CHILD},
       {user_manager::USER_TYPE_ARC_KIOSK_APP, LoginStatus::KIOSK_APP},
       {user_manager::USER_TYPE_WEB_KIOSK_APP, LoginStatus::KIOSK_APP}
-      // TODO: Add USER_TYPE_ACTIVE_DIRECTORY if we add a status for it.
+      // TODO(jamescook): Add USER_TYPE_ACTIVE_DIRECTORY if we add a status for
+      // it.
   };
 
   for (const auto& test_case : kTestCases) {
@@ -414,9 +415,6 @@
   controller()->UpdateUserSession(session);
 
   EXPECT_TRUE(controller()->IsUserChild());
-
-  // Child accounts are supervised.
-  EXPECT_TRUE(controller()->IsUserChildOrDeprecatedSupervised());
 }
 
 using SessionControllerImplPrefsTest = NoSessionAshTestBase;
diff --git a/ash/strings/ash_strings_af.xtb b/ash/strings/ash_strings_af.xtb
index bd7ece3..09d93da 100644
--- a/ash/strings/ash_strings_af.xtb
+++ b/ash/strings/ash_strings_af.xtb
@@ -330,6 +330,7 @@
 <translation id="3595596368722241419">Battery is vol</translation>
 <translation id="3604801046548457007">Lessenaar <ph name="DESK_TITILE" /> is geskep</translation>
 <translation id="3606978283550408104">Braille-skerm gekoppel.</translation>
+<translation id="3615926715408477684">As mobiele data geaktiveer word, sal dit Bluetooth aktiveer</translation>
 <translation id="3616883743181209306">Kieslys is na die skerm se hoek regs bo geskuif.</translation>
 <translation id="3621202678540785336">Invoer</translation>
 <translation id="3621712662352432595">Oudio-instellings</translation>
@@ -553,6 +554,7 @@
 <translation id="5283198616748585639">Voeg 1 min. by</translation>
 <translation id="528468243742722775">Einde</translation>
 <translation id="5286194356314741248">Skandeer tans</translation>
+<translation id="5297423144044956168">Geen mobiele toestelle gekry nie</translation>
 <translation id="5297704307811127955">Af</translation>
 <translation id="5302048478445481009">Taal</translation>
 <translation id="5308380583665731573">Koppel</translation>
diff --git a/ash/strings/ash_strings_ja.xtb b/ash/strings/ash_strings_ja.xtb
index 44107b10..f4bb66a 100644
--- a/ash/strings/ash_strings_ja.xtb
+++ b/ash/strings/ash_strings_ja.xtb
@@ -330,6 +330,7 @@
 <translation id="3595596368722241419">バッテリー残量: フル</translation>
 <translation id="3604801046548457007">デスク <ph name="DESK_TITILE" /> が作成されました</translation>
 <translation id="3606978283550408104">ブライユ点字ディスプレイが接続されています。</translation>
+<translation id="3615926715408477684">モバイルデータ通信を有効にすると、Bluetooth も有効になります</translation>
 <translation id="3616883743181209306">メニューは画面右上に移動しました。</translation>
 <translation id="3621202678540785336">入力</translation>
 <translation id="3621712662352432595">オーディオ設定</translation>
@@ -552,6 +553,7 @@
 <translation id="5283198616748585639">1 分追加</translation>
 <translation id="528468243742722775">終了</translation>
 <translation id="5286194356314741248">スキャン中</translation>
+<translation id="5297423144044956168">モバイル デバイスが見つかりませんでした</translation>
 <translation id="5297704307811127955">オフ</translation>
 <translation id="5302048478445481009">言語</translation>
 <translation id="5308380583665731573">接続</translation>
diff --git a/ash/strings/ash_strings_mr.xtb b/ash/strings/ash_strings_mr.xtb
index 4b259e1..8e705ec8 100644
--- a/ash/strings/ash_strings_mr.xtb
+++ b/ash/strings/ash_strings_mr.xtb
@@ -207,6 +207,7 @@
 <translation id="2582112259361606227">अपडेट करण्यासाठी रीस्टार्ट करा</translation>
 <translation id="2595239820337756193">५००० मैल</translation>
 <translation id="2596078834055697711">विंडो स्क्रीनशॉट घ्या</translation>
+<translation id="2607678425161541573">ऑनलाइन साइन इन करणे आवश्यक आहे</translation>
 <translation id="2617342710774726426">सिम कार्ड लॉक केले आहे</translation>
 <translation id="2621713457727696555">सुरक्षित</translation>
 <translation id="2653019840645008922">विंडो कॅप्चर</translation>
diff --git a/ash/strings/ash_strings_si.xtb b/ash/strings/ash_strings_si.xtb
index 78f932a..f70adc3 100644
--- a/ash/strings/ash_strings_si.xtb
+++ b/ash/strings/ash_strings_si.xtb
@@ -330,6 +330,7 @@
 <translation id="3595596368722241419">බැටරිය ආරෝපිතයි</translation>
 <translation id="3604801046548457007"><ph name="DESK_TITILE" /> මේසය සාදන ලදි</translation>
 <translation id="3606978283550408104">බ්‍රේල් ප්‍රදර්ශකය සම්බන්ධ කර ඇත.</translation>
+<translation id="3615926715408477684">ජංගම දත්ත සබල කිරීම බ්ලූටූත් සබල කරනු ඇත</translation>
 <translation id="3616883743181209306">මෙනුව තිරයේ ඉහළ දකුණු කොණට ගෙන ගියා.</translation>
 <translation id="3621202678540785336">ආදානය</translation>
 <translation id="3621712662352432595">ශ්‍රව්‍ය සැකසුම්</translation>
@@ -552,6 +553,7 @@
 <translation id="5283198616748585639">1 විනාඩියක් එක් කරන්න</translation>
 <translation id="528468243742722775">අවසන් කරන්න</translation>
 <translation id="5286194356314741248">ස්කෑන් කිරීම</translation>
+<translation id="5297423144044956168">ජංගම උපාංග හමු නොවීය</translation>
 <translation id="5297704307811127955">අක්‍රියයි</translation>
 <translation id="5302048478445481009">භාෂාව</translation>
 <translation id="5308380583665731573">සම්බන්ධ කරන්න</translation>
diff --git a/ash/strings/ash_strings_sw.xtb b/ash/strings/ash_strings_sw.xtb
index 30b60a6c..6cd9bb1b 100644
--- a/ash/strings/ash_strings_sw.xtb
+++ b/ash/strings/ash_strings_sw.xtb
@@ -330,6 +330,7 @@
 <translation id="3595596368722241419">Betri imejaa</translation>
 <translation id="3604801046548457007">Kiolesura cha <ph name="DESK_TITILE" /> kimeanzishwa</translation>
 <translation id="3606978283550408104">Onyesho la breli limeunganishwa.</translation>
+<translation id="3615926715408477684">Hatua ya kuwasha data ya mtandao wa simu itawasha Bluetooth</translation>
 <translation id="3616883743181209306">Menyu imehamishiwa kwenye kona ya juu kulia mwa skrini.</translation>
 <translation id="3621202678540785336">Ingizo</translation>
 <translation id="3621712662352432595">Mipangilio ya Sauti</translation>
@@ -552,6 +553,7 @@
 <translation id="5283198616748585639">Ongeza dakika 1</translation>
 <translation id="528468243742722775">Mwisho</translation>
 <translation id="5286194356314741248">Inachanganua</translation>
+<translation id="5297423144044956168">Hakuna vifaa vya mkononi vilivyopatikana</translation>
 <translation id="5297704307811127955">Umezimwa</translation>
 <translation id="5302048478445481009">Lugha</translation>
 <translation id="5308380583665731573">Unganisha</translation>
diff --git a/ash/strings/ash_strings_uz.xtb b/ash/strings/ash_strings_uz.xtb
index 9ee94bb0..aa2e286 100644
--- a/ash/strings/ash_strings_uz.xtb
+++ b/ash/strings/ash_strings_uz.xtb
@@ -330,6 +330,7 @@
 <translation id="3595596368722241419">Batareya to‘ldi</translation>
 <translation id="3604801046548457007"><ph name="DESK_TITILE" /> ish stoli yaratildi</translation>
 <translation id="3606978283550408104">Brayl displeyi ulandi.</translation>
+<translation id="3615926715408477684">Mobil internet yoqilsa, Bluetooth ham birga yonadi</translation>
 <translation id="3616883743181209306">Menyu ekranning yuqori oʻng burchagiga surildi.</translation>
 <translation id="3621202678540785336">Kirish</translation>
 <translation id="3621712662352432595">Audio sozlamalari</translation>
@@ -552,6 +553,7 @@
 <translation id="5283198616748585639">1 daqiqa qoʻshish</translation>
 <translation id="528468243742722775">Tugatish</translation>
 <translation id="5286194356314741248">Qidiruv</translation>
+<translation id="5297423144044956168">Mobil qurilmalar topilmadi</translation>
 <translation id="5297704307811127955">Yoqilmagan</translation>
 <translation id="5302048478445481009">Til</translation>
 <translation id="5308380583665731573">Ulanish</translation>
diff --git a/ash/strings/ash_strings_zh-HK.xtb b/ash/strings/ash_strings_zh-HK.xtb
index d2ca707..a74980f 100644
--- a/ash/strings/ash_strings_zh-HK.xtb
+++ b/ash/strings/ash_strings_zh-HK.xtb
@@ -330,6 +330,7 @@
 <translation id="3595596368722241419">電池已滿</translation>
 <translation id="3604801046548457007">已建立桌面 <ph name="DESK_TITILE" /></translation>
 <translation id="3606978283550408104">已連接點字顯示器。</translation>
+<translation id="3615926715408477684">如果您啟用流動數據,藍牙亦會隨之開啟</translation>
 <translation id="3616883743181209306">已經將選單移去螢幕右上角。</translation>
 <translation id="3621202678540785336">輸入</translation>
 <translation id="3621712662352432595">音效檔案設定</translation>
@@ -551,6 +552,7 @@
 <translation id="5283198616748585639">增加 1 分鐘</translation>
 <translation id="528468243742722775">結束</translation>
 <translation id="5286194356314741248">掃描中</translation>
+<translation id="5297423144044956168">找不到流動裝置</translation>
 <translation id="5297704307811127955">已關閉</translation>
 <translation id="5302048478445481009">語言</translation>
 <translation id="5308380583665731573">連線</translation>
diff --git a/ash/system/bluetooth/bluetooth_power_controller.cc b/ash/system/bluetooth/bluetooth_power_controller.cc
index 6f1862f..0a14522 100644
--- a/ash/system/bluetooth/bluetooth_power_controller.cc
+++ b/ash/system/bluetooth/bluetooth_power_controller.cc
@@ -294,7 +294,6 @@
     user_manager::UserType user_type) const {
   return user_type == user_manager::USER_TYPE_REGULAR ||
          user_type == user_manager::USER_TYPE_CHILD ||
-         user_type == user_manager::USER_TYPE_SUPERVISED_DEPRECATED ||
          user_type == user_manager::USER_TYPE_ACTIVE_DIRECTORY;
 }
 
diff --git a/ash/system/unified/unified_system_info_view.cc b/ash/system/unified/unified_system_info_view.cc
index 31624c7..4bcf125 100644
--- a/ash/system/unified/unified_system_info_view.cc
+++ b/ash/system/unified/unified_system_info_view.cc
@@ -421,8 +421,7 @@
     : ManagedStateView(PressedCallback(),
                        IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL,
                        GetSupervisedUserIcon()) {
-  bool visible =
-      Shell::Get()->session_controller()->IsUserChildOrDeprecatedSupervised();
+  bool visible = Shell::Get()->session_controller()->IsUserChild();
   SetVisible(visible);
   if (visible)
     SetTooltipText(GetSupervisedUserMessage());
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index ea7f4aa..5cebb2b 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -1479,7 +1479,6 @@
   // everything resets.
   user_manager::UserType active_user_type = active_user_session->user_info.type;
   return active_user_type == user_manager::USER_TYPE_REGULAR ||
-         active_user_type == user_manager::USER_TYPE_SUPERVISED_DEPRECATED ||
          active_user_type == user_manager::USER_TYPE_CHILD;
 }
 
@@ -2378,7 +2377,7 @@
     return;
   switch (info.type) {
     case CUSTOMIZED:
-      // TODO (b/180736877): Implement getting synced wallpaper image and
+      // TODO(b/180736877): Implement getting synced wallpaper image and
       // setting it as the wallpaper.
       NOTIMPLEMENTED();
       break;
diff --git a/base/sampling_heap_profiler/poisson_allocation_sampler.cc b/base/sampling_heap_profiler/poisson_allocation_sampler.cc
index 1b762fe..351010d 100644
--- a/base/sampling_heap_profiler/poisson_allocation_sampler.cc
+++ b/base/sampling_heap_profiler/poisson_allocation_sampler.cc
@@ -50,6 +50,10 @@
 
   operator bool() { return allowed_; }
 
+  // This function must be called in very early of the process start-up in
+  // order to acquire a low TLS slot number because glibc TLS implementation
+  // will require a malloc call to allocate storage for a higher slot number
+  // (>= PTHREAD_KEY_2NDLEVEL_SIZE == 32).  c.f. heap_profiling::InitTLSSlot.
   static void Init() {
     int error = pthread_key_create(&entered_key_, nullptr);
     CHECK(!error);
@@ -568,6 +572,12 @@
 }
 
 void PoissonAllocationSampler::AddSamplesObserver(SamplesObserver* observer) {
+  // The following implementation (including ScopedMuteThreadSamples) will use
+  // `thread_local`, which may cause a reentrancy issue.  So, temporarily
+  // disable the sampling by having a ReentryGuard.
+  ReentryGuard guard;
+  ignore_result(guard);
+
   ScopedMuteThreadSamples no_reentrancy_scope;
   AutoLock lock(mutex_);
   DCHECK(ranges::find(observers_, observer) == observers_.end());
@@ -578,6 +588,12 @@
 
 void PoissonAllocationSampler::RemoveSamplesObserver(
     SamplesObserver* observer) {
+  // The following implementation (including ScopedMuteThreadSamples) will use
+  // `thread_local`, which may cause a reentrancy issue.  So, temporarily
+  // disable the sampling by having a ReentryGuard.
+  ReentryGuard guard;
+  ignore_result(guard);
+
   ScopedMuteThreadSamples no_reentrancy_scope;
   AutoLock lock(mutex_);
   auto it = ranges::find(observers_, observer);
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index bf02854..c54b4e6 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -186,6 +186,9 @@
 class CronetPrefsManager;
 class CronetURLRequestContext;
 }  // namespace cronet
+namespace crosapi {
+class LacrosThreadPriorityDelegate;
+}  // namespace crosapi
 namespace dbus {
 class Bus;
 }
@@ -412,6 +415,7 @@
   friend class content::WebContentsViewMac;
   friend class cronet::CronetPrefsManager;
   friend class cronet::CronetURLRequestContext;
+  friend class crosapi::LacrosThreadPriorityDelegate;
   friend class memory_instrumentation::OSMetrics;
   friend class metrics::AndroidMetricsServiceClient;
   friend class module_installer::ScopedAllowModulePakLoad;
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 7bd1a33..622f815 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1839,147 +1839,96 @@
     }
   }
 
-  template("process_java_prebuilt") {
+  template("process_java_library") {
     forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
 
-    _rebased_build_config = rebase_path(invoker.build_config, root_build_dir)
-    not_needed([ "_rebased_build_config" ])
-
     _deps = invoker.jar_deps
     _previous_output_jar = invoker.input_jar_path
 
-    # Create the .jar in lib.java for use by java_binary.
-    if (defined(invoker.host_jar_path)) {
-      if (defined(invoker.jacoco_instrument) && invoker.jacoco_instrument) {
-        _filter_jar_target_name = "${target_name}_host__filter_jar"
-        _filter_jar_output_jar = "$target_out_dir/$target_name.host_filter.jar"
-      } else {
-        _filter_jar_target_name = "${target_name}_host"
-        _filter_jar_output_jar = invoker.host_jar_path
-      }
-      filter_jar(_filter_jar_target_name) {
-        forward_variables_from(invoker,
-                               [
-                                 "jar_excluded_patterns",
-                                 "jar_included_patterns",
-                               ])
-        deps = _deps
-        input_jar = _previous_output_jar
-        output_jar = _filter_jar_output_jar
-        inputs = []
-        if (defined(invoker.inputs)) {
-          inputs += invoker.inputs
-          deps += invoker.input_deps
+    if (invoker.is_device_jar && invoker.enable_desugar) {
+      _desugar_target = "${target_name}_device__desugar"
+      _desugar_output_jar = "$target_out_dir/$target_name.desugar.jar"
+
+      action_with_pydeps(_desugar_target) {
+        script = "//build/android/gyp/desugar.py"
+        deps = _deps + invoker.classpath_deps
+        depfile = "$target_gen_dir/$target_name.d"
+        _rebased_build_config =
+            rebase_path(invoker.build_config, root_build_dir)
+        _desugar_jar = "//third_party/bazel/desugar/Desugar.jar"
+
+        inputs = [
+          invoker.build_config,
+          _previous_output_jar,
+          _desugar_jar,
+        ]
+        outputs = [ _desugar_output_jar ]
+        args = [
+          "--desugar-jar",
+          rebase_path(_desugar_jar, root_build_dir),
+          "--input-jar",
+          rebase_path(_previous_output_jar, root_build_dir),
+          "--output-jar",
+          rebase_path(_desugar_output_jar, root_build_dir),
+
+          # Temporarily using java_full_interface_classpath until classpath validation of targets
+          # is implemented, see http://crbug.com/885273
+          "--classpath=@FileArg($_rebased_build_config:deps_info:javac_full_interface_classpath)",
+          "--bootclasspath=@FileArg($_rebased_build_config:android:sdk_interface_jars)",
+          "--depfile",
+          rebase_path(depfile, root_build_dir),
+        ]
+        if (defined(invoker.desugar_jars_paths)) {
+          _rebased_desugar_jars_paths =
+              rebase_path(invoker.desugar_jars_paths, root_build_dir)
+          args += [ "--classpath=${_rebased_desugar_jars_paths}" ]
+        }
+        if (treat_warnings_as_errors) {
+          args += [ "--warnings-as-errors" ]
         }
       }
 
-      if (defined(invoker.jacoco_instrument) && invoker.jacoco_instrument) {
-        # Jacoco must run after desugar (or else desugar sometimes fails).
-        # It must run after filtering to avoid the same (filtered) class mapping
-        # to multiple .jar files.
-        # We run offline code coverage processing here rather than with a
-        # javaagent as the desired coverage data was not being generated.
-        # See crbug.com/1097815.
-        jacoco_instr("${target_name}_host") {
-          deps = [ ":$_filter_jar_target_name" ] + invoker.jar_deps
-          forward_variables_from(invoker,
-                                 [
-                                   "java_files",
-                                   "java_sources_file",
-                                 ])
-
-          input_jar_path = _filter_jar_output_jar
-          output_jar_path = invoker.host_jar_path
-        }
-      }
+      _deps = []
+      _deps = [ ":$_desugar_target" ]
+      _previous_output_jar = _desugar_output_jar
     }
 
-    if (defined(invoker.device_jar_path)) {
-      if (invoker.enable_desugar) {
-        _desugar_target = "${target_name}_device__desugar"
-        _desugar_output_jar = "$target_out_dir/$target_name.desugar.jar"
+    if (invoker.jacoco_instrument) {
+      _filter_jar_target_name = "${target_name}__filter_jar"
+      _filter_jar_output_jar = "$target_out_dir/$target_name.filter.jar"
+    } else {
+      _filter_jar_target_name = target_name
+      _filter_jar_output_jar = invoker.output_jar_path
+    }
 
-        action_with_pydeps(_desugar_target) {
-          script = "//build/android/gyp/desugar.py"
-          deps = _deps + invoker.classpath_deps
-          depfile = "$target_gen_dir/$target_name.d"
-          _desugar_jar = "//third_party/bazel/desugar/Desugar.jar"
+    filter_jar(_filter_jar_target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "jar_excluded_patterns",
+                               "jar_included_patterns",
+                             ])
+      deps = _deps
+      input_jar = _previous_output_jar
+      output_jar = _filter_jar_output_jar
+    }
 
-          inputs = [
-            invoker.build_config,
-            _previous_output_jar,
-            _desugar_jar,
-          ]
-          outputs = [ _desugar_output_jar ]
-          args = [
-            "--desugar-jar",
-            rebase_path(_desugar_jar, root_build_dir),
-            "--input-jar",
-            rebase_path(_previous_output_jar, root_build_dir),
-            "--output-jar",
-            rebase_path(_desugar_output_jar, root_build_dir),
-
-            # Temporarily using java_full_interface_classpath until classpath validation of targets
-            # is implemented, see http://crbug.com/885273
-            "--classpath=@FileArg($_rebased_build_config:deps_info:javac_full_interface_classpath)",
-            "--bootclasspath=@FileArg($_rebased_build_config:android:sdk_interface_jars)",
-            "--depfile",
-            rebase_path(depfile, root_build_dir),
-          ]
-          if (defined(invoker.desugar_jars_paths)) {
-            _rebased_desugar_jars_paths =
-                rebase_path(invoker.desugar_jars_paths, root_build_dir)
-            args += [ "--classpath=${_rebased_desugar_jars_paths}" ]
-          }
-          if (treat_warnings_as_errors) {
-            args += [ "--warnings-as-errors" ]
-          }
-        }
-
-        _deps = []
-        _deps = [ ":$_desugar_target" ]
-        _previous_output_jar = _desugar_output_jar
-      }
-
-      if (invoker.jacoco_instrument) {
-        _filter_jar_target_name = "${target_name}_device__filter_jar"
-        _filter_jar_output_jar =
-            "$target_out_dir/$target_name.device_filter.jar"
-      } else {
-        _filter_jar_target_name = "${target_name}_device"
-        _filter_jar_output_jar = invoker.device_jar_path
-      }
-      filter_jar(_filter_jar_target_name) {
+    if (invoker.jacoco_instrument) {
+      # Jacoco must run after desugar (or else desugar sometimes fails).
+      # It must run after filtering to avoid the same (filtered) class mapping
+      # to multiple .jar files.
+      # We run offline code coverage processing here rather than with a
+      # javaagent as the desired coverage data was not being generated.
+      # See crbug.com/1097815.
+      jacoco_instr(target_name) {
+        deps = [ ":$_filter_jar_target_name" ] + invoker.jar_deps
         forward_variables_from(invoker,
                                [
-                                 "jar_excluded_patterns",
-                                 "jar_included_patterns",
+                                 "java_files",
+                                 "java_sources_file",
                                ])
-        deps = _deps
-        input_jar = _previous_output_jar
-        output_jar = _filter_jar_output_jar
-        inputs = []
-        if (!defined(invoker.host_jar_path) && defined(invoker.inputs)) {
-          inputs += invoker.inputs
-          deps += invoker.input_deps
-        }
-      }
 
-      if (invoker.jacoco_instrument) {
-        # Jacoco must run after desugar (or else desugar sometimes fails).
-        # It must run after filtering to avoid the same (filtered) class mapping
-        # to multiple .jar files.
-        jacoco_instr("${target_name}_device") {
-          deps = [ ":$_filter_jar_target_name" ] + invoker.jar_deps
-          forward_variables_from(invoker,
-                                 [
-                                   "java_files",
-                                   "java_sources_file",
-                                 ])
-
-          input_jar_path = _filter_jar_output_jar
-          output_jar_path = invoker.device_jar_path
-        }
+        input_jar_path = _filter_jar_output_jar
+        output_jar_path = invoker.output_jar_path
       }
     }
   }
@@ -3739,6 +3688,22 @@
 
     _public_deps = []
     _analysis_public_deps = []
+    _analysis_files = []
+
+    if (defined(invoker.proguard_configs)) {
+      assert(_build_host_jar || _build_device_jar)
+
+      # proguard_configs listed on java_library targets need to be marked
+      # as inputs to at least one action so that "gn analyze" will know
+      # about them. Although this target doesn't use them, it's a convenient spot
+      # to list them.
+      # https://crbug.com/827197
+      _analysis_files = invoker.proguard_configs
+      _analysis_public_deps =
+          _non_java_deps + _srcjar_deps  # For the aapt-generated
+                                         # proguard rules.
+    }
+
     if (_has_sources) {
       if (defined(invoker.enable_errorprone)) {
         _enable_errorprone = invoker.enable_errorprone
@@ -3933,51 +3898,6 @@
     }
 
     if (_build_host_jar || _build_device_jar) {
-      _process_prebuilt_target_name = "${target_name}__process"
-      process_java_prebuilt(_process_prebuilt_target_name) {
-        forward_variables_from(invoker,
-                               [
-                                 "jar_excluded_patterns",
-                                 "jar_included_patterns",
-                               ])
-        build_config = _build_config
-        input_jar_path = _unprocessed_jar_path
-        jar_deps = _unprocessed_jar_deps + _full_classpath_deps
-        if (_build_host_jar) {
-          host_jar_path = _host_processed_jar_path
-        }
-        if (_build_device_jar) {
-          device_jar_path = _device_processed_jar_path
-          jacoco_instrument = _jacoco_instrument
-          if (_jacoco_instrument) {
-            java_files = _java_files
-            java_sources_file = _java_sources_file
-          }
-          enable_desugar = _enable_desugar && _use_classic_desugar
-          if (enable_desugar) {
-            classpath_deps = _classpath_deps
-            forward_variables_from(invoker, [ "desugar_jars_paths" ])
-          }
-        }
-
-        # proguard_configs listed on java_library targets need to be marked
-        # as inputs to at least one action so that "gn analyze" will know
-        # about them. Although ijar doesn't use them, it's a convenient spot
-        # to list them.
-        # https://crbug.com/827197
-        if (defined(invoker.proguard_configs)) {
-          inputs = invoker.proguard_configs
-          input_deps = _non_java_deps + _srcjar_deps  # For the aapt-generated
-                                                      # proguard rules.
-        }
-      }
-      if (_build_host_jar) {
-        _public_deps += [ ":${_process_prebuilt_target_name}_host" ]
-      }
-      if (_build_device_jar) {
-        _public_deps += [ ":${_process_prebuilt_target_name}_device" ]
-      }
-
       _enable_bytecode_checks = !defined(invoker.enable_bytecode_checks) ||
                                 invoker.enable_bytecode_checks
       if (_enable_bytecode_checks) {
@@ -3995,37 +3915,83 @@
         }
         _analysis_public_deps += [ ":$_bytecode_checks_target" ]
       }
-    }
 
-    if (_build_device_jar) {
-      dex("${target_name}__dex") {
-        forward_variables_from(invoker,
-                               [
-                                 "desugar_jars_paths",
-                                 "proguard_enable_obfuscation",
-                                 "use_classic_desugar",
-                               ])
-        input_class_jars = [ _device_processed_jar_path ]
-        enable_desugar = _enable_desugar
-        ignore_desugar_missing_deps = !_enable_bytecode_checks
-
-        # There's no value in per-class dexing prebuilts since they never
-        # change just one class at a time.
-        disable_incremental = _is_prebuilt
-        output = _dex_path
-        deps = [ ":${_process_prebuilt_target_name}_device" ]
-
-        if (enable_desugar && !_use_classic_desugar) {
-          # Desugaring with D8 requires full classpath.
-          build_config = _build_config
-          final_ijar_path = _final_ijar_path
-          deps += _classpath_deps + [ ":$_header_target_name" ]
+      if (_build_host_jar) {
+        _process_host_jar_target_name = "${target_name}__process_host"
+        process_java_library(_process_host_jar_target_name) {
+          forward_variables_from(invoker,
+                                 [
+                                   "jar_excluded_patterns",
+                                   "jar_included_patterns",
+                                 ])
+          input_jar_path = _unprocessed_jar_path
+          jar_deps = _unprocessed_jar_deps + _full_classpath_deps
+          is_device_jar = false
+          output_jar_path = _host_processed_jar_path
+          jacoco_instrument = _jacoco_instrument
+          if (_jacoco_instrument) {
+            java_files = _java_files
+            java_sources_file = _java_sources_file
+          }
         }
-
-        enable_multidex = false
-        is_library = true
+        _public_deps += [ ":${_process_host_jar_target_name}" ]
       }
-      _public_deps += [ ":${target_name}__dex" ]
+
+      if (_build_device_jar) {
+        _process_device_jar_target_name = "${target_name}__process_device"
+        process_java_library(_process_device_jar_target_name) {
+          forward_variables_from(invoker,
+                                 [
+                                   "jar_excluded_patterns",
+                                   "jar_included_patterns",
+                                 ])
+          input_jar_path = _unprocessed_jar_path
+          jar_deps = _unprocessed_jar_deps + _full_classpath_deps
+          is_device_jar = true
+          output_jar_path = _device_processed_jar_path
+          jacoco_instrument = _jacoco_instrument
+          if (_jacoco_instrument) {
+            java_files = _java_files
+            java_sources_file = _java_sources_file
+          }
+          enable_desugar = _enable_desugar && _use_classic_desugar
+          if (enable_desugar) {
+            build_config = _build_config
+            classpath_deps = _classpath_deps
+            forward_variables_from(invoker, [ "desugar_jars_paths" ])
+          }
+        }
+        _public_deps += [ ":${_process_device_jar_target_name}" ]
+
+        dex("${target_name}__dex") {
+          forward_variables_from(invoker,
+                                 [
+                                   "desugar_jars_paths",
+                                   "proguard_enable_obfuscation",
+                                   "use_classic_desugar",
+                                 ])
+          input_class_jars = [ _device_processed_jar_path ]
+          enable_desugar = _enable_desugar
+          ignore_desugar_missing_deps = !_enable_bytecode_checks
+
+          # There's no value in per-class dexing prebuilts since they never
+          # change just one class at a time.
+          disable_incremental = _is_prebuilt
+          output = _dex_path
+          deps = [ ":${_process_device_jar_target_name}" ]
+
+          if (enable_desugar && !_use_classic_desugar) {
+            # Desugaring with D8 requires full classpath.
+            build_config = _build_config
+            final_ijar_path = _final_ijar_path
+            deps += _classpath_deps + [ ":$_header_target_name" ]
+          }
+
+          enable_multidex = false
+          is_library = true
+        }
+        _public_deps += [ ":${target_name}__dex" ]
+      }
     }
 
     if (_is_java_binary) {
@@ -4079,12 +4045,14 @@
         public_deps = []
       }
       public_deps += [ ":${target_name}__impl" ]
-      if (defined(_analysis_public_deps)) {
-        if (!defined(data_deps)) {
-          data_deps = []
-        }
-        data_deps += _analysis_public_deps
+      if (!defined(data)) {
+        data = []
       }
+      data += _analysis_files
+      if (!defined(data_deps)) {
+        data_deps = []
+      }
+      data_deps += _analysis_public_deps
     }
   }
 }
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 3537798a..8ce1002b 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -196,7 +196,7 @@
   # Set to true to use lld, the LLVM linker.
   # In late bring-up on macOS (see docs/mac_lld.md), and not functional at all for
   # iOS. The default linker everywhere else.
-  use_lld = is_clang && (!is_apple || (target_os == "mac" && chrome_pgo_phase != 1))
+  use_lld = is_clang && (!is_apple || (is_mac && chrome_pgo_phase != 1))
 }
 
 declare_args() {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index a1ca3c3..a2f380f 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-5.20210711.0.1
+5.20210712.0.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index a1ca3c3..a2f380f 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-5.20210711.0.1
+5.20210712.0.1
diff --git a/build/toolchain/apple/toolchain.gni b/build/toolchain/apple/toolchain.gni
index 50a968c..9e9c52c 100644
--- a/build/toolchain/apple/toolchain.gni
+++ b/build/toolchain/apple/toolchain.gni
@@ -83,6 +83,11 @@
     } else {
       toolchain_cc_wrapper = cc_wrapper
     }
+    if (defined(toolchain_args.use_lld)) {
+      toolchain_uses_lld = toolchain_args.use_lld
+    } else {
+      toolchain_uses_lld = use_lld
+    }
     if (defined(toolchain_args.use_xcode_clang)) {
       toolchain_uses_xcode_clang = toolchain_args.use_xcode_clang
     } else {
@@ -119,7 +124,7 @@
 
     # Set the explicit search path for clang++ so it uses the right linker
     # binary.
-    if (!use_lld) {
+    if (!toolchain_uses_lld) {
       ld += " -B " + invoker.bin_path
     }
 
@@ -244,7 +249,7 @@
     tool("alink") {
       rspfile = "{{output}}.rsp"
 
-      if (!use_lld) {
+      if (!toolchain_uses_lld) {
         # Note about -filelist: Apple's linker reads the file list file and
         # interprets each newline-separated chunk of text as a file name. It
         # doesn't do the things one would expect from the shell like unescaping
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn
index 1d0f2a2..70274fa 100644
--- a/build/toolchain/mac/BUILD.gn
+++ b/build/toolchain/mac/BUILD.gn
@@ -21,6 +21,9 @@
       current_os = "mac"
 
       if (target_os == "ios") {
+        # Use LLD for the host part of a chrome/ios build.
+        use_lld = true
+
         # TODO(crbug.com/753445): the use_sanitizer_coverage arg is currently
         # not supported by the Chromium mac_clang_x64 toolchain on iOS
         # distribution.
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index 7b13db34..8cacd48 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -51,7 +51,7 @@
 
   ContentLayerClient* client() { return picture_layer_inputs_.client; }
 
-  RecordingSource* GetRecordingSourceForTesting() {
+  RecordingSource* GetRecordingSourceForTesting() const {
     return recording_source_.get();
   }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 367fc78..2c6b136 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=93
 MINOR=0
-BUILD=4573
+BUILD=4574
 PATCH=0
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/MainIntentBehaviorMetricsIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/MainIntentBehaviorMetricsIntegrationTest.java
index 296982c..ee73306 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/MainIntentBehaviorMetricsIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/MainIntentBehaviorMetricsIntegrationTest.java
@@ -68,6 +68,7 @@
     }
 
     @MediumTest
+    @DisabledTest(message = "crbug.com/1225878")
     @Test
     public void testBackgroundDuration_24hrs() {
         assertBackgroundDurationLogged(
@@ -75,6 +76,7 @@
     }
 
     @MediumTest
+    @DisabledTest(message = "crbug.com/1225878")
     @Test
     public void testBackgroundDuration_12hrs() {
         assertBackgroundDurationLogged(
@@ -82,6 +84,7 @@
     }
 
     @MediumTest
+    @DisabledTest(message = "crbug.com/1225878")
     @Test
     public void testBackgroundDuration_6hrs() {
         assertBackgroundDurationLogged(
@@ -89,12 +92,14 @@
     }
 
     @MediumTest
+    @DisabledTest(message = "crbug.com/1225878")
     @Test
     public void testBackgroundDuration_1hr() {
         assertBackgroundDurationLogged(HOURS_IN_MS, "MobileStartup.MainIntentReceived.After1Hour");
     }
 
     @MediumTest
+    @DisabledTest(message = "crbug.com/1225878")
     @Test
     public void testBackgroundDuration_0hr() {
         assertBackgroundDurationLogged(0, null);
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 33a09dd..fedc66e 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-93.0.4571.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-93.0.4572.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 34582f09..6f11584 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5569,20 +5569,20 @@
     <message name="IDS_RESTORE_NOTIFICATION_RESTORE_BUTTON" desc="The restore button label of the notification for the user to select restore apps and pages on startup.">
       Restore
     </message>
-    <message name="IDS_SET_RESTORE_NOTIFICATION_BUTTON" desc="The button label of the notification for the user to set restore by default.">
-      Settings
-    </message>
     <message name="IDS_RESTORE_NOTIFICATION_CANCEL_BUTTON" desc="The cancel button label of the notification for the user to select not restore on startup.">
       No thanks
     </message>
     <message name="IDS_RESTORE_NOTIFICATION_TITLE" desc="This is the title of the notification for the user to select restore or not on startup.">
-      Restore apps &amp; pages?
+      Restore apps?
     </message>
-    <message name="IDS_SET_RESTORE_NOTIFICATION_TITLE" desc="This is the title of the notification for the user to set restore by default.">
-      Restore apps &amp; pages by default?
+    <message name="IDS_RESTORE_CRASH_NOTIFICATION_TITLE" desc="This is the title of the notification for the user to select restore or not on startup after crash.">
+      Your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> restarted unexpectedly
     </message>
-    <message name="IDS_RESTORE_NOTIFICATION_MESSAGE" desc="This is the text message of the notification for the user to select restore or not on startup if the 'restore_apps_and_pages' setting is 'Ask every time', and the system is not crashed before reboot.">
-      Continue where you left off.
+    <message name="IDS_RESTORE_NOTIFICATION_MESSAGE" desc="This is the text message of the notification for the user to select restore or not on startup if the 'restore_apps' setting is 'Ask every time', and the system is not crashed before reboot.">
+      Continue from where you left off. You can set apps to restore automatically in Settings.
+    </message>
+    <message name="IDS_RESTORE_CRASH_NOTIFICATION_MESSAGE" desc="This is the text message of the notification for the user to select restore or not on startup after crash.">
+      You can restore your previous apps
     </message>
   </if>
 
diff --git a/chrome/app/chromeos_strings_grdp/IDS_RESTORE_CRASH_NOTIFICATION_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_RESTORE_CRASH_NOTIFICATION_MESSAGE.png.sha1
new file mode 100644
index 0000000..464ea035
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_RESTORE_CRASH_NOTIFICATION_MESSAGE.png.sha1
@@ -0,0 +1 @@
+f0fe1ec1affd8a7f9d89d2c60af54ce278f840ef
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_RESTORE_CRASH_NOTIFICATION_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_RESTORE_CRASH_NOTIFICATION_TITLE.png.sha1
new file mode 100644
index 0000000..464ea035
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_RESTORE_CRASH_NOTIFICATION_TITLE.png.sha1
@@ -0,0 +1 @@
+f0fe1ec1affd8a7f9d89d2c60af54ce278f840ef
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_RESTORE_NOTIFICATION_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_RESTORE_NOTIFICATION_MESSAGE.png.sha1
index ed4c242..4644e8c 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_RESTORE_NOTIFICATION_MESSAGE.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_RESTORE_NOTIFICATION_MESSAGE.png.sha1
@@ -1 +1 @@
-69bf591cd5c98c716673498e022daf621f118cd2
\ No newline at end of file
+348f4887e4c7b3a1782f38416dd3b3ae7c51d8a4
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_RESTORE_NOTIFICATION_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_RESTORE_NOTIFICATION_TITLE.png.sha1
index 46075f4..4644e8c 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_RESTORE_NOTIFICATION_TITLE.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_RESTORE_NOTIFICATION_TITLE.png.sha1
@@ -1 +1 @@
-657acbf8f413bb610546b27dd5203a59f2b3c4f8
\ No newline at end of file
+348f4887e4c7b3a1782f38416dd3b3ae7c51d8a4
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_SET_RESTORE_NOTIFICATION_BUTTON.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_SET_RESTORE_NOTIFICATION_BUTTON.png.sha1
deleted file mode 100644
index 921f727..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_SET_RESTORE_NOTIFICATION_BUTTON.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-857fd7008ecb96b8ff900f229cb53803df36fcc2
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_SET_RESTORE_NOTIFICATION_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_SET_RESTORE_NOTIFICATION_TITLE.png.sha1
deleted file mode 100644
index 921f727..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_SET_RESTORE_NOTIFICATION_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-857fd7008ecb96b8ff900f229cb53803df36fcc2
\ No newline at end of file
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index b317ec3d..0711d03 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -1290,12 +1290,6 @@
         <message name="IDS_RESTORE_NOTIFICATION_DISPLAY_SOURCE" desc="This is the string shown as the display source of the notification for the user to select restore or not on startup.">
           Chromium OS system
         </message>
-        <message name="IDS_RESTORE_FOR_CRASH_NOTIFICATION_MESSAGE" desc="This is the text message of the notification for the user to select restore or not on startup after crash.">
-          Chromium OS didn't shut down correctly.
-        </message>
-        <message name="IDS_SET_RESTORE_NOTIFICATION_MESSAGE" desc="This is the text message of the notification for the user to set restore by default.">
-          Chromium OS can always restore your apps &amp; pages after reboot without asking every time.
-        </message>
       </if>
 
       <!-- ChromeLabs bubble -->
diff --git a/chrome/app/chromium_strings_grd/IDS_RESTORE_FOR_CRASH_NOTIFICATION_MESSAGE.png.sha1 b/chrome/app/chromium_strings_grd/IDS_RESTORE_FOR_CRASH_NOTIFICATION_MESSAGE.png.sha1
deleted file mode 100644
index 3b74886..0000000
--- a/chrome/app/chromium_strings_grd/IDS_RESTORE_FOR_CRASH_NOTIFICATION_MESSAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-63cab9675eb6764fe65fc2b89c3002538d76dba2
\ No newline at end of file
diff --git a/chrome/app/chromium_strings_grd/IDS_SET_RESTORE_NOTIFICATION_MESSAGE.png.sha1 b/chrome/app/chromium_strings_grd/IDS_SET_RESTORE_NOTIFICATION_MESSAGE.png.sha1
deleted file mode 100644
index b22c33b3..0000000
--- a/chrome/app/chromium_strings_grd/IDS_SET_RESTORE_NOTIFICATION_MESSAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b0d1616fde28e22e3e6a58bcc3249e4d60135ba2
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 0ef0a41..b087e2c 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2498,29 +2498,6 @@
         Open as tabbed window
       </message>
 
-      <!-- WebApp name/icon update dialog -->
-      <message name="IDS_WEBAPP_UPDATE_DIALOG_TITLE_NAME" desc="The title at the top of the dialog when only the name changed.">
-        Review name updates
-      </message>
-      <message name="IDS_WEBAPP_UPDATE_DIALOG_TITLE_ICON" desc="The title at the top of the dialog when only the icon changed.">
-        Review icon updates
-      </message>
-      <message name="IDS_WEBAPP_UPDATE_DIALOG_TITLE_NAME_AND_ICON" desc="The title at the top of the dialog when the name and icon changed.">
-        Review name &amp; icon updates
-      </message>
-      <message name="IDS_WEBAPP_UPDATE_EXPLANATION" desc="The text at the top of the dialog, explaining what to do when an app changes its identity.">
-        If this web app is trying to trick you into thinking it is a different app, uninstall it.
-      </message>
-      <message name="IDS_WEBAPP_UPDATE_NEGATIVE_BUTTON" desc="The text for the negative button (aka. cancel button), allowing the user to uninstall the app and report it to the abuse team.">
-        Uninstall app
-      </message>
-      <message name="IDS_UPDATE_WEBAPP_CURRENT_ICON" desc="The accessibility string explaining which icon is the current icon.">
-        Current icon
-      </message>
-      <message name="IDS_UPDATE_WEBAPP_UPDATED_ICON" desc="The accessibility string explaining which icon is the new icon.">
-        New icon
-      </message>
-
       <!-- Finish policy app installation dialog -->
       <message name="IDS_FINISH_POLICY_WEB_APP_INSTALLATION" desc="Main text for the Finish Policy Web App Installation dialog. This is a dialog message that appears on the first launch of an app after it was remotely installed by an enterprise administrator. The app has some cosmetic factors (like the app icon) that can only be fixed if the user launches and then restarts the app. After the initial launch, this dialog encourages users to restart the app to complete the installation.">
           This app was added by your organization. Restart the app to finish installing it.
diff --git a/chrome/app/generated_resources_grd/IDS_UPDATE_WEBAPP_CURRENT_ICON.png.sha1 b/chrome/app/generated_resources_grd/IDS_UPDATE_WEBAPP_CURRENT_ICON.png.sha1
deleted file mode 100644
index 0860acb..0000000
--- a/chrome/app/generated_resources_grd/IDS_UPDATE_WEBAPP_CURRENT_ICON.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-70a25cf918959e716c27dbc0652d1ad6b400f6d6
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_UPDATE_WEBAPP_UPDATED_ICON.png.sha1 b/chrome/app/generated_resources_grd/IDS_UPDATE_WEBAPP_UPDATED_ICON.png.sha1
deleted file mode 100644
index 0860acb..0000000
--- a/chrome/app/generated_resources_grd/IDS_UPDATE_WEBAPP_UPDATED_ICON.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-70a25cf918959e716c27dbc0652d1ad6b400f6d6
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_DIALOG_TITLE_ICON.png.sha1 b/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_DIALOG_TITLE_ICON.png.sha1
deleted file mode 100644
index 046d794..0000000
--- a/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_DIALOG_TITLE_ICON.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-89752956d6c66d449c7d8eac2d5ac76f63acf9a3
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_DIALOG_TITLE_NAME.png.sha1 b/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_DIALOG_TITLE_NAME.png.sha1
deleted file mode 100644
index ad7cad5..0000000
--- a/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_DIALOG_TITLE_NAME.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-bc9dfc7931813a2e3cc421a343331e197dfb85f9
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_DIALOG_TITLE_NAME_AND_ICON.png.sha1 b/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_DIALOG_TITLE_NAME_AND_ICON.png.sha1
deleted file mode 100644
index 0860acb..0000000
--- a/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_DIALOG_TITLE_NAME_AND_ICON.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-70a25cf918959e716c27dbc0652d1ad6b400f6d6
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_EXPLANATION.png.sha1 b/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_EXPLANATION.png.sha1
deleted file mode 100644
index 0860acb..0000000
--- a/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_EXPLANATION.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-70a25cf918959e716c27dbc0652d1ad6b400f6d6
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_NEGATIVE_BUTTON.png.sha1 b/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_NEGATIVE_BUTTON.png.sha1
deleted file mode 100644
index 0860acb..0000000
--- a/chrome/app/generated_resources_grd/IDS_WEBAPP_UPDATE_NEGATIVE_BUTTON.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-70a25cf918959e716c27dbc0652d1ad6b400f6d6
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 52a015f..c0b1747 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -1307,12 +1307,6 @@
         <message name="IDS_RESTORE_NOTIFICATION_DISPLAY_SOURCE" desc="This is the string shown as the display source of the notification for the user to select restore or not on startup.">
           Chrome OS system
         </message>
-        <message name="IDS_RESTORE_FOR_CRASH_NOTIFICATION_MESSAGE" desc="This is the text message of the notification for the user to select restore or not on startup after crash.">
-          Chrome OS didn't shut down correctly.
-        </message>
-        <message name="IDS_SET_RESTORE_NOTIFICATION_MESSAGE" desc="This is the text message of the notification for the user to set restore by default.">
-          Chrome OS can always restore your apps &amp; pages after reboot without asking every time.
-        </message>
       </if>
 
       <!-- ChromeLabs bubble -->
diff --git a/chrome/app/google_chrome_strings_grd/IDS_RESTORE_FOR_CRASH_NOTIFICATION_MESSAGE.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_RESTORE_FOR_CRASH_NOTIFICATION_MESSAGE.png.sha1
deleted file mode 100644
index 46075f4..0000000
--- a/chrome/app/google_chrome_strings_grd/IDS_RESTORE_FOR_CRASH_NOTIFICATION_MESSAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-657acbf8f413bb610546b27dd5203a59f2b3c4f8
\ No newline at end of file
diff --git a/chrome/app/google_chrome_strings_grd/IDS_SET_RESTORE_NOTIFICATION_MESSAGE.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_SET_RESTORE_NOTIFICATION_MESSAGE.png.sha1
deleted file mode 100644
index 921f727..0000000
--- a/chrome/app/google_chrome_strings_grd/IDS_SET_RESTORE_NOTIFICATION_MESSAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-857fd7008ecb96b8ff900f229cb53803df36fcc2
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index 2d95950f..395f893 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -405,6 +405,12 @@
   <message name="IDS_OS_SETTINGS_LANGUAGES_SPELL_CHECK_TITLE" desc="Title for the section containing all the options for spell check settings. The options include picking between using the system's spell check or using Google's web service and a list of the enabled languages which support spell checking.">
     Spell check
   </message>
+  <message name="IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_TITLE" desc="Title for the section containing all the options for spell and grammar check settings. The options include a list of the enabled languages which support spell checking.">
+    Spelling and grammar check
+  </message>
+  <message name="IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_DESCRIPTION" desc="Description for the spell and grammar check section.">
+    Grammar check currently avaiable for English only
+  </message>
   <message name="IDS_OS_SETTINGS_LANGUAGES_SPELL_CHECK_ENHANCED_LABEL" desc="Label for enhanced spell check toggle, the type of spell check that sends the text the user types to Google spelling service. It is important that it is communicated that the text the user types will be sent to Google.">
     Enhanced spell check in Chrome browser (text is sent to Google for spelling suggestions)
   </message>
@@ -3916,7 +3922,7 @@
     Ask every time
   </message>
   <message name="IDS_OS_SETTINGS_ON_STARTUP_DO_NOT_RESTORE" desc="Label for the dropdown menu which enables the do not restore option, which means not restore apps or pages on startup.">
-    Never restore
+    Off
   </message>
 </if>
 </grit-part>
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..d82ea3e
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+a5ace9187cf3c524e7e72add4989ea00d06492f1
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_TITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_TITLE.png.sha1
new file mode 100644
index 0000000..d82ea3e
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_TITLE.png.sha1
@@ -0,0 +1 @@
+a5ace9187cf3c524e7e72add4989ea00d06492f1
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_ON_STARTUP_DO_NOT_RESTORE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_ON_STARTUP_DO_NOT_RESTORE.png.sha1
index 50506e9b..da7620c3 100644
--- a/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_ON_STARTUP_DO_NOT_RESTORE.png.sha1
+++ b/chrome/app/os_settings_strings_grdp/IDS_OS_SETTINGS_ON_STARTUP_DO_NOT_RESTORE.png.sha1
@@ -1 +1 @@
-67319cff5fc3d20ae53fa29c416bd80bf0073860
\ No newline at end of file
+04b69566942265ebfd6f8458472b11ada0590c7e
\ No newline at end of file
diff --git a/chrome/app/resources/generated_resources_af.xtb b/chrome/app/resources/generated_resources_af.xtb
index 209d8873..d251d77e 100644
--- a/chrome/app/resources/generated_resources_af.xtb
+++ b/chrome/app/resources/generated_resources_af.xtb
@@ -2072,6 +2072,7 @@
 <translation id="3192947282887913208">Oudiolêers</translation>
 <translation id="3197453258332670132">Wys verwante inligting vir jou tekskeuse met 'n regsklik of langdruk</translation>
 <translation id="3199127022143353223">Bedieners</translation>
+<translation id="3200061262156232574">In jou inkopiemandjie</translation>
 <translation id="3201422919974259695">Beskikbare USB-toestelle sal hier verskyn.</translation>
 <translation id="3202131003361292969">Pad</translation>
 <translation id="3202173864863109533">Hierdie oortjie se klank word gedemp.</translation>
@@ -3004,6 +3005,7 @@
 <translation id="42126664696688958">Voer uit</translation>
 <translation id="42137655013211669">Toegang tot hierdie hulpbron is deur die bediener verbied.</translation>
 <translation id="4217571870635786043">Diktee</translation>
+<translation id="4219558185499589032">Boks</translation>
 <translation id="4220648711404560261">Kon nie aktiveer nie.</translation>
 <translation id="4222772810963087151">Boubesonderhede</translation>
 <translation id="4225020013797061859">Druk 'n skakelaar of sleutel om "<ph name="ACTION" />" toe te wys</translation>
@@ -4298,6 +4300,7 @@
 <translation id="5677503058916217575">Bladsytaal:</translation>
 <translation id="5677928146339483299">Geblokkeer</translation>
 <translation id="5678550637669481956">Lees- en skryftoegang tot <ph name="VOLUME_NAME" /> is toegestaan.</translation>
+<translation id="5678821117681811450">Stuur tans aan <ph name="WEB_DRIVE" /></translation>
 <translation id="5678955352098267522">Lees jou data op <ph name="WEBSITE_1" /></translation>
 <translation id="5680050361008726776">Verwyder "<ph name="ESIM_PROFILE_NAME" />"?</translation>
 <translation id="5683806393796685434">Voer asseblief jou aktiveringkode in</translation>
@@ -4757,6 +4760,7 @@
 <translation id="6207200176136643843">Stel terug na verstek-zoemvlak</translation>
 <translation id="6207937957461833379">Land/Streek</translation>
 <translation id="6208521041562685716">Mobiele data word tans geaktiveer</translation>
+<translation id="6208725777148613371">Kon nie in <ph name="WEB_DRIVE" /> stoor nie – <ph name="INTERRUPT_REASON" /></translation>
 <translation id="6209838773933913227">Komponentopdatering</translation>
 <translation id="6209908325007204267">Jou toestel sluit 'n Chrome Enterprise-opgradering in, maar jou gebruikernaam word nie met 'n ondernemingrekening geassosieer nie. Skep asseblief 'n ondernemingrekening deur g.co/ChromeEnterpriseAccount op 'n sekondêre toestel te besoek.</translation>
 <translation id="6212039847102026977">Wys gevorderde netwerkeienskappe</translation>
@@ -5752,6 +5756,7 @@
 <translation id="7326004502692201767">Stel hierdie <ph name="DEVICE_TYPE" /> vir 'n kind op</translation>
 <translation id="7326025035243649350">Wil jy ChromeVox, Chrome-bedryfstelsel se ingeboude skermleser, aktiveer?</translation>
 <translation id="7327989755579928735"><ph name="MANAGER" /> het ADB-ontfouting gedeaktiveer. Jy sal nie programme direk kan laai nadat jy jou <ph name="DEVICE_TYPE" /> herbegin het nie.</translation>
+<translation id="7328119182036084494">Gestoor in <ph name="WEB_DRIVE" /></translation>
 <translation id="7328867076235380839">Ongeldige kombinasie</translation>
 <translation id="7329154610228416156">Kon nie aanmeld nie omdat dit opgestel is om 'n onveilige URL (<ph name="BLOCKED_URL" />) te gebruik. Kontak jou administrateur.</translation>
 <translation id="7332053360324989309">Toegewyde werker: <ph name="SCRIPT_URL" /></translation>
@@ -6640,6 +6645,7 @@
 <translation id="8235418492073272647">Bladsy vanaf <ph name="DEVICE_NAME" /> gedeel</translation>
 <translation id="8236911020904880539">gaan uit</translation>
 <translation id="8236917170563564587">Deel eerder hierdie oortjie</translation>
+<translation id="8237471930911823556"><ph name="APP_NAME" /> is gestel om in 'n nuwe blaaieroortjie oop te maak; gesteunde skakels sal ook in die blaaier oopmaak.</translation>
 <translation id="8237647586961940482">Donkerpienk en rooi</translation>
 <translation id="8239032431519548577">Onderneminginskrywing is voltooi</translation>
 <translation id="8239932336306009582">Mag nie kennisgewings stuur nie</translation>
@@ -7176,6 +7182,7 @@
 <translation id="8835786707922974220">Maak seker dat jy altyd toegang tot jou gestoorde wagwoorde het</translation>
 <translation id="8836360711089151515"><ph name="MANAGER" /> vereis dat jy jou data rugsteun en hierdie <ph name="DEVICE_TYPE" /> binne 1 week terugstuur. <ph name="LINK_BEGIN" />Sien besonderhede<ph name="LINK_END" /></translation>
 <translation id="8836782447513334597">gaan voort</translation>
+<translation id="8838234842677265403"><ph name="WEB_DRIVE_MESSAGE" /> (<ph name="SUPPORT_INFO" />)</translation>
 <translation id="8838601485495657486">Ondeursigtig</translation>
 <translation id="8838770651474809439">Hamburger</translation>
 <translation id="883911313571074303">Maak aantekening by prent</translation>
diff --git a/chrome/app/resources/generated_resources_ja.xtb b/chrome/app/resources/generated_resources_ja.xtb
index d9bf542b..5d64849 100644
--- a/chrome/app/resources/generated_resources_ja.xtb
+++ b/chrome/app/resources/generated_resources_ja.xtb
@@ -2057,6 +2057,7 @@
 <translation id="3192947282887913208">音声ファイル</translation>
 <translation id="3197453258332670132">右クリックするか長押しすると、選択したテキストに関連する情報が表示されます</translation>
 <translation id="3199127022143353223">サーバー</translation>
+<translation id="3200061262156232574">ショッピング カートの商品</translation>
 <translation id="3201422919974259695">使用可能な USB デバイスがここに表示されます。</translation>
 <translation id="3202131003361292969">パス</translation>
 <translation id="3202173864863109533">このタブの音声はミュートされています。</translation>
@@ -2989,6 +2990,7 @@
 <translation id="42126664696688958">エクスポート</translation>
 <translation id="42137655013211669">このリソースへのアクセスはサーバーにより禁止されています。</translation>
 <translation id="4217571870635786043">音声入力</translation>
+<translation id="4219558185499589032">ボックス</translation>
 <translation id="4220648711404560261">有効化中にエラーが発生しました。</translation>
 <translation id="4222772810963087151">ビルドの詳細</translation>
 <translation id="4225020013797061859">「<ph name="ACTION" />」を割り当てるスイッチまたはキーを押してください</translation>
@@ -4281,6 +4283,7 @@
 <translation id="5677503058916217575">ページの言語:</translation>
 <translation id="5677928146339483299">ブロック中</translation>
 <translation id="5678550637669481956"><ph name="VOLUME_NAME" /> への読み書きのアクセス権が許可されました。</translation>
+<translation id="5678821117681811450"><ph name="WEB_DRIVE" /> に送信しています</translation>
 <translation id="5678955352098267522"><ph name="WEBSITE_1" /> でのユーザーデータの読み取り</translation>
 <translation id="5680050361008726776">「<ph name="ESIM_PROFILE_NAME" />」を削除しますか?</translation>
 <translation id="5683806393796685434">アクティベーション コードを入力してください</translation>
@@ -4740,6 +4743,7 @@
 <translation id="6207200176136643843">リセットしてデフォルトのズームレベルに戻す</translation>
 <translation id="6207937957461833379">国/地域</translation>
 <translation id="6208521041562685716">モバイルデータを有効化しています</translation>
+<translation id="6208725777148613371"><ph name="WEB_DRIVE" /> に保存できませんでした - <ph name="INTERRUPT_REASON" /></translation>
 <translation id="6209838773933913227">コンポーネントを更新しています</translation>
 <translation id="6209908325007204267">デバイスには Chrome Enterprise Upgrade が含まれていますが、ユーザー名が Enterprise アカウントに関連付けられていません。サブデバイスで g.co/ChromeEnterpriseAccount にアクセスし、Enterprise アカウントを作成してください。</translation>
 <translation id="6212039847102026977">ネットワークの詳細プロパティを表示</translation>
@@ -5735,6 +5739,7 @@
 <translation id="7326004502692201767">この <ph name="DEVICE_TYPE" /> をお子様向けに設定する</translation>
 <translation id="7326025035243649350">ChromeVox を有効にしますか?ChromeVox は Chrome OS 向けの組み込みのスクリーン リーダーです。</translation>
 <translation id="7327989755579928735"><ph name="MANAGER" /> により ADB デバッグが無効になりました。<ph name="DEVICE_TYPE" /> を再起動すると、アプリをサイドローディングできなくなります。</translation>
+<translation id="7328119182036084494"><ph name="WEB_DRIVE" /> に保存しました</translation>
 <translation id="7328867076235380839">無効な組み合わせです</translation>
 <translation id="7329154610228416156">保護されていない URL(<ph name="BLOCKED_URL" />)を使用するよう設定されているため、ログインできませんでした。管理者にお問い合わせください。</translation>
 <translation id="7332053360324989309">専用ワーカー: <ph name="SCRIPT_URL" /></translation>
@@ -6623,6 +6628,7 @@
 <translation id="8235418492073272647"><ph name="DEVICE_NAME" /> から共有されたページ</translation>
 <translation id="8236911020904880539">終了する</translation>
 <translation id="8236917170563564587">代わりにこのタブを共有</translation>
+<translation id="8237471930911823556"><ph name="APP_NAME" /> は新しいブラウザタブで開くよう設定されています。サポートされているリンクもブラウザで開かれます。</translation>
 <translation id="8237647586961940482">暗いピンクと赤</translation>
 <translation id="8239032431519548577">企業の登録が完了しました</translation>
 <translation id="8239932336306009582">通知の送信を許可しないサイト</translation>
@@ -7159,6 +7165,7 @@
 <translation id="8835786707922974220">保存したパスワードに常にアクセスできるようにしてください</translation>
 <translation id="8836360711089151515"><ph name="MANAGER" /> が、データをバックアップして、1 週間以内にこの <ph name="DEVICE_TYPE" /> を返却するよう求めています。<ph name="LINK_BEGIN" />詳細を表示<ph name="LINK_END" /></translation>
 <translation id="8836782447513334597">続行する</translation>
+<translation id="8838234842677265403"><ph name="WEB_DRIVE_MESSAGE" />(<ph name="SUPPORT_INFO" />)</translation>
 <translation id="8838601485495657486">不透明</translation>
 <translation id="8838770651474809439">ハンバーガー</translation>
 <translation id="883911313571074303">画像に注釈を付ける</translation>
diff --git a/chrome/app/resources/generated_resources_mr.xtb b/chrome/app/resources/generated_resources_mr.xtb
index 1be9d4b..37c0d26 100644
--- a/chrome/app/resources/generated_resources_mr.xtb
+++ b/chrome/app/resources/generated_resources_mr.xtb
@@ -4390,6 +4390,7 @@
 <translation id="5794700615121138172">Linux ने शेअर केलेले फोल्डर</translation>
 <translation id="5794786537412027208">सर्व Chrome Apps मधून बाहेर पडा</translation>
 <translation id="5797070761912323120">शोध, जाहिरात आणि इतर Google सेवा पर्सनलाइझ करण्यासाठी Google कदाचित तुमच्या इतिहासाचा वापर करू शकते</translation>
+<translation id="5797521893972859201">सर्च बॉक्समधील इतिहासाच्या समावेशासह, इतिहास साफ करते</translation>
 <translation id="5798079537501238810">साइट पेमेंट हँडलर इंस्टॉल करू शकतात</translation>
 <translation id="579907812742603813">संरक्षित आशय</translation>
 <translation id="579915268381781820">तुमची सिक्युरिटी की काढून टाकली होती.</translation>
@@ -4473,6 +4474,7 @@
 <translation id="5900302528761731119">Google प्रोफाइल फोटो</translation>
 <translation id="590036993063074298">मिररिंगच्या गुणवत्तेचे तपशील</translation>
 <translation id="5901069264981746702">तुमचा फिंगरप्रिंट डेटा सुरक्षितपणे स्टोअर केला आहे आणि तो तुमच्या <ph name="DEVICE_TYPE" /> मध्येच राहील. <ph name="LINK_BEGIN" />अधिक जाणून घ्या<ph name="LINK_END" /></translation>
+<translation id="5901089233978050985">कॅप्चर करणाऱ्या टॅबवर स्विच करा</translation>
 <translation id="5901494423252125310">प्रिंटरचे दार उघडे आहे</translation>
 <translation id="5901630391730855834">पिवळा</translation>
 <translation id="5904614460720589786">कॉन्फिगरेशनच्या समस्येमुळे <ph name="APP_NAME" /> सेट करता आले नाही. कृपया तुमच्या अ‍ॅडमिनिस्ट्रेटरशी संपर्क साधा. एरर कोड: <ph name="ERROR_CODE" />.</translation>
@@ -4746,6 +4748,7 @@
 <translation id="6196854373336333322">"<ph name="EXTENSION_NAME" />" एक्स्टेंशनने तुमच्या प्रॉक्सी सेटिंग्जचे नियंत्रण घेतले आहे, याचा अर्थ हे तुम्ही ऑनलाइन करता ती कोणतीही गोष्ट बदलू शकते, खंडित करू शकते किंवा चोरून ऐकू शकते. हा बदल का झाला, याबद्दल तुम्ही खात्री नसल्यास, तुम्हाला कदाचित तो नको आहे.</translation>
 <translation id="6198102561359457428">साइन आउट करा नंतर पुन्हा साइन इन करा...</translation>
 <translation id="6198252989419008588">पिन बदला</translation>
+<translation id="6200047250927636406">फाइल काढून टाका</translation>
 <translation id="6202304368170870640">तुमच्या डिव्हाइसमध्ये साइन इन करण्यासाठी किंवा ते अनलॉक करण्यासाठी तुम्ही तुमचा पिन वापरू शकता.</translation>
 <translation id="6206311232642889873">इमेज कॉ&amp;पी करा</translation>
 <translation id="6207200176136643843">झूम स्तर डीफॉल्टवर रीसेट करा</translation>
@@ -5313,6 +5316,7 @@
 <translation id="6831043979455480757">Translate</translation>
 <translation id="6833479554815567477">टॅब गट <ph name="GROUP_NAME" /> - <ph name="GROUP_CONTENTS" /> यामधून काढून टाकला आहे</translation>
 <translation id="683373380308365518">स्मार्ट आणि सुरक्षित ब्राउझरवर बदला</translation>
+<translation id="6834652994408928492">सूर्यास्ताच्या वेळी गडद मोड आपोआप सुरू होईल</translation>
 <translation id="683540480453879381"><ph name="FILE_EXTENSIONS" /> फाइल उघडा</translation>
 <translation id="6835762382653651563">कृपया तुमचे <ph name="DEVICE_TYPE" /> अपडेट करण्‍यासाठी इंटरनेटशी कनेक्ट करा.</translation>
 <translation id="6838034009068684089">साइटला तुमच्या स्क्रीनवर विंडो उघडायच्या आणि ठेवायच्या असतील तेव्हा विचारा (शिफारस केलेले)</translation>
@@ -6026,6 +6030,7 @@
 <translation id="7622114377921274169">चार्ज होत आहे.</translation>
 <translation id="7622768823216805500">आणखी सोपे चेकआउट यासारख्या खरेदी वैशिष्ट्यांसाठी साइट सामान्यपणे पेमेंट हँडलर इंस्टॉल करतात</translation>
 <translation id="7622903810087708234">पासवर्डचे तपशील</translation>
+<translation id="7622966771025050155">कॅप्चर केलेल्या टॅबवर स्विच करा</translation>
 <translation id="7624337243375417909">कॅप्सलॉक बंद आहे</translation>
 <translation id="7625568159987162309">परवानग्या आणि साइटवर स्टोअर केलेला डेटा पहा</translation>
 <translation id="7628201176665550262">रिफ्रेश रेट</translation>
@@ -6192,6 +6197,7 @@
 <translation id="7784067724422331729">तुमच्या कॉंप्युटरवरील सुरक्षितता सेटिंग्जने ही फाइल ब्लॉक केली.</translation>
 <translation id="7784796923038949829">साइटचा डेटा रीड करू किंवा बदलू शकत नाही</translation>
 <translation id="778480864305029524">इंस्टंट टेदरिंग वापरण्यासाठी, Google Play सेवा च्या सूचना सुरू करा.</translation>
+<translation id="7785471469930192436">लागू असल्यास, तुमचा शोध इतिहास हटवण्यासाठी तुमच्या शोध इंजीनच्या सूचना पहा</translation>
 <translation id="7786889348652477777">&amp;अ‍ॅप रीलोड करा</translation>
 <translation id="7787308148023287649">दुसऱ्या स्क्रीनवर डिस्प्ले करा</translation>
 <translation id="7788298548579301890">तुमच्या कॉंप्युटरवरील दुसर्‍या प्रोग्रामने एक अ‍ॅप जोडला जो Chrome ची काम करण्‍याची पद्धत कदाचित बदलू शकतो.
@@ -6802,6 +6808,7 @@
 <translation id="8438566539970814960">शोध आणि ब्राउझ करणे चांगले करा</translation>
 <translation id="8439506636278576865">या भाषेमध्ये पेज भाषांतरीत करण्यासाठी ऑफर</translation>
 <translation id="8440630305826533614">Linux ॲप्स</translation>
+<translation id="8446225304314102060"><ph name="TAB_ORIGIN" /> टॅबवर स्विच करा</translation>
 <translation id="8446884382197647889">अधिक जाणून घ्या</translation>
 <translation id="8447409163267621480">एकतर Ctrl किंवा Alt समाविष्‍ट करा</translation>
 <translation id="8448729345478502352">तुमच्या स्क्रीनवर आयटम लहान किंवा मोठे करा</translation>
@@ -7464,6 +7471,7 @@
 <translation id="9148058034647219655">निर्गमन</translation>
 <translation id="9148126808321036104">पुन्हा साइन इन करा </translation>
 <translation id="9148963623915467028">ही साइट तुमचे स्थान अ‍ॅक्सेस करू शकते.</translation>
+<translation id="9149529198050266366">सूर्योदयाच्या वेळी गडद मोड आपोआप बंद होईल</translation>
 <translation id="9149866541089851383">संपादन...</translation>
 <translation id="9150045010208374699">तुमचा कॅमेरा वापरा</translation>
 <translation id="9150079578948279438">प्रोफाइल काढून टाकता आली नाही. कृपया पुन्हा प्रयत्न करा किंवा तांत्रिक सपोर्टसाठी तुमच्या वाहकाशी संपर्क साधा.</translation>
diff --git a/chrome/app/resources/generated_resources_si.xtb b/chrome/app/resources/generated_resources_si.xtb
index 595a5a1..019db48 100644
--- a/chrome/app/resources/generated_resources_si.xtb
+++ b/chrome/app/resources/generated_resources_si.xtb
@@ -2060,6 +2060,7 @@
 <translation id="3192947282887913208">ශ්‍රව්‍ය ගොනුව</translation>
 <translation id="3197453258332670132">දකුණු-ක්ලික් කිරීමකින් හෝ දිගු එබුමකින්, ඔබගේ පෙළ තේරීම සඳහා අදාළ තතු පෙන්වන්න</translation>
 <translation id="3199127022143353223">සේවාදායක</translation>
+<translation id="3200061262156232574">ඔබගේ සාප්පු කරත්තය තුළ</translation>
 <translation id="3201422919974259695">ලද හැකි USB උපාංග මෙහි දිස් වෙති.</translation>
 <translation id="3202131003361292969">පෙත</translation>
 <translation id="3202173864863109533">මෙම ටැබයේ ශ්‍රව්‍යයන් නිහඬ කර ඇත.</translation>
@@ -2993,6 +2994,7 @@
 <translation id="42126664696688958">නිර්යාත කරන්න</translation>
 <translation id="42137655013211669">මෙම සම්පත වෙත ප්‍රවේශය සේවාදායකය විසින් තහනම් කර ඇත.</translation>
 <translation id="4217571870635786043">අනුලේඛනය</translation>
+<translation id="4219558185499589032">Box</translation>
 <translation id="4220648711404560261">ක්‍රියාත්මක කිරීමේදී දෝෂයක් සිදු විය.</translation>
 <translation id="4222772810963087151">නිමැවුම් විස්තර</translation>
 <translation id="4225020013797061859">"<ph name="ACTION" />" පැවරීමට ස්විචයක් හෝ යතුරක් ඔබන්න</translation>
@@ -4286,6 +4288,7 @@
 <translation id="5677503058916217575">පිටුවේ භාෂාව:</translation>
 <translation id="5677928146339483299">බාධාකළ</translation>
 <translation id="5678550637669481956"><ph name="VOLUME_NAME" /> වෙත කියවීම් සහ ලිවීම් ප්‍රවේශය ලබා දී ඇත.</translation>
+<translation id="5678821117681811450"><ph name="WEB_DRIVE" /> වෙත යවමින්</translation>
 <translation id="5678955352098267522"><ph name="WEBSITE_1" /> හි ඔබගේ දත්ත කියවන්න</translation>
 <translation id="5680050361008726776">"<ph name="ESIM_PROFILE_NAME" />" ඉවත් කරන්නද?</translation>
 <translation id="5683806393796685434">කරුණාකර ඔබගේ සක්‍රිය කිරීමේ කේතය ඇතුළු කරන්න</translation>
@@ -4745,6 +4748,7 @@
 <translation id="6207200176136643843">පෙරනිමි විශාලන මට්ටමට යළි පිහිටුවන්න</translation>
 <translation id="6207937957461833379">රට/කලාපය:</translation>
 <translation id="6208521041562685716">ජංගම දත්ත ක්‍රියාත්මක කරනු ලැබේ</translation>
+<translation id="6208725777148613371"><ph name="WEB_DRIVE" /> - <ph name="INTERRUPT_REASON" /> වෙත සුරැකීම අසාර්ථක විය</translation>
 <translation id="6209838773933913227">සංඝටක යාවත්කාලීනය</translation>
 <translation id="6209908325007204267">ඔබේ උපාංගයට Chrome ව්‍යවසාය උත්ශ්‍රේණිගත කිරීමක් ඇතුළත් වේ, නමුත් ඔබේ පරිශීලක නම ව්‍යවසාය ගිණුමක් සමග ආශ්‍රිත නොවේ. ද්විතීයික උපාංගයක g.co/ChromeEnterpriseAccount කරා පිවිසීමෙන් ව්‍යවසාය ගිණුමක් සාදන්න.</translation>
 <translation id="6212039847102026977">උසස් ජාල ගුණාංග පෙන්වන්න</translation>
@@ -5738,6 +5742,7 @@
 <translation id="7326004502692201767">ළමයකු සඳහා මෙම <ph name="DEVICE_TYPE" /> පිහිටුවන්න</translation>
 <translation id="7326025035243649350">ඔබට Chrome OS සඳහා වන ආවේණික තිර කියවනය, ChromeVox සක්‍රිය කිරීමට අවශ්‍යද?</translation>
 <translation id="7327989755579928735"><ph name="MANAGER" /> ADB නිදොස් කිරීම අබල කර ඇත. ඔබ ඔබගේ <ph name="DEVICE_TYPE" /> යළි ආරම්භ කළ පසු, ඔබට යෙදුම් පැති පූරණය කිරීමට නොහැකි වනු ඇත.</translation>
+<translation id="7328119182036084494"><ph name="WEB_DRIVE" /> වෙත සුරකින ලදි</translation>
 <translation id="7328867076235380839">අවලංගු සංයෝජනයක්</translation>
 <translation id="7329154610228416156">එය ආරක්ෂිත නොවන URL (<ph name="BLOCKED_URL" />) එකක් භාවිත කිරීමට වින්‍යාස කර ඇති බැවින් පිරීම අසාර්ථක විය. කරුණාකර ඔබේ පරිපාලක අමතන්න.</translation>
 <translation id="7332053360324989309">කැප වූ සේවකයා: <ph name="SCRIPT_URL" /></translation>
@@ -6623,6 +6628,7 @@
 <translation id="8235418492073272647"><ph name="DEVICE_NAME" /> වෙතින් බෙදා ගත් පිටුව</translation>
 <translation id="8236911020904880539">පිටවන්න</translation>
 <translation id="8236917170563564587">ඒ වෙනුවට මෙම පටිත්ත බෙදා ගන්න</translation>
+<translation id="8237471930911823556"><ph name="APP_NAME" /> නව බ්‍රව්සර ටැබයක විවෘත කිරීමට සකසා ඇති අතර, සහාය දක්වන සබැඳි බ්‍රව්සරයේද විවෘත වනු ඇත.</translation>
 <translation id="8237647586961940482">තද රෝස සහ රතු</translation>
 <translation id="8239032431519548577">ව්‍යවසාය ලියාපදිංචිය සම්පූර්ණයි</translation>
 <translation id="8239932336306009582">දැනුම්දීම් යැවීමට ඉඩ නොදේ</translation>
@@ -7160,6 +7166,7 @@
 <translation id="8835786707922974220">ඔබට ඔබගේ සුරකින ලද මුරපදවලට සැම විට ප්‍රවේශ විය හැකි බවට සහතික කර ගන්න</translation>
 <translation id="8836360711089151515"><ph name="MANAGER" /> හට ඔබ ඔබගේ දත්ත උපස්ථ කර සති 1ක් තුළ <ph name="DEVICE_TYPE" /> ආපසු දීමට අවශ්‍යයි. <ph name="LINK_BEGIN" />විස්තර බලන්න<ph name="LINK_END" /></translation>
 <translation id="8836782447513334597">දිගටම කරගෙන යන්න</translation>
+<translation id="8838234842677265403"><ph name="WEB_DRIVE_MESSAGE" /> (<ph name="SUPPORT_INFO" />)</translation>
 <translation id="8838601485495657486">පාරාන්ධ</translation>
 <translation id="8838770651474809439">හැම්බර්ගර්</translation>
 <translation id="883911313571074303">රූපය අනුසටහන් කරන්න</translation>
diff --git a/chrome/app/resources/generated_resources_sw.xtb b/chrome/app/resources/generated_resources_sw.xtb
index e866842..d3ab90d 100644
--- a/chrome/app/resources/generated_resources_sw.xtb
+++ b/chrome/app/resources/generated_resources_sw.xtb
@@ -2068,6 +2068,7 @@
 <translation id="3192947282887913208">Faili za Sauti</translation>
 <translation id="3197453258332670132">Ukibofya kulia au ukibonyeza kwa muda mrefu, unaweza kuonyesha maelezo yanayohusiana na maandishi uliyoyachagua</translation>
 <translation id="3199127022143353223">Seva</translation>
+<translation id="3200061262156232574">Katika kikapu chako cha ununuzi</translation>
 <translation id="3201422919974259695">Vifaa vya USB vinavyopatikana vitaonekana hapa.</translation>
 <translation id="3202131003361292969">Njia</translation>
 <translation id="3202173864863109533">Sauti ya kichupo hiki inazimwa.</translation>
@@ -2998,6 +2999,7 @@
 <translation id="42126664696688958">Hamisha</translation>
 <translation id="42137655013211669">Idhini ya kufikia rasilimali hii ilizuiwa na seva.</translation>
 <translation id="4217571870635786043">Kuandika kwa kutamka</translation>
+<translation id="4219558185499589032">Box</translation>
 <translation id="4220648711404560261">Hitilafu imetokea wakati wa kuwasha mipangilio.</translation>
 <translation id="4222772810963087151">Maelezo ya Muundo</translation>
 <translation id="4225020013797061859">Bonyeza swichi au kitufe ili ukabidhi kitendo cha "<ph name="ACTION" />"</translation>
@@ -4291,6 +4293,7 @@
 <translation id="5677503058916217575">Lugha ya ukurasa:</translation>
 <translation id="5677928146339483299">Kumezuiwa</translation>
 <translation id="5678550637669481956">Idhini ya kufikia kusoma na kuandika kwenye <ph name="VOLUME_NAME" /> imeruhusiwa.</translation>
+<translation id="5678821117681811450">Inatumwa kwa <ph name="WEB_DRIVE" /></translation>
 <translation id="5678955352098267522">Soma data yako kwenye <ph name="WEBSITE_1" /></translation>
 <translation id="5680050361008726776">Ungependa kuondoa "<ph name="ESIM_PROFILE_NAME" />"?</translation>
 <translation id="5683806393796685434">Tafadhali weka msimbo wako wa kuanza kutumia</translation>
@@ -4750,6 +4753,7 @@
 <translation id="6207200176136643843">Rejesha kiwango cha kukuza kuwa chaguomsingi</translation>
 <translation id="6207937957461833379">Nchi/Eneo</translation>
 <translation id="6208521041562685716">Data ya mtandao wa simu inawashwa</translation>
+<translation id="6208725777148613371">Imeshindwa kuhifadhi kwenye <ph name="WEB_DRIVE" /> - <ph name="INTERRUPT_REASON" /></translation>
 <translation id="6209838773933913227">Inasasisha vipengele</translation>
 <translation id="6209908325007204267">Kifaa chako kina Chrome Enterprise Upgrade, lakini jina lako la mtumiaji halijahusishwa na akaunti ya biashara. Tafadhali fungua akaunti ya biashara kwa kutembelea g.co/ChromeEnterpriseAccount kwenye kifaa kingine.</translation>
 <translation id="6212039847102026977">Onyesha sifa za kina za mtandao</translation>
@@ -5745,6 +5749,7 @@
 <translation id="7326004502692201767">Weka mipangilio kwenye <ph name="DEVICE_TYPE" /> hii kwa ajili ya mtoto</translation>
 <translation id="7326025035243649350">Je, ungependa kuwasha ChromeVox, kisoma skrini kilichojumuishwa cha Mfumo wa Uendeshaji wa Chrome?</translation>
 <translation id="7327989755579928735"><ph name="MANAGER" /> imezima utatuzi wa ADB. Ukizima kisha uwashe <ph name="DEVICE_TYPE" /> yako, hutaweza kupakia programu kutoka kifaa kingine.</translation>
+<translation id="7328119182036084494">Imehifadhiwa kwenye <ph name="WEB_DRIVE" /></translation>
 <translation id="7328867076235380839">Mkusanyiko si sahihi</translation>
 <translation id="7329154610228416156">Haikufaulu kuingia katika akaunti kwa sababu ilisanidiwa ili itumie URL isiyo salama (<ph name="BLOCKED_URL" />). Tafadhali wasiliana na msimamizi wako.</translation>
 <translation id="7332053360324989309">Mfanyakazi Maalum: <ph name="SCRIPT_URL" /></translation>
@@ -6636,6 +6641,7 @@
 <translation id="8235418492073272647">Ukurasa umeshirikiwa kutoka <ph name="DEVICE_NAME" /></translation>
 <translation id="8236911020904880539">ufunge</translation>
 <translation id="8236917170563564587">Shiriki kichupo hiki badala yake</translation>
+<translation id="8237471930911823556"><ph name="APP_NAME" /> imewekewa mipangilio ya kufunguka katika kichupo kipya cha kivinjari, viungo vinavyoweza kutumika pia vitafunguka katika kivinjari hicho.</translation>
 <translation id="8237647586961940482">Nyekundu na waridi iliyokolea</translation>
 <translation id="8239032431519548577">Usajili wa biashara umekamilika</translation>
 <translation id="8239932336306009582">Zisizoruhusiwa kutuma arifa</translation>
@@ -7172,6 +7178,7 @@
 <translation id="8835786707922974220">Hakikisha kwamba unaweza kufikia manenosiri uliyoyahifadhi kila wakati</translation>
 <translation id="8836360711089151515"><ph name="MANAGER" /> inahitaji uhifadhi nakala ya data yako na urudishe <ph name="DEVICE_TYPE" /> hii ndani ya wiki moja. <ph name="LINK_BEGIN" />Angalia maelezo<ph name="LINK_END" /></translation>
 <translation id="8836782447513334597">uendelee</translation>
+<translation id="8838234842677265403"><ph name="WEB_DRIVE_MESSAGE" /> (<ph name="SUPPORT_INFO" />)</translation>
 <translation id="8838601485495657486">Isiyopenyeza nuru</translation>
 <translation id="8838770651474809439">Hambaga</translation>
 <translation id="883911313571074303">Eleza kuhusu picha</translation>
diff --git a/chrome/app/resources/generated_resources_uz.xtb b/chrome/app/resources/generated_resources_uz.xtb
index 6e725ef..6bc416a 100644
--- a/chrome/app/resources/generated_resources_uz.xtb
+++ b/chrome/app/resources/generated_resources_uz.xtb
@@ -2059,6 +2059,7 @@
 <translation id="3192947282887913208">Audio fayllar</translation>
 <translation id="3197453258332670132">Oʻng klik yoki biroz bosib turilsa, belgilangan matn uchun aloqador axborot chiqariladi</translation>
 <translation id="3199127022143353223">Serverlar</translation>
+<translation id="3200061262156232574">Xarid qutingizda</translation>
 <translation id="3201422919974259695">Mavjud USB qurilmalar bu yerda chiqadi.</translation>
 <translation id="3202131003361292969">Fayl yo‘lagi</translation>
 <translation id="3202173864863109533">Bu ichki oyna ovozi o‘chirib qo‘yilgan</translation>
@@ -2991,6 +2992,7 @@
 <translation id="42126664696688958">Eksport</translation>
 <translation id="42137655013211669">Server bu manbaga kirishga ruxsat bermagan.</translation>
 <translation id="4217571870635786043">Ovoz bilan yozish</translation>
+<translation id="4219558185499589032">Box</translation>
 <translation id="4220648711404560261">Sozlashda xatolik yuz berdi.</translation>
 <translation id="4222772810963087151">Nashr axboroti</translation>
 <translation id="4225020013797061859">“<ph name="ACTION" />” amali uchun belgilanadigan kalit yoki tugmani bosing</translation>
@@ -4284,6 +4286,7 @@
 <translation id="5677503058916217575">Sahifa tili:</translation>
 <translation id="5677928146339483299">Bloklangan</translation>
 <translation id="5678550637669481956"><ph name="VOLUME_NAME" />’ga o‘qish va yozish uchun ruxsat berildi.</translation>
+<translation id="5678821117681811450"><ph name="WEB_DRIVE" /> omboriga yuborilmoqda</translation>
 <translation id="5678955352098267522">Ma’lumotlarni <ph name="WEBSITE_1" /> saytida ko‘rish</translation>
 <translation id="5680050361008726776"><ph name="ESIM_PROFILE_NAME" /> olib tashlansinmi?</translation>
 <translation id="5683806393796685434">Aktivatsiya kodini kiriting</translation>
@@ -4743,6 +4746,7 @@
 <translation id="6207200176136643843">Standart masshtab</translation>
 <translation id="6207937957461833379">Mamlakat / hudud</translation>
 <translation id="6208521041562685716">Mobil tarmoq faollashtirilmoqda</translation>
+<translation id="6208725777148613371"><ph name="WEB_DRIVE" /> omboriga saqlanmadi, sababi: <ph name="INTERRUPT_REASON" /></translation>
 <translation id="6209838773933913227">Komponent yangilanmoqda</translation>
 <translation id="6209908325007204267">Bu qurilmada Chrome korporativ litsenziyasi bor, lekin qurilmadagi foydalanuvchi nomi korporativ hisobga tegishli emas. Boshqa qurilma orqali g.co/ChromeEnterpriseAccount sahifasidan korporativ hisob oching.</translation>
 <translation id="6212039847102026977">Qo‘shimcha tarmoq parametrlari</translation>
@@ -5739,6 +5743,7 @@
 <translation id="7326004502692201767">Bu <ph name="DEVICE_TYPE" /> qurilmasini farzand uchun sozlang</translation>
 <translation id="7326025035243649350">Chrome OS tizimidagi ichki oʻrnatilgan ekrandan oʻqish vositasi – ChromeVox faollashtirilsinmi?</translation>
 <translation id="7327989755579928735">ADB tuzatish vositasi <ph name="MANAGER" /> tomonidan faolsizlantirildi. <ph name="DEVICE_TYPE" /> qurilmasini qayta ishga tushirsangiz, tashqaridan yuklab olingan ilovalarga kira olmaysiz.</translation>
+<translation id="7328119182036084494"><ph name="WEB_DRIVE" /> omboriga saqlandi</translation>
 <translation id="7328867076235380839">Xato kombinatsiya</translation>
 <translation id="7329154610228416156">Kirish amalga oshmadi, chunki u xavfli URL manzildan foydalanish uchun moslangan (<ph name="BLOCKED_URL" />). Administrator bilan bog‘laning.</translation>
 <translation id="7332053360324989309">Dedicated Worker: <ph name="SCRIPT_URL" /></translation>
@@ -6626,6 +6631,7 @@
 <translation id="8235418492073272647">Sahifa <ph name="DEVICE_NAME" /> qurilmasidan ulashilgan</translation>
 <translation id="8236911020904880539">chiqish</translation>
 <translation id="8236917170563564587">Oʻrniga bu varaqni ulashish</translation>
+<translation id="8237471930911823556">Brauzer yangi varaqlari <ph name="APP_NAME" /> ilovasida ochiladi, tegishli havolalar ham brauzerda ochiladi.</translation>
 <translation id="8237647586961940482">Toʻq pushti va qizil</translation>
 <translation id="8239032431519548577">Korporativ domenda qayd qilindi</translation>
 <translation id="8239932336306009582">Bildirishnomalar yuborishga ruxsat berilmagan</translation>
@@ -7162,6 +7168,7 @@
 <translation id="8835786707922974220">Saqlangan parollaringizni doim ocha olishingizni tekshiring</translation>
 <translation id="8836360711089151515"><ph name="MANAGER" /> maʼlumotlaringizni zaxiralash va bu <ph name="DEVICE_TYPE" /> qurilmasini 1 hafta ichida qaytarishingizni talab qilmoqda. <ph name="LINK_BEGIN" />Tafsilotlar<ph name="LINK_END" /></translation>
 <translation id="8836782447513334597">davom etish</translation>
+<translation id="8838234842677265403"><ph name="WEB_DRIVE_MESSAGE" /> (<ph name="SUPPORT_INFO" />)</translation>
 <translation id="8838601485495657486">Shaffoflik</translation>
 <translation id="8838770651474809439">Gamburger</translation>
 <translation id="883911313571074303">Rasmni izohlash</translation>
diff --git a/chrome/app/resources/generated_resources_zh-HK.xtb b/chrome/app/resources/generated_resources_zh-HK.xtb
index 2379374..8d75c60 100644
--- a/chrome/app/resources/generated_resources_zh-HK.xtb
+++ b/chrome/app/resources/generated_resources_zh-HK.xtb
@@ -2071,6 +2071,7 @@
 <translation id="3192947282887913208">音效檔案</translation>
 <translation id="3197453258332670132">按一下右鍵或長按畫面,即可查看所選文字的相關資料</translation>
 <translation id="3199127022143353223">伺服器</translation>
+<translation id="3200061262156232574">購物車內商品</translation>
 <translation id="3201422919974259695">可用的 USB 裝置將會在這裡顯示。</translation>
 <translation id="3202131003361292969">路徑</translation>
 <translation id="3202173864863109533">此分頁的音效已設為靜音。</translation>
@@ -3003,6 +3004,7 @@
 <translation id="42126664696688958">匯出</translation>
 <translation id="42137655013211669">伺服器已禁止存取此資源。</translation>
 <translation id="4217571870635786043">語音輸入</translation>
+<translation id="4219558185499589032">Box</translation>
 <translation id="4220648711404560261">啟用時發生錯誤。</translation>
 <translation id="4222772810963087151">版本詳細資料</translation>
 <translation id="4225020013797061859">請按下要為「<ph name="ACTION" />」動作指派的按鈕裝置或按鍵</translation>
@@ -4296,6 +4298,7 @@
 <translation id="5677503058916217575">網頁語言:</translation>
 <translation id="5677928146339483299">已封鎖</translation>
 <translation id="5678550637669481956">已授與「<ph name="VOLUME_NAME" />」的讀取和寫入權限。</translation>
+<translation id="5678821117681811450">正在傳送至「<ph name="WEB_DRIVE" />」</translation>
 <translation id="5678955352098267522">讀取您在 <ph name="WEBSITE_1" /> 上的資料</translation>
 <translation id="5680050361008726776">要移除「<ph name="ESIM_PROFILE_NAME" />」嗎?</translation>
 <translation id="5683806393796685434">請輸入您的確認碼</translation>
@@ -4755,6 +4758,7 @@
 <translation id="6207200176136643843">重設為預設縮放等級</translation>
 <translation id="6207937957461833379">國家/地區</translation>
 <translation id="6208521041562685716">正在啟用流動數據</translation>
+<translation id="6208725777148613371">無法儲存至「<ph name="WEB_DRIVE" />」- <ph name="INTERRUPT_REASON" /></translation>
 <translation id="6209838773933913227">正在更新組件</translation>
 <translation id="6209908325007204267">您的裝置包含一項 Chrome Enterprise 升級,但您的使用者名稱尚未連結企業賬戶。請透過另一部裝置前往 g.co/ChromeEnterpriseAccount 建立企業帳戶。</translation>
 <translation id="6212039847102026977">顯示進階網絡屬性</translation>
@@ -5750,6 +5754,7 @@
 <translation id="7326004502692201767">為子女設定此 <ph name="DEVICE_TYPE" /></translation>
 <translation id="7326025035243649350">要啟用 Chrome 作業系統內置的螢幕閱讀器 ChromeVox 嗎?</translation>
 <translation id="7327989755579928735"><ph name="MANAGER" /> 已停用 ADB 偵錯。重新啟動 <ph name="DEVICE_TYPE" /> 後,您將無法載入應用程式。</translation>
+<translation id="7328119182036084494">已儲存至「<ph name="WEB_DRIVE" />」</translation>
 <translation id="7328867076235380839">無效的組合</translation>
 <translation id="7329154610228416156">由於設定使用的網址 (<ph name="BLOCKED_URL" />) 不安全,導致登入失敗。請與您的管理員聯絡。</translation>
 <translation id="7332053360324989309">專用工作程式:<ph name="SCRIPT_URL" /></translation>
@@ -6639,6 +6644,7 @@
 <translation id="8235418492073272647">透過「<ph name="DEVICE_NAME" />」分享的網頁</translation>
 <translation id="8236911020904880539">離開</translation>
 <translation id="8236917170563564587">改為分享此分頁</translation>
+<translation id="8237471930911823556">「<ph name="APP_NAME" />」已設定為在新瀏覽器分頁中開啟,支援的連結亦會在瀏覽器中開啟。</translation>
 <translation id="8237647586961940482">深粉紅色和紅色</translation>
 <translation id="8239032431519548577">企業註冊完成</translation>
 <translation id="8239932336306009582">不允許傳送通知</translation>
@@ -7175,6 +7181,7 @@
 <translation id="8835786707922974220">請確保您可隨時存取已儲存的密碼</translation>
 <translation id="8836360711089151515"><ph name="MANAGER" /> 要求您備份資料,並在 1 星期內歸還此 <ph name="DEVICE_TYPE" />。<ph name="LINK_BEGIN" />查看詳情<ph name="LINK_END" /></translation>
 <translation id="8836782447513334597">繼續</translation>
+<translation id="8838234842677265403"><ph name="WEB_DRIVE_MESSAGE" /> (<ph name="SUPPORT_INFO" />)</translation>
 <translation id="8838601485495657486">不透明</translation>
 <translation id="8838770651474809439">漢堡包</translation>
 <translation id="883911313571074303">為圖片加入註釋</translation>
diff --git a/chrome/app/resources/google_chrome_strings_sw.xtb b/chrome/app/resources/google_chrome_strings_sw.xtb
index 634aea3..eaff7f7b 100644
--- a/chrome/app/resources/google_chrome_strings_sw.xtb
+++ b/chrome/app/resources/google_chrome_strings_sw.xtb
@@ -9,7 +9,7 @@
 Baadhi ya vipengele huenda visipatikane na mabadiliko katika mapendeleo hayatahifadhiwa.</translation>
 <translation id="1088300314857992706"><ph name="USER_EMAIL_ADDRESS" /> ilikuwa ikitumia Chrome awali</translation>
 <translation id="110877069173485804">Hii ndiyo Chrome yako</translation>
-<translation id="1125124144982679672">Ni nani anayetumia Chrome?</translation>
+<translation id="1125124144982679672">Ungependa kutumia wasifu gani wa Chrome?</translation>
 <translation id="1142745911746664600">Imeshindwa kusasisha Chrome</translation>
 <translation id="1154147086299354128">na Fungua katika Chrome</translation>
 <translation id="1182414570724401860">Chrome inapendekeza usipakue wala kufungua faili hii</translation>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 2f46703..4312f60 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3480,6 +3480,9 @@
      FEATURE_VALUE_TYPE(ash::features::kLockScreenNotifications)},
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+    {"crostini-use-dlc", flag_descriptions::kCrostiniUseDlcName,
+     flag_descriptions::kCrostiniUseDlcDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(chromeos::features::kCrostiniUseDlc)},
     {"pluginvm-fullscreen", flag_descriptions::kPluginVmFullscreenName,
      flag_descriptions::kPluginVmFullscreenDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kPluginVmFullscreen)},
@@ -6812,10 +6815,12 @@
      FEATURE_VALUE_TYPE(language::kDesktopDetailedLanguageSettings)},
 #endif
 
+#if defined(OS_ANDROID)
     {"pwa-update-dialog-for-name-and-icon",
      flag_descriptions::kPwaUpdateDialogForNameAndIconName,
-     flag_descriptions::kPwaUpdateDialogForNameAndIconDescription, kOsAll,
-     FEATURE_VALUE_TYPE(features::kPwaUpdateDialogForNameAndIcon)},
+     flag_descriptions::kPwaUpdateDialogForNameAndIconDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kPwaUpdateDialogForNameAndIcon)},
+#endif
 
     {"sync-autofill-wallet-offer-data",
      flag_descriptions::kSyncAutofillWalletOfferDataName,
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 98dcad7..961844c 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -150,7 +150,7 @@
 // there are only minimized windows), it will unminimize it.
 Browser* ActivateBrowser(Profile* profile) {
   Browser* browser = chrome::FindLastActiveWithProfile(
-      (profile->IsGuestSession() || profile->IsEphemeralGuestProfile())
+      profile->IsGuestSession()
           ? profile->GetPrimaryOTRProfile(/*create_if_needed=*/true)
           : profile);
   if (browser)
@@ -1449,8 +1449,8 @@
     // to AppKit as there's nothing that it can do either.
     return NO;
   }
-  if (lastProfile->IsGuestSession() || lastProfile->IsEphemeralGuestProfile() ||
-      IsProfileSignedOut(lastProfile) || lastProfile->IsSystemProfile()) {
+  if (lastProfile->IsGuestSession() || IsProfileSignedOut(lastProfile) ||
+      lastProfile->IsSystemProfile()) {
     ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileLocked);
   } else if (ProfilePicker::ShouldShowAtLaunch()) {
     ProfilePicker::Show(
diff --git a/chrome/browser/apps/app_service/browser_app_launcher.cc b/chrome/browser/apps/app_service/browser_app_launcher.cc
index 0b70f3627..dc1af2f6 100644
--- a/chrome/browser/apps/app_service/browser_app_launcher.cc
+++ b/chrome/browser/apps/app_service/browser_app_launcher.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/apps/app_service/app_platform_metrics.h"
 #include "chrome/browser/apps/app_service/launch_utils.h"
 #include "components/full_restore/app_launch_info.h"
+#include "components/full_restore/full_restore_save_handler.h"
 #include "components/full_restore/full_restore_utils.h"
 #include "components/sessions/core/session_id.h"
 #endif
@@ -46,6 +47,10 @@
     apps::mojom::LaunchContainer container = params.container;
     int restore_id = params.restore_id;
 
+    // Create the FullRestoreSaveHandler instance before launching the app to
+    // observe the browser window.
+    full_restore::FullRestoreSaveHandler::GetInstance();
+
     auto* web_contents =
         web_app_launch_manager_.OpenApplication(std::move(params));
 
diff --git a/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer.cc b/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer.cc
index 73057f82..56bb07e 100644
--- a/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer.cc
+++ b/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer.cc
@@ -19,14 +19,16 @@
 #include "chrome/browser/net/nss_context.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/net/x509_certificate_model_nss.h"
+#include "chrome/services/keymaster/public/mojom/cert_store.mojom.h"
 #include "crypto/rsa_private_key.h"
 #include "net/cert/x509_util_nss.h"
 
 namespace arc {
 
 CertDescription::CertDescription(crypto::RSAPrivateKey* placeholder_key,
-                                 CERTCertificate* nss_cert)
-    : placeholder_key(placeholder_key), nss_cert(nss_cert) {}
+                                 CERTCertificate* nss_cert,
+                                 keymaster::mojom::ChapsSlot slot)
+    : placeholder_key(placeholder_key), nss_cert(nss_cert), slot(slot) {}
 
 CertDescription::CertDescription(CertDescription&& other) = default;
 
diff --git a/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer.h b/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer.h
index 7c783575..59037c4 100644
--- a/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer.h
+++ b/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
+#include "chrome/services/keymaster/public/mojom/cert_store.mojom.h"
 #include "components/policy/core/common/remote_commands/remote_command_job.h"
 #include "components/policy/core/common/remote_commands/remote_commands_queue.h"
 #include "crypto/rsa_private_key.h"
@@ -27,17 +28,24 @@
 
 namespace arc {
 
+// This class is basically a value holder associating metadata relevant to an
+// NSS CERTCertificate.
 struct CertDescription {
   CertDescription(crypto::RSAPrivateKey* placeholder_key,
-                  CERTCertificate* nss_cert);
+                  CERTCertificate* nss_cert,
+                  keymaster::mojom::ChapsSlot slot);
   CertDescription(CertDescription&& other);
   CertDescription(const CertDescription& other) = delete;
   CertDescription& operator=(CertDescription&& other);
   CertDescription& operator=(const CertDescription& other) = delete;
   ~CertDescription();
 
+  // The dummy key to be installed in ARC as a placeholder for |nss_cert|.
   std::unique_ptr<crypto::RSAPrivateKey> placeholder_key;
+  // The NSS certificate that corresponds to this object.
   net::ScopedCERTCertificate nss_cert;
+  // The chaps slot where this key is stored.
+  keymaster::mojom::ChapsSlot slot;
 };
 
 // This class manages the certificates, available to ARC.
diff --git a/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer_unittest.cc b/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer_unittest.cc
index b145f151..a2d7bc32 100644
--- a/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer_unittest.cc
+++ b/chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer_unittest.cc
@@ -76,7 +76,8 @@
   cert = net::x509_util::CreateCERTCertificateFromBytes(
       reinterpret_cast<const uint8_t*>(der_cert.data()), der_cert.size());
   ASSERT_TRUE(cert);
-  certs->push_back(CertDescription(key.release(), cert.release()));
+  certs->push_back(CertDescription(key.release(), cert.release(),
+                                   keymaster::mojom::ChapsSlot::kUser));
 }
 
 }  // namespace
diff --git a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service.cc b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service.cc
index 963ba0dd..f209a5a 100644
--- a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service.cc
+++ b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service.cc
@@ -32,6 +32,8 @@
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/core/common/policy_namespace.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
 #include "crypto/rsa_private_key.h"
 #include "net/cert/x509_util_nss.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -77,6 +79,144 @@
   }
 };
 
+// The following series of functions related to ListCerts make use of the
+// NSSCertDatabase to fulfill its goal of listing certificates. The cert
+// database is accessed through a raw pointer with limited lifetime guarantees
+// and is not thread safe. Namely, the cert database is guaranteed valid for the
+// single IO thread task where it was received.
+//
+// Furthermore, creating an NssCertDatabaseGetter requires a BrowserContext,
+// which can only be accessed on the UI thread.
+//
+// ListCerts and related functions are implemented to make sure the above
+// requirements are respected. Here's a diagram of the interaction between UI
+// and IO threads.
+//
+//                    UI Thread                     IO Thread
+//
+//                    ListCerts
+//                        |
+//            CreateNSSCertDatabaseGetter
+//                        |
+//                        \----------------------------v
+//                                          ListCertsWithDbGetterOnIO
+//                                                     |
+//                                           database_getter.Run()
+//                                                     |
+//                                               ListCertsOnIO
+//                                                     |
+//                                              ListCertsInSlot
+//                                                     |
+//                                   PostListedCertsBackToOriginalTaskRunner
+//                                                     |
+//                        v----------------------------/
+//  Process certs / Repeat ListCerts for system slot
+//
+// ARC requires certs from both the 'user' and 'system' chaps slots to be
+// processed. Because ListCertsInSlot is asynchronous, it's not possible to
+// guarantee that both ListCertsInSlot calls happen in the same task execution,
+// so this entire process is performed twice: first for the user slot, then for
+// the system slot. The ordering of the calls is not important, other than the
+// implementation lists the 'user' slot first, and uses the 'system' slot to
+// signal the process is complete.
+//
+// The current user may not have access to the system slot, but that is only
+// discoverable on the IO thread. In that case, the sequence for the system slot
+// becomes:
+//
+//                    UI Thread                     IO Thread
+//
+//                    ListCerts
+//                        |
+//            CreateNSSCertDatabaseGetter
+//                        |
+//                        \----------------------------v
+//                                          ListCertsWithDbGetterOnIO
+//                                                     |
+//                                           database_getter.Run()
+//                                                     |
+//                                                ListCertsOnIO
+//                                                     |
+//                                   (Determine system slot isn't allowed)
+//                                                     |
+//                                   PostListedCertsBackToOriginalTaskRunner
+//                                                     |
+//                        v----------------------------/
+//             Process list of certs...
+
+void PostListedCertsBackToOriginalTaskRunner(
+    scoped_refptr<base::TaskRunner> original_task_runner,
+    net::NSSCertDatabase::ListCertsCallback callback,
+    net::ScopedCERTCertificateList cert_list) {
+  original_task_runner->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(cert_list)));
+}
+
+void ListCertsOnIO(scoped_refptr<base::TaskRunner> original_task_runner,
+                   keymaster::mojom::ChapsSlot slot,
+                   net::NSSCertDatabase::ListCertsCallback callback,
+                   net::NSSCertDatabase* database) {
+  // |database->ListCertsInSlot| must be called from the IO thread.
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  if (slot == keymaster::mojom::ChapsSlot::kSystem &&
+      !database->GetSystemSlot()) {
+    // Trying to list system slot when it's not available, return empty list.
+    PostListedCertsBackToOriginalTaskRunner(original_task_runner,
+                                            std::move(callback),
+                                            net::ScopedCERTCertificateList());
+    return;
+  }
+
+  // List the certs on |database|, which may dispatch to a worker thread to
+  // avoid blocking. The actual result needs to make it back to the UI thread,
+  // but the callback will be invoked on the IO thread, so the results need
+  // to be forwarded onwards.
+  database->ListCertsInSlot(
+      base::BindOnce(&PostListedCertsBackToOriginalTaskRunner,
+                     original_task_runner, std::move(callback)),
+      slot == keymaster::mojom::ChapsSlot::kUser
+          ? database->GetPrivateSlot().get()
+          : database->GetSystemSlot().get());
+}
+
+void ListCertsWithDbGetterOnIO(
+    scoped_refptr<base::TaskRunner> original_task_runner,
+    keymaster::mojom::ChapsSlot slot,
+    net::NSSCertDatabase::ListCertsCallback callback,
+    NssCertDatabaseGetter database_getter) {
+  // |database_getter| must be run from the IO thread.
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  // Running |database_getter| may either return a non-null pointer
+  // synchronously or invoke the given callback asynchronously with a non-null
+  // pointer. |split_callback| is used here to handle both cases.
+  auto split_callback = base::SplitOnceCallback(
+      base::BindOnce(&ListCertsOnIO, std::move(original_task_runner), slot,
+                     std::move(callback)));
+
+  net::NSSCertDatabase* database =
+      std::move(database_getter).Run(std::move(split_callback.first));
+  if (database)
+    std::move(split_callback.second).Run(database);
+}
+
+// Returns the list of certificates in |slot|, making sure to fetch the cert
+// database and list certs from the IO thread, while posting |callback| with the
+// output list to the original caller thread.
+void ListCerts(content::BrowserContext* const context,
+               keymaster::mojom::ChapsSlot slot,
+               net::NSSCertDatabase::ListCertsCallback callback) {
+  // |context| must be accessed on the UI thread.
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  // The NssCertDatabaseGetter must be posted to the IO thread immediately.
+  content::GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE, base::BindOnce(&ListCertsWithDbGetterOnIO,
+                                base::ThreadTaskRunnerHandle::Get(), slot,
+                                std::move(callback),
+                                CreateNSSCertDatabaseGetter(context)));
+}
+
 using IsCertificateAllowedCallback = base::OnceCallback<void(bool allowed)>;
 
 void CheckCorporateFlag(
@@ -93,26 +233,18 @@
   std::move(callback).Run(/* allowed */ corporate_key.value());
 }
 
-void CheckKeyLocationAndCorporateFlag(
-    IsCertificateAllowedCallback callback,
-    const std::string& public_key_spki_der,
-    content::BrowserContext* const context,
-    absl::optional<bool> key_on_user_token,
-    chromeos::platform_keys::Status is_key_on_token_status) {
-  if (is_key_on_token_status != chromeos::platform_keys::Status::kSuccess) {
-    LOG(WARNING) << "Error while checking key location: "
-                 << chromeos::platform_keys::StatusToString(
-                        is_key_on_token_status);
-    std::move(callback).Run(/* allowed */ false);
-    return;
-  }
+// Returns true if the certificate is allowed to be used by ARC. The certificate
+// is allowed to be used by ARC if its key is marked for corporate usage. |cert|
+// must be non-null.
+void IsCertificateAllowed(IsCertificateAllowedCallback callback,
+                          scoped_refptr<net::X509Certificate> cert,
+                          content::BrowserContext* const context) {
+  // |context| must be accessed on the UI thread.
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(cert);
 
-  DCHECK(key_on_user_token.has_value());
-
-  if (!key_on_user_token.value_or(false)) {
-    std::move(callback).Run(/* allowed */ false);
-    return;
-  }
+  std::string public_key_spki_der =
+      chromeos::platform_keys::GetSubjectPublicKeyInfo(cert);
 
   // Check if the key is marked for corporate usage.
   chromeos::platform_keys::KeyPermissionsServiceFactory::GetForBrowserContext(
@@ -122,29 +254,11 @@
           base::BindOnce(&CheckCorporateFlag, std::move(callback)));
 }
 
-// Returns true if the certificate is allowed to be used by ARC. The certificate
-// is allowed to be used by ARC if its key is marked for corporate usage and
-// resides on a user token. |cert| must be non-null.
-void IsCertificateAllowed(IsCertificateAllowedCallback callback,
-                          scoped_refptr<net::X509Certificate> cert,
-                          content::BrowserContext* const context) {
-  DCHECK(cert);
-
-  const std::string public_key_spki_der =
-      chromeos::platform_keys::GetSubjectPublicKeyInfo(cert);
-
-  // Check if the key is on the user token.
-  chromeos::platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(
-      context)
-      ->IsKeyOnToken(
-          chromeos::platform_keys::TokenId::kUser, public_key_spki_der,
-          base::BindOnce(&CheckKeyLocationAndCorporateFlag, std::move(callback),
-                         public_key_spki_der, context));
-}
-
-std::vector<CertDescription> PrepareCertDescriptions(
-    net::ScopedCERTCertificateList nss_certs) {
-  std::vector<CertDescription> certificates;
+// Appends the given |nss_certs| into |cert_descriptions| along with new
+// placeholder keys for each. Certs in |nss_certs| come from the given |slot|.
+void PrepareCertDescriptions(net::ScopedCERTCertificateList nss_certs,
+                             keymaster::mojom::ChapsSlot slot,
+                             std::vector<CertDescription>* cert_descriptions) {
   for (auto& nss_cert : nss_certs) {
     if (!nss_cert)
       continue;
@@ -152,15 +266,21 @@
     auto placeholder_key = crypto::RSAPrivateKey::Create(2048);
     DCHECK(placeholder_key);
 
-    certificates.emplace_back(placeholder_key.release(), nss_cert.release());
+    cert_descriptions->emplace_back(placeholder_key.release(),
+                                    nss_cert.release(), slot);
   }
-  return certificates;
 }
 
+// Returns the list of Chrome OS keys with the data arc-keymasterd needs to find
+// and execute operations on the certs in |cert_descriptions| through chaps.
+// Each ChromeOsKey instance contains a ChapsKeyData with its CKA_LABEL,
+// CKA_ID, and the slot where it's stored. Note this slot is NOT the PKCS#11
+// CK_SLOT_ID, but a more abstract representation that can be used to find a
+// CK_SLOT_ID at runtime.
 std::vector<keymaster::mojom::ChromeOsKeyPtr> PrepareChromeOsKeys(
-    const std::vector<CertDescription>& certificates) {
+    const std::vector<CertDescription>& cert_descriptions) {
   std::vector<keymaster::mojom::ChromeOsKeyPtr> chrome_os_keys;
-  for (const auto& certificate : certificates) {
+  for (const auto& certificate : cert_descriptions) {
     CERTCertificate* nss_cert = certificate.nss_cert.get();
     DCHECK(nss_cert);
 
@@ -185,7 +305,8 @@
 
     // Build a mojo ChromeOsKey and store it in the output vector.
     keymaster::mojom::ChapsKeyDataPtr key_data =
-        keymaster::mojom::ChapsKeyData::New(pkcs11_label, pkcs11_id);
+        keymaster::mojom::ChapsKeyData::New(pkcs11_label, pkcs11_id,
+                                            certificate.slot);
     keymaster::mojom::ChromeOsKeyPtr key = keymaster::mojom::ChromeOsKey::New(
         ExportSpki(certificate.placeholder_key.get()),
         keymaster::mojom::KeyData::NewChapsKeyData(std::move(key_data)));
@@ -239,10 +360,11 @@
 }
 
 void CertStoreService::UpdateCertificates() {
-  GetNSSCertDatabaseForProfile(
-      Profile::FromBrowserContext(context_),
-      base::BindOnce(&CertStoreService::OnGetNSSCertDatabaseForProfile,
-                     weak_ptr_factory_.GetWeakPtr()));
+  ListCerts(context_, keymaster::mojom::ChapsSlot::kUser,
+            base::BindOnce(&CertStoreService::OnCertificatesListed,
+                           weak_ptr_factory_.GetWeakPtr(),
+                           keymaster::mojom::ChapsSlot::kUser,
+                           std::vector<CertDescription>()));
 }
 
 void CertStoreService::FilterAllowedCertificatesRecursively(
@@ -287,16 +409,9 @@
       std::move(callback), std::move(cert_queue), std::move(allowed_certs));
 }
 
-void CertStoreService::OnGetNSSCertDatabaseForProfile(
-    net::NSSCertDatabase* database) {
-  DCHECK(database);
-  database->ListCertsInSlot(
-      base::BindOnce(&CertStoreService::OnCertificatesListed,
-                     weak_ptr_factory_.GetWeakPtr()),
-      database->GetPrivateSlot().get());
-}
-
 void CertStoreService::OnCertificatesListed(
+    keymaster::mojom::ChapsSlot slot,
+    std::vector<CertDescription> cert_descriptions,
     net::ScopedCERTCertificateList cert_list) {
   base::queue<net::ScopedCERTCertificate> cert_queue;
   for (auto& cert : cert_list) {
@@ -306,11 +421,14 @@
   net::ScopedCERTCertificateList allowed_certs;
   FilterAllowedCertificatesRecursively(
       base::BindOnce(&CertStoreService::OnFilteredAllowedCertificates,
-                     weak_ptr_factory_.GetWeakPtr()),
+                     weak_ptr_factory_.GetWeakPtr(), slot,
+                     std::move(cert_descriptions)),
       std::move(cert_queue), std::move(allowed_certs));
 }
 
 void CertStoreService::OnFilteredAllowedCertificates(
+    keymaster::mojom::ChapsSlot slot,
+    std::vector<CertDescription> cert_descriptions,
     net::ScopedCERTCertificateList allowed_certs) {
   ArcKeymasterBridge* const keymaster_bridge =
       ArcKeymasterBridge::GetForBrowserContext(context_);
@@ -319,15 +437,31 @@
     return;
   }
 
-  std::vector<CertDescription> certificates =
-      PrepareCertDescriptions(std::move(allowed_certs));
-  std::vector<keymaster::mojom::ChromeOsKeyPtr> keys =
-      PrepareChromeOsKeys(certificates);
+  PrepareCertDescriptions(std::move(allowed_certs), slot, &cert_descriptions);
 
+  if (slot == keymaster::mojom::ChapsSlot::kUser) {
+    // Done with the user slot, so try to process additional certs in the
+    // system slot. If there is no system slot (e.g. the user is not allowed
+    // to access it), this call won't mutate |cert_descriptions|, and only
+    // return the user slot certificates. However, it's necessary to perform
+    // this check asynchronously on the IO thread (through ListCerts), because
+    // that's the only thread that knows if the system slot is enabled.
+    ListCerts(context_, keymaster::mojom::ChapsSlot::kSystem,
+              base::BindOnce(&CertStoreService::OnCertificatesListed,
+                             weak_ptr_factory_.GetWeakPtr(),
+                             keymaster::mojom::ChapsSlot::kSystem,
+                             std::move(cert_descriptions)));
+    return;
+  }
+  // At this point certs have been gathered from all available slots (i.e. user
+  // slot and potentially system slot if access is allowed to this user),
+  // proceed to send them to arc-keymaster and ARC.
+  std::vector<keymaster::mojom::ChromeOsKeyPtr> keys =
+      PrepareChromeOsKeys(cert_descriptions);
   keymaster_bridge->UpdatePlaceholderKeys(
-      std::move(keys),
-      base::BindOnce(&CertStoreService::OnUpdatedKeymasterKeys,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(certificates)));
+      std::move(keys), base::BindOnce(&CertStoreService::OnUpdatedKeymasterKeys,
+                                      weak_ptr_factory_.GetWeakPtr(),
+                                      std::move(cert_descriptions)));
 }
 
 void CertStoreService::OnUpdatedKeymasterKeys(
@@ -355,11 +489,11 @@
 CertStoreService::CertificateCache::~CertificateCache() = default;
 
 void CertStoreService::CertificateCache::Update(
-    const std::vector<CertDescription>& certificates) {
+    const std::vector<CertDescription>& cert_descriptions) {
   // Map cert name to real SPKI.
   key_info_by_name_cache_.clear();
   std::set<std::string> new_required_cert_names;
-  for (const auto& certificate : certificates) {
+  for (const auto& certificate : cert_descriptions) {
     CERTCertificate* nss_cert = certificate.nss_cert.get();
     DCHECK(nss_cert);
 
diff --git a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service.h b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service.h
index cc6e9bf..4a5fd6e2 100644
--- a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service.h
+++ b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service.h
@@ -14,6 +14,7 @@
 #include "base/containers/queue.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/arc/enterprise/cert_store/arc_cert_installer.h"
+#include "chrome/services/keymaster/public/mojom/cert_store.mojom.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "content/public/browser/browser_context.h"
@@ -120,9 +121,14 @@
       net::ScopedCERTCertificate cert,
       bool certificate_allowed) const;
 
-  void OnGetNSSCertDatabaseForProfile(net::NSSCertDatabase* database);
-  void OnCertificatesListed(net::ScopedCERTCertificateList cert_list);
+  void OnCertificatesListed(keymaster::mojom::ChapsSlot slot,
+                            std::vector<CertDescription> certificates,
+                            net::ScopedCERTCertificateList cert_list);
+  // Processes metadata from |allowed_certs| stored in the given |slot| and
+  // appends them to |certificates|.
   void OnFilteredAllowedCertificates(
+      keymaster::mojom::ChapsSlot slot,
+      std::vector<CertDescription> certificates,
       net::ScopedCERTCertificateList allowed_certs);
   void OnUpdatedKeymasterKeys(std::vector<CertDescription> certificates,
                               bool success);
diff --git a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
index c63bf775..4dad718 100644
--- a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
+++ b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <algorithm>
 #include <map>
 #include <string>
 #include <vector>
@@ -15,8 +16,8 @@
 #include "chrome/browser/ash/arc/enterprise/cert_store/cert_store_service.h"
 #include "chrome/browser/ash/arc/keymaster/arc_keymaster_bridge.h"
 #include "chrome/browser/ash/arc/session/arc_service_launcher.h"
-#include "chrome/browser/ash/login/test/local_policy_test_server_mixin.h"
-#include "chrome/browser/ash/policy/core/user_policy_test_helper.h"
+#include "chrome/browser/ash/policy/affiliation/affiliation_mixin.h"
+#include "chrome/browser/ash/policy/affiliation/affiliation_test_helper.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_service_factory.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
@@ -37,8 +38,10 @@
 #include "components/arc/test/arc_util_test_support.h"
 #include "components/policy/policy_constants.h"
 #include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_test.h"
+#include "content/public/test/test_launcher.h"
 #include "crypto/scoped_test_system_nss_key_slot.h"
 #include "extensions/browser/extension_system.h"
 #include "net/cert/nss_cert_database.h"
@@ -51,10 +54,42 @@
 
 namespace {
 
-constexpr char kFakeUserName[] = "test@example.com";
+constexpr char kFileName1[] = "client_1";
+constexpr char kFileName2[] = "client_2";
+constexpr char kFileName3[] = "client_3";
+constexpr char kFileName4[] = "client_4";
+
 constexpr char kFakeExtensionId[] = "fakeextensionid";
 
-const std::vector<std::string> kCertFiles = {"client_1", "client_2"};
+// Contains information needed for test cert parameters.
+struct TestCertData {
+  TestCertData(const std::string& file_name,
+               bool is_corporate_usage,
+               keymaster::mojom::ChapsSlot slot)
+      : file_name(file_name),
+        is_corporate_usage(is_corporate_usage),
+        slot(slot) {
+    // Keys in system slot must be corporate usage.
+    DCHECK(slot != keymaster::mojom::ChapsSlot::kSystem || is_corporate_usage);
+  }
+  TestCertData(const TestCertData&) = default;
+  bool operator==(const TestCertData& other) const {
+    return std::tie(file_name, is_corporate_usage, slot) ==
+           std::tie(other.file_name, other.is_corporate_usage, other.slot);
+  }
+
+  std::string file_name;
+  bool is_corporate_usage;
+  keymaster::mojom::ChapsSlot slot;
+};
+
+// Associates a |test_data| to its |nss_cert| once installed.
+struct InstalledTestCert {
+  InstalledTestCert(TestCertData test_data, net::ScopedCERTCertificate nss_cert)
+      : test_data(test_data), nss_cert(std::move(nss_cert)) {}
+  TestCertData test_data;
+  net::ScopedCERTCertificate nss_cert;
+};
 
 std::string GetDerCert64(CERTCertificate* cert) {
   std::string der_cert;
@@ -140,353 +175,536 @@
   return std::make_unique<CertStoreService>(profile, std::move(installer));
 }
 
+// The following series of functions related to IsSystemSlotAvailable use the
+// NSSCertDatabase. The cert database is accessed through a raw pointer with
+// limited lifetime guarantees and is not thread safe. Namely, the cert database
+// is guaranteed valid for the single IO thread task where it was received.
+//
+// Furthermore, creating an NssCertDatabaseGetter requires a BrowserContext,
+// which can only be accessed on the UI thread.
+//
+// ListCerts and related functions are implemented to make sure the above
+// requirements are respected. Here's a diagram of the interaction between UI
+// and IO threads.
+//
+//             UI Thread                        IO Thread
+//
+//       IsSystemSlotAvailable
+//                 |
+//       run_loop.QuitClosure
+//                 |
+//     CreateNSSCertDatabaseGetter
+//                 |
+//                 \--------------------------------v
+//                                 IsSystemSlotAvailableWithDbGetterOnIO
+//                                                  |
+//                                         database_getter.Run
+//                                                  |
+//                                       IsSystemSlotAvailableOnIO
+//                                                  |
+//                                            GetSystemSlot
+//                                                  |
+//                                           quit_closure.Run
+
+void IsSystemSlotAvailableOnIO(bool* out_system_slot_available,
+                               base::OnceClosure done_closure,
+                               net::NSSCertDatabase* cert_db) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  *out_system_slot_available = cert_db->GetSystemSlot() != nullptr;
+  std::move(done_closure).Run();
+}
+
+void IsSystemSlotAvailableWithDbGetterOnIO(
+    NssCertDatabaseGetter database_getter,
+    bool* out_system_slot_available,
+    base::OnceClosure done_closure) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  auto did_get_cert_db_split_callback = base::SplitOnceCallback(
+      base::BindOnce(&IsSystemSlotAvailableOnIO, out_system_slot_available,
+                     std::move(done_closure)));
+  net::NSSCertDatabase* cert_db =
+      std::move(database_getter)
+          .Run(std::move(did_get_cert_db_split_callback.first));
+  if (cert_db) {
+    std::move(did_get_cert_db_split_callback.second).Run(cert_db);
+  }
+}
+
+// Returns trus if the test system slot was setup correctly and is available.
+bool IsSystemSlotAvailable(Profile* profile) {
+  // |profile| must be accessed on the UI thread.
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  base::RunLoop run_loop;
+  bool system_slot_available = false;
+  // The NssCertDatabaseGetter must be posted to the IO thread immediately.
+  content::GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(IsSystemSlotAvailableWithDbGetterOnIO,
+                     CreateNSSCertDatabaseGetter(profile),
+                     &system_slot_available, run_loop.QuitClosure()));
+  run_loop.Run();
+  return system_slot_available;
+}
+
+// Returns the number of corporate usage certs in |test_certs|.
+size_t CountCorporateUsage(const std::vector<TestCertData>& test_certs) {
+  return std::count_if(test_certs.begin(), test_certs.end(),
+                       [](const TestCertData& test_data) {
+                         return test_data.is_corporate_usage;
+                       });
+}
+
+// Deletes the given |cert| from |cert_db|.
+void DeleteCertAndKey(CERTCertificate* cert,
+                      base::OnceClosure done_callback,
+                      net::NSSCertDatabase* cert_db) {
+  base::ScopedAllowBlockingForTesting allow_io;
+  EXPECT_TRUE(cert_db->DeleteCertAndKey(cert));
+  std::move(done_callback).Run();
+}
+
+// Called once a key has been registered as corporate usage.
+void OnKeyRegisteredForCorporateUsage(base::OnceClosure done_callback,
+                                      bool is_error,
+                                      crosapi::mojom::KeystoreError error) {
+  ASSERT_FALSE(is_error) << static_cast<int>(error);
+  std::move(done_callback).Run();
+}
+
+// Uses |service| to register |cert| as corporate usage.
+void RegisterCorporateKeyWithService(
+    CERTCertificate* cert,
+    base::OnceClosure done_callback,
+    std::unique_ptr<chromeos::platform_keys::ExtensionKeyPermissionsService>
+        service) {
+  std::string client_cert_spki(
+      cert->derPublicKey.data,
+      cert->derPublicKey.data + cert->derPublicKey.len);
+  service->RegisterKeyForCorporateUsage(
+      client_cert_spki, base::BindOnce(&OnKeyRegisteredForCorporateUsage,
+                                       std::move(done_callback)));
+}
+
 }  // namespace
 
-class CertStoreServiceTest : public MixinBasedInProcessBrowserTest {
+class CertStoreServiceTest
+    : public MixinBasedInProcessBrowserTest,
+      public ::testing::WithParamInterface<std::vector<TestCertData>> {
+ public:
+  CertStoreServiceTest() = default;
+  CertStoreServiceTest(const CertStoreServiceTest& other) = delete;
+  CertStoreServiceTest& operator=(const CertStoreServiceTest&) = delete;
+
  protected:
-  // MixinBasedInProcessBrowserTest:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line);
+  void SetUpCommandLine(base::CommandLine* command_line) override;
 
-    arc::SetArcAvailableCommandLineForTesting(command_line);
+  void SetUpInProcessBrowserTestFixture() override;
 
-    policy_helper_ = std::make_unique<policy::UserPolicyTestHelper>(
-        kFakeUserName, &local_policy_server_);
-    policy_helper_->SetPolicy(
-        base::DictionaryValue() /* empty mandatory policy */,
-        base::DictionaryValue() /* empty recommended policy */);
+  void SetUpOnMainThread() override;
 
-    command_line->AppendSwitchASCII(chromeos::switches::kLoginUser,
-                                    kFakeUserName);
-    command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile,
-                                    TestingProfile::kTestUserProfileDir);
-    // Don't require policy for our sessions - this is required because
-    // this test creates a secondary profile synchronously, so we need to
-    // let the policy code know not to expect cached policy.
-    command_line->AppendSwitchASCII(chromeos::switches::kProfileRequiresPolicy,
-                                    "false");
+  void TearDownOnMainThread() override;
 
-    // Tell the policy subsystem to wait for an initial policy load, even
-    // though we are using a synchronously loaded profile.
-    // TODO(edmanp): `Update this test to properly use an asynchronously loaded
-    // user profile and remove the use of this flag (crbug.com/795737).
-    command_line->AppendSwitchASCII(
-        chromeos::switches::kWaitForInitialPolicyFetchForTest, "true");
-  }
+  void TearDownInProcessBrowserTestFixture() override;
 
-  void SetUp() override {
-    chromeos::platform_keys::PlatformKeysServiceFactory::GetInstance()
-        ->SetTestingMode(true);
+  // Installs the given |certs_to_setup| in the NSS database.
+  void SetUpCerts(const std::vector<TestCertData>& certs_to_setup);
 
-    MixinBasedInProcessBrowserTest::SetUp();
-  }
+  // Registers the given |cert| as corporate usage through platform keys.
+  void RegisterCorporateKey(CERTCertificate* cert);
 
-  void SetUpOnMainThread() override {
-    MixinBasedInProcessBrowserTest::SetUpOnMainThread();
+  // Deletes the given |cert| from the NSS cert database.
+  void DeleteCert(CERTCertificate* cert);
 
-    policy_helper_->WaitForInitialPolicy(browser()->profile());
+  // Verifies the expected |test_certs| are installed correctly.
+  void CheckInstalledCerts(std::vector<TestCertData> test_certs,
+                           CertStoreService* service);
 
-    // Init ArcSessionManager for testing.
-    ArcServiceLauncher::Get()->ResetForTesting();
+  // Returns the profile for the |affiliation_mixin_| account.
+  Profile* profile();
 
-    chromeos::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
+  // Owned by the CertStoreService instance.
+  FakeArcCertInstaller* installer_;
 
-    browser()->profile()->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true);
-    browser()->profile()->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted,
-                                                 true);
+  std::vector<InstalledTestCert> installed_certs_;
 
-    ArcKeymasterBridge::GetFactory()->SetTestingFactoryAndUse(
-        browser()->profile(),
-        base::BindRepeating(&BuildFakeArcKeymasterBridge));
-    auto* keymaster_bridge =
-        ArcKeymasterBridge::GetForBrowserContext(browser()->profile());
-    keymaster_bridge_ = static_cast<FakeArcKeymasterBridge*>(keymaster_bridge);
-
-    auto installer = std::make_unique<FakeArcCertInstaller>(
-        browser()->profile(), std::make_unique<policy::RemoteCommandsQueue>());
-    installer_ = installer.get();
-    CertStoreService::GetFactory()->SetTestingFactoryAndUse(
-        browser()->profile(),
-        base::BindRepeating(&BuildCertStoreService,
-                            base::Passed(std::move(installer))));
-
-    ArcServiceLauncher::Get()->OnPrimaryUserProfilePrepared(
-        browser()->profile());
-  }
-
-  void TearDownOnMainThread() override {
-    // Since ArcServiceLauncher is (re-)set up with profile() in
-    // SetUpOnMainThread() it is necessary to Shutdown() before the profile()
-    // is destroyed. ArcServiceLauncher::Shutdown() will be called again on
-    // fixture destruction (because it is initialized with the original Profile
-    // instance in fixture, once), but it should be no op.
-    ArcServiceLauncher::Get()->Shutdown();
-    chromeos::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(false);
-    MixinBasedInProcessBrowserTest::TearDownOnMainThread();
-  }
-
-  void TearDown() override {
-    MixinBasedInProcessBrowserTest::TearDown();
-
-    chromeos::platform_keys::PlatformKeysServiceFactory::GetInstance()
-        ->SetTestingMode(false);
-  }
-
-  void RegisterCorporateKey(CERTCertificate* cert) {
-    base::RunLoop run_loop;
-    chromeos::platform_keys::ExtensionKeyPermissionsServiceFactory::
-        GetForBrowserContextAndExtension(
-            base::BindOnce(&CertStoreServiceTest::GotPermissionsForExtension,
-                           base::Unretained(this), cert,
-                           run_loop.QuitClosure()),
-            browser()->profile(), kFakeExtensionId);
-    run_loop.Run();
-  }
-
-  void SetUpCerts(const std::vector<std::string>& keys_file_names,
-                  bool is_corporate_usage_key) {
-    // Read certs from files.
-    base::RunLoop loop;
-    GetNSSCertDatabaseForProfile(
-        browser()->profile(),
-        base::BindOnce(&CertStoreServiceTest::SetUpTestClientCerts,
-                       base::Unretained(this), keys_file_names,
-                       loop.QuitClosure()));
-    loop.Run();
-    // Register certs for corporate usage if needed.
-    for (auto& cert : client_certs_) {
-      // Certificates must be imported.
-      ASSERT_TRUE(cert);
-      if (is_corporate_usage_key)
-        RegisterCorporateKey(cert.get());
-    }
-
-    // Import certs into database.
-    {
-      base::RunLoop loop;
-      GetNSSCertDatabaseForProfile(
-          browser()->profile(),
-          base::BindOnce(&CertStoreServiceTest::ImportTestClientCerts,
-                         base::Unretained(this), loop.QuitClosure()));
-      loop.Run();
-    }
-  }
-
-  void DeleteCert(CERTCertificate* cert) {
-    base::RunLoop loop;
-    GetNSSCertDatabaseForProfile(
-        browser()->profile(),
-        base::BindOnce(&CertStoreServiceTest::DeleteCertAndKey,
-                       base::Unretained(this), cert, loop.QuitClosure()));
-    loop.Run();
-  }
-
-  bool PlaceholdersContainId(const std::string& id) {
-    for (const auto& key : keymaster_bridge()->placeholder_keys()) {
-      if (key->key_data->is_chaps_key_data() &&
-          key->key_data->get_chaps_key_data()->id == id) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  void CheckInstalledCerts(size_t installed_cert_num,
-                           CertStoreService* service) {
-    EXPECT_EQ(installed_cert_num, client_certs_.size());
-    EXPECT_EQ(installed_cert_num, installer()->certs().size());
-    EXPECT_EQ(installed_cert_num, service->get_required_cert_names().size());
-    EXPECT_EQ(installed_cert_num,
-              keymaster_bridge()->placeholder_keys().size());
-
-    for (const auto& cert_name : service->get_required_cert_names()) {
-      bool found = false;
-      // Check the required cert is installed.
-      ASSERT_TRUE(installer()->certs().count(cert_name));
-      for (const auto& cert : client_certs_) {
-        // Check the required cert is one of the imported for the test
-        // certificates.
-        if (GetDerCert64(cert.get()) == installer()->certs()[cert_name]) {
-          // Check nickname.
-          EXPECT_EQ(x509_certificate_model::GetCertNameOrNickname(cert.get()),
-                    cert_name);
-          found = true;
-          // Check KeyInfo.
-          auto key_info =
-              service->GetKeyInfoForDummySpki(installer()->certs()[cert_name]);
-          EXPECT_TRUE(key_info.has_value());
-          EXPECT_EQ(key_info.value().nickname, cert_name);
-          int slot_id;
-          // Check CKA_ID.
-          std::string hex_encoded_id = base::HexEncode(
-              key_info.value().id.data(), key_info.value().id.size());
-          EXPECT_EQ(hex_encoded_id,
-                    chromeos::NetworkCertLoader::GetPkcs11IdAndSlotForCert(
-                        cert.get(), &slot_id));
-          EXPECT_TRUE(PlaceholdersContainId(key_info.value().id));
-          break;
-        }
-      }
-      // Check the required cert was found.
-      EXPECT_TRUE(found);
-    }
-  }
-
-  FakeArcCertInstaller* installer() { return installer_; }
-
-  FakeArcKeymasterBridge* keymaster_bridge() { return keymaster_bridge_; }
-
-  net::ScopedCERTCertificateList client_certs_;
+  chromeos::DeviceStateMixin device_state_{
+      &mixin_host_,
+      chromeos::DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
+  policy::DevicePolicyCrosTestHelper device_policy_helper_;
+  policy::AffiliationMixin affiliation_mixin_{&mixin_host_,
+                                              &device_policy_helper_};
 
  private:
-  void OnKeyRegisteredForCorporateUsage(
-      std::unique_ptr<chromeos::platform_keys::ExtensionKeyPermissionsService>
-          extension_key_permissions_service,
-      base::OnceClosure done_callback,
-      bool is_error,
-      crosapi::mojom::KeystoreError error) {
-    ASSERT_FALSE(is_error) << static_cast<int>(error);
-    std::move(done_callback).Run();
-  }
-
-  // Register only client_cert1_ for corporate usage to test that
-  // client_cert2_ is not allowed.
-  void GotPermissionsForExtension(
-      CERTCertificate* cert,
-      base::OnceClosure done_callback,
-      std::unique_ptr<chromeos::platform_keys::ExtensionKeyPermissionsService>
-          extension_key_permissions_service) {
-    auto* extension_key_permissions_service_unowned =
-        extension_key_permissions_service.get();
-    std::string client_cert_spki(
-        cert->derPublicKey.data,
-        cert->derPublicKey.data + cert->derPublicKey.len);
-    extension_key_permissions_service_unowned->RegisterKeyForCorporateUsage(
-        client_cert_spki,
-        base::BindOnce(&CertStoreServiceTest::OnKeyRegisteredForCorporateUsage,
-                       base::Unretained(this),
-                       std::move(extension_key_permissions_service),
-                       std::move(done_callback)));
-  }
-
-  void SetUpTestClientCerts(const std::vector<std::string>& key_file_names,
+  // Creates ScopedCERTCertificates for each |certs_to_setup| and appends them
+  // to |installed_certs_|.
+  void SetUpTestClientCerts(const std::vector<TestCertData>& certs_to_setup,
                             base::OnceClosure done_callback,
-                            net::NSSCertDatabase* cert_db) {
-    for (const auto& file_name : key_file_names) {
-      base::ScopedAllowBlockingForTesting allow_io;
-      net::ImportSensitiveKeyFromFile(net::GetTestCertsDirectory(),
-                                      file_name + ".pk8",
-                                      cert_db->GetPrivateSlot().get());
-      net::ScopedCERTCertificateList certs =
-          net::CreateCERTCertificateListFromFile(
-              net::GetTestCertsDirectory(), file_name + ".pem",
-              net::X509Certificate::FORMAT_AUTO);
-      EXPECT_EQ(1U, certs.size());
-      if (certs.size() != 1U) {
-        std::move(done_callback).Run();
-        return;
-      }
+                            net::NSSCertDatabase* cert_db);
 
-      client_certs_.emplace_back(
-          net::x509_util::DupCERTCertificate(certs[0].get()));
-    }
-    std::move(done_callback).Run();
-  }
-
+  // Imports the list of |installed_certs_| into the NSS |cert_db|.
   void ImportTestClientCerts(base::OnceClosure done_callback,
-                             net::NSSCertDatabase* cert_db) {
-    for (const auto& cert : client_certs_) {
-      // Import user certificate properly how it's done in PlatfromKeys.
-      cert_db->ImportUserCert(cert.get());
-    }
-    std::move(done_callback).Run();
-  }
+                             net::NSSCertDatabase* cert_db);
 
-  void DeleteCertAndKey(CERTCertificate* cert,
-                        base::OnceClosure done_callback,
-                        net::NSSCertDatabase* cert_db) {
-    base::ScopedAllowBlockingForTesting allow_io;
-    EXPECT_TRUE(cert_db->DeleteCertAndKey(cert));
-    std::move(done_callback).Run();
-  }
+  // Checks that |keymaster_bridge_->placeholder_keys()| contains a key with
+  // given |id| and |slot|.
+  bool PlaceholdersContainIdAndSlot(const std::string& id,
+                                    keymaster::mojom::ChapsSlot slot);
 
-  std::unique_ptr<policy::UserPolicyTestHelper> policy_helper_;
-  chromeos::LocalPolicyTestServerMixin local_policy_server_{&mixin_host_};
+  // Initializes |test_system_slot_|.
+  void SetUpTestSystemSlot();
 
-  // Owned by service.
-  FakeArcCertInstaller* installer_;
+  void SetUpTestSystemSlotOnIO(bool* out_system_slot_constructed_successfully);
+
+  // Destroys |test_system_slot_|.
+  void TearDownTestSystemSlot();
+
+  void TearDownTestSystemSlotOnIO();
+
+  std::unique_ptr<crypto::ScopedTestSystemNSSKeySlot> test_system_slot_;
+
+  // Owned by the CertStoreService instance.
   FakeArcKeymasterBridge* keymaster_bridge_;
 };
 
-// Test no corporate usage keys.
-IN_PROC_BROWSER_TEST_F(CertStoreServiceTest, Basic) {
-  CertStoreService* service =
-      CertStoreService::GetForBrowserContext(browser()->profile());
-  ASSERT_TRUE(service);
-
-  // Import 2 certs into DB. No corporate usage keys.
-  ASSERT_NO_FATAL_FAILURE(
-      SetUpCerts(kCertFiles, false /* is_corporate_usage */));
-  installer()->Wait();
-  installer()->RunCompletionCallback(true /* success */);
-
-  EXPECT_EQ(kCertFiles.size(), client_certs_.size());
-  // No corporate usage keys installed.
-  EXPECT_TRUE(installer()->certs().empty());
-  EXPECT_TRUE(service->get_required_cert_names().empty());
-  EXPECT_TRUE(keymaster_bridge()->placeholder_keys().empty());
+void CertStoreServiceTest::SetUpCommandLine(base::CommandLine* command_line) {
+  MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line);
+  arc::SetArcAvailableCommandLineForTesting(command_line);
+  policy::AffiliationTestHelper::AppendCommandLineSwitchesForLoginManager(
+      command_line);
 }
 
-// Test installation of 2 corporate usage keys.
-IN_PROC_BROWSER_TEST_F(CertStoreServiceTest, InstalledCorporateUsageKeys) {
-  CertStoreService* service =
-      CertStoreService::GetForBrowserContext(browser()->profile());
-  EXPECT_EQ(browser()->profile(),
-            Profile::FromBrowserContext(browser()->profile()));
+void CertStoreServiceTest::SetUpInProcessBrowserTestFixture() {
+  MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+  chromeos::platform_keys::PlatformKeysServiceFactory::GetInstance()
+      ->SetTestingMode(true);
+}
+
+void CertStoreServiceTest::SetUpOnMainThread() {
+  MixinBasedInProcessBrowserTest::SetUpOnMainThread();
+
+  // Pre tests need no further setup.
+  if (content::IsPreTest())
+    return;
+
+  policy::AffiliationTestHelper::LoginUser(affiliation_mixin_.account_id());
+
+  // Use fake ArcKeymasterBridge.
+  ArcKeymasterBridge::GetFactory()->SetTestingFactoryAndUse(
+      profile(), base::BindRepeating(&BuildFakeArcKeymasterBridge));
+  auto* keymaster_bridge = ArcKeymasterBridge::GetForBrowserContext(profile());
+  keymaster_bridge_ = static_cast<FakeArcKeymasterBridge*>(keymaster_bridge);
+
+  // Use fake ArcCertInstaller in CertStoreService.
+  auto installer = std::make_unique<FakeArcCertInstaller>(
+      profile(), std::make_unique<policy::RemoteCommandsQueue>());
+  installer_ = installer.get();
+  CertStoreService::GetFactory()->SetTestingFactoryAndUse(
+      profile(), base::BindRepeating(&BuildCertStoreService,
+                                     base::Passed(std::move(installer))));
+
+  // Set up a system slot so tests can access device certs.
+  ASSERT_NO_FATAL_FAILURE(SetUpTestSystemSlot());
+  ASSERT_TRUE(IsSystemSlotAvailable(profile()));
+}
+
+void CertStoreServiceTest::TearDownOnMainThread() {
+  TearDownTestSystemSlot();
+  MixinBasedInProcessBrowserTest::TearDownOnMainThread();
+}
+
+void CertStoreServiceTest::TearDownInProcessBrowserTestFixture() {
+  chromeos::platform_keys::PlatformKeysServiceFactory::GetInstance()
+      ->SetTestingMode(false);
+  MixinBasedInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
+}
+
+void CertStoreServiceTest::SetUpCerts(
+    const std::vector<TestCertData>& certs_to_setup) {
+  // Remember current size of |installed_certs_| before new certs.
+  size_t initial_size = installed_certs_.size();
+
+  // Read certs from files.
+  base::RunLoop loop;
+  GetNSSCertDatabaseForProfile(
+      profile(), base::BindOnce(&CertStoreServiceTest::SetUpTestClientCerts,
+                                base::Unretained(this), certs_to_setup,
+                                loop.QuitClosure()));
+  loop.Run();
+
+  // Verify |certs_to_setup.size()| new certs have been installed.
+  ASSERT_EQ(installed_certs_.size(), certs_to_setup.size() + initial_size);
+
+  // Register newly installed certs for corporate usage if needed.
+  for (size_t i = initial_size; i < installed_certs_.size(); ++i) {
+    const InstalledTestCert& cert = installed_certs_[i];
+    if (cert.test_data.is_corporate_usage)
+      RegisterCorporateKey(cert.nss_cert.get());
+  }
+
+  // Import certs into database.
+  {
+    base::RunLoop loop;
+    GetNSSCertDatabaseForProfile(
+        profile(), base::BindOnce(&CertStoreServiceTest::ImportTestClientCerts,
+                                  base::Unretained(this), loop.QuitClosure()));
+    loop.Run();
+  }
+}
+
+void CertStoreServiceTest::RegisterCorporateKey(CERTCertificate* cert) {
+  base::RunLoop run_loop;
+  chromeos::platform_keys::ExtensionKeyPermissionsServiceFactory::
+      GetForBrowserContextAndExtension(
+          base::BindOnce(&RegisterCorporateKeyWithService, cert,
+                         run_loop.QuitClosure()),
+          profile(), kFakeExtensionId);
+  run_loop.Run();
+}
+
+void CertStoreServiceTest::DeleteCert(CERTCertificate* cert) {
+  base::RunLoop loop;
+  GetNSSCertDatabaseForProfile(
+      profile(), base::BindOnce(&DeleteCertAndKey, cert, loop.QuitClosure()));
+  loop.Run();
+  installed_certs_.pop_back();
+}
+
+void CertStoreServiceTest::CheckInstalledCerts(
+    std::vector<TestCertData> test_certs,
+    CertStoreService* service) {
+  // Verify the number of corporate usage certs reported is correct.
+  EXPECT_EQ(CountCorporateUsage(test_certs), installer_->certs().size());
+  EXPECT_EQ(CountCorporateUsage(test_certs),
+            service->get_required_cert_names().size());
+  EXPECT_EQ(CountCorporateUsage(test_certs),
+            keymaster_bridge_->placeholder_keys().size());
+
+  // Verify |test_certs| and |installed_certs_| have matching elements.
+  ASSERT_EQ(test_certs.size(), installed_certs_.size());
+  for (size_t i = 0; i < installed_certs_.size(); ++i)
+    EXPECT_EQ(test_certs[i], installed_certs_[i].test_data);
+
+  for (const auto& cert_name : service->get_required_cert_names()) {
+    bool found = false;
+    // Check the required cert is installed.
+    ASSERT_TRUE(installer_->certs().count(cert_name));
+    for (const auto& cert : installed_certs_) {
+      // Check the required cert is one of the installed test certificates.
+      const net::ScopedCERTCertificate& nss_cert = cert.nss_cert;
+
+      // Skip until |cert| corresponds to the current |cert_name|.
+      if (GetDerCert64(nss_cert.get()) != installer_->certs()[cert_name])
+        continue;
+
+      // Check nickname.
+      EXPECT_EQ(x509_certificate_model::GetCertNameOrNickname(nss_cert.get()),
+                cert_name);
+      found = true;
+      // Check KeyInfo.
+      auto key_info =
+          service->GetKeyInfoForDummySpki(installer_->certs()[cert_name]);
+      EXPECT_TRUE(key_info.has_value());
+      EXPECT_EQ(key_info.value().nickname, cert_name);
+      // Check CKA_ID and slot.
+      int slot_id;
+      std::string hex_encoded_id = base::HexEncode(key_info.value().id.data(),
+                                                   key_info.value().id.size());
+      EXPECT_EQ(hex_encoded_id,
+                chromeos::NetworkCertLoader::GetPkcs11IdAndSlotForCert(
+                    nss_cert.get(), &slot_id));
+      EXPECT_TRUE(PlaceholdersContainIdAndSlot(key_info.value().id,
+                                               cert.test_data.slot));
+      break;
+    }
+    // Check the required cert was found.
+    EXPECT_TRUE(found);
+  }
+}
+
+Profile* CertStoreServiceTest::profile() {
+  return chromeos::ProfileHelper::Get()->GetProfileByAccountId(
+      affiliation_mixin_.account_id());
+}
+
+void CertStoreServiceTest::SetUpTestClientCerts(
+    const std::vector<TestCertData>& certs_to_setup,
+    base::OnceClosure done_callback,
+    net::NSSCertDatabase* cert_db) {
+  for (const auto& test_data : certs_to_setup) {
+    base::ScopedAllowBlockingForTesting allow_io;
+    net::ImportSensitiveKeyFromFile(
+        net::GetTestCertsDirectory(), test_data.file_name + ".pk8",
+        test_data.slot == keymaster::mojom::ChapsSlot::kUser
+            ? cert_db->GetPrivateSlot().get()
+            : cert_db->GetSystemSlot().get());
+    net::ScopedCERTCertificateList certs =
+        net::CreateCERTCertificateListFromFile(
+            net::GetTestCertsDirectory(), test_data.file_name + ".pem",
+            net::X509Certificate::FORMAT_AUTO);
+    ASSERT_EQ(1U, certs.size());
+
+    installed_certs_.emplace_back(
+        test_data, net::x509_util::DupCERTCertificate(certs[0].get()));
+  }
+  std::move(done_callback).Run();
+}
+
+void CertStoreServiceTest::ImportTestClientCerts(
+    base::OnceClosure done_callback,
+    net::NSSCertDatabase* cert_db) {
+  for (const auto& cert : installed_certs_) {
+    // Import user certificate properly how it's done in PlatformKeys.
+    cert_db->ImportUserCert(cert.nss_cert.get());
+  }
+  std::move(done_callback).Run();
+}
+
+bool CertStoreServiceTest::PlaceholdersContainIdAndSlot(
+    const std::string& id,
+    keymaster::mojom::ChapsSlot slot) {
+  for (const auto& key : keymaster_bridge_->placeholder_keys()) {
+    if (key->key_data->is_chaps_key_data() &&
+        key->key_data->get_chaps_key_data()->id == id &&
+        key->key_data->get_chaps_key_data()->slot == slot) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void CertStoreServiceTest::SetUpTestSystemSlot() {
+  bool system_slot_constructed_successfully = false;
+  base::RunLoop loop;
+  content::GetIOThreadTaskRunner({})->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&CertStoreServiceTest::SetUpTestSystemSlotOnIO,
+                     base::Unretained(this),
+                     &system_slot_constructed_successfully),
+      loop.QuitClosure());
+  loop.Run();
+  ASSERT_TRUE(system_slot_constructed_successfully);
+}
+
+void CertStoreServiceTest::SetUpTestSystemSlotOnIO(
+    bool* out_system_slot_constructed_successfully) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>();
+  *out_system_slot_constructed_successfully =
+      test_system_slot_->ConstructedSuccessfully();
+}
+
+void CertStoreServiceTest::TearDownTestSystemSlot() {
+  if (!test_system_slot_)
+    return;
+
+  base::RunLoop loop;
+  content::GetIOThreadTaskRunner({})->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&CertStoreServiceTest::TearDownTestSystemSlotOnIO,
+                     base::Unretained(this)),
+      loop.QuitClosure());
+  loop.Run();
+}
+
+void CertStoreServiceTest::TearDownTestSystemSlotOnIO() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  test_system_slot_.reset();
+}
+
+IN_PROC_BROWSER_TEST_P(CertStoreServiceTest, PRE_HandlesCorporateUsageCerts) {
+  policy::AffiliationTestHelper::PreLoginUser(affiliation_mixin_.account_id());
+}
+
+IN_PROC_BROWSER_TEST_P(CertStoreServiceTest, HandlesCorporateUsageCerts) {
+  CertStoreService* service = CertStoreService::GetForBrowserContext(profile());
   ASSERT_TRUE(service);
 
-  size_t installed_cert_num = 0;
+  // Install all certs from parameter at once.
+  ASSERT_NO_FATAL_FAILURE(SetUpCerts(GetParam()));
+  installer_->Wait();
+  installer_->RunCompletionCallback(true /* success */);
 
-  // Import and register corporate certificates.
-  for (const auto& file : kCertFiles) {
+  // Verify all certs are installed correctly.
+  ASSERT_NO_FATAL_FAILURE(CheckInstalledCerts(GetParam(), service));
+}
+
+IN_PROC_BROWSER_TEST_P(CertStoreServiceTest,
+                       PRE_InstallsAndDeletesCorporateUsageCerts) {
+  policy::AffiliationTestHelper::PreLoginUser(affiliation_mixin_.account_id());
+}
+
+IN_PROC_BROWSER_TEST_P(CertStoreServiceTest,
+                       InstallsAndDeletesCorporateUsageCerts) {
+  CertStoreService* service = CertStoreService::GetForBrowserContext(profile());
+  ASSERT_TRUE(service);
+
+  // Install certs from parameter one by one.
+  for (size_t i = 0; i < GetParam().size(); ++i) {
+    ASSERT_NO_FATAL_FAILURE(SetUpCerts({GetParam()[i]}));
+    installer_->Wait();
+    installer_->RunCompletionCallback(true /* success */);
+
+    // Verify only the first (i+1) certs are installed so far.
     ASSERT_NO_FATAL_FAILURE(
-        SetUpCerts({file}, true /* is_corporate_usage_key */));
-    installer()->Wait();
-    installer()->RunCompletionCallback(true /* success */);
+        CheckInstalledCerts(std::vector<TestCertData>(
+                                GetParam().begin(), GetParam().begin() + i + 1),
+                            service));
+  }
 
-    installed_cert_num++;
-    CheckInstalledCerts(installed_cert_num, service);
+  // Uninstall certs from parameter one by one, from last to first.
+  for (size_t i = GetParam().size(); i--;) {
+    DeleteCert(installed_certs_.back().nss_cert.get());
+    installer_->Wait();
+    installer_->RunCompletionCallback(true /* success */);
+
+    // Verify only the first i certs are left after the uninstall.
+    ASSERT_NO_FATAL_FAILURE(CheckInstalledCerts(
+        std::vector<TestCertData>(GetParam().begin(), GetParam().begin() + i),
+        service));
   }
 }
 
-// Test uninstallation of 2 corporate usage keys.
-IN_PROC_BROWSER_TEST_F(CertStoreServiceTest, UninstalledCorporateUsageKeys) {
-  CertStoreService* service =
-      CertStoreService::GetForBrowserContext(browser()->profile());
-  EXPECT_EQ(browser()->profile(),
-            Profile::FromBrowserContext(browser()->profile()));
-  ASSERT_TRUE(service);
-
-  installer()->Wait();
-  installer()->RunCompletionCallback(true /* success */);
-
-  CheckInstalledCerts(0, service);
-  ASSERT_NO_FATAL_FAILURE(
-      SetUpCerts({kCertFiles}, true /* is_corporate_usage_key */));
-  installer()->Wait();
-  installer()->RunCompletionCallback(true /* success */);
-  CheckInstalledCerts(kCertFiles.size(), service);
-
-  size_t installed_cert_num = kCertFiles.size();
-  while (!client_certs_.empty()) {
-    DeleteCert(client_certs_.back().get());
-    installer()->Wait();
-    installer()->RunCompletionCallback(true /* success */);
-
-    client_certs_.pop_back();
-    installed_cert_num--;
-    CheckInstalledCerts(installed_cert_num, service);
-  }
-}
+INSTANTIATE_TEST_SUITE_P(
+    CertStoreTests,
+    CertStoreServiceTest,
+    ::testing::Values(
+        // No corporate usage keys.
+        std::vector<TestCertData>{
+            TestCertData(kFileName1,
+                         false /* is_corporate_usage */,
+                         keymaster::mojom::ChapsSlot::kUser),
+            TestCertData(kFileName2,
+                         false /* is_corporate_usage */,
+                         keymaster::mojom::ChapsSlot::kUser)},
+        // Corporate usage keys in user slot.
+        std::vector<TestCertData>{
+            TestCertData(kFileName1,
+                         true /* is_corporate_usage */,
+                         keymaster::mojom::ChapsSlot::kUser),
+            TestCertData(kFileName2,
+                         true /* is_corporate_usage */,
+                         keymaster::mojom::ChapsSlot::kUser)},
+        // Corporate usage keys in system slot.
+        std::vector<TestCertData>{
+            TestCertData(kFileName1,
+                         true /* is_corporate_usage */,
+                         keymaster::mojom::ChapsSlot::kSystem),
+            TestCertData(kFileName2,
+                         true /* is_corporate_usage */,
+                         keymaster::mojom::ChapsSlot::kSystem)},
+        // Corporate usage keys in both slots.
+        std::vector<TestCertData>{
+            TestCertData(kFileName1,
+                         true /* is_corporate_usage */,
+                         keymaster::mojom::ChapsSlot::kUser),
+            TestCertData(kFileName2,
+                         true /* is_corporate_usage */,
+                         keymaster::mojom::ChapsSlot::kSystem),
+            TestCertData(kFileName3,
+                         false /* is_corporate_usage */,
+                         keymaster::mojom::ChapsSlot::kUser),
+            TestCertData(kFileName4,
+                         true /* is_corporate_usage */,
+                         keymaster::mojom::ChapsSlot::kSystem)}));
 
 }  // namespace arc
diff --git a/chrome/browser/ash/assistant/assistant_util.cc b/chrome/browser/ash/assistant/assistant_util.cc
index a190320..b4979f6 100644
--- a/chrome/browser/ash/assistant/assistant_util.cc
+++ b/chrome/browser/ash/assistant/assistant_util.cc
@@ -72,7 +72,6 @@
       NOTREACHED();
       return AssistantAllowedState::DISALLOWED_BY_ACCOUNT_TYPE;
 
-    case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
     case user_manager::NUM_USER_TYPES:
       NOTREACHED();
       return AssistantAllowedState::DISALLOWED_BY_ACCOUNT_TYPE;
diff --git a/chrome/browser/ash/assistant/assistant_util_unittest.cc b/chrome/browser/ash/assistant/assistant_util_unittest.cc
index d8d75b5..4ee0be9 100644
--- a/chrome/browser/ash/assistant/assistant_util_unittest.cc
+++ b/chrome/browser/ash/assistant/assistant_util_unittest.cc
@@ -131,7 +131,6 @@
         EXPECT_EQ(account_id_, fake_user_manager_->GetGuestAccountId());
         return;
       case user_manager::NUM_USER_TYPES:
-      case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
         NOTREACHED();
     }
   }
@@ -162,7 +161,6 @@
       case user_manager::USER_TYPE_GUEST:
         fake_user_manager_->AddGuestUser();
         return;
-      case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
       case user_manager::NUM_USER_TYPES:
         NOTREACHED();
     }
diff --git a/chrome/browser/ash/crosapi/browser_manager.cc b/chrome/browser/ash/crosapi/browser_manager.cc
index 289f8bdd..c5fad163 100644
--- a/chrome/browser/ash/crosapi/browser_manager.cc
+++ b/chrome/browser/ash/crosapi/browser_manager.cc
@@ -38,6 +38,7 @@
 #include "base/system/sys_info.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
+#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/ash/crosapi/browser_loader.h"
 #include "chrome/browser/ash/crosapi/browser_service_host_ash.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
@@ -89,15 +90,6 @@
     "lacros_cannot_launch_notification_id";
 const char kLacrosLauncherNotifierID[] = "lacros_launcher";
 
-// To be sure the lacros is running with neutral priority
-class ThreadPriorityDelegate : public base::LaunchOptions::PreExecDelegate {
- public:
-  void RunAsyncSafe() override {
-    base::PlatformThread::SetCurrentThreadPriority(
-        base::ThreadPriority::NORMAL);
-  }
-};
-
 base::FilePath LacrosLogPath() {
   return browser_util::GetUserDataDir().Append("lacros.log");
 }
@@ -197,6 +189,18 @@
 
 }  // namespace
 
+// To be sure the lacros is running with neutral priority.
+class LacrosThreadPriorityDelegate
+    : public base::LaunchOptions::PreExecDelegate {
+ public:
+  void RunAsyncSafe() override {
+    // SetCurrentThreadPriority() needs file I/O on /proc and /sys.
+    base::ScopedAllowBlocking allow_blocking;
+    base::PlatformThread::SetCurrentThreadPriority(
+        base::ThreadPriority::NORMAL);
+  }
+};
+
 // static
 BrowserManager* BrowserManager::Get() {
   return g_instance;
@@ -594,7 +598,7 @@
                << command_line.GetCommandLineString();
 
   // Lacros-chrome starts with NORMAL priority
-  ThreadPriorityDelegate thread_priority_delegate;
+  LacrosThreadPriorityDelegate thread_priority_delegate;
   options.pre_exec_delegate = &thread_priority_delegate;
 
   // Prepare to invite lacros-chrome to the Mojo universe of Crosapi.
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc
index 2e17267..96812625 100644
--- a/chrome/browser/ash/crosapi/browser_util.cc
+++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -115,7 +115,6 @@
       return true;
     case user_manager::USER_TYPE_GUEST:
     case user_manager::USER_TYPE_PUBLIC_ACCOUNT:
-    case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
     case user_manager::USER_TYPE_KIOSK_APP:
     case user_manager::USER_TYPE_CHILD:
     case user_manager::USER_TYPE_ARC_KIOSK_APP:
diff --git a/chrome/browser/ash/crostini/crostini_manager.cc b/chrome/browser/ash/crostini/crostini_manager.cc
index 1d623d2..d539763 100644
--- a/chrome/browser/ash/crostini/crostini_manager.cc
+++ b/chrome/browser/ash/crostini/crostini_manager.cc
@@ -1014,13 +1014,13 @@
   return is_dev_kvm_present_;
 }
 
-void CrostiniManager::RunSessionStartTasks() {
+void CrostiniManager::MaybeUpdateCrostini() {
   // This is a new user session, perhaps using an old CrostiniManager.
   container_upgrade_prompt_shown_.clear();
   base::ThreadPool::PostTaskAndReply(
       FROM_HERE, {base::MayBlock()},
       base::BindOnce(&CrostiniManager::CheckPaths),
-      base::BindOnce(&CrostiniManager::MaybeUpgradeCrostiniAfterChecks,
+      base::BindOnce(&CrostiniManager::MaybeUpdateCrostiniAfterChecks,
                      weak_ptr_factory_.GetWeakPtr()));
   // Probe Concierge - if it's still running after an unclean shutdown, a
   // success response will be received.
@@ -1054,7 +1054,7 @@
   is_dev_kvm_present_ = base::PathExists(base::FilePath("/dev/kvm"));
 }
 
-void CrostiniManager::MaybeUpgradeCrostiniAfterChecks() {
+void CrostiniManager::MaybeUpdateCrostiniAfterChecks() {
   if (!CrostiniFeatures::Get()->IsEnabled(profile_)) {
     return;
   }
@@ -1065,6 +1065,8 @@
     upgrade_available_notification_ =
         CrostiniUpgradeAvailableNotification::Show(profile_, base::DoNothing());
   }
+  // TODO(crbug/953544) Remove this once we have transitioned completely to DLC
+  InstallTermina(base::DoNothing(), /*is_initial_install=*/false);
 }
 
 void CrostiniManager::InstallTermina(CrostiniResultCallback callback,
@@ -1093,7 +1095,8 @@
             std::move(callback).Run(res);
           },
           std::move(callback)),
-      is_initial_install);
+      // TODO(crbug/1228109): uncomment when Dlc issues are fixed.
+      /*is_initial_install=*/false);
 }
 
 void CrostiniManager::CancelInstallTermina() {
diff --git a/chrome/browser/ash/crostini/crostini_manager.h b/chrome/browser/ash/crostini/crostini_manager.h
index 6195558..782f5ca 100644
--- a/chrome/browser/ash/crostini/crostini_manager.h
+++ b/chrome/browser/ash/crostini/crostini_manager.h
@@ -220,12 +220,13 @@
   // Returns true if the /dev/kvm directory is present.
   static bool IsDevKvmPresent();
 
-  // Run tasks for session start. Currently this means: checking that /dev/kvm
-  // exists, promting for container upgrade (if needed), and checking if there's
-  // an running VM from a previous crashed session.
-  void RunSessionStartTasks();
+  // Upgrades cros-termina component if the current version is not
+  // compatible. This is a no-op if chromeos::features::kCrostiniUseDlc is
+  // enabled.
+  void MaybeUpdateCrostini();
 
-  // Installs termina using DLC service
+  // Installs termina using either component updater or the DLC service
+  // depending on the value of chromeos::features::kCrostiniUseDlc
   void InstallTermina(CrostiniResultCallback callback, bool is_initial_install);
 
   // Try to cancel a previous InstallTermina call. This is done on a best-effort
@@ -799,13 +800,13 @@
   // Callback for AnsibleManagementService::ConfigureDefaultContainer
   void OnDefaultContainerConfigured(bool success);
 
-  // Helper for CrostiniManager::RunSessionStartTasks. Makes blocking calls to
+  // Helper for CrostiniManager::MaybeUpdateCrostini. Makes blocking calls to
   // check for /dev/kvm.
   static void CheckPaths();
 
-  // Helper for CrostiniManager::RunSessionStartTasks. Separated because
-  // checking for /dev/kvm can block.
-  void MaybeUpgradeCrostiniAfterChecks();
+  // Helper for CrostiniManager::MaybeUpdateCrostini. Separated because the
+  // checking component registration code may block.
+  void MaybeUpdateCrostiniAfterChecks();
 
   void FinishRestart(CrostiniRestarter* restarter, CrostiniResult result);
 
diff --git a/chrome/browser/ash/crostini/crostini_util.cc b/chrome/browser/ash/crostini/crostini_util.cc
index 9d27eae..dc625e7 100644
--- a/chrome/browser/ash/crostini/crostini_util.cc
+++ b/chrome/browser/ash/crostini/crostini_util.cc
@@ -278,6 +278,17 @@
   }
 }
 
+bool MaybeShowCrostiniDialogBeforeLaunch(Profile* profile,
+                                         CrostiniResult result) {
+  if (result == CrostiniResult::OFFLINE_WHEN_UPGRADE_REQUIRED ||
+      result == CrostiniResult::LOAD_COMPONENT_FAILED) {
+    ShowCrostiniUpdateComponentView(profile, CrostiniUISurface::kAppList);
+    VLOG(1) << "Update Component dialog";
+    return true;
+  }
+  return false;
+}
+
 void LaunchCrostiniAppImpl(
     Profile* profile,
     const std::string& app_id,
@@ -336,6 +347,10 @@
                                  "crostini restart to launch app %s failed: %d",
                                  app_id.c_str(), result),
                              result);
+              if (crostini::MaybeShowCrostiniDialogBeforeLaunch(profile,
+                                                                result)) {
+                VLOG(1) << "Crostini restart blocked by dialog";
+              }
               return;
             }
 
diff --git a/chrome/browser/ash/crostini/crostini_util.h b/chrome/browser/ash/crostini/crostini_util.h
index 2236c3a8..1b04ceb 100644
--- a/chrome/browser/ash/crostini/crostini_util.h
+++ b/chrome/browser/ash/crostini/crostini_util.h
@@ -103,6 +103,10 @@
 // the configuration specified by CrostiniAnsiblePlaybook user policy.
 bool ShouldConfigureDefaultContainer(Profile* profile);
 
+// Returns whether a dialog from Crostini is blocking the immediate launch.
+bool MaybeShowCrostiniDialogBeforeLaunch(Profile* profile,
+                                         CrostiniResult result);
+
 using LaunchArg = absl::variant<storage::FileSystemURL, std::string>;
 
 // Launch a Crostini App with a given set of files, given as absolute paths in
diff --git a/chrome/browser/ash/crostini/termina_installer.cc b/chrome/browser/ash/crostini/termina_installer.cc
index 677249c..522816c 100644
--- a/chrome/browser/ash/crostini/termina_installer.cc
+++ b/chrome/browser/ash/crostini/termina_installer.cc
@@ -59,35 +59,43 @@
   auto remove_callback = base::BindOnce(
       [](std::unique_ptr<UninstallResult> ptr) {}, std::move(ptr));
 
-  InstallDlc(
-      base::BindOnce(
-          [](base::WeakPtr<TerminaInstaller> weak_this,
-             base::OnceCallback<void(InstallResult)> callback,
-             bool is_initial_install, base::OnceClosure remove_callback,
-             UninstallResult* uninstall_result_ptr, InstallResult result) {
-            if (!weak_this)
-              return;
+  // Remove whichever version of termina we're *not* using and install the right
+  // one.
+  if (base::FeatureList::IsEnabled(chromeos::features::kCrostiniUseDlc)) {
+    InstallDlc(
+        base::BindOnce(
+            [](base::WeakPtr<TerminaInstaller> weak_this,
+               base::OnceCallback<void(InstallResult)> callback,
+               bool is_initial_install, base::OnceClosure remove_callback,
+               UninstallResult* uninstall_result_ptr, InstallResult result) {
+              if (!weak_this)
+                return;
 
-            // Fallback logic for the transition to DLC.
-            // If we succeeded with DLC, we're good.
-            // If we're running the installer, we can show a useful error
-            // message. Otherwise, try and fall back to installing the
-            // cros-termina component.
-            if (is_initial_install || result == InstallResult::Success) {
-              // Delay removing cros-termina until here so as to avoid messing
-              // up the InstallComponent call below.
-              weak_this->RemoveComponentIfPresent(std::move(remove_callback),
-                                                  uninstall_result_ptr);
-              std::move(callback).Run(result);
-              return;
-            }
-            LOG(ERROR) << "Failed to install termina-dlc, falling back to "
-                          "cros-termina";
-            weak_this->InstallComponent(std::move(callback));
-          },
-          weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-          is_initial_install, std::move(remove_callback), uninstall_result_ptr),
-      is_initial_install);
+              // Fallback logic for the transition to DLC.
+              // If we succeeded with DLC, we're good.
+              // If we're running the installer, we can show a useful error
+              // message. Otherwise, try and fall back to installing the
+              // cros-termina component.
+              if (is_initial_install || result == InstallResult::Success) {
+                // Delay removing cros-termina until here so as to avoid messing
+                // up the InstallComponent call below.
+                weak_this->RemoveComponentIfPresent(std::move(remove_callback),
+                                                    uninstall_result_ptr);
+                std::move(callback).Run(result);
+                return;
+              }
+              LOG(ERROR) << "Failed to install termina-dlc, falling back to "
+                            "cros-termina";
+              weak_this->InstallComponent(std::move(callback));
+            },
+            weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+            is_initial_install, std::move(remove_callback),
+            uninstall_result_ptr),
+        is_initial_install);
+  } else {
+    RemoveDlcIfPresent(std::move(remove_callback), uninstall_result_ptr);
+    InstallComponent(std::move(callback));
+  }
 }
 
 void TerminaInstaller::InstallDlc(
diff --git a/chrome/browser/ash/crostini/termina_installer_unittest.cc b/chrome/browser/ash/crostini/termina_installer_unittest.cc
index 1edbabb..b2a1239 100644
--- a/chrome/browser/ash/crostini/termina_installer_unittest.cc
+++ b/chrome/browser/ash/crostini/termina_installer_unittest.cc
@@ -158,6 +158,32 @@
   base::RunLoop run_loop_2_;
 };
 
+// Specialization of TerminaInstallTest that force-enables installing via DLC
+class TerminaDlcInstallTest : public TerminaInstallTest {
+ public:
+  TerminaDlcInstallTest() = default;
+
+  void SetUp() override {
+    this->CommonSetUp();
+    feature_list_.InitWithFeatures(
+        /*enabled_features=*/{chromeos::features::kCrostiniUseDlc},
+        /*disabled_features=*/{});
+  }
+};
+
+// Specialization of TerminaInstallTest that force-disables installing via DLC
+class TerminaComponentInstallTest : public TerminaInstallTest {
+ public:
+  TerminaComponentInstallTest() = default;
+
+  void SetUp() override {
+    this->CommonSetUp();
+    feature_list_.InitWithFeatures(
+        /*enabled_features=*/{},
+        /*disabled_features=*/{chromeos::features::kCrostiniUseDlc});
+  }
+};
+
 TEST_F(TerminaInstallTest, UninstallWithNothingInstalled) {
   termina_installer_.Uninstall(
       base::BindOnce(&TerminaInstallTest::ExpectTrue, base::Unretained(this)));
@@ -237,7 +263,7 @@
   CheckDlcInstallCalledTimes(0);
 }
 
-TEST_F(TerminaInstallTest, InstallDlc) {
+TEST_F(TerminaDlcInstallTest, InstallDlc) {
   termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
                                             base::Unretained(this)),
                              /*is_initial_install=*/true);
@@ -247,7 +273,7 @@
   ExpectDlcInstalled();
 }
 
-TEST_F(TerminaInstallTest, InstallDlcError) {
+TEST_F(TerminaDlcInstallTest, InstallDlcError) {
   fake_dlc_client_->set_install_error("An error");
 
   termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectFailure,
@@ -256,7 +282,7 @@
   run_loop_.Run();
 }
 
-TEST_F(TerminaInstallTest, InstallDlcNeedsReboot) {
+TEST_F(TerminaDlcInstallTest, InstallDlcNeedsReboot) {
   fake_dlc_client_->set_install_error(dlcservice::kErrorNeedReboot);
 
   termina_installer_.Install(
@@ -266,7 +292,7 @@
   run_loop_.Run();
 }
 
-TEST_F(TerminaInstallTest, InstallDlcNoImageFound) {
+TEST_F(TerminaDlcInstallTest, InstallDlcNoImageFound) {
   fake_dlc_client_->set_install_error(dlcservice::kErrorNoImageFound);
 
   termina_installer_.Install(
@@ -276,7 +302,7 @@
   run_loop_.Run();
 }
 
-TEST_F(TerminaInstallTest, InstallDlcBusyTriggersRetry) {
+TEST_F(TerminaDlcInstallTest, InstallDlcBusyTriggersRetry) {
   fake_dlc_client_->set_install_error(dlcservice::kErrorBusy);
 
   termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
@@ -291,7 +317,7 @@
   ExpectDlcInstalled();
 }
 
-TEST_F(TerminaInstallTest, InstallDlcBusyRetryIsCancelable) {
+TEST_F(TerminaDlcInstallTest, InstallDlcBusyRetryIsCancelable) {
   fake_dlc_client_->set_install_error(dlcservice::kErrorBusy);
 
   termina_installer_.Install(
@@ -309,7 +335,7 @@
   CheckDlcInstallCalledTimes(1);
 }
 
-TEST_F(TerminaInstallTest, InstallDlcBusyDoesntTriggerRetry) {
+TEST_F(TerminaDlcInstallTest, InstallDlcBusyDoesntTriggerRetry) {
   fake_dlc_client_->set_install_error(dlcservice::kErrorBusy);
 
   termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectFailure,
@@ -320,7 +346,7 @@
   CheckDlcInstallCalledTimes(1);
 }
 
-TEST_F(TerminaInstallTest, InstallDlcOffline) {
+TEST_F(TerminaDlcInstallTest, InstallDlcOffline) {
   fake_dlc_client_->set_install_error("An error");
 
   auto* network_connection_tracker =
@@ -334,7 +360,7 @@
   run_loop_.Run();
 }
 
-TEST_F(TerminaInstallTest, InstallDlcWithComponentInstalled) {
+TEST_F(TerminaDlcInstallTest, InstallDlcWithComponentInstalled) {
   component_manager_->SetRegisteredComponents(
       {imageloader::kTerminaComponentName});
 
@@ -351,7 +377,7 @@
       imageloader::kTerminaComponentName));
 }
 
-TEST_F(TerminaInstallTest, InstallDlcWithComponentInstalledUninstallError) {
+TEST_F(TerminaDlcInstallTest, InstallDlcWithComponentInstalledUninstallError) {
   component_manager_->SetRegisteredComponents(
       {imageloader::kTerminaComponentName});
   component_manager_->set_unload_component_result(false);
@@ -365,7 +391,7 @@
   ExpectDlcInstalled();
 }
 
-TEST_F(TerminaInstallTest, InstallDlcFallback) {
+TEST_F(TerminaDlcInstallTest, InstallDlcFallback) {
   termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
                                             base::Unretained(this)),
                              /*is_initial_install=*/false);
@@ -375,7 +401,7 @@
   ExpectDlcInstalled();
 }
 
-TEST_F(TerminaInstallTest, InstallDlcFallbackError) {
+TEST_F(TerminaDlcInstallTest, InstallDlcFallbackError) {
   fake_dlc_client_->set_install_error("An error");
   PrepareComponentForLoad();
 
@@ -388,7 +414,7 @@
   ExpectComponentInstalled();
 }
 
-TEST_F(TerminaInstallTest, InstallDlcFallbackIsCancelable) {
+TEST_F(TerminaDlcInstallTest, InstallDlcFallbackIsCancelable) {
   fake_dlc_client_->set_install_error("An error");
   PrepareComponentForLoad();
 
@@ -405,7 +431,7 @@
       imageloader::kTerminaComponentName));
 }
 
-TEST_F(TerminaInstallTest, InstallDlcFallbackOffline) {
+TEST_F(TerminaDlcInstallTest, InstallDlcFallbackOffline) {
   fake_dlc_client_->set_install_error("An error");
   PrepareComponentForLoad();
 
@@ -423,7 +449,8 @@
       imageloader::kTerminaComponentName));
 }
 
-TEST_F(TerminaInstallTest, InstallDlcFallbackOfflineComponentAlreadyInstalled) {
+TEST_F(TerminaDlcInstallTest,
+       InstallDlcFallbackOfflineComponentAlreadyInstalled) {
   fake_dlc_client_->set_install_error("An error");
   PrepareComponentForLoad();
   component_manager_->RegisterCompatiblePath(imageloader::kTerminaComponentName,
@@ -442,4 +469,259 @@
   ExpectComponentInstalled();
 }
 
+TEST_F(TerminaComponentInstallTest, InstallComponent) {
+  PrepareComponentForLoad();
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  run_loop_.Run();
+
+  ExpectComponentInstalled();
+}
+
+TEST_F(TerminaComponentInstallTest, InstallComponentOffline) {
+  PrepareComponentForLoad();
+  auto* network_connection_tracker =
+      network::TestNetworkConnectionTracker::GetInstance();
+  network_connection_tracker->SetConnectionType(
+      network::mojom::ConnectionType::CONNECTION_NONE);
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectOffline,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  run_loop_.Run();
+}
+
+TEST_F(TerminaComponentInstallTest, InstallComponentWithDlcInstalled) {
+  PrepareComponentForLoad();
+  InjectDlc();
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  run_loop_.Run();
+
+  CheckDlcInstallCalledTimes(0);
+  ExpectComponentInstalled();
+}
+
+TEST_F(TerminaComponentInstallTest, InstallComponentWithDlcInstalledError) {
+  PrepareComponentForLoad();
+  InjectDlc();
+  fake_dlc_client_->set_uninstall_error("An error");
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  run_loop_.Run();
+
+  ExpectComponentInstalled();
+}
+
+TEST_F(TerminaComponentInstallTest, LoadComponentAlreadyInstalled) {
+  component_manager_->set_supported_components(
+      {imageloader::kTerminaComponentName});
+  component_manager_->set_queue_load_requests(true);
+  component_manager_->RegisterCompatiblePath(imageloader::kTerminaComponentName,
+                                             component_install_path_);
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_TRUE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::NONE, component_install_path_,
+                    component_mount_path_));
+  run_loop_.Run();
+  ExpectComponentInstalled();
+}
+
+TEST_F(TerminaComponentInstallTest, LoadComponentInitiallyOffline) {
+  component_manager_->set_supported_components(
+      {imageloader::kTerminaComponentName});
+  component_manager_->set_queue_load_requests(true);
+  component_manager_->RegisterCompatiblePath(imageloader::kTerminaComponentName,
+                                             component_install_path_);
+  auto* network_connection_tracker =
+      network::TestNetworkConnectionTracker::GetInstance();
+  network_connection_tracker->SetConnectionType(
+      network::mojom::ConnectionType::CONNECTION_NONE);
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_FALSE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::NONE, component_install_path_,
+                    component_mount_path_));
+
+  network_connection_tracker->SetConnectionType(
+      network::mojom::ConnectionType::CONNECTION_ETHERNET);
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess2,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_TRUE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::NONE, component_install_path_,
+                    component_mount_path_));
+  run_loop_.Run();
+  ExpectComponentInstalled();
+
+  run_loop_2_.Run();
+  ExpectComponentInstalled();
+}
+
+TEST_F(TerminaComponentInstallTest, ComponentUpdatesOnlyOnce) {
+  component_manager_->set_supported_components(
+      {imageloader::kTerminaComponentName});
+  component_manager_->set_queue_load_requests(true);
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_TRUE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::NONE, component_install_path_,
+                    component_mount_path_));
+  run_loop_.Run();
+
+  termina_installer_.Install(base::DoNothing(),
+                             /*is_initial_install=*/true);
+  EXPECT_FALSE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+
+  ExpectComponentInstalled();
+}
+
+TEST_F(TerminaComponentInstallTest, UpdateComponentErrorRetry) {
+  component_manager_->set_supported_components(
+      {imageloader::kTerminaComponentName});
+  component_manager_->set_queue_load_requests(true);
+  component_manager_->RegisterCompatiblePath(imageloader::kTerminaComponentName,
+                                             component_install_path_);
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_TRUE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::INSTALL_FAILURE, base::FilePath(),
+                    base::FilePath()));
+
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_FALSE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::NONE, component_install_path_,
+                    component_mount_path_));
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess2,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_TRUE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::NONE, component_install_path_,
+                    component_mount_path_));
+
+  run_loop_.Run();
+  ExpectComponentInstalled();
+
+  run_loop_2_.Run();
+  ExpectComponentInstalled();
+}
+
+TEST_F(TerminaComponentInstallTest, InstallComponentErrorNoRetry) {
+  component_manager_->set_supported_components(
+      {imageloader::kTerminaComponentName});
+  component_manager_->set_queue_load_requests(true);
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectFailure,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_TRUE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::INSTALL_FAILURE, base::FilePath(),
+                    base::FilePath()));
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess2,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_TRUE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::NONE, component_install_path_,
+                    component_mount_path_));
+
+  run_loop_.Run();
+  run_loop_2_.Run();
+  ExpectComponentInstalled();
+}
+
+TEST_F(TerminaComponentInstallTest, UpdateInProgressTriggersRetry) {
+  component_manager_->set_supported_components(
+      {imageloader::kTerminaComponentName});
+  component_manager_->set_queue_load_requests(true);
+
+  termina_installer_.Install(base::BindOnce(&TerminaInstallTest::ExpectSuccess,
+                                            base::Unretained(this)),
+                             /*is_initial_install=*/true);
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_TRUE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::UPDATE_IN_PROGRESS, base::FilePath(),
+                    base::FilePath()));
+
+  task_env_.FastForwardBy(base::TimeDelta::FromSeconds(6));
+
+  EXPECT_TRUE(component_manager_->HasPendingInstall(
+      imageloader::kTerminaComponentName));
+  EXPECT_TRUE(
+      component_manager_->UpdateRequested(imageloader::kTerminaComponentName));
+  component_manager_->FinishLoadRequest(
+      imageloader::kTerminaComponentName,
+      ComponentInfo(ComponentError::NONE, component_install_path_,
+                    component_mount_path_));
+
+  run_loop_.Run();
+  ExpectComponentInstalled();
+}
+
 }  // namespace crostini
diff --git a/chrome/browser/ash/dbus/chrome_features_service_provider.cc b/chrome/browser/ash/dbus/chrome_features_service_provider.cc
index 0a2874f..e4a9b33 100644
--- a/chrome/browser/ash/dbus/chrome_features_service_provider.cc
+++ b/chrome/browser/ash/dbus/chrome_features_service_provider.cc
@@ -163,6 +163,7 @@
       &arc::kNativeBridgeToggleFeature,
       &features::kSessionManagerLongKillTimeout,
       &features::kSessionManagerLivenessCheck,
+      &features::kCrostiniUseDlc,
   };
 
   dbus::MessageReader reader(method_call);
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 f2475f9..976c769 100644
--- a/chrome/browser/ash/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -665,7 +665,6 @@
   SET_STRING("MULTIPART_DEVICE_UNSUPPORTED_MESSAGE",
              IDS_MULTIPART_DEVICE_UNSUPPORTED_MESSAGE);
   SET_STRING("NAME_COLUMN_LABEL", IDS_FILE_BROWSER_NAME_COLUMN_LABEL);
-  SET_STRING("EMPTY_FOLDER", IDS_FILE_BROWSER_EMPTY_FOLDER);
   SET_STRING("NEW_FOLDER_BUTTON_LABEL",
              IDS_FILE_BROWSER_NEW_FOLDER_BUTTON_LABEL);
   SET_STRING("NEW_WINDOW_BUTTON_LABEL",
diff --git a/chrome/browser/ash/login/existing_user_controller.cc b/chrome/browser/ash/login/existing_user_controller.cc
index 8966a83..1cfaf25 100644
--- a/chrome/browser/ash/login/existing_user_controller.cc
+++ b/chrome/browser/ash/login/existing_user_controller.cc
@@ -477,9 +477,6 @@
     // KioskAppManager, ArcKioskAppManager and WebKioskAppManager.
     if (user->IsKioskType())
       continue;
-    // TODO(xiyuan): Clean user profile whose email is not in allowlist.
-    if (user->GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED)
-      continue;
     // Allow offline login from the error screen if user of one of these types
     // has already logged in.
     if (user->GetType() == user_manager::USER_TYPE_REGULAR ||
@@ -1221,9 +1218,6 @@
     // KioskAppManager, ArcKioskAppManager and WebKioskAppManager.
     if (user->IsKioskType())
       continue;
-    // TODO(xiyuan): Clean user profile whose email is not in allowlist.
-    if (user->GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED)
-      continue;
     const bool meets_allowlist_requirements =
         !user->HasGaiaAccount() ||
         user_manager::UserManager::Get()->IsGaiaUserAllowed(*user);
diff --git a/chrome/browser/ash/login/login_ui_remove_legacy_supervised_users_browsertest.cc b/chrome/browser/ash/login/login_ui_remove_legacy_supervised_users_browsertest.cc
deleted file mode 100644
index ae9fcd9d..0000000
--- a/chrome/browser/ash/login/login_ui_remove_legacy_supervised_users_browsertest.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/public/cpp/login_screen_test_api.h"
-#include "base/feature_list.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/browser/ash/login/login_manager_test.h"
-#include "chrome/browser/ash/login/test/login_manager_mixin.h"
-#include "components/account_id/account_id.h"
-#include "components/user_manager/user.h"
-#include "components/user_manager/user_manager.h"
-#include "components/user_manager/user_manager_base.h"
-#include "components/user_manager/user_type.h"
-#include "content/public/test/browser_test.h"
-
-namespace chromeos {
-
-namespace {
-
-const LoginManagerMixin::TestUserInfo kDeprecatedSupervisedUser{
-    AccountId::FromUserEmailGaiaId("test@locally-managed.localhost",
-                                   "123456780"),
-    user_manager::USER_TYPE_SUPERVISED_DEPRECATED};
-
-const LoginManagerMixin::TestUserInfo kFamilyLinkUser{
-    AccountId::FromUserEmailGaiaId(test::kTestEmail, test::kTestGaiaId),
-    user_manager::USER_TYPE_CHILD};
-
-}  // namespace
-
-class LoginUIRemoveLegacySupervisedUsersTest : public LoginManagerTest {
- public:
-  LoginUIRemoveLegacySupervisedUsersTest() : LoginManagerTest() {
-    login_mixin_.AppendRegularUsers(1);
-  }
-
- protected:
-  LoginManagerMixin login_mixin_{&mixin_host_,
-                                 {kDeprecatedSupervisedUser, kFamilyLinkUser}};
-  base::HistogramTester histogram_tester_;
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-class LoginUIRemoveLegacySupervisedUsersEnabledTest
-    : public LoginUIRemoveLegacySupervisedUsersTest {
- public:
-  LoginUIRemoveLegacySupervisedUsersEnabledTest()
-      : LoginUIRemoveLegacySupervisedUsersTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        user_manager::UserManagerBase::kRemoveLegacySupervisedUsersOnStartup);
-  }
-};
-
-// Verifies that the login screen deletes deprecated supervised users and
-// records metrics.
-IN_PROC_BROWSER_TEST_F(LoginUIRemoveLegacySupervisedUsersEnabledTest,
-                       SupervisedUserHiddenAndDeleted) {
-  // Only the two Gaia users (regular and Family Link) should be displayed on
-  // the login screen.
-  EXPECT_EQ(2, ash::LoginScreenTestApi::GetUsersCount());
-  EXPECT_EQ(2u, user_manager::UserManager::Get()->GetUsers().size());
-  for (const user_manager::User* user :
-       user_manager::UserManager::Get()->GetUsers()) {
-    EXPECT_TRUE(user->HasGaiaAccount());
-    EXPECT_FALSE(user->IsChildOrDeprecatedSupervised() && !user->IsChild());
-  }
-
-  histogram_tester_.ExpectBucketCount(
-      user_manager::UserManagerBase::kLegacySupervisedUsersHistogramName,
-      /*sample=*/
-      user_manager::UserManagerBase::LegacySupervisedUserStatus::kLSUHidden,
-      /*expected_count=*/0);
-  // The login screen deleted one legacy supervised user.
-  histogram_tester_.ExpectBucketCount(
-      user_manager::UserManagerBase::kLegacySupervisedUsersHistogramName,
-      /*sample=*/
-      user_manager::UserManagerBase::LegacySupervisedUserStatus::kLSUDeleted,
-      /*expected_count=*/1);
-  // The login screen displayed one regular user and one Family Link user.
-  histogram_tester_.ExpectBucketCount(
-      user_manager::UserManagerBase::kLegacySupervisedUsersHistogramName,
-      /*sample=*/
-      user_manager::UserManagerBase::LegacySupervisedUserStatus::
-          kGaiaUserDisplayed,
-      /*expected_count=*/2);
-  histogram_tester_.ExpectTotalCount(
-      user_manager::UserManagerBase::kLegacySupervisedUsersHistogramName, 3);
-}
-
-class LoginUIRemoveLegacySupervisedUsersDisabledTest
-    : public LoginUIRemoveLegacySupervisedUsersTest {
- public:
-  LoginUIRemoveLegacySupervisedUsersDisabledTest()
-      : LoginUIRemoveLegacySupervisedUsersTest() {
-    scoped_feature_list_.InitAndDisableFeature(
-        user_manager::UserManagerBase::kRemoveLegacySupervisedUsersOnStartup);
-  }
-};
-
-// Tests no users removed.
-IN_PROC_BROWSER_TEST_F(LoginUIRemoveLegacySupervisedUsersDisabledTest,
-                       NoLegacySupervisedUsersRemoved) {
-  // Only the two Gaia users (regular and Family Link) should be displayed on
-  // the login screen. The legacy supervised user is still hidden.
-  EXPECT_EQ(2, ash::LoginScreenTestApi::GetUsersCount());
-  EXPECT_EQ(2u, user_manager::UserManager::Get()->GetUsers().size());
-  for (const user_manager::User* user :
-       user_manager::UserManager::Get()->GetUsers()) {
-    EXPECT_TRUE(user->HasGaiaAccount());
-    EXPECT_FALSE(user->IsChildOrDeprecatedSupervised() && !user->IsChild());
-  }
-
-  histogram_tester_.ExpectBucketCount(
-      user_manager::UserManagerBase::kLegacySupervisedUsersHistogramName,
-      /*sample=*/
-      user_manager::UserManagerBase::LegacySupervisedUserStatus::kLSUHidden,
-      /*expected_count=*/1);
-  // No users deleted.
-  histogram_tester_.ExpectBucketCount(
-      user_manager::UserManagerBase::kLegacySupervisedUsersHistogramName,
-      /*sample=*/
-      user_manager::UserManagerBase::LegacySupervisedUserStatus::kLSUDeleted,
-      /*expected_count=*/0);
-  // The login screen displayed one regular user and one Family Link user.
-  histogram_tester_.ExpectBucketCount(
-      user_manager::UserManagerBase::kLegacySupervisedUsersHistogramName,
-      /*sample=*/
-      user_manager::UserManagerBase::LegacySupervisedUserStatus::
-          kGaiaUserDisplayed,
-      /*expected_count=*/2);
-  histogram_tester_.ExpectTotalCount(
-      user_manager::UserManagerBase::kLegacySupervisedUsersHistogramName, 3);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/ash/login/quick_unlock/pin_storage_prefs.cc b/chrome/browser/ash/login/quick_unlock/pin_storage_prefs.cc
index af7f0e2..f20c1e2 100644
--- a/chrome/browser/ash/login/quick_unlock/pin_storage_prefs.cc
+++ b/chrome/browser/ash/login/quick_unlock/pin_storage_prefs.cc
@@ -63,8 +63,8 @@
   const bool exceeded_unlock_attempts =
       unlock_attempt_count() >= kMaximumUnlockAttempts;
 
-  return IsPinEnabled(pref_service_) && !IsPinDisabledByPolicy(pref_service_) &&
-         IsPinSet() && !exceeded_unlock_attempts;
+  return !IsPinDisabledByPolicy(pref_service_) && IsPinSet() &&
+         !exceeded_unlock_attempts;
 }
 
 bool PinStoragePrefs::TryAuthenticatePin(const Key& key) {
diff --git a/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc b/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc
index 361a151..ffbb79a 100644
--- a/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc
+++ b/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc
@@ -111,17 +111,7 @@
   return !enabled;
 }
 
-bool IsPinEnabled(PrefService* pref_service) {
-  if (enable_for_testing_)
-    return true;
-
-  // PIN is disabled for deprecated supervised user, but allowed to child user.
-  user_manager::User* user = user_manager::UserManager::Get()->GetActiveUser();
-  if (user && user->GetType() ==
-                  user_manager::UserType::USER_TYPE_SUPERVISED_DEPRECATED) {
-    return false;
-  }
-
+bool IsPinEnabled() {
   return true;
 }
 
diff --git a/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h b/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h
index 730df11..3c323aa 100644
--- a/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h
+++ b/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h
@@ -52,7 +52,8 @@
 bool IsPinDisabledByPolicy(PrefService* pref_service);
 
 // Returns true if the quick unlock feature flag is present.
-bool IsPinEnabled(PrefService* pref_service);
+// TODO(crbug/1111541): Remove this function because it always returns true.
+bool IsPinEnabled();
 
 // Returns true if the fingerprint is supported by the device.
 bool IsFingerprintSupported();
diff --git a/chrome/browser/ash/login/screens/assistant_optin_flow_screen_browsertest.cc b/chrome/browser/ash/login/screens/assistant_optin_flow_screen_browsertest.cc
index 6cd3ceb1..ab7c03a 100644
--- a/chrome/browser/ash/login/screens/assistant_optin_flow_screen_browsertest.cc
+++ b/chrome/browser/ash/login/screens/assistant_optin_flow_screen_browsertest.cc
@@ -32,6 +32,7 @@
 #include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
 #include "chromeos/services/assistant/public/cpp/assistant_settings.h"
 #include "chromeos/services/assistant/public/cpp/features.h"
+#include "chromeos/services/assistant/public/proto/get_settings_ui.pb.h"
 #include "chromeos/services/assistant/public/proto/settings_ui.pb.h"
 #include "chromeos/services/assistant/service.h"
 #include "components/prefs/pref_service.h"
@@ -159,6 +160,8 @@
 
   void set_setting_zippy_size(int size) { setting_zippy_size_ = size; }
 
+  void set_is_minor_user(bool is_minor_user) { is_minor_user_ = is_minor_user; }
+
   const std::set<OptIn>& collected_optins() const { return collected_optins_; }
 
   // Advances speaker ID enrollment to the next state.
@@ -203,7 +206,10 @@
 
   // chromeos::assistant::AssistantSettings:
   void GetSettings(const std::string& selector,
-                   GetSettingsCallback callback) override {
+                   GetSettingsCallback callback) override {}
+
+  void GetSettingsWithHeader(const std::string& selector,
+                             GetSettingsCallback callback) override {
     chromeos::assistant::SettingsUiSelector selector_proto;
     ASSERT_TRUE(selector_proto.ParseFromString(selector));
     EXPECT_FALSE(selector_proto.about_me_settings());
@@ -212,15 +218,24 @@
                   ASSISTANT_SUW_ONBOARDING_ON_CHROME_OS,
               selector_proto.consent_flow_ui_selector().flow_id());
 
-    chromeos::assistant::SettingsUi settings_ui;
-    auto* gaia_user_context_ui = settings_ui.mutable_gaia_user_context_ui();
+    chromeos::assistant::GetSettingsUiResponse response;
+
+    if (is_minor_user_) {
+      auto* header = response.mutable_header();
+      header->set_footer_button_layout(
+          chromeos::assistant::
+              SettingsResponseHeader_AcceptRejectLayout_EQUAL_WEIGHT);
+    }
+
+    auto* settings_ui = response.mutable_settings();
+    auto* gaia_user_context_ui = settings_ui->mutable_gaia_user_context_ui();
     gaia_user_context_ui->set_is_gaia_user(true);
     gaia_user_context_ui->set_waa_disabled_by_dasher_domain(
         (consent_ui_flags_ & CONSENT_UI_FLAG_WAA_DISABLED_BY_POLICY));
     gaia_user_context_ui->set_assistant_disabled_by_dasher_domain(
         (consent_ui_flags_ & CONSENT_UI_FLAG_ASSISTANT_DISABLED_BY_POLICY));
 
-    auto* consent_flow_ui = settings_ui.mutable_consent_flow_ui();
+    auto* consent_flow_ui = settings_ui->mutable_consent_flow_ui();
     consent_flow_ui->set_consent_status(
         chromeos::assistant::ConsentFlowUi_ConsentStatus_ASK_FOR_CONSENT);
     consent_flow_ui->mutable_consent_ui()->set_accept_button_text("OK");
@@ -251,7 +266,7 @@
 
     if (selector_proto.email_opt_in() &&
         (consent_ui_flags_ & CONSENT_UI_FLAG_ASK_EMAIL_OPT_IN)) {
-      auto* email_opt_in = settings_ui.mutable_email_opt_in_ui();
+      auto* email_opt_in = settings_ui->mutable_email_opt_in_ui();
       email_opt_in->set_title("Receive email upfates");
       email_opt_in->set_description("It might be useful");
       email_opt_in->set_legal_text("And you can opt out");
@@ -261,7 +276,7 @@
     }
 
     std::string message;
-    EXPECT_TRUE(settings_ui.SerializeToString(&message));
+    EXPECT_TRUE(response.SerializeToString(&message));
     std::move(callback).Run(message);
   }
 
@@ -366,6 +381,7 @@
   std::set<OptIn> collected_optins_;
 
   int setting_zippy_size_ = 1;
+  bool is_minor_user_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedAssistantSettings);
 };
@@ -530,12 +546,17 @@
   screen_waiter.Wait();
 
   test::OobeJS().CreateVisibilityWaiter(true, kAssistantValueProp)->Wait();
+  EXPECT_TRUE(test::OobeJS().GetAttributeBool("inverse", kValuePropNextButton));
   TapWhenEnabled(kValuePropNextButton);
 
   test::OobeJS().CreateVisibilityWaiter(true, kAssistantRelatedInfo)->Wait();
+  EXPECT_TRUE(
+      test::OobeJS().GetAttributeBool("inverse", kRelatedInfoNextButton));
   TapWhenEnabled(kRelatedInfoNextButton);
 
   test::OobeJS().CreateVisibilityWaiter(true, kAssistantVoiceMatch)->Wait();
+  EXPECT_TRUE(
+      test::OobeJS().GetAttributeBool("inverse", kVoiceMatchAgreeButton));
   TapWhenEnabled(kVoiceMatchAgreeButton);
 
   WaitForScreenExit();
@@ -1113,6 +1134,11 @@
     scoped_feature_list_.Reset();
     scoped_feature_list_.InitAndEnableFeature(features::kMinorModeRestriction);
   }
+
+  void SetUpOnMainThread() override {
+    AssistantOptInFlowTest::SetUpOnMainThread();
+    assistant_settings_->set_is_minor_user(true);
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(AssistantOptInFlowMinorModeTest,
@@ -1131,13 +1157,21 @@
   screen_waiter.Wait();
 
   test::OobeJS().CreateVisibilityWaiter(true, kAssistantValueProp)->Wait();
+  EXPECT_FALSE(
+      test::OobeJS().GetAttributeBool("inverse", kValuePropNextButton));
   TapWhenEnabled(kValuePropNextButton);
+  EXPECT_FALSE(
+      test::OobeJS().GetAttributeBool("inverse", kValuePropNextButton));
   TapWhenEnabled(kValuePropNextButton);
 
   test::OobeJS().CreateVisibilityWaiter(true, kAssistantRelatedInfo)->Wait();
+  EXPECT_FALSE(
+      test::OobeJS().GetAttributeBool("inverse", kRelatedInfoNextButton));
   TapWhenEnabled(kRelatedInfoNextButton);
 
   test::OobeJS().CreateVisibilityWaiter(true, kAssistantVoiceMatch)->Wait();
+  EXPECT_FALSE(
+      test::OobeJS().GetAttributeBool("inverse", kVoiceMatchAgreeButton));
   TapWhenEnabled(kVoiceMatchAgreeButton);
 
   WaitForScreenExit();
diff --git a/chrome/browser/ash/login/screens/pin_setup_screen.cc b/chrome/browser/ash/login/screens/pin_setup_screen.cc
index 1b7d9ab5..9430ed32 100644
--- a/chrome/browser/ash/login/screens/pin_setup_screen.cc
+++ b/chrome/browser/ash/login/screens/pin_setup_screen.cc
@@ -96,7 +96,6 @@
     return false;
   PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
   if (chrome_user_manager_util::IsPublicSessionOrEphemeralLogin() ||
-      !quick_unlock::IsPinEnabled(prefs) ||
       quick_unlock::IsPinDisabledByPolicy(prefs)) {
     return true;
   }
diff --git a/chrome/browser/ash/login/session/user_session_initializer.cc b/chrome/browser/ash/login/session/user_session_initializer.cc
index 5e70de77..2d7d20e 100644
--- a/chrome/browser/ash/login/session/user_session_initializer.cc
+++ b/chrome/browser/ash/login/session/user_session_initializer.cc
@@ -225,7 +225,7 @@
   crostini::CrostiniManager* crostini_manager =
       crostini::CrostiniManager::GetForProfile(profile);
   if (crostini_manager)
-    crostini_manager->RunSessionStartTasks();
+    crostini_manager->MaybeUpdateCrostini();
 
   if (features::IsClipboardHistoryEnabled()) {
     clipboard_image_model_factory_impl_ =
diff --git a/chrome/browser/ash/login/session/user_session_manager.cc b/chrome/browser/ash/login/session/user_session_manager.cc
index aa66aab..b015241 100644
--- a/chrome/browser/ash/login/session/user_session_manager.cc
+++ b/chrome/browser/ash/login/session/user_session_manager.cc
@@ -1089,7 +1089,6 @@
   for (auto* user : logged_in_users) {
     if (user->GetType() != user_manager::USER_TYPE_REGULAR &&
         user->GetType() != user_manager::USER_TYPE_GUEST &&
-        user->GetType() != user_manager::USER_TYPE_SUPERVISED_DEPRECATED &&
         user->GetType() != user_manager::USER_TYPE_CHILD) {
       continue;
     }
diff --git a/chrome/browser/ash/login/signin/auth_error_observer.cc b/chrome/browser/ash/login/signin/auth_error_observer.cc
index 0900b17..ac9a8f5 100644
--- a/chrome/browser/ash/login/signin/auth_error_observer.cc
+++ b/chrome/browser/ash/login/signin/auth_error_observer.cc
@@ -17,7 +17,6 @@
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/user_manager/user_manager.h"
-#include "components/user_manager/user_type.h"
 
 namespace chromeos {
 
@@ -25,9 +24,7 @@
 bool AuthErrorObserver::ShouldObserve(Profile* profile) {
   const user_manager::User* const user =
       ProfileHelper::Get()->GetUserByProfile(profile);
-  return user &&
-         (user->HasGaiaAccount() ||
-          user->GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED);
+  return user && user->HasGaiaAccount();
 }
 
 AuthErrorObserver::AuthErrorObserver(Profile* profile) : profile_(profile) {
@@ -79,8 +76,7 @@
     const GoogleServiceAuthError& auth_error) {
   const user_manager::User* const user =
       ProfileHelper::Get()->GetUserByProfile(profile_);
-  DCHECK(user->HasGaiaAccount() ||
-         user->GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED);
+  DCHECK(user->HasGaiaAccount());
 
   if (auth_error.IsPersistentError()) {
     // Invalidate OAuth2 refresh token to force Gaia sign-in flow. This is
diff --git a/chrome/browser/ash/login/users/chrome_user_manager.cc b/chrome/browser/ash/login/users/chrome_user_manager.cc
index f119ba4..e1be036 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager.cc
+++ b/chrome/browser/ash/login/users/chrome_user_manager.cc
@@ -105,7 +105,6 @@
       return LoginState::LOGGED_IN_USER_REGULAR;
     case user_manager::USER_TYPE_WEB_KIOSK_APP:
       return LoginState::LOGGED_IN_USER_KIOSK_APP;
-    case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
     case user_manager::NUM_USER_TYPES:
       break;  // Go to invalid-type handling code.
       // Since there is no default, the compiler warns about unhandled types.
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
index 62babef..0b3d2a6 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
@@ -1163,7 +1163,6 @@
     const user_manager::User& user) const {
   DCHECK(user.GetType() == user_manager::USER_TYPE_REGULAR ||
          user.GetType() == user_manager::USER_TYPE_GUEST ||
-         user.GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED ||
          user.GetType() == user_manager::USER_TYPE_CHILD);
 
   return chrome_user_manager_util::IsUserAllowed(
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_util.cc b/chrome/browser/ash/login/users/chrome_user_manager_util.cc
index b2ab565..2b8469a 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_util.cc
+++ b/chrome/browser/ash/login/users/chrome_user_manager_util.cc
@@ -62,15 +62,11 @@
                    bool is_user_allowlisted) {
   DCHECK(user.GetType() == user_manager::USER_TYPE_REGULAR ||
          user.GetType() == user_manager::USER_TYPE_GUEST ||
-         user.GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED ||
          user.GetType() == user_manager::USER_TYPE_CHILD);
 
   if (user.GetType() == user_manager::USER_TYPE_GUEST && !is_guest_allowed) {
     return false;
   }
-  if (user.GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED) {
-    return false;
-  }
   if (user.HasGaiaAccount() && !is_user_allowlisted) {
     return false;
   }
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_util.h b/chrome/browser/ash/login/users/chrome_user_manager_util.h
index 85ae259..4798492 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_util.h
+++ b/chrome/browser/ash/login/users/chrome_user_manager_util.h
@@ -13,7 +13,7 @@
 
 // Returns true if all `users` are allowed depending on the provided device
 // policies. Accepted user types: USER_TYPE_REGULAR, USER_TYPE_GUEST,
-// USER_TYPE_SUPERVISED_DEPRECATED, USER_TYPE_CHILD.
+// USER_TYPE_CHILD.
 // This function only checks against the device policies provided, so it does
 // not depend on CrosSettings or any other policy store.
 bool AreAllUsersAllowed(const user_manager::UserList& users,
@@ -22,7 +22,7 @@
 
 // Returns true if `user` is allowed, according to the given constraints.
 // Accepted user types: USER_TYPE_REGULAR, USER_TYPE_GUEST,
-// USER_TYPE_SUPERVISED_DEPRECATED, USER_TYPE_CHILD.
+// USER_TYPE_CHILD.
 bool IsUserAllowed(const user_manager::User& user,
                    bool is_guest_allowed,
                    bool is_user_allowlisted);
diff --git a/chrome/browser/ash/login/users/fake_chrome_user_manager.cc b/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
index 84c137f..f0808ad2 100644
--- a/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
+++ b/chrome/browser/ash/login/users/fake_chrome_user_manager.cc
@@ -635,14 +635,11 @@
     const user_manager::User& user) const {
   DCHECK(user.GetType() == user_manager::USER_TYPE_REGULAR ||
          user.GetType() == user_manager::USER_TYPE_GUEST ||
-         user.GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED ||
          user.GetType() == user_manager::USER_TYPE_CHILD);
 
   if (user.GetType() == user_manager::USER_TYPE_GUEST &&
       !IsGuestSessionAllowed())
     return false;
-  if (user.GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED)
-    return false;
   if (user.HasGaiaAccount() && !IsGaiaUserAllowed(user))
     return false;
   return true;
diff --git a/chrome/browser/ash/login/wizard_controller.cc b/chrome/browser/ash/login/wizard_controller.cc
index 9b16ecb..da40143 100644
--- a/chrome/browser/ash/login/wizard_controller.cc
+++ b/chrome/browser/ash/login/wizard_controller.cc
@@ -1809,7 +1809,7 @@
 
   // Check for tests configurations.
   if (wizard_context_->skip_to_update_for_tests ||
-      wizard_context_->skip_to_login_for_tests) {
+      wizard_context_->skip_to_login_for_tests || current_screen_) {
     return;
   }
 
diff --git a/chrome/browser/ash/policy/core/user_policy_manager_builder_chromeos.cc b/chrome/browser/ash/policy/core/user_policy_manager_builder_chromeos.cc
index c59a7e6..61ec529 100644
--- a/chrome/browser/ash/policy/core/user_policy_manager_builder_chromeos.cc
+++ b/chrome/browser/ash/policy/core/user_policy_manager_builder_chromeos.cc
@@ -116,10 +116,8 @@
   //   |UserCloudPolicyManagerChromeOS| is created here.
   // All other user types do not have user policy.
   const AccountId& account_id = user->GetAccountId();
-  if (user->GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED ||
-      (user->GetType() != user_manager::USER_TYPE_CHILD &&
-       BrowserPolicyConnector::IsNonEnterpriseUser(
-           account_id.GetUserEmail()))) {
+  if (user->GetType() != user_manager::USER_TYPE_CHILD &&
+      BrowserPolicyConnector::IsNonEnterpriseUser(account_id.GetUserEmail())) {
     DLOG(WARNING) << "No policy loaded for known non-enterprise user";
     // Mark this profile as not requiring policy.
     user_manager::known_user::SetProfileRequiresPolicy(
diff --git a/chrome/browser/ash/system/timezone_util.cc b/chrome/browser/ash/system/timezone_util.cc
index 6b6bfb71..059bb49 100644
--- a/chrome/browser/ash/system/timezone_util.cc
+++ b/chrome/browser/ash/system/timezone_util.cc
@@ -169,7 +169,6 @@
 
   switch (user->GetType()) {
     case user_manager::USER_TYPE_REGULAR:
-    case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
     case user_manager::USER_TYPE_KIOSK_APP:
     case user_manager::USER_TYPE_ARC_KIOSK_APP:
     case user_manager::USER_TYPE_ACTIVE_DIRECTORY:
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_untrusted_ui_config.cc b/chrome/browser/ash/web_applications/help_app/help_app_untrusted_ui_config.cc
index 3c7dfc6..736e1022 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_untrusted_ui_config.cc
+++ b/chrome/browser/ash/web_applications/help_app/help_app_untrusted_ui_config.cc
@@ -127,8 +127,7 @@
       ash::AssistantState::Get()->settings_enabled().value_or(false));
   source->AddBoolean("playStoreEnabled",
                      arc::IsArcPlayStoreEnabledForProfile(profile));
-  source->AddBoolean("pinEnabled",
-                     chromeos::quick_unlock::IsPinEnabled(pref_service));
+  source->AddBoolean("pinEnabled", chromeos::quick_unlock::IsPinEnabled());
 
   // Data about what type of account/login this is.
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
diff --git a/chrome/browser/browser_features.cc b/chrome/browser/browser_features.cc
index 8f75874..dcc255d 100644
--- a/chrome/browser/browser_features.cc
+++ b/chrome/browser/browser_features.cc
@@ -47,11 +47,6 @@
     "MuteNotificationSnoozeAction", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-// Shows a confirmation dialog when updates to PWAs identity (name and icon)
-// have been detected.
-const base::Feature kPwaUpdateDialogForNameAndIcon{
-    "pwa-update-dialog-for-name-and-icon", base::FEATURE_DISABLED_BY_DEFAULT};
-
 #if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables taking snapshots of the user data directory after a major
 // milestone update and restoring them after a version rollback.
diff --git a/chrome/browser/browser_features.h b/chrome/browser/browser_features.h
index 7a0a22d9..e6832e47 100644
--- a/chrome/browser/browser_features.h
+++ b/chrome/browser/browser_features.h
@@ -33,8 +33,6 @@
 extern const base::Feature kMuteNotificationSnoozeAction;
 #endif
 
-extern const base::Feature kPwaUpdateDialogForNameAndIcon;
-
 #if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 extern const base::Feature kUserDataSnapshot;
 #endif
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 503fac23..0f388a1 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -2053,23 +2053,6 @@
       false);
 }
 
-// TODO(crbug.com/589586): Disabled, since history is not yet marked as
-// a filterable datatype.
-TEST_F(ChromeBrowsingDataRemoverDelegateTest,
-       DISABLED_RemoveCompromisedCredentialsByUrlAndTime) {
-  RemovePasswordsTester tester(GetProfile());
-  auto builder = BrowsingDataFilterBuilder::Create(
-      BrowsingDataFilterBuilder::Mode::kDelete);
-  builder->AddRegisterableDomain(kTestRegisterableDomain1);
-  base::RepeatingCallback<bool(const GURL&)> filter = builder->BuildUrlFilter();
-
-  EXPECT_CALL(*tester.profile_store(),
-              RemoveCompromisedCredentialsByUrlAndTimeImpl(
-                  ProbablySameFilter(filter), base::Time(), base::Time::Max()));
-  BlockUntilOriginDataRemoved(base::Time(), base::Time::Max(),
-                              constants::DATA_TYPE_HISTORY, std::move(builder));
-}
-
 TEST_F(ChromeBrowsingDataRemoverDelegateTest,
        RemoveContentSettingsWithPreserveFilter) {
   // This test relies on async loading to complete. RunUntilIdle() should be
diff --git a/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc b/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc
index 5cdbc376..10688ff 100644
--- a/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc
+++ b/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc
@@ -92,13 +92,25 @@
     run_loop_->Run();
   }
 
+  // Once the GetResult() or GetDomainExamples()  is called, it can be called
+  // again until the next result is available.
   BrowsingDataCounter::ResultInt GetResult() {
     DCHECK(finished_);
+    // Some tests call WaitForCounting() multiple times. Set `finished_` to
+    // false such that next call of WaitForCounting() will indeed block until
+    // counting is done.
+    finished_ = false;
     return result_;
   }
 
+  // Once the GetResult() or GetDomainExamples() is called, it can be called
+  // again until the next result is available.
   std::vector<std::string> GetDomainExamples() {
     DCHECK(finished_);
+    // Some tests call WaitForCounting() multiple times. Set `finished_` to
+    // false such that next call of WaitForCounting() will indeed block until
+    // counting is done.
+    finished_ = false;
     return domain_examples_;
   }
 
diff --git a/chrome/browser/chromeos/extensions/users_private/users_private_api.cc b/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
index f1d044bf7..ec0dedf 100644
--- a/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
+++ b/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
@@ -77,7 +77,6 @@
   api_user.name = base::UTF16ToUTF8(user.GetDisplayName());
   api_user.is_owner = user.GetAccountId() ==
                       user_manager::UserManager::Get()->GetOwnerAccountId();
-  api_user.is_supervised = user.IsChildOrDeprecatedSupervised();
   api_user.is_child = user.IsChild();
   return api_user;
 }
@@ -89,7 +88,6 @@
   api_user.display_email = email;
   api_user.name = email;
   api_user.is_owner = false;
-  api_user.is_supervised = false;
   api_user.is_child = false;
   return api_user;
 }
diff --git a/chrome/browser/chromeos/first_run/first_run.cc b/chrome/browser/chromeos/first_run/first_run.cc
index becdcc2..e8bb997 100644
--- a/chrome/browser/chromeos/first_run/first_run.cc
+++ b/chrome/browser/chromeos/first_run/first_run.cc
@@ -51,7 +51,6 @@
 bool IsRegularUserOrSupervisedChild(user_manager::UserManager* user_manager) {
   switch (user_manager->GetActiveUser()->GetType()) {
     case user_manager::USER_TYPE_REGULAR:
-    case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
     case user_manager::USER_TYPE_CHILD:
       return true;
     default:
@@ -59,8 +58,7 @@
   }
 }
 
-// Getting started module is shown to  unmanaged regular, supervised and child
-// accounts.
+// Getting started module is shown to unmanaged regular and child accounts.
 bool ShouldShowGetStarted(Profile* profile,
                           user_manager::UserManager* user_manager) {
   // Child users return true for IsManaged. These are not EDU accounts though,
@@ -69,7 +67,6 @@
     return true;
   switch (user_manager->GetActiveUser()->GetType()) {
     case user_manager::USER_TYPE_REGULAR:
-    case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
       return !profile->GetProfilePolicyConnector()->IsManaged();
     default:
       return false;
diff --git a/chrome/browser/chromeos/full_restore/arc_app_launch_handler.cc b/chrome/browser/chromeos/full_restore/arc_app_launch_handler.cc
index a1772ab..373d911 100644
--- a/chrome/browser/chromeos/full_restore/arc_app_launch_handler.cc
+++ b/chrome/browser/chromeos/full_restore/arc_app_launch_handler.cc
@@ -10,6 +10,7 @@
 #include "ash/shell.h"
 #include "base/callback.h"
 #include "base/containers/contains.h"
+#include "base/cpu.h"
 #include "chrome/browser/apps/app_service/app_platform_metrics.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
@@ -51,9 +52,18 @@
 constexpr base::TimeDelta kAppLaunchDelay = base::TimeDelta::FromSeconds(3);
 
 constexpr int kCpuUsageRefreshIntervalInSeconds = 1;
+
+// Count CPU usage by average on last 6 seconds.
 constexpr int kCpuUsageCountWindowLength =
     6 * kCpuUsageRefreshIntervalInSeconds;
 
+// Restrict ARC app launch if CPU usage over threshold.
+constexpr int kCpuUsageThreshold = 90;
+
+// Apply CPU usage restrict if and only if the CPU cores not over
+// |kCpuRestrictCoresCondition|.
+constexpr int kCpuRestrictCoresCondition = 2;
+
 }  // namespace
 
 namespace chromeos {
@@ -69,6 +79,13 @@
     if (activation_client)
       activation_client->AddObserver(this);
   }
+
+  // Get CPU cores.
+  base::CPU::TimeInState state;
+  if (base::CPU::GetTimeInState(state) &&
+      state.size() <= kCpuRestrictCoresCondition) {
+    should_apply_cpu_restirction_ = true;
+  }
 }
 
 ArcAppLaunchHandler::~ArcAppLaunchHandler() {
@@ -338,6 +355,11 @@
 }
 
 bool ArcAppLaunchHandler::CanLaunchApp() {
+  if (should_apply_cpu_restirction_) {
+    if (GetCpuUsageRate() >= kCpuUsageThreshold)
+      return false;
+  }
+
   switch (pressure_level_) {
     case chromeos::ResourcedClient::PressureLevel::NONE:
       return true;
@@ -360,7 +382,7 @@
 }
 
 void ArcAppLaunchHandler::MaybeLaunchApp() {
-  if (!CanLaunchApp())
+  if (!first_run_ && !CanLaunchApp())
     return;
 
   for (auto it = pending_windows_.begin(); it != pending_windows_.end(); ++it) {
@@ -406,6 +428,7 @@
 void ArcAppLaunchHandler::LaunchApp(const std::string& app_id,
                                     int32_t window_id) {
   DCHECK(handler_);
+
   const auto it = handler_->restore_data_->app_id_to_launch_list().find(app_id);
   if (it == handler_->restore_data_->app_id_to_launch_list().end())
     return;
@@ -419,6 +442,8 @@
   if (data_it == it->second.end())
     return;
 
+  first_run_ = false;
+
   auto* proxy = apps::AppServiceProxyFactory::GetForProfile(handler_->profile_);
   DCHECK(proxy);
 
@@ -544,6 +569,8 @@
   if (stop_restore_timer_ && stop_restore_timer_->IsRunning())
     stop_restore_timer_->Stop();
   stop_restore_timer_.reset();
+
+  StopCpuUsageCount();
 }
 
 int ArcAppLaunchHandler::GetCpuUsageRate() {
diff --git a/chrome/browser/chromeos/full_restore/arc_app_launch_handler.h b/chrome/browser/chromeos/full_restore/arc_app_launch_handler.h
index ea886220..8668dd56 100644
--- a/chrome/browser/chromeos/full_restore/arc_app_launch_handler.h
+++ b/chrome/browser/chromeos/full_restore/arc_app_launch_handler.h
@@ -176,6 +176,12 @@
 
   ArcWindowHandler* window_handler_ = nullptr;
 
+  // If the system is under memory pressuure or high CPU usage rate, only launch
+  // 1 window following the window stack priority. `first_run_` is used to check
+  // whether this is the first window to be restored, which can skip the system
+  // memory and CPU usage rate checking.
+  bool first_run_ = true;
+
   // The number to record how many times the current top window has been
   // launched.
   int launch_count_ = 0;
@@ -197,6 +203,8 @@
   chromeos::ResourcedClient::PressureLevel pressure_level_ =
       chromeos::ResourcedClient::PressureLevel::MODERATE;
 
+  bool should_apply_cpu_restirction_ = false;
+
   mojo::Remote<cros_healthd::mojom::CrosHealthdProbeService> probe_service_;
 
   // Cpu usage rate count window. It save the cpu usage in a time interval.
diff --git a/chrome/browser/chromeos/full_restore/full_restore_prefs.cc b/chrome/browser/chromeos/full_restore/full_restore_prefs.cc
index 703cadf2..ecf9fee 100644
--- a/chrome/browser/chromeos/full_restore/full_restore_prefs.cc
+++ b/chrome/browser/chromeos/full_restore/full_restore_prefs.cc
@@ -18,11 +18,6 @@
 // Refer to |RestoreOption|.
 const char kRestoreAppsAndPagesPrefName[] = "settings.restore_apps_and_pages";
 
-// An integer pref to count how many times the user selected the 'Restore'
-// button from the restore notification dialog.
-const char kRestoreSelectedCountPrefName[] =
-    "full_restore.restore_selected_count";
-
 void RegisterProfilePrefs(PrefRegistrySimple* registry) {
   if (!::full_restore::features::IsFullRestoreEnabled())
     return;
@@ -31,8 +26,6 @@
       kRestoreAppsAndPagesPrefName,
       static_cast<int>(RestoreOption::kAskEveryTime),
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
-
-  registry->RegisterIntegerPref(kRestoreSelectedCountPrefName, 0);
 }
 
 bool HasRestorePref(PrefService* prefs) {
@@ -88,13 +81,5 @@
   }
 }
 
-int GetRestoreSelectedCountPref(PrefService* prefs) {
-  return prefs->GetInteger(kRestoreSelectedCountPrefName);
-}
-
-void SetRestoreSelectedCountPref(PrefService* prefs, int count) {
-  prefs->SetInteger(kRestoreSelectedCountPrefName, count);
-}
-
 }  // namespace full_restore
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/full_restore/full_restore_prefs.h b/chrome/browser/chromeos/full_restore/full_restore_prefs.h
index 589bb02..847fc2a 100644
--- a/chrome/browser/chromeos/full_restore/full_restore_prefs.h
+++ b/chrome/browser/chromeos/full_restore/full_restore_prefs.h
@@ -27,10 +27,8 @@
 };
 
 extern const char kRestoreAppsAndPagesPrefName[];
-extern const char kRestoreSelectedCountPrefName[];
 
-// Registers the restore pref |kRestoreAppsAndPagesPrefName| and
-// |kRestoreSelectedCountPrefName|.
+// Registers the restore pref |kRestoreAppsAndPagesPrefName|.
 void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
 // Returns true if the pref has |kRestoreAppsAndPagesPrefName|. Otherwise,
@@ -58,12 +56,6 @@
 // restore settings is synced.
 void UpdateRestorePrefIfNecessary(PrefService* prefs);
 
-// Returns the value of the pref |kRestoreSelectedCountPrefName|.
-int GetRestoreSelectedCountPref(PrefService* prefs);
-
-// Sets the pref |kRestoreSelectedCountPrefName| as |count|.
-void SetRestoreSelectedCountPref(PrefService* prefs, int count);
-
 }  // namespace full_restore
 }  // namespace chromeos
 
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service.cc b/chrome/browser/chromeos/full_restore/full_restore_service.cc
index 1f61159..e855060 100644
--- a/chrome/browser/chromeos/full_restore/full_restore_service.cc
+++ b/chrome/browser/chromeos/full_restore/full_restore_service.cc
@@ -26,6 +26,7 @@
 #include "components/full_restore/full_restore_save_handler.h"
 #include "components/prefs/pref_service.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/chromeos/devicetype_utils.h"
 #include "ui/message_center/public/cpp/notification.h"
 
 namespace chromeos {
@@ -35,12 +36,6 @@
 
 const char kRestoreForCrashNotificationId[] = "restore_for_crash_notification";
 const char kRestoreNotificationId[] = "restore_notification";
-const char kSetRestorePrefNotificationId[] = "set_restore_pref_notification";
-
-// If the user selected the 'Restore' button from the restore notification
-// dialog for more than |kMaxConsecutiveRestoreSelectionCount| times, show the
-// set restore pref notification.
-const int kMaxConsecutiveRestoreSelectionCount = 3;
 
 const char kRestoreNotificationHistogramName[] = "Apps.RestoreNotification";
 const char kRestoreForCrashNotificationHistogramName[] =
@@ -129,9 +124,7 @@
 }
 
 void FullRestoreService::Close(bool by_user) {
-  if (!skip_notification_histogram_ &&
-      (notification_->id() == kRestoreNotificationId ||
-       notification_->id() == kRestoreForCrashNotificationId)) {
+  if (!skip_notification_histogram_) {
     RecordRestoreAction(
         notification_->id(),
         by_user ? RestoreAction::kCloseByUser : RestoreAction::kCloseNotByUser);
@@ -139,52 +132,34 @@
 }
 void FullRestoreService::Click(const absl::optional<int>& button_index,
                                const absl::optional<std::u16string>& reply) {
-  skip_notification_histogram_ = true;
   DCHECK(notification_);
+
+  if (!button_index.has_value()) {
+    if (notification_->id() == kRestoreNotificationId) {
+      // Show the 'On Startup' OS setting page.
+      chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
+          profile_, chromeos::settings::mojom::kAppsSectionPath);
+    }
+    return;
+  }
+
+  skip_notification_histogram_ = true;
+  RecordRestoreAction(
+      notification_->id(),
+      button_index.value() ==
+              static_cast<int>(RestoreNotificationButtonIndex::kRestore)
+          ? RestoreAction::kRestore
+          : RestoreAction::kCancel);
+
+  if (button_index.value() ==
+      static_cast<int>(RestoreNotificationButtonIndex::kRestore)) {
+    Restore();
+  }
+
   if (!is_shut_down_) {
     NotificationDisplayService::GetForProfile(profile_)->Close(
         NotificationHandler::Type::TRANSIENT, notification_->id());
   }
-
-  if (!button_index.has_value())
-    return;
-
-  if (notification_->id() == kRestoreNotificationId ||
-      notification_->id() == kRestoreForCrashNotificationId) {
-    RecordRestoreAction(
-        notification_->id(),
-        button_index.value() ==
-                static_cast<int>(RestoreNotificationButtonIndex::kRestore)
-            ? RestoreAction::kRestore
-            : RestoreAction::kCancel);
-  }
-
-  if (button_index.value() !=
-      static_cast<int>(RestoreNotificationButtonIndex::kRestore)) {
-    return;
-  }
-
-  if (notification_->id() == kSetRestorePrefNotificationId) {
-    // Show the 'On Startup' OS setting page.
-    chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
-        profile_, chromeos::settings::mojom::kAppsSectionPath);
-    return;
-  }
-
-  // For the restore notification, check how many times the user selected the
-  // 'Restore' button. If the user selects the 'restore' button for more than 3
-  // times, show the set restore pref notification.
-  if (notification_->id() == kRestoreNotificationId) {
-    int count = GetRestoreSelectedCountPref(profile_->GetPrefs());
-
-    if (count < kMaxConsecutiveRestoreSelectionCount)
-      SetRestoreSelectedCountPref(profile_->GetPrefs(), ++count);
-
-    if (count >= kMaxConsecutiveRestoreSelectionCount)
-      MaybeShowRestoreNotification(kSetRestorePrefNotificationId);
-  }
-
-  Restore();
 }
 
 void FullRestoreService::Shutdown() {
@@ -198,30 +173,29 @@
   message_center::RichNotificationData notification_data;
 
   message_center::ButtonInfo restore_button(l10n_util::GetStringUTF16(
-      base::ToUpperASCII(id == kSetRestorePrefNotificationId
-                             ? IDS_SET_RESTORE_NOTIFICATION_BUTTON
-                             : IDS_RESTORE_NOTIFICATION_RESTORE_BUTTON)));
+      base::ToUpperASCII(IDS_RESTORE_NOTIFICATION_RESTORE_BUTTON)));
   notification_data.buttons.push_back(restore_button);
 
   message_center::ButtonInfo cancel_button(l10n_util::GetStringUTF16(
       base::ToUpperASCII(IDS_RESTORE_NOTIFICATION_CANCEL_BUTTON)));
   notification_data.buttons.push_back(cancel_button);
 
-  int title_id = id == kSetRestorePrefNotificationId
-                     ? IDS_SET_RESTORE_NOTIFICATION_TITLE
-                     : IDS_RESTORE_NOTIFICATION_TITLE;
+  std::u16string title;
+  if (id == kRestoreForCrashNotificationId) {
+    title = l10n_util::GetStringFUTF16(IDS_RESTORE_CRASH_NOTIFICATION_TITLE,
+                                       ui::GetChromeOSDeviceName());
+  } else {
+    title = l10n_util::GetStringUTF16(IDS_RESTORE_NOTIFICATION_TITLE);
+  }
 
   int message_id;
   if (id == kRestoreForCrashNotificationId)
-    message_id = IDS_RESTORE_FOR_CRASH_NOTIFICATION_MESSAGE;
-  else if (id == kRestoreNotificationId)
-    message_id = IDS_RESTORE_NOTIFICATION_MESSAGE;
+    message_id = IDS_RESTORE_CRASH_NOTIFICATION_MESSAGE;
   else
-    message_id = IDS_SET_RESTORE_NOTIFICATION_MESSAGE;
+    message_id = IDS_RESTORE_NOTIFICATION_MESSAGE;
 
   notification_ = ash::CreateSystemNotification(
-      message_center::NOTIFICATION_TYPE_SIMPLE, id,
-      l10n_util::GetStringUTF16(title_id),
+      message_center::NOTIFICATION_TYPE_SIMPLE, id, title,
       l10n_util::GetStringUTF16(message_id),
       l10n_util::GetStringUTF16(IDS_RESTORE_NOTIFICATION_DISPLAY_SOURCE),
       GURL(),
@@ -232,7 +206,6 @@
           weak_ptr_factory_.GetWeakPtr()),
       kFullRestoreNotificationIcon,
       message_center::SystemNotificationWarningLevel::NORMAL);
-  notification_->set_priority(message_center::SYSTEM_PRIORITY);
 
   auto* notification_display_service =
       NotificationDisplayService::GetForProfile(profile_);
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc b/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc
index 087ecae..5e70d0e 100644
--- a/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc
+++ b/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc
@@ -127,8 +127,7 @@
   }
 
   void VerifyNotification(bool has_crash_notification,
-                          bool has_restore_notification,
-                          bool has_set_restore_notification) {
+                          bool has_restore_notification) {
     if (has_crash_notification)
       EXPECT_TRUE(HasNotificationFor(kRestoreForCrashNotificationId));
     else
@@ -138,11 +137,6 @@
       EXPECT_TRUE(HasNotificationFor(kRestoreNotificationId));
     else
       EXPECT_FALSE(HasNotificationFor(kRestoreNotificationId));
-
-    if (has_set_restore_notification)
-      EXPECT_TRUE(HasNotificationFor(kSetRestorePrefNotificationId));
-    else
-      EXPECT_FALSE(HasNotificationFor(kSetRestorePrefNotificationId));
   }
 
   void SimulateClick(const std::string& notification_id,
@@ -172,10 +166,6 @@
         profile()->GetPrefs()->GetInteger(kRestoreAppsAndPagesPrefName));
   }
 
-  int GetRestoreSelectedCount() const {
-    return profile()->GetPrefs()->GetInteger(kRestoreSelectedCountPrefName);
-  }
-
   TestingProfile* profile() const { return profile_.get(); }
 
   const AccountId& account_id() const { return account_id_; }
@@ -204,8 +194,7 @@
   CreateFullRestoreServiceForTesting();
 
   VerifyNotification(false /* has_crash_notification */,
-                     false /* has_restore_notification */,
-                     false /* has_set_restore_notification */);
+                     false /* has_restore_notification */);
 
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
@@ -222,8 +211,7 @@
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
   VerifyNotification(false /* has_crash_notification */,
-                     false /* has_restore_notification */,
-                     false /* has_set_restore_notification */);
+                     false /* has_restore_notification */);
 
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
@@ -265,8 +253,7 @@
   CreateFullRestoreServiceForTesting();
 
   VerifyNotification(true /* has_crash_notification */,
-                     false /* has_restore_notification */,
-                     false /* has_set_restore_notification */);
+                     false /* has_restore_notification */);
 
   SimulateClick(kRestoreForCrashNotificationId,
                 RestoreNotificationButtonIndex::kRestore);
@@ -276,37 +263,7 @@
 
   // Verify the set restore notification is not shown.
   VerifyNotification(false /* has_crash_notification */,
-                     false /* has_restore_notification */,
-                     false /* has_set_restore_notification */);
-}
-
-// If the system is crash, and the restore option has been selected 3 times,
-// show the crash notification, and verify the restore flag when click the
-// restore button, without showing the set restore notification.
-TEST_F(FullRestoreServiceTestHavingFullRestoreFile,
-       CrashAndRestoreWithoutSetRestorePrefNotification) {
-  profile()->set_last_session_exited_cleanly(false);
-
-  // Set |kRestoreSelectedCountPrefName| = 3 to simulate the restore option has
-  // been selected 3 times.
-  profile()->GetPrefs()->SetInteger(kRestoreSelectedCountPrefName, 3);
-
-  CreateFullRestoreServiceForTesting();
-
-  VerifyNotification(true /* has_crash_notification */,
-                     false /* has_restore_notification */,
-                     false /* has_set_restore_notification */);
-
-  SimulateClick(kRestoreForCrashNotificationId,
-                RestoreNotificationButtonIndex::kRestore);
-
-  EXPECT_TRUE(::full_restore::ShouldRestore(account_id()));
-  EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
-
-  // Verify the set restore notification is not shown.
-  VerifyNotification(false /* has_crash_notification */,
-                     false /* has_restore_notification */,
-                     false /* has_set_restore_notification */);
+                     false /* has_restore_notification */);
 }
 
 // If the system is crash, show the crash notification, and verify the restore
@@ -316,8 +273,7 @@
   CreateFullRestoreServiceForTesting();
 
   VerifyNotification(true /* has_crash_notification */,
-                     false /* has_restore_notification */,
-                     false /* has_set_restore_notification */);
+                     false /* has_restore_notification */);
 
   SimulateClick(kRestoreForCrashNotificationId,
                 RestoreNotificationButtonIndex::kCancel);
@@ -341,7 +297,7 @@
 
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 }
 
 // For a brand new user, if sync off, set 'Ask Every Time' as the default value,
@@ -352,7 +308,7 @@
 
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
@@ -367,7 +323,7 @@
 
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
@@ -382,7 +338,7 @@
 
   EXPECT_EQ(RestoreOption::kAlways, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
@@ -416,7 +372,7 @@
 
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
@@ -431,7 +387,7 @@
 
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
@@ -464,7 +420,7 @@
 
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
@@ -482,7 +438,7 @@
 
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
@@ -518,7 +474,7 @@
 
   EXPECT_EQ(RestoreOption::kDoNotRestore, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_FALSE(::full_restore::CanPerformRestore(account_id()));
@@ -545,8 +501,7 @@
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
   VerifyNotification(false /* has_crash_notification */,
-                     true /* has_restore_notification */,
-                     false /* has_set_restore_notification */);
+                     true /* has_restore_notification */);
 
   SimulateClick(kRestoreNotificationId,
                 RestoreNotificationButtonIndex::kRestore);
@@ -555,7 +510,7 @@
   EXPECT_TRUE(::full_restore::ShouldRestore(account_id()));
   EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 }
 
 // If the OS restore setting is 'Ask every time', after reboot, show the restore
@@ -569,8 +524,7 @@
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
   VerifyNotification(false /* has_crash_notification */,
-                     true /* has_restore_notification */,
-                     false /* has_set_restore_notification */);
+                     true /* has_restore_notification */);
 
   SimulateClick(kRestoreNotificationId,
                 RestoreNotificationButtonIndex::kCancel);
@@ -579,7 +533,7 @@
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 }
 
 // If the OS restore setting is 'Always', after reboot, don't show any
@@ -591,7 +545,7 @@
 
   EXPECT_EQ(RestoreOption::kAlways, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 
   EXPECT_TRUE(::full_restore::ShouldRestore(account_id()));
   EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
@@ -607,78 +561,11 @@
 
   EXPECT_EQ(RestoreOption::kDoNotRestore, GetRestoreOption());
 
-  VerifyNotification(false, false, false);
+  VerifyNotification(false, false);
 
   EXPECT_FALSE(::full_restore::ShouldRestore(account_id()));
   EXPECT_FALSE(::full_restore::CanPerformRestore(account_id()));
 }
 
-// If the restore option has been selected 3 times, show the set restore
-// notification.
-TEST_F(FullRestoreServiceTestHavingFullRestoreFile,
-       SetRestorePrefNotification) {
-  profile()->GetPrefs()->SetInteger(
-      kRestoreAppsAndPagesPrefName,
-      static_cast<int>(RestoreOption::kAskEveryTime));
-
-  // Set |kRestoreSelectedCountPrefName| = 2 to simulate the restore option has
-  // been selected twice.
-  profile()->GetPrefs()->SetInteger(kRestoreSelectedCountPrefName, 2);
-
-  CreateFullRestoreServiceForTesting();
-
-  EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
-
-  VerifyNotification(false /* has_crash_notification */,
-                     true /* has_restore_notification */,
-                     false /* has_set_restore_notification */);
-
-  // The restore option has been selected the 3rd times.
-  SimulateClick(kRestoreNotificationId,
-                RestoreNotificationButtonIndex::kRestore);
-
-  EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
-  EXPECT_TRUE(::full_restore::ShouldRestore(account_id()));
-  EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
-
-  // Verify the set restore notification is shown.
-  VerifyNotification(false /* has_crash_notification */,
-                     false /* has_restore_notification */,
-                     true /* has_set_restore_notification */);
-
-  EXPECT_EQ(3, GetRestoreSelectedCount());
-}
-
-// When |kRestoreSelectedCountPrefName| = 3, if the restore option is selected
-// again, |kRestoreSelectedCountPrefName| should not change.
-TEST_F(FullRestoreServiceTestHavingFullRestoreFile, RestoreSelectedCount) {
-  profile()->GetPrefs()->SetInteger(
-      kRestoreAppsAndPagesPrefName,
-      static_cast<int>(RestoreOption::kAskEveryTime));
-
-  // Set |kRestoreSelectedCountPrefName| = 3 to simulate the restore option has
-  // been selected 3 times locally.
-  profile()->GetPrefs()->SetInteger(kRestoreSelectedCountPrefName, 3);
-
-  CreateFullRestoreServiceForTesting();
-
-  EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
-
-  // The restore option is selected.
-  SimulateClick(kRestoreNotificationId,
-                RestoreNotificationButtonIndex::kRestore);
-
-  EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
-  EXPECT_TRUE(::full_restore::ShouldRestore(account_id()));
-  EXPECT_TRUE(::full_restore::CanPerformRestore(account_id()));
-
-  // Verify the set restore notification is shown.
-  VerifyNotification(false /* has_crash_notification */,
-                     false /* has_restore_notification */,
-                     true /* has_set_restore_notification */);
-
-  EXPECT_EQ(3, GetRestoreSelectedCount());
-}
-
 }  // namespace full_restore
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/grammar_service_client.cc b/chrome/browser/chromeos/input_method/grammar_service_client.cc
index d29cc85..cb47ec1 100644
--- a/chrome/browser/chromeos/input_method/grammar_service_client.cc
+++ b/chrome/browser/chromeos/input_method/grammar_service_client.cc
@@ -128,11 +128,9 @@
 bool GrammarServiceClient::IsAvailable(Profile* profile) const {
   const PrefService* pref = profile->GetPrefs();
   DCHECK(pref);
-  // If prefs don't allow spell checking, if enhanced spell check is disabled,
-  // or if the profile is off the record, the grammar service should be
-  // unavailable.
+  // If prefs don't allow spell checking, if the profile is off the record, the
+  // grammar service should be unavailable.
   if (!pref->GetBoolean(spellcheck::prefs::kSpellCheckEnable) ||
-      !pref->GetBoolean(spellcheck::prefs::kSpellCheckUseSpellingService) ||
       profile->IsOffTheRecord())
     return false;
 
diff --git a/chrome/browser/chromeos/input_method/grammar_service_client_unittest.cc b/chrome/browser/chromeos/input_method/grammar_service_client_unittest.cc
index cecba30d..5e09cb8e 100644
--- a/chrome/browser/chromeos/input_method/grammar_service_client_unittest.cc
+++ b/chrome/browser/chromeos/input_method/grammar_service_client_unittest.cc
@@ -38,8 +38,6 @@
 
   auto profile = std::make_unique<TestingProfile>();
   profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable, false);
-  profile->GetPrefs()->SetBoolean(
-      spellcheck::prefs::kSpellCheckUseSpellingService, false);
 
   GrammarServiceClient client;
   base::RunLoop().RunUntilIdle();
@@ -63,8 +61,6 @@
 
   auto profile = std::make_unique<TestingProfile>();
   profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable, true);
-  profile->GetPrefs()->SetBoolean(
-      spellcheck::prefs::kSpellCheckUseSpellingService, true);
 
   // Construct fake output
   machine_learning::mojom::GrammarCheckerResultPtr result =
@@ -112,8 +108,6 @@
 
   auto profile = std::make_unique<TestingProfile>();
   profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable, true);
-  profile->GetPrefs()->SetBoolean(
-      spellcheck::prefs::kSpellCheckUseSpellingService, true);
 
   // Construct fake output
   std::vector<machine_learning::mojom::TextLanguagePtr> languages;
@@ -142,8 +136,6 @@
 
   auto profile = std::make_unique<TestingProfile>();
   profile->GetPrefs()->SetBoolean(spellcheck::prefs::kSpellCheckEnable, true);
-  profile->GetPrefs()->SetBoolean(
-      spellcheck::prefs::kSpellCheckUseSpellingService, true);
 
   GrammarServiceClient client;
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc
index ef4ef2b9..9735fcf 100644
--- a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc
+++ b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc
@@ -72,7 +72,6 @@
   for (auto* user : logged_in_users) {
     if (user->GetType() == user_manager::USER_TYPE_REGULAR ||
         user->GetType() == user_manager::USER_TYPE_GUEST ||
-        user->GetType() == user_manager::USER_TYPE_SUPERVISED_DEPRECATED ||
         user->GetType() == user_manager::USER_TYPE_CHILD) {
       users_to_check.push_back(user);
     }
diff --git a/chrome/browser/chromeos/policy/reporting/extension_install_event_log_collector.cc b/chrome/browser/chromeos/policy/reporting/extension_install_event_log_collector.cc
index 2a4236e..af8b8f70 100644
--- a/chrome/browser/chromeos/policy/reporting/extension_install_event_log_collector.cc
+++ b/chrome/browser/chromeos/policy/reporting/extension_install_event_log_collector.cc
@@ -150,9 +150,6 @@
       return em::ExtensionInstallReportLogEvent::USER_TYPE_GUEST;
     case user_manager::USER_TYPE_PUBLIC_ACCOUNT:
       return em::ExtensionInstallReportLogEvent::USER_TYPE_PUBLIC_ACCOUNT;
-    case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
-      return em::ExtensionInstallReportLogEvent::
-          USER_TYPE_SUPERVISED_DEPRECATED;
     case user_manager::USER_TYPE_KIOSK_APP:
       return em::ExtensionInstallReportLogEvent::USER_TYPE_KIOSK_APP;
     case user_manager::USER_TYPE_CHILD:
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 9348bc9..bbfa636 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -981,16 +981,6 @@
     }
   }
 
-  if (enable_autofill_assistant_api) {
-    sources += [
-      "api/autofill_assistant_private/autofill_assistant_private_api.cc",
-      "api/autofill_assistant_private/autofill_assistant_private_api.h",
-      "api/autofill_assistant_private/extension_access_token_fetcher.cc",
-      "api/autofill_assistant_private/extension_access_token_fetcher.h",
-    ]
-    deps += [ "//components/autofill_assistant/browser" ]
-  }
-
   if (is_chromeos) {
     sources += [
       "api/enterprise_device_attributes/enterprise_device_attributes_api.h",
diff --git a/chrome/browser/extensions/activity_log/activity_database.cc b/chrome/browser/extensions/activity_log/activity_database.cc
index ad762fd..edd089c 100644
--- a/chrome/browser/extensions/activity_log/activity_database.cc
+++ b/chrome/browser/extensions/activity_log/activity_database.cc
@@ -39,7 +39,7 @@
 
 ActivityDatabase::ActivityDatabase(ActivityDatabase::Delegate* delegate)
     : delegate_(delegate),
-      db_({.exclusive_locking = false, .page_size = 4096, .cache_size = 32}),
+      db_({.exclusive_locking = true, .page_size = 4096, .cache_size = 32}),
       valid_db_(false),
       batch_mode_(true),
       already_closed_(false),
diff --git a/chrome/browser/extensions/api/autofill_assistant_private/OWNERS b/chrome/browser/extensions/api/autofill_assistant_private/OWNERS
deleted file mode 100644
index ed6d5f0..0000000
--- a/chrome/browser/extensions/api/autofill_assistant_private/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://components/autofill_assistant/OWNERS
diff --git a/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_api.cc b/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_api.cc
deleted file mode 100644
index 6bba029..0000000
--- a/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_api.cc
+++ /dev/null
@@ -1,442 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_api.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/no_destructor.h"
-#include "base/time/default_tick_clock.h"
-#include "base/values.h"
-#include "chrome/browser/autofill/personal_data_manager_factory.h"
-#include "chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher.h"
-#include "chrome/browser/extensions/chrome_extension_function_details.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/channel_info.h"
-#include "components/autofill/core/browser/field_types.h"
-#include "extensions/browser/event_router_factory.h"
-
-namespace extensions {
-namespace {
-content::WebContents* GetActiveWebContents(ExtensionFunction* function) {
-  // TODO(crbug.com/1015753): GetCurrentBrowser is not deterministic and needs
-  // to be replaced with an explicit tabID passed to the create(...) extension
-  // function.
-  return ChromeExtensionFunctionDetails(function)
-      .GetCurrentBrowser()
-      ->tab_strip_model()
-      ->GetActiveWebContents();
-}
-}  // namespace
-
-AutofillAssistantPrivateCreateFunction::
-    AutofillAssistantPrivateCreateFunction() = default;
-
-AutofillAssistantPrivateCreateFunction::
-    ~AutofillAssistantPrivateCreateFunction() = default;
-
-ExtensionFunction::ResponseAction
-AutofillAssistantPrivateCreateFunction::Run() {
-  auto* web_contents = GetActiveWebContents(this);
-  CHECK(web_contents);
-  AutofillAssistantPrivateAPI::GetFactoryInstance()
-      ->Get(browser_context())
-      ->CreateAutofillAssistantController(web_contents);
-
-  // TODO(crbug.com/1015753): Add unittests and check that no arguments are
-  // returned!
-  return RespondNow(NoArguments());
-}
-
-AutofillAssistantPrivateStartFunction::AutofillAssistantPrivateStartFunction() =
-    default;
-
-AutofillAssistantPrivateStartFunction::
-    ~AutofillAssistantPrivateStartFunction() = default;
-
-ExtensionFunction::ResponseAction AutofillAssistantPrivateStartFunction::Run() {
-  std::unique_ptr<api::autofill_assistant_private::Start::Params> params =
-      api::autofill_assistant_private::Start::Params::Create(*args_);
-  EXTENSION_FUNCTION_VALIDATE(params.get());
-
-  // TODO(crbug.com/1015753): Populate parameters from params.
-  std::map<std::string, std::string> parameters;
-
-  bool ok = AutofillAssistantPrivateAPI::GetFactoryInstance()
-                ->Get(browser_context())
-                ->StartAutofillAssistantController(std::move(parameters));
-
-  if (!ok) {
-    return RespondNow(Error("Starting requires a valid controller!"));
-  }
-  return RespondNow(NoArguments());
-}
-
-AutofillAssistantPrivatePerformActionFunction::
-    AutofillAssistantPrivatePerformActionFunction() = default;
-
-AutofillAssistantPrivatePerformActionFunction::
-    ~AutofillAssistantPrivatePerformActionFunction() = default;
-
-ExtensionFunction::ResponseAction
-AutofillAssistantPrivatePerformActionFunction::Run() {
-  std::unique_ptr<api::autofill_assistant_private::PerformAction::Params>
-      parameters =
-          api::autofill_assistant_private::PerformAction::Params::Create(
-              *args_);
-  EXTENSION_FUNCTION_VALIDATE(parameters.get());
-
-  bool ok = AutofillAssistantPrivateAPI::GetFactoryInstance()
-                ->Get(browser_context())
-                ->PerformAction(parameters->index);
-  if (!ok) {
-    return RespondNow(Error("performAction requires a valid controller!"));
-  }
-  return RespondNow(NoArguments());
-}
-
-AutofillAssistantPrivateProvideUserDataFunction::
-    AutofillAssistantPrivateProvideUserDataFunction() = default;
-
-AutofillAssistantPrivateProvideUserDataFunction::
-    ~AutofillAssistantPrivateProvideUserDataFunction() = default;
-
-ExtensionFunction::ResponseAction
-AutofillAssistantPrivateProvideUserDataFunction::Run() {
-  AutofillAssistantPrivateAPI::GetFactoryInstance()
-      ->Get(browser_context())
-      ->ProvideUserData();
-
-  return RespondNow(NoArguments());
-}
-
-AutofillAssistantPrivateEventRouter::AutofillAssistantPrivateEventRouter(
-    autofill_assistant::Controller* controller,
-    content::BrowserContext* browser_context)
-    : controller_(controller), browser_context_(browser_context) {
-  DCHECK_NE(nullptr, controller);
-  controller_->AddObserver(this);
-}
-
-AutofillAssistantPrivateEventRouter::~AutofillAssistantPrivateEventRouter() {}
-
-void AutofillAssistantPrivateEventRouter::OnUserActionsChanged(
-    const std::vector<autofill_assistant::UserAction>& user_actions) {
-  if (!HasEventListenerForEvent(
-          api::autofill_assistant_private::OnActionsChanged::kEventName))
-    return;
-
-  std::vector<api::autofill_assistant_private::ActionObject> actions;
-  actions.reserve(user_actions.size());
-  for (size_t i = 0; i < user_actions.size(); ++i) {
-    actions.emplace_back();
-    actions.back().name = user_actions[i].chip().text;
-    actions.back().index = i;
-  }
-
-  std::unique_ptr<base::ListValue> args(
-      api::autofill_assistant_private::OnActionsChanged::Create(actions));
-
-  std::unique_ptr<Event> extension_event = std::make_unique<Event>(
-      events::AUTOFILL_ASSISTANT_PRIVATE_ON_ACTIONS_CHANGED,
-      api::autofill_assistant_private::OnActionsChanged::kEventName,
-      std::move(args));
-  EventRouter::Get(browser_context_)
-      ->BroadcastEvent(std::move(extension_event));
-}
-
-void AutofillAssistantPrivateEventRouter::OnStatusMessageChanged(
-    const std::string& message) {
-  if (!HasEventListenerForEvent(
-          api::autofill_assistant_private::OnStatusMessageChanged::kEventName))
-    return;
-
-  std::unique_ptr<base::ListValue> args(
-      api::autofill_assistant_private::OnStatusMessageChanged::Create(message));
-
-  std::unique_ptr<Event> extension_event(new Event(
-      events::AUTOFILL_ASSISTANT_PRIVATE_ON_STATUS_MESSAGE_CHANGED,
-      api::autofill_assistant_private::OnStatusMessageChanged::kEventName,
-      std::move(args)));
-  EventRouter::Get(browser_context_)
-      ->BroadcastEvent(std::move(extension_event));
-}
-
-void AutofillAssistantPrivateEventRouter::OnStateChanged(
-    autofill_assistant::AutofillAssistantState new_state) {}
-
-void AutofillAssistantPrivateEventRouter::OnBubbleMessageChanged(
-    const std::string& message) {}
-
-void AutofillAssistantPrivateEventRouter::CloseCustomTab() {}
-
-void AutofillAssistantPrivateEventRouter::OnCollectUserDataOptionsChanged(
-    const autofill_assistant::CollectUserDataOptions* options) {}
-
-void AutofillAssistantPrivateEventRouter::OnUserDataChanged(
-    const autofill_assistant::UserData* state,
-    autofill_assistant::UserData::FieldChange field_change) {}
-
-void AutofillAssistantPrivateEventRouter::OnDetailsChanged(
-    const autofill_assistant::Details* details) {}
-
-void AutofillAssistantPrivateEventRouter::OnInfoBoxChanged(
-    const autofill_assistant::InfoBox* info_box) {}
-
-void AutofillAssistantPrivateEventRouter::OnProgressChanged(int progress) {}
-
-void AutofillAssistantPrivateEventRouter::OnProgressActiveStepChanged(
-    int active_step) {}
-
-void AutofillAssistantPrivateEventRouter::OnProgressVisibilityChanged(
-    bool visible) {}
-
-void AutofillAssistantPrivateEventRouter::OnStepProgressBarConfigurationChanged(
-    const autofill_assistant::ShowProgressBarProto::
-        StepProgressBarConfiguration& configuration) {}
-
-void AutofillAssistantPrivateEventRouter::OnProgressBarErrorStateChanged(
-    bool error) {}
-
-void AutofillAssistantPrivateEventRouter::OnTouchableAreaChanged(
-    const autofill_assistant::RectF& visual_viewport,
-    const std::vector<autofill_assistant::RectF>& touchable_areas,
-    const std::vector<autofill_assistant::RectF>& restricted_areas) {}
-
-void AutofillAssistantPrivateEventRouter::OnViewportModeChanged(
-    autofill_assistant::ViewportMode mode) {}
-
-void AutofillAssistantPrivateEventRouter::OnPeekModeChanged(
-    autofill_assistant::ConfigureBottomSheetProto::PeekMode peek_mode) {}
-
-void AutofillAssistantPrivateEventRouter::OnOverlayColorsChanged(
-    const autofill_assistant::UiDelegate::OverlayColors& colors) {}
-
-void AutofillAssistantPrivateEventRouter::OnFormChanged(
-    const autofill_assistant::FormProto* form,
-    const autofill_assistant::FormProto::Result* result) {}
-
-void AutofillAssistantPrivateEventRouter::OnClientSettingsChanged(
-    const autofill_assistant::ClientSettings& settings) {}
-
-void AutofillAssistantPrivateEventRouter::OnGenericUserInterfaceChanged(
-    const autofill_assistant::GenericUserInterfaceProto* generic_ui) {}
-
-void AutofillAssistantPrivateEventRouter::OnExpandBottomSheet() {}
-
-void AutofillAssistantPrivateEventRouter::OnCollapseBottomSheet() {}
-
-bool AutofillAssistantPrivateEventRouter::HasEventListenerForEvent(
-    const char* event_name) {
-  return EventRouter::Get(browser_context_)->HasEventListener(event_name);
-}
-
-// static
-BrowserContextKeyedAPIFactory<AutofillAssistantPrivateAPI>*
-AutofillAssistantPrivateAPI::GetFactoryInstance() {
-  static base::NoDestructor<
-      BrowserContextKeyedAPIFactory<AutofillAssistantPrivateAPI>>
-      instance;
-  return instance.get();
-}
-
-template <>
-void BrowserContextKeyedAPIFactory<
-    AutofillAssistantPrivateAPI>::DeclareFactoryDependencies() {
-  DependsOn(EventRouterFactory::GetInstance());
-}
-
-AutofillAssistantPrivateAPI::AutofillAssistantPrivateAPI(
-    content::BrowserContext* context)
-    : browser_context_(context) {
-  access_token_fetcher_ = std::make_unique<ExtensionAccessTokenFetcher>(
-      IdentityManagerFactory::GetForProfile(
-          Profile::FromBrowserContext(browser_context_)));
-}
-
-AutofillAssistantPrivateAPI::~AutofillAssistantPrivateAPI() {
-  access_token_fetcher_.reset();
-}
-
-void AutofillAssistantPrivateAPI::CreateAutofillAssistantController(
-    content::WebContents* web_contents) {
-  if (active_autofill_assistant_) {
-    DestroyActiveAutofillAssistant();
-  }
-
-  CreateActiveAutofillAssistant(web_contents);
-}
-
-bool AutofillAssistantPrivateAPI::StartAutofillAssistantController(
-    std::map<std::string, std::string> parameters) {
-  if (!active_autofill_assistant_)
-    return false;
-
-  // TODO(crbug.com/1015753): Remove the hard coded parameter and use |params|
-  // instead. The url usually comes from an Android intent data URL and is
-  // logged as the trigger deep link. This does not fully translate to the
-  // extension use case and needs more thought. For now we pass in a dummy URL.
-  parameters["DETAILS_SHOW_INITIAL"] = "false";
-  const std::string url = "http://localhost:8080/test.html";
-
-  auto context = autofill_assistant::TriggerContext::Create(parameters, "");
-  active_autofill_assistant_->controller->Start(GURL(url), std::move(context));
-  return true;
-}
-
-bool AutofillAssistantPrivateAPI::PerformAction(int index) {
-  if (!active_autofill_assistant_)
-    return false;
-  active_autofill_assistant_->controller->PerformUserAction(index);
-  return true;
-}
-
-bool AutofillAssistantPrivateAPI::ProvideUserData() {
-  if (!active_autofill_assistant_)
-    return false;
-
-  auto* controller = active_autofill_assistant_->controller.get();
-
-  // TODO(crbug.com/1015753): Plumb the hard coded user data to the idl
-  // interface definition and expose it to the extension.
-  // Note that the set of empty profiles provided here is currently not
-  // sufficient for a working e2e flow.
-  auto shipping = std::make_unique<autofill::AutofillProfile>();
-  // TBD: set some shipping fields.
-  controller->SetShippingAddress(std::move(shipping));
-  auto contact = std::make_unique<autofill::AutofillProfile>();
-  controller->SetContactInfo(std::move(contact));
-
-  auto billing = std::make_unique<autofill::AutofillProfile>();
-  auto card = std::make_unique<autofill::CreditCard>();
-  card->set_billing_address_id(billing->guid());
-
-  controller->SetCreditCard(std::move(card), std::move(billing));
-  controller->SetTermsAndConditions(
-      autofill_assistant::TermsAndConditionsState::ACCEPTED);
-  return true;
-}
-
-void AutofillAssistantPrivateAPI::AttachUI() {}
-
-void AutofillAssistantPrivateAPI::DestroyUI() {}
-
-version_info::Channel AutofillAssistantPrivateAPI::GetChannel() const {
-  // TODO(crbug.com/1015753): Make a minimal client impl available in a common
-  // chrome/browser/autofill_assistant and share it with the android client
-  // impl.
-  return chrome::GetChannel();
-}
-
-std::string AutofillAssistantPrivateAPI::GetEmailAddressForAccessTokenAccount()
-    const {
-  return "joe@example.com";
-}
-
-std::string AutofillAssistantPrivateAPI::GetChromeSignedInEmailAddress() const {
-  return "joe@example.com";
-}
-
-autofill_assistant::AccessTokenFetcher*
-AutofillAssistantPrivateAPI::GetAccessTokenFetcher() {
-  return access_token_fetcher_.get();
-}
-
-autofill::PersonalDataManager*
-AutofillAssistantPrivateAPI::GetPersonalDataManager() const {
-  return autofill::PersonalDataManagerFactory::GetForProfile(
-      Profile::FromBrowserContext(browser_context_));
-}
-
-password_manager::PasswordManagerClient*
-AutofillAssistantPrivateAPI::GetPasswordManagerClient() const {
-  // TODO(crbug.com/1015753): Support credential leak flows.
-  return nullptr;
-}
-
-autofill_assistant::WebsiteLoginManager*
-AutofillAssistantPrivateAPI::GetWebsiteLoginManager() const {
-  return nullptr;
-}
-
-std::string AutofillAssistantPrivateAPI::GetLocale() const {
-  return "en-us";
-}
-
-std::string AutofillAssistantPrivateAPI::GetCountryCode() const {
-  return "us";
-}
-
-autofill_assistant::DeviceContext
-AutofillAssistantPrivateAPI::GetDeviceContext() const {
-  return autofill_assistant::DeviceContext();
-}
-
-bool AutofillAssistantPrivateAPI::IsAccessibilityEnabled() const {
-  return false;
-}
-
-void AutofillAssistantPrivateAPI::Shutdown(
-    autofill_assistant::Metrics::DropOutReason reason) {}
-
-void AutofillAssistantPrivateAPI::RecordDropOut(
-    autofill_assistant::Metrics::DropOutReason reason) {}
-
-void bool AutofillAssistantPrivateAPI::HasHadUI() {
-  return true;
-}
-
-// Note that this method implements autofill_assistant::Client and simply
-// forwards the web_contents associated with the controller. There is no reason
-// to use this method in this context.
-// TODO(crbug.com/1015753): Revisit the interfaces used for this extension API
-// and introduce new, more concise ones if needed.
-content::WebContents* AutofillAssistantPrivateAPI::GetWebContents() const {
-  if (!active_autofill_assistant_)
-    return nullptr;
-  return active_autofill_assistant_->controller->GetWebContents();
-}
-
-void AutofillAssistantPrivateAPI::Shutdown() {
-  if (active_autofill_assistant_)
-    DestroyActiveAutofillAssistant();
-}
-
-AutofillAssistantPrivateAPI::ActiveAutofillAssistant::
-    ActiveAutofillAssistant() {}
-AutofillAssistantPrivateAPI::ActiveAutofillAssistant::
-    ~ActiveAutofillAssistant() {}
-
-void AutofillAssistantPrivateAPI::CreateActiveAutofillAssistant(
-    content::WebContents* web_contents) {
-  active_autofill_assistant_ = std::make_unique<ActiveAutofillAssistant>();
-  // TODO(crbug.com/1015753): Make sure web_contents going away is properly
-  // handled by the controller. And if so, clean up state here.
-  active_autofill_assistant_->controller =
-      std::make_unique<autofill_assistant::Controller>(
-          web_contents, this, base::DefaultTickClock::GetInstance(),
-          std::move(service_));
-  active_autofill_assistant_->event_router =
-      std::make_unique<AutofillAssistantPrivateEventRouter>(
-          active_autofill_assistant_->controller.get(), browser_context_);
-}
-
-void AutofillAssistantPrivateAPI::DestroyActiveAutofillAssistant() {
-  // The event router has a reference to controller, so that is being cleaned up
-  // first.
-  active_autofill_assistant_->event_router.reset();
-  active_autofill_assistant_->controller.reset();
-  active_autofill_assistant_.reset();
-}
-
-void AutofillAssistantPrivateAPI::SetService(
-    std::unique_ptr<autofill_assistant::Service> service) {
-  DCHECK_EQ(nullptr, service_);
-  service_ = std::move(service);
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_api.h b/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_api.h
deleted file mode 100644
index ae35aa0..0000000
--- a/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_api.h
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_ASSISTANT_PRIVATE_AUTOFILL_ASSISTANT_PRIVATE_API_H_
-#define CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_ASSISTANT_PRIVATE_AUTOFILL_ASSISTANT_PRIVATE_API_H_
-
-#include <string>
-
-#include "chrome/common/extensions/api/autofill_assistant_private.h"
-#include "components/autofill_assistant/browser/client.h"
-#include "components/autofill_assistant/browser/controller.h"
-#include "components/autofill_assistant/browser/controller_observer.h"
-#include "components/autofill_assistant/browser/service.h"
-#include "extensions/browser/browser_context_keyed_api_factory.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_function.h"
-
-namespace extensions {
-
-class AutofillAssistantPrivateCreateFunction : public ExtensionFunction {
- public:
-  AutofillAssistantPrivateCreateFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillAssistantPrivate.create",
-                             AUTOFILLASSISTANTPRIVATE_CREATE)
-
-  AutofillAssistantPrivateCreateFunction(
-      const AutofillAssistantPrivateCreateFunction&) = delete;
-  AutofillAssistantPrivateCreateFunction& operator=(
-      const AutofillAssistantPrivateCreateFunction&) = delete;
-
- protected:
-  ~AutofillAssistantPrivateCreateFunction() override;
-
-  // ExtensionFunction:
-  ResponseAction Run() override;
-};
-
-class AutofillAssistantPrivateStartFunction : public ExtensionFunction {
- public:
-  AutofillAssistantPrivateStartFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillAssistantPrivate.start",
-                             AUTOFILLASSISTANTPRIVATE_START)
-
-  AutofillAssistantPrivateStartFunction(
-      const AutofillAssistantPrivateStartFunction&) = delete;
-  AutofillAssistantPrivateStartFunction& operator=(
-      const AutofillAssistantPrivateStartFunction&) = delete;
-
- protected:
-  ~AutofillAssistantPrivateStartFunction() override;
-
-  // ExtensionFunction:
-  ResponseAction Run() override;
-};
-
-class AutofillAssistantPrivateGetStateFunction : public ExtensionFunction {
- public:
-  AutofillAssistantPrivateGetStateFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillAssistantPrivate.getState",
-                             AUTOFILLASSISTANTPRIVATE_GETSTATE)
-
-  AutofillAssistantPrivateGetStateFunction(
-      const AutofillAssistantPrivateGetStateFunction&) = delete;
-  AutofillAssistantPrivateGetStateFunction& operator=(
-      const AutofillAssistantPrivateGetStateFunction&) = delete;
-
- protected:
-  ~AutofillAssistantPrivateGetStateFunction() override;
-
-  // ExtensionFunction:
-  ResponseAction Run() override;
-};
-
-class AutofillAssistantPrivatePerformActionFunction : public ExtensionFunction {
- public:
-  AutofillAssistantPrivatePerformActionFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillAssistantPrivate.performAction",
-                             AUTOFILLASSISTANTPRIVATE_PERFORMACTION)
-
-  AutofillAssistantPrivatePerformActionFunction(
-      const AutofillAssistantPrivatePerformActionFunction&) = delete;
-  AutofillAssistantPrivatePerformActionFunction& operator=(
-      const AutofillAssistantPrivatePerformActionFunction&) = delete;
-
- protected:
-  ~AutofillAssistantPrivatePerformActionFunction() override;
-
-  // ExtensionFunction:
-  ResponseAction Run() override;
-};
-
-class AutofillAssistantPrivateProvideUserDataFunction
-    : public ExtensionFunction {
- public:
-  AutofillAssistantPrivateProvideUserDataFunction();
-  DECLARE_EXTENSION_FUNCTION("autofillAssistantPrivate.provideUserData",
-                             AUTOFILLASSISTANTPRIVATE_PROVIDEUSERDATA)
-
-  AutofillAssistantPrivateProvideUserDataFunction(
-      const AutofillAssistantPrivateProvideUserDataFunction&) = delete;
-  AutofillAssistantPrivateProvideUserDataFunction& operator=(
-      const AutofillAssistantPrivateProvideUserDataFunction&) = delete;
-
- protected:
-  ~AutofillAssistantPrivateProvideUserDataFunction() override;
-
-  // ExtensionFunction:
-  ResponseAction Run() override;
-};
-
-class AutofillAssistantPrivateEventRouter
-    : public autofill_assistant::ControllerObserver {
- public:
-  AutofillAssistantPrivateEventRouter(
-      autofill_assistant::Controller* controller,
-      content::BrowserContext* browser_context);
-  ~AutofillAssistantPrivateEventRouter() override;
-
-  AutofillAssistantPrivateEventRouter(
-      const AutofillAssistantPrivateEventRouter&) = delete;
-  AutofillAssistantPrivateEventRouter& operator=(
-      const AutofillAssistantPrivateEventRouter&) = delete;
-
-  // autofill_assistant::ControllerObserver:
-  void OnUserActionsChanged(
-      const std::vector<autofill_assistant::UserAction>& user_actions) override;
-  void OnStatusMessageChanged(const std::string& message) override;
-  // TODO(crbug.com/1015753): Expose more notifications as needed here.
-  void OnStateChanged(
-      autofill_assistant::AutofillAssistantState new_state) override;
-  void OnBubbleMessageChanged(const std::string& message) override;
-  void CloseCustomTab() override;
-  void OnCollectUserDataOptionsChanged(
-      const autofill_assistant::CollectUserDataOptions* options) override;
-  void OnUserDataChanged(
-      const autofill_assistant::UserData* state,
-      autofill_assistant::UserData::FieldChange field_change) override;
-  void OnDetailsChanged(const autofill_assistant::Details* details) override;
-  void OnInfoBoxChanged(const autofill_assistant::InfoBox* info_box) override;
-  void OnProgressChanged(int progress) override;
-  void OnProgressActiveStepChanged(int active_step) override;
-  void OnProgressVisibilityChanged(bool visible) override;
-  void OnStepProgressBarConfigurationChanged(
-      const autofill_assistant::ShowProgressBarProto::
-          StepProgressBarConfiguration& configuration) override;
-  void OnProgressBarErrorStateChanged(bool error) override;
-  void OnTouchableAreaChanged(
-      const autofill_assistant::RectF& visual_viewport,
-      const std::vector<autofill_assistant::RectF>& touchable_areas,
-      const std::vector<autofill_assistant::RectF>& restricted_areas) override;
-  void OnViewportModeChanged(autofill_assistant::ViewportMode mode) override;
-  void OnPeekModeChanged(autofill_assistant::ConfigureBottomSheetProto::PeekMode
-                             peek_mode) override;
-  void OnOverlayColorsChanged(
-      const autofill_assistant::UiDelegate::OverlayColors& colors) override;
-  void OnFormChanged(
-      const autofill_assistant::FormProto* form,
-      const autofill_assistant::FormProto::Result* result) override;
-  void OnClientSettingsChanged(
-      const autofill_assistant::ClientSettings& settings) override;
-  void OnGenericUserInterfaceChanged(
-      const autofill_assistant::GenericUserInterfaceProto* generic_ui) override;
-
-  void OnExpandBottomSheet() override;
-  void OnCollapseBottomSheet() override;
-
- private:
-  bool HasEventListenerForEvent(const char* event_name);
-
-  // |controller_|'s lifetime and this object are managed by the
-  // AutofillAssistantPrivateAPI, and |controller_| is guaranteed to be alive
-  // while this object is around.
-  autofill_assistant::Controller* controller_;
-  content::BrowserContext* browser_context_;
-};
-
-class AutofillAssistantPrivateAPI : public BrowserContextKeyedAPI,
-                                    public autofill_assistant::Client {
- public:
-  static BrowserContextKeyedAPIFactory<AutofillAssistantPrivateAPI>*
-  GetFactoryInstance();
-
-  explicit AutofillAssistantPrivateAPI(content::BrowserContext* context);
-  ~AutofillAssistantPrivateAPI() override;
-
-  AutofillAssistantPrivateAPI(const AutofillAssistantPrivateAPI&) = delete;
-  AutofillAssistantPrivateAPI& operator=(const AutofillAssistantPrivateAPI&) =
-      delete;
-
-  void CreateAutofillAssistantController(content::WebContents* web_contents);
-  bool StartAutofillAssistantController(
-      std::map<std::string, std::string> params);
-  // Relay a selected action to the autofill assistant controller.
-  bool PerformAction(int index);
-  // Provides user data to the controller.
-  // TODO(crbug.com/1015753): Flesh this out to let the extension pass in user
-  // data.
-  bool ProvideUserData();
-
-  // autofill_assistant::Client:
-  void AttachUI() override;
-  void DestroyUI() override;
-  version_info::Channel GetChannel() const override;
-  std::string GetEmailAddressForAccessTokenAccount() const override;
-  std::string GetChromeSignedInEmailAddress() const override;
-  autofill_assistant::AccessTokenFetcher* GetAccessTokenFetcher() override;
-  autofill::PersonalDataManager* GetPersonalDataManager() const override;
-  password_manager::PasswordManagerClient* GetPasswordManagerClient()
-      const override;
-  autofill_assistant::WebsiteLoginManager* GetWebsiteLoginManager()
-      const override;
-  std::string GetLocale() const override;
-  std::string GetCountryCode() const override;
-  autofill_assistant::DeviceContext GetDeviceContext() const override;
-  bool IsAccessibilityEnabled() const override;
-  void Shutdown(autofill_assistant::Metrics::DropOutReason reason) override;
-  content::WebContents* GetWebContents() const override;
-  void RecordDropOut(Metrics::DropOutReason reason) override;
-  bool HasHadUI() const override;
-
-  // BrowserContextKeyedAPI:
-  void Shutdown() override;
-
-  // Used to inject a mock backend service in tests.
-  void SetService(std::unique_ptr<autofill_assistant::Service> service);
-
- private:
-  friend class BrowserContextKeyedAPIFactory<AutofillAssistantPrivateAPI>;
-
-  // BrowserContextKeyedAPI:
-  static const char* service_name() { return "AutofillAssistantPrivateAPI"; }
-  static const bool kServiceIsNULLWhileTesting = true;
-
-  void CreateActiveAutofillAssistant(content::WebContents* web_contents);
-  void DestroyActiveAutofillAssistant();
-
-  content::BrowserContext* browser_context_;
-  std::unique_ptr<autofill_assistant::Service> service_;
-
-  // This struct ties the lifecycle of the event router and the controller
-  // together. That way event are only dispatched when both are alive.
-  struct ActiveAutofillAssistant {
-    ActiveAutofillAssistant();
-    ~ActiveAutofillAssistant();
-
-    std::unique_ptr<autofill_assistant::Controller> controller;
-    std::unique_ptr<AutofillAssistantPrivateEventRouter> event_router;
-  };
-  std::unique_ptr<ActiveAutofillAssistant> active_autofill_assistant_;
-  std::unique_ptr<autofill_assistant::AccessTokenFetcher> access_token_fetcher_;
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_ASSISTANT_PRIVATE_AUTOFILL_ASSISTANT_PRIVATE_API_H_
diff --git a/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_apitest.cc b/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_apitest.cc
deleted file mode 100644
index d00b5b8..0000000
--- a/chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_apitest.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/test/gmock_callback_support.h"
-#include "base/test/mock_callback.h"
-#include "base/values.h"
-#include "chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_api.h"
-#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/common/extensions/api/autofill_assistant_private.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/autofill_assistant/browser/mock_service.h"
-#include "components/autofill_assistant/browser/service.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/test_utils.h"
-#include "extensions/common/switches.h"
-#include "net/dns/mock_host_resolver.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace extensions {
-
-namespace {
-
-using autofill_assistant::ActionsResponseProto;
-using autofill_assistant::MockService;
-using autofill_assistant::SupportedScriptProto;
-using autofill_assistant::SupportsScriptResponseProto;
-using autofill_assistant::TellProto;
-using base::test::RunOnceCallback;
-using testing::_;
-using testing::NiceMock;
-using testing::StrEq;
-
-// TODO(crbug.com/1015753): We have to split some of these tests up due to the
-// MockService being owned by the controller. If we were to run two tests that
-// create a controller in the same browser test, the mock service is lost and a
-// real ServiceImpl is used. This is an issue in the architecture of the
-// controller and service and should be changed to avoid this issue.
-class AutofillAssistantPrivateApiTest : public ExtensionApiTest {
- public:
-  AutofillAssistantPrivateApiTest() = default;
-  AutofillAssistantPrivateApiTest(const AutofillAssistantPrivateApiTest&) =
-      delete;
-  AutofillAssistantPrivateApiTest& operator=(
-      const AutofillAssistantPrivateApiTest&) = delete;
-
-  void SetUpOnMainThread() override {
-    ExtensionApiTest::SetUpOnMainThread();
-
-    auto service = std::make_unique<NiceMock<MockService>>();
-    mock_service_ = service.get();
-
-    AutofillAssistantPrivateAPI::GetFactoryInstance()
-        ->Get(browser()->profile())
-        ->SetService(std::move(service));
-
-    // Prepare the mock service to return two scripts when asked.
-    SupportsScriptResponseProto scripts_proto;
-    SupportedScriptProto* script = scripts_proto.add_scripts();
-    script->set_path("some/path");
-    script->mutable_presentation()->mutable_chip()->set_text("Action 0");
-    SupportedScriptProto* script1 = scripts_proto.add_scripts();
-    script1->set_path("some/path");
-    script1->mutable_presentation()->mutable_chip()->set_text("Action 1");
-    std::string scripts_output;
-    scripts_proto.SerializeToString(&scripts_output);
-    ON_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
-        .WillByDefault(RunOnceCallback<2>(true, scripts_output));
-
-    // Always return a script with a single tell action.
-    ActionsResponseProto actions_proto;
-    TellProto* tell_action = actions_proto.add_actions()->mutable_tell();
-    tell_action->set_message("This is a test status.");
-    std::string actions_output;
-    actions_proto.SerializeToString(&actions_output);
-    ON_CALL(*mock_service_, OnGetActions(StrEq("some/path"), _, _, _, _, _))
-        .WillByDefault(RunOnceCallback<5>(true, actions_output));
-
-    // We never return more additional actions.
-    ON_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _))
-        .WillByDefault(RunOnceCallback<4>(true, ""));
-  }
-
- private:
-  std::unique_ptr<MockService> service_;
-  MockService* mock_service_;
-};
-
-IN_PROC_BROWSER_TEST_F(AutofillAssistantPrivateApiTest, DefaultTest) {
-  ui_test_utils::NavigateToURL(browser(), GURL("chrome://version"));
-  EXPECT_TRUE(
-      RunComponentExtensionTestWithArg("autofill_assistant_private", "default"))
-      << message_;
-}
-
-}  // namespace
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher.cc b/chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher.cc
deleted file mode 100644
index 5d4cc3b..0000000
--- a/chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher.h"
-
-#include "base/callback.h"
-#include "components/signin/public/identity_manager/access_token_fetcher.h"
-#include "components/signin/public/identity_manager/access_token_info.h"
-#include "components/signin/public/identity_manager/scope_set.h"
-#include "google_apis/gaia/gaia_constants.h"
-
-namespace extensions {
-
-ExtensionAccessTokenFetcher::ExtensionAccessTokenFetcher(
-    signin::IdentityManager* identity_manager)
-    : identity_manager_(identity_manager) {}
-
-ExtensionAccessTokenFetcher::~ExtensionAccessTokenFetcher() = default;
-
-void ExtensionAccessTokenFetcher::FetchAccessToken(
-    base::OnceCallback<void(bool, const std::string&)> callback) {
-  // TODO(b/143736397): Use a more flexible logic to pick this account.
-  auto account_info =
-      identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync);
-
-  callback_ = std::move(callback);
-  signin::ScopeSet scopes;
-  scopes.insert(GaiaConstants::kGoogleUserInfoProfile);
-  auto mode = signin::AccessTokenFetcher::Mode::kImmediate;
-  access_token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForAccount(
-      account_info.account_id,
-      /*consumer_name=*/"AccessTokenFetcher", scopes,
-      base::BindOnce(&ExtensionAccessTokenFetcher::OnCompleted,
-                     // It is safe to use base::Unretained as
-                     // |this| owns |access_token_fetcher_|.
-                     base::Unretained(this)),
-      mode);
-}
-
-void ExtensionAccessTokenFetcher::InvalidateAccessToken(
-    const std::string& access_token) {
-  // TODO(b/143736397) Implement this by providing the data required for
-  // RemoveAccessTokenFromCache?
-}
-
-void ExtensionAccessTokenFetcher::OnCompleted(
-    GoogleServiceAuthError error,
-    signin::AccessTokenInfo access_token_info) {
-  access_token_fetcher_.reset();
-
-  if (!callback_)
-    return;
-
-  if (error.state() == GoogleServiceAuthError::NONE) {
-    std::move(callback_).Run(true, access_token_info.token);
-  } else {
-    VLOG(2) << "Access token fetching failed with error state " << error.state()
-            << " and message " << error.ToString();
-    std::move(callback_).Run(false, "");
-  }
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher.h b/chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher.h
deleted file mode 100644
index f94060e..0000000
--- a/chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_ASSISTANT_PRIVATE_EXTENSION_ACCESS_TOKEN_FETCHER_H_
-#define CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_ASSISTANT_PRIVATE_EXTENSION_ACCESS_TOKEN_FETCHER_H_
-
-#include "components/autofill_assistant/browser/access_token_fetcher.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
-
-namespace extensions {
-
-// A class that fetches tokens as needed for requests to Autofill Assistant
-// backends. This is an implementation provided to a service in the AA
-// component.
-class ExtensionAccessTokenFetcher
-    : public autofill_assistant::AccessTokenFetcher {
- public:
-  explicit ExtensionAccessTokenFetcher(
-      signin::IdentityManager* identity_manager);
-  ~ExtensionAccessTokenFetcher() override;
-
-  // AccessTokenFetcher:
-  void FetchAccessToken(
-      base::OnceCallback<void(bool, const std::string&)> callback) override;
-  void InvalidateAccessToken(const std::string& access_token) override;
-
- private:
-  void OnCompleted(GoogleServiceAuthError error,
-                   signin::AccessTokenInfo access_token_info);
-
-  signin::IdentityManager* identity_manager_;
-  std::unique_ptr<signin::AccessTokenFetcher> access_token_fetcher_;
-  base::OnceCallback<void(bool, const std::string&)> callback_;
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_ASSISTANT_PRIVATE_EXTENSION_ACCESS_TOKEN_FETCHER_H_
diff --git a/chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher_unittest.cc b/chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher_unittest.cc
deleted file mode 100644
index ed0dfb28..0000000
--- a/chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher_unittest.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher.h"
-
-#include "base/test/gmock_callback_support.h"
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "components/signin/public/identity_manager/identity_test_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace extensions {
-
-class ExtensionAccessTokenFetcherTest : public testing::Test {
- public:
-  ExtensionAccessTokenFetcherTest() = default;
-  ~ExtensionAccessTokenFetcherTest() override = default;
-
-  void SetUp() override {
-    identity_test_env_.MakePrimaryAccountAvailable("primary@example.com",
-                                                   signin::ConsentLevel::kSync);
-  }
-
-  void TearDown() override {}
-
- protected:
-  // The environment needs to be the first member to be initialized.
-  base::test::TaskEnvironment task_environment_;
-
-  signin::IdentityTestEnvironment identity_test_env_;
-};
-
-TEST_F(ExtensionAccessTokenFetcherTest, SuccessfulAccessTokenFetch) {
-  base::MockCallback<base::OnceCallback<void(bool, const std::string&)>>
-      callback;
-  EXPECT_CALL(callback, Run(true, "access_token"));
-
-  ExtensionAccessTokenFetcher fetcher(identity_test_env_.identity_manager());
-  fetcher.FetchAccessToken(callback.Get());
-
-  identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
-      "access_token", base::Time::Max());
-}
-
-TEST_F(ExtensionAccessTokenFetcherTest, FailedAccessTokenFetch) {
-  base::MockCallback<base::OnceCallback<void(bool, const std::string&)>>
-      callback;
-  EXPECT_CALL(callback, Run(false, ""));
-
-  ExtensionAccessTokenFetcher fetcher(identity_test_env_.identity_manager());
-  fetcher.FetchAccessToken(callback.Get());
-
-  identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
-      GoogleServiceAuthError::FromConnectionError(
-          GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/terminal/terminal_private_api.cc b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
index c3772c1..743b9b9f 100644
--- a/chrome/browser/extensions/api/terminal/terminal_private_api.cc
+++ b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
@@ -298,6 +298,13 @@
     const std::string& user_id_hash,
     base::CommandLine cmdline,
     crostini::CrostiniResult result) {
+  if (crostini::MaybeShowCrostiniDialogBeforeLaunch(
+          Profile::FromBrowserContext(browser_context()), result)) {
+    const std::string msg = "Waiting for component update dialog response";
+    LOG(ERROR) << msg;
+    Respond(Error(msg));
+    return;
+  }
   startup_status_->OnCrostiniRestarted(result);
   if (result == crostini::CrostiniResult::SUCCESS) {
     OpenVmshellProcess(user_id_hash, std::move(cmdline));
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
index fd8e4ae..16f8a741 100644
--- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -67,18 +67,11 @@
 #include "chrome/browser/extensions/api/mdns/mdns_api.h"
 #endif
 
-#if BUILDFLAG(ENABLE_AUTOFILL_ASSISTANT_API)
-#include "chrome/browser/extensions/api/autofill_assistant_private/autofill_assistant_private_api.h"
-#endif
-
 namespace chrome_extensions {
 
 void EnsureBrowserContextKeyedServiceFactoriesBuilt() {
   extensions::ActivityLog::GetFactoryInstance();
   extensions::ActivityLogAPI::GetFactoryInstance();
-#if BUILDFLAG(ENABLE_AUTOFILL_ASSISTANT_API)
-  extensions::AutofillAssistantPrivateAPI::GetFactoryInstance();
-#endif
   extensions::AutofillPrivateEventRouterFactory::GetInstance();
   extensions::BluetoothLowEnergyAPI::GetFactoryInstance();
   extensions::BookmarksAPI::GetFactoryInstance();
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc
index 742de38..c78ef239 100644
--- a/chrome/browser/extensions/service_worker_apitest.cc
+++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -501,52 +501,6 @@
               HasSubstr("Logged from MV3 service worker"));
 }
 
-// Tests that two extensions with the same ServiceWorkerContext* can be
-// disabled successfully. This test ensures that the DCHECK in
-// ServiceWorkerTaskQueue::StopObserving does not fail in such a scenario.
-// Regression test for https://crbug.com/1223476
-IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
-                       ObserveServiceWorkerContext) {
-  static constexpr char kManifest1[] =
-      R"({
-           "name": "Empty Extension",
-           "manifest_version": 3,
-           "version": "0.1",
-           "background": {"service_worker": "worker.js"}
-         })";
-  static constexpr char kScript[] = "";
-
-  TestExtensionDir test_dir1;
-  test_dir1.WriteManifest(kManifest1);
-  test_dir1.WriteFile(FILE_PATH_LITERAL("worker.js"), kScript);
-
-  scoped_refptr<const Extension> extension1 =
-      LoadExtension(test_dir1.UnpackedPath());
-  ASSERT_TRUE(extension1);
-
-  static constexpr char kManifest2[] =
-      R"({
-           "name": "Empty Extension",
-           "manifest_version": 3,
-           "version": "0.1",
-           "background": {"service_worker": "worker.js"}
-         })";
-
-  TestExtensionDir test_dir2;
-  test_dir2.WriteManifest(kManifest2);
-  test_dir2.WriteFile(FILE_PATH_LITERAL("worker.js"), kScript);
-
-  scoped_refptr<const Extension> extension2 =
-      LoadExtension(test_dir2.UnpackedPath());
-  ASSERT_TRUE(extension2);
-  EXPECT_NE(extension1->id(), extension2->id());
-
-  extension_service()->DisableExtension(extension1->id(),
-                                        disable_reason::DISABLE_USER_ACTION);
-  extension_service()->DisableExtension(extension2->id(),
-                                        disable_reason::DISABLE_USER_ACTION);
-}
-
 // Tests chrome.runtime.onInstalled fires for extension service workers.
 IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest, OnInstalledEvent) {
   ASSERT_TRUE(RunExtensionTest(
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
index 797352d..462eb54 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -137,8 +137,6 @@
       return "guest";
     case user_manager::USER_TYPE_PUBLIC_ACCOUNT:
       return "public_account";
-    case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
-      return "supervised";
     case user_manager::USER_TYPE_KIOSK_APP:
       return "kiosk_app";
     case user_manager::USER_TYPE_CHILD:
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 0caf749..e198f67 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -836,6 +836,11 @@
     "expiry_milestone": 93
   },
   {
+    "name": "crostini-enable-dlc",
+    "owners": [ "sidereal", "davidmunro@google.com", "nverne" ],
+    "expiry_milestone": 92
+  },
+  {
     "name": "crostini-gpu-support",
     "owners": [ "nverne", "benwells" ],
     "expiry_milestone": 95
@@ -851,6 +856,11 @@
     "expiry_milestone": 99
   },
   {
+    "name": "crostini-use-dlc",
+    "owners": [ "sidereal", "davidmunro@google.com", "nverne" ],
+    "expiry_milestone": 92
+  },
+  {
     "name": "cryptauth-v2-device-activity-status",
     "owners": [ "khorimoto", "nohle", "themaxli" ],
     "expiry_milestone": 93
@@ -2798,8 +2808,8 @@
   },
   {
     "name": "enable-webrtc-hide-local-ips-with-mdns",
-    "owners": [ "qingsi" ],
-    "expiry_milestone": 90
+    "owners": [ "hta" ],
+    "expiry_milestone": 100
   },
   {
     "name": "enable-webrtc-hybrid-agc",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 42d50c74..919b4f7 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4209,6 +4209,11 @@
 const char kCrostiniGpuSupportName[] = "Crostini GPU Support";
 const char kCrostiniGpuSupportDescription[] = "Enable Crostini GPU support.";
 
+const char kCrostiniUseDlcName[] = "Crostini Use DLC";
+const char kCrostiniUseDlcDescription[] =
+    "Download the termina VM using the new DLC service instead of the old "
+    "component updater.";
+
 const char kCrostiniResetLxdDbName[] = "Crostini Reset LXD DB on launch";
 const char kCrostiniResetLxdDbDescription[] =
     "Recreates the LXD database every time we launch it";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 4892790..a6a1e2d 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2413,6 +2413,9 @@
 extern const char kCrostiniGpuSupportName[];
 extern const char kCrostiniGpuSupportDescription[];
 
+extern const char kCrostiniUseDlcName[];
+extern const char kCrostiniUseDlcDescription[];
+
 extern const char kCrostiniResetLxdDbName[];
 extern const char kCrostiniResetLxdDbDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 68f1ef1b..ea850bd 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -12,7 +12,6 @@
 #include "base/android/jni_string.h"
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
-#include "chrome/browser/browser_features.h"
 #include "chrome/browser/commerce/commerce_feature_list.h"
 #include "chrome/browser/flags/jni_headers/ChromeFeatureList_jni.h"
 #include "chrome/browser/notifications/chime/android/features.h"
@@ -116,7 +115,6 @@
     &features::kPrivacySandboxSettings,
     &features::kPrivacySandboxSettings2,
     &features::kPrioritizeBootstrapTasks,
-    &features::kPwaUpdateDialogForNameAndIcon,
     &features::kQuietNotificationPrompts,
     &features::kRequestDesktopSiteForTablets,
     &features::kSearchHistoryLink,
@@ -221,6 +219,7 @@
     &kOfflineMeasurementsBackgroundTask,
     &kPageAnnotationsService,
     &kProbabilisticCryptidRenderer,
+    &kPwaUpdateDialogForNameAndIcon,
     &kQuickActionSearchWidgetAndroid,
     &kReachedCodeProfiler,
     &kReaderModeInCCT,
@@ -612,6 +611,9 @@
 const base::Feature kProbabilisticCryptidRenderer{
     "ProbabilisticCryptidRenderer", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kPwaUpdateDialogForNameAndIcon{
+    "PwaUpdateDialogForNameAndIcon", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kQuickActionSearchWidgetAndroid{
     "QuickActionSearchWidgetAndroid", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 186bc00..b6b15089 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -101,6 +101,7 @@
 extern const base::Feature kOfflineIndicatorV2;
 extern const base::Feature kOfflineMeasurementsBackgroundTask;
 extern const base::Feature kPageAnnotationsService;
+extern const base::Feature kPwaUpdateDialogForNameAndIcon;
 extern const base::Feature kProbabilisticCryptidRenderer;
 extern const base::Feature kQuickActionSearchWidgetAndroid;
 extern const base::Feature kReachedCodeProfiler;
diff --git a/chrome/browser/policy/policy_network_browsertest.cc b/chrome/browser/policy/policy_network_browsertest.cc
index 19a9437c..2468c32 100644
--- a/chrome/browser/policy/policy_network_browsertest.cc
+++ b/chrome/browser/policy/policy_network_browsertest.cc
@@ -161,18 +161,10 @@
 
   virtual void GetQuicAllowedPolicy(PolicyMap* values) = 0;
 
-  // Crashes the network service and restarts the QUIC server. If the QUIC
-  // server isn't restarted, requests will fail with ERR_QUIC_PROTOCOL_ERROR.
-  // TODO(https://crbug.com/851532): The reason the server restart is needed is
-  // unclear, but ideally that should be fixed.
-  void CrashNetworkServiceAndRestartQuicServer() {
-    {
-      base::ScopedAllowBlockingForTesting allow_blocking;
-      net::QuicSimpleTestServer::Shutdown();
-    }
+  // Crashes the network service.
+  void CrashNetworkService() {
     SimulateNetworkServiceCrash();
     ConfigureMockCertVerifier();
-    ASSERT_TRUE(net::QuicSimpleTestServer::Start());
   }
 
  private:
@@ -206,7 +198,7 @@
   // If using the network service, crash the service, and make sure QUIC is
   // still disabled.
   if (content::IsOutOfProcessNetworkService()) {
-    CrashNetworkServiceAndRestartQuicServer();
+    CrashNetworkService();
     // Make sure the NetworkContext has noticed the pipe was closed.
     g_browser_process->system_network_context_manager()
         ->FlushNetworkInterfaceForTesting();
@@ -221,7 +213,7 @@
   // If using the network service, crash the service, and make sure QUIC is
   // still disabled.
   if (content::IsOutOfProcessNetworkService()) {
-    CrashNetworkServiceAndRestartQuicServer();
+    CrashNetworkService();
     // Make sure the NetworkContext has noticed the pipe was closed.
     g_browser_process->safe_browsing_service()
         ->FlushNetworkInterfaceForTesting();
@@ -235,7 +227,7 @@
   // If using the network service, crash the service, and make sure QUIC is
   // still disabled.
   if (content::IsOutOfProcessNetworkService()) {
-    CrashNetworkServiceAndRestartQuicServer();
+    CrashNetworkService();
     // Make sure the NetworkContext has noticed the pipe was closed.
     browser()
         ->profile()
@@ -277,7 +269,7 @@
   // If using the network service, crash the service, and make sure QUIC is
   // still enabled.
   if (content::IsOutOfProcessNetworkService()) {
-    CrashNetworkServiceAndRestartQuicServer();
+    CrashNetworkService();
     // Make sure the NetworkContext has noticed the pipe was closed.
     g_browser_process->system_network_context_manager()
         ->FlushNetworkInterfaceForTesting();
@@ -291,7 +283,7 @@
   // If using the network service, crash the service, and make sure QUIC is
   // still enabled.
   if (content::IsOutOfProcessNetworkService()) {
-    CrashNetworkServiceAndRestartQuicServer();
+    CrashNetworkService();
     // Make sure the NetworkContext has noticed the pipe was closed.
     g_browser_process->safe_browsing_service()
         ->FlushNetworkInterfaceForTesting();
@@ -305,7 +297,7 @@
   // If using the network service, crash the service, and make sure QUIC is
   // still enabled.
   if (content::IsOutOfProcessNetworkService()) {
-    CrashNetworkServiceAndRestartQuicServer();
+    CrashNetworkService();
     // Make sure the NetworkContext has noticed the pipe was closed.
     browser()
         ->profile()
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 084253e..0266019 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -123,7 +123,6 @@
 #include "components/omnibox/browser/omnibox_prefs.h"
 #include "components/omnibox/browser/zero_suggest_provider.h"
 #include "components/optimization_guide/core/optimization_guide_prefs.h"
-#include "components/password_manager/core/browser/password_bubble_experiment.h"
 #include "components/password_manager/core/browser/password_manager.h"
 #include "components/payments/core/payment_prefs.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
@@ -621,6 +620,14 @@
 const char kPasswordRecovery[] = "password_manager.password_recovery";
 #endif
 
+// Deprecated 07/2021.
+const char kWasSignInPasswordPromoClicked[] =
+    "profile.was_sign_in_password_promo_clicked";
+const char kNumberSignInPasswordPromoShown[] =
+    "profile.number_sign_in_password_promo_shown";
+const char kSignInPasswordPromoRevive[] =
+    "profile.sign_in_password_promo_revive";
+
 // Register local state used only for migration (clearing or moving to a new
 // key).
 void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
@@ -789,6 +796,10 @@
 #if defined(OS_MAC)
   registry->RegisterTimePref(kPasswordRecovery, base::Time());
 #endif
+
+  registry->RegisterBooleanPref(kWasSignInPasswordPromoClicked, false);
+  registry->RegisterIntegerPref(kNumberSignInPasswordPromoShown, 0);
+  registry->RegisterBooleanPref(kSignInPasswordPromoRevive, false);
 }
 
 }  // namespace
@@ -1056,7 +1067,6 @@
   NotifierStateTracker::RegisterProfilePrefs(registry);
   ntp_tiles::MostVisitedSites::RegisterProfilePrefs(registry);
   optimization_guide::prefs::RegisterProfilePrefs(registry);
-  password_bubble_experiment::RegisterPrefs(registry);
   password_manager::PasswordManager::RegisterProfilePrefs(registry);
   payments::RegisterProfilePrefs(registry);
   PermissionBubbleMediaAccessHandler::RegisterProfilePrefs(registry);
@@ -1563,6 +1573,11 @@
   profile_prefs->ClearPref(kPasswordRecovery);
 #endif
 
+  // Added 07/2021
+  profile_prefs->ClearPref(kWasSignInPasswordPromoClicked);
+  profile_prefs->ClearPref(kNumberSignInPasswordPromoShown);
+  profile_prefs->ClearPref(kSignInPasswordPromoRevive);
+
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_PROFILE_PREFS
 }
diff --git a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java
index e2bc076..88619bd 100644
--- a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java
+++ b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/profiles/Profile.java
@@ -77,7 +77,7 @@
      * Returns the {@link BrowserProfileType} for the corresponding profile.
      *
      * Please note {@link BrowserProfileType} is generated from native so, it also contains other
-     * types of Profile like Guest, System, EphemeralGuest that we don't support in Android.
+     * types of Profile like Guest and System that we don't support in Android.
      */
     public static @BrowserProfileType int getBrowserProfileTypeFromProfile(Profile profile) {
         assert profile != null;
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 24cba6c4..88309c7 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -381,11 +381,6 @@
          profile_metrics::BrowserProfileType::kIncognito;
 }
 
-// static
-bool Profile::IsEphemeralGuestProfileEnabled() {
-  return false;
-}
-
 bool Profile::IsGuestSession() const {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   static bool is_guest_session =
@@ -409,10 +404,6 @@
   return nullptr;
 }
 
-bool Profile::IsEphemeralGuestProfile() const {
-  return false;
-}
-
 bool Profile::IsSystemProfile() const {
   return profile_metrics::GetBrowserProfileType(this) ==
          profile_metrics::BrowserProfileType::kSystem;
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 9982f3e..b28d8706 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -437,24 +437,10 @@
   // OffTheRecord profile used for incognito mode and guest sessions.
   bool IsPrimaryOTRProfile() const;
 
-  // Returns whether ephemeral Guest profiles are enabled.
-  //
-  // NOTE: Ephemeral Guest profiles are deprecated and code support is under
-  // removal.
-  // TODO(https://crbug.com/1225156): Delete this function.
-  static bool IsEphemeralGuestProfileEnabled();
-
   // Returns whether it is a Guest session. This covers both regular and
   // off-the-record profiles of a Guest session.
   virtual bool IsGuestSession() const;
 
-  // Returns whether it is an ephemeral Guest profile.
-  //
-  // NOTE: Ephemeral Guest profiles are deprecated and code support is under
-  // removal.
-  // TODO(https://crbug.com/1225156): Delete this function.
-  bool IsEphemeralGuestProfile() const;
-
   // Returns whether it is a system profile.
   bool IsSystemProfile() const;
 
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 0652a43..c6712d47 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -82,11 +82,15 @@
 #include "chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/web_applications/app_browser_controller.h"
+#include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/webui/history/foreign_session_handler.h"
 #include "chrome/browser/web_applications/components/app_icon_manager.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
+#include "chrome/browser/web_applications/system_web_apps/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_render_frame.mojom.h"
@@ -591,6 +595,19 @@
 }
 #endif
 
+// If the link points to a system web app (in |profile|), return its type.
+// Otherwise nullopt.
+absl::optional<web_app::SystemAppType> GetLinkSystemAppType(Profile* profile,
+                                                            const GURL& url) {
+  absl::optional<web_app::AppId> link_app_id =
+      web_app::FindInstalledAppWithUrlInScope(profile, url);
+
+  if (!link_app_id)
+    return absl::nullopt;
+
+  return web_app::GetSystemWebAppTypeForAppId(profile, *link_app_id);
+}
+
 }  // namespace
 
 // static
@@ -632,6 +649,10 @@
   }
   set_content_type(
       ContextMenuContentTypeFactory::Create(source_web_contents_, params));
+
+  system_app_type_ = GetBrowser() && GetBrowser()->app_controller()
+                         ? GetBrowser()->app_controller()->system_app_type()
+                         : absl::nullopt;
 }
 
 RenderViewContextMenu::~RenderViewContextMenu() = default;
@@ -1208,23 +1229,48 @@
     WebContents* active_web_contents =
         browser ? browser->tab_strip_model()->GetActiveWebContents() : nullptr;
 
-    menu_model_.AddItemWithStringId(
-        IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
-        in_app ? IDS_CONTENT_CONTEXT_OPENLINKNEWTAB_INAPP
-               : IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
-    if (!in_app) {
-      menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
-                                      IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
+    Profile* profile = GetProfile();
+    absl::optional<web_app::SystemAppType> link_system_app_type =
+        GetLinkSystemAppType(profile, params_.link_url);
+    if (system_app_type_ && link_system_app_type) {
+      // Show "Open in new tab" if this link points to the current app, and the
+      // app has a tab strip.
+      //
+      // We don't show "open in tab" for links to a different SWA, because two
+      // SWAs can't share the same browser window.
+      if (system_app_type_ == link_system_app_type &&
+          web_app::WebAppProvider::GetForSystemWebApps(profile)
+              ->system_web_app_manager()
+              .ShouldHaveTabStrip(system_app_type_.value())) {
+        menu_model_.AddItemWithStringId(
+            IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
+            IDS_CONTENT_CONTEXT_OPENLINKNEWTAB_INAPP);
+      }
+
+      // Don't show "open in new window", this is instead handled below in
+      // |AppendOpenInWebAppLinkItems| (which includes app's name and icon).
+    } else {
+      menu_model_.AddItemWithStringId(
+          IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
+          in_app ? IDS_CONTENT_CONTEXT_OPENLINKNEWTAB_INAPP
+                 : IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
+      if (!in_app) {
+        menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
+                                        IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
+      }
     }
 
     if (params_.link_url.is_valid()) {
       AppendProtocolHandlerSubMenu();
     }
 
-    menu_model_.AddItemWithStringId(
-        IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
-        in_app ? IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD_INAPP
-               : IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
+    // Links to system web app can't be opened in incognito / off-the-record.
+    if (!link_system_app_type) {
+      menu_model_.AddItemWithStringId(
+          IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
+          in_app ? IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD_INAPP
+                 : IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
+    }
 
     AppendOpenInWebAppLinkItems();
     AppendOpenWithLinkItems();
@@ -1391,15 +1437,26 @@
   if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile))
     return;
 
-  absl::optional<web_app::AppId> app_id =
+  absl::optional<web_app::AppId> link_app_id =
       web_app::FindInstalledAppWithUrlInScope(profile, params_.link_url);
-  if (!app_id)
+  if (!link_app_id)
     return;
 
+  // Don't show "Open link in new app window", if the link points to the
+  // current app, and the app is single windowed.
+  if (system_app_type_ &&
+      system_app_type_ ==
+          web_app::GetSystemWebAppTypeForAppId(profile, *link_app_id) &&
+      web_app::WebAppProvider::GetForSystemWebApps(GetProfile())
+          ->system_web_app_manager()
+          .IsSingleWindow(*system_app_type_)) {
+    return;
+  }
+
   int open_in_app_string_id;
   const Browser* browser = GetBrowser();
   if (browser && browser->app_name() ==
-                     web_app::GenerateApplicationNameFromAppId(*app_id)) {
+                     web_app::GenerateApplicationNameFromAppId(*link_app_id)) {
     open_in_app_string_id = IDS_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP_SAMEAPP;
   } else {
     open_in_app_string_id = IDS_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP;
@@ -1410,10 +1467,11 @@
       IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP,
       l10n_util::GetStringFUTF16(
           open_in_app_string_id,
-          base::UTF8ToUTF16(provider->registrar().GetAppShortName(*app_id))));
+          base::UTF8ToUTF16(
+              provider->registrar().GetAppShortName(*link_app_id))));
 
   gfx::Image icon = gfx::Image::CreateFrom1xBitmap(
-      provider->icon_manager().GetFavicon(*app_id));
+      provider->icon_manager().GetFavicon(*link_app_id));
   menu_model_.SetIcon(menu_model_.GetItemCount() - 1,
                       ui::ImageModel::FromImage(icon));
 }
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h
index 9f23d7f..34b6152 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -17,6 +17,7 @@
 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_sub_menu_model.h"
+#include "chrome/browser/web_applications/system_web_apps/system_web_app_types.h"
 #include "components/renderer_context_menu/context_menu_content_type.h"
 #include "components/renderer_context_menu/render_view_context_menu_base.h"
 #include "components/renderer_context_menu/render_view_context_menu_observer.h"
@@ -344,6 +345,9 @@
   std::unique_ptr<SharedClipboardContextMenuObserver>
       shared_clipboard_context_menu_observer_;
 
+  // The type of system app (if any) associated with the WebContents we're in.
+  absl::optional<web_app::SystemAppType> system_app_type_;
+
   DISALLOW_COPY_AND_ASSIGN(RenderViewContextMenu);
 };
 
diff --git a/chrome/browser/resources/accessibility/accessibility.js b/chrome/browser/resources/accessibility/accessibility.js
index 8bc655d..f60c8d5 100644
--- a/chrome/browser/resources/accessibility/accessibility.js
+++ b/chrome/browser/resources/accessibility/accessibility.js
@@ -73,11 +73,6 @@
   get kAXModeComplete() {
     return AXMode.kNativeAPIs | AXMode.kWebContents | AXMode.kInlineTextBoxes |
         AXMode.kScreenReader | AXMode.kHTML;
-  },
-
-  get kAXModeCompleteNoHTML() {
-    return AXMode.kNativeAPIs | AXMode.kWebContents | AXMode.kInlineTextBoxes |
-        AXMode.kScreenReader;
   }
 };
 
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 22aaded..42b75b92 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/tutorial_test.js
@@ -142,7 +142,9 @@
 });
 
 // Tests that a static lesson does not show the 'Practice area' button.
-TEST_F('ChromeVoxTutorialTest', 'NoPracticeAreaTest', function() {
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
+TEST_F('ChromeVoxTutorialTest', 'DISABLED_NoPracticeAreaTest', function() {
   const mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(this.simpleDoc, async function(root) {
     await this.launchAndWaitForTutorial();
@@ -168,7 +170,9 @@
 });
 
 // Tests that an interactive lesson shows the 'Practice area' button.
-TEST_F('ChromeVoxTutorialTest', 'HasPracticeAreaTest', function() {
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
+TEST_F('ChromeVoxTutorialTest', 'DISABLED_HasPracticeAreaTest', function() {
   const mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(this.simpleDoc, async function(root) {
     await this.launchAndWaitForTutorial();
@@ -295,7 +299,9 @@
 });
 
 // Tests that the main menu button navigates the user to the main menu screen.
-TEST_F('ChromeVoxTutorialTest', 'MainMenuButton', function() {
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
+TEST_F('ChromeVoxTutorialTest', 'DISABLED_MainMenuButton', function() {
   const mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(this.simpleDoc, async function(root) {
     await this.launchAndWaitForTutorial();
@@ -410,7 +416,9 @@
 });
 
 // Tests that we read a hint for navigating a lesson when it is shown.
-TEST_F('ChromeVoxTutorialTest', 'LessonHint', function() {
+// TODO(crbug.com/1193799): fix ax node errors causing console spew and
+// breaking tests
+TEST_F('ChromeVoxTutorialTest', 'DISABLED_LessonHint', function() {
   const mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(this.simpleDoc, async function(root) {
     await this.launchAndWaitForTutorial();
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js
index 568c6e6f..38fcdf7 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js
@@ -136,6 +136,7 @@
     data['flowType'] = this.flowType;
     this.$.valueProp.reloadContent(data);
     this.$.relatedInfo.reloadContent(data);
+    this.$.voiceMatch.reloadContent(data);
     this.$.thirdParty.reloadContent(data);
     this.$.getMore.reloadContent(data);
   },
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.html
index 468b0f9..0b34f7d 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.html
@@ -83,7 +83,7 @@
       <oobe-text-button id="skip-button" disabled="[[loading]]"
           text-key="assistantOptinNoThanksButton" on-click="onSkipTap_">
       </oobe-text-button>
-      <oobe-text-button id="next-button" inverse="[[!isMinorMode_]]"
+      <oobe-text-button id="next-button" inverse="[[!equalWeightButtons_]]"
           disabled="[[loading]]" text-key="assistantOptinAgreeButton"
           on-click="onNextTap_">
       </oobe-text-button>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js
index 528ef1ec..9f24cea 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_related_info.js
@@ -47,14 +47,11 @@
     },
 
     /**
-     * Indicates whether user is minor mode user (e.g. under age of 18).
+     * Indicates whether to use same design for accept/decline buttons.
      */
-    isMinorMode_: {
+    equalWeightButtons_: {
       type: Boolean,
-      value() {
-        return loadTimeData.valueExists('isMinorMode') &&
-            loadTimeData.getBoolean('isMinorMode');
-      }
+      value: false,
     },
   },
 
@@ -240,6 +237,8 @@
                 'https://www.gstatic.com/images/icons/material/system/2x/' +
                     'info_outline_grey600_24dp.png',
                 this.i18n('assistantScreenContextTitle'))));
+    this.equalWeightButtons_ = data['equalWeightButtons'];
+
     this.consentStringLoaded_ = true;
     if (this.webViewLoaded_) {
       this.onPageLoaded();
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.html
index da18cf2..f739276 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.html
@@ -51,7 +51,7 @@
             disabled="[[buttonsDisabled]]">
           <div id="skip-button-text" slot="text"></div>
         </oobe-text-button>
-        <oobe-text-button id="next-button" inverse="[[!isMinorMode_]]"
+        <oobe-text-button id="next-button" inverse="[[!equalWeightButtons_]]"
             on-click="onNextTap_" disabled="[[buttonsDisabled]]">
           <div id="next-button-text" slot="text"></div>
         </oobe-text-button>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
index 8fe87158..40f94332 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
@@ -58,10 +58,15 @@
      */
     isMinorMode_: {
       type: Boolean,
-      value() {
-        return loadTimeData.valueExists('isMinorMode') &&
-            loadTimeData.getBoolean('isMinorMode');
-      }
+      value: false,
+    },
+
+    /**
+     * Indicates whether to use same design for accept/decline buttons.
+     */
+    equalWeightButtons_: {
+      type: Boolean,
+      value: false,
     },
 
     /**
@@ -300,6 +305,7 @@
     this.$['skip-button-text'].textContent = data['valuePropSkipButton'];
     this.$['footer-text'].innerHTML =
         this.sanitizer_.sanitizeHtml(data['valuePropFooter']);
+    this.equalWeightButtons_ = data['equalWeightButtons'];
 
     this.consentStringLoaded_ = true;
     if (this.settingZippyLoaded_) {
@@ -318,8 +324,17 @@
       return;
     }
 
+    // Clear `consents-container` to prevent setting zippys being added
+    // multiple times.
+    while (this.$['consents-container'].firstElementChild) {
+      this.$['consents-container'].firstElementChild.remove();
+    }
+
     // `zippy_data` contains a list of lists, where each list contains the
     // setting zippys that should be shown on the same screen.
+    // `isMinorMode` is the same for all data in `zippy_data`. We could use the
+    // first one and set `isMinorMode_` flag.
+    this.isMinorMode_ = zippy_data[0][0]['isMinorMode'];
     for (var i in zippy_data) {
       for (var j in zippy_data[i]) {
         var data = zippy_data[i][j];
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
index a2a97fa..0d5699c 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.html
@@ -48,7 +48,7 @@
             disabled="[[buttonsDisabled]]"
             text-key="assistantOptinNoThanksButton">
         </oobe-text-button>
-        <oobe-text-button id="agree-button" inverse="[[!isMinorMode_]]"
+        <oobe-text-button id="agree-button" inverse="[[!equalWeightButtons_]]"
             on-click="onAgreeTap_" disabled="[[buttonsDisabled]]"
             text-key="assistantOptinAgreeButton">
         </oobe-text-button>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js
index 45a1035..02234b9 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_voice_match.js
@@ -30,14 +30,11 @@
 
   properties: {
     /**
-     * Indicates whether user is minor mode user (e.g. under age of 18).
+     * Indicates whether to use same design for accept/decline buttons.
      */
-    isMinorMode_: {
+    equalWeightButtons_: {
       type: Boolean,
-      value() {
-        return loadTimeData.valueExists('isMinorMode') &&
-            loadTimeData.getBoolean('isMinorMode');
-      }
+      value: false,
     },
   },
 
@@ -124,6 +121,13 @@
   },
 
   /**
+   * Reload the page with the given settings data.
+   */
+  reloadContent(data) {
+    this.equalWeightButtons_ = data['equalWeightButtons'];
+  },
+
+  /**
    * Reloads voice match flow.
    */
   reloadPage() {
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html
index c4fa668..7c959c74 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html
@@ -215,14 +215,30 @@
           </div>
         </div>
       </div>
-      <settings-toggle-button id="enableSpellcheckingToggle" class="hr"
-          label="$i18n{spellCheckTitle}"
-          pref="{{prefs.browser.enable_spellchecking}}" no-set-pref
-          disabled="[[isEnableSpellcheckingDisabled_(
-              languageSettingsV2Update2Enabled_, spellCheckLanguages_.length)]]"
-          on-settings-boolean-control-change="onSpellcheckToggleChange_"
-          deep-link-focus-id$="[[Setting.kSpellCheck]]">
-      </settings-toggle-button>
+      <template is="dom-if" if="[[onDeviceGrammarCheckEnabled_]]">
+        <settings-toggle-button id="enableSpellcheckingToggle" class="hr"
+            label="$i18n{spellAndGrammarCheckTitle}"
+            sub-label="$i18n{spellAndGrammarCheckDescription}"
+            pref="{{prefs.browser.enable_spellchecking}}" no-set-pref
+            disabled="[[isEnableSpellcheckingDisabled_(
+                languageSettingsV2Update2Enabled_,
+                spellCheckLanguages_.length)]]"
+            on-settings-boolean-control-change="onSpellcheckToggleChange_"
+            deep-link-focus-id$="[[Setting.kSpellCheck]]"
+            aria-describedby="spellAndGrammarCheckDescription">
+        </settings-toggle-button>
+      </template>
+      <template is="dom-if" if="[[!onDeviceGrammarCheckEnabled_]]">
+        <settings-toggle-button id="enableSpellcheckingToggle" class="hr"
+            label="$i18n{spellCheckTitle}"
+            pref="{{prefs.browser.enable_spellchecking}}" no-set-pref
+            disabled="[[isEnableSpellcheckingDisabled_(
+                languageSettingsV2Update2Enabled_,
+                spellCheckLanguages_.length)]]"
+            on-settings-boolean-control-change="onSpellcheckToggleChange_"
+            deep-link-focus-id$="[[Setting.kSpellCheck]]">
+        </settings-toggle-button>
+      </template>
       <iron-collapse class="subsection" opened="[[isCollapseOpened_(
           languageSettingsV2Update2Enabled_,
           prefs.browser.enable_spellchecking.value)]]">
@@ -285,13 +301,15 @@
             </div>
           </div>
         </template>
-        <settings-toggle-button id="enhancedSpellCheckToggle"
-            class="[[getEnhancedSpellCheckClass_(
-                languageSettingsV2Update2Enabled_)]]"
-            label="$i18n{spellCheckEnhancedLabel}"
-            pref="{{prefs.spellcheck.use_spelling_service}}"
-            disabled="[[!prefs.browser.enable_spellchecking.value]]">
-        </settings-toggle-button>
+        <template is="dom-if" if="[[!onDeviceGrammarCheckEnabled_]]">
+          <settings-toggle-button id="enhancedSpellCheckToggle"
+              class="[[getEnhancedSpellCheckClass_(
+                  languageSettingsV2Update2Enabled_)]]"
+              label="$i18n{spellCheckEnhancedLabel}"
+              pref="{{prefs.spellcheck.use_spelling_service}}"
+              disabled="[[!prefs.browser.enable_spellchecking.value]]">
+          </settings-toggle-button>
+        </template>
         <cr-link-row class="hr" label="$i18n{editDictionaryLabel}"
             on-click="onEditDictionaryClick_"
             id="editDictionarySubpageTrigger"
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js
index fbfce78..9219710 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js
@@ -112,6 +112,14 @@
       computed: `getShortcutReminderBody_(showLastUsedIMEShortcutReminder_,
           showNextIMEShortcutReminder_)`,
     },
+
+    /** @private */
+    onDeviceGrammarCheckEnabled_: {
+      type: Boolean,
+      value() {
+        return loadTimeData.getBoolean('onDeviceGrammarCheckEnabled');
+      },
+    },
   },
 
   /** @private {?settings.LanguagesMetricsProxy} */
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/user_list.js b/chrome/browser/resources/settings/chromeos/os_people_page/user_list.js
index b57687f..8f9adbe 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/user_list.js
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/user_list.js
@@ -133,7 +133,7 @@
    * @private
    */
   shouldShowEmail_(user) {
-    return !user.isSupervised && user.name !== user.displayEmail;
+    return !user.isChild && user.name !== user.displayEmail;
   },
 
   /**
diff --git a/chrome/browser/resources/settings/settings_page/settings_section.html b/chrome/browser/resources/settings/settings_page/settings_section.html
index 0e8a08c..60dde27 100644
--- a/chrome/browser/resources/settings/settings_page/settings_section.html
+++ b/chrome/browser/resources/settings/settings_page/settings_section.html
@@ -25,6 +25,7 @@
         flex: 1;
       }
 
+      :host(.expanded) #header,
       :host([hidden-by-search]) {
         display: none;
       }
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.html b/chrome/browser/resources/settings/settings_page/settings_subpage.html
index 187efdb..a2b1e38 100644
--- a/chrome/browser/resources/settings/settings_page/settings_subpage.html
+++ b/chrome/browser/resources/settings/settings_page/settings_subpage.html
@@ -1,7 +1,5 @@
     <style include="cr-shared-style settings-shared">
       :host {
-        background-color: var(--cr-card-background-color);
-        box-shadow: var(--cr-card-shadow);
         box-sizing: border-box;
         display: block;
         left: 0;
@@ -13,6 +11,11 @@
         top: 0;
       }
 
+      :host(:not(.multi-card)) {
+        background-color: var(--cr-card-background-color);
+        box-shadow: var(--cr-card-shadow);
+      }
+
       #headerLine {
         min-height: 40px;
         padding-bottom: 24px;
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
index 575d49f5f..c1011b3c 100644
--- a/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
+++ b/chrome/browser/signin/dice_web_signin_interceptor_browsertest.cc
@@ -218,10 +218,6 @@
           ? DiceInterceptedSessionStartupHelper::Result::kReconcilorSuccess
           : DiceInterceptedSessionStartupHelper::Result::kMultiloginSuccess,
       1);
-  histogram_tester.ExpectTotalCount("Profile.Guest.SigninTransferred.Lifetime",
-                                    intercept_to_guest ? 1 : 0);
-  histogram_tester.ExpectBucketCount("Profile.EphemeralGuest.Signin", true,
-                                     intercept_to_guest ? 1 : 0);
 }
 
 }  // namespace
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service.cc b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
index ad99707..831801c8 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service.cc
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
@@ -353,16 +353,10 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
-  if (user) {
-    // Note that deprecated legacy supervised users are allowed to change type
-    // due to legacy initialization.
-    if (user->GetType() != user_manager::USER_TYPE_SUPERVISED_DEPRECATED) {
-      if (is_child != (user->GetType() == user_manager::USER_TYPE_CHILD))
-        LOG(FATAL) << "User child flag has changed: " << is_child;
-    }
-  } else if (chromeos::ProfileHelper::IsRegularProfile(profile_)) {
+  if (user && is_child != (user->GetType() == user_manager::USER_TYPE_CHILD))
+    LOG(FATAL) << "User child flag has changed: " << is_child;
+  if (!user && chromeos::ProfileHelper::IsRegularProfile(profile_))
     LOG(DFATAL) << "User instance not found while setting child account flag.";
-  }
 #endif
 }
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 4482e490..9232122 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1132,8 +1132,6 @@
       "passwords/bubble_controllers/save_unsynced_credentials_locally_bubble_controller.h",
       "passwords/bubble_controllers/save_update_with_account_store_bubble_controller.cc",
       "passwords/bubble_controllers/save_update_with_account_store_bubble_controller.h",
-      "passwords/bubble_controllers/sign_in_promo_bubble_controller.cc",
-      "passwords/bubble_controllers/sign_in_promo_bubble_controller.h",
       "passwords/credential_leak_dialog_controller.h",
       "passwords/credential_leak_dialog_controller_impl.cc",
       "passwords/credential_leak_dialog_controller_impl.h",
@@ -2200,6 +2198,8 @@
       "views/crostini/crostini_recovery_view.h",
       "views/crostini/crostini_uninstaller_view.cc",
       "views/crostini/crostini_uninstaller_view.h",
+      "views/crostini/crostini_update_component_view.cc",
+      "views/crostini/crostini_update_component_view.h",
       "views/crostini/crostini_update_filesystem_view.cc",
       "views/crostini/crostini_update_filesystem_view.h",
       "views/extensions/print_job_confirmation_dialog_view.cc",
@@ -3115,8 +3115,6 @@
         "signin/dice_web_signin_interceptor_delegate.cc",
         "signin/dice_web_signin_interceptor_delegate.h",
         "signin/profile_customization_bubble_sync_controller.h",
-        "views/passwords/password_sign_in_promo_view.cc",
-        "views/passwords/password_sign_in_promo_view.h",
         "views/profiles/dice_web_signin_interception_bubble_view.cc",
         "views/profiles/dice_web_signin_interception_bubble_view.h",
         "views/profiles/profile_customization_bubble_sync_controller.cc",
@@ -4456,8 +4454,6 @@
       "views/web_apps/web_app_confirmation_view.h",
       "views/web_apps/web_app_hover_button.cc",
       "views/web_apps/web_app_hover_button.h",
-      "views/web_apps/web_app_identity_update_confirmation_view.cc",
-      "views/web_apps/web_app_identity_update_confirmation_view.h",
       "views/web_apps/web_app_info_image_source.cc",
       "views/web_apps/web_app_info_image_source.h",
       "views/web_apps/web_app_protocol_handler_intent_picker_dialog_view.cc",
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_af.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_af.xtb
index d2a8c9b..7ffe1f2 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_af.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_af.xtb
@@ -1302,6 +1302,7 @@
 <translation id="948039501338975565">Lys boekmerkvouers</translation>
 <translation id="95817756606698420">Chrome kan <ph name="BEGIN_BOLD" />Sogou<ph name="END_BOLD" /> gebruik om soektogte in China uit te voer. Jy kan dit in <ph name="BEGIN_LINK" />Instellings<ph name="END_LINK" /> verander.</translation>
 <translation id="962979164594783469">Installeer hierdie program</translation>
+<translation id="96681097142096641">Bekyk vereenvoudigde bladsy?</translation>
 <translation id="968900484120156207">Bladsye wat jy besoek, verskyn hier</translation>
 <translation id="970715775301869095"><ph name="MINUTES" /> minute oor</translation>
 <translation id="981121421437150478">Vanlyn</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ja.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ja.xtb
index 2d7d92e..4545dec 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ja.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ja.xtb
@@ -1302,6 +1302,7 @@
 <translation id="948039501338975565">ブックマーク フォルダのリスト</translation>
 <translation id="95817756606698420">中国のユーザーは Chrome での検索に <ph name="BEGIN_BOLD" />Sogou<ph name="END_BOLD" /> を使用できます。この設定は [<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />] で変更可能です。</translation>
 <translation id="962979164594783469">このアプリをインストール</translation>
+<translation id="96681097142096641">簡易版ページを表示しますか?</translation>
 <translation id="968900484120156207">アクセスしたページがここに表示されます</translation>
 <translation id="970715775301869095">残り <ph name="MINUTES" /> 分</translation>
 <translation id="981121421437150478">オフライン</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_mr.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_mr.xtb
index 474611f7..fe26fee 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_mr.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_mr.xtb
@@ -488,6 +488,7 @@
 <translation id="4181841719683918333">भाषा</translation>
 <translation id="4183868528246477015"><ph name="BEGIN_NEW" />नवीन<ph name="END_NEW" /> Google लेन्स वापरून शोधा</translation>
 <translation id="4195643157523330669">नवीन टॅबमध्ये उघडा</translation>
+<translation id="4196597275619698563">कार्ड तयार करा</translation>
 <translation id="4198423547019359126">कोणतीही डाउनलोड स्थाने उपलब्ध नाहीत</translation>
 <translation id="4209895695669353772">Google ने सुचवलेला पर्सनलाइझ केलेला आशय मिळवण्यासाठी, सिंक सुरू करा</translation>
 <translation id="4225895483398857530">टूलबार शॉर्टकट</translation>
@@ -1047,6 +1048,7 @@
 <translation id="7704317875155739195">ऑटोकंप्लीट शोध आणि URL</translation>
 <translation id="7707922173985738739">मोबाइल डेटा वापरा</translation>
 <translation id="7725024127233776428">तुम्ही बुकमार्क केलेली पेज येथे दिसतील</translation>
+<translation id="7731260005404856143">तुम्ही साइन इन केलेले असते तेव्हा, तुमच्या Google खाते मध्ये <ph name="BEGIN_LINK1" />इतर प्रकारची ॲक्टिव्हिटी<ph name="END_LINK1" /> सेव्ह केली जाऊ शकते. तुम्ही ती कधीही हटवू शकता.</translation>
 <translation id="7757787379047923882"><ph name="DEVICE_NAME" /> वरून शेअर केलेला मजकूर</translation>
 <translation id="7761849928583394409">तारीख आणि वेळ निवडा</translation>
 <translation id="7762668264895820836">SD कार्ड <ph name="SD_CARD_NUMBER" /></translation>
@@ -1237,6 +1239,7 @@
 <translation id="8854223127042600341">तुमच्या ऑफलाइन फाइल पहा</translation>
 <translation id="8856607253650333758">वर्णने मिळवा</translation>
 <translation id="8873817150012960745">सुरू करण्यासाठी येथे टॅप करा</translation>
+<translation id="8881973373982641723">सर्च बॉक्समधील इतिहासाच्या समावेशासह, इतिहास साफ करते.</translation>
 <translation id="889338405075704026">Chrome सेटिंग्जवर जा</translation>
 <translation id="8898822736010347272">नवीन धोके शोधण्यात आणि वेबवरील प्रत्येकाचे संरक्षण करण्यात मदत करण्यासाठी, तुम्ही भेट देत असलेल्या काही पेजच्या URL, मर्यादित सिस्टम माहिती आणि काही पेज आशय Google ला पाठवते.</translation>
 <translation id="8909135823018751308">शेअर करा...</translation>
@@ -1290,6 +1293,7 @@
 <translation id="9209888181064652401">कॉल करू शकत नाही</translation>
 <translation id="9212845824145208577">तळाशी जाऊ शकत नाही. पेजच्या आणखी तळाशी जाऊन सुरुवात करून पहा.</translation>
 <translation id="9219103736887031265">Images</translation>
+<translation id="923957533152125119">तुम्ही साइन इन केलेले असते तेव्हा, तुमच्या Google खाते मध्ये <ph name="BEGIN_LINK1" />शोध इतिहास<ph name="END_LINK1" /> आणि <ph name="BEGIN_LINK2" />इतर प्रकारची ॲक्टिव्हिटी<ph name="END_LINK2" /> सेव्ह केली जाऊ शकते. तुम्ही ते कधीही हटवू शकता.</translation>
 <translation id="926205370408745186">Digital wellbeing वरून तुमची Chrome ॲक्टिव्हिटी काढून टाका</translation>
 <translation id="927968626442779827">Google Chrome वर लाइट मोड वापरा</translation>
 <translation id="932327136139879170">होम</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_si.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_si.xtb
index 963e4225..d9f4065 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_si.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_si.xtb
@@ -1302,6 +1302,7 @@
 <translation id="948039501338975565">පිටුසන් ෆෝල්ඩර ලැයිස්තුව</translation>
 <translation id="95817756606698420">Chrome හට චීනයෙහි සෙවීම සඳහා <ph name="BEGIN_BOLD" />Sogou<ph name="END_BOLD" /> භාවිතා කළ හැකිය. ඔබට <ph name="BEGIN_LINK" />සැකසීම්<ph name="END_LINK" /> තුළ මෙය වෙනස් කළ හැකිය.</translation>
 <translation id="962979164594783469">මෙම යෙදුම ස්ථාපනය කරන්න</translation>
+<translation id="96681097142096641">සරල කළ පිටුව බලන්නද?</translation>
 <translation id="968900484120156207">ඔබ පැමිණෙන පිටු මෙහි දිස් වෙති</translation>
 <translation id="970715775301869095">මිනිත්තු <ph name="MINUTES" />ක් ඉතිරියි</translation>
 <translation id="981121421437150478">ඕෆ්ලයින්</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_sw.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_sw.xtb
index b2c32c4..df107036 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_sw.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_sw.xtb
@@ -1302,6 +1302,7 @@
 <translation id="948039501338975565">Orodha ya folda za alamisho</translation>
 <translation id="95817756606698420">Chrome inaweza kutumia <ph name="BEGIN_BOLD" />Sogou<ph name="END_BOLD" /> kutafuta nchini Uchina. Unaweza kuibadilisha katika <ph name="BEGIN_LINK" />MipangilioE<ph name="END_LINK" />.</translation>
 <translation id="962979164594783469">Sakinisha programu hii</translation>
+<translation id="96681097142096641">Ungependa kuangalia ukurasa uliorahisishwa?</translation>
 <translation id="968900484120156207">Kurasa unazotembelea zitaonekana hapa</translation>
 <translation id="970715775301869095">Zimesalia dakika <ph name="MINUTES" /></translation>
 <translation id="981121421437150478">Nje ya mtandao</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb
index 08b37c5..c6fcf149 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_uz.xtb
@@ -1302,6 +1302,7 @@
 <translation id="948039501338975565">Bukmark jildlari roʻyxati</translation>
 <translation id="95817756606698420">Chrome Xitoyda <ph name="BEGIN_BOLD" />Sogou<ph name="END_BOLD" /> qidiruv tizimidan foydalanishi mumkin. Asosiy qidiruv tizimini <ph name="BEGIN_LINK" />Sozlamalar<ph name="END_LINK" /> orqali tayinlash mumkin.</translation>
 <translation id="962979164594783469">Bu ilovani oʻrnatish</translation>
+<translation id="96681097142096641">Soddalashgan shaklda koʻrasizmi?</translation>
 <translation id="968900484120156207">Siz kirgan sahifalar shu yerda chiqadi</translation>
 <translation id="970715775301869095"><ph name="MINUTES" /> daqiqa qoldi</translation>
 <translation id="981121421437150478">Oflayn</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-HK.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-HK.xtb
index c005186..f2a0465 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-HK.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-HK.xtb
@@ -1302,6 +1302,7 @@
 <translation id="948039501338975565">書籤資料夾清單</translation>
 <translation id="95817756606698420">Chrome 可在中國使用「搜狗」<ph name="BEGIN_BOLD" /><ph name="END_BOLD" />搜尋內容。您可以在「<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />」中變更此設定。</translation>
 <translation id="962979164594783469">安裝此應用程式</translation>
+<translation id="96681097142096641">要查看簡化頁面嗎?</translation>
 <translation id="968900484120156207">您瀏覽的網頁會在這裡顯示</translation>
 <translation id="970715775301869095">尚餘 <ph name="MINUTES" /> 分鐘</translation>
 <translation id="981121421437150478">離線</translation>
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h
index 940fe19e..d5f1a9a 100644
--- a/chrome/browser/ui/browser_dialogs.h
+++ b/chrome/browser/ui/browser_dialogs.h
@@ -14,7 +14,6 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/bookmarks/bookmark_editor.h"
-#include "chrome/browser/web_applications/components/web_app_callback_app_identity.h"
 #include "chrome/browser/web_applications/components/web_app_id.h"
 #include "chrome/common/buildflags.h"
 #include "content/public/browser/content_browser_client.h"
@@ -134,29 +133,6 @@
                              std::unique_ptr<WebApplicationInfo> web_app_info,
                              AppInstallationAcceptanceCallback callback);
 
-// When an app changes its icon or name, that is considered an app identity
-// change which (for some types of apps) needs confirmation from the user.
-// This function shows that confirmation dialog. |app_id| is the unique id of
-// the app that is updating and |title_change| and |icon_change| specify which
-// piece of information is changing. Can be one or the other, or both (but
-// both cannot be |false|). |old_title| and |new_title|, as well as |old_icon|
-// and |new_icon| show the 'before' and 'after' values. A response is sent
-// back via the |callback|.
-void ShowWebAppIdentityUpdateDialog(
-    const std::string& app_id,
-    bool title_change,
-    bool icon_change,
-    const std::u16string& old_title,
-    const std::u16string& new_title,
-    const SkBitmap& old_icon,
-    const SkBitmap& new_icon,
-    content::WebContents* web_contents,
-    web_app::AppIdentityDialogCallback callback);
-
-// Sets whether |ShowWebAppIdentityUpdateDialog| should accept immediately
-// without any user interaction.
-void SetAutoAcceptAppIdentityUpdateForTesting(bool auto_accept);
-
 #if !defined(OS_ANDROID)
 // Callback used to indicate whether a user has accepted the launch of a
 // web app. The boolean parameter is true when the user accepts the dialog.
@@ -376,7 +352,6 @@
   EXTENSION_INSTALL_FRICTION = 108,
   FILE_HANDLING_PERMISSION_REQUEST = 109,
   SIGNIN_ENTERPRISE_INTERCEPTION = 110,
-  APP_IDENTITY_UPDATE_CONFIRMATION = 111,
   // Add values above this line with a corresponding label in
   // tools/metrics/histograms/enums.xml
   MAX_VALUE
diff --git a/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller.cc
deleted file mode 100644
index 84df2a6..0000000
--- a/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/passwords/passwords_model_delegate.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "content/public/browser/web_contents.h"
-
-SignInPromoBubbleController::SignInPromoBubbleController(
-    base::WeakPtr<PasswordsModelDelegate> delegate)
-    : delegate_(std::move(delegate)) {}
-
-SignInPromoBubbleController::~SignInPromoBubbleController() = default;
-
-Profile* SignInPromoBubbleController::GetProfile() const {
-  content::WebContents* web_contents =
-      delegate_ ? delegate_->GetWebContents() : nullptr;
-  if (!web_contents)
-    return nullptr;
-  return Profile::FromBrowserContext(web_contents->GetBrowserContext());
-}
-
-void SignInPromoBubbleController::OnSignInToChromeClicked(
-    const AccountInfo& account) {
-  // Enabling sync for an existing account and starting a new sign-in are
-  // triggered by the user interacting with the sign-in promo.
-  GetProfile()->GetPrefs()->SetBoolean(
-      password_manager::prefs::kWasSignInPasswordPromoClicked, true);
-  if (delegate_)
-    delegate_->EnableSync(account);
-}
diff --git a/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller.h b/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller.h
deleted file mode 100644
index 0fec814..0000000
--- a/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_PASSWORDS_BUBBLE_CONTROLLERS_SIGN_IN_PROMO_BUBBLE_CONTROLLER_H_
-#define CHROME_BROWSER_UI_PASSWORDS_BUBBLE_CONTROLLERS_SIGN_IN_PROMO_BUBBLE_CONTROLLER_H_
-
-#include "base/memory/weak_ptr.h"
-
-struct AccountInfo;
-class PasswordsModelDelegate;
-class Profile;
-
-// This controller provides data and actions for the PasswordSignInPromoView.
-class SignInPromoBubbleController {
- public:
-  explicit SignInPromoBubbleController(
-      base::WeakPtr<PasswordsModelDelegate> delegate);
-  ~SignInPromoBubbleController();
-
-  Profile* GetProfile() const;
-
-  // Called by the view when the "Sign in" button or the "Sync to" button in the
-  // promo bubble is clicked.
-  void OnSignInToChromeClicked(const AccountInfo& account);
-
- private:
-  // A bridge to ManagePasswordsUIController instance.
-  base::WeakPtr<PasswordsModelDelegate> delegate_;
-};
-
-#endif  // CHROME_BROWSER_UI_PASSWORDS_BUBBLE_CONTROLLERS_SIGN_IN_PROMO_BUBBLE_CONTROLLER_H_
diff --git a/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller_unittest.cc b/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller_unittest.cc
deleted file mode 100644
index d726255..0000000
--- a/chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller_unittest.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller.h"
-
-#include <memory>
-
-#include "base/strings/utf_string_conversions.h"
-#include "build/chromeos_buildflags.h"
-#include "chrome/browser/ui/passwords/passwords_model_delegate_mock.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/password_manager/core/browser/password_form.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/public/identity_manager/account_info.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/test/browser_task_environment.h"
-#include "content/public/test/test_renderer_host.h"
-#include "content/public/test/web_contents_tester.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::Return;
-
-namespace {
-
-MATCHER_P(AccountEq, expected, "") {
-  return expected.account_id == arg.account_id && expected.email == arg.email &&
-         expected.gaia == arg.gaia;
-}
-
-}  // namespace
-
-class SignInPromoBubbleControllerTest : public ::testing::Test {
- public:
-  SignInPromoBubbleControllerTest() {
-    test_web_contents_ =
-        content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
-    mock_delegate_ =
-        std::make_unique<testing::NiceMock<PasswordsModelDelegateMock>>();
-  }
-  ~SignInPromoBubbleControllerTest() override = default;
-
-  std::vector<std::unique_ptr<password_manager::PasswordForm>> GetCurrentForms()
-      const;
-
-  PasswordsModelDelegateMock* delegate() { return mock_delegate_.get(); }
-  SignInPromoBubbleController* controller() { return controller_.get(); }
-  TestingProfile* profile() { return &profile_; }
-
-  void Init();
-  void DestroyController();
-
- private:
-  content::BrowserTaskEnvironment task_environment_;
-  content::RenderViewHostTestEnabler rvh_enabler_;
-  TestingProfile profile_;
-  std::unique_ptr<content::WebContents> test_web_contents_;
-  std::unique_ptr<PasswordsModelDelegateMock> mock_delegate_;
-  std::unique_ptr<SignInPromoBubbleController> controller_;
-};
-
-void SignInPromoBubbleControllerTest::Init() {
-  EXPECT_CALL(*delegate(), GetWebContents())
-      .WillRepeatedly(Return(test_web_contents_.get()));
-
-  controller_ = std::make_unique<SignInPromoBubbleController>(
-      mock_delegate_->AsWeakPtr());
-}
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(SignInPromoBubbleControllerTest, SignInPromoOK) {
-  Init();
-  AccountInfo account;
-  account.account_id = CoreAccountId("foo_account_id");
-  account.gaia = "foo_gaia_id";
-  account.email = "foo@bar.com";
-  EXPECT_CALL(*delegate(), EnableSync(AccountEq(account)));
-
-  controller()->OnSignInToChromeClicked(account);
-  EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
-      password_manager::prefs::kWasSignInPasswordPromoClicked));
-}
-#endif
diff --git a/chrome/browser/ui/views/crostini/crostini_update_component_view.cc b/chrome/browser/ui/views/crostini/crostini_update_component_view.cc
new file mode 100644
index 0000000..79d922a
--- /dev/null
+++ b/chrome/browser/ui/views/crostini/crostini_update_component_view.cc
@@ -0,0 +1,87 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/crostini/crostini_update_component_view.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ash/crostini/crostini_features.h"
+#include "chrome/browser/ash/crostini/crostini_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/chromeos/devicetype_utils.h"
+#include "ui/strings/grit/ui_strings.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/layout_provider.h"
+
+namespace {
+
+CrostiniUpdateComponentView* g_crostini_upgrade_view = nullptr;
+
+constexpr char kCrostiniUpgradeSourceHistogram[] = "Crostini.UpgradeSource";
+
+}  // namespace
+
+void crostini::ShowCrostiniUpdateComponentView(
+    Profile* profile,
+    crostini::CrostiniUISurface ui_surface) {
+  base::UmaHistogramEnumeration(kCrostiniUpgradeSourceHistogram, ui_surface,
+                                crostini::CrostiniUISurface::kCount);
+  return CrostiniUpdateComponentView::Show(profile);
+}
+
+void CrostiniUpdateComponentView::Show(Profile* profile) {
+  if (!crostini::CrostiniFeatures::Get()->IsAllowedNow(profile)) {
+    return;
+  }
+
+  if (!g_crostini_upgrade_view) {
+    g_crostini_upgrade_view = new CrostiniUpdateComponentView;
+    CreateDialogWidget(g_crostini_upgrade_view, nullptr, nullptr);
+  }
+  g_crostini_upgrade_view->GetWidget()->Show();
+}
+
+// static
+CrostiniUpdateComponentView*
+CrostiniUpdateComponentView::GetActiveViewForTesting() {
+  return g_crostini_upgrade_view;
+}
+
+CrostiniUpdateComponentView::CrostiniUpdateComponentView() {
+  SetButtons(ui::DIALOG_BUTTON_OK);
+  SetShowCloseButton(false);
+  SetTitle(IDS_CROSTINI_TERMINA_UPDATE_REQUIRED);
+  set_fixed_width(ChromeLayoutProvider::Get()->GetDistanceMetric(
+      DISTANCE_STANDALONE_BUBBLE_PREFERRED_WIDTH));
+
+  views::LayoutProvider* provider = views::LayoutProvider::Get();
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical,
+      provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG),
+      provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL)));
+
+  const std::u16string message =
+      l10n_util::GetStringUTF16(IDS_CROSTINI_TERMINA_UPDATE_OFFLINE);
+  views::Label* message_label = new views::Label(message);
+  message_label->SetMultiLine(true);
+  message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  AddChildView(message_label);
+
+  chrome::RecordDialogCreation(chrome::DialogIdentifier::CROSTINI_UPGRADE);
+}
+
+CrostiniUpdateComponentView::~CrostiniUpdateComponentView() {
+  g_crostini_upgrade_view = nullptr;
+}
+
+BEGIN_METADATA(CrostiniUpdateComponentView, views::BubbleDialogDelegateView)
+END_METADATA
diff --git a/chrome/browser/ui/views/crostini/crostini_update_component_view.h b/chrome/browser/ui/views/crostini/crostini_update_component_view.h
new file mode 100644
index 0000000..18f2e0e
--- /dev/null
+++ b/chrome/browser/ui/views/crostini/crostini_update_component_view.h
@@ -0,0 +1,32 @@
+// 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 CHROME_BROWSER_UI_VIEWS_CROSTINI_CROSTINI_UPDATE_COMPONENT_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_CROSTINI_CROSTINI_UPDATE_COMPONENT_VIEW_H_
+
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+
+namespace crostini {
+enum class CrostiniResult;
+}  // namespace crostini
+
+class Profile;
+
+// Provides a warning to the user that an upgrade is required and and internet
+// connection is needed.
+class CrostiniUpdateComponentView : public views::BubbleDialogDelegateView {
+ public:
+  METADATA_HEADER(CrostiniUpdateComponentView);
+
+  static void Show(Profile* profile);
+
+  static CrostiniUpdateComponentView* GetActiveViewForTesting();
+
+ private:
+  CrostiniUpdateComponentView();
+  ~CrostiniUpdateComponentView() override;
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_CROSTINI_CROSTINI_UPDATE_COMPONENT_VIEW_H_
diff --git a/chrome/browser/ui/views/crostini/crostini_update_component_view_browsertest.cc b/chrome/browser/ui/views/crostini/crostini_update_component_view_browsertest.cc
new file mode 100644
index 0000000..147412e
--- /dev/null
+++ b/chrome/browser/ui/views/crostini/crostini_update_component_view_browsertest.cc
@@ -0,0 +1,154 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/crostini/crostini_update_component_view.h"
+
+#include "ash/constants/ash_features.h"
+#include "base/metrics/histogram_base.h"
+#include "base/run_loop.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ash/crostini/crostini_manager.h"
+#include "chrome/browser/ash/crostini/crostini_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/views/crostini/crostini_dialogue_browser_test_util.h"
+#include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
+#include "chrome/browser/web_applications/system_web_apps/system_web_app_manager.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chromeos/dbus/concierge/fake_concierge_client.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "components/crx_file/id_util.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class CrostiniUpdateComponentViewBrowserTest
+    : public CrostiniDialogBrowserTest {
+ public:
+  CrostiniUpdateComponentViewBrowserTest()
+      : CrostiniDialogBrowserTest(true /*register_termina*/) {
+    // TODO(crbug/953544) DLC makes this entire feature redundant, so once we're
+    // committed to it delete all of this.
+    scoped_feature_list_.InitAndDisableFeature(
+        chromeos::features::kCrostiniUseDlc);
+  }
+
+  // DialogBrowserTest:
+  void ShowUi(const std::string& name) override {
+    ShowCrostiniUpdateComponentView(browser()->profile(),
+                                    crostini::CrostiniUISurface::kAppList);
+  }
+
+  CrostiniUpdateComponentView* ActiveView() {
+    return CrostiniUpdateComponentView::GetActiveViewForTesting();
+  }
+
+  bool HasAcceptButton() { return ActiveView()->GetOkButton() != nullptr; }
+
+  bool HasCancelButton() { return ActiveView()->GetCancelButton() != nullptr; }
+
+  void WaitForViewDestroyed() {
+    base::RunLoop().RunUntilIdle();
+    ExpectNoView();
+  }
+
+  void ExpectView() {
+    // A new Widget was created in ShowUi() or since the last VerifyUi().
+    EXPECT_TRUE(VerifyUi());
+    // There is one view, and it's ours.
+    EXPECT_NE(nullptr, ActiveView());
+  }
+
+  void ExpectNoView() {
+    // No new Widget was created in ShowUi() or since the last VerifyUi().
+    EXPECT_FALSE(VerifyUi());
+    // Our view has really been deleted.
+    EXPECT_EQ(nullptr, ActiveView());
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Test the dialog is actually launched.
+IN_PROC_BROWSER_TEST_F(CrostiniUpdateComponentViewBrowserTest,
+                       InvokeUi_default) {
+  ShowAndVerifyUi();
+}
+
+IN_PROC_BROWSER_TEST_F(CrostiniUpdateComponentViewBrowserTest, HitOK) {
+  base::HistogramTester histogram_tester;
+
+  ShowUi("default");
+  ExpectView();
+  EXPECT_EQ(ui::DIALOG_BUTTON_OK, ActiveView()->GetDialogButtons());
+
+  EXPECT_TRUE(HasAcceptButton());
+  EXPECT_FALSE(HasCancelButton());
+
+  ActiveView()->AcceptDialog();
+  EXPECT_TRUE(ActiveView()->GetWidget()->IsClosed());
+
+  WaitForViewDestroyed();
+
+  histogram_tester.ExpectUniqueSample(
+      "Crostini.UpgradeSource",
+      static_cast<base::HistogramBase::Sample>(
+          crostini::CrostiniUISurface::kAppList),
+      1);
+}
+
+IN_PROC_BROWSER_TEST_F(CrostiniUpdateComponentViewBrowserTest,
+                       LaunchAppOnline_UpgradeNeeded) {
+  base::HistogramTester histogram_tester;
+  crostini::CrostiniManager::GetForProfile(browser()->profile())
+      ->MaybeUpdateCrostini();
+
+  ExpectNoView();
+
+  UnregisterTermina();
+  crostini::LaunchCrostiniApp(browser()->profile(),
+                              crostini::kCrostiniTerminalSystemAppId, 0);
+  ExpectNoView();
+}
+
+IN_PROC_BROWSER_TEST_F(CrostiniUpdateComponentViewBrowserTest,
+                       LaunchAppOffline_UpgradeNeeded) {
+  // Ensure Terminal System App is installed.
+  web_app::WebAppProvider::Get(browser()->profile())
+      ->system_web_app_manager()
+      .InstallSystemAppsForTesting();
+
+  base::HistogramTester histogram_tester;
+  SetConnectionType(network::mojom::ConnectionType::CONNECTION_NONE);
+  crostini::CrostiniManager::GetForProfile(browser()->profile())
+      ->MaybeUpdateCrostini();
+
+  ExpectNoView();
+
+  UnregisterTermina();
+  crostini::LaunchCrostiniApp(browser()->profile(),
+                              crostini::kCrostiniTerminalSystemAppId, 0);
+
+  // For Terminal System App, we must wait for browser to load.
+  Browser* terminal_browser = web_app::FindSystemWebAppBrowser(
+      browser()->profile(), web_app::SystemAppType::TERMINAL);
+  CHECK_NE(nullptr, terminal_browser);
+  WaitForLoadFinished(terminal_browser->tab_strip_model()->GetWebContentsAt(0));
+
+  ExpectView();
+
+  ActiveView()->AcceptDialog();
+  EXPECT_TRUE(ActiveView()->GetWidget()->IsClosed());
+
+  WaitForViewDestroyed();
+
+  histogram_tester.ExpectUniqueSample(
+      "Crostini.UpgradeSource",
+      static_cast<base::HistogramBase::Sample>(
+          crostini::CrostiniUISurface::kAppList),
+      1);
+}
diff --git a/chrome/browser/ui/views/passwords/password_sign_in_promo_view.cc b/chrome/browser/ui/views/passwords/password_sign_in_promo_view.cc
deleted file mode 100644
index 652c25631..0000000
--- a/chrome/browser/ui/views/passwords/password_sign_in_promo_view.cc
+++ /dev/null
@@ -1,58 +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 "chrome/browser/ui/views/passwords/password_sign_in_promo_view.h"
-
-#include <memory>
-
-#include "base/metrics/user_metrics.h"
-#include "build/buildflag.h"
-#include "chrome/browser/signin/account_consistency_mode_manager.h"
-#include "chrome/browser/ui/passwords/passwords_model_delegate.h"
-#include "chrome/browser/ui/views/chrome_layout_provider.h"
-#include "chrome/browser/ui/views/chrome_typography.h"
-#include "chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/signin/public/base/signin_buildflags.h"
-#include "components/signin/public/base/signin_metrics.h"
-#include "components/signin/public/identity_manager/account_info.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/metadata/metadata_impl_macros.h"
-#include "ui/views/controls/button/md_text_button.h"
-#include "ui/views/layout/fill_layout.h"
-
-PasswordSignInPromoView::DiceSyncPromoDelegate::DiceSyncPromoDelegate(
-    SignInPromoBubbleController* controller)
-    : controller_(controller) {
-  DCHECK(controller_);
-}
-
-PasswordSignInPromoView::DiceSyncPromoDelegate::~DiceSyncPromoDelegate() =
-    default;
-
-void PasswordSignInPromoView::DiceSyncPromoDelegate::OnEnableSync(
-    const AccountInfo& account) {
-  controller_->OnSignInToChromeClicked(account);
-}
-
-PasswordSignInPromoView::PasswordSignInPromoView(
-    content::WebContents* web_contents)
-    : controller_(PasswordsModelDelegateFromWebContents(web_contents)) {
-  SetLayoutManager(std::make_unique<views::FillLayout>());
-  Profile* profile = controller_.GetProfile();
-  DCHECK(AccountConsistencyModeManager::IsDiceEnabledForProfile(profile));
-  dice_sync_promo_delegate_ =
-      std::make_unique<PasswordSignInPromoView::DiceSyncPromoDelegate>(
-          &controller_);
-  AddChildView(new DiceBubbleSyncPromoView(
-      profile, dice_sync_promo_delegate_.get(),
-      signin_metrics::AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE,
-      IDS_PASSWORD_MANAGER_DICE_PROMO_SIGNIN_MESSAGE,
-      IDS_PASSWORD_MANAGER_DICE_PROMO_SYNC_MESSAGE));
-}
-
-PasswordSignInPromoView::~PasswordSignInPromoView() = default;
-
-BEGIN_METADATA(PasswordSignInPromoView, views::View)
-END_METADATA
diff --git a/chrome/browser/ui/views/passwords/password_sign_in_promo_view.h b/chrome/browser/ui/views/passwords/password_sign_in_promo_view.h
deleted file mode 100644
index 0f3a945..0000000
--- a/chrome/browser/ui/views/passwords/password_sign_in_promo_view.h
+++ /dev/null
@@ -1,51 +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 CHROME_BROWSER_UI_VIEWS_PASSWORDS_PASSWORD_SIGN_IN_PROMO_VIEW_H_
-#define CHROME_BROWSER_UI_VIEWS_PASSWORDS_PASSWORD_SIGN_IN_PROMO_VIEW_H_
-
-#include "chrome/browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller.h"
-#include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
-#include "ui/base/metadata/metadata_header_macros.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/view.h"
-
-namespace content {
-class WebContents;
-}
-class SignInPromoBubbleController;
-
-// A view that can show up after saving a password without being signed in to
-// offer signing users in so they can access their credentials across devices.
-// TODO(crbug.com/1108738): This class is unused; delete it.
-class PasswordSignInPromoView : public views::View {
- public:
-  METADATA_HEADER(PasswordSignInPromoView);
-  explicit PasswordSignInPromoView(content::WebContents* web_contents);
-  PasswordSignInPromoView(const PasswordSignInPromoView&) = delete;
-  PasswordSignInPromoView& operator=(const PasswordSignInPromoView&) = delete;
-  ~PasswordSignInPromoView() override;
-
- private:
-  // Delegate for the personalized sync promo view used when desktop identity
-  // consistency is enabled.
-  class DiceSyncPromoDelegate : public BubbleSyncPromoDelegate {
-   public:
-    explicit DiceSyncPromoDelegate(SignInPromoBubbleController* controller);
-    DiceSyncPromoDelegate(const DiceSyncPromoDelegate&) = delete;
-    DiceSyncPromoDelegate& operator=(const DiceSyncPromoDelegate&) = delete;
-    ~DiceSyncPromoDelegate() override;
-
-    // BubbleSyncPromoDelegate:
-    void OnEnableSync(const AccountInfo& account) override;
-
-   private:
-    SignInPromoBubbleController* controller_;
-  };
-
-  SignInPromoBubbleController controller_;
-  std::unique_ptr<DiceSyncPromoDelegate> dice_sync_promo_delegate_;
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_PASSWORDS_PASSWORD_SIGN_IN_PROMO_VIEW_H_
diff --git a/chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.cc b/chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.cc
deleted file mode 100644
index 028929a..0000000
--- a/chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.cc
+++ /dev/null
@@ -1,222 +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 "chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.h"
-
-#include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/views/chrome_layout_provider.h"
-#include "chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.h"
-#include "chrome/browser/web_applications/components/web_app_callback_app_identity.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/constrained_window/constrained_window_views.h"
-#include "components/webapps/browser/installable/installable_metrics.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/metadata/metadata_impl_macros.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/paint_vector_icon.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/layout/grid_layout.h"
-#include "ui/views/style/typography.h"
-
-namespace {
-const int kArrowIconSize = 32;
-
-bool g_auto_accept_app_identity_update_for_testing = false;
-
-}  // namespace
-
-WebAppIdentityUpdateConfirmationView::~WebAppIdentityUpdateConfirmationView() =
-    default;
-
-WebAppIdentityUpdateConfirmationView::WebAppIdentityUpdateConfirmationView(
-    const std::string& app_id,
-    bool title_change,
-    bool icon_change,
-    const std::u16string& old_title,
-    const std::u16string& new_title,
-    const SkBitmap& old_icon,
-    const SkBitmap& new_icon,
-    content::WebContents* web_contents,
-    web_app::AppIdentityDialogCallback callback) {
-  app_id_ = app_id;
-  web_contents_ = web_contents;
-  DCHECK(!callback.is_null());
-  callback_ = std::move(callback);
-  SetButtonLabel(ui::DIALOG_BUTTON_CANCEL,
-                 l10n_util::GetStringUTF16(IDS_WEBAPP_UPDATE_NEGATIVE_BUTTON));
-  SetModalType(ui::MODAL_TYPE_WINDOW);
-  DCHECK(title_change || icon_change);
-  SetTitle(title_change
-               ? (icon_change ? IDS_WEBAPP_UPDATE_DIALOG_TITLE_NAME_AND_ICON
-                              : IDS_WEBAPP_UPDATE_DIALOG_TITLE_NAME)
-               : IDS_WEBAPP_UPDATE_DIALOG_TITLE_ICON);
-
-  SetAcceptCallback(
-      base::BindOnce(&WebAppIdentityUpdateConfirmationView::OnDialogAccepted,
-                     base::Unretained(this)));
-
-  const ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
-  set_margins(layout_provider->GetDialogInsetsForContentType(
-      views::DialogContentType::kControl, views::DialogContentType::kText));
-  views::GridLayout* layout =
-      SetLayoutManager(std::make_unique<views::GridLayout>());
-
-  // The headline column set is simply a single column that fills up the row.
-  constexpr int kColumnSetIdHeadline = 0;
-  views::ColumnSet* column_set_headline =
-      layout->AddColumnSet(kColumnSetIdHeadline);
-  column_set_headline->AddColumn(
-      views::GridLayout::FILL, views::GridLayout::CENTER,
-      views::GridLayout::kFixedSize,
-      views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
-
-  // The main column set is |padding|col1|padding|arrow|padding|col2|padding|,
-  // where col1 and col2 contain the 'before' and 'after' values (either text or
-  // icon) and the first and last columns grow as needed to fill upp the rest.
-  constexpr int kColumnSetIdMain = 1;
-  views::ColumnSet* column_set_main = layout->AddColumnSet(kColumnSetIdMain);
-
-  // Padding column on the far left side of the dialog. Grows as needed to keep
-  // the views centered.
-  column_set_main->AddPaddingColumn(/*resize_percent= */ 100, /* width= */ 0);
-  // Column showing the 'before' icon/text.
-  column_set_main->AddColumn(views::GridLayout::CENTER,
-                             views::GridLayout::CENTER,
-                             views::GridLayout::kFixedSize,
-                             views::GridLayout::ColumnSize::kUsePreferred,
-                             /* fixed_width= */ 0, /* min_width= */ 0);
-  // Padding between the left side and the arrow.
-  column_set_main->AddPaddingColumn(
-      views::GridLayout::kFixedSize,
-      layout_provider->GetDistanceMetric(
-          views::DISTANCE_RELATED_CONTROL_HORIZONTAL));
-  // Column showing the arrow to indicate what is before and what is after.
-  column_set_main->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
-                             views::GridLayout::kFixedSize,
-                             views::GridLayout::ColumnSize::kUsePreferred,
-                             /* fixed_width= */ 0,
-                             /* min_width= */ 0);
-  // Padding between the arrow and the right side.
-  column_set_main->AddPaddingColumn(
-      views::GridLayout::FILL, layout_provider->GetDistanceMetric(
-                                   views::DISTANCE_RELATED_CONTROL_HORIZONTAL));
-  // Column showing the 'after' icon/text.
-  column_set_main->AddColumn(views::GridLayout::CENTER,
-                             views::GridLayout::CENTER,
-                             views::GridLayout::kFixedSize,
-                             views::GridLayout::ColumnSize::kUsePreferred,
-                             /* fixed_width= */ 0, /* min_width= */ 0);
-  // Padding column on the far right side of the dialog. Grows as needed to keep
-  // the views centered.
-  column_set_main->AddPaddingColumn(/*resize_percent= */ 100, /* width= */ 0);
-
-  layout->StartRow(views::GridLayout::kFixedSize, kColumnSetIdHeadline);
-
-  auto message_label = std::make_unique<views::Label>(
-      l10n_util::GetStringUTF16(IDS_WEBAPP_UPDATE_EXPLANATION),
-      views::style::CONTEXT_LABEL);
-  message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  message_label->SetMultiLine(true);
-  layout->AddView(std::move(message_label));
-
-  layout->AddPaddingRow(
-      views::GridLayout::kFixedSize,
-      2 * layout_provider->GetDistanceMetric(DISTANCE_CONTROL_LIST_VERTICAL));
-
-  layout->StartRow(views::GridLayout::kFixedSize, kColumnSetIdMain);
-
-  auto old_icon_image_view = std::make_unique<views::ImageView>();
-  gfx::Size image_size(web_app::kWebAppIconSmall, web_app::kWebAppIconSmall);
-  old_icon_image_view->SetImageSize(image_size);
-  old_icon_image_view->SetImage(gfx::ImageSkia::CreateFrom1xBitmap(old_icon));
-  layout->AddView(std::move(old_icon_image_view));
-
-  auto arrow = std::make_unique<views::ImageView>();
-  arrow->SetImage(
-      gfx::CreateVectorIcon(kKeyboardArrowRightIcon, kArrowIconSize,
-                            GetNativeTheme()->GetSystemColor(
-                                ui::NativeTheme::kColorId_DefaultIconColor)));
-  layout->AddView(std::move(arrow));
-
-  auto new_icon_image_view = std::make_unique<views::ImageView>();
-  new_icon_image_view->SetImageSize(image_size);
-  new_icon_image_view->SetImage(gfx::ImageSkia::CreateFrom1xBitmap(new_icon));
-  layout->AddView(std::move(new_icon_image_view));
-
-  layout->AddPaddingRow(
-      views::GridLayout::kFixedSize,
-      layout_provider->GetDistanceMetric(DISTANCE_CONTROL_LIST_VERTICAL));
-
-  auto old_title_label =
-      std::make_unique<views::Label>(old_title, views::style::CONTEXT_LABEL);
-  auto new_title_label =
-      std::make_unique<views::Label>(new_title, views::style::CONTEXT_LABEL);
-  old_title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  new_title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  old_title_label->SetMultiLine(true);
-  new_title_label->SetMultiLine(true);
-
-  layout->StartRow(views::GridLayout::kFixedSize, kColumnSetIdMain);
-  layout->AddView(std::move(old_title_label));
-  layout->SkipColumns(1);
-  layout->AddView(std::move(new_title_label));
-
-  chrome::RecordDialogCreation(
-      chrome::DialogIdentifier::APP_IDENTITY_UPDATE_CONFIRMATION);
-}
-
-bool WebAppIdentityUpdateConfirmationView::ShouldShowCloseButton() const {
-  return false;
-}
-
-void WebAppIdentityUpdateConfirmationView::OnDialogAccepted() {
-  std::move(callback_).Run(web_app::AppIdentityUpdate::kAllowed);
-}
-
-bool WebAppIdentityUpdateConfirmationView::Cancel() {
-  uninstall_dialog_ = std::make_unique<WebAppUninstallDialogViews>(
-      Profile::FromBrowserContext(web_contents_->GetBrowserContext()),
-      web_contents_->GetTopLevelNativeWindow());
-  uninstall_dialog_->show_data_clearing_confirmation(false);
-  uninstall_dialog_->ConfirmUninstall(
-      app_id_, webapps::WebappUninstallSource::kAppMenu, base::DoNothing());
-  return false;
-}
-
-BEGIN_METADATA(WebAppIdentityUpdateConfirmationView, views::DialogDelegateView)
-END_METADATA
-
-namespace chrome {
-
-void ShowWebAppIdentityUpdateDialog(
-    const std::string& app_id,
-    bool title_change,
-    bool icon_change,
-    const std::u16string& old_title,
-    const std::u16string& new_title,
-    const SkBitmap& old_icon,
-    const SkBitmap& new_icon,
-    content::WebContents* web_contents,
-    web_app::AppIdentityDialogCallback callback) {
-  auto* dialog = new WebAppIdentityUpdateConfirmationView(
-      app_id, title_change, icon_change, old_title, new_title, old_icon,
-      new_icon, web_contents, std::move(callback));
-  views::Widget* dialog_widget =
-      constrained_window::CreateBrowserModalDialogViews(
-          dialog, web_contents->GetTopLevelNativeWindow());
-  dialog_widget->Show();
-
-  if (g_auto_accept_app_identity_update_for_testing) {
-    dialog->AcceptDialog();
-  }
-}
-
-void SetAutoAcceptAppIdentityUpdateForTesting(bool auto_accept) {
-  g_auto_accept_app_identity_update_for_testing = auto_accept;
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.h b/chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.h
deleted file mode 100644
index 8926ed7..0000000
--- a/chrome/browser/ui/views/web_apps/web_app_identity_update_confirmation_view.h
+++ /dev/null
@@ -1,61 +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.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_IDENTITY_UPDATE_CONFIRMATION_VIEW_H_
-#define CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_IDENTITY_UPDATE_CONFIRMATION_VIEW_H_
-
-#include <string>
-
-#include "chrome/browser/ui/browser_dialogs.h"
-#include "chrome/browser/web_applications/components/web_app_callback_app_identity.h"
-#include "ui/base/metadata/metadata_header_macros.h"
-#include "ui/views/window/dialog_delegate.h"
-
-class SkBitmap;
-class WebAppUninstallDialogViews;
-
-// WebAppIdentityUpdateConfirmationView provides views for showing which parts
-// of the app's identity changed so the user can make a determination whether to
-// allow the update or uninstall it.
-class WebAppIdentityUpdateConfirmationView : public views::DialogDelegateView {
- public:
-  METADATA_HEADER(WebAppIdentityUpdateConfirmationView);
-  WebAppIdentityUpdateConfirmationView(
-      const std::string& app_id,
-      bool title_change,
-      bool icon_change,
-      const std::u16string& old_title,
-      const std::u16string& new_title,
-      const SkBitmap& old_icon,
-      const SkBitmap& new_icon,
-      content::WebContents* web_contents,
-      web_app::AppIdentityDialogCallback callback);
-  WebAppIdentityUpdateConfirmationView(
-      const WebAppIdentityUpdateConfirmationView&) = delete;
-  WebAppIdentityUpdateConfirmationView& operator=(
-      const WebAppIdentityUpdateConfirmationView&) = delete;
-  ~WebAppIdentityUpdateConfirmationView() override;
-
- private:
-  // Overridden from views::WidgetDelegate:
-  bool ShouldShowCloseButton() const override;
-
-  // Overriden from views::DialogDelegateView:
-  bool Cancel() override;
-
-  void OnDialogAccepted();
-
-  // The id of the app whose identity is changing.
-  std::string app_id_;
-
-  // A callback to relay the results of the app identity update dialog.
-  web_app::AppIdentityDialogCallback callback_;
-
-  // The app uninstall dialog, shown to confirm the uninstallation.
-  std::unique_ptr<WebAppUninstallDialogViews> uninstall_dialog_;
-
-  content::WebContents* web_contents_;
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_WEB_APPS_WEB_APP_IDENTITY_UPDATE_CONFIRMATION_VIEW_H_
diff --git a/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.cc b/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.cc
index 02b2b509..e1178222 100644
--- a/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.cc
@@ -61,7 +61,6 @@
     Profile* profile,
     WebAppUninstallDialogViews* dialog_view,
     web_app::AppId app_id,
-    bool show_data_clearing_confirmation,
     webapps::WebappUninstallSource uninstall_source,
     std::map<SquareSizePx, SkBitmap> icon_bitmaps)
     : dialog_(dialog_view), app_id_(app_id), profile_(profile) {
@@ -71,7 +70,6 @@
   app_start_url_ = provider->registrar().GetAppStartUrl(app_id_);
   DCHECK(!app_start_url_.is_empty());
   DCHECK(app_start_url_.is_valid());
-  show_data_clearing_confirmation_ = show_data_clearing_confirmation;
 
   gfx::Size image_size{kIconSizeInDip, kIconSizeInDip};
 
@@ -111,16 +109,14 @@
       views::DialogContentType::kText, views::DialogContentType::kText);
   set_margins(insets + gfx::Insets(0, insets.left() + kIconSizeInDip, 0, 0));
 
-  if (show_data_clearing_confirmation_) {
-    std::u16string checkbox_label = l10n_util::GetStringFUTF16(
-        IDS_EXTENSION_UNINSTALL_PROMPT_REMOVE_DATA_CHECKBOX,
-        url_formatter::FormatUrlForSecurityDisplay(
-            app_start_url_, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
+  std::u16string checkbox_label = l10n_util::GetStringFUTF16(
+      IDS_EXTENSION_UNINSTALL_PROMPT_REMOVE_DATA_CHECKBOX,
+      url_formatter::FormatUrlForSecurityDisplay(
+          app_start_url_, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
 
-    auto checkbox = std::make_unique<views::Checkbox>(checkbox_label);
-    checkbox->SetMultiLine(true);
-    checkbox_ = AddChildView(std::move(checkbox));
-  }
+  auto checkbox = std::make_unique<views::Checkbox>(checkbox_label);
+  checkbox->SetMultiLine(true);
+  checkbox_ = AddChildView(std::move(checkbox));
 
   uninstall_source_ = uninstall_source;
 
@@ -136,16 +132,14 @@
   if (!dialog_)
     return;
 
-  bool clear_web_app_site_data =
-      !show_data_clearing_confirmation_ || checkbox_->GetChecked();
   HistogramCloseAction action =
-      clear_web_app_site_data
+      checkbox_->GetChecked()
           ? HistogramCloseAction::kUninstallAndCheckboxChecked
           : HistogramCloseAction::kUninstall;
   UMA_HISTOGRAM_ENUMERATION("Webapp.UninstallDialogAction", action);
 
   Uninstall();
-  if (clear_web_app_site_data)
+  if (checkbox_->GetChecked())
     ClearWebAppSiteData();
 }
 
@@ -269,8 +263,7 @@
   }
 
   view_ = new WebAppUninstallDialogDelegateView(
-      profile_, this, app_id_, show_data_clearing_confirmation_,
-      uninstall_source, std::move(icon_bitmaps));
+      profile_, this, app_id_, uninstall_source, std::move(icon_bitmaps));
 
   constrained_window::CreateBrowserModalDialogViews(view_, parent_)->Show();
 
diff --git a/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.h b/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.h
index 25f37bf..3014d07 100644
--- a/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.h
+++ b/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_view.h
@@ -44,7 +44,6 @@
       Profile* profile,
       WebAppUninstallDialogViews* dialog_view,
       web_app::AppId app_id,
-      bool show_data_clearing_confirmation,
       webapps::WebappUninstallSource uninstall_source,
       std::map<SquareSizePx, SkBitmap> icon_bitmaps);
   WebAppUninstallDialogDelegateView(const WebAppUninstallDialogDelegateView&) =
@@ -73,13 +72,9 @@
 
   // The web app we are showing the dialog for.
   const web_app::AppId app_id_;
-
   // The dialog needs start_url copy even if app gets uninstalled.
   GURL app_start_url_;
 
-  // Whether to show the 'Also clear data for this site' checkbox.
-  bool show_data_clearing_confirmation_ = true;
-
   Profile* const profile_;
 
   webapps::WebappUninstallSource uninstall_source_;
@@ -99,13 +94,6 @@
       delete;
   ~WebAppUninstallDialogViews() override;
 
-  // Whether to show the 'Also clear data for this site' checkbox. Defaults to
-  // |true|, but when set to |false| implies deletion of data for the site will
-  // occur.
-  void show_data_clearing_confirmation(bool value) {
-    show_data_clearing_confirmation_ = value;
-  }
-
   // web_app::WebAppUninstallDialog:
   void ConfirmUninstall(const web_app::AppId& app_id,
                         webapps::WebappUninstallSource uninstall_source,
@@ -151,9 +139,6 @@
   web_app::AppId app_id_;
   Profile* const profile_;
 
-  // Whether to show the 'Also clear data for this site' checkbox.
-  bool show_data_clearing_confirmation_ = true;
-
   THREAD_CHECKER(thread_checker_);
 
   base::WeakPtrFactory<WebAppUninstallDialogViews> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
index 86082a2..acbea14 100644
--- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
+++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -25,12 +24,10 @@
 #include "chrome/browser/ui/web_applications/web_app_metrics.h"
 #include "chrome/browser/ui/webui/web_app_internals/web_app_internals_source.h"
 #include "chrome/browser/web_applications/components/app_registry_controller.h"
-#include "chrome/browser/web_applications/components/web_app_callback_app_identity.h"
 #include "chrome/browser/web_applications/extensions/web_app_extension_shortcut.h"
 #include "chrome/browser/web_applications/system_web_apps/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
-#include "components/constrained_window/constrained_window_views.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
 #include "components/services/app_service/public/cpp/types_util.h"
 #include "components/webapps/browser/installable/installable_metrics.h"
@@ -371,21 +368,6 @@
   return nullptr;
 }
 
-void WebAppUiManagerImpl::ShowWebAppIdentityUpdateDialog(
-    const std::string& app_id,
-    bool title_change,
-    bool icon_change,
-    const std::u16string& old_title,
-    const std::u16string& new_title,
-    const SkBitmap& old_icon,
-    const SkBitmap& new_icon,
-    content::WebContents* web_contents,
-    web_app::AppIdentityDialogCallback callback) {
-  chrome::ShowWebAppIdentityUpdateDialog(
-      app_id, title_change, icon_change, old_title, new_title, old_icon,
-      new_icon, web_contents, std::move(callback));
-}
-
 void WebAppUiManagerImpl::OnBrowserAdded(Browser* browser) {
   DCHECK(started_);
   if (!IsBrowserForInstalledApp(browser))
diff --git a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
index 95eea892..80d8f83 100644
--- a/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
+++ b/chrome/browser/ui/web_applications/web_app_ui_manager_impl.h
@@ -64,16 +64,6 @@
                               bool shortcut_created) override;
   content::WebContents* NavigateExistingWindow(const AppId& app_id,
                                                const GURL& url) override;
-  void ShowWebAppIdentityUpdateDialog(
-      const std::string& app_id,
-      bool title_change,
-      bool icon_change,
-      const std::u16string& old_title,
-      const std::u16string& new_title,
-      const SkBitmap& old_icon,
-      const SkBitmap& new_icon,
-      content::WebContents* web_contents,
-      web_app::AppIdentityDialogCallback callback) override;
 
   // BrowserListObserver:
   void OnBrowserAdded(Browser* browser) override;
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc
index 236e14a..df5722a 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.cc
@@ -96,7 +96,8 @@
 }
 
 // Helper method to create zippy data.
-base::Value CreateZippyData(const SettingZippyList& zippy_list) {
+base::Value CreateZippyData(const SettingZippyList& zippy_list,
+                            bool is_minor_mode) {
   base::Value zippy_data(base::Value::Type::LIST);
   for (auto& setting_zippy : zippy_list) {
     base::Value data(base::Value::Type::DICTIONARY);
@@ -112,6 +113,7 @@
     data.SetKey("iconUri", base::Value(setting_zippy.icon_uri()));
     data.SetKey("popupLink", base::Value(l10n_util::GetStringUTF16(
                                  IDS_ASSISTANT_ACTIVITY_CONTROL_POPUP_LINK)));
+    data.SetKey("isMinorMode", base::Value(is_minor_mode));
     zippy_data.Append(std::move(data));
   }
   return zippy_data;
@@ -178,7 +180,8 @@
 
 // Get string constants for settings ui.
 base::Value GetSettingsUiStrings(const assistant::SettingsUi& settings_ui,
-                                 bool activity_control_needed) {
+                                 bool activity_control_needed,
+                                 bool equal_weight_buttons) {
   auto consent_ui = settings_ui.consent_flow_ui().consent_ui();
   auto activity_control_ui = consent_ui.activity_control_ui();
   auto third_party_disclosure_ui = consent_ui.third_party_disclosure_ui();
@@ -186,6 +189,7 @@
 
   dictionary.SetKey("activityControlNeeded",
                     base::Value(activity_control_needed));
+  dictionary.SetKey("equalWeightButtons", base::Value(equal_weight_buttons));
 
   // Add activity control string constants.
   if (activity_control_needed) {
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h
index ad7cb77..a80687b 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_utils.h
@@ -59,7 +59,8 @@
 using SettingZippyList = google::protobuf::RepeatedPtrField<
     assistant::ClassicActivityControlUiTexts::SettingZippy>;
 // Helper method to create zippy data.
-base::Value CreateZippyData(const SettingZippyList& zippy_list);
+base::Value CreateZippyData(const SettingZippyList& zippy_list,
+                            bool is_minor_mode);
 
 // Helper method to create disclosure data.
 base::Value CreateDisclosureData(const SettingZippyList& disclosure_list);
@@ -71,7 +72,8 @@
 
 // Get string constants for settings ui.
 base::Value GetSettingsUiStrings(const assistant::SettingsUi& settings_ui,
-                                 bool activity_control_needed);
+                                 bool activity_control_needed,
+                                 bool equal_weight_buttons);
 
 void RecordActivityControlConsent(Profile* profile,
                                   std::string ui_audit_key,
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
index c995db8..cdd79561 100644
--- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
@@ -22,6 +22,7 @@
 #include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
 #include "chromeos/services/assistant/public/cpp/assistant_service.h"
 #include "chromeos/services/assistant/public/cpp/features.h"
+#include "chromeos/services/assistant/public/proto/get_settings_ui.pb.h"
 #include "chromeos/services/assistant/public/proto/settings_ui.pb.h"
 #include "components/login/localized_values_builder.h"
 #include "components/prefs/pref_service.h"
@@ -169,9 +170,6 @@
                    chromeos::assistant::features::IsVoiceMatchDisabled());
   dict->SetBoolean("betterAssistantEnabled",
                    chromeos::assistant::features::IsBetterAssistantEnabled());
-  // TODO(https://crbug.com/1224850): read actual minor mode signal from account
-  // capability or get this info from consent server.
-  dict->SetBoolean("isMinorMode", features::IsMinorModeRestrictionEnabled());
   BaseScreenHandler::GetAdditionalParameters(dict);
 }
 
@@ -350,7 +348,7 @@
   }
 
   assistant::SettingsUiSelector selector = GetSettingsUiSelector();
-  assistant::AssistantSettings::Get()->GetSettings(
+  assistant::AssistantSettings::Get()->GetSettingsWithHeader(
       selector.SerializeAsString(),
       base::BindOnce(&AssistantOptInFlowScreenHandler::OnGetSettingsResponse,
                      weak_factory_.GetWeakPtr()));
@@ -377,7 +375,7 @@
 }
 
 void AssistantOptInFlowScreenHandler::OnGetSettingsResponse(
-    const std::string& settings) {
+    const std::string& response) {
   const base::TimeDelta time_since_request_sent =
       base::TimeTicks::Now() - send_request_time_;
   UMA_HISTOGRAM_TIMES("Assistant.OptInFlow.GetSettingsRequestTime",
@@ -391,13 +389,21 @@
     return;
   }
 
-  assistant::SettingsUi settings_ui;
-  if (!settings_ui.ParseFromString(settings)) {
+  assistant::GetSettingsUiResponse settings_ui_response;
+  if (!settings_ui_response.ParseFromString(response)) {
     LOG(ERROR) << "Failed to parse get settings response.";
     HandleFlowFinished();
     return;
   }
 
+  auto settings_ui = settings_ui_response.settings();
+  auto header = settings_ui_response.header();
+
+  bool equal_weight_buttons =
+      features::IsMinorModeRestrictionEnabled() &&
+      header.footer_button_layout() ==
+          assistant::SettingsResponseHeader_AcceptRejectLayout_EQUAL_WEIGHT;
+
   if (settings_ui.has_gaia_user_context_ui()) {
     auto gaia_user_context_ui = settings_ui.gaia_user_context_ui();
     if (gaia_user_context_ui.assistant_disabled_by_dasher_domain()) {
@@ -427,6 +433,8 @@
   base::Value zippy_data(base::Value::Type::LIST);
   bool skip_activity_control = true;
   pending_consent_data_.clear();
+  // We read from `multi_consent_ui` field if it is populated and we assume user
+  // is a minor user; otherwise, we read from `consent_ui` field.
   if (features::IsMinorModeRestrictionEnabled() &&
       settings_ui.consent_flow_ui().multi_consent_ui().size()) {
     auto multi_consent_ui = settings_ui.consent_flow_ui().multi_consent_ui();
@@ -438,7 +446,8 @@
         data.consent_token = activity_control_ui.consent_token();
         data.ui_audit_key = activity_control_ui.ui_audit_key();
         pending_consent_data_.push_back(data);
-        zippy_data.Append(CreateZippyData(activity_control_ui.setting_zippy()));
+        zippy_data.Append(CreateZippyData(activity_control_ui.setting_zippy(),
+                                          /*is_minor_mode=*/true));
       }
     }
   } else {
@@ -449,7 +458,8 @@
       data.consent_token = activity_control_ui.consent_token();
       data.ui_audit_key = activity_control_ui.ui_audit_key();
       pending_consent_data_.push_back(data);
-      zippy_data.Append(CreateZippyData(activity_control_ui.setting_zippy()));
+      zippy_data.Append(CreateZippyData(activity_control_ui.setting_zippy(),
+                                        /*is_minor_mode=*/false));
     }
   }
 
@@ -505,7 +515,8 @@
   }
 
   // Pass string constants dictionary.
-  auto dictionary = GetSettingsUiStrings(settings_ui, activity_control_needed_);
+  auto dictionary = GetSettingsUiStrings(settings_ui, activity_control_needed_,
+                                         equal_weight_buttons);
   PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
   dictionary.SetKey("voiceMatchEnforcedOff",
                     base::Value(IsVoiceMatchEnforcedOff(prefs)));
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index c2b5236..ec18fe4 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -262,11 +262,6 @@
 }
 
 user_manager::UserType CalculateUserType(const AccountId& account_id) {
-  if (user_manager::UserManager::Get()->IsDeprecatedSupervisedAccountId(
-          account_id)) {
-    return user_manager::USER_TYPE_SUPERVISED_DEPRECATED;
-  }
-
   if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY)
     return user_manager::USER_TYPE_ACTIVE_DIRECTORY;
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/languages_section.cc b/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
index ce2569e..2b9b79b 100644
--- a/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
@@ -352,6 +352,10 @@
       {"inputMethodNotAllowed",
        IDS_OS_SETTINGS_LANGUAGES_INPUT_METHOD_NOT_ALLOWED},
       {"spellCheckTitle", IDS_OS_SETTINGS_LANGUAGES_SPELL_CHECK_TITLE},
+      {"spellAndGrammarCheckTitle",
+       IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_TITLE},
+      {"spellAndGrammarCheckDescription",
+       IDS_OS_SETTINGS_LANGUAGES_SPELL_AND_GRAMMAR_CHECK_DESCRIPTION},
       {"spellCheckEnhancedLabel",
        IDS_OS_SETTINGS_LANGUAGES_SPELL_CHECK_ENHANCED_LABEL},
       {"spellCheckLanguagesListTitle",
@@ -464,6 +468,9 @@
           base::FeatureList::IsEnabled(::chromeos::features::kImeMojoDecoder));
   html_source->AddBoolean("enableLanguageSettingsV2Update2",
                           IsLanguageSettingsV2Update2Enabled());
+  html_source->AddBoolean("onDeviceGrammarCheckEnabled",
+                          base::FeatureList::IsEnabled(
+                              ::chromeos::features::kOnDeviceGrammarCheck));
 }
 
 void LanguagesSection::AddHandlers(content::WebUI* web_ui) {
diff --git a/chrome/browser/ui/webui/settings/chromeos/people_section.cc b/chrome/browser/ui/webui/settings/chromeos/people_section.cc
index ce7c809..889a7a9 100644
--- a/chrome/browser/ui/webui/settings/chromeos/people_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/people_section.cc
@@ -440,7 +440,7 @@
   html_source->AddLocalizedStrings(kLocalizedStrings);
 
   html_source->AddBoolean("quickUnlockEnabled",
-                          chromeos::quick_unlock::IsPinEnabled(pref_service));
+                          chromeos::quick_unlock::IsPinEnabled());
   html_source->AddBoolean("quickUnlockPinAutosubmitFeatureEnabled",
                           chromeos::features::IsPinAutosubmitFeatureEnabled());
   html_source->AddBoolean(
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
index ffbf044..1dcb9c83 100644
--- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
+++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
@@ -52,6 +52,7 @@
 #include "chrome/browser/ash/crostini/crostini_util.h"
 #include "chrome/browser/web_applications/system_web_apps/system_web_app_manager.h"
 #include "components/full_restore/app_launch_info.h"
+#include "components/full_restore/full_restore_save_handler.h"
 #include "components/full_restore/full_restore_utils.h"
 #include "components/sessions/core/session_id.h"
 #endif
@@ -531,6 +532,12 @@
       params.app_id, params.container, params.disposition, params.source,
       params.display_id, params.launch_files, params.intent);
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // Create the FullRestoreSaveHandler instance before launching the app to
+  // observe the browser window.
+  full_restore::FullRestoreSaveHandler::GetInstance();
+#endif
+
   content::WebContents* const web_contents =
       web_app_launch_manager_->OpenApplication(std::move(params));
 
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 1549741..48193b6 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -37,7 +37,6 @@
     "url_handler_manager.h",
     "web_app_audio_focus_id_map.cc",
     "web_app_audio_focus_id_map.h",
-    "web_app_callback_app_identity.h",
     "web_app_chromeos_data.cc",
     "web_app_chromeos_data.h",
     "web_app_constants.cc",
diff --git a/chrome/browser/web_applications/components/web_app_callback_app_identity.h b/chrome/browser/web_applications/components/web_app_callback_app_identity.h
deleted file mode 100644
index 183fe33..0000000
--- a/chrome/browser/web_applications/components/web_app_callback_app_identity.h
+++ /dev/null
@@ -1,25 +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.
-
-#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_CALLBACK_APP_IDENTITY_H_
-#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_CALLBACK_APP_IDENTITY_H_
-
-#include "base/callback.h"
-
-namespace web_app {
-
-// As part of evaluating a manifest update, the flow needs to take into
-// consideration whether the app identity (name and icon) is changing and
-// whether to allow that.
-enum class AppIdentityUpdate {
-  kAllowed = 0,
-  kUninstall,
-  kSkipped,
-};
-
-using AppIdentityDialogCallback = base::OnceCallback<void(AppIdentityUpdate)>;
-
-}  // namespace web_app
-
-#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_CALLBACK_APP_IDENTITY_H_
diff --git a/chrome/browser/web_applications/components/web_app_ui_manager.h b/chrome/browser/web_applications/components/web_app_ui_manager.h
index a4a0453..d211a57e 100644
--- a/chrome/browser/web_applications/components/web_app_ui_manager.h
+++ b/chrome/browser/web_applications/components/web_app_ui_manager.h
@@ -10,7 +10,6 @@
 
 #include "base/callback_forward.h"
 #include "chrome/browser/web_applications/components/os_integration_manager.h"
-#include "chrome/browser/web_applications/components/web_app_callback_app_identity.h"
 #include "chrome/browser/web_applications/components/web_app_id.h"
 #include "chrome/browser/web_applications/components/web_app_shortcut.h"
 
@@ -74,17 +73,6 @@
 
   virtual content::WebContents* NavigateExistingWindow(const AppId& app_id,
                                                        const GURL& url) = 0;
-
-  virtual void ShowWebAppIdentityUpdateDialog(
-      const std::string& app_id,
-      bool title_change,
-      bool icon_change,
-      const std::u16string& old_title,
-      const std::u16string& new_title,
-      const SkBitmap& old_icon,
-      const SkBitmap& new_icon,
-      content::WebContents* web_contents,
-      web_app::AppIdentityDialogCallback callback) = 0;
 };
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
index 506c9910..00b95cc 100644
--- a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
+++ b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
@@ -20,11 +20,9 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/browser_features.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/web_applications/components/app_shortcut_manager.h"
 #include "chrome/browser/web_applications/components/externally_managed_app_manager.h"
@@ -546,39 +544,6 @@
             "Different app name");
 }
 
-class ManifestUpdateManagerAppIdentityBrowserTest
-    : public ManifestUpdateManagerBrowserTest {
-  base::test::ScopedFeatureList scoped_feature_list_{
-      features::kPwaUpdateDialogForNameAndIcon};
-};
-
-IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerAppIdentityBrowserTest,
-                       VerifyAppIdentityUpdatesWithDlgForUserInstalledApps) {
-  chrome::SetAutoAcceptAppIdentityUpdateForTesting(true);
-
-  constexpr char kManifestTemplate[] = R"(
-    {
-      "name": "$1",
-      "start_url": ".",
-      "scope": "/",
-      "display": "standalone",
-      "icons": $2
-    }
-  )";
-  OverrideManifest(kManifestTemplate, {"Test app name", kInstallableIconList});
-  AppId app_id = InstallWebApp();
-
-  OverrideManifest(kManifestTemplate,
-                   {"Different app name", kAnotherInstallableIconList});
-  EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
-            ManifestUpdateResult::kAppUpdated);
-  histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
-                                      ManifestUpdateResult::kAppUpdated, 1);
-  EXPECT_EQ(GetProvider().registrar().GetAppShortName(app_id),
-            "Different app name");
-  CheckShortcutInfoUpdated(app_id, kAnotherInstallableIconTopLeftColor);
-}
-
 IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTest,
                        CheckIgnoresStartUrlChange) {
   constexpr char kManifestTemplate[] = R"(
diff --git a/chrome/browser/web_applications/manifest_update_task.cc b/chrome/browser/web_applications/manifest_update_task.cc
index 70f17eb..1ef572c 100644
--- a/chrome/browser/web_applications/manifest_update_task.cc
+++ b/chrome/browser/web_applications/manifest_update_task.cc
@@ -12,7 +12,6 @@
 #include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/browser_features.h"
 #include "chrome/browser/web_applications/components/app_icon_manager.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/install_manager.h"
@@ -32,27 +31,13 @@
 
 namespace web_app {
 
-struct IconDiff {
- public:
-  IconDiff() = default;
-  explicit IconDiff(bool changes) { changes_detected = changes; }
-  IconDiff(const SkBitmap& before_icon, const SkBitmap& after_icon) {
-    changes_detected = true;
-    before = before_icon;
-    after = after_icon;
-  }
-  bool changes_detected = false;
-  SkBitmap before;
-  SkBitmap after;
-};
-
 namespace {
 
-IconDiff HaveIconContentsChanged(
+bool HaveIconContentsChanged(
     const std::map<SquareSizePx, SkBitmap>& disk_icon_bitmaps,
     const std::map<SquareSizePx, SkBitmap>& downloaded_icon_bitmaps) {
   if (downloaded_icon_bitmaps.size() != disk_icon_bitmaps.size())
-    return IconDiff(true);
+    return true;
 
   for (const std::pair<const SquareSizePx, SkBitmap>& entry :
        downloaded_icon_bitmaps) {
@@ -61,40 +46,29 @@
 
     auto it = disk_icon_bitmaps.find(size);
     if (it == disk_icon_bitmaps.end())
-      return IconDiff(true);
+      return true;
 
     const SkBitmap& disk_bitmap = it->second;
     if (!gfx::BitmapsAreEqual(downloaded_bitmap, disk_bitmap))
-      return IconDiff(disk_bitmap, downloaded_bitmap);
+      return true;
   }
 
-  return IconDiff(false);
+  return false;
 }
 
-IconDiff HaveIconBitmapsChanged(const IconBitmaps& disk_icon_bitmaps,
-                                const IconBitmaps& downloaded_icon_bitmaps) {
-  IconDiff icon_diff = HaveIconContentsChanged(disk_icon_bitmaps.any,
-                                               downloaded_icon_bitmaps.any);
-  if (icon_diff.changes_detected)
-    return icon_diff;
-
-  icon_diff = HaveIconContentsChanged(disk_icon_bitmaps.maskable,
-                                      downloaded_icon_bitmaps.maskable);
-  if (icon_diff.changes_detected)
-    return icon_diff;
-
-  icon_diff = HaveIconContentsChanged(disk_icon_bitmaps.monochrome,
-                                      downloaded_icon_bitmaps.monochrome);
-  if (icon_diff.changes_detected)
-    return icon_diff;
-
-  return IconDiff(false);
+bool HaveIconBitmapsChanged(const IconBitmaps& disk_icon_bitmaps,
+                            const IconBitmaps& downloaded_icon_bitmaps) {
+  return HaveIconContentsChanged(disk_icon_bitmaps.any,
+                                 downloaded_icon_bitmaps.any) ||
+         HaveIconContentsChanged(disk_icon_bitmaps.maskable,
+                                 downloaded_icon_bitmaps.maskable) ||
+         HaveIconContentsChanged(disk_icon_bitmaps.monochrome,
+                                 downloaded_icon_bitmaps.monochrome);
 }
 
 // Some apps, such as pre-installed apps, have been vetted and are therefore
 // considered safe and permitted to update their names.
-bool AllowUnpromptedNameUpdate(const AppId& app_id,
-                               const AppRegistrar& registrar) {
+bool AllowNameUpdating(const AppId& app_id, const AppRegistrar& registrar) {
   const WebApp* web_app = registrar.AsWebAppRegistrar()->GetAppById(app_id);
   if (!web_app)
     return false;
@@ -104,8 +78,7 @@
 // Some apps, such as pre-installed apps, have been vetted and are therefore
 // considered safe and permitted to update their icon. For others, the feature
 // flag needs to be on.
-bool AllowUnpromptedIconUpdate(const AppId& app_id,
-                               const AppRegistrar& registrar) {
+bool AllowIconUpdating(const AppId& app_id, const AppRegistrar& registrar) {
   const WebApp* web_app = registrar.AsWebAppRegistrar()->GetAppById(app_id);
   if (!web_app)
     return false;
@@ -336,7 +309,7 @@
 
   // Allow app icon updating for certain apps, or if the existing icons are
   // empty - this means the app icon download during install failed.
-  if (AllowUnpromptedIconUpdate(app_id_, registrar_) &&
+  if (AllowIconUpdating(app_id_, registrar_) &&
       web_application_info_->icon_infos !=
           registrar_.GetAppIconInfos(app_id_)) {
     return true;
@@ -398,7 +371,7 @@
     return true;
   }
 
-  if (AllowUnpromptedNameUpdate(app_id_, registrar_) &&
+  if (AllowNameUpdating(app_id_, registrar_) &&
       web_application_info_->title !=
           base::UTF8ToUTF16(registrar_.GetAppShortName(app_id_))) {
     return true;
@@ -446,6 +419,7 @@
   }
 
   stage_ = Stage::kPendingIconReadFromDisk;
+  Observe(nullptr);
   icon_manager_.ReadAllIcons(
       app_id_, base::BindOnce(&ManifestUpdateTask::OnAllIconsRead, AsWeakPtr(),
                               std::move(icons_map)));
@@ -461,85 +435,19 @@
   }
   DCHECK(web_application_info_.has_value());
 
-  if (!AllowUnpromptedNameUpdate(app_id_, registrar_) &&
-      !AllowUnpromptedIconUpdate(app_id_, registrar_) &&
-      base::FeatureList::IsEnabled(features::kPwaUpdateDialogForNameAndIcon)) {
-    // This call populates the |web_application_info_| with all icon bitmap
-    // data.
-    FilterAndResizeIconsGenerateMissing(&web_application_info_.value(),
-                                        &downloaded_icons_map);
-    IconDiff icon_diff = IsUpdateNeededForIconContents(disk_icon_bitmaps);
-    std::u16string old_title =
-        base::UTF8ToUTF16(registrar_.GetAppShortName(app_id_));
-    std::u16string new_title = web_application_info_->title;
-    bool title_change = old_title != new_title;
-
-    if (title_change || icon_diff.changes_detected) {
-      SkBitmap* before_icon = nullptr;
-      SkBitmap* after_icon = nullptr;
-      if (icon_diff.changes_detected) {
-        before_icon = &icon_diff.before;
-        after_icon = &icon_diff.after;
-      } else {
-        auto it = disk_icon_bitmaps.any.find(web_app::kWebAppIconSmall);
-        if (it != disk_icon_bitmaps.any.end()) {
-          before_icon = &it->second;
-          after_icon = &it->second;
-        }
-      }
-
-      if (before_icon != nullptr && after_icon != nullptr) {
-        ui_manager_.ShowWebAppIdentityUpdateDialog(
-            app_id_, title_change, icon_diff.changes_detected, old_title,
-            new_title, *before_icon, *after_icon, web_contents(),
-            base::BindOnce(&ManifestUpdateTask::OnPostAppIdentityUpdateCheck,
-                           AsWeakPtr(), std::move(downloaded_icons_map),
-                           std::move(disk_icon_bitmaps)));
-        // Must be called after showing the dialog, to have access to
-        // web_contents() above.
-        Observe(nullptr);
-        return;
-      }
-    }
-  }
-
-  Observe(nullptr);
-
-  // App Identity Warning dialog was not needed, proceed with update check.
-  OnPostAppIdentityUpdateCheck(downloaded_icons_map, disk_icon_bitmaps,
-                               AppIdentityUpdate::kSkipped);
-}
-
-void ManifestUpdateTask::OnPostAppIdentityUpdateCheck(
-    IconsMap downloaded_icons_map,
-    IconBitmaps disk_icon_bitmaps,
-    AppIdentityUpdate app_identity_update_allowed) {
-  app_identity_update_allowed_ =
-      app_identity_update_allowed == AppIdentityUpdate::kAllowed;
-  if (app_identity_update_allowed_) {
-    UpdateAfterWindowsClose();
-    return;
-  }
-
   // Allow app icon updating for certain apps, or if the existing icons are
   // empty - this means the app icon download during install failed.
-  if (AllowUnpromptedIconUpdate(app_id_, registrar_)) {
-    // When kPwaUpdateDialogForNameAndIcon is enabled, the FilterAndResizeIcons
-    // call has already been made.
-    if (!base::FeatureList::IsEnabled(
-            features::kPwaUpdateDialogForNameAndIcon)) {
-      // This call populates the |web_application_info_| with all icon bitmap
-      // data.
-      // If this data does not match what we already have on disk, then an
-      // update is necessary.
-      // TODO(https://crbug.com/1184911): Reuse this data in the web app install
-      // task.
-      FilterAndResizeIconsGenerateMissing(&web_application_info_.value(),
-                                          &downloaded_icons_map);
-    }
-
+  if (AllowIconUpdating(app_id_, registrar_)) {
+    // This call populates the |web_application_info_| with all icon bitmap
+    // data.
+    // If this data does not match what we already have on disk, then an update
+    // is necessary.
+    // TODO(https://crbug.com/1184911): Reuse this data in the web app install
+    // task.
+    FilterAndResizeIconsGenerateMissing(&web_application_info_.value(),
+                                        &downloaded_icons_map);
     // TODO: compare in a BEST_EFFORT blocking PostTaskAndReply.
-    if (IsUpdateNeededForIconContents(disk_icon_bitmaps).changes_detected) {
+    if (IsUpdateNeededForIconContents(disk_icon_bitmaps)) {
       UpdateAfterWindowsClose();
       return;
     }
@@ -567,7 +475,7 @@
   }
 }
 
-IconDiff ManifestUpdateTask::IsUpdateNeededForIconContents(
+bool ManifestUpdateTask::IsUpdateNeededForIconContents(
     const IconBitmaps& disk_icon_bitmaps) const {
   DCHECK(web_application_info_.has_value());
   return HaveIconBitmapsChanged(disk_icon_bitmaps,
@@ -603,8 +511,7 @@
     const IconBitmaps& downloaded_icon_bitmaps =
         downloaded_shortcuts_menu_icon_bitmaps[i];
     const IconBitmaps& disk_icon_bitmaps = disk_shortcuts_menu_icon_bitmaps[i];
-    if (HaveIconBitmapsChanged(disk_icon_bitmaps, downloaded_icon_bitmaps)
-            .changes_detected)
+    if (HaveIconBitmapsChanged(disk_icon_bitmaps, downloaded_icon_bitmaps))
       return true;
   }
 
@@ -644,8 +551,7 @@
 
   DCHECK(web_application_info_.has_value());
 
-  if (!AllowUnpromptedNameUpdate(app_id_, registrar_) &&
-      !app_identity_update_allowed_) {
+  if (!AllowNameUpdating(app_id_, registrar_)) {
     // The app's name must not change due to an automatic update, except for
     // default installed apps (that have been vetted).
     // TODO(crbug.com/1088338): Provide a safe way for apps to update their
@@ -672,10 +578,9 @@
   }
 
   stage_ = Stage::kPendingMaybeReadExistingIcons;
-  // If icon updating is disabled, then read the existing icons so they can be
-  // populated on the WebApplicationInfo.
-  if (AllowUnpromptedIconUpdate(app_id_, registrar_) ||
-      app_identity_update_allowed_) {
+  // Allow app icon updating if the existing icons are empty - this means the
+  // app icon download during install failed.
+  if (AllowIconUpdating(app_id_, registrar_)) {
     OnExistingIconsRead(IconBitmaps());
     return;
   }
diff --git a/chrome/browser/web_applications/manifest_update_task.h b/chrome/browser/web_applications/manifest_update_task.h
index 6dfcb0c..bf1f07541 100644
--- a/chrome/browser/web_applications/manifest_update_task.h
+++ b/chrome/browser/web_applications/manifest_update_task.h
@@ -27,8 +27,6 @@
 }
 
 namespace web_app {
-enum class AppIdentityUpdate;
-struct IconDiff;
 
 // Checks for whether file handlers have changed. Ignores differences in names,
 // which aren't stored in the apps::FileHandlers, and ordering, which may
@@ -131,11 +129,7 @@
   void OnIconsDownloaded(bool success, IconsMap icons_map);
   void OnAllIconsRead(IconsMap downloaded_icons_map,
                       IconBitmaps disk_icon_bitmaps);
-  void OnPostAppIdentityUpdateCheck(
-      IconsMap downloaded_icons_map,
-      IconBitmaps disk_icon_bitmaps,
-      AppIdentityUpdate app_identity_update_allowed);
-  IconDiff IsUpdateNeededForIconContents(
+  bool IsUpdateNeededForIconContents(
       const IconBitmaps& disk_icon_bitmaps) const;
   void OnAllShortcutsMenuIconsRead(
       ShortcutsMenuIconBitmaps disk_shortcuts_menu_icons);
@@ -166,7 +160,6 @@
   const AppId app_id_;
   StoppedCallback stopped_callback_;
   bool hang_for_testing_ = false;
-  bool app_identity_update_allowed_ = false;
 
 #if DCHECK_IS_ON()
   bool* destructor_called_ptr_ = nullptr;
diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.cc b/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.cc
index 77030a2e..8a0885eb 100644
--- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.cc
+++ b/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.cc
@@ -80,8 +80,7 @@
 
   if (wait_for_load) {
     navigation_observer.Wait();
-    // TODO(https://crbug.com/1218703): We should check the navigation succeeds
-    // (i.e. doesn't end up in an error page).
+    DCHECK(navigation_observer.last_navigation_succeeded());
   }
 
   if (out_browser)
@@ -123,6 +122,10 @@
                    .GetAppStartUrl(params.app_id);
 }
 
+GURL SystemWebAppBrowserTestBase::GetStartUrl(SystemAppType type) {
+  return GetStartUrl(LaunchParamsForApp(type));
+}
+
 GURL SystemWebAppBrowserTestBase::GetStartUrl() {
   return GetStartUrl(LaunchParamsForApp(GetMockAppType()));
 }
diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h b/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h
index f230657..4865def 100644
--- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h
+++ b/chrome/browser/web_applications/system_web_apps/test/system_web_app_browsertest_base.h
@@ -56,6 +56,9 @@
   // Returns the default start url.
   GURL GetStartUrl();
 
+  // Returns the URL for a installed system web app type.
+  GURL GetStartUrl(SystemAppType type);
+
   void WaitForTestSystemAppInstall();
 
   // Creates a default AppLaunchParams for |system_app_type|. Launches a window.
diff --git a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc
index 48766eb3..7475c4a 100644
--- a/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc
+++ b/chrome/browser/web_applications/system_web_apps/test/system_web_app_manager_browsertest.cc
@@ -18,6 +18,7 @@
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
@@ -26,6 +27,7 @@
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/file_system_access/file_system_access_permission_request_manager.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
@@ -1123,15 +1125,16 @@
   EXPECT_EQ(GetManager().GetRegisteredSystemAppsForTesting().size(),
             app_ids.size());
 
-  for (const auto& app_id : app_ids) {
-    const auto type = GetManager().GetSystemAppTypeForAppId(app_id).value();
+  // Some system web apps keep their resources (e.g. html pages) in real
+  // Chrome OS images. Here we test a few apps whose resources are bundled in
+  // chrome and always available. These apps are able to cover the code path we
+  // execute when launching the app.
+  const SystemAppType apps_to_launch[] = {
+      SystemAppType::SETTINGS,
+      SystemAppType::MEDIA,  // Uses File Handling with launch directory
+  };
 
-    // We don't launch Terminal in browsertest, because it requires resources
-    // that are only available in Chrome OS images.
-    if (type == SystemAppType::TERMINAL)
-      continue;
-
-    // Launch other System Apps normally, and check the app's launch_url loads.
+  for (const auto& type : apps_to_launch) {
     EXPECT_TRUE(LaunchApp(type));
   }
 }
@@ -1504,6 +1507,143 @@
                                 1);
 }
 
+class SystemWebAppManagerContextMenuBrowserTest
+    : public SystemWebAppManagerBrowserTest {
+ public:
+  SystemWebAppManagerContextMenuBrowserTest()
+      : SystemWebAppManagerBrowserTest(/*install_mock=*/false) {
+    maybe_installation_ =
+        TestSystemWebAppInstallation::SetUpAppsForContestMenuTest();
+  }
+  ~SystemWebAppManagerContextMenuBrowserTest() override = default;
+
+ protected:
+  std::unique_ptr<TestRenderViewContextMenu> CreateContextMenu(
+      content::WebContents* web_contents,
+      const GURL& link_href) {
+    content::ContextMenuParams params;
+    params.unfiltered_link_url = link_href;
+    params.link_url = link_href;
+    params.src_url = link_href;
+    params.link_text = std::u16string();
+    params.media_type = blink::mojom::ContextMenuDataMediaType::kNone;
+    params.page_url = web_contents->GetVisibleURL();
+    params.source_type = ui::MENU_SOURCE_NONE;
+    auto menu = std::make_unique<TestRenderViewContextMenu>(
+        web_contents->GetMainFrame(), params);
+    menu->Init();
+    return menu;
+  }
+
+  // See TestSystemWebAppInstallation::SetUpAppsForContestMenuTest.
+  const SystemAppType kAppTypeSingleWindow = SystemAppType::SETTINGS;
+  const SystemAppType kAppTypeMultiWindow = SystemAppType::FILE_MANAGER;
+  const SystemAppType kAppTypeSingleWindowTabStrip = SystemAppType::MEDIA;
+  const SystemAppType kAppTypeMultiWindowTabStrip = SystemAppType::HELP;
+};
+
+IN_PROC_BROWSER_TEST_P(SystemWebAppManagerContextMenuBrowserTest,
+                       LinkToAppItself) {
+  WaitForTestSystemAppInstall();
+
+  {
+    // Single window, no tab strip.
+    auto* web_contents = LaunchApp(kAppTypeSingleWindow);
+    auto menu =
+        CreateContextMenu(web_contents, web_contents->GetLastCommittedURL());
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP));
+  }
+
+  {
+    // Single window, has tab strip.
+    auto* web_contents = LaunchApp(kAppTypeSingleWindowTabStrip);
+    auto menu =
+        CreateContextMenu(web_contents, web_contents->GetLastCommittedURL());
+    EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP));
+  }
+
+  {
+    // Multi window, no tab strip.
+    auto* web_contents = LaunchApp(kAppTypeMultiWindow);
+    auto menu =
+        CreateContextMenu(web_contents, web_contents->GetLastCommittedURL());
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD));
+    EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP));
+  }
+
+  {
+    // Multi window, has tab strip.
+    auto* web_contents = LaunchApp(kAppTypeMultiWindowTabStrip);
+    auto menu =
+        CreateContextMenu(web_contents, web_contents->GetLastCommittedURL());
+    EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD));
+    EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP));
+  }
+}
+
+IN_PROC_BROWSER_TEST_P(SystemWebAppManagerContextMenuBrowserTest,
+                       LinkToOtherSystemWebApp) {
+  WaitForTestSystemAppInstall();
+
+  {
+    // Typical SWA, single window, no tab strip.
+    auto* web_contents = LaunchApp(kAppTypeSingleWindow);
+    auto menu = CreateContextMenu(web_contents,
+                                  GetStartUrl(kAppTypeSingleWindowTabStrip));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD));
+    EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP));
+  }
+
+  {
+    // Deliberately test on a multi-window, tab-strip app to cover edge cases.
+    auto* web_contents = LaunchApp(kAppTypeMultiWindowTabStrip);
+    auto menu =
+        CreateContextMenu(web_contents, GetStartUrl(kAppTypeMultiWindow));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD));
+    EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP));
+  }
+}
+
+IN_PROC_BROWSER_TEST_P(SystemWebAppManagerContextMenuBrowserTest, WebLink) {
+  WaitForTestSystemAppInstall();
+
+  GURL kWebUrl = GURL("https://example.com/");
+
+  {
+    // Typical SWA, single window, no tab strip.
+    auto* web_contents = LaunchApp(kAppTypeSingleWindow);
+    auto menu = CreateContextMenu(web_contents, kWebUrl);
+    EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+    EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP));
+  }
+
+  {
+    // Deliberately test on a multi-window, tab-strip app to cover edge cases.
+    auto* web_contents = LaunchApp(kAppTypeMultiWindowTabStrip);
+    auto menu = CreateContextMenu(web_contents, kWebUrl);
+    EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+    EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD));
+    EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKBOOKMARKAPP));
+  }
+}
+
 INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
     SystemWebAppManagerBrowserTest);
 
@@ -1558,4 +1698,7 @@
     SystemWebAppManagerDefaultBoundsTest);
 #endif
 
+INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
+    SystemWebAppManagerContextMenuBrowserTest);
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc
index b6ab0a8..d9709951 100644
--- a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc
+++ b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.cc
@@ -539,6 +539,91 @@
       new TestSystemWebAppInstallation(std::move(delegate)));
 }
 
+namespace {
+enum SystemWebAppWindowConfig {
+  SINGLE_WINDOW,
+  SINGLE_WINDOW_TAB_STRIP,
+  MULTI_WINDOW,
+  MULTI_WINDOW_TAB_STRIP,
+};
+
+std::unique_ptr<UnittestingSystemAppDelegate>
+CreateSystemAppDelegateWithWindowConfig(
+    const SystemAppType type,
+    const GURL& app_url,
+    SystemWebAppWindowConfig window_config) {
+  auto* delegate = new UnittestingSystemAppDelegate(
+      type, "Test App", app_url, base::BindLambdaForTesting([=]() {
+        auto info = std::make_unique<WebApplicationInfo>();
+        info->start_url = app_url;
+        info->scope = app_url.GetOrigin();
+        info->title = u"Test System App";
+        info->theme_color = 0xFF00FF00;
+        info->display_mode = blink::mojom::DisplayMode::kStandalone;
+        info->open_as_window = true;
+        return info;
+      }));
+
+  switch (window_config) {
+    case SystemWebAppWindowConfig::SINGLE_WINDOW:
+      delegate->SetShouldBeSingleWindow(true);
+      delegate->SetShouldHaveTabStrip(false);
+      break;
+    case SystemWebAppWindowConfig::SINGLE_WINDOW_TAB_STRIP:
+      delegate->SetShouldBeSingleWindow(true);
+      delegate->SetShouldHaveTabStrip(true);
+      break;
+    case SystemWebAppWindowConfig::MULTI_WINDOW:
+      delegate->SetShouldBeSingleWindow(false);
+      delegate->SetShouldHaveTabStrip(false);
+      break;
+    case SystemWebAppWindowConfig::MULTI_WINDOW_TAB_STRIP:
+      delegate->SetShouldBeSingleWindow(false);
+      delegate->SetShouldHaveTabStrip(true);
+      break;
+  }
+
+  return base::WrapUnique(delegate);
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<TestSystemWebAppInstallation>
+TestSystemWebAppInstallation::SetUpAppsForContestMenuTest() {
+  std::vector<std::unique_ptr<UnittestingSystemAppDelegate>> delegates;
+  delegates.emplace_back(CreateSystemAppDelegateWithWindowConfig(
+      SystemAppType::SETTINGS, GURL("chrome://single-window/pwa.html"),
+      SystemWebAppWindowConfig::SINGLE_WINDOW));
+
+  delegates.emplace_back(CreateSystemAppDelegateWithWindowConfig(
+      SystemAppType::FILE_MANAGER, GURL("chrome://multi-window/pwa.html"),
+      SystemWebAppWindowConfig::MULTI_WINDOW));
+
+  delegates.emplace_back(CreateSystemAppDelegateWithWindowConfig(
+      SystemAppType::MEDIA, GURL("chrome://single-window-tab-strip/pwa.html"),
+      SystemWebAppWindowConfig::SINGLE_WINDOW_TAB_STRIP));
+
+  delegates.emplace_back(CreateSystemAppDelegateWithWindowConfig(
+      SystemAppType::HELP, GURL("chrome://multi-window-tab-strip/pwa.html"),
+      SystemWebAppWindowConfig::MULTI_WINDOW_TAB_STRIP));
+  auto* installation =
+      new TestSystemWebAppInstallation(std::move(delegates[0]));
+
+  for (size_t i = 1; i < delegates.size(); ++i) {
+    auto& delegate = delegates[i];
+    installation->web_ui_controller_factories_.push_back(
+        std::make_unique<TestSystemWebAppWebUIControllerFactory>(
+            GetDataSourceNameFromSystemAppInstallUrl(
+                delegate->GetInstallUrl())));
+
+    installation->system_app_delegates_.insert_or_assign(delegate->GetType(),
+                                                         std::move(delegate));
+  }
+
+  return base::WrapUnique(installation);
+}
+
 std::unique_ptr<KeyedService>
 TestSystemWebAppInstallation::CreateWebAppProvider(
     UnittestingSystemAppDelegate* delegate,
diff --git a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h
index 370fd36..10f3710 100644
--- a/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h
+++ b/chrome/browser/web_applications/system_web_apps/test/test_system_web_app_installation.h
@@ -151,6 +151,16 @@
   static std::unique_ptr<TestSystemWebAppInstallation>
   SetUpAppWithNewWindowMenuItem();
 
+  // This creates 4 system web app types for testing context menu with
+  // different windowing options:
+  //
+  // - SETTINGS: Single Window, No TabStrip
+  // - FILE_MANAGER: Multi Window, No TabStrip
+  // - MEDIA: Single Window, TabStrip
+  // - HELP: Multi Window, TabStrip
+  static std::unique_ptr<TestSystemWebAppInstallation>
+  SetUpAppsForContestMenuTest();
+
   ~TestSystemWebAppInstallation();
 
   void WaitForAppInstall();
diff --git a/chrome/browser/web_applications/test/test_web_app_ui_manager.h b/chrome/browser/web_applications/test/test_web_app_ui_manager.h
index a46eddc..315ae7b8 100644
--- a/chrome/browser/web_applications/test/test_web_app_ui_manager.h
+++ b/chrome/browser/web_applications/test/test_web_app_ui_manager.h
@@ -47,16 +47,6 @@
                               bool shortcut_created) override;
   content::WebContents* NavigateExistingWindow(const AppId& app_id,
                                                const GURL& url) override;
-  void ShowWebAppIdentityUpdateDialog(
-      const std::string& app_id,
-      bool title_change,
-      bool icon_change,
-      const std::u16string& old_title,
-      const std::u16string& new_title,
-      const SkBitmap& old_icon,
-      const SkBitmap& new_icon,
-      content::WebContents* web_contents,
-      web_app::AppIdentityDialogCallback callback) override {}
 
  private:
   std::map<AppId, size_t> app_id_to_num_windows_map_;
diff --git a/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc b/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc
index 5044d775..eafe317 100644
--- a/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc
+++ b/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc
@@ -22,7 +22,7 @@
 namespace {
 
 void CheckFromValue(extensions::APIPermission* permission,
-                    base::ListValue* value,
+                    base::Value* value,
                     bool success_expected) {
   std::string error;
   std::vector<std::string> unhandled;
@@ -40,53 +40,53 @@
       permission_info->CreateAPIPermission());
 
   // access_type + all_detected
-  std::unique_ptr<base::ListValue> value(new base::ListValue());
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  CheckFromValue(permission.get(), value.get(), true);
+  base::Value value(base::Value::Type::LIST);
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  CheckFromValue(permission.get(), &value, true);
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  CheckFromValue(permission.get(), value.get(), true);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  CheckFromValue(permission.get(), &value, true);
 
   // all_detected
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  CheckFromValue(permission.get(), value.get(), true);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  CheckFromValue(permission.get(), &value, true);
 
   // access_type
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  CheckFromValue(permission.get(), value.get(), true);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  CheckFromValue(permission.get(), &value, true);
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  CheckFromValue(permission.get(), value.get(), true);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  CheckFromValue(permission.get(), &value, true);
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  CheckFromValue(permission.get(), value.get(), true);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  CheckFromValue(permission.get(), &value, true);
 
   // Repeats do not make a difference.
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  CheckFromValue(permission.get(), value.get(), true);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  CheckFromValue(permission.get(), &value, true);
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  CheckFromValue(permission.get(), value.get(), true);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  CheckFromValue(permission.get(), &value, true);
 }
 
 TEST(MediaGalleriesPermissionTest, BadValues) {
@@ -98,40 +98,40 @@
       permission_info->CreateAPIPermission());
 
   // copyTo and delete without read
-  std::unique_ptr<base::ListValue> value(new base::ListValue());
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  CheckFromValue(permission.get(), value.get(), false);
+  base::Value value(base::Value::Type::LIST);
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  CheckFromValue(permission.get(), &value, false);
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  CheckFromValue(permission.get(), value.get(), false);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  CheckFromValue(permission.get(), &value, false);
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  CheckFromValue(permission.get(), value.get(), false);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  CheckFromValue(permission.get(), &value, false);
 
   // copyTo without delete
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  CheckFromValue(permission.get(), value.get(), false);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  CheckFromValue(permission.get(), &value, false);
 
   // Repeats do not make a difference.
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  CheckFromValue(permission.get(), value.get(), false);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  CheckFromValue(permission.get(), &value, false);
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  CheckFromValue(permission.get(), value.get(), false);
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  CheckFromValue(permission.get(), &value, false);
 }
 
 TEST(MediaGalleriesPermissionTest, UnknownValues) {
@@ -145,29 +145,29 @@
       permission_info->CreateAPIPermission());
 
   // A good one and an unknown one.
-  std::unique_ptr<base::ListValue> value(new base::ListValue());
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString("Unknown");
-  EXPECT_TRUE(permission->FromValue(value.get(), &error, &unhandled));
+  base::Value value(base::Value::Type::LIST);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append("Unknown");
+  EXPECT_TRUE(permission->FromValue(&value, &error, &unhandled));
   EXPECT_TRUE(error.empty());
   EXPECT_EQ(1U, unhandled.size());
   error.clear();
   unhandled.clear();
 
   // Multiple unknown permissions.
-  value = std::make_unique<base::ListValue>();
-  value->AppendString("Unknown1");
-  value->AppendString("Unknown2");
-  EXPECT_TRUE(permission->FromValue(value.get(), &error, &unhandled));
+  value.ClearList();
+  value.Append("Unknown1");
+  value.Append("Unknown2");
+  EXPECT_TRUE(permission->FromValue(&value, &error, &unhandled));
   EXPECT_TRUE(error.empty());
   EXPECT_EQ(2U, unhandled.size());
   error.clear();
   unhandled.clear();
 
-  // Unnknown with a NULL argument.
-  value = std::make_unique<base::ListValue>();
-  value->AppendString("Unknown1");
-  EXPECT_FALSE(permission->FromValue(value.get(), &error, NULL));
+  // Unnknown with a nullptr argument.
+  value.ClearList();
+  value.Append("Unknown1");
+  EXPECT_FALSE(permission->FromValue(&value, &error, nullptr));
   EXPECT_FALSE(error.empty());
   error.clear();
 }
@@ -182,46 +182,46 @@
   std::unique_ptr<extensions::APIPermission> permission2(
       permission_info->CreateAPIPermission());
 
-  std::unique_ptr<base::ListValue> value(new base::ListValue());
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+  base::Value value(base::Value::Type::LIST);
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  ASSERT_TRUE(permission1->FromValue(&value, nullptr, nullptr));
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL));
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  ASSERT_TRUE(permission2->FromValue(&value, nullptr, nullptr));
   EXPECT_TRUE(permission1->Equal(permission2.get()));
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL));
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  ASSERT_TRUE(permission2->FromValue(&value, nullptr, nullptr));
   EXPECT_TRUE(permission1->Equal(permission2.get()));
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  ASSERT_TRUE(permission1->FromValue(&value, nullptr, nullptr));
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL));
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  ASSERT_TRUE(permission2->FromValue(&value, nullptr, nullptr));
   EXPECT_TRUE(permission1->Equal(permission2.get()));
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  ASSERT_TRUE(permission1->FromValue(&value, nullptr, nullptr));
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL));
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  ASSERT_TRUE(permission2->FromValue(&value, nullptr, nullptr));
   EXPECT_TRUE(permission1->Equal(permission2.get()));
 }
 
@@ -235,17 +235,17 @@
   std::unique_ptr<extensions::APIPermission> permission2(
       permission_info->CreateAPIPermission());
 
-  std::unique_ptr<base::ListValue> value(new base::ListValue());
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+  base::Value value(base::Value::Type::LIST);
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  ASSERT_TRUE(permission1->FromValue(&value, nullptr, nullptr));
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL));
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  ASSERT_TRUE(permission2->FromValue(&value, nullptr, nullptr));
   EXPECT_FALSE(permission1->Equal(permission2.get()));
 }
 
@@ -259,44 +259,44 @@
   std::unique_ptr<extensions::APIPermission> permission2(
       permission_info->CreateAPIPermission());
 
-  std::unique_ptr<base::ListValue> value(new base::ListValue());
-  value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+  base::Value value(base::Value::Type::LIST);
+  value.Append(MediaGalleriesPermission::kAllAutoDetectedPermission);
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  ASSERT_TRUE(permission1->FromValue(&value, nullptr, nullptr));
 
   std::unique_ptr<base::Value> vtmp(permission1->ToValue());
   ASSERT_TRUE(vtmp);
-  ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL));
+  ASSERT_TRUE(permission2->FromValue(vtmp.get(), nullptr, nullptr));
   EXPECT_TRUE(permission1->Equal(permission2.get()));
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  value->AppendString(MediaGalleriesPermission::kCopyToPermission);
-  ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  value.Append(MediaGalleriesPermission::kCopyToPermission);
+  ASSERT_TRUE(permission1->FromValue(&value, nullptr, nullptr));
 
   vtmp = permission1->ToValue();
   ASSERT_TRUE(vtmp);
-  ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL));
+  ASSERT_TRUE(permission2->FromValue(vtmp.get(), nullptr, nullptr));
   EXPECT_TRUE(permission1->Equal(permission2.get()));
 
-  value = std::make_unique<base::ListValue>();
-  value->AppendString(MediaGalleriesPermission::kReadPermission);
-  value->AppendString(MediaGalleriesPermission::kDeletePermission);
-  ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+  value.ClearList();
+  value.Append(MediaGalleriesPermission::kReadPermission);
+  value.Append(MediaGalleriesPermission::kDeletePermission);
+  ASSERT_TRUE(permission1->FromValue(&value, nullptr, nullptr));
 
   vtmp = permission1->ToValue();
   ASSERT_TRUE(vtmp);
-  ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL));
+  ASSERT_TRUE(permission2->FromValue(vtmp.get(), nullptr, nullptr));
   EXPECT_TRUE(permission1->Equal(permission2.get()));
 
-  value = std::make_unique<base::ListValue>();
+  value.ClearList();
   // without sub-permission
-  ASSERT_TRUE(permission1->FromValue(NULL, NULL, NULL));
+  ASSERT_TRUE(permission1->FromValue(nullptr, nullptr, nullptr));
 
   vtmp = permission1->ToValue();
   ASSERT_TRUE(vtmp);
-  ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL));
+  ASSERT_TRUE(permission2->FromValue(vtmp.get(), nullptr, nullptr));
   EXPECT_TRUE(permission1->Equal(permission2.get()));
 }
 
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 517f82e..04f9960 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -98,7 +98,6 @@
 
 const char kInitialProfile[] = "Default";
 const char kMultiProfileDirPrefix[] = "Profile ";
-const char kEphemeralGuestProfileDirPrefix[] = "Guest ";
 const base::FilePath::CharType kGuestProfileDir[] = FPL("Guest Profile");
 const base::FilePath::CharType kSystemProfileDir[] = FPL("System Profile");
 
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index 875b594..05e6d59 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -36,7 +36,6 @@
 
 extern const char kInitialProfile[];
 extern const char kMultiProfileDirPrefix[];
-extern const char kEphemeralGuestProfileDirPrefix[];
 extern const base::FilePath::CharType kGuestProfileDir[];
 extern const base::FilePath::CharType kSystemProfileDir[];
 
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 2342557..bc031fe 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -762,10 +762,6 @@
       "chrome://settings/*"
     ]
   }],
-  "autofillAssistantPrivate": {
-    "dependencies": ["permission:autofillAssistantPrivate"],
-    "contexts": ["blessed_extension"]
-  },
   "signedInDevices": {
     "dependencies": ["permission:signedInDevices"],
     "contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index b17207e..fc1d235c 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -801,16 +801,6 @@
       "A9A9FC0228ADF541F0334F22BEFB8F9C245B21D7"   // https://crbug.com/839189
     ]
   }],
-  "autofillAssistantPrivate": {
-    "channel": "trunk",
-    "extension_types": ["extension"],
-    "location": "component",
-    "allowlist": [
-      // api_test extension "jjeoclcdfjddkdjokiejckgcildcflpp"
-      // https://crbug.com/1015753
-      "64B58C7B53E3E1447FD0DEA62C5E654206179F99"
-    ]
-  },
   "signedInDevices": {
     "channel": "dev",
     "extension_types": ["extension", "legacy_packaged_app", "platform_app"]
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni
index 9894d40..15312b4 100644
--- a/chrome/common/extensions/api/api_sources.gni
+++ b/chrome/common/extensions/api/api_sources.gni
@@ -124,10 +124,6 @@
   schema_sources_ += [ "mdns.idl" ]
 }
 
-if (enable_autofill_assistant_api) {
-  schema_sources_ += [ "autofill_assistant_private.idl" ]
-}
-
 uncompiled_sources_ = [
   "action.json",
   "browser_action.json",
diff --git a/chrome/common/extensions/api/autofill_assistant_private.idl b/chrome/common/extensions/api/autofill_assistant_private.idl
deleted file mode 100644
index 95a2492..0000000
--- a/chrome/common/extensions/api/autofill_assistant_private.idl
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2020 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.
-
-// Use the <code>chrome.autofillAssistantPrivate</code> API to interact with
-// the Autofill Assistant execution engine. Access is restricted to a set of
-// extensions part of an allowlist.
-//
-// The correct usage of this API is to to first call <code>create</code>, then
-// add listeners for the Events and then call <code>start</code>.
-// <code>onActionsChanged</code> will be called when actions become available
-// and can be executed via <code>performAction</code>.
-namespace autofillAssistantPrivate {
-  // Success or error of a function call will be communicated by setting
-  // $(ref:runtime.lastError).
-  callback VoidCallback = void ();
-
-  dictionary ActionObject {
-    // The name for the action.
-    DOMString name;
-
-    // |onActionsChanged| returns an array of ActionObjects. |index|
-    // corresponds to the position in that array and is also the index to be
-    // passed to |performAction|.
-    long index;
-  };
-
-  interface Functions {
-    // Creates the autofill assistant controller and cleans up and existing
-    // controller if applicable.
-    static void create(optional VoidCallback callback);
-
-    // Starts the controller with the given parameters.
-    static void start(any parameters, optional VoidCallback callback);
-
-    // Performs an action.
-    // |index|: The index into the |actions| array provided by
-    //          |onActionsChanged|.
-    static void performAction(
-        long index, optional VoidCallback callback);
-
-    // Set user data to configure collect data actions.
-    static void provideUserData(optional VoidCallback callback);
-  };
-
-  interface Events {
-    // Fires when the status message changed.
-    //
-    // |message| The new status of the autofill assistant controller.
-    static void onStatusMessageChanged(DOMString message);
-
-    // Fires when a set of actions has changed.
-    //
-    // |actions| The new list of available actions.
-    static void onActionsChanged(ActionObject[] actions);
-  };
-};
diff --git a/chrome/common/extensions/api/users_private.idl b/chrome/common/extensions/api/users_private.idl
index eb9a380d..ce7ad818 100644
--- a/chrome/common/extensions/api/users_private.idl
+++ b/chrome/common/extensions/api/users_private.idl
@@ -20,9 +20,6 @@
     // Whether this user is the device owner.
     boolean isOwner;
 
-    // Whether this user is supervised.
-    boolean isSupervised;
-
     // Whether this user is Child.
     boolean isChild;
   };
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index 815285a1..130b920 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -189,8 +189,6 @@
      APIPermissionInfo::kFlagCannotBeOptional},
     {APIPermissionID::kSettingsPrivate, "settingsPrivate",
      APIPermissionInfo::kFlagCannotBeOptional},
-    {APIPermissionID::kAutofillAssistantPrivate, "autofillAssistantPrivate",
-     APIPermissionInfo::kFlagCannotBeOptional},
     {APIPermissionID::kAutofillPrivate, "autofillPrivate",
      APIPermissionInfo::kFlagCannotBeOptional},
     {APIPermissionID::kPasswordsPrivate, "passwordsPrivate",
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 6b3aef5..c1e3ee9 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -814,7 +814,6 @@
   skip.insert(APIPermissionID::kAccessibilityPrivate);
   skip.insert(APIPermissionID::kArcAppsPrivate);
   skip.insert(APIPermissionID::kAutoTestPrivate);
-  skip.insert(APIPermissionID::kAutofillAssistantPrivate);
   skip.insert(APIPermissionID::kBookmarkManagerPrivate);
   skip.insert(APIPermissionID::kBrailleDisplayPrivate);
   skip.insert(APIPermissionID::kCecPrivate);
diff --git a/chrome/services/keymaster/public/mojom/cert_store.mojom b/chrome/services/keymaster/public/mojom/cert_store.mojom
index 6339c7b7..15c2f4d 100644
--- a/chrome/services/keymaster/public/mojom/cert_store.mojom
+++ b/chrome/services/keymaster/public/mojom/cert_store.mojom
@@ -33,10 +33,25 @@
   kUnsupportedAlgorithm,
 };
 
-// Metadata to uniquely identify a Chaps key.
+// The possible chaps slots relevant for arc-keymaster. Note this does NOT map
+// to the PKCS#11 CK_SLOT_ID, but rather to an abstract representation of the
+// value. The corresponding CK_SLOT_ID must be queried from cryptohome.
+[Extensible]
+enum ChapsSlot {
+  // The key is stored in the user slot.
+  [Default] kUser,
+  // The key is stored in the system slot.
+  kSystem,
+};
+
+// Metadata to uniquely identify a chaps key.
 struct ChapsKeyData {
+  // Maps to the CKA_LABEL of the CKO_PRIVATE_KEY in PKCS#11.
   string label;
+  // Maps to the CKA_ID of the CKO_PRIVATE_KEY in PKCS#11.
   string id;
+  // The slot where this key is stored. Does NOT map to the PKCS#11 CK_SLOT_ID.
+  [MinVersion=1] ChapsSlot slot;
 };
 
 // Union of Chrome OS keys from different sources.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 2cc8830..143b418 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -209,6 +209,8 @@
     sources += [
       "../browser/banners/test_app_banner_manager_desktop.cc",
       "../browser/banners/test_app_banner_manager_desktop.h",
+      "../browser/renderer_context_menu/render_view_context_menu_test_util.cc",
+      "../browser/renderer_context_menu/render_view_context_menu_test_util.h",
       "../browser/themes/test/theme_service_changed_waiter.cc",
       "../browser/themes/test/theme_service_changed_waiter.h",
     ]
@@ -230,6 +232,7 @@
 
   deps = [
     "//build:chromeos_buildflags",
+    "//chrome/app:command_ids",
     "//chrome/common/search:mojo_bindings",
     "//components/safe_browsing/content/renderer/phishing_classifier:unit_tests_support",
     "//components/security_interstitials/content:security_interstitial_page",
@@ -1723,8 +1726,6 @@
       "../browser/renderer_context_menu/render_view_context_menu_browsertest.cc",
       "../browser/renderer_context_menu/render_view_context_menu_browsertest_util.cc",
       "../browser/renderer_context_menu/render_view_context_menu_browsertest_util.h",
-      "../browser/renderer_context_menu/render_view_context_menu_test_util.cc",
-      "../browser/renderer_context_menu/render_view_context_menu_test_util.h",
       "../browser/renderer_context_menu/spelling_bubble_model_browsertest.cc",
       "../browser/renderer_context_menu/spelling_menu_observer_browsertest.cc",
       "../browser/renderer_host/render_process_host_chrome_browsertest.cc",
@@ -2746,10 +2747,6 @@
         "../browser/ui/web_applications/test/web_app_navigation_browsertest.h",
       ]
 
-      if (enable_autofill_assistant_api) {
-        sources += [ "../browser/extensions/api/autofill_assistant_private/autofill_assistant_private_apitest.cc" ]
-      }
-
       if (enable_background_mode) {
         sources += [ "../browser/extensions/background_app_browsertest.cc" ]
       }
@@ -2820,12 +2817,6 @@
         "//extensions/common/api",
       ]
 
-      if (enable_autofill_assistant_api) {
-        deps += [
-          "//components/autofill_assistant/browser:extensions_test_support",
-        ]
-      }
-
       data += [
         "//chrome/test/data/extensions/",
         "//extensions/test/data/",
@@ -3136,7 +3127,6 @@
         "../browser/ash/login/login_screen_policy_browsertest.cc",
         "../browser/ash/login/login_ui_browsertest.cc",
         "../browser/ash/login/login_ui_keyboard_browsertest.cc",
-        "../browser/ash/login/login_ui_remove_legacy_supervised_users_browsertest.cc",
         "../browser/ash/login/login_ui_shelf_visibility_browsertest.cc",
         "../browser/ash/login/login_utils_browsertest.cc",
         "../browser/ash/login/oobe_browsertest.cc",
@@ -3444,6 +3434,7 @@
         "../browser/ui/views/crostini/crostini_package_install_failure_view_browsertest.cc",
         "../browser/ui/views/crostini/crostini_recovery_view_browsertest.cc",
         "../browser/ui/views/crostini/crostini_uninstaller_view_browsertest.cc",
+        "../browser/ui/views/crostini/crostini_update_component_view_browsertest.cc",
         "../browser/ui/views/crostini/crostini_update_filesystem_view_browsertest.cc",
         "../browser/ui/views/extensions/extension_dialog_bounds_browsertest.cc",
         "../browser/ui/views/frame/browser_frame_ash_browsertest.cc",
@@ -5657,7 +5648,6 @@
       "../browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller_unittest.cc",
       "../browser/ui/passwords/bubble_controllers/save_unsynced_credentials_locally_bubble_controller_unittest.cc",
       "../browser/ui/passwords/bubble_controllers/save_update_with_account_store_bubble_controller_unittest.cc",
-      "../browser/ui/passwords/bubble_controllers/sign_in_promo_bubble_controller_unittest.cc",
       "../browser/ui/passwords/credential_leak_dialog_controller_impl_unittest.cc",
       "../browser/ui/passwords/credential_manager_dialog_controller_impl_unittest.cc",
       "../browser/ui/qrcode_generator/qrcode_generator_bubble_controller_unittest.cc",
@@ -6639,10 +6629,6 @@
       ]
     }
 
-    if (enable_autofill_assistant_api) {
-      sources += [ "../browser/extensions/api/autofill_assistant_private/extension_access_token_fetcher_unittest.cc" ]
-    }
-
     allow_circular_includes_from = [
       "//chrome/browser/web_applications:web_applications_unit_tests",
       "//chrome/browser/web_applications/extensions:unit_tests",
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 2087c68..6823069 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -191,13 +191,6 @@
 const char TestingProfile::kTestUserProfileDir[] = "Default";
 #endif
 
-// static
-bool TestingProfile::SetScopedFeatureListForEphemeralGuestProfiles(
-    base::test::ScopedFeatureList& scoped_feature_list,
-    bool enabled) {
-  return false;
-}
-
 TestingProfile::TestingProfile() : TestingProfile(base::FilePath()) {}
 
 TestingProfile::TestingProfile(const base::FilePath& path)
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index c6f1fa2..4bf3966 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -88,16 +88,6 @@
   // always "Default", because they are runnining without logged-in user.
   static const char kTestUserProfileDir[];
 
-  // Sets the feature list to enable/disable ephemeral Guest profiles.
-  // Returns true if ephemeral Guest profiles are supported on the platform and
-  // feature list is initialized.
-  // NOTE: Ephemeral Guest profiles are deprecated and code support is under
-  // removal. This function always returns false.
-  // TODO(https://crbug.com/1225156): Delete this function.
-  static bool SetScopedFeatureListForEphemeralGuestProfiles(
-      base::test::ScopedFeatureList& scoped_feature_list,
-      bool enabled);
-
   // Default constructor that cannot be used with multi-profiles.
   TestingProfile();
 
diff --git a/chrome/test/data/extensions/api_test/autofill_assistant_private/manifest.json b/chrome/test/data/extensions/api_test/autofill_assistant_private/manifest.json
deleted file mode 100644
index 64fea7f..0000000
--- a/chrome/test/data/extensions/api_test/autofill_assistant_private/manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "name": "autofillAssistantPrivate API interface test",
-  "version": "1.0",
-  "manifest_version": 2,
-  "background": {
-    "scripts": ["test.js"]
-  },
-  "permissions": ["autofillAssistantPrivate"],
-  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+uU63MD6T82Ldq5wjrDFn5mGmPnnnjWZBWxYXfpG4kVf0s+p24VkXwTXsxeI12bRm8/ft9sOq0XiLfgQEh5JrVUZqvFlaZYoS+giZfUqzKFGMLa4uiSMDnvv+byxrqAepKz5G8XX/q5Wm5cvpdjwgiu9z9iM768xJy+Ca/G5qQwIDAQAB"
-}
diff --git a/chrome/test/data/extensions/api_test/autofill_assistant_private/test.js b/chrome/test/data/extensions/api_test/autofill_assistant_private/test.js
deleted file mode 100644
index 3c7590f..0000000
--- a/chrome/test/data/extensions/api_test/autofill_assistant_private/test.js
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2020 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.
-
-const expectedMessages = ['Opening version…', 'This is a test status.'];
-
-function actionsChangedListener(actions) {
-  chrome.test.assertEq(2, actions.length);
-  chrome.test.assertEq('Action 0', actions[0].name);
-  chrome.test.assertEq(0, actions[0].index);
-  chrome.test.assertEq('Action 1', actions[1].name);
-  chrome.test.assertEq(1, actions[1].index);
-
-  // Now we trigger 'Action 1' and expect the status message to change.
-  chrome.autofillAssistantPrivate.performAction(1);
-
-  // Ignore subsequent updates since they just mean a script got started and the
-  // available scripts reset to the empty list.
-  chrome.autofillAssistantPrivate.onActionsChanged.removeListener(
-      actionsChangedListener);
-}
-
-let messageCount = 0;
-function setStatusMessage(message) {
-  chrome.test.assertEq(expectedMessages[messageCount++], message);
-
-  // Everything worked as expected, notify the test infra.
-  if (messageCount >= 2)
-    chrome.test.succeed();
-}
-
-function testNoController() {
-  chrome.autofillAssistantPrivate.start({}, () => {
-    chrome.test.assertLastError('Starting requires a valid controller!');
-    chrome.autofillAssistantPrivate.performAction(0, () => {
-      chrome.test.assertLastError('performAction requires a valid controller!');
-      chrome.test.succeed();
-    });
-  });
-}
-
-function testNormalFlow() {
-  messageCount = 0;
-  chrome.autofillAssistantPrivate.create();
-
-  // Add listeners.
-  chrome.autofillAssistantPrivate.onActionsChanged.addListener(
-      actionsChangedListener);
-  chrome.autofillAssistantPrivate.onStatusMessageChanged.addListener(
-      setStatusMessage);
-
-  chrome.autofillAssistantPrivate.start({}, () => {
-    chrome.test.assertNoLastError();
-  });
-}
-
-chrome.test.runTests([testNoController, testNormalFlow]);
diff --git a/chrome/test/data/webui/settings/basic_page_test.js b/chrome/test/data/webui/settings/basic_page_test.js
index 7f57821..2fe038c5 100644
--- a/chrome/test/data/webui/settings/basic_page_test.js
+++ b/chrome/test/data/webui/settings/basic_page_test.js
@@ -104,6 +104,18 @@
     }
   }
 
+  /** @param {string} section */
+  function assertActiveSubpage(section) {
+    // Check that only the subpage of the |active| section is visible.
+    const settingsPages = page.shadowRoot.querySelectorAll(
+        `settings-section[active] settings-${section}-page`);
+    assertEquals(1, settingsPages.length);
+    const subpages =
+        settingsPages[0].shadowRoot.querySelectorAll('settings-subpage');
+    assertEquals(1, subpages.length);
+    assertTrue(isVisible(subpages[0]));
+  }
+
   test('OnlyOneSectionShown', async () => {
     // RouteState.INITIAL -> RoutState.TOP_LEVEL
     // Check that only one is marked as |active|.
@@ -152,7 +164,7 @@
     Router.getInstance().navigateTo(routes.FONTS);
     await whenDone;
     await flushTasks();
-    assertActiveSection(routes.APPEARANCE.section);
+    assertActiveSubpage(routes.APPEARANCE.section);
     assertTrue(!!getCardElement());
     assertFalse(!!getDefault());
     assertTrue(!!getSubpage());
diff --git a/chrome/test/data/webui/settings/chromeos/input_page_test.js b/chrome/test/data/webui/settings/chromeos/input_page_test.js
index ae4a27a..0ca8afac 100644
--- a/chrome/test/data/webui/settings/chromeos/input_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/input_page_test.js
@@ -497,7 +497,7 @@
 
       Polymer.dom.flush();
       // spell check is initially on
-      spellCheckToggle = inputPage.$.enableSpellcheckingToggle;
+      spellCheckToggle = inputPage.$$('#enableSpellcheckingToggle');
       assertTrue(!!spellCheckToggle);
       assertTrue(spellCheckToggle.checked);
 
@@ -819,11 +819,14 @@
       inputPage.languageSettingsV2Update2Enabled_ = true;
       // However, we should still set loadTimeData as some other code may use
       // it (such as languages.js).
-      loadTimeData.overrideValues({enableLanguageSettingsV2Update2: true});
+      loadTimeData.overrideValues({
+        enableLanguageSettingsV2Update2: true,
+        onDeviceGrammarCheckEnabled: true,
+      });
       Polymer.dom.flush();
 
       // Spell check is initially on.
-      spellCheckToggle = inputPage.$.enableSpellcheckingToggle;
+      spellCheckToggle = inputPage.$$('#enableSpellcheckingToggle');
       assertTrue(!!spellCheckToggle);
       assertTrue(spellCheckToggle.checked);
 
@@ -1153,15 +1156,6 @@
       assertTrue(retryButtons[0].hidden);
     });
 
-    test('toggle off disables enhanced spell check', () => {
-      const enhancedSpellCheckToggle =
-          inputPage.$$('#enhancedSpellCheckToggle');
-      assertFalse(enhancedSpellCheckToggle.disabled);
-      spellCheckToggle.click();
-
-      assertTrue(enhancedSpellCheckToggle.disabled);
-    });
-
     test('toggle off disables edit dictionary', () => {
       const editDictionarySubpageTrigger =
           inputPage.$$('#editDictionarySubpageTrigger');
diff --git a/chrome/test/data/webui/settings/chromeos/user_page_tests.js b/chrome/test/data/webui/settings/chromeos/user_page_tests.js
index 44dc761..9f925dd 100644
--- a/chrome/test/data/webui/settings/chromeos/user_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/user_page_tests.js
@@ -21,7 +21,6 @@
     displayEmail: 'test@gmail.com',
     name: 'test',
     isOwner: false,
-    isSupervised: false,
     isChild: false
   },
   {
@@ -29,7 +28,6 @@
     displayEmail: 'test1@gmail.com',
     name: 'test1',
     isOwner: false,
-    isSupervised: false,
     isChild: false
   },
   {
@@ -37,7 +35,6 @@
     displayEmail: 'test2@gmail.com',
     name: 'test2',
     isOwner: false,
-    isSupervised: false,
     isChild: false
   },
   {
@@ -45,7 +42,6 @@
     displayEmail: 'owner@gmail.com',
     name: 'owner',
     isOwner: true,
-    isSupervised: false,
     isChild: false
   }
 ];
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index eda5bd2..c0ae1758 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-14083.0.0
\ No newline at end of file
+14085.0.0
\ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources.h b/chromeos/components/camera_app_ui/resources.h
index f06bc73..8428aff 100644
--- a/chromeos/components/camera_app_ui/resources.h
+++ b/chromeos/components/camera_app_ui/resources.h
@@ -75,7 +75,9 @@
     {"label_grid_golden", IDS_LABEL_GRID_GOLDEN},
     {"label_new_control_toast", IDS_LABEL_NEW_CONTROL_TOAST},
     {"label_photo_resolution", IDS_LABEL_PHOTO_RESOLUTION},
+    {"label_scan_qrcode_option", IDS_LABEL_SCAN_QRCODE_OPTION},
     {"label_switch_record_video_button", IDS_LABEL_SWITCH_RECORD_VIDEO_BUTTON},
+    {"label_switch_scanner_mode_button", IDS_LABEL_SWITCH_SCANNER_MODE_BUTTON},
     {"label_switch_take_photo_button", IDS_LABEL_SWITCH_TAKE_PHOTO_BUTTON},
     {"label_switch_take_portrait_bokeh_photo_button",
      IDS_LABEL_SWITCH_TAKE_PORTRAIT_BOKEH_PHOTO_BUTTON},
@@ -99,6 +101,7 @@
     {"record_video_resume_button", IDS_RECORD_VIDEO_RESUME_BUTTON},
     {"record_video_start_button", IDS_RECORD_VIDEO_START_BUTTON},
     {"record_video_stop_button", IDS_RECORD_VIDEO_STOP_BUTTON},
+    {"scan_qrcode_option", IDS_SCAN_QRCODE_OPTION},
     {"settings_button", IDS_SETTINGS_BUTTON},
     {"snackbar_link_copied", IDS_SNACKBAR_LINK_COPIED},
     {"snackbar_text_copied", IDS_SNACKBAR_TEXT_COPIED},
@@ -108,6 +111,7 @@
     {"status_msg_recording_stopped", IDS_STATUS_MSG_RECORDING_STOPPED},
     {"switch_camera_button", IDS_SWITCH_CAMERA_BUTTON},
     {"switch_record_video_button", IDS_SWITCH_RECORD_VIDEO_BUTTON},
+    {"switch_scanner_mode_button", IDS_SWITCH_SCANNER_MODE_BUTTON},
     {"switch_take_photo_button", IDS_SWITCH_TAKE_PHOTO_BUTTON},
     {"switch_take_portrait_bokeh_photo_button",
      IDS_SWITCH_TAKE_PORTRAIT_BOKEH_PHOTO_BUTTON},
diff --git a/chromeos/components/camera_app_ui/resources/css/main.css b/chromeos/components/camera_app_ui/resources/css/main.css
index 2f7e4992..ce8e155 100644
--- a/chromeos/components/camera_app_ui/resources/css/main.css
+++ b/chromeos/components/camera_app_ui/resources/css/main.css
@@ -532,7 +532,6 @@
 }
 
 body:not(.video) #toggle-mic,
-body:not(.photo) #toggle-barcode,
 body:not(.multi-camera) #switch-device {
   visibility: hidden;
 }
@@ -683,16 +682,6 @@
   background-image: url(/images/camera_button_mic_off.svg);
 }
 
-#toggle-barcode:checked {
-  background: url(/images/barcode_toggle_on.svg) center no-repeat,
-              rgba(var(--blue-300-rgb), 0.3);
-}
-
-#toggle-barcode {
-  background-image: url(/images/barcode_toggle_off.svg);
-  border-radius: 50%;
-}
-
 body:not(.multi-fps) #toggle-fps,
 body:not(.video) #toggle-fps {
   display: none;
@@ -940,7 +929,6 @@
 body:not(.streaming) #options-group,
 body:not(.streaming) #preview-focus,
 body:not(.streaming) #preview-grid,
-body:not(.streaming) #toggle-barcode,
 body:not(.streaming) #toggle-mic {
   visibility: hidden;
 }
@@ -1527,224 +1515,6 @@
   visibility: visible;
 }
 
-/* The container of scan box for layout and positioning. */
-.barcode-scan-box {
-  --border-distance: 8px;
-  --border-width: 4px;
-  --inner-border-radius: 16px;
-  opacity: 0;
-  /* Use padding-top instead of height to make a responsive square, since the
-   * percentage in padding-top is relative to the width of the containing
-   * block. */
-  padding-top: calc(100% / 2);
-  transition: all var(--exit-easing) var(--moderate1-duration);
-  visibility: hidden;
-  width: calc(100% / 2);
-}
-
-body.photo.scan-barcode .barcode-scan-box {
-  opacity: 1;
-  padding-top: calc(100% / 3);
-  transition: all var(--enter-easing) var(--moderate1-duration);
-  visibility: visible;
-  width: calc(100% / 3);
-}
-
-/* The inner scan box with a translucent overlay. */
-.barcode-scan-box::before {
-  --offset: calc(var(--border-width) + var(--border-distance));
-  border-radius: var(--inner-border-radius);
-  bottom: var(--offset);
-  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.6);
-  content: '';
-  left: var(--offset);
-  position: absolute;
-  right: var(--offset);
-  top: var(--offset);
-  z-index: -1;  /* This need to be lower than the corner borders */
-}
-
-/* The corner borders of the scan box. */
-.barcode-scan-box::after {
-  -webkit-mask: url(/images/barcode_scan_box_border_mask.svg);
-  border: var(--border-width) solid white;
-  border-radius: calc(var(--inner-border-radius) + var(--border-distance));
-  box-sizing: border-box;
-  content: '';
-  height: 100%;
-  left: 0;
-  position: absolute;
-  top: 0;
-  width: 100%;
-}
-
-/* TODO(b/172879638): Tune the position and layout after we finalized the
- * responsive window design. */
-.barcode-chip-container {
-  --chip-height: 32px;
-  --chip-max-width: 420px;
-  --min-scanbox-distance: 40px;
-  --text-expand-button-height: 40px;
-  --text-line-height: 24px;
-  --text-padding-vertical: 8px;
-  /* Avoid collision with scan-box and preview-box */
-  --top: max(8px, min(10%, 33.33% - var(--text-line-height) -
-      var(--text-expand-button-height) - 2 * var(--text-padding-vertical) -
-      var(--min-scanbox-distance)));
-
-  left: 50%;
-  max-width: min(80%, var(--chip-max-width));
-  opacity: 1;
-  pointer-events: auto;
-  position: absolute;
-  top: var(--top);
-  transform: translateX(-50%);
-  transition: opacity var(--fast2-duration) linear,
-              top var(--fast2-duration) var(--standard-easing);
-  z-index: 50;
-}
-
-.barcode-chip-container.invisible {
-  opacity: 0;
-  top: calc(var(--top) + 2px);
-  transition: opacity var(--fast2-duration) linear,
-              top var(--fast2-duration) var(--standard-easing),
-              visibility 0s var(--fast2-duration);
-}
-
-.barcode-chip-url {
-  align-items: center;
-  background: var(--grey-900);
-  border-radius: 16px;
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 4px 8px rgba(0, 0, 0, 0.15);
-  box-sizing: border-box;
-  display: flex;
-  font: 400 15px Roboto;
-  height: var(--chip-height);
-  padding: 8px;
-}
-
-.barcode-chip-url::before {
-  background: url(/images/barcode_url.svg) no-repeat;
-  content: '';
-  display: inline-block;
-  flex-shrink: 0;
-  height: 20px;
-  margin-inline-end: 6px;
-  vertical-align: middle;
-  width: 20px;
-}
-
-.barcode-chip-url > a {
-  color: var(--blue-300);
-  overflow: hidden;
-  text-decoration: none;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.barcode-chip-url > a:focus {
-  outline: none;
-}
-
-.barcode-copy-button:hover {
-  /* TODO(b/172879638): Tweak color according to the final UX spec */
-  background: url(/images/barcode_copy.svg) center no-repeat, rgb(50, 51, 54);
-}
-
-.barcode-copy-button {
-  background: url(/images/barcode_copy.svg) center no-repeat, var(--grey-900);
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 4px 8px rgba(0, 0, 0, 0.15);
-  cursor: pointer;
-  height: var(--chip-height);
-  inset-inline-start: calc(100% + 8px);
-  position: absolute;
-  top: 0;
-  width: var(--chip-height);
-  z-index: 50;
-}
-
-.barcode-chip-text {
-  align-items: center;
-  background: var(--grey-900);
-  border-radius: 4px;
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 4px 8px rgba(0, 0, 0, 0.15);
-  box-sizing: border-box;
-  display: flex;
-  flex-direction: column;
-  font: 400 15px Roboto;
-  padding: var(--text-padding-vertical) 20px;
-}
-
-#barcode-chip-text-content {
-  color: var(--grey-200);
-  line-height: var(--text-line-height);
-  max-width: 100%;
-  overflow: hidden;
-  text-decoration: none;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.expanded #barcode-chip-text-content {
-  /* TODO(b/172879638): Make this responsive */
-  max-height: calc(var(--text-line-height) * 10);
-  white-space: normal;
-  /* Keep the same width as before to avoid text jumping. */
-  width: var(--chip-max-width);
-}
-
-#barcode-chip-text-expand {
-  background: url(/images/barcode_chevron_down.svg) center no-repeat;
-  height: var(--text-expand-button-height);
-  width: 100%;
-}
-
-.expanded #barcode-chip-text-expand {
-  background: url(/images/barcode_chevron_up.svg) center no-repeat;
-}
-
-.snackbar {
-  align-items: center;
-  background: var(--grey-900);
-  border-radius: 4px;
-  bottom: 4px;
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 4px 8px rgba(0, 0, 0, 0.15);
-  box-sizing: border-box;
-  color: var(--grey-200);
-  display: flex;
-  font-family: Roboto;
-  font-size: 13px;
-  height: 48px;
-  left: 4px;
-  opacity: 0;
-  padding: 14px 16px;
-  position: absolute;
-  width: 256px;
-  z-index: 50;
-}
-
-.snackbar.animate {
-  animation: 3s show-snackbar linear;
-}
-
-@keyframes show-snackbar {
-  0% {
-    opacity: 0;
-  }
-  /* 100ms fade-in */
-  3.33% {
-    opacity: 1;
-  }
-  97.33% {
-    opacity: 1;
-  }
-  /* 80ms fade-out */
-  100% {
-    opacity: 0;
-  }
-}
-
 .hidden {
   display: none;
 }
diff --git a/chromeos/components/camera_app_ui/resources/css/scanner.css b/chromeos/components/camera_app_ui/resources/css/scanner.css
index 96b2894..5879916 100644
--- a/chromeos/components/camera_app_ui/resources/css/scanner.css
+++ b/chromeos/components/camera_app_ui/resources/css/scanner.css
@@ -6,3 +6,283 @@
   display: none;
 }
 
+body:is(.show-scanner-mode, :not(.streaming), :not(.photo)) #toggle-barcode {
+  display: none;
+}
+
+body:is(:not(.show-scanner-mode), :not(.scanner), :not(.streaming)) #scanner-modes-group {
+  display: none;
+}
+
+body.scanner.scan-barcode #shutters-group {
+  display: none;
+}
+
+body.scanner.scan-barcode #toggle-timer {
+  display: none;
+}
+
+#toggle-barcode:checked {
+  background: url(/images/barcode_toggle_on.svg) center no-repeat,
+              rgba(var(--blue-300-rgb), 0.3);
+}
+
+#toggle-barcode {
+  background-image: url(/images/barcode_toggle_off.svg);
+  border-radius: 50%;
+}
+
+#scanner-modes-group {
+  background-color: rgba(var(--grey-900-rgb), 0.8);
+  border-radius: var(--border-radius-rounded-with-short-side);
+  bottom: 96px;
+  box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.3);
+  color: white;
+  display: flex;
+  left: 50%;
+  position: absolute;
+  transform: translateX(-50%);
+}
+
+.scanner-mode-item {
+  border-radius: var(--border-radius-rounded-with-short-side);
+  pointer-events: auto;
+  position: relative;
+}
+
+.scanner-mode-item > input {
+  height: 100%;
+  position: absolute;
+  width: 100%;
+  z-index: 1;
+}
+
+.scanner-mode-item > div.label {
+  border-radius: var(--border-radius-rounded-with-short-side);
+  line-height: 20px;
+  padding: 6px 16px;
+  size: 14px;
+  z-index: 0;
+}
+
+.scanner-mode-item input:checked + div.label {
+  background: rgb(26, 115, 232);
+}
+
+/* The container of scan box for layout and positioning. */
+.barcode-scan-box {
+  --border-distance: 8px;
+  --border-width: 4px;
+  --inner-border-radius: 16px;
+  opacity: 0;
+  /* Use padding-top instead of height to make a responsive square, since the
+   * percentage in padding-top is relative to the width of the containing
+   * block. */
+  padding-top: calc(100% / 2);
+  transition: all var(--exit-easing) var(--moderate1-duration);
+  visibility: hidden;
+  width: calc(100% / 2);
+}
+
+body.enable-scan-barcode .barcode-scan-box {
+  opacity: 1;
+  padding-top: calc(100% / 3);
+  transition: all var(--enter-easing) var(--moderate1-duration);
+  visibility: visible;
+  width: calc(100% / 3);
+}
+
+/* The inner scan box with a translucent overlay. */
+.barcode-scan-box::before {
+  --offset: calc(var(--border-width) + var(--border-distance));
+  border-radius: var(--inner-border-radius);
+  bottom: var(--offset);
+  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.6);
+  content: '';
+  left: var(--offset);
+  position: absolute;
+  right: var(--offset);
+  top: var(--offset);
+  z-index: -1;  /* This need to be lower than the corner borders */
+}
+
+/* The corner borders of the scan box. */
+.barcode-scan-box::after {
+  -webkit-mask: url(/images/barcode_scan_box_border_mask.svg);
+  border: var(--border-width) solid white;
+  border-radius: calc(var(--inner-border-radius) + var(--border-distance));
+  box-sizing: border-box;
+  content: '';
+  height: 100%;
+  left: 0;
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+
+/* TODO(b/172879638): Tune the position and layout after we finalized the
+ * responsive window design. */
+.barcode-chip-container {
+  --chip-height: 32px;
+  --chip-max-width: 420px;
+  --min-scanbox-distance: 40px;
+  --text-expand-button-height: 40px;
+  --text-line-height: 24px;
+  --text-padding-vertical: 8px;
+  /* Avoid collision with scan-box and preview-box */
+  --top: max(8px, min(10%, 33.33% - var(--text-line-height) -
+      var(--text-expand-button-height) - 2 * var(--text-padding-vertical) -
+      var(--min-scanbox-distance)));
+
+  left: 50%;
+  max-width: min(80%, var(--chip-max-width));
+  opacity: 1;
+  pointer-events: auto;
+  position: absolute;
+  top: var(--top);
+  transform: translateX(-50%);
+  transition: opacity var(--fast2-duration) linear,
+              top var(--fast2-duration) var(--standard-easing);
+  z-index: 50;
+}
+
+.barcode-chip-container.invisible {
+  opacity: 0;
+  top: calc(var(--top) + 2px);
+  transition: opacity var(--fast2-duration) linear,
+              top var(--fast2-duration) var(--standard-easing),
+              visibility 0s var(--fast2-duration);
+}
+
+.barcode-chip-url {
+  align-items: center;
+  background: var(--grey-900);
+  border-radius: 16px;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 4px 8px rgba(0, 0, 0, 0.15);
+  box-sizing: border-box;
+  display: flex;
+  font: 400 15px Roboto;
+  height: var(--chip-height);
+  padding: 8px;
+}
+
+.barcode-chip-url::before {
+  background: url(/images/barcode_url.svg) no-repeat;
+  content: '';
+  display: inline-block;
+  flex-shrink: 0;
+  height: 20px;
+  margin-inline-end: 6px;
+  vertical-align: middle;
+  width: 20px;
+}
+
+.barcode-chip-url > a {
+  color: var(--blue-300);
+  overflow: hidden;
+  text-decoration: none;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.barcode-chip-url > a:focus {
+  outline: none;
+}
+
+.barcode-copy-button:hover {
+  /* TODO(b/172879638): Tweak color according to the final UX spec */
+  background: url(/images/barcode_copy.svg) center no-repeat, rgb(50, 51, 54);
+}
+
+.barcode-copy-button {
+  background: url(/images/barcode_copy.svg) center no-repeat, var(--grey-900);
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 4px 8px rgba(0, 0, 0, 0.15);
+  cursor: pointer;
+  height: var(--chip-height);
+  inset-inline-start: calc(100% + 8px);
+  position: absolute;
+  top: 0;
+  width: var(--chip-height);
+  z-index: 50;
+}
+
+.barcode-chip-text {
+  align-items: center;
+  background: var(--grey-900);
+  border-radius: 4px;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 4px 8px rgba(0, 0, 0, 0.15);
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  font: 400 15px Roboto;
+  padding: var(--text-padding-vertical) 20px;
+}
+
+#barcode-chip-text-content {
+  color: var(--grey-200);
+  line-height: var(--text-line-height);
+  max-width: 100%;
+  overflow: hidden;
+  text-decoration: none;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.expanded #barcode-chip-text-content {
+  /* TODO(b/172879638): Make this responsive */
+  max-height: calc(var(--text-line-height) * 10);
+  white-space: normal;
+  /* Keep the same width as before to avoid text jumping. */
+  width: var(--chip-max-width);
+}
+
+#barcode-chip-text-expand {
+  background: url(/images/barcode_chevron_down.svg) center no-repeat;
+  height: var(--text-expand-button-height);
+  width: 100%;
+}
+
+.expanded #barcode-chip-text-expand {
+  background: url(/images/barcode_chevron_up.svg) center no-repeat;
+}
+
+.snackbar {
+  align-items: center;
+  background: var(--grey-900);
+  border-radius: 4px;
+  bottom: 4px;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 4px 8px rgba(0, 0, 0, 0.15);
+  box-sizing: border-box;
+  color: var(--grey-200);
+  display: flex;
+  font-family: Roboto;
+  font-size: 13px;
+  height: 48px;
+  left: 4px;
+  opacity: 0;
+  padding: 14px 16px;
+  position: absolute;
+  width: 256px;
+  z-index: 50;
+}
+
+.snackbar.animate {
+  animation: 3s show-snackbar linear;
+}
+
+@keyframes show-snackbar {
+  0% {
+    opacity: 0;
+  }
+  /* 100ms fade-in */
+  3.33% {
+    opacity: 1;
+  }
+  97.33% {
+    opacity: 1;
+  }
+  /* 80ms fade-out */
+  100% {
+    opacity: 0;
+  }
+}
diff --git a/chromeos/components/camera_app_ui/resources/js/i18n_string.js b/chromeos/components/camera_app_ui/resources/js/i18n_string.js
index 95dba12..c0f7c979 100644
--- a/chromeos/components/camera_app_ui/resources/js/i18n_string.js
+++ b/chromeos/components/camera_app_ui/resources/js/i18n_string.js
@@ -65,7 +65,9 @@
   LABEL_GRID_GOLDEN: 'label_grid_golden',
   LABEL_NEW_CONTROL_TOAST: 'label_new_control_toast',
   LABEL_PHOTO_RESOLUTION: 'label_photo_resolution',
+  LABEL_SCAN_QRCODE_OPTION: 'label_scan_qrcode_option',
   LABEL_SWITCH_RECORD_VIDEO_BUTTON: 'label_switch_record_video_button',
+  LABEL_SWITCH_SCANNER_MODE_BUTTON: 'label_switch_scanner_mode_button',
   LABEL_SWITCH_TAKE_PHOTO_BUTTON: 'label_switch_take_photo_button',
   LABEL_SWITCH_TAKE_PORTRAIT_BOKEH_PHOTO_BUTTON:
       'label_switch_take_portrait_bokeh_photo_button',
@@ -89,6 +91,7 @@
   RECORD_VIDEO_RESUME_BUTTON: 'record_video_resume_button',
   RECORD_VIDEO_START_BUTTON: 'record_video_start_button',
   RECORD_VIDEO_STOP_BUTTON: 'record_video_stop_button',
+  SCAN_QRCODE_OPTION: 'scan_qrcode_option',
   SETTINGS_BUTTON: 'settings_button',
   SNACKBAR_LINK_COPIED: 'snackbar_link_copied',
   SNACKBAR_TEXT_COPIED: 'snackbar_text_copied',
@@ -98,6 +101,7 @@
   STATUS_MSG_RECORDING_STOPPED: 'status_msg_recording_stopped',
   SWITCH_CAMERA_BUTTON: 'switch_camera_button',
   SWITCH_RECORD_VIDEO_BUTTON: 'switch_record_video_button',
+  SWITCH_SCANNER_MODE_BUTTON: 'switch_scanner_mode_button',
   SWITCH_TAKE_PHOTO_BUTTON: 'switch_take_photo_button',
   SWITCH_TAKE_PORTRAIT_BOKEH_PHOTO_BUTTON:
       'switch_take_portrait_bokeh_photo_button',
diff --git a/chromeos/components/camera_app_ui/resources/js/js.gni b/chromeos/components/camera_app_ui/resources/js/js.gni
index f16d6a4..3550126 100644
--- a/chromeos/components/camera_app_ui/resources/js/js.gni
+++ b/chromeos/components/camera_app_ui/resources/js/js.gni
@@ -74,11 +74,13 @@
   "views/camera/mode/photo.js",
   "views/camera/mode/portrait.js",
   "views/camera/mode/record_time.js",
+  "views/camera/mode/scanner.js",
   "views/camera/mode/square.js",
   "views/camera/mode/video.js",
   "views/camera/options.js",
   "views/camera/preview.js",
   "views/camera/review_result.js",
+  "views/camera/scanner_options.js",
   "views/camera/timertick.js",
   "views/camera/video_encoder_options.js",
   "views/dialog.js",
diff --git a/chromeos/components/camera_app_ui/resources/js/main.js b/chromeos/components/camera_app_ui/resources/js/main.js
index c30a7f1..cffb9220b 100644
--- a/chromeos/components/camera_app_ui/resources/js/main.js
+++ b/chromeos/components/camera_app_ui/resources/js/main.js
@@ -178,12 +178,13 @@
         }
       });
       if (element.dataset['state'] !== undefined) {
-        state.addObserver(
-            state.assertState(element.dataset['state']), (value) => {
-              if (value !== element.checked) {
-                util.toggleChecked(element, value);
-              }
-            });
+        const s = state.assertState(element.dataset['state']);
+        state.addObserver(s, (value) => {
+          if (value !== element.checked) {
+            util.toggleChecked(element, value);
+          }
+        });
+        state.set(s, element.checked);
       }
       if (element.dataset['key'] !== undefined) {
         // Restore the previously saved state on startup.
diff --git a/chromeos/components/camera_app_ui/resources/js/state.js b/chromeos/components/camera_app_ui/resources/js/state.js
index 2bc4e581..2367bea 100644
--- a/chromeos/components/camera_app_ui/resources/js/state.js
+++ b/chromeos/components/camera_app_ui/resources/js/state.js
@@ -20,6 +20,7 @@
   ENABLE_DOCUMENT_MODE_ON_ALL_CAMERAS: 'enable-document-mode-on-all-cameras',
   ENABLE_MULTISTREAM_RECORDING: 'enable-multistream-recording',
   ENABLE_PTZ: 'enable-ptz',
+  ENABLE_SCAN_BARCODE: 'enable-scan-barcode',
   EXPERT: 'expert',
   FPS_30: 'fps-30',
   FPS_60: 'fps-60',
@@ -58,6 +59,7 @@
   SHOULD_HANDLE_INTENT_RESULT: 'should-handle-intent-result',
   SHOW_METADATA: 'show-metadata',
   SHOW_SCAN_DOCUMENT_OPTIONS: 'show-scan-document-options',
+  SHOW_SCANNER_MODE: 'show-scanner-mode',
   SCREEN_OFF_AUTO: 'screen-off-auto',
   STREAMING: 'streaming',
   SUSPEND: 'suspend',
diff --git a/chromeos/components/camera_app_ui/resources/js/type.js b/chromeos/components/camera_app_ui/resources/js/type.js
index d96d495..acd024b 100644
--- a/chromeos/components/camera_app_ui/resources/js/type.js
+++ b/chromeos/components/camera_app_ui/resources/js/type.js
@@ -95,6 +95,7 @@
   VIDEO: 'video',
   SQUARE: 'square',
   PORTRAIT: 'portrait',
+  SCANNER: 'scanner',
 };
 
 /**
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera.js b/chromeos/components/camera_app_ui/resources/js/views/camera.js
index 0d944db1..af01b0b 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera.js
@@ -45,13 +45,15 @@
 import {Layout} from './camera/layout.js';
 import {
   Modes,
-  PhotoHandler,  // eslint-disable-line no-unused-vars
+  PhotoHandler,    // eslint-disable-line no-unused-vars
+  ScannerHandler,  // eslint-disable-line no-unused-vars
   setAvc1Parameters,
   Video,
   VideoHandler,  // eslint-disable-line no-unused-vars
 } from './camera/mode/index.js';
 import {Options} from './camera/options.js';
 import {Preview} from './camera/preview.js';
+import {ScannerOptions} from './camera/scanner_options.js';
 import * as timertick from './camera/timertick.js';
 import {VideoEncoderOptions} from './camera/video_encoder_options.js';
 import {PTZPanel} from './ptz_panel.js';
@@ -76,6 +78,7 @@
  * Camera-view controller.
  * @implements {VideoHandler}
  * @implements {PhotoHandler}
+ * @implements {ScannerHandler}
  */
 export class Camera extends View {
   /**
@@ -126,6 +129,13 @@
     this.layout_ = new Layout();
 
     /**
+     * @type {!ScannerOptions}
+     * @private
+     */
+    this.scannerOptions_ =
+        new ScannerOptions(this.start.bind(this), this.infoUpdater_);
+
+    /**
      * Video preview for the camera.
      * @type {!Preview}
      * @private
@@ -183,7 +193,7 @@
      */
     this.modes_ = new Modes(
         this.defaultMode_, photoPreferrer, videoPreferrer,
-        this.start.bind(this), this, this);
+        this.start.bind(this), this, this, this);
 
     /**
      * @type {!Facing}
@@ -447,7 +457,6 @@
         await helper.isDocumentModeSupported());
   }
 
-
   /**
    * @param {function(): *} listener
    * @private
@@ -774,6 +783,7 @@
           await this.modes_.updateModeSelectionUI(deviceId);
           await this.modes_.updateMode(
               mode, factory, stream, this.facingMode_, deviceId, captureR);
+          await this.scannerOptions_.initialize(this.preview_.video);
           for (const l of this.configureCompleteListener_) {
             l();
           }
@@ -882,5 +892,6 @@
     // mode before stopping preview to close extra stream first.
     await this.modes_.clear();
     await this.preview_.close();
+    await this.scannerOptions_.uninitialize();
   }
 }
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
index 918e714..b5bd54b 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
@@ -32,6 +32,10 @@
   PhotoHandler,  // eslint-disable-line no-unused-vars
 } from './photo.js';
 import {PortraitFactory} from './portrait.js';
+import {
+  ScannerFactory,
+  ScannerHandler,  // eslint-disable-line no-unused-vars
+} from './scanner.js';
 import {SquareFactory} from './square.js';
 import {
   VideoFactory,
@@ -39,6 +43,7 @@
 } from './video.js';
 
 export {PhotoHandler, PhotoResult} from './photo.js';
+export {ScannerHandler} from './scanner.js';
 export {setAvc1Parameters, Video, VideoHandler, VideoResult} from './video.js';
 
 /**
@@ -100,7 +105,7 @@
    * @return {!Mode}
    * @abstract
    */
-  get nextMode() {}
+  get fallbackMode() {}
 
   /* eslint-enable getter-return */
 }
@@ -118,10 +123,11 @@
    * @param {!DoSwitchMode} doSwitchMode
    * @param {!PhotoHandler} photoHandler
    * @param {!VideoHandler} videoHandler
+   * @param {!ScannerHandler} scannerHandler
    */
   constructor(
       defaultMode, photoPreferrer, videoPreferrer, doSwitchMode, photoHandler,
-      videoHandler) {
+      videoHandler, scannerHandler) {
     /**
      * @type {!DoSwitchMode}
      * @private
@@ -191,7 +197,7 @@
         constraintsPreferrer: videoPreferrer,
         getConstraintsForFakeCamera:
             getConstraintsForFakeCamera.bind(this, true),
-        nextMode: Mode.PHOTO,
+        fallbackMode: Mode.PHOTO,
       },
       [Mode.PHOTO]: {
         captureFactory: new PhotoFactory(photoHandler),
@@ -200,7 +206,7 @@
         constraintsPreferrer: photoPreferrer,
         getConstraintsForFakeCamera:
             getConstraintsForFakeCamera.bind(this, false),
-        nextMode: Mode.SQUARE,
+        fallbackMode: Mode.SQUARE,
       },
       [Mode.SQUARE]: {
         captureFactory: new SquareFactory(photoHandler),
@@ -209,7 +215,7 @@
         constraintsPreferrer: photoPreferrer,
         getConstraintsForFakeCamera:
             getConstraintsForFakeCamera.bind(this, false),
-        nextMode: Mode.PHOTO,
+        fallbackMode: Mode.PHOTO,
       },
       [Mode.PORTRAIT]: {
         captureFactory: new PortraitFactory(photoHandler),
@@ -227,7 +233,17 @@
         constraintsPreferrer: photoPreferrer,
         getConstraintsForFakeCamera:
             getConstraintsForFakeCamera.bind(this, false),
-        nextMode: Mode.PHOTO,
+        fallbackMode: Mode.PHOTO,
+      },
+      [Mode.SCANNER]: {
+        captureFactory: new ScannerFactory(scannerHandler),
+        isSupported: async (deviceId) =>
+            state.get(state.State.SHOW_SCANNER_MODE),
+        isSupportPTZ: checkSupportPTZForPhotoMode,
+        constraintsPreferrer: photoPreferrer,
+        getConstraintsForFakeCamera:
+            getConstraintsForFakeCamera.bind(this, false),
+        fallbackMode: Mode.PHOTO,
       },
     };
 
@@ -301,7 +317,7 @@
     while (!tried[mode]) {
       tried[mode] = true;
       results.push(mode);
-      mode = this.allModes_[mode].nextMode;
+      mode = this.allModes_[mode].fallbackMode;
     }
     return results;
   }
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js
index df6cd459..1928231 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js
@@ -247,22 +247,10 @@
 }
 
 /**
- * Factory for creating photo mode capture object.
+ * Base factory for photo related modes.
+ * @abstract
  */
-export class PhotoFactory extends ModeFactory {
-  /**
-   * @param {!PhotoHandler} handler
-   */
-  constructor(handler) {
-    super();
-
-    /**
-     * @const {!PhotoHandler}
-     * @protected
-     */
-    this.handler_ = handler;
-  }
-
+export class PhotoBaseFactory extends ModeFactory {
   /**
    * @override
    */
@@ -277,6 +265,24 @@
           deviceId, assertInstanceof(this.captureResolution_, Resolution));
     }
   }
+}
+
+/**
+ * Factory for creating photo mode capture object.
+ */
+export class PhotoFactory extends PhotoBaseFactory {
+  /**
+   * @param {!PhotoHandler} handler
+   */
+  constructor(handler) {
+    super();
+
+    /**
+     * @const {!PhotoHandler}
+     * @protected
+     */
+    this.handler_ = handler;
+  }
 
   /**
    * @override
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/scanner.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/scanner.js
new file mode 100644
index 0000000..539eee4
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/scanner.js
@@ -0,0 +1,72 @@
+// 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.
+
+import {
+  Facing,      // eslint-disable-line no-unused-vars
+  Resolution,  // eslint-disable-line no-unused-vars
+} from '../../../type.js';
+
+import {
+  Photo,
+  PhotoBaseFactory,
+  PhotoHandler,  // eslint-disable-line no-unused-vars
+} from './photo.js';
+
+/**
+ * Provides external dependency functions used by photo mode and handles the
+ * captured result photo.
+ * @interface
+ */
+export class ScannerHandler {}
+
+/**
+ * Photo mode capture controller.
+ */
+export class Scanner extends Photo {
+  /**
+   * @param {!MediaStream} stream
+   * @param {!Facing} facing
+   * @param {?Resolution} captureResolution
+   * @param {!ScannerHandler} handler
+   */
+  constructor(stream, facing, captureResolution, handler) {
+    super(stream, facing, captureResolution, /** @type {!PhotoHandler} */ ({}));
+
+    /**
+     * @const {!ScannerHandler}
+     * @protected
+     */
+    this.scannerHandler_ = handler;
+  }
+}
+
+/**
+ * Factory for creating photo mode capture object.
+ */
+export class ScannerFactory extends PhotoBaseFactory {
+  /**
+   * @param {!ScannerHandler} handler
+   */
+  constructor(handler) {
+    super();
+
+    /**
+     * @const {!ScannerHandler}
+     * @protected
+     */
+    this.handler_ = handler;
+  }
+
+  /**
+   * @override
+   */
+  produce_() {
+    return new Scanner(
+        this.previewStream_,
+        this.facing_,
+        this.captureResolution_,
+        this.handler_,
+    );
+  }
+}
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/options.js b/chromeos/components/camera_app_ui/resources/js/views/camera/options.js
index ed256de..16768b0 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/options.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/options.js
@@ -9,11 +9,10 @@
 import {DeviceInfoUpdater} from '../../device/device_info_updater.js';
 import * as dom from '../../dom.js';
 import {I18nString} from '../../i18n_string.js';
-import {sendBarcodeEnabledEvent} from '../../metrics.js';
 import * as localStorage from '../../models/local_storage.js';
 import * as nav from '../../nav.js';
 import * as state from '../../state.js';
-import {Facing, Mode, PerfEvent, ViewName} from '../../type.js';
+import {Facing, PerfEvent, ViewName} from '../../type.js';
 import * as util from '../../util.js';
 
 /**
@@ -55,13 +54,6 @@
     this.toggleMirror_ = dom.get('#toggle-mirror', HTMLInputElement);
 
     /**
-     * @type {!HTMLInputElement}
-     * @private
-     * @const
-     */
-    this.toggleBarcode_ = dom.get('#toggle-barcode', HTMLInputElement);
-
-    /**
      * Device id of the camera device currently used or selected.
      * @type {?string}
      * @private
@@ -98,14 +90,6 @@
 
     this.toggleMic_.addEventListener('click', () => this.updateAudioByMic_());
     this.toggleMirror_.addEventListener('click', () => this.saveMirroring_());
-    this.toggleBarcode_.addEventListener('click', () => this.updateBarcode_());
-
-    state.addObserver(Mode.PHOTO, (inPhotoMode) => {
-      if (!inPhotoMode) {
-        this.toggleBarcode_.checked = false;
-        this.updateBarcode_();
-      }
-    });
 
     util.bindElementAriaLabelWithState({
       element: dom.get('#toggle-timer', Element),
@@ -211,17 +195,6 @@
   }
 
   /**
-   * Enables/disables barcode scanning according to the barcode option.
-   * @private
-   */
-  updateBarcode_() {
-    state.set(state.State.SCAN_BARCODE, this.toggleBarcode_.checked);
-    if (this.toggleBarcode_.checked) {
-      sendBarcodeEnabledEvent();
-    }
-  }
-
-  /**
    * Gets the video device ids sorted by preference.
    * @return {!Promise<!Array<?string>>} May contain null for fake cameras.
    */
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
index f34837a..e67d8da 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
@@ -2,12 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import * as barcodeChip from '../../barcode_chip.js';
 import {assert, assertInstanceof} from '../../chrome_util.js';
 import * as dom from '../../dom.js';
 import {reportError} from '../../error.js';
 import {FaceOverlay} from '../../face.js';
-import {BarcodeScanner} from '../../models/barcode.js';
 import {DeviceOperator, parseMetadata} from '../../mojo/device_operator.js';
 import * as nav from '../../nav.js';
 import * as state from '../../state.js';
@@ -15,7 +13,6 @@
   ErrorLevel,
   ErrorType,
   Facing,
-  Mode,
   Resolution,
 } from '../../type.js';
 import * as util from '../../util.js';
@@ -79,12 +76,6 @@
     this.focus_ = null;
 
     /**
-     * @type {?BarcodeScanner}
-     * @private
-     */
-    this.scanner_ = null;
-
-    /**
      * @type {!Facing}
      * @private
      */
@@ -103,9 +94,6 @@
     [state.State.EXPERT, state.State.SHOW_METADATA].forEach((s) => {
       state.addObserver(s, this.updateShowMetadata_.bind(this));
     });
-    [state.State.EXPERT, state.State.SCAN_BARCODE].forEach((s) => {
-      state.addObserver(s, this.updateScanBarcode_.bind(this));
-    });
   }
 
   /**
@@ -247,10 +235,6 @@
         }
       }, 100);
       await this.updateFacing_();
-      this.scanner_ = new BarcodeScanner(this.video_, (value) => {
-        barcodeChip.show(value);
-      });
-      this.updateScanBarcode_();
       this.updateShowMetadata_();
 
       const deviceOperator = await DeviceOperator.getInstance();
@@ -299,30 +283,10 @@
       }
       this.stream_ = null;
     }
-    if (this.scanner_ !== null) {
-      this.scanner_.stop();
-      this.scanner_ = null;
-    }
     state.set(state.State.STREAMING, false);
   }
 
   /**
-   * Checks whether to scan barcode on preview or not.
-   * @private
-   */
-  updateScanBarcode_() {
-    if (this.scanner_ === null) {
-      return;
-    }
-    if (state.get(Mode.PHOTO) && state.get(state.State.SCAN_BARCODE)) {
-      this.scanner_.start();
-    } else {
-      this.scanner_.stop();
-      barcodeChip.dismiss();
-    }
-  }
-
-  /**
    * Checks preview whether to show preview metadata or not.
    * @private
    */
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/scanner_options.js b/chromeos/components/camera_app_ui/resources/js/views/camera/scanner_options.js
new file mode 100644
index 0000000..2ab2acb
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/scanner_options.js
@@ -0,0 +1,160 @@
+// 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.
+
+import * as barcodeChip from '../../barcode_chip.js';
+// eslint-disable-next-line no-unused-vars
+import {DeviceInfoUpdater} from '../../device/device_info_updater.js';
+import * as dom from '../../dom.js';
+import {sendBarcodeEnabledEvent} from '../../metrics.js';
+import {BarcodeScanner} from '../../models/barcode.js';
+import * as state from '../../state.js';
+import {Mode} from '../../type.js';
+
+/**
+ * Controller for the scanner options of Camera view.
+ */
+export class ScannerOptions {
+  /**
+   * @param {function(): !Promise} reconfigure Request camera reconfiguration.
+   * @param {!DeviceInfoUpdater} infoUpdater
+   */
+  constructor(reconfigure, infoUpdater) {
+    /**
+     * @type {function(): !Promise}
+     * @private
+     */
+    this.reconfigure_ = reconfigure;
+
+    /**
+     * Togglable barcode option in photo mode.
+     * @type {!HTMLInputElement}
+     * @private
+     * @const
+     */
+    this.photoBarcodeOption_ = dom.get('#toggle-barcode', HTMLInputElement);
+
+    /**
+     * Barcode scanner type option in scanner mode.
+     * @type {!HTMLInputElement}
+     * @private
+     * @const
+     */
+    this.scannerBarcodeOption_ = dom.get('#scanner-barcode', HTMLInputElement);
+
+    /**
+     * May be null if preview is not ready.
+     * @type {?BarcodeScanner}
+     * @private
+     */
+    this.scanner_ = null;
+
+    /**
+     * @type {boolean}
+     * @private
+     */
+    this.hasCameraSupportDocumentMode_ = false;
+
+    const updateShowScannerMode = () => {
+      state.set(
+          state.State.SHOW_SCANNER_MODE,
+          this.hasCameraSupportDocumentMode_ ||
+              state.get(state.State.ENABLE_DOCUMENT_MODE_ON_ALL_CAMERAS));
+    };
+    state.addObserver(state.State.ENABLE_DOCUMENT_MODE_ON_ALL_CAMERAS, () => {
+      this.reconfigure_();
+      updateShowScannerMode();
+    });
+    infoUpdater.addDeviceChangeListener(async () => {
+      const devicesInfo = await infoUpdater.getCamera3DevicesInfo();
+      if (devicesInfo === null) {
+        return;
+      }
+      this.hasCameraSupportDocumentMode_ =
+          devicesInfo.some(({supportDocumentScan}) => supportDocumentScan);
+      updateShowScannerMode();
+    });
+    [state.State.SHOW_SCANNER_MODE, state.State.SCAN_BARCODE].forEach((s) => {
+      state.addObserver(s, (value) => {
+        if (state.get(state.State.CAMERA_CONFIGURING)) {
+          return;
+        }
+        this.updateOption_(state.get(state.State.SCAN_BARCODE));
+      });
+    });
+  }
+
+  /**
+   * @return {boolean} Whether barcode option is toggled.
+   */
+  isBarcodeOptionToggled_() {
+    if (!state.get(state.State.SCAN_BARCODE)) {
+      return false;
+    }
+    if (state.get(state.State.SHOW_SCANNER_MODE)) {
+      return state.get(Mode.SCANNER);
+    } else {
+      return state.get(Mode.PHOTO);
+    }
+  }
+
+  /**
+   * @param {!HTMLVideoElement} video
+   */
+  async initialize(video) {
+    this.scanner_ = new BarcodeScanner(video, (value) => {
+      barcodeChip.show(value);
+    });
+    this.updateOption_(this.isBarcodeOptionToggled_());
+  }
+
+  /**
+   * @param {boolean} toggled Whether barcode scanner option is toggled.
+   * @private
+   */
+  updateOption_(toggled) {
+    if (this.scanner_ === null) {
+      return;
+    }
+
+    this.updateOptionsUI_(toggled);
+    const mode =
+        state.get(state.State.SHOW_SCANNER_MODE) ? Mode.SCANNER : Mode.PHOTO;
+    if (state.get(mode) && toggled) {
+      sendBarcodeEnabledEvent();
+      this.scanner_.start();
+      state.set(state.State.ENABLE_SCAN_BARCODE, true);
+    } else {
+      this.stopBarcodeScanner_();
+    }
+  }
+
+  /**
+   * @private
+   */
+  stopBarcodeScanner_() {
+    this.scanner_.stop();
+    barcodeChip.dismiss();
+    state.set(state.State.ENABLE_SCAN_BARCODE, false);
+  }
+
+  /**
+   * @param {boolean} toggled Whether barcode scanner option is toggled.
+   * @private
+   */
+  updateOptionsUI_(toggled) {
+    this.photoBarcodeOption_.checked = toggled;
+    this.scannerBarcodeOption_.checked = toggled;
+    state.set(state.State.SCAN_BARCODE, toggled);
+  }
+
+  /**
+   * Stops all scanner.
+   */
+  async uninitialize() {
+    if (this.scanner_ !== null) {
+      this.stopBarcodeScanner_();
+      this.scanner_= null;
+    }
+  }
+}
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings.grd b/chromeos/components/camera_app_ui/resources/strings/camera_strings.grd
index 022bef7..8bc8dd6 100644
--- a/chromeos/components/camera_app_ui/resources/strings/camera_strings.grd
+++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings.grd
@@ -446,6 +446,18 @@
       <message desc="Label for switch to take portrait (bokeh effect, background blur) photo mode button." name="IDS_LABEL_SWITCH_TAKE_PORTRAIT_BOKEH_PHOTO_BUTTON">
         Portrait
       </message>
+      <message desc="Label for spoken feedback to read out for switch to scanner mode button." name="IDS_SWITCH_SCANNER_MODE_BUTTON">
+        Switch to scanner mode
+      </message>
+      <message desc="Label for switch to scanner mode button for scanning QR Code or document." name="IDS_LABEL_SWITCH_SCANNER_MODE_BUTTON">
+        Scanner
+      </message>
+      <message desc="Label for scanning QR code option." name="IDS_LABEL_SCAN_QRCODE_OPTION">
+        QR Code
+      </message>
+      <message desc="Label for spoken feedback to read out for scan QR code option." name="IDS_SCAN_QRCODE_OPTION">
+        Scan QR Code
+      </message>
       <message desc="Label for the confirm button to confirm with the reviewed photo or video." name="IDS_CONFIRM_REVIEW_BUTTON">
         Confirm
       </message>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_es.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_es.xtb
index 8ab4e94f..62b494f3 100644
--- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_es.xtb
+++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_es.xtb
@@ -57,7 +57,7 @@
 <translation id="4628948037717959914">Foto</translation>
 <translation id="4649291346448517080">No se puede guardar el archivo</translation>
 <translation id="4890010094662541459">3x3</translation>
-<translation id="491895758387112773">Grabación de varias emisiones de vídeo</translation>
+<translation id="491895758387112773">Grabación de vídeo con varias emisiones</translation>
 <translation id="5057360777601936059">Tu cámara no está disponible en este momento.
         Comprueba si está conectada correctamente.</translation>
 <translation id="5152121255775685072">Ir a la galería</translation>
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_LABEL_SCAN_QRCODE_OPTION.png.sha1 b/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_LABEL_SCAN_QRCODE_OPTION.png.sha1
new file mode 100644
index 0000000..de492027
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_LABEL_SCAN_QRCODE_OPTION.png.sha1
@@ -0,0 +1 @@
+b335acca873fd61c698eab1dc282ac66cc4bb8a9
\ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_LABEL_SWITCH_SCANNER_MODE_BUTTON.png.sha1 b/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_LABEL_SWITCH_SCANNER_MODE_BUTTON.png.sha1
new file mode 100644
index 0000000..a17384c4b
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_LABEL_SWITCH_SCANNER_MODE_BUTTON.png.sha1
@@ -0,0 +1 @@
+d98368dda6061d72e277d223814afef52e1f8eae
\ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_SCAN_QRCODE_OPTION.png.sha1 b/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_SCAN_QRCODE_OPTION.png.sha1
new file mode 100644
index 0000000..de492027
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_SCAN_QRCODE_OPTION.png.sha1
@@ -0,0 +1 @@
+b335acca873fd61c698eab1dc282ac66cc4bb8a9
\ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_SWITCH_SCANNER_MODE_BUTTON.png.sha1 b/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_SWITCH_SCANNER_MODE_BUTTON.png.sha1
new file mode 100644
index 0000000..a17384c4b
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_grd/IDS_SWITCH_SCANNER_MODE_BUTTON.png.sha1
@@ -0,0 +1 @@
+d98368dda6061d72e277d223814afef52e1f8eae
\ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_mr.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_mr.xtb
index 0edf83a..0db0e75 100644
--- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_mr.xtb
+++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_mr.xtb
@@ -57,6 +57,7 @@
 <translation id="4628948037717959914">फोटो</translation>
 <translation id="4649291346448517080">फाइल सेव्‍ह करता आली नाही</translation>
 <translation id="4890010094662541459">३ x ३</translation>
+<translation id="491895758387112773">मल्टिस्ट्रीम व्हिडिओ रेकॉर्डिंग</translation>
 <translation id="5057360777601936059">तुमचा कॅमेरा सध्या उपलब्ध नाही.
         कॅमेरा योग्य प्रकारे कनेक्ट केला आहे का ते तपासा.</translation>
 <translation id="5152121255775685072">गॅलरीवर जा</translation>
diff --git a/chromeos/components/camera_app_ui/resources/views/main.html b/chromeos/components/camera_app_ui/resources/views/main.html
index fa42880..ce7cd92 100644
--- a/chromeos/components/camera_app_ui/resources/views/main.html
+++ b/chromeos/components/camera_app_ui/resources/views/main.html
@@ -13,6 +13,7 @@
     <link rel="stylesheet" href="/css/ptz_panel.css">
     <link rel="stylesheet" href="/css/ptz_toast.css">
     <link rel="stylesheet" href="/css/ripple.css">
+    <link rel="stylesheet" href="/css/scanner.css">
     <script src="/js/mojo/mojo_bindings_lite.js"></script>
     <script src="/js/mojo/time.mojom-lite.js"></script>
     <script src="/js/mojo/camera_metadata_tags.mojom-lite.js"></script>
@@ -175,6 +176,13 @@
           </div>
           <div class="mode-item">
             <input type="radio" name="mode"
+                 data-mode="scanner" tabindex="0"
+                 i18n-aria="switch_scanner_mode_button">
+            <span i18n-text="label_switch_scanner_mode_button"
+                  aria-hidden="true"></span>
+          </div>
+          <div class="mode-item">
+            <input type="radio" name="mode"
                  data-mode="portrait" tabindex="0"
                  i18n-aria="switch_take_portrait_bokeh_photo_button">
             <span i18n-text="label_switch_take_portrait_bokeh_photo_button"
@@ -182,6 +190,14 @@
           </div>
         </div>
       </div>
+      <div id="scanner-modes-group">
+        <div class="scanner-mode-item">
+          <input id="scanner-barcode" type="radio" tabindex="0"
+                 name="scanner-type" data-state="scan-barcode"
+                 i18n-aria="scan_qrcode_option">
+          <div class="label" i18n-text="label_scan_qrcode_option"></div>
+        </div>
+      </div>
       <div id="banner" class="horizontal-center-stripe" aria-live="polite">
         <div id="banner-title">
           <div id="banner-title-icon"></div>
@@ -241,7 +257,7 @@
                data-key="toggleMic" checked>
       </div>
       <div class="top-stripe right-stripe circle buttons">
-        <input id="toggle-barcode" type="checkbox"
+        <input id="toggle-barcode" type="checkbox" data-state="scan-barcode"
                tabindex="0" i18n-label="toggle_barcode_button">
       </div>
       <div class="centered-overlay">
diff --git a/chromeos/components/help_app_ui/BUILD.gn b/chromeos/components/help_app_ui/BUILD.gn
index 19387183..d00289d 100644
--- a/chromeos/components/help_app_ui/BUILD.gn
+++ b/chromeos/components/help_app_ui/BUILD.gn
@@ -97,7 +97,7 @@
 js2gtest("browser_tests_js") {
   test_type = "mojo_lite_webui"
 
-  sources = [ "test/help_app_ui_browsertest.js" ]
+  sources = [ "test/help_app_ui_gtest_browsertest.js" ]
 
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 
@@ -126,6 +126,7 @@
     "test/driver.js",
     "test/driver_api.js",
     "test/guest_query_receiver.js",
+    "test/help_app_ui_browsertest.js",
     "test/help_app_guest_ui_browsertest.js",
   ]
 }
@@ -148,6 +149,7 @@
   deps = [
     ":test_help_app_guest_ui_browsertest_js",
     ":test_help_app_ui_browsertest_js",
+    ":test_help_app_ui_gtest_browsertest_js",
   ]
 }
 
@@ -177,11 +179,17 @@
   ]
 }
 
+js_library("test_help_app_ui_gtest_browsertest_js") {
+  testonly = true
+  sources = [ "test/help_app_ui_gtest_browsertest.js" ]
+  externs_list =
+      [ "//chromeos/components/web_applications/js2gtest_support.externs.js" ]
+  deps = [ ":test_help_app_ui_browsertest_js" ]
+}
+
 js_library("test_help_app_ui_browsertest_js") {
   testonly = true
   sources = [ "test/help_app_ui_browsertest.js" ]
-  externs_list =
-      [ "//chromeos/components/web_applications/js2gtest_support.externs.js" ]
   deps = [
     ":test_driver_js",
     "//chromeos/components/help_app_ui/resources:browser_proxy",
diff --git a/chromeos/components/help_app_ui/help_app_ui.cc b/chromeos/components/help_app_ui/help_app_ui.cc
index f67b371..dcd9fb9 100644
--- a/chromeos/components/help_app_ui/help_app_ui.cc
+++ b/chromeos/components/help_app_ui/help_app_ui.cc
@@ -16,6 +16,7 @@
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy.h"
 #include "chromeos/components/local_search_service/public/cpp/local_search_service_proxy_factory.h"
 #include "chromeos/components/local_search_service/public/mojom/types.mojom.h"
+#include "chromeos/components/web_applications/webui_test_prod_util.h"
 #include "chromeos/grit/chromeos_help_app_resources.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
@@ -37,16 +38,8 @@
   source->SetDefaultResource(IDR_HELP_APP_HOST_INDEX_HTML);
   source->AddResourcePath("app_icon_192.png", IDR_HELP_APP_ICON_192);
   source->AddResourcePath("app_icon_512.png", IDR_HELP_APP_ICON_512);
-  source->AddResourcePath("help_app_index_scripts.js",
-                          IDR_HELP_APP_INDEX_SCRIPTS_JS);
-  source->AddResourcePath("help_app.mojom-lite.js",
-                          IDR_HELP_APP_HELP_APP_MOJOM_JS);
-  source->AddResourcePath("local_search_service_types.mojom-lite.js",
-                          IDR_HELP_APP_LOCAL_SEARCH_SERVICE_TYPES_MOJOM_JS);
-  source->AddResourcePath("local_search_service_index.mojom-lite.js",
-                          IDR_HELP_APP_LOCAL_SEARCH_SERVICE_INDEX_MOJOM_JS);
-  source->AddResourcePath("help_app_search.mojom-lite.js",
-                          IDR_HELP_APP_SEARCH_MOJOM_JS);
+  source->AddResourcePath("browser_proxy.js", IDR_HELP_APP_BROWSER_PROXY_JS);
+
   source->AddLocalizedString("appTitle", IDS_HELP_APP_EXPLORE);
   return source;
 }
@@ -82,6 +75,12 @@
                             ContentSettingsType::SOUND,
                         });
 
+  if (MaybeConfigureTestableDataSource(host_source)) {
+    host_source->OverrideContentSecurityPolicy(
+        network::mojom::CSPDirectiveName::TrustedTypes,
+        std::string("trusted-types test-harness;"));
+  }
+
   // Register common permissions for chrome-untrusted:// pages.
   // TODO(https://crbug.com/1113568): Remove this after common permissions are
   // granted by default.
diff --git a/chromeos/components/help_app_ui/help_app_untrusted_ui.cc b/chromeos/components/help_app_ui/help_app_untrusted_ui.cc
index 9349b9e..48dc628 100644
--- a/chromeos/components/help_app_ui/help_app_untrusted_ui.cc
+++ b/chromeos/components/help_app_ui/help_app_untrusted_ui.cc
@@ -5,6 +5,7 @@
 #include "chromeos/components/help_app_ui/help_app_untrusted_ui.h"
 
 #include "chromeos/components/help_app_ui/url_constants.h"
+#include "chromeos/components/web_applications/webui_test_prod_util.h"
 #include "chromeos/grit/chromeos_help_app_bundle_resources.h"
 #include "chromeos/grit/chromeos_help_app_bundle_resources_map.h"
 #include "chromeos/grit/chromeos_help_app_resources.h"
@@ -14,7 +15,6 @@
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/common/url_constants.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
-#include "ui/resources/grit/webui_generated_resources.h"
 
 namespace chromeos {
 
@@ -29,15 +29,15 @@
   // the other paths.
   source->SetDefaultResource(IDR_HELP_APP_APP_HTML);
   source->AddResourcePath("app_bin.js", IDR_HELP_APP_APP_BIN_JS);
-  source->AddResourcePath("load_time_data.js", IDR_WEBUI_JS_LOAD_TIME_DATA_JS);
-  source->AddResourcePath("help_app_app_scripts.js",
-                          IDR_HELP_APP_APP_SCRIPTS_JS);
+  source->AddResourcePath("receiver.js", IDR_HELP_APP_RECEIVER_JS);
   source->DisableTrustedTypesCSP();
 
   // Add all resources from chromeos_help_app_bundle.pak.
   source->AddResourcePaths(base::make_span(
       kChromeosHelpAppBundleResources, kChromeosHelpAppBundleResourcesSize));
 
+  MaybeConfigureTestableDataSource(source);
+
   // Add device and feature flags.
   populate_load_time_data_callback.Run(source);
   source->AddLocalizedString("appName", IDS_HELP_APP_EXPLORE);
diff --git a/chromeos/components/help_app_ui/resources/BUILD.gn b/chromeos/components/help_app_ui/resources/BUILD.gn
index 3a3ac48..346d199 100644
--- a/chromeos/components/help_app_ui/resources/BUILD.gn
+++ b/chromeos/components/help_app_ui/resources/BUILD.gn
@@ -2,11 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//chrome/browser/resources/tools/optimize_webui.gni")
 import("//chromeos/components/web_applications/system_apps.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 
 assert(is_chromeos, "Help App is Chrome OS only")
 
+stage_folder = "$target_gen_dir/stage"
+
 group("closure_compile") {
   deps = [
     ":closure_compile_app",
@@ -14,6 +17,60 @@
   ]
 }
 
+# Move all files into a single folder so optimize_webui can generate a single
+# file bundle. stage_static moves all static files from src/ into stage/ and
+# stage_generated moves generated files from gen/ into stage/.
+copy("stage_static") {
+  sources = [
+    "//chromeos/components/system_apps/public/js/sandboxed_load_time_data.js",
+    "browser_proxy.js",
+    "message_types.js",
+    "receiver.js",
+  ]
+  outputs = [ stage_folder + "/{{source_file_part}}" ]
+}
+
+copy("stage_generated") {
+  sources = [
+    "$target_gen_dir/../../local_search_service/public/mojom/index.mojom-lite.js",
+    "$target_gen_dir/../../local_search_service/public/mojom/types.mojom-lite.js",
+    "$target_gen_dir/../../system_apps/public/js/message_pipe.m.js",
+    "$target_gen_dir/../help_app_ui.mojom-lite.js",
+    "$target_gen_dir/../search/search.mojom-lite.js",
+  ]
+  outputs = [ stage_folder + "/{{source_file_part}}" ]
+  deps = [
+    "//chromeos/components/help_app_ui:mojo_bindings_js",
+    "//chromeos/components/help_app_ui/search:mojo_bindings_js__generator",
+    "//chromeos/components/local_search_service/public/mojom:mojom_js__generator",
+    "//chromeos/components/system_apps/public/js:modulize",
+  ]
+}
+
+# Generate a bundle of all the JS needed for chrome://help-app.
+optimize_webui("browser_proxy_rollup") {
+  host = "help-app"
+  js_out_files = [ "browser_proxy.rollup.js" ]
+  js_module_in_files = [ "browser_proxy.js" ]
+  input = rebase_path(stage_folder, root_build_dir)
+  deps = [
+    ":stage_generated",
+    ":stage_static",
+  ]
+}
+
+# Generate a bundle of all the JS needed for chrome-untrusted://help-app.
+optimize_webui("receiver_rollup") {
+  host = "help-app"
+  js_out_files = [ "receiver.rollup.js" ]
+  js_module_in_files = [ "receiver.js" ]
+  input = rebase_path(stage_folder, root_build_dir)
+  deps = [
+    ":stage_generated",
+    ":stage_static",
+  ]
+}
+
 js_type_check("closure_compile_index") {
   closure_flags = system_app_closure_flags_strict
   deps = [ ":browser_proxy" ]
@@ -24,6 +81,8 @@
   deps = [ ":receiver" ]
 }
 
+# We don't use these libraries in our build process but have them so we can
+# retain type checking via the above js_type_check rules.
 js_library("browser_proxy") {
   externs_list = [
     # The privileged context can't access the app, but shares struct definitions
@@ -36,7 +95,7 @@
     "//chromeos/components/help_app_ui:mojo_bindings_js_library_for_compile",
     "//chromeos/components/help_app_ui/search:mojo_bindings_js_library_for_compile",
     "//chromeos/components/local_search_service/public/mojom:mojom_js_library_for_compile",
-    "//chromeos/components/system_apps/public/js:message_pipe",
+    "//chromeos/components/system_apps/public/js:message_pipe.m",
   ]
 }
 
@@ -47,6 +106,6 @@
   externs_list = [ "help_app.externs.js" ]
   deps = [
     ":message_types",
-    "//chromeos/components/system_apps/public/js:message_pipe",
+    "//chromeos/components/system_apps/public/js:message_pipe.m",
   ]
 }
diff --git a/chromeos/components/help_app_ui/resources/app.html b/chromeos/components/help_app_ui/resources/app.html
index 4de93a2..4ed8fca 100644
--- a/chromeos/components/help_app_ui/resources/app.html
+++ b/chromeos/components/help_app_ui/resources/app.html
@@ -9,8 +9,13 @@
     margin: 0;
   }
 </style>
-<script src="/load_time_data.js"></script>
-<script src="/strings.js"></script>
-<script src="/app_bin.js"></script>
-<script src="/help_app_app_scripts.js"></script>
+<script src="/receiver.js" type="module"></script>
+<!--
+  Populates `window.loadTimeData.data`. Needs to be after
+  "receiver.js" which loads "sandboxed_load_time_data.js". But
+  module scripts do not block parsing, so these non-module scripts must be
+  loaded on the defer queue.
+-->
+<script src="/strings.js" defer></script>
+<script src="/app_bin.js" defer></script>
 </html>
diff --git a/chromeos/components/help_app_ui/resources/browser_proxy.js b/chromeos/components/help_app_ui/resources/browser_proxy.js
index c75a3f8..84d73011 100644
--- a/chromeos/components/help_app_ui/resources/browser_proxy.js
+++ b/chromeos/components/help_app_ui/resources/browser_proxy.js
@@ -1,6 +1,15 @@
 // Copyright 2020 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 './help_app_ui.mojom-lite.js';
+// The order here matters, types must be imported before index and search which
+// rely on it.
+import './types.mojom-lite.js';
+import './index.mojom-lite.js';
+import './search.mojom-lite.js';
+
+import {MessagePipe} from './message_pipe.m.js';
+import {Message} from './message_types.js';
 
 const help_app = {
   handler: new helpAppUi.mojom.PageHandlerRemote()
@@ -12,8 +21,7 @@
 
 // Set up an index remote to talk to Local Search Service.
 /** @type {!chromeos.localSearchService.mojom.IndexRemote} */
-const indexRemote =
-    chromeos.localSearchService.mojom.Index.getRemote();
+const indexRemote = chromeos.localSearchService.mojom.Index.getRemote();
 
 /**
  * Talks to the search handler. Use for updating the content for launcher
@@ -170,7 +178,7 @@
         // Id of the best subheading that appears in positions. We consider
         // the subheading containing the most match positions to be the best.
         // "" means no subheading positions found.
-        let bestSubheadingId = "";
+        let bestSubheadingId = '';
         /**
          * Counts how many positions there are for each subheading id.
          * @type {!Object<string, number>}
@@ -189,8 +197,8 @@
             // best subheading.
             const newCount = (subheadingPosCounts[position.contentId] || 0) + 1;
             subheadingPosCounts[position.contentId] = newCount;
-            if (!bestSubheadingId
-                || newCount > subheadingPosCounts[bestSubheadingId]) {
+            if (!bestSubheadingId ||
+                newCount > subheadingPosCounts[bestSubheadingId]) {
               bestSubheadingId = position.contentId;
             }
           }
@@ -217,12 +225,10 @@
           id: result.id,
           titlePositions,
           bodyPositions,
-          subheadingIndex: bestSubheadingId
-              ? Number(bestSubheadingId.substring(SUBHEADING_ID.length))
-              : null,
-          subheadingPositions: bestSubheadingId
-              ? subheadingPositions
-              : null,
+          subheadingIndex: bestSubheadingId ?
+              Number(bestSubheadingId.substring(SUBHEADING_ID.length)) :
+              null,
+          subheadingPositions: bestSubheadingId ? subheadingPositions : null,
         };
       });
       return {results};
@@ -239,7 +245,9 @@
 
 guestMessagePipe.registerHandler(
     Message.UPDATE_LAUNCHER_SEARCH_INDEX, async (message) => {
-      if (!(await isLauncherSearchEnabled)) return;
+      if (!(await isLauncherSearchEnabled)) {
+        return;
+      }
 
       const dataFromApp =
           /** @type {!Array<!helpApp.LauncherSearchableItem>} */ (message);
@@ -258,13 +266,13 @@
           }));
       // Filter out invalid items. No field can be empty except locale.
       const dataFiltered = dataToSend.filter(item => {
-        const valid = item.id && item.title && item.mainCategory
-            && item.tags.length > 0 && item.urlPathWithParameters;
+        const valid = item.id && item.title && item.mainCategory &&
+            item.tags.length > 0 && item.urlPathWithParameters;
         // This is a google-internal histogram. If changing this, also change
         // the corresponding histograms file.
         if (!valid) {
           chrome.metricsPrivate.recordSparseHashable(
-            'Discover.LauncherSearch.InvalidConceptInUpdate', item.id);
+              'Discover.LauncherSearch.InvalidConceptInUpdate', item.id);
         }
         return valid;
       });
@@ -299,7 +307,13 @@
  * @return {string}
  */
 function truncate(s) {
-  if (typeof s !== 'string') return '';
-  if (s.length <= MAX_STRING_LEN) return s;
+  if (typeof s !== 'string') {
+    return '';
+  }
+  if (s.length <= MAX_STRING_LEN) {
+    return s;
+  }
   return s.substring(0, MAX_STRING_LEN);
 }
+
+export const TEST_ONLY = {guestMessagePipe};
diff --git a/chromeos/components/help_app_ui/resources/help_app_app_scripts.js b/chromeos/components/help_app_ui/resources/help_app_app_scripts.js
deleted file mode 100644
index 9375725..0000000
--- a/chromeos/components/help_app_ui/resources/help_app_app_scripts.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2020 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.
-
-/** @fileoverview Concatenation of the JS files we use in app.html. */
-
-// <include src="../../system_apps/public/js/message_pipe.js">
-// <include src="message_types.js">
-// <include src="receiver.js">
diff --git a/chromeos/components/help_app_ui/resources/help_app_index_scripts.js b/chromeos/components/help_app_ui/resources/help_app_index_scripts.js
deleted file mode 100644
index b20808c..0000000
--- a/chromeos/components/help_app_ui/resources/help_app_index_scripts.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2020 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.
-
-/** @fileoverview Concatenation of the JS files we use in index.html. */
-
-// <include src="../../system_apps/public/js/message_pipe.js">
-// <include src="message_types.js">
-// <include src="browser_proxy.js">
diff --git a/chromeos/components/help_app_ui/resources/help_app_resources.grd b/chromeos/components/help_app_ui/resources/help_app_resources.grd
index aa91e6ff..81212bb 100644
--- a/chromeos/components/help_app_ui/resources/help_app_resources.grd
+++ b/chromeos/components/help_app_ui/resources/help_app_resources.grd
@@ -19,23 +19,16 @@
           type="BINDATA" />
       <include name="IDR_HELP_APP_ICON_512" file="app_icon_512.png"
           type="BINDATA" />
-      <include name="IDR_HELP_APP_HELP_APP_MOJOM_JS"
-          file="${root_gen_dir}/chromeos/components/help_app_ui/help_app_ui.mojom-lite.js"
-          resource_path="help_app_ui.mojom-lite.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_HELP_APP_LOCAL_SEARCH_SERVICE_TYPES_MOJOM_JS"
-          file="${root_gen_dir}/chromeos/components/local_search_service/public/mojom/types.mojom-lite.js"
-          resource_path="local_search_service_types.mojom-lite.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_HELP_APP_LOCAL_SEARCH_SERVICE_INDEX_MOJOM_JS"
-          file="${root_gen_dir}/chromeos/components/local_search_service/public/mojom/index.mojom-lite.js"
-          resource_path="local_search_service_index.mojom-lite.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_HELP_APP_SEARCH_MOJOM_JS"
-          file="${root_gen_dir}/chromeos/components/help_app_ui/search/search.mojom-lite.js"
-          resource_path="help_app_search.mojom-lite.js" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_HELP_APP_INDEX_SCRIPTS_JS" file="help_app_index_scripts.js" flattenhtml="true" type="BINDATA" />
-
+      <include name="IDR_HELP_APP_BROWSER_PROXY_JS"
+          file="${root_gen_dir}/chromeos/components/help_app_ui/resources/browser_proxy.rollup.js"
+          resource_path="browser_proxy.js"
+          use_base_dir="false" type="BINDATA" />
       <!-- Unprivileged guest contents. -->
       <include name="IDR_HELP_APP_APP_HTML" file="app.html" type="BINDATA" />
-      <include name="IDR_HELP_APP_APP_SCRIPTS_JS" file="help_app_app_scripts.js" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_HELP_APP_RECEIVER_JS"
+          file="${root_gen_dir}/chromeos/components/help_app_ui/resources/receiver.rollup.js"
+          resource_path="receiver.js" use_base_dir="false"
+          type="BINDATA" />
     </includes>
   </release>
 </grit>
diff --git a/chromeos/components/help_app_ui/resources/index.html b/chromeos/components/help_app_ui/resources/index.html
index 58469fd..478a8c1 100644
--- a/chromeos/components/help_app_ui/resources/index.html
+++ b/chromeos/components/help_app_ui/resources/index.html
@@ -25,12 +25,8 @@
 </head>
 <body>
   <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
-  <script src="/help_app.mojom-lite.js"></script>
   <script src="chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js"></script>
   <script src="chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js"></script>
-  <script src="/local_search_service_types.mojom-lite.js"></script>
-  <script src="/local_search_service_index.mojom-lite.js"></script>
-  <script src="/help_app_search.mojom-lite.js"></script>
-  <script src="/help_app_index_scripts.js"></script>
+  <script src="/browser_proxy.js" type="module"></script>
 </body>
 </html>
diff --git a/chromeos/components/help_app_ui/resources/message_types.js b/chromeos/components/help_app_ui/resources/message_types.js
index 742fd72f..0778de7 100644
--- a/chromeos/components/help_app_ui/resources/message_types.js
+++ b/chromeos/components/help_app_ui/resources/message_types.js
@@ -11,7 +11,7 @@
  * Enum for message types.
  * @enum {string}
  */
-const Message = {
+export const Message = {
   OPEN_FEEDBACK_DIALOG: 'open-feedback-dialog',
   SHOW_PARENTAL_CONTROLS: 'show-parental-controls',
   ADD_OR_UPDATE_SEARCH_INDEX: 'add-or-update-search-index',
diff --git a/chromeos/components/help_app_ui/resources/receiver.js b/chromeos/components/help_app_ui/resources/receiver.js
index 62fb2049..e024606 100644
--- a/chromeos/components/help_app_ui/resources/receiver.js
+++ b/chromeos/components/help_app_ui/resources/receiver.js
@@ -6,6 +6,10 @@
  * @fileoverview
  * A script for the app inside the iframe. Implements a delegate.
  */
+import './sandboxed_load_time_data.js';
+
+import {MessagePipe} from './message_pipe.m.js';
+import {Message} from './message_types.js';
 
 /** A pipe through which we can send messages to the parent frame. */
 const parentMessagePipe = new MessagePipe('chrome://help-app', window.parent);
@@ -70,3 +74,5 @@
 window.customLaunchData = {
   delegate: DELEGATE,
 };
+
+export const TEST_ONLY = {parentMessagePipe};
diff --git a/chromeos/components/help_app_ui/test/driver.js b/chromeos/components/help_app_ui/test/driver.js
index fcb35f6..138aae51 100644
--- a/chromeos/components/help_app_ui/test/driver.js
+++ b/chromeos/components/help_app_ui/test/driver.js
@@ -1,26 +1,28 @@
 // Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-
 // TODO(b/169279800): Pull out test code that media app and help app have in
 // common.
 
+// Note we can only import from 'browser_proxy.js': other modules are rolled-up
+// into it, and already loaded.
+import {TEST_ONLY} from './browser_proxy.js';
+const {guestMessagePipe} = TEST_ONLY;
+
 /**
  * Promise that signals the guest is ready to receive test messages (in addition
  * to messages handled by receiver.js).
  * @type {!Promise<undefined>}
  */
 const testMessageHandlersReady = new Promise(resolve => {
-  window.addEventListener('DOMContentLoaded', () => {
-    guestMessagePipe.registerHandler('test-handlers-ready', resolve);
-  });
+  guestMessagePipe.registerHandler('test-handlers-ready', resolve);
 });
 
 /**
  * Runs the given `testCase` in the guest context.
  * @param {string} testCase
  */
-async function runTestInGuest(testCase) {
+export async function runTestInGuest(testCase) {
   /** @type {!TestMessageRunTestCase} */
   const message = {testCase};
   await testMessageHandlersReady;
diff --git a/chromeos/components/help_app_ui/test/guest_query_receiver.js b/chromeos/components/help_app_ui/test/guest_query_receiver.js
index 58b93f7..5e0de6a 100644
--- a/chromeos/components/help_app_ui/test/guest_query_receiver.js
+++ b/chromeos/components/help_app_ui/test/guest_query_receiver.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TEST_ONLY} from './receiver.js';
+
+const {parentMessagePipe} = TEST_ONLY;
+
 /**
  * Test cases registered by GUEST_TEST.
  * @type {!Map<string, function(): Promise<undefined>>}
@@ -28,7 +32,7 @@
  * @param {!string} testName
  * @param {!function(): Promise<undefined>} testCase
  */
-function GUEST_TEST(testName, testCase) {
+export function GUEST_TEST(testName, testCase) {
   guestTestCases.set(testName, testCase);
 }
 
@@ -41,18 +45,23 @@
  */
 async function signalTestHandlersReady() {
   const EXPECTED_ERROR =
-      `No handler registered for message type 'test-handlers-ready'`;
-  while (true) {
+      /No handler registered for message type 'test-handlers-ready'/;
+  // Attempt to signal to the driver that we are ready to run tests, give up
+  // after 10 tries and assume something went wrong so we don't spam the error
+  // log too much.
+  let attempts = 10;
+  while (--attempts >= 0) {
     try {
       await parentMessagePipe.sendMessage('test-handlers-ready', {});
       return;
     } catch (/** @type {!GenericErrorResponse} */ e) {
-      if (e.message !== EXPECTED_ERROR) {
+      if (!EXPECTED_ERROR.test(e.message)) {
         console.error('Unexpected error in signalTestHandlersReady', e);
         return;
       }
     }
   }
+  console.error('signalTestHandlersReady failed to signal.');
 }
 
 /** Installs the MessagePipe handlers for receiving test queries. */
@@ -80,5 +89,3 @@
 } else {
   installTestHandlers();
 }
-
-//# sourceURL=guest_query_receiver.js
diff --git a/chromeos/components/help_app_ui/test/help_app_guest_ui_browsertest.js b/chromeos/components/help_app_ui/test/help_app_guest_ui_browsertest.js
index 2d9ec4a..9d268f4 100644
--- a/chromeos/components/help_app_ui/test/help_app_guest_ui_browsertest.js
+++ b/chromeos/components/help_app_ui/test/help_app_guest_ui_browsertest.js
@@ -4,6 +4,8 @@
 
 /** @fileoverview Test suite for chrome-untrusted://help-app. */
 
+import {GUEST_TEST} from './guest_query_receiver.js';
+
 // Test that language is set correctly on the guest frame.
 GUEST_TEST('GuestHasLang', () => {
   assertEquals(document.documentElement.lang, 'en-US');
@@ -23,7 +25,9 @@
     // 'Chrome' appears in the mock app's fake search results, and should appear
     // in the real app's search results.
     const response = await delegate.findInSearchIndex('Chrome');
-    if (response && response.results && response.results.length > 0) break;
+    if (response && response.results && response.results.length > 0) {
+      break;
+    }
     await new Promise(resolve => {setTimeout(resolve, 50)});
   }
   return delegate;
@@ -34,33 +38,37 @@
 GUEST_TEST('GuestCanSearchWithHeadings', async () => {
   const delegate = await waitForInitialIndexUpdate();
 
-  await delegate.addOrUpdateSearchIndex([{
-    // Title match. No subheadings.
-    id: 'test-id-1',
-    title: 'Title with verycomplicatedsearchtoken',
-    body: 'Body text',
-    mainCategoryName: 'Help',
-    locale: 'en-US',
-  },{
-    // Subheading match.
-    id: 'test-id-2',
-    title: 'Title 2',
-    subheadings: [
-      'Subheading 1',
-      'verycomplicatedsearchtoken in subheading. Verycomplicatedsearchtoken',
-      'Another subheading with verycomplicatedsearchtoken',
-    ],
-    body: 'Body text',
-    mainCategoryName: 'Help',
-    locale: 'en-US',
-  },{
-    // Should not appear in the results.
-    id: 'test-id-3',
-    title: 'Title of irrelevant article',
-    body: 'Body text',
-    mainCategoryName: 'Help',
-    locale: 'en-US',
-  }]);
+  await delegate.addOrUpdateSearchIndex([
+    {
+      // Title match. No subheadings.
+      id: 'test-id-1',
+      title: 'Title with verycomplicatedsearchtoken',
+      body: 'Body text',
+      mainCategoryName: 'Help',
+      locale: 'en-US',
+    },
+    {
+      // Subheading match.
+      id: 'test-id-2',
+      title: 'Title 2',
+      subheadings: [
+        'Subheading 1',
+        'verycomplicatedsearchtoken in subheading. Verycomplicatedsearchtoken',
+        'Another subheading with verycomplicatedsearchtoken',
+      ],
+      body: 'Body text',
+      mainCategoryName: 'Help',
+      locale: 'en-US',
+    },
+    {
+      // Should not appear in the results.
+      id: 'test-id-3',
+      title: 'Title of irrelevant article',
+      body: 'Body text',
+      mainCategoryName: 'Help',
+      locale: 'en-US',
+    }
+  ]);
 
   // Keep polling until the index finishes updating or too much time has passed.
   /** @type {?helpApp.FindResponse} */
@@ -69,7 +77,9 @@
     // This search query was chosen because it is unlikely to show any search
     // results for the real app's data.
     response = await delegate.findInSearchIndex('verycomplicatedsearchtoken');
-    if (response && response.results && response.results.length > 0) break;
+    if (response && response.results && response.results.length > 0) {
+      break;
+    }
     await new Promise(resolve => {setTimeout(resolve, 50)});
   }
 
@@ -102,33 +112,37 @@
 GUEST_TEST('GuestCanSearchWithCategories', async () => {
   const delegate = await waitForInitialIndexUpdate();
 
-  await delegate.addOrUpdateSearchIndex([{
-    // Main category match. No subcategories.
-    id: 'test-id-1',
-    title: 'Title with of article',
-    body: 'Body text',
-    mainCategoryName: 'Verycomplicatedsearchtoken',
-    locale: 'en-US',
-  },{
-    // Subcategory match.
-    id: 'test-id-2',
-    title: 'Title 2',
-    subcategoryNames: [
-      'Subcategory 1',
-      'verycomplicatedsearchtoken in subcategory. Verycomplicatedsearchtoken',
-      'Another subcategory with verycomplicatedsearchtoken',
-    ],
-    body: 'Body text',
-    mainCategoryName: 'Help',
-    locale: 'en-US',
-  },{
-    // Should not appear in the results.
-    id: 'test-id-3',
-    title: 'Title of irrelevant article',
-    body: 'Body text',
-    mainCategoryName: 'Help',
-    locale: 'en-US',
-  }]);
+  await delegate.addOrUpdateSearchIndex([
+    {
+      // Main category match. No subcategories.
+      id: 'test-id-1',
+      title: 'Title with of article',
+      body: 'Body text',
+      mainCategoryName: 'Verycomplicatedsearchtoken',
+      locale: 'en-US',
+    },
+    {
+      // Subcategory match.
+      id: 'test-id-2',
+      title: 'Title 2',
+      subcategoryNames: [
+        'Subcategory 1',
+        'verycomplicatedsearchtoken in subcategory. Verycomplicatedsearchtoken',
+        'Another subcategory with verycomplicatedsearchtoken',
+      ],
+      body: 'Body text',
+      mainCategoryName: 'Help',
+      locale: 'en-US',
+    },
+    {
+      // Should not appear in the results.
+      id: 'test-id-3',
+      title: 'Title of irrelevant article',
+      body: 'Body text',
+      mainCategoryName: 'Help',
+      locale: 'en-US',
+    }
+  ]);
 
   // Keep polling until the index finishes updating or too much time has passed.
   /** @type {?helpApp.FindResponse} */
@@ -137,30 +151,32 @@
     // This search query was chosen because it is unlikely to show any search
     // results for the real app's data.
     response = await delegate.findInSearchIndex('verycomplicatedsearchtoken');
-    if (response && response.results && response.results.length > 0) break;
+    if (response && response.results && response.results.length > 0) {
+      break;
+    }
     await new Promise(resolve => {setTimeout(resolve, 50)});
   }
 
   // Don't test the ordering of search results because they should have similar
   // relevance.
   chai.expect(response.results).to.have.deep.members([
-      // This result only matches on the main category.
-      {
-        id: 'test-id-1',
-        titlePositions: [],
-        subheadingIndex: null,
-        subheadingPositions: null,
-        bodyPositions: [],
-      },
-      // This result only matches on the second and third subcategories.
-      {
-        id: 'test-id-2',
-        titlePositions: [],
-        subheadingIndex: null,
-        subheadingPositions: null,
-        bodyPositions: [],
-      },
-    ]);
+    // This result only matches on the main category.
+    {
+      id: 'test-id-1',
+      titlePositions: [],
+      subheadingIndex: null,
+      subheadingPositions: null,
+      bodyPositions: [],
+    },
+    // This result only matches on the second and third subcategories.
+    {
+      id: 'test-id-2',
+      titlePositions: [],
+      subheadingIndex: null,
+      subheadingPositions: null,
+      bodyPositions: [],
+    },
+  ]);
 });
 
 // Test that the number of search results is reduced when maxResults is
diff --git a/chromeos/components/help_app_ui/test/help_app_ui_browsertest.cc b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.cc
index 81d6a954..9b0fe03 100644
--- a/chromeos/components/help_app_ui/test/help_app_ui_browsertest.cc
+++ b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.cc
@@ -5,20 +5,37 @@
 #include "chromeos/components/help_app_ui/test/help_app_ui_browsertest.h"
 
 #include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/path_service.h"
+#include "chromeos/components/help_app_ui/help_app_ui.h"
 #include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/components/web_applications/test/sandboxed_web_ui_test_base.h"
 
-constexpr base::FilePath::CharType kHelpAppGuestTestApi[] = FILE_PATH_LITERAL(
-    "chromeos/components/help_app_ui/test/guest_query_receiver.js");
+// Path to test files loaded via the TestFileRequestFilter.
+constexpr base::FilePath::CharType kTestFileLocation[] =
+    FILE_PATH_LITERAL("chromeos/components/help_app_ui/test");
 
 // Test cases that run in the guest context.
-constexpr base::FilePath::CharType kGuestTestCases[] = FILE_PATH_LITERAL(
-    "chromeos/components/help_app_ui/test/help_app_guest_ui_browsertest.js");
+constexpr char kGuestTestCases[] = "help_app_guest_ui_browsertest.js";
+
+// Paths requested on the media-app origin that should be delivered by the test
+// handler.
+constexpr const char* kTestFiles[] = {
+    kGuestTestCases,
+    "help_app_ui_browsertest.js",
+    "driver.js",
+    "guest_query_receiver.js",
+};
 
 HelpAppUiBrowserTest::HelpAppUiBrowserTest()
     : SandboxedWebUiAppTestBase(chromeos::kChromeUIHelpAppURL,
                                 chromeos::kChromeUIHelpAppUntrustedURL,
-                                {base::FilePath(kHelpAppGuestTestApi),
-                                 base::FilePath(kGuestTestCases)}) {}
+                                {},
+                                kGuestTestCases) {
+  ConfigureDefaultTestRequestHandler(
+      base::FilePath(kTestFileLocation),
+      {std::begin(kTestFiles), std::end(kTestFiles)});
+}
 
 HelpAppUiBrowserTest::~HelpAppUiBrowserTest() = default;
diff --git a/chromeos/components/help_app_ui/test/help_app_ui_browsertest.js b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.js
index ef17b60..f9885a1 100644
--- a/chromeos/components/help_app_ui/test/help_app_ui_browsertest.js
+++ b/chromeos/components/help_app_ui/test/help_app_ui_browsertest.js
@@ -3,98 +3,41 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview Test suite for chrome://help-app.
+ * @fileoverview Test suite for chrome://help-app. The tests are actually
+ * invoked in help_app_ui_gtest_browsertest.js, this file simply packages up
+ * each tests logic into a single object that file can import.
+ *
+ * To add a new test to this file, add the test function to
+ * `HelpAppUIBrowserTest` and then invoke in in gtest_browsertest.js.
  */
+import {runTestInGuest} from './driver.js';
 
-GEN('#include "chromeos/components/help_app_ui/test/help_app_ui_browsertest.h"');
+const GUEST_ORIGIN = 'chrome-untrusted://help-app';
 
-GEN('#include "ash/constants/ash_features.h"');
-GEN('#include "content/public/test/browser_test.h"');
-
-const HOST_ORIGIN = 'chrome://help-app';
-
-var HelpAppUIBrowserTest = class extends testing.Test {
-  /** @override */
-  get browsePreload() {
-    return HOST_ORIGIN;
-  }
-
-  /** @override */
-  get extraLibraries() {
-    return [
-      ...super.extraLibraries,
-      '//chromeos/components/help_app_ui/test/driver.js',
-      '//ui/webui/resources/js/assert.js',
-    ];
-  }
-
-  /** @override */
-  get isAsync() {
-    return true;
-  }
-
-  /** @override */
-  get featureList() {
-    return {
-      enabled: [
-        'chromeos::features::kHelpAppLauncherSearch',
-        'chromeos::features::kHelpAppSearchServiceIntegration',
-      ]
-    };
-  }
-
-  /** @override */
-  get typedefCppFixture() {
-    return 'HelpAppUiBrowserTest';
-  }
-
-  /** @override */
-  get runAccessibilityChecks() {
-    return false;
-  }
+/** @struct */
+const HelpAppUIBrowserTest = {
+  /**
+   * Expose the runTestInGuest function to help_app_ui_gtest_browsertest.js so
+   * it can call it.
+   * @type function(string): !Promise<undefined>
+   */
+  runTestInGuest,
 };
 
+// Expose an old-style export for js2gtest.
+window['HelpAppUIBrowserTest_for_js2gtest'] = HelpAppUIBrowserTest;
+
 // Tests that chrome://help-app goes somewhere instead of 404ing or crashing.
-TEST_F('HelpAppUIBrowserTest', 'HasChromeSchemeURL', () => {
-  const guest = /** @type {!HTMLIFrameElement} */ (
-      document.querySelector('iframe'));
+HelpAppUIBrowserTest.HasChromeSchemeURL = () => {
+  const guest =
+      /** @type {!HTMLIFrameElement} */ (document.querySelector('iframe'));
 
   assertEquals(document.location.origin, HOST_ORIGIN);
   assertEquals(guest.src, GUEST_ORIGIN + '/');
-  testDone();
-});
+};
 
-// Tests that we have localised information in the HTML like title and lang.
-TEST_F('HelpAppUIBrowserTest', 'HasTitleAndLang', () => {
+// Tests that we have localized information in the HTML like title and lang.
+HelpAppUIBrowserTest.HasTitleAndLang = () => {
   assertEquals(document.documentElement.lang, 'en');
   assertEquals(document.title, 'Explore');
-  testDone();
-});
-
-// Test cases injected into the guest context.
-// See implementations in help_app_guest_ui_browsertest.js.
-
-TEST_F('HelpAppUIBrowserTest', 'GuestHasLang', async () => {
-  await runTestInGuest('GuestHasLang');
-  testDone();
-});
-
-TEST_F('HelpAppUIBrowserTest', 'GuestCanSearchWithHeadings', async () => {
-  await runTestInGuest('GuestCanSearchWithHeadings');
-  testDone();
-});
-
-TEST_F('HelpAppUIBrowserTest', 'GuestCanSearchWithCategories', async () => {
-  await runTestInGuest('GuestCanSearchWithCategories');
-  testDone();
-});
-
-TEST_F('HelpAppUIBrowserTest', 'GuestCanLimitMaxSearchResults', async () => {
-  await runTestInGuest('GuestCanLimitMaxSearchResults');
-  testDone();
-});
-
-TEST_F('HelpAppUIBrowserTest', 'GuestCanClearSearchIndex', async () => {
-  await runTestInGuest('GuestCanClearSearchIndex');
-  testDone();
-});
+};
diff --git a/chromeos/components/help_app_ui/test/help_app_ui_gtest_browsertest.js b/chromeos/components/help_app_ui/test/help_app_ui_gtest_browsertest.js
new file mode 100644
index 0000000..e7eb9f9
--- /dev/null
+++ b/chromeos/components/help_app_ui/test/help_app_ui_gtest_browsertest.js
@@ -0,0 +1,142 @@
+// 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.
+
+/**
+ * @fileoverview js2gtest wrapper for the chrome://help-app test suite. Actual
+ * test implementations live in help_app_ui_browsertest.js and
+ * help_app_guest_ui_browsertest.js.
+ */
+GEN('#include "chromeos/components/help_app_ui/test/help_app_ui_browsertest.h"');
+
+GEN('#include "ash/constants/ash_features.h"');
+GEN('#include "content/public/test/browser_test.h"');
+
+const HOST_ORIGIN = 'chrome://help-app';
+
+// js2gtest fixtures require var here (https://crbug.com/1033337).
+// eslint-disable-next-line no-var
+var HelpAppUIGtestBrowserTest = class extends testing.Test {
+  /** @override */
+  get browsePreload() {
+    return HOST_ORIGIN;
+  }
+
+  /** @override */
+  get isAsync() {
+    return true;
+  }
+
+  /** @override */
+  get featureList() {
+    return {
+      enabled: [
+        'chromeos::features::kHelpAppLauncherSearch',
+        'chromeos::features::kHelpAppSearchServiceIntegration',
+      ]
+    };
+  }
+
+  /** @override */
+  get typedefCppFixture() {
+    return 'HelpAppUiBrowserTest';
+  }
+
+  /** @override */
+  get runAccessibilityChecks() {
+    return false;
+  }
+};
+
+async function GetTestHarness() {
+  const testHarnessPolicy = trustedTypes.createPolicy('test-harness', {
+    createScriptURL: () => './help_app_ui_browsertest.js',
+  });
+
+  const tests =
+      /** @type {!HTMLScriptElement} */ (document.createElement('script'));
+  tests.src = testHarnessPolicy.createScriptURL('');
+  tests.type = 'module';
+  await new Promise((resolve, reject) => {
+    tests.onload = resolve;
+    tests.onerror = reject;
+    document.body.appendChild(tests);
+  });
+
+  // When help_app_ui_browsertest.js loads, it will add this onto the window.
+  return window['HelpAppUIBrowserTest_for_js2gtest'];
+}
+
+/**
+ * Small helper to run the `name` test function on the `HelpAppUIBrowserTest`
+ * object we get from `help_app_ui_browsertest.js`.
+ */
+async function runHelpAppTest(name, guest = false) {
+  const HelpAppUIBrowserTest = await GetTestHarness();
+  try {
+    if (guest) {
+      await HelpAppUIBrowserTest.runTestInGuest(name);
+    } else {
+      await HelpAppUIBrowserTest[name]();
+    }
+    testDone();
+  } catch (/* @type {Error} */ error) {
+    let message = 'exception';
+    if (typeof error === 'object' && error !== null && error['message']) {
+      message = error['message'];
+      console.log(error['stack']);
+    } else {
+      console.log(error);
+    }
+    /** @type {function(*)} */ (testDone)([false, message]);
+  }
+}
+
+function runHelpAppTestInGuest(name) {
+  return runHelpAppTest(name, true);
+}
+
+// Ensure every test body has a `TEST_F` call in this file.
+TEST_F('HelpAppUIGtestBrowserTest', 'ConsistencyCheck', async () => {
+  const HelpAppUIBrowserTest = await GetTestHarness();
+  const bodies =
+      /** @type {{testCaseBodies: Object}} */ (HelpAppUIGtestBrowserTest)
+          .testCaseBodies;
+  for (const f in HelpAppUIBrowserTest) {
+    if (f === 'runTestInGuest') {
+      continue;
+    }
+    if (!(f in bodies || `DISABLED_${f}` in bodies)) {
+      console.error(
+          `HelpAppUIBrowserTest.${f} is missing a TEST_F and will not be run.`);
+    }
+  }
+  testDone();
+});
+
+TEST_F('HelpAppUIGtestBrowserTest', 'HasChromeSchemeURL', () => {
+  runHelpAppTest('HasChromeSchemeURL');
+});
+
+TEST_F('HelpAppUIGtestBrowserTest', 'HasTitleAndLang', () => {
+  runHelpAppTest('HasTitleAndLang');
+});
+
+// Test cases injected into the guest context.
+// See implementations in `help_app_guest_ui_browsertest.js`.
+
+TEST_F('HelpAppUIGtestBrowserTest', 'GuestHasLang', () => {
+  runHelpAppTestInGuest('GuestHasLang');
+});
+
+TEST_F('HelpAppUIGtestBrowserTest', 'GuestCanSearchWithHeadings', () => {
+  runHelpAppTestInGuest('GuestCanSearchWithHeadings');
+});
+
+TEST_F('HelpAppUIGtestBrowserTest', 'GuestCanSearchWithCategories', () => {
+  runHelpAppTestInGuest('GuestCanSearchWithCategories');
+});
+
+TEST_F('HelpAppUIGtestBrowserTest', 'GuestCanClearSearchIndex', () => {
+  runHelpAppTestInGuest('GuestCanClearSearchIndex');
+});
diff --git a/chromeos/components/media_app_ui/resources/js/BUILD.gn b/chromeos/components/media_app_ui/resources/js/BUILD.gn
index f10bd76..8e34314 100644
--- a/chromeos/components/media_app_ui/resources/js/BUILD.gn
+++ b/chromeos/components/media_app_ui/resources/js/BUILD.gn
@@ -15,6 +15,7 @@
 copy("stage_static") {
   sources = [
     "../../../../../ui/file_manager/image_loader/piex_loader.js",
+    "//chromeos/components/system_apps/public/js/sandboxed_load_time_data.js",
     "app_context_test_support.js",
     "error_reporter.js",
     "launch.js",
@@ -22,7 +23,6 @@
     "piex_module.js",
     "piex_module_loader.js",
     "receiver.js",
-    "sandboxed_load_time_data.js",
   ]
   outputs = [ stage_folder + "/{{source_file_part}}" ]
 }
@@ -158,17 +158,14 @@
   deps = [ "//ui/file_manager/image_loader:piex_loader" ]
 }
 
-js_library("sandboxed_load_time_data") {
-}
-
 js_library("receiver") {
   externs_list = [ "media_app.externs.js" ]
   deps = [
     ":app_context_test_support",
     ":message_types.m",
     ":piex_module_loader",
-    ":sandboxed_load_time_data",
     "//chromeos/components/system_apps/public/js:message_pipe.m",
+    "//chromeos/components/system_apps/public/js:sandboxed_load_time_data",
   ]
 }
 
diff --git a/chromeos/components/media_app_ui/resources/js/sandboxed_load_time_data.js b/chromeos/components/media_app_ui/resources/js/sandboxed_load_time_data.js
deleted file mode 100644
index 101a94e..0000000
--- a/chromeos/components/media_app_ui/resources/js/sandboxed_load_time_data.js
+++ /dev/null
@@ -1,22 +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.
-
-/**
- * @fileoverview Minimal version of load_time_data.js for chrome-untrusted://
- * origins. They are sandboxed, so cannot use chrome://resources ("unable to
- * load local resource") and we don't want to maintain a "mirror" of all the
- * module dependencies on each chrome-untrusted:// origin. For simplicity, this
- * version lacks all the validation done by load_time_data.js, and just aims to
- * provide a compatible API.
- */
-
-const impl = {
-  data: {},  // Set by strings.js.
-  getValue: (id) => impl.data[id],
-  getString: (id) => /** @type{string} */ (impl.data[id]),
-  getBoolean: (id) => /** @type{boolean} */ (impl.data[id]),
-  getInteger: (id) => /** @type{number} */ (impl.data[id]),
-  valueExists: (id) => impl.data[id] !== undefined
-};
-window['loadTimeData'] = impl;
diff --git a/chromeos/components/system_apps/public/js/BUILD.gn b/chromeos/components/system_apps/public/js/BUILD.gn
index b246675..cc31c353 100644
--- a/chromeos/components/system_apps/public/js/BUILD.gn
+++ b/chromeos/components/system_apps/public/js/BUILD.gn
@@ -10,6 +10,9 @@
 js_library("message_pipe") {
 }
 
+js_library("sandboxed_load_time_data") {
+}
+
 js_library("message_pipe.m") {
   sources = [
     "$root_gen_dir/chromeos/components/system_apps/public/js/message_pipe.m.js",
diff --git a/chromeos/components/system_apps/public/js/sandboxed_load_time_data.js b/chromeos/components/system_apps/public/js/sandboxed_load_time_data.js
new file mode 100644
index 0000000..55f2544
--- /dev/null
+++ b/chromeos/components/system_apps/public/js/sandboxed_load_time_data.js
@@ -0,0 +1,37 @@
+// 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.
+
+/**
+ * @fileoverview Minimal version of load_time_data.js for chrome-untrusted://
+ * origins. They are sandboxed, so cannot use chrome://resources ("unable to
+ * load local resource") which load_time_data.js relies on through strings.js.
+ * Since we don't want to maintain a "mirror" of all the module dependencies on
+ * each chrome-untrusted:// origin. For simplicity, this version lacks all the
+ * validation done by load_time_data.js, and just aims to provide a compatible
+ * API.
+ */
+
+const impl = {
+  /**
+   * Needs to be separate from data since some tast tests expect a data_ field.
+   * TODO(b/192977700): Remove this.
+   * @type {!Object}
+   */
+  data_: {},
+  /**
+   * Used by strings.js to populate loadTimeData.
+   * Note we don't provide a getter since the original load_time_data object
+   * interface explicitly disallows reading the data object directly.
+   * @param {!Object} value
+   */
+  set data(value) {
+    impl.data_ = value;
+  },
+  getValue: (id) => impl.data_[id],
+  getString: (id) => /** @type{string} */ (impl.data_[id]),
+  getBoolean: (id) => /** @type{boolean} */ (impl.data_[id]),
+  getInteger: (id) => /** @type{number} */ (impl.data_[id]),
+  valueExists: (id) => impl.data_[id] !== undefined
+};
+window['loadTimeData'] = impl;
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 45c6aec..c32c33b4 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-93-4554.0-1625477697-benchmark-93.0.4571.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-93-4554.0-1625477697-benchmark-93.0.4572.0-r1-redacted.afdo.xz
diff --git a/chromeos/resources/BUILD.gn b/chromeos/resources/BUILD.gn
index 9e081af..1d48c2fe 100644
--- a/chromeos/resources/BUILD.gn
+++ b/chromeos/resources/BUILD.gn
@@ -144,6 +144,8 @@
 
   deps = [
     "//chromeos/components/help_app_ui:mojo_bindings_js",
+    "//chromeos/components/help_app_ui/resources:browser_proxy_rollup",
+    "//chromeos/components/help_app_ui/resources:receiver_rollup",
     "//chromeos/components/help_app_ui/search:mojo_bindings_js",
     "//chromeos/components/local_search_service/public/mojom:mojom_js",
   ]
diff --git a/chromeos/services/assistant/assistant_settings_impl.cc b/chromeos/services/assistant/assistant_settings_impl.cc
index 249cc62..5d33793 100644
--- a/chromeos/services/assistant/assistant_settings_impl.cc
+++ b/chromeos/services/assistant/assistant_settings_impl.cc
@@ -35,7 +35,15 @@
 
 void AssistantSettingsImpl::GetSettings(const std::string& selector,
                                         GetSettingsCallback callback) {
-  settings_controller().GetSettings(selector, std::move(callback));
+  settings_controller().GetSettings(selector, /*include_header=*/false,
+                                    std::move(callback));
+}
+
+void AssistantSettingsImpl::GetSettingsWithHeader(
+    const std::string& selector,
+    GetSettingsCallback callback) {
+  settings_controller().GetSettings(selector, /*include_header=*/true,
+                                    std::move(callback));
 }
 
 void AssistantSettingsImpl::UpdateSettings(const std::string& update,
diff --git a/chromeos/services/assistant/assistant_settings_impl.h b/chromeos/services/assistant/assistant_settings_impl.h
index c01839a..6db5892 100644
--- a/chromeos/services/assistant/assistant_settings_impl.h
+++ b/chromeos/services/assistant/assistant_settings_impl.h
@@ -40,6 +40,8 @@
   // AssistantSettings overrides:
   void GetSettings(const std::string& selector,
                    GetSettingsCallback callback) override;
+  void GetSettingsWithHeader(const std::string& selector,
+                             GetSettingsCallback callback) override;
   void UpdateSettings(const std::string& update,
                       UpdateSettingsCallback callback) override;
   void StartSpeakerIdEnrollment(
diff --git a/chromeos/services/assistant/public/cpp/assistant_settings.h b/chromeos/services/assistant/public/cpp/assistant_settings.h
index 38a7fbb..382ecb72 100644
--- a/chromeos/services/assistant/public/cpp/assistant_settings.h
+++ b/chromeos/services/assistant/public/cpp/assistant_settings.h
@@ -41,12 +41,17 @@
 
   // |selector| is a serialized proto of SettingsUiSelector, indicating which
   // settings sub-pages should be requested to the server.
-  // Return value is a serialized proto of SettingsUi, containing the settings
-  // sub-pages requested.
+  // For `GetSettings`, a serialized proto of SettingsUi containing the settings
+  // sub-pages requested is paased to `GetSettingsCallback`.
+  // For `GetSettingsWithHeader`, a serialized proto of GetSettingsUiResponse
+  // containing the settings and the header information is passed to
+  // `GetSettingsCallback`.
   // Send a request for the settings ui sub-pages indicated by the |selector|.
   using GetSettingsCallback = base::OnceCallback<void(const std::string&)>;
   virtual void GetSettings(const std::string& selector,
                            GetSettingsCallback callback) = 0;
+  virtual void GetSettingsWithHeader(const std::string& selector,
+                                     GetSettingsCallback callback) = 0;
 
   // |update| is a serialized proto of SettingsUiUpdate, indicating what kind
   // of updates should be applied to the settings.
diff --git a/chromeos/services/assistant/public/proto/BUILD.gn b/chromeos/services/assistant/public/proto/BUILD.gn
index d09e1e8..ca25ea7 100644
--- a/chromeos/services/assistant/public/proto/BUILD.gn
+++ b/chromeos/services/assistant/public/proto/BUILD.gn
@@ -14,6 +14,7 @@
     "email_opt_in_ui.proto",
     "gaia_user_context_ui.proto",
     "get_settings_ui.proto",
+    "header.proto",
     "settings_ui.proto",
   ]
 }
diff --git a/chromeos/services/assistant/public/proto/get_settings_ui.proto b/chromeos/services/assistant/public/proto/get_settings_ui.proto
index 9d5890a..156dacf 100644
--- a/chromeos/services/assistant/public/proto/get_settings_ui.proto
+++ b/chromeos/services/assistant/public/proto/get_settings_ui.proto
@@ -8,6 +8,7 @@
 
 package chromeos.assistant;
 
+import "header.proto";
 import "settings_ui.proto";
 
 // GetSettingsUi.
@@ -16,3 +17,9 @@
   // Required.
   optional SettingsUiSelector selector = 4;
 }
+
+message GetSettingsUiResponse {
+  optional SettingsUi settings = 1;
+
+  optional SettingsResponseHeader header = 2;
+}
diff --git a/chromeos/services/assistant/public/proto/header.proto b/chromeos/services/assistant/public/proto/header.proto
new file mode 100644
index 0000000..0996b1d
--- /dev/null
+++ b/chromeos/services/assistant/public/proto/header.proto
@@ -0,0 +1,21 @@
+// 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package chromeos.assistant;
+
+// Metadata for the response back to the user.
+message SettingsResponseHeader {
+  enum AcceptRejectLayout {
+    // Unspecified layout for buttons.
+    UNSPECIFIED = 0;
+    // Accept is filled on RHS, Reject is filled on LHS.
+    EQUAL_WEIGHT = 1;
+  }
+  // Controls the way the accept and reject buttons are rendered.
+  optional AcceptRejectLayout footer_button_layout = 2;
+}
diff --git a/chromeos/services/assistant/test_support/fake_assistant_settings_impl.cc b/chromeos/services/assistant/test_support/fake_assistant_settings_impl.cc
index 2b15d77..5526984 100644
--- a/chromeos/services/assistant/test_support/fake_assistant_settings_impl.cc
+++ b/chromeos/services/assistant/test_support/fake_assistant_settings_impl.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/callback.h"
+#include "chromeos/services/assistant/public/proto/get_settings_ui.pb.h"
 #include "chromeos/services/assistant/public/proto/settings_ui.pb.h"
 
 namespace chromeos {
@@ -25,6 +26,16 @@
   std::move(callback).Run(settings_ui.SerializeAsString());
 }
 
+void FakeAssistantSettingsImpl::GetSettingsWithHeader(
+    const std::string& selector,
+    GetSettingsCallback callback) {
+  // Create a fake response
+  assistant::GetSettingsUiResponse response;
+  response.mutable_settings()->mutable_consent_flow_ui()->set_consent_status(
+      ConsentFlowUi_ConsentStatus_ALREADY_CONSENTED);
+  std::move(callback).Run(response.SerializeAsString());
+}
+
 void FakeAssistantSettingsImpl::UpdateSettings(
     const std::string& update,
     UpdateSettingsCallback callback) {
diff --git a/chromeos/services/assistant/test_support/fake_assistant_settings_impl.h b/chromeos/services/assistant/test_support/fake_assistant_settings_impl.h
index 7c1d0dc9..d7e058a 100644
--- a/chromeos/services/assistant/test_support/fake_assistant_settings_impl.h
+++ b/chromeos/services/assistant/test_support/fake_assistant_settings_impl.h
@@ -22,6 +22,8 @@
   // AssistantSettings overrides:
   void GetSettings(const std::string& selector,
                    GetSettingsCallback callback) override;
+  void GetSettingsWithHeader(const std::string& selector,
+                             GetSettingsCallback callback) override;
   void UpdateSettings(const std::string& update,
                       UpdateSettingsCallback callback) override;
   void StartSpeakerIdEnrollment(
diff --git a/chromeos/services/assistant/test_support/fake_service_controller.cc b/chromeos/services/assistant/test_support/fake_service_controller.cc
index 0c7991f..465b463 100644
--- a/chromeos/services/assistant/test_support/fake_service_controller.cc
+++ b/chromeos/services/assistant/test_support/fake_service_controller.cc
@@ -122,6 +122,7 @@
 }
 
 void FakeServiceController::GetSettings(const std::string& selector,
+                                        bool include_header,
                                         GetSettingsCallback callback) {
   // Callback must be called to satisfy the mojom contract.
   std::move(callback).Run(std::string());
diff --git a/chromeos/services/assistant/test_support/fake_service_controller.h b/chromeos/services/assistant/test_support/fake_service_controller.h
index aafa4e2c..9b42ab12f 100644
--- a/chromeos/services/assistant/test_support/fake_service_controller.h
+++ b/chromeos/services/assistant/test_support/fake_service_controller.h
@@ -98,6 +98,7 @@
   void UpdateSettings(const std::string& settings,
                       UpdateSettingsCallback callback) override;
   void GetSettings(const std::string& selector,
+                   bool include_header,
                    GetSettingsCallback callback) override;
   void SetHotwordEnabled(bool value) override {}
 
diff --git a/chromeos/services/libassistant/public/mojom/settings_controller.mojom b/chromeos/services/libassistant/public/mojom/settings_controller.mojom
index 16e43b6..9e77b7d 100644
--- a/chromeos/services/libassistant/public/mojom/settings_controller.mojom
+++ b/chromeos/services/libassistant/public/mojom/settings_controller.mojom
@@ -31,10 +31,12 @@
   // Retrieve settings. |selector| is a serialized proto of
   // |SettingsUiSelector|, indicating which settings sub-pages should be
   // requested to the server.
-  // On success, the return value is a serialized proto of |SettingsUi|,
-  // containing the requested sub-pages.
+  // On success, the return value is a serialized proto of
+  // |GetSettingsUiResponse| when `include_header` is true; otherwisse, the
+  // return value is a serialized proto of |SettingsUi|, containing the
+  // requested sub-pages.
   // On failure, the return value is the empty string.
-  GetSettings(string selector) => (string result);
+  GetSettings(string selector, bool include_header) => (string result);
 
   // Update settings. |update| is a serialized proto of |SettingsUiUpdate|,
   // indicating the newly updated values.
@@ -49,4 +51,3 @@
   string gaia_id;
   string access_token;
 };
-
diff --git a/chromeos/services/libassistant/service_controller_unittest.cc b/chromeos/services/libassistant/service_controller_unittest.cc
index b5397f7..684aa45 100644
--- a/chromeos/services/libassistant/service_controller_unittest.cc
+++ b/chromeos/services/libassistant/service_controller_unittest.cc
@@ -112,7 +112,9 @@
   MOCK_METHOD(void, SetHotwordEnabled, (bool value));
   MOCK_METHOD(void,
               GetSettings,
-              (const std::string& selector, GetSettingsCallback callback));
+              (const std::string& selector,
+               bool include_header,
+               GetSettingsCallback callback));
   MOCK_METHOD(void,
               UpdateSettings,
               (const std::string& settings, UpdateSettingsCallback callback));
diff --git a/chromeos/services/libassistant/settings_controller.cc b/chromeos/services/libassistant/settings_controller.cc
index 865d25f3..aff4b7a 100644
--- a/chromeos/services/libassistant/settings_controller.cc
+++ b/chromeos/services/libassistant/settings_controller.cc
@@ -117,9 +117,9 @@
 // running or stopped.
 class GetSettingsResponseWaiter : public AbortableTask {
  public:
-  explicit GetSettingsResponseWaiter(
-      SettingsController::GetSettingsCallback callback)
-      : callback_(std::move(callback)) {}
+  GetSettingsResponseWaiter(SettingsController::GetSettingsCallback callback,
+                            bool include_header)
+      : callback_(std::move(callback)), include_header_(include_header) {}
 
   GetSettingsResponseWaiter(const GetSettingsResponseWaiter&) = delete;
   GetSettingsResponseWaiter& operator=(const GetSettingsResponseWaiter&) =
@@ -154,11 +154,16 @@
 
  private:
   void OnResponse(const assistant_client::VoicelessResponse& response) {
-    std::string result = assistant::UnwrapGetSettingsUiResponse(response);
+    std::string result =
+        assistant::UnwrapGetSettingsUiResponse(response, include_header_);
     std::move(callback_).Run(result);
   }
 
   SettingsController::GetSettingsCallback callback_;
+  // Whether to include header in response. If this is true, a serialized proto
+  // of GetSettingsUiResponse is passed to the callback; otherwise, a serialized
+  // proto of SettingsUi is passed to the callback.
+  bool include_header_;
   base::WeakPtrFactory<GetSettingsResponseWaiter> weak_factory_{this};
 };
 
@@ -247,9 +252,11 @@
 }
 
 void SettingsController::GetSettings(const std::string& selector,
+                                     bool include_header,
                                      GetSettingsCallback callback) {
-  auto* waiter = pending_response_waiters_.Add(
-      std::make_unique<GetSettingsResponseWaiter>(std::move(callback)));
+  auto* waiter =
+      pending_response_waiters_.Add(std::make_unique<GetSettingsResponseWaiter>(
+          std::move(callback), include_header));
   waiter->SendRequest(assistant_manager_internal_, selector);
 }
 
diff --git a/chromeos/services/libassistant/settings_controller.h b/chromeos/services/libassistant/settings_controller.h
index 7fe0ec6..730b237 100644
--- a/chromeos/services/libassistant/settings_controller.h
+++ b/chromeos/services/libassistant/settings_controller.h
@@ -40,6 +40,7 @@
   void SetSpokenFeedbackEnabled(bool value) override;
   void SetHotwordEnabled(bool value) override;
   void GetSettings(const std::string& selector,
+                   bool include_header,
                    GetSettingsCallback callback) override;
   void UpdateSettings(const std::string& settings,
                       UpdateSettingsCallback callback) override;
diff --git a/chromeos/strings/chromeos_strings_af.xtb b/chromeos/strings/chromeos_strings_af.xtb
index 669570f..f75649b 100644
--- a/chromeos/strings/chromeos_strings_af.xtb
+++ b/chromeos/strings/chromeos_strings_af.xtb
@@ -234,6 +234,7 @@
 <translation id="5669267381087807207">Aktiveer tans</translation>
 <translation id="5670702108860320605">BSSID</translation>
 <translation id="5691511426247308406">Familie</translation>
+<translation id="5707900041990977207"><ph name="CURRENT_PAGE" /> van <ph name="TOTAL_PAGES" /></translation>
 <translation id="5752751666635965375">Maak jou eie speletjie</translation>
 <translation id="5760715441271661976">Portaalstatus</translation>
 <translation id="5832805196449965646">Voeg persoon by</translation>
@@ -296,6 +297,7 @@
 <translation id="6911383237894364323">Kan nie aan mediabedieners koppel nie</translation>
 <translation id="6957231940976260713">Diensnaam</translation>
 <translation id="6977381486153291903">Fermwarehersiening</translation>
+<translation id="6982876849933694860">Gaan na <ph name="BEGIN_LINK" />Instellings<ph name="END_LINK" /> om 'n nuwe verbinding op te stel.</translation>
 <translation id="7028979494427204405"><ph name="MANAGER" /> bestuur hierdie toestel en het toegang tot alle gebruikeraktiwiteit, insluitend webblaaie wat besoek is, wagwoorde en e-pos.</translation>
 <translation id="7040230719604914234">Diensverskaffer</translation>
 <translation id="7059230779847288458">Laai tans; <ph name="TIME_VALUE" /> tot vol</translation>
diff --git a/chromeos/strings/chromeos_strings_ja.xtb b/chromeos/strings/chromeos_strings_ja.xtb
index 521bd723..0d2992e 100644
--- a/chromeos/strings/chromeos_strings_ja.xtb
+++ b/chromeos/strings/chromeos_strings_ja.xtb
@@ -234,6 +234,7 @@
 <translation id="5669267381087807207">有効化中</translation>
 <translation id="5670702108860320605">BSSID</translation>
 <translation id="5691511426247308406">ファミリー</translation>
+<translation id="5707900041990977207"><ph name="CURRENT_PAGE" />/<ph name="TOTAL_PAGES" /></translation>
 <translation id="5752751666635965375">独自のゲームを作成する</translation>
 <translation id="5760715441271661976">ポータル状態</translation>
 <translation id="5832805196449965646">ユーザーを追加</translation>
@@ -296,6 +297,7 @@
 <translation id="6911383237894364323">メディア サーバーに接続できません</translation>
 <translation id="6957231940976260713">サービス名</translation>
 <translation id="6977381486153291903">ファームウェア リビジョン</translation>
+<translation id="6982876849933694860">新しい接続の設定は<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />で行うことができます。</translation>
 <translation id="7028979494427204405"><ph name="MANAGER" /> はこのデバイスを管理しており、閲覧したウェブページ、パスワード、メールなど、すべてのユーザー アクティビティにアクセスできます。</translation>
 <translation id="7040230719604914234">携帯通信会社</translation>
 <translation id="7059230779847288458">充電中、フル充電まで <ph name="TIME_VALUE" /></translation>
diff --git a/chromeos/strings/chromeos_strings_mr.xtb b/chromeos/strings/chromeos_strings_mr.xtb
index 043624d..aa60787 100644
--- a/chromeos/strings/chromeos_strings_mr.xtb
+++ b/chromeos/strings/chromeos_strings_mr.xtb
@@ -63,6 +63,7 @@
 <translation id="2224337661447660594">इंटरनेट नाही</translation>
 <translation id="2230051135190148440">CHAP</translation>
 <translation id="225692081236532131">सक्रियन स्थिती</translation>
+<translation id="2294675138977897428">कोणतेही इथरनेट कनेक्‍शन डिटेक्ट झाले नाही</translation>
 <translation id="2326139988748364651"><ph name="RESOLUTION_VALUE" /> dpi</translation>
 <translation id="2338501278241028356">जवळपासचे डिव्हाइस शोधण्यासाठी ब्लूटूथ सुरू करा</translation>
 <translation id="2364498172489649528">पास झाले</translation>
@@ -279,6 +280,7 @@
 <translation id="6527081081771465939">अनोळखी वायफाय सुरक्षा प्रोटोकॉल</translation>
 <translation id="65587193855025101">फ्लॅटबेड</translation>
 <translation id="6564646048574748301">अयशस्वी झाले - प्रिंटरशी कनेक्ट करता आले नाही</translation>
+<translation id="6603230386432466813">कनेक्ट करताना समस्या येत आहे का?</translation>
 <translation id="6618744767048954150">रन होत आहे</translation>
 <translation id="6620487321149975369">प्रिंट जॉब मॅन्‍युअली काढून टाकेपर्यंत इतिहासामध्ये दिसतील</translation>
 <translation id="6643016212128521049">साफ करा</translation>
diff --git a/chromeos/strings/chromeos_strings_si.xtb b/chromeos/strings/chromeos_strings_si.xtb
index a455af05..549795ca 100644
--- a/chromeos/strings/chromeos_strings_si.xtb
+++ b/chromeos/strings/chromeos_strings_si.xtb
@@ -234,6 +234,7 @@
 <translation id="5669267381087807207">සක්‍රීය වෙමින්...</translation>
 <translation id="5670702108860320605">BSSID</translation>
 <translation id="5691511426247308406">පවුල</translation>
+<translation id="5707900041990977207"><ph name="CURRENT_PAGE" />න් <ph name="TOTAL_PAGES" /></translation>
 <translation id="5752751666635965375">ඔබේම ක්‍රීඩාව සාදන්න</translation>
 <translation id="5760715441271661976">ද්වාර තත්වය</translation>
 <translation id="5832805196449965646">පුද්ගලයා එක් කරන්න</translation>
@@ -296,6 +297,7 @@
 <translation id="6911383237894364323">මාධ්‍ය සේවාදායක වෙත සබැඳීමට නොහැකිය</translation>
 <translation id="6957231940976260713">සේවා නාමය</translation>
 <translation id="6977381486153291903">නිත්‍ය මෘදුකාංග සංශෝධනය</translation>
+<translation id="6982876849933694860">නව සබැඳුමක් පිහිටුවීමට <ph name="BEGIN_LINK" />සැකසීම්<ph name="END_LINK" /> වෙත යන්න.</translation>
 <translation id="7028979494427204405"><ph name="MANAGER" /> මෙම උපාංගය කළමනාකරණය කරන අතර, එයට පිවිසි වෙබ් පිටු, මුරපද සහ ඉ-තැපෑල ඇතුළුව සියලු පරිශීලක ක්‍රියාකාරකම් වෙත ප්‍රවේශය තිබේ.</translation>
 <translation id="7040230719604914234">මෙහෙයවනය</translation>
 <translation id="7059230779847288458">ආරෝපණය වෙමින්, සම්පූර්ණ වන තෙක් <ph name="TIME_VALUE" /></translation>
diff --git a/chromeos/strings/chromeos_strings_sw.xtb b/chromeos/strings/chromeos_strings_sw.xtb
index 1918b2a..4c13d0c 100644
--- a/chromeos/strings/chromeos_strings_sw.xtb
+++ b/chromeos/strings/chromeos_strings_sw.xtb
@@ -233,6 +233,7 @@
 <translation id="5669267381087807207">Inawashwa</translation>
 <translation id="5670702108860320605">BSSID</translation>
 <translation id="5691511426247308406">Familia</translation>
+<translation id="5707900041990977207"><ph name="CURRENT_PAGE" /> kati ya <ph name="TOTAL_PAGES" /></translation>
 <translation id="5752751666635965375">Tengeneza mchezo wako</translation>
 <translation id="5760715441271661976">Hali ya Ukurasa wa Mwanzo</translation>
 <translation id="5832805196449965646">Ongeza Mtumiaji Mwingine</translation>
@@ -295,6 +296,7 @@
 <translation id="6911383237894364323">Imeshindwa kuunganisha kwenye seva za maudhui</translation>
 <translation id="6957231940976260713">Jina la huduma</translation>
 <translation id="6977381486153291903">Sahihisho la programu dhibiti</translation>
+<translation id="6982876849933694860">Ili uweke mipangilio ya muunganisho mpya, nenda kwenye <ph name="BEGIN_LINK" />Mipangilio<ph name="END_LINK" />.</translation>
 <translation id="7028979494427204405"><ph name="MANAGER" /> hudhibiti kifaa hiki na ina idhini ya kufikia shughuli zote za mtumiaji, zikiwemo kurasa za wavuti alizotembelea, manenosiri na anwani za barua pepe.</translation>
 <translation id="7040230719604914234">Mtoa huduma</translation>
 <translation id="7059230779847288458">Inachaji, imebakisha <ph name="TIME_VALUE" /> ijae</translation>
diff --git a/chromeos/strings/chromeos_strings_uz.xtb b/chromeos/strings/chromeos_strings_uz.xtb
index 4a609523..776b4c0 100644
--- a/chromeos/strings/chromeos_strings_uz.xtb
+++ b/chromeos/strings/chromeos_strings_uz.xtb
@@ -234,6 +234,7 @@
 <translation id="5669267381087807207">Faollashmoqda</translation>
 <translation id="5670702108860320605">BSSID</translation>
 <translation id="5691511426247308406">Oilaviy</translation>
+<translation id="5707900041990977207"><ph name="CURRENT_PAGE" /> / <ph name="TOTAL_PAGES" /></translation>
 <translation id="5752751666635965375">Shaxsiy oʻyin quring</translation>
 <translation id="5760715441271661976">Portal holati</translation>
 <translation id="5832805196449965646">Foydalanuvchi qo‘shish</translation>
@@ -296,6 +297,7 @@
 <translation id="6911383237894364323">Media serverlarga ulana olmadi</translation>
 <translation id="6957231940976260713">Xizmat nomi</translation>
 <translation id="6977381486153291903">Mikrodastur versiyasi</translation>
+<translation id="6982876849933694860">Yangi ulanishni sozlash uchun <ph name="BEGIN_LINK" />Sozlamalar<ph name="END_LINK" /> sahifasini oching.</translation>
 <translation id="7028979494427204405">Bu qurilma va uning foydalanuvchilari harakatlari, ochilgan sahifalar, parollar va emaillar <ph name="MANAGER" /> domenida boshqariladi.</translation>
 <translation id="7040230719604914234">Operator</translation>
 <translation id="7059230779847288458">Quvvat olmoqda (<ph name="TIME_VALUE" /> qoldi)</translation>
diff --git a/chromeos/strings/chromeos_strings_zh-HK.xtb b/chromeos/strings/chromeos_strings_zh-HK.xtb
index f24eeb8..c5eafafd 100644
--- a/chromeos/strings/chromeos_strings_zh-HK.xtb
+++ b/chromeos/strings/chromeos_strings_zh-HK.xtb
@@ -234,6 +234,7 @@
 <translation id="5669267381087807207">啟用</translation>
 <translation id="5670702108860320605">BSSID</translation>
 <translation id="5691511426247308406">家庭</translation>
+<translation id="5707900041990977207"><ph name="CURRENT_PAGE" />/<ph name="TOTAL_PAGES" /></translation>
 <translation id="5752751666635965375">自製遊戲</translation>
 <translation id="5760715441271661976">入口網站狀態</translation>
 <translation id="5832805196449965646">新增使用者</translation>
@@ -296,6 +297,7 @@
 <translation id="6911383237894364323">無法連線至媒體伺服器</translation>
 <translation id="6957231940976260713">服務名稱</translation>
 <translation id="6977381486153291903">韌體版本</translation>
+<translation id="6982876849933694860">如要設定新連線,請前往「<ph name="BEGIN_LINK" />設定<ph name="END_LINK" />」。</translation>
 <translation id="7028979494427204405"><ph name="MANAGER" /> 會管理此裝置並可存取所有使用者活動,包括網頁瀏覽記錄、密碼和電郵。</translation>
 <translation id="7040230719604914234">流動網絡供應商</translation>
 <translation id="7059230779847288458">充電中,<ph name="TIME_VALUE" />後完成充電</translation>
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index 4659586c..29f2a1a 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -13,10 +13,10 @@
   "hwsec.ChapsRSAPSS",
 
   # crbug.com/1167243
-  "ui.ChromeLogin",
+  "login.Chrome",
 
   # crbug.com/1115622
-  "ui.ChromeLoginGAIA",
+  "login.ChromeGAIA",
 
   # crbug.com/1099695
   "platform.Drivefs",
diff --git a/components/arc/arc_util_unittest.cc b/components/arc/arc_util_unittest.cc
index eb313358..2ffcaab 100644
--- a/components/arc/arc_util_unittest.cc
+++ b/components/arc/arc_util_unittest.cc
@@ -370,7 +370,6 @@
       {user_manager::USER_TYPE_REGULAR, true},
       {user_manager::USER_TYPE_GUEST, false},
       {user_manager::USER_TYPE_PUBLIC_ACCOUNT, true},
-      {user_manager::USER_TYPE_SUPERVISED_DEPRECATED, false},
       {user_manager::USER_TYPE_KIOSK_APP, false},
       {user_manager::USER_TYPE_CHILD, true},
       {user_manager::USER_TYPE_ARC_KIOSK_APP, true},
diff --git a/components/arc/compat_mode/resize_toggle_menu.cc b/components/arc/compat_mode/resize_toggle_menu.cc
index d819e21..3d98cbd 100644
--- a/components/arc/compat_mode/resize_toggle_menu.cc
+++ b/components/arc/compat_mode/resize_toggle_menu.cc
@@ -53,16 +53,10 @@
                                                  const gfx::VectorIcon& icon,
                                                  int title_string_id)
     : views::Button(std::move(callback)), icon_(icon) {
-  SetLayoutManager(std::make_unique<views::FlexLayout>())
-      ->SetOrientation(views::LayoutOrientation::kVertical)
-      .SetMainAxisAlignment(views::LayoutAlignment::kCenter)
-      .SetCrossAxisAlignment(views::LayoutAlignment::kStretch)
-      .SetInteriorMargin(gfx::Insets(16, 0, 14, 0))
-      .SetDefault(
-          views::kFlexBehaviorKey,
-          views::FlexSpecification(views::MinimumFlexSizeRule::kPreferred,
-                                   views::MaximumFlexSizeRule::kPreferred,
-                                   /*adjust_height_for_width=*/true));
+  // Don't use FlexLayout here because it breaks the focus ring's bounds.
+  // TODO(b/193195191): Investigate why we can't use FlexLayout.
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical, gfx::Insets(16, 0, 14, 0)));
 
   AddChildView(views::Builder<views::ImageView>()
                    .CopyAddressTo(&icon_view_)
diff --git a/components/enterprise/browser/reporting/policy_info.cc b/components/enterprise/browser/reporting/policy_info.cc
index f699733..76122c7 100644
--- a/components/enterprise/browser/reporting/policy_info.cc
+++ b/components/enterprise/browser/reporting/policy_info.cc
@@ -65,6 +65,9 @@
       return em::Policy_PolicySource_SOURCE_MERGED;
     case policy::POLICY_SOURCE_CLOUD_FROM_ASH:
       return em::Policy_PolicySource_SOURCE_CLOUD_FROM_ASH;
+    case policy::POLICY_SOURCE_RESTRICTED_MANAGED_GUEST_SESSION_OVERRIDE:
+      return em::
+          Policy_PolicySource_SOURCE_RESTRICTED_MANAGED_GUEST_SESSION_OVERRIDE;
     case policy::POLICY_SOURCE_COUNT:
       NOTREACHED();
       return em::Policy_PolicySource_SOURCE_UNKNOWN;
diff --git a/components/password_manager/core/browser/mock_password_store.cc b/components/password_manager/core/browser/mock_password_store.cc
index f312f25..9c2f4d0 100644
--- a/components/password_manager/core/browser/mock_password_store.cc
+++ b/components/password_manager/core/browser/mock_password_store.cc
@@ -17,8 +17,4 @@
   return base::SequencedTaskRunnerHandle::Get();
 }
 
-bool MockPasswordStore::InitOnBackgroundSequence() {
-  return true;
-}
-
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h
index f344f6ff..92ae4927 100644
--- a/components/password_manager/core/browser/mock_password_store.h
+++ b/components/password_manager/core/browser/mock_password_store.h
@@ -26,79 +26,115 @@
 
   MOCK_METHOD(void, GetAutofillableLogins, (PasswordStoreConsumer*), (override));
 
-  MOCK_METHOD1(RemoveLogin, void(const PasswordForm&));
-  MOCK_METHOD2(Unblocklist, void(const PasswordFormDigest&, base::OnceClosure));
-  MOCK_METHOD2(GetLogins,
-               void(const PasswordFormDigest&, PasswordStoreConsumer*));
-  MOCK_METHOD1(AddLogin, void(const PasswordForm&));
-  MOCK_METHOD1(UpdateLogin, void(const PasswordForm&));
-  MOCK_METHOD2(UpdateLoginWithPrimaryKey,
-               void(const PasswordForm&, const PasswordForm&));
-  MOCK_METHOD3(ReportMetrics, void(const std::string&, bool, bool));
-  MOCK_METHOD3(ReportMetricsImpl,
-               void(const std::string&, bool, BulkCheckDone));
-  MOCK_METHOD2(AddLoginImpl,
-               PasswordStoreChangeList(const PasswordForm&,
-                                       AddLoginError* error));
-  MOCK_METHOD2(UpdateLoginImpl,
-               PasswordStoreChangeList(const PasswordForm&,
-                                       UpdateLoginError* error));
-  MOCK_METHOD1(RemoveLoginImpl, PasswordStoreChangeList(const PasswordForm&));
-  MOCK_METHOD3(
-      RemoveLoginsByURLAndTimeImpl,
-      PasswordStoreChangeList(const base::RepeatingCallback<bool(const GURL&)>&,
-                              base::Time,
-                              base::Time));
-  MOCK_METHOD2(RemoveLoginsCreatedBetweenImpl,
-               PasswordStoreChangeList(base::Time, base::Time));
-  MOCK_METHOD3(RemoveStatisticsByOriginAndTimeImpl,
-               bool(const base::RepeatingCallback<bool(const GURL&)>&,
-                    base::Time,
-                    base::Time));
-  MOCK_METHOD1(DisableAutoSignInForOriginsImpl,
-               PasswordStoreChangeList(
-                   const base::RepeatingCallback<bool(const GURL&)>&));
+  MOCK_METHOD(void, RemoveLogin, (const PasswordForm&), (override));
+  MOCK_METHOD(void,
+              Unblocklist,
+              (const PasswordFormDigest&, base::OnceClosure),
+              (override));
+  MOCK_METHOD(void,
+              GetLogins,
+              (const PasswordFormDigest&, PasswordStoreConsumer*),
+              (override));
+  MOCK_METHOD(void, AddLogin, (const PasswordForm&), (override));
+  MOCK_METHOD(void, UpdateLogin, (const PasswordForm&), (override));
+  MOCK_METHOD(void,
+              UpdateLoginWithPrimaryKey,
+              (const PasswordForm&, const PasswordForm&),
+              (override));
+  MOCK_METHOD(void,
+              ReportMetrics,
+              (const std::string&, bool, bool),
+              (override));
+  MOCK_METHOD(void,
+              ReportMetricsImpl,
+              (const std::string&, bool, BulkCheckDone),
+              (override));
+  MOCK_METHOD(PasswordStoreChangeList,
+              AddLoginImpl,
+              (const PasswordForm&, AddLoginError* error),
+              (override));
+  MOCK_METHOD(PasswordStoreChangeList,
+              UpdateLoginImpl,
+              (const PasswordForm&, UpdateLoginError* error),
+              (override));
+  MOCK_METHOD(PasswordStoreChangeList,
+              RemoveLoginImpl,
+              (const PasswordForm&),
+              (override));
+  MOCK_METHOD(PasswordStoreChangeList,
+              RemoveLoginsByURLAndTimeImpl,
+              (const base::RepeatingCallback<bool(const GURL&)>&,
+               base::Time,
+               base::Time),
+              (override));
+  MOCK_METHOD(PasswordStoreChangeList,
+              RemoveLoginsCreatedBetweenImpl,
+              (base::Time, base::Time),
+              (override));
+  MOCK_METHOD(bool,
+              RemoveStatisticsByOriginAndTimeImpl,
+              (const base::RepeatingCallback<bool(const GURL&)>&,
+               base::Time,
+               base::Time),
+              (override));
+  MOCK_METHOD(PasswordStoreChangeList,
+              DisableAutoSignInForOriginsImpl,
+              (const base::RepeatingCallback<bool(const GURL&)>&),
+              (override));
   std::vector<std::unique_ptr<PasswordForm>> FillMatchingLogins(
       const PasswordFormDigest& form) override {
     return std::vector<std::unique_ptr<PasswordForm>>();
   }
-  MOCK_METHOD1(
-      FillMatchingLoginsByPassword,
-      std::vector<std::unique_ptr<PasswordForm>>(const std::u16string&));
-  MOCK_METHOD1(FillAutofillableLogins,
-               bool(std::vector<std::unique_ptr<PasswordForm>>*));
-  MOCK_METHOD1(FillBlocklistLogins,
-               bool(std::vector<std::unique_ptr<PasswordForm>>*));
-  MOCK_METHOD0(DeleteUndecryptableLogins, DatabaseCleanupResult());
-  MOCK_METHOD1(NotifyLoginsChanged, void(const PasswordStoreChangeList&));
-  MOCK_METHOD0(NotifyInsecureCredentialsChanged, void());
-  MOCK_METHOD1(GetSiteStatsImpl,
-               std::vector<InteractionsStats>(const GURL& origin_domain));
-  MOCK_METHOD1(AddSiteStatsImpl, void(const InteractionsStats&));
-  MOCK_METHOD1(RemoveSiteStatsImpl, void(const GURL&));
-  MOCK_METHOD1(AddInsecureCredentialImpl,
-               PasswordStoreChangeList(const InsecureCredential&));
-  MOCK_METHOD3(RemoveInsecureCredentialsImpl,
-               PasswordStoreChangeList(const std::string&,
-                                       const std::u16string&,
-                                       RemoveInsecureCredentialsReason));
-  MOCK_METHOD0(GetAllInsecureCredentialsImpl,
-               std::vector<InsecureCredential>());
-  MOCK_METHOD1(
-      GetMatchingInsecureCredentialsImpl,
-      std::vector<InsecureCredential>(const std::string& signon_realm));
-  MOCK_METHOD3(RemoveCompromisedCredentialsByUrlAndTimeImpl,
-               bool(const base::RepeatingCallback<bool(const GURL&)>&,
-                    base::Time,
-                    base::Time));
-  MOCK_METHOD1(AddFieldInfoImpl, void(const FieldInfo&));
-  MOCK_METHOD0(GetAllFieldInfoImpl, std::vector<FieldInfo>());
-  MOCK_METHOD2(RemoveFieldInfoByTimeImpl, void(base::Time, base::Time));
-  MOCK_METHOD0(IsEmpty, bool());
-  MOCK_METHOD1(GetAllLoginsWithAffiliationAndBrandingInformation,
-               void(PasswordStoreConsumer*));
+  MOCK_METHOD(std::vector<std::unique_ptr<PasswordForm>>,
+              FillMatchingLoginsByPassword,
+              (const std::u16string&),
+              (override));
+  MOCK_METHOD(DatabaseCleanupResult, DeleteUndecryptableLogins, (), (override));
+  MOCK_METHOD(void,
+              NotifyLoginsChanged,
+              (const PasswordStoreChangeList&),
+              (override));
+  MOCK_METHOD(std::vector<InteractionsStats>,
+              GetSiteStatsImpl,
+              (const GURL& origin_domain),
+              (override));
+  MOCK_METHOD(void, AddSiteStatsImpl, (const InteractionsStats&));
+  MOCK_METHOD(void, RemoveSiteStatsImpl, (const GURL&), (override));
+  MOCK_METHOD(PasswordStoreChangeList,
+              AddInsecureCredentialImpl,
+              (const InsecureCredential&),
+              (override));
+  MOCK_METHOD(PasswordStoreChangeList,
+              RemoveInsecureCredentialsImpl,
+              (const std::string&,
+               const std::u16string&,
+               RemoveInsecureCredentialsReason),
+              (override));
+  MOCK_METHOD(std::vector<InsecureCredential>,
+              GetAllInsecureCredentialsImpl,
+              (),
+              (override));
+  MOCK_METHOD(std::vector<InsecureCredential>,
+              GetMatchingInsecureCredentialsImpl,
+              (const std::string&),
+              (override));
+  MOCK_METHOD(void, AddFieldInfoImpl, (const FieldInfo&), (override));
+  MOCK_METHOD(std::vector<FieldInfo>, GetAllFieldInfoImpl, (), (override));
+  MOCK_METHOD(void,
+              RemoveFieldInfoByTimeImpl,
+              (base::Time, base::Time),
+              (override));
+  MOCK_METHOD(bool, IsEmpty, (), (override));
+  MOCK_METHOD(base::WeakPtr<syncer::ModelTypeControllerDelegate>,
+              GetSyncControllerDelegateOnBackgroundSequence,
+              (),
+              (override));
+  MOCK_METHOD(void,
+              GetAllLoginsWithAffiliationAndBrandingInformation,
+              (PasswordStoreConsumer*),
+              (override));
 
-  MOCK_CONST_METHOD0(IsAbleToSavePasswords, bool());
+  MOCK_METHOD(bool, IsAbleToSavePasswords, (), (override, const));
 
   // TODO(crbug.bom/1226042): Remove this after PasswordStore no longer
   // inherits PasswordStoreSync.
@@ -122,17 +158,27 @@
               RemoveLoginSync,
               (const PasswordForm& form),
               (override));
-  MOCK_METHOD0(BeginTransaction, bool());
-  MOCK_METHOD0(RollbackTransaction, void());
-  MOCK_METHOD0(CommitTransaction, bool());
-  MOCK_METHOD1(ReadAllLogins, FormRetrievalResult(PrimaryKeyToFormMap*));
-  MOCK_METHOD1(ReadSecurityIssues,
-               std::vector<InsecureCredential>(FormPrimaryKey));
-  MOCK_METHOD1(RemoveLoginByPrimaryKeySync,
-               PasswordStoreChangeList(FormPrimaryKey));
-  MOCK_METHOD0(GetMetadataStore, PasswordStoreSync::MetadataStore*());
-  MOCK_CONST_METHOD0(IsAccountStore, bool());
-  MOCK_METHOD0(DeleteAndRecreateDatabaseFile, bool());
+  MOCK_METHOD(bool, BeginTransaction, ());
+  MOCK_METHOD(void, RollbackTransaction, (), (override));
+  MOCK_METHOD(bool, CommitTransaction, (), (override));
+  MOCK_METHOD(FormRetrievalResult,
+              ReadAllLogins,
+              (PrimaryKeyToFormMap*),
+              (override));
+  MOCK_METHOD(std::vector<InsecureCredential>,
+              ReadSecurityIssues,
+              (FormPrimaryKey),
+              (override));
+  MOCK_METHOD(PasswordStoreChangeList,
+              RemoveLoginByPrimaryKeySync,
+              (FormPrimaryKey),
+              (override));
+  MOCK_METHOD(PasswordStoreSync::MetadataStore*,
+              GetMetadataStore,
+              (),
+              (override));
+  MOCK_METHOD(bool, IsAccountStore, (), (override, const));
+  MOCK_METHOD(bool, DeleteAndRecreateDatabaseFile, (), (override));
 
   PasswordStoreSync* GetSyncInterface() { return this; }
 
@@ -143,7 +189,6 @@
   // PasswordStore:
   scoped_refptr<base::SequencedTaskRunner> CreateBackgroundTaskRunner()
       const override;
-  bool InitOnBackgroundSequence() override;
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_bubble_experiment.cc b/components/password_manager/core/browser/password_bubble_experiment.cc
index f0cf92a..1772a75 100644
--- a/components/password_manager/core/browser/password_bubble_experiment.cc
+++ b/components/password_manager/core/browser/password_bubble_experiment.cc
@@ -24,17 +24,6 @@
 
 namespace password_bubble_experiment {
 
-void RegisterPrefs(PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(
-      password_manager::prefs::kWasSignInPasswordPromoClicked, false);
-
-  registry->RegisterIntegerPref(
-      password_manager::prefs::kNumberSignInPasswordPromoShown, 0);
-
-  registry->RegisterBooleanPref(
-      password_manager::prefs::kSignInPasswordPromoRevive, false);
-}
-
 int GetSmartBubbleDismissalThreshold() {
   return 3;
 }
@@ -59,46 +48,4 @@
                     false);
 }
 
-bool ShouldShowChromeSignInPasswordPromo(
-    PrefService* prefs,
-    const syncer::SyncService* sync_service) {
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
-  // If the account-scoped storage for passwords is enabled, then the user
-  // doesn't need to enable the full Sync feature to get their account
-  // passwords, so suppress the promo in this case.
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kEnablePasswordsAccountStorage)) {
-    return false;
-  }
-
-  if (!prefs->GetBoolean(prefs::kSigninAllowed))
-    return false;
-
-  if (!sync_service ||
-      sync_service->HasDisableReason(
-          syncer::SyncService::DISABLE_REASON_PLATFORM_OVERRIDE) ||
-      sync_service->HasDisableReason(
-          syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY) ||
-      sync_service->GetUserSettings()->IsFirstSetupComplete()) {
-    return false;
-  }
-  if (!prefs->GetBoolean(password_manager::prefs::kSignInPasswordPromoRevive)) {
-    // Reset the counters so that the promo is shown again.
-    prefs->SetBoolean(password_manager::prefs::kSignInPasswordPromoRevive,
-                      true);
-    prefs->ClearPref(password_manager::prefs::kWasSignInPasswordPromoClicked);
-    prefs->ClearPref(password_manager::prefs::kNumberSignInPasswordPromoShown);
-  }
-  // Don't show the promo more than 3 times.
-  constexpr int kThreshold = 3;
-  return !prefs->GetBoolean(
-             password_manager::prefs::kWasSignInPasswordPromoClicked) &&
-         prefs->GetInteger(
-             password_manager::prefs::kNumberSignInPasswordPromoShown) <
-             kThreshold;
-#else
-  return false;
-#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
-}
-
 }  // namespace password_bubble_experiment
diff --git a/components/password_manager/core/browser/password_bubble_experiment.h b/components/password_manager/core/browser/password_bubble_experiment.h
index fadf729..e069a9ce 100644
--- a/components/password_manager/core/browser/password_bubble_experiment.h
+++ b/components/password_manager/core/browser/password_bubble_experiment.h
@@ -5,7 +5,6 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_BUBBLE_EXPERIMENT_H_
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_BUBBLE_EXPERIMENT_H_
 
-class PrefRegistrySimple;
 class PrefService;
 
 namespace syncer {
@@ -14,11 +13,6 @@
 
 namespace password_bubble_experiment {
 
-// Registers prefs which controls appearance of the first run experience for the
-// Smart Lock UI, namely was first run experience shown for save prompt or auto
-// sign-in prompt.
-void RegisterPrefs(PrefRegistrySimple* registry);
-
 // Returns the number of times the "Save password" bubble can be dismissed by
 // user before it's not shown automatically.
 int GetSmartBubbleDismissalThreshold();
@@ -37,12 +31,6 @@
 // Turns off the auto signin experience setting.
 void TurnOffAutoSignin(PrefService* prefs);
 
-// Returns true if the Chrome Sign In promo should be shown.
-// TODO(crbug.com/1108738): This is unused; remove it and its prefs.
-bool ShouldShowChromeSignInPasswordPromo(
-    PrefService* prefs,
-    const syncer::SyncService* sync_service);
-
 }  // namespace password_bubble_experiment
 
 #endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_BUBBLE_EXPERIMENT_H_
diff --git a/components/password_manager/core/browser/password_bubble_experiment_unittest.cc b/components/password_manager/core/browser/password_bubble_experiment_unittest.cc
index ad0a40d..e10758a 100644
--- a/components/password_manager/core/browser/password_bubble_experiment_unittest.cc
+++ b/components/password_manager/core/browser/password_bubble_experiment_unittest.cc
@@ -33,12 +33,9 @@
 class PasswordManagerPasswordBubbleExperimentTest : public testing::Test {
  public:
   PasswordManagerPasswordBubbleExperimentTest() {
-    RegisterPrefs(pref_service_.registry());
     signin::IdentityManager::RegisterProfilePrefs(pref_service_.registry());
   }
 
-  PrefService* prefs() { return &pref_service_; }
-
   syncer::TestSyncService* sync_service() { return &fake_sync_service_; }
 
  protected:
@@ -55,82 +52,6 @@
   TestingPrefServiceSimple pref_service_;
 };
 
-TEST_F(PasswordManagerPasswordBubbleExperimentTest,
-       ShouldShowChromeSignInPasswordPromo) {
-  // By default the promo is off.
-  EXPECT_FALSE(ShouldShowChromeSignInPasswordPromo(prefs(), nullptr));
-  constexpr struct {
-    bool account_storage_enabled;
-    bool was_already_clicked;
-    bool is_sync_allowed;
-    bool is_first_setup_complete;
-    bool is_signin_allowed;
-    int current_shown_count;
-    bool result;
-  } kTestData[] = {
-      {false, false, true, false, true, 0, true},
-      {true, false, true, false, true, 0, false},
-      {false, false, true, false, true, 5, false},
-      {false, true, true, false, true, 0, false},
-      {false, true, true, false, true, 10, false},
-      {false, false, false, false, true, 0, false},
-      {false, false, true, true, true, 0, false},
-      {false, false, true, false, false, 0, false},
-  };
-  for (const auto& test_case : kTestData) {
-    SCOPED_TRACE(testing::Message("#test_case = ") << (&test_case - kTestData));
-    base::test::ScopedFeatureList account_storage_feature;
-    account_storage_feature.InitWithFeatureState(
-        password_manager::features::kEnablePasswordsAccountStorage,
-        test_case.account_storage_enabled);
-    prefs()->SetBoolean(password_manager::prefs::kWasSignInPasswordPromoClicked,
-                        test_case.was_already_clicked);
-    prefs()->SetInteger(
-        password_manager::prefs::kNumberSignInPasswordPromoShown,
-        test_case.current_shown_count);
-    sync_service()->SetDisableReasons(
-        test_case.is_sync_allowed
-            ? syncer::SyncService::DisableReasonSet()
-            : syncer::SyncService::DISABLE_REASON_PLATFORM_OVERRIDE);
-    sync_service()->SetFirstSetupComplete(test_case.is_first_setup_complete);
-    sync_service()->SetTransportState(
-        test_case.is_first_setup_complete
-            ? syncer::SyncService::TransportState::ACTIVE
-            : syncer::SyncService::TransportState::
-                  PENDING_DESIRED_CONFIGURATION);
-    prefs()->SetBoolean(prefs::kSigninAllowed, test_case.is_signin_allowed);
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
-    EXPECT_EQ(test_case.result,
-              ShouldShowChromeSignInPasswordPromo(prefs(), sync_service()));
-#else
-    EXPECT_FALSE(ShouldShowChromeSignInPasswordPromo(prefs(), sync_service()));
-#endif
-  }
-}
-
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
-TEST_F(PasswordManagerPasswordBubbleExperimentTest, ReviveSignInPasswordPromo) {
-  // If kEnablePasswordsAccountStorage is enabled, then the password manager
-  // bubble never shows Sync promos, so this test doesn't apply.
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kEnablePasswordsAccountStorage)) {
-    return;
-  }
-
-  sync_service()->SetDisableReasons(syncer::SyncService::DisableReasonSet());
-  sync_service()->SetFirstSetupComplete(false);
-  sync_service()->SetTransportState(
-      syncer::SyncService::TransportState::PENDING_DESIRED_CONFIGURATION);
-  prefs()->SetBoolean(password_manager::prefs::kWasSignInPasswordPromoClicked,
-                      true);
-  prefs()->SetInteger(password_manager::prefs::kNumberSignInPasswordPromoShown,
-                      10);
-
-  // The state is to be reset.
-  EXPECT_TRUE(ShouldShowChromeSignInPasswordPromo(prefs(), sync_service()));
-}
-#endif
-
 TEST_F(PasswordManagerPasswordBubbleExperimentTest, IsSmartLockUser) {
   constexpr struct {
     syncer::ModelType type;
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 98779677..6b268fd 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -40,12 +40,10 @@
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "components/password_manager/core/browser/password_store_signin_notifier.h"
 #include "components/password_manager/core/browser/statistics_table.h"
-#include "components/password_manager/core/browser/sync/password_sync_bridge.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
-#include "components/sync/model/client_tag_based_model_type_processor.h"
 #include "components/sync/model/proxy_model_type_controller_delegate.h"
 
 namespace password_manager {
@@ -82,15 +80,15 @@
   DCHECK(main_task_runner_);
   background_task_runner_ = CreateBackgroundTaskRunner();
   DCHECK(background_task_runner_);
-  sync_enabled_or_disabled_cb_ = std::move(sync_enabled_or_disabled_cb);
   prefs_ = prefs;
 
-  if (background_task_runner_) {
+  // TODO(crbug.bom/1226042): Backend might be null in tests, remove this after
+  // tests switch to MockPasswordStoreInterface.
+  if (background_task_runner_ && backend_) {
     TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
         "passwords", "PasswordStore::InitOnBackgroundSequence", this);
-    background_task_runner_->PostTaskAndReplyWithResult(
-        FROM_HERE,
-        base::BindOnce(&PasswordStore::InitOnBackgroundSequence, this),
+    backend_->InitBackend(
+        std::move(sync_enabled_or_disabled_cb),
         base::BindOnce(&PasswordStore::OnInitCompleted, this));
   }
 
@@ -378,8 +376,6 @@
 }
 
 void PasswordStore::ShutdownOnUIThread() {
-  ScheduleTask(
-      base::BindOnce(&PasswordStore::DestroyOnBackgroundSequence, this));
   // The AffiliationService must be destroyed from the main sequence.
   affiliated_match_helper_.reset();
   shutdown_called_ = true;
@@ -421,25 +417,12 @@
       {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
 }
 
-bool PasswordStore::InitOnBackgroundSequence() {
-  DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-
-  sync_bridge_ = base::WrapUnique(new PasswordSyncBridge(
-      std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
-          syncer::PASSWORDS, base::DoNothing()),
-      /*password_store_sync=*/this, sync_enabled_or_disabled_cb_));
-
-  return true;
-}
-
 void PasswordStore::NotifyLoginsChanged(
     const PasswordStoreChangeList& changes) {
   DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
   if (!changes.empty()) {
     observers_->Notify(FROM_HERE, &Observer::OnLoginsChanged,
                        base::RetainedRef(this), changes);
-    if (sync_bridge_)
-      sync_bridge_->ActOnPasswordStoreChanges(changes);
   }
 }
 
@@ -888,16 +871,4 @@
                               affiliated_web_realms));
 }
 
-base::WeakPtr<syncer::ModelTypeControllerDelegate>
-PasswordStore::GetSyncControllerDelegateOnBackgroundSequence() {
-  DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(sync_bridge_);
-  return sync_bridge_->change_processor()->GetControllerDelegate();
-}
-
-void PasswordStore::DestroyOnBackgroundSequence() {
-  DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-  sync_bridge_.reset();
-}
-
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index b363f7e..98c5c01 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -50,7 +50,6 @@
 class PasswordStoreConsumer;
 class InsecureCredentialsConsumer;
 class PasswordStoreConsumer;
-class PasswordSyncBridge;
 struct FieldInfo;
 
 // Partial, cross-platform implementation for storing form passwords.
@@ -229,14 +228,6 @@
   virtual scoped_refptr<base::SequencedTaskRunner> CreateBackgroundTaskRunner()
       const;
 
-  // Creates PasswordSyncBridge and PasswordReuseDetector instances on the
-  // background sequence. Subclasses can add more logic. Returns true on
-  // success. If |upload_phished_credentials_to_sync| is true, metadata will be
-  // dropped to force syncing, if local phished credentials information exist.
-  // Dropping metadata clears all of the information about previous syncing and
-  // force uploading all the local passwords with security issues again.
-  virtual bool InitOnBackgroundSequence();
-
   // Methods below will be run in PasswordStore's own sequence.
   // Synchronous implementation that reports usage metrics.
   virtual void ReportMetricsImpl(const std::string& sync_username,
@@ -319,6 +310,13 @@
   // store is empty.
   virtual bool IsEmpty() = 0;
 
+  // Returns the sync controller delegate for syncing passwords. It must be
+  // called on the background sequence.
+  // TODO(crbug.bom/1226042): Remove this after fully switching to the
+  // PasswordStoreInterface.
+  virtual base::WeakPtr<syncer::ModelTypeControllerDelegate>
+  GetSyncControllerDelegateOnBackgroundSequence() = 0;
+
   // Called by *Internal() methods once the underlying data-modifying operation
   // has been performed. Notifies observers that password store data may have
   // been changed.
@@ -347,7 +345,6 @@
   // TODO(crbug.com/1217071): Make private std::unique_ptr as soon as the
   // backend is passed into the store instead of it being the store(_impl).
   PasswordStoreBackend* backend_ = nullptr;
-
  private:
   using StatsResult = std::vector<InteractionsStats>;
   using StatsTask = base::OnceCallback<StatsResult()>;
@@ -488,21 +485,12 @@
       const PasswordForm& updated_android_form,
       const std::vector<std::string>& affiliated_web_realms);
 
-  // Returns the sync controller delegate for syncing passwords. It must be
-  // called on the background sequence.
-  base::WeakPtr<syncer::ModelTypeControllerDelegate>
-  GetSyncControllerDelegateOnBackgroundSequence();
-
   // Schedules UpdateAffiliatedWebLoginsImpl() to run on the background
   // sequence. Should be called from the main sequence.
   void ScheduleUpdateAffiliatedWebLoginsImpl(
       const PasswordForm& updated_android_form,
       const std::vector<std::string>& affiliated_web_realms);
 
-  // Deletes object that should be destroyed on the background sequence.
-  // WARNING: this method can be skipped on shutdown.
-  void DestroyOnBackgroundSequence();
-
   // TaskRunner for tasks that run on the main sequence (usually the UI thread).
   scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
 
@@ -512,10 +500,6 @@
   // The observers.
   scoped_refptr<base::ObserverListThreadSafe<Observer>> observers_;
 
-  std::unique_ptr<PasswordSyncBridge> sync_bridge_;
-
-  base::RepeatingClosure sync_enabled_or_disabled_cb_;
-
   std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper_;
 
   PrefService* prefs_ = nullptr;
diff --git a/components/password_manager/core/browser/password_store_backend.h b/components/password_manager/core/browser/password_store_backend.h
index 6b56db6..1e42c73 100644
--- a/components/password_manager/core/browser/password_store_backend.h
+++ b/components/password_manager/core/browser/password_store_backend.h
@@ -38,6 +38,11 @@
   PasswordStoreBackend& operator=(PasswordStoreBackend&&) = delete;
   virtual ~PasswordStoreBackend() = default;
 
+  // TODO(crbug.bom/1226042): Rename this to Init after PasswordStoreImpl no
+  // longer inherits PasswordStore.
+  virtual void InitBackend(base::RepeatingClosure sync_enabled_or_disabled_cb,
+                           base::OnceCallback<void(bool)> completion) = 0;
+
   // Returns the complete list of PasswordForms (regardless of their blocklist
   // status) and notify `consumer` on completion. Callback is called on the main
   // sequence.
diff --git a/components/password_manager/core/browser/password_store_impl.cc b/components/password_manager/core/browser/password_store_impl.cc
index 1f56a401..8ec2b8d 100644
--- a/components/password_manager/core/browser/password_store_impl.cc
+++ b/components/password_manager/core/browser/password_store_impl.cc
@@ -11,7 +11,9 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "components/password_manager/core/browser/password_store_change.h"
+#include "components/password_manager/core/browser/sync/password_sync_bridge.h"
 #include "components/prefs/pref_service.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
 
 namespace password_manager {
 
@@ -41,25 +43,8 @@
 
 void PasswordStoreImpl::ShutdownOnUIThread() {
   PasswordStore::ShutdownOnUIThread();
-  ScheduleTask(base::BindOnce(&PasswordStoreImpl::ResetLoginDB, this));
-}
-
-bool PasswordStoreImpl::InitOnBackgroundSequence() {
-  DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
-  DCHECK(login_db_);
-  bool success = true;
-  if (!login_db_->Init()) {
-    login_db_.reset();
-    // The initialization should be continued, because PasswordSyncBridge
-    // has to be initialized even if database initialization failed.
-    success = false;
-    LOG(ERROR) << "Could not create/open login database.";
-  }
-  if (success) {
-    login_db_->SetDeletionsHaveSyncedCallback(base::BindRepeating(
-        &PasswordStoreImpl::NotifyDeletionsHaveSynced, base::Unretained(this)));
-  }
-  return PasswordStore::InitOnBackgroundSequence() && success;
+  ScheduleTask(
+      base::BindOnce(&PasswordStoreImpl::DestroyOnBackgroundSequence, this));
 }
 
 void PasswordStoreImpl::ReportMetricsImpl(const std::string& sync_username,
@@ -306,6 +291,13 @@
     login_db_->field_info_table().RemoveRowsByTime(remove_begin, remove_end);
 }
 
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+PasswordStoreImpl::GetSyncControllerDelegateOnBackgroundSequence() {
+  DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
+  DCHECK(sync_bridge_);
+  return sync_bridge_->change_processor()->GetControllerDelegate();
+}
+
 bool PasswordStoreImpl::IsEmpty() {
   if (!login_db_)
     return true;
@@ -344,6 +336,13 @@
   return RemoveLoginImpl(form);
 }
 
+void PasswordStoreImpl::NotifyLoginsChanged(
+    const PasswordStoreChangeList& changes) {
+  PasswordStore::NotifyLoginsChanged(changes);
+  if (sync_bridge_ && !changes.empty())
+    sync_bridge_->ActOnPasswordStoreChanges(changes);
+}
+
 bool PasswordStoreImpl::BeginTransaction() {
   if (login_db_)
     return login_db_->BeginTransaction();
@@ -398,6 +397,16 @@
   return login_db_ && login_db_->DeleteAndRecreateDatabaseFile();
 }
 
+void PasswordStoreImpl::InitBackend(
+    base::RepeatingClosure sync_enabled_or_disabled_cb,
+    base::OnceCallback<void(bool)> completion) {
+  background_task_runner()->PostTaskAndReplyWithResult(
+      FROM_HERE,
+      base::BindOnce(&PasswordStoreImpl::InitOnBackgroundSequence, this,
+                     std::move(sync_enabled_or_disabled_cb)),
+      std::move(completion));
+}
+
 void PasswordStoreImpl::GetAllLoginsAsync(LoginsReply callback) {
   background_task_runner()->PostTaskAndReplyWithResult(
       FROM_HERE, base::BindOnce(&PasswordStoreImpl::GetAllLoginsInternal, this),
@@ -426,9 +435,38 @@
       std::move(callback));
 }
 
-void PasswordStoreImpl::ResetLoginDB() {
+bool PasswordStoreImpl::InitOnBackgroundSequence(
+    base::RepeatingClosure sync_enabled_or_disabled_cb) {
+  DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
+  DCHECK(login_db_);
+  bool success = true;
+  if (!login_db_->Init()) {
+    login_db_.reset();
+    // The initialization should be continued, because PasswordSyncBridge
+    // has to be initialized even if database initialization failed.
+    success = false;
+    LOG(ERROR) << "Could not create/open login database.";
+  }
+  if (success) {
+    login_db_->SetDeletionsHaveSyncedCallback(base::BindRepeating(
+        &PasswordStoreImpl::NotifyDeletionsHaveSynced, base::Unretained(this)));
+  }
+
+  // TODO(crbug.com/1226042): Remove static_cast when PasswordStoreImpl inherits
+  // PasswordStoreSync directly.
+  sync_bridge_ = std::make_unique<PasswordSyncBridge>(
+      std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
+          syncer::PASSWORDS, base::DoNothing()),
+      /*password_store_sync=*/static_cast<PasswordStoreSync*>(this),
+      sync_enabled_or_disabled_cb);
+
+  return success;
+}
+
+void PasswordStoreImpl::DestroyOnBackgroundSequence() {
   DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
   login_db_.reset();
+  sync_bridge_.reset();
 }
 
 LoginsResult PasswordStoreImpl::GetAllLoginsInternal() {
diff --git a/components/password_manager/core/browser/password_store_impl.h b/components/password_manager/core/browser/password_store_impl.h
index dcc17b0..c894d1c 100644
--- a/components/password_manager/core/browser/password_store_impl.h
+++ b/components/password_manager/core/browser/password_store_impl.h
@@ -16,6 +16,8 @@
 
 namespace password_manager {
 
+class PasswordSyncBridge;
+
 // Simple password store implementation that delegates everything to
 // the LoginDatabase.
 // TODO(crbug.com/1217071): Currently, only implicitly inherits from protected
@@ -34,9 +36,6 @@
  protected:
   ~PasswordStoreImpl() override;
 
-  // Opens |login_db_| on the background sequence.
-  bool InitOnBackgroundSequence() override;
-
   // Implements PasswordStore interface.
   void ReportMetricsImpl(const std::string& sync_username,
                          bool custom_passphrase_sync_enabled,
@@ -84,6 +83,8 @@
                                  base::Time remove_end) override;
 
   bool IsEmpty() override;
+  base::WeakPtr<syncer::ModelTypeControllerDelegate>
+  GetSyncControllerDelegateOnBackgroundSequence() override;
 
   // Implements PasswordStoreSync interface.
   PasswordStoreChangeList AddLoginSync(const PasswordForm& form,
@@ -96,6 +97,7 @@
       const PasswordForm& form,
       base::span<const InsecureCredential> credentials) override;
   PasswordStoreChangeList RemoveLoginSync(const PasswordForm& form) override;
+  void NotifyLoginsChanged(const PasswordStoreChangeList& changes) override;
   bool BeginTransaction() override;
   void RollbackTransaction() override;
   bool CommitTransaction() override;
@@ -116,15 +118,20 @@
   FRIEND_TEST_ALL_PREFIXES(PasswordStoreTest, UpdateInsecureCredentialsSync);
 
   // Implements PasswordStoreBackend interface.
-
+  void InitBackend(base::RepeatingClosure sync_enabled_or_disabled_cb,
+                   base::OnceCallback<void(bool)> completion) override;
   void GetAllLoginsAsync(LoginsReply callback) override;
   void GetAutofillableLoginsAsync(LoginsReply callback) override;
   void FillMatchingLoginsAsync(
       LoginsReply callback,
       const std::vector<PasswordFormDigest>& forms) override;
 
-  // Resets |login_db_| on the background sequence.
-  void ResetLoginDB();
+  // Opens |login_db_| and creates |sync_bridge_| on the background sequence.
+  bool InitOnBackgroundSequence(
+      base::RepeatingClosure sync_enabled_or_disabled_cb);
+
+  // Resets |login_db_| and |sync_bridge_| on the background sequence.
+  void DestroyOnBackgroundSequence();
 
   // Synchronous implementation of GetAllLoginsAsync.
   LoginsResult GetAllLoginsInternal();
@@ -142,6 +149,8 @@
   // fails, |login_db_| will be reset and stay NULL for the lifetime of |this|.
   std::unique_ptr<LoginDatabase> login_db_;
 
+  std::unique_ptr<PasswordSyncBridge> sync_bridge_;
+
   DISALLOW_COPY_AND_ASSIGN(PasswordStoreImpl);
 };
 
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc
index 10698ba1..7c7a63d 100644
--- a/components/password_manager/core/browser/test_password_store.cc
+++ b/components/password_manager/core/browser/test_password_store.cc
@@ -137,6 +137,12 @@
   return number_of_passwords == 0u;
 }
 
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+TestPasswordStore::GetSyncControllerDelegateOnBackgroundSequence() {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
 TestPasswordStore::~TestPasswordStore() = default;
 
 scoped_refptr<base::SequencedTaskRunner>
@@ -144,6 +150,13 @@
   return base::SequencedTaskRunnerHandle::Get();
 }
 
+void TestPasswordStore::InitBackend(
+    base::RepeatingClosure sync_enabled_or_disabled_cb,
+    base::OnceCallback<void(bool)> completion) {
+  main_task_runner()->PostTask(FROM_HERE,
+                               base::BindOnce(std::move(completion), true));
+}
+
 void TestPasswordStore::GetAllLoginsAsync(LoginsReply callback) {
   background_task_runner()->PostTaskAndReplyWithResult(
       FROM_HERE,
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h
index 85ee509..7e48ea7 100644
--- a/components/password_manager/core/browser/test_password_store.h
+++ b/components/password_manager/core/browser/test_password_store.h
@@ -71,6 +71,9 @@
   // have entries of size 0.
   bool IsEmpty() override;
 
+  base::WeakPtr<syncer::ModelTypeControllerDelegate>
+  GetSyncControllerDelegateOnBackgroundSequence() override;
+
   int fill_matching_logins_calls() const { return fill_matching_logins_calls_; }
 
  protected:
@@ -80,6 +83,8 @@
       const override;
 
   // PasswordStoreBackend interface
+  void InitBackend(base::RepeatingClosure sync_enabled_or_disabled_cb,
+                   base::OnceCallback<void(bool)> completion) override;
   void GetAllLoginsAsync(LoginsReply callback) override;
   void GetAutofillableLoginsAsync(LoginsReply callback) override;
   void FillMatchingLoginsAsync(
diff --git a/components/password_manager/core/common/password_manager_pref_names.cc b/components/password_manager/core/common/password_manager_pref_names.cc
index 20eb904..aecfb82c 100644
--- a/components/password_manager/core/common/password_manager_pref_names.cc
+++ b/components/password_manager/core/common/password_manager_pref_names.cc
@@ -25,18 +25,9 @@
 const char kWasAutoSignInFirstRunExperienceShown[] =
     "profile.was_auto_sign_in_first_run_experience_shown";
 
-const char kWasSignInPasswordPromoClicked[] =
-    "profile.was_sign_in_password_promo_clicked";
-
 const char kWereOldGoogleLoginsRemoved[] =
     "profile.were_old_google_logins_removed";
 
-const char kNumberSignInPasswordPromoShown[] =
-    "profile.number_sign_in_password_promo_shown";
-
-const char kSignInPasswordPromoRevive[] =
-    "profile.sign_in_password_promo_revive";
-
 const char kAccountStoragePerAccountSettings[] =
     "profile.password_account_storage_settings";
 
diff --git a/components/password_manager/core/common/password_manager_pref_names.h b/components/password_manager/core/common/password_manager_pref_names.h
index 89f5a68..56e934c 100644
--- a/components/password_manager/core/common/password_manager_pref_names.h
+++ b/components/password_manager/core/common/password_manager_pref_names.h
@@ -43,20 +43,10 @@
 // prompt was shown or not.
 extern const char kWasAutoSignInFirstRunExperienceShown[];
 
-// Boolean that indicated if user interacted with the Chrome Sign in promo.
-extern const char kWasSignInPasswordPromoClicked[];
-
 // Boolean that indicated whether one time removal of old google.com logins was
 // performed.
 extern const char kWereOldGoogleLoginsRemoved[];
 
-// Number of times the Chrome Sign in promo popped up.
-extern const char kNumberSignInPasswordPromoShown[];
-
-// True if the counters for the sign in promo were reset for M79.
-// Safe to remove for M82.
-extern const char kSignInPasswordPromoRevive[];
-
 // A dictionary of account-storage-related settings that exist per Gaia account
 // (e.g. whether that user has opted in). It maps from hash of Gaia ID to
 // dictionary of key-value pairs.
diff --git a/components/policy/core/browser/policy_conversions.cc b/components/policy/core/browser/policy_conversions.cc
index 8c0b412..e0ca524 100644
--- a/components/policy/core/browser/policy_conversions.cc
+++ b/components/policy/core/browser/policy_conversions.cc
@@ -28,6 +28,8 @@
     {"priorityCloud", IDS_POLICY_SOURCE_CLOUD},
     {"merged", IDS_POLICY_SOURCE_MERGED},
     {"cloud_from_ash", IDS_POLICY_SOURCE_CLOUD_FROM_ASH},
+    {"restrictedManagedGuestSessionOverride",
+     IDS_POLICY_SOURCE_RESTRICTED_MANAGED_GUEST_SESSION_OVERRIDE},
 };
 
 PolicyConversions::PolicyConversions(
diff --git a/components/policy/core/common/policy_types.h b/components/policy/core/common/policy_types.h
index 7e6ce591..6a86a74 100644
--- a/components/policy/core/common/policy_types.h
+++ b/components/policy/core/common/policy_types.h
@@ -62,6 +62,10 @@
   // The policy was set by Cloud in Ash and piped to Lacros.
   POLICY_SOURCE_CLOUD_FROM_ASH,
 
+  // The policy was set by the RestrictedManagedGuestSessionEnabled policy. This
+  // source should be kept as highest priority source.
+  POLICY_SOURCE_RESTRICTED_MANAGED_GUEST_SESSION_OVERRIDE,
+
   // Number of source types. Has to be the last element.
   POLICY_SOURCE_COUNT
 };
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index 0c7f91a..2731b10 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -1831,6 +1831,9 @@
     // A policy is set by Google's cloud management tool in Ash and piped to
     // Lacros.
     SOURCE_CLOUD_FROM_ASH = 9;
+
+    // A policy that is set by the restricted managed guest session override.
+    SOURCE_RESTRICTED_MANAGED_GUEST_SESSION_OVERRIDE = 10;
   }
   optional PolicySource source = 4;
 
@@ -3035,7 +3038,7 @@
     USER_TYPE_REGULAR = 1;
     USER_TYPE_GUEST = 2;
     USER_TYPE_PUBLIC_ACCOUNT = 3;
-    USER_TYPE_SUPERVISED_DEPRECATED = 4;
+    USER_TYPE_SUPERVISED_DEPRECATED = 4 [deprecated = true];
     USER_TYPE_KIOSK_APP = 5;
     USER_TYPE_CHILD = 6;
     USER_TYPE_ARC_KIOSK_APP = 7;
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp
index e7c3a1e..e05bbadb 100644
--- a/components/policy_strings.grdp
+++ b/components/policy_strings.grdp
@@ -492,6 +492,9 @@
   <message name="IDS_POLICY_SOURCE_CLOUD_FROM_ASH" desc="Indicates that the policy originates from the cloud in Ash and piped to Lacros.">
     Cloud (system-wide)
   </message>
+  <message name="IDS_POLICY_SOURCE_RESTRICTED_MANAGED_GUEST_SESSION_OVERRIDE" desc="Indicates that the policy originates from the restricted managed guest session override.">
+    Restricted managed guest session override
+  </message>
   <message name="IDS_POLICY_SOURCE_ACTIVE_DIRECTORY" desc="Indicates that the policy originates from a local server, e.g. Samba or Active Directory.">
     <ph name="MICROSOFT_ACTIVE_DIRECTORY">Local Server</ph>
   </message>
diff --git a/components/policy_strings_grdp/IDS_POLICY_SOURCE_RESTRICTED_MANAGED_GUEST_SESSION_OVERRIDE.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_SOURCE_RESTRICTED_MANAGED_GUEST_SESSION_OVERRIDE.png.sha1
new file mode 100644
index 0000000..a7ed15b
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_SOURCE_RESTRICTED_MANAGED_GUEST_SESSION_OVERRIDE.png.sha1
@@ -0,0 +1 @@
+7555b2a3cd630a2f7786e6b081cbaa9afb849281
\ No newline at end of file
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index ca3c4bc..2b822515 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -432,6 +432,25 @@
 // Different types of reporting. This is used as a histogram suffix.
 enum class ReportingType { PERIODIC, ON_CHANGE };
 
+// Result for fetching account capabilities from the system library, used to
+// record histogram Signin.AccountCapabilities.GetFromSystemLibraryResult.
+//
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class FetchAccountCapabilitiesFromSystemLibraryResult {
+  // Errors common to iOS and Android.
+  kSuccess = 0,
+  kErrorGeneric = 1,
+
+  // Errors from 10 to 19 are reserved for Android.
+
+  // Errors after 20 are reserved for iOS.
+  kErrorMissingCapability = 20,
+  kErrorUnexpectedValue = 21,
+
+  kMaxValue = kErrorUnexpectedValue
+};
+
 // -----------------------------------------------------------------------------
 // Histograms
 // -----------------------------------------------------------------------------
diff --git a/components/strings/components_strings_af.xtb b/components/strings/components_strings_af.xtb
index 8a8cba1..900e3f9 100644
--- a/components/strings/components_strings_af.xtb
+++ b/components/strings/components_strings_af.xtb
@@ -381,6 +381,7 @@
 <translation id="2310021320168182093">Chou2 (Envelope)</translation>
 <translation id="2316887270356262533">Maak minder as 1 MB beskikbaar. Sommige werwe sal dalk op jou volgende besoek stadiger laai.</translation>
 <translation id="2317259163369394535"><ph name="DOMAIN" /> vereis 'n gebruikernaam en wagwoord.</translation>
+<translation id="2328651992442742497">Toegelaat (verstek)</translation>
 <translation id="2330137317877982892"><ph name="CREDIT_CARD" />, verval op <ph name="EXPIRATION_DATE_ABBR" /></translation>
 <translation id="2337852623177822836">Instelling word deur jou administrateur gekontroleer</translation>
 <translation id="2340263603246777781"><ph name="ORIGIN" /> wil saambind</translation>
@@ -429,6 +430,7 @@
 <translation id="2498091847651709837">Skandeer nuwe kaart</translation>
 <translation id="2501278716633472235">Gaan terug</translation>
 <translation id="2505268675989099013">Beskerm rekening</translation>
+<translation id="2512101340618156538">Nie toegelaat nie (verstek)</translation>
 <translation id="2515629240566999685">Die sein in jou omgewing nagaan</translation>
 <translation id="2521385132275182522">Kram regs onder</translation>
 <translation id="2523886232349826891">Net op hierdie toestel gestoor</translation>
@@ -964,6 +966,7 @@
 <translation id="4434045419905280838">Opspringers en herleidings</translation>
 <translation id="4435702339979719576">Postcard)</translation>
 <translation id="443673843213245140">Die gebruik van 'n instaanbediener is gedeaktiveer, maar 'n eksplisiete instaanbedieneropstelling word gespesifiseer.</translation>
+<translation id="4460315069258617173">Toegelaat totdat jy oortjies vir hierdie werf toemaak</translation>
 <translation id="4464826014807964867">Webwerwe met inligting van jou organisasie</translation>
 <translation id="4476953670630786061">Hierdie vorm is nie veilig nie. Outovul is afgeskakel.</translation>
 <translation id="4477350412780666475">Volgende snit</translation>
@@ -1005,6 +1008,7 @@
 <translation id="464342062220857295">Soekkenmerke</translation>
 <translation id="4644670975240021822">Omgekeerde volgorde, voorkant na onder</translation>
 <translation id="4646534391647090355">Vat my nou soontoe</translation>
+<translation id="4652266463001779298">Nie toegelaat nie</translation>
 <translation id="4658638640878098064">Kram links bo</translation>
 <translation id="4660119392514473465">Jy kan nou privaat blaai en ander mense wat hierdie toestel gebruik, sal nie jou aktiwiteit sien nie. Aflaaie, boekmerke en leeslysitems sal egter gestoor word.</translation>
 <translation id="4668929960204016307">,</translation>
@@ -1716,6 +1720,7 @@
 <translation id="734600844861828519">11x15</translation>
 <translation id="7346048084945669753">Is geaffilieer:</translation>
 <translation id="7349430561505560861">A4-Extra</translation>
+<translation id="7349921148288539306">Toegelaat totdat jy hierdie oortjie toemaak</translation>
 <translation id="7352651011704765696">Iets het verkeerd geloop</translation>
 <translation id="7353601530677266744">Bevellyn</translation>
 <translation id="7359588939039777303">Advertensies is geblokkeer.</translation>
@@ -1858,6 +1863,7 @@
 <translation id="7800304661137206267">Die verbinding word geënkripteer deur <ph name="CIPHER" /> te gebruik, met <ph name="MAC" /> vir boodskapstawing en <ph name="KX" /> as die sleuteluitruilmeganisme.</translation>
 <translation id="7802523362929240268">Werf is eg</translation>
 <translation id="780301667611848630">Nee, dankie</translation>
+<translation id="7805571567667010077">Bestuur deur jou organisasie</translation>
 <translation id="7805768142964895445">Status</translation>
 <translation id="7812922009395017822">Mir</translation>
 <translation id="7813600968533626083">Verwyder vormvoorstel uit Chrome?</translation>
@@ -1953,6 +1959,7 @@
 <translation id="8175796834047840627">Chrome bied aan om jou kaarte in jou Google-rekening te stoor omdat jy aangemeld is. Jy kan hierdie gedrag in instellings verander.</translation>
 <translation id="8176440868214972690">Die administrateur van hierdie toestel het sommige inligting, soos instellings of beleide, na die volgende webwerwe gestuur.</translation>
 <translation id="8184538546369750125">Gebruik globale verstek (Laat toe)</translation>
+<translation id="8190193880870196235">Bestuur deur 'n uitbreiding</translation>
 <translation id="8193086767630290324">Handelinge uitgevoer met data wat as vertroulik gevlag is</translation>
 <translation id="8194797478851900357">Ontdoen skuif</translation>
 <translation id="8201077131113104583">Ongeldige opdatering-URL vir uitbreiding met ID "<ph name="EXTENSION_ID" />".</translation>
@@ -2052,6 +2059,7 @@
 <translation id="8541158209346794904">Bluetooth-toestel</translation>
 <translation id="8542014550340843547">Tripelkram onder</translation>
 <translation id="8543181531796978784">Jy kan <ph name="BEGIN_ERROR_LINK" />'n bespeuringsprobleem aangee<ph name="END_ERROR_LINK" /> of, as jy die risikos vir jou sekuriteit verstaan, kan jy <ph name="BEGIN_LINK" />hierdie onveilige werf besoek<ph name="END_LINK" />.</translation>
+<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Stel toestemming terug}other{Stel toestemmings terug}}</translation>
 <translation id="8557066899867184262">Die CVC is agterop jou kaart.</translation>
 <translation id="8558485628462305855">Dateer ARCore op om verhoogderealiteitinhoud te bekyk</translation>
 <translation id="8559762987265718583">'n Private verbinding aan <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> kan nie gevestig word nie omdat jou toestel se datum en tyd (<ph name="DATE_AND_TIME" />) verkeerd is.</translation>
diff --git a/components/strings/components_strings_ja.xtb b/components/strings/components_strings_ja.xtb
index c280b190..2f633ff 100644
--- a/components/strings/components_strings_ja.xtb
+++ b/components/strings/components_strings_ja.xtb
@@ -377,6 +377,7 @@
 <translation id="2310021320168182093">長2(封筒)</translation>
 <translation id="2316887270356262533">最大で 1 MB を解放します。サイトによっては、次回アクセスする際に読み込みに時間がかかる可能性があります。</translation>
 <translation id="2317259163369394535"><ph name="DOMAIN" /> にはユーザー名とパスワードが必要です。</translation>
+<translation id="2328651992442742497">許可(デフォルト)</translation>
 <translation id="2330137317877982892">「<ph name="CREDIT_CARD" />」の有効期限は <ph name="EXPIRATION_DATE_ABBR" /> です</translation>
 <translation id="2337852623177822836">管理者が指定する設定</translation>
 <translation id="2340263603246777781"><ph name="ORIGIN" /> がペア設定を要求しています</translation>
@@ -425,6 +426,7 @@
 <translation id="2498091847651709837">新しいカードをスキャン</translation>
 <translation id="2501278716633472235">戻る</translation>
 <translation id="2505268675989099013">アカウントを保護</translation>
+<translation id="2512101340618156538">ブロック(デフォルト)</translation>
 <translation id="2515629240566999685">電波状況を確認する</translation>
 <translation id="2521385132275182522">ステープル(右下)</translation>
 <translation id="2523886232349826891">カードはこのデバイスのみに保存されます</translation>
@@ -955,6 +957,7 @@
 <translation id="4434045419905280838">ポップアップとリダイレクト</translation>
 <translation id="4435702339979719576">ポストカード</translation>
 <translation id="443673843213245140">プロキシの使用は無効ですが、プロキシの設定が明示的に指定されています。</translation>
+<translation id="4460315069258617173">このサイトのタブを開いている間のみ許可</translation>
 <translation id="4464826014807964867">組織の情報を使用しているウェブサイト</translation>
 <translation id="4476953670630786061">このフォームは安全ではないため、自動入力をオフにしました。</translation>
 <translation id="4477350412780666475">次の曲</translation>
@@ -996,6 +999,7 @@
 <translation id="464342062220857295">検索機能</translation>
 <translation id="4644670975240021822">逆の順序(下向き)</translation>
 <translation id="4646534391647090355">今すぐ表示</translation>
+<translation id="4652266463001779298">ブロック</translation>
 <translation id="4658638640878098064">ステープル(左上)</translation>
 <translation id="4660119392514473465">現在、シークレット モードで閲覧しています。あなたのアクティビティは、このデバイスを利用する他のユーザーには表示されません。ただし、ダウンロードしたファイル、ブックマーク、リーディング リストは通常どおり保存されます。</translation>
 <translation id="4668929960204016307">,</translation>
@@ -1707,6 +1711,7 @@
 <translation id="734600844861828519">11x15</translation>
 <translation id="7346048084945669753">外部のユーザーかどうか:</translation>
 <translation id="7349430561505560861">A4-Extra</translation>
+<translation id="7349921148288539306">このタブを開いている間のみ許可</translation>
 <translation id="7352651011704765696">問題が発生しました</translation>
 <translation id="7353601530677266744">コマンドライン</translation>
 <translation id="7359588939039777303">広告がブロックされました。</translation>
@@ -1849,6 +1854,7 @@
 <translation id="7800304661137206267">この接続は <ph name="CIPHER" /> で暗号化されており、メッセージ認証には <ph name="MAC" />、鍵交換メカニズムには <ph name="KX" /> が使用されています。</translation>
 <translation id="7802523362929240268">正規のサイトです</translation>
 <translation id="780301667611848630">いいえ</translation>
+<translation id="7805571567667010077">組織によって管理されています</translation>
 <translation id="7805768142964895445">ステータス</translation>
 <translation id="7812922009395017822">Mir</translation>
 <translation id="7813600968533626083">Chrome から候補を削除してもよろしいですか?</translation>
@@ -1944,6 +1950,7 @@
 <translation id="8175796834047840627">ログインしている場合は、その Google アカウントにカードを保存できます。この動作は設定で変更できます。</translation>
 <translation id="8176440868214972690">このデバイスの管理者は、次のウェブサイトに設定やポリシーなどの情報を送信するよう設定しています。</translation>
 <translation id="8184538546369750125">グローバルのデフォルト値([許可])を使用</translation>
+<translation id="8190193880870196235">拡張機能によって管理されています</translation>
 <translation id="8193086767630290324">機密として指定されたデータに対する操作</translation>
 <translation id="8194797478851900357">移動の取り消し(&amp;U)</translation>
 <translation id="8201077131113104583">ID「<ph name="EXTENSION_ID" />」の拡張機能に対する無効な更新 URL です。</translation>
@@ -2043,6 +2050,7 @@
 <translation id="8541158209346794904">Bluetooth デバイス</translation>
 <translation id="8542014550340843547">3 か所のステープル(下)</translation>
 <translation id="8543181531796978784"><ph name="BEGIN_ERROR_LINK" />検出の問題をご報告<ph name="END_ERROR_LINK" />ください。<ph name="BEGIN_LINK" />安全でないこのサイトにアクセス<ph name="END_LINK" />する場合は、セキュリティ上のリスクがあることをご承知おきください。</translation>
+<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{権限をリセット}other{権限をリセット}}</translation>
 <translation id="8557066899867184262">CVC はカードの裏面に記載されています。</translation>
 <translation id="8558485628462305855">拡張現実(AR)コンテンツを表示するには ARCore を更新してください</translation>
 <translation id="8559762987265718583">デバイスの日時(<ph name="DATE_AND_TIME" />)が正しくないため、<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> へのプライベート接続を確立できません。</translation>
diff --git a/components/strings/components_strings_si.xtb b/components/strings/components_strings_si.xtb
index 8a85eb72..50fda320 100644
--- a/components/strings/components_strings_si.xtb
+++ b/components/strings/components_strings_si.xtb
@@ -381,6 +381,7 @@
 <translation id="2310021320168182093">Chou2 (ලියුම් කවරය)</translation>
 <translation id="2316887270356262533">1 MB ට වඩා අඩුවෙන් හිස් කරයි. ඔබේ ඊළඟ පිවිසීමේදී සමහර අඩවි වඩාත් සෙමින් පූරණය විය හැකිය.</translation>
 <translation id="2317259163369394535"><ph name="DOMAIN" /> හට පරිශීලක නාමයක් සහ මුරපදයක් අවශ්‍යයි.</translation>
+<translation id="2328651992442742497">ඉඩ දේ (පෙරනිමි)</translation>
 <translation id="2330137317877982892"><ph name="CREDIT_CARD" />, <ph name="EXPIRATION_DATE_ABBR" /> දින කල් ඉකුත් වේ</translation>
 <translation id="2337852623177822836">සැකසීම ඔබේ පරිපාලක විසින් පාලනය කරයි</translation>
 <translation id="2340263603246777781"><ph name="ORIGIN" /> හට යුගල වීමට අවශ්‍යයි</translation>
@@ -429,6 +430,7 @@
 <translation id="2498091847651709837">නව කාඩ්පත ස්කෑන් කරන්න</translation>
 <translation id="2501278716633472235">ආපසු යන්න</translation>
 <translation id="2505268675989099013">ගිණුම ආරක්‍ෂා කරන්න</translation>
+<translation id="2512101340618156538">ඉඩ නොදේ (පෙරනිමි)</translation>
 <translation id="2515629240566999685">ඔබේ ප්‍රදේශයේ සංඥා පරීක්ෂා කරමින්</translation>
 <translation id="2521385132275182522">පහළ දකුණ ස්ටේපල් කරන්න</translation>
 <translation id="2523886232349826891">මෙම උපාංගයෙහි පමණක් සුරැකිණි</translation>
@@ -961,6 +963,7 @@
 <translation id="4434045419905280838">උත්පතන සහ හරවා යැවීම්</translation>
 <translation id="4435702339979719576">තැපැල් පත)</translation>
 <translation id="443673843213245140">ප්‍රොක්සියක භාවිතය අබල කර ඇති නමුත් ප්‍රකාශිත ප්‍රොක්සි වින්‍යාසකරණයක් නිශ්චය කර ඇත.</translation>
+<translation id="4460315069258617173">ඔබ මෙම අඩවිය සඳහා ටැබ වසන තෙක් ඉඩ දේ</translation>
 <translation id="4464826014807964867">ඔබේ සංවිධානය වෙතින් වන තොරතුරු සහිත වෙබ් අඩවි</translation>
 <translation id="4476953670630786061">මෙම පෝරමය ආරක්ෂිත නොවේ. ස්වයං පිරවුම ක්‍රියාවිරහිත කර ඇත.</translation>
 <translation id="4477350412780666475">ඊළඟ ඛණ්ඩය</translation>
@@ -1002,6 +1005,7 @@
 <translation id="464342062220857295">විශේෂාංග සොයන්න</translation>
 <translation id="4644670975240021822">ප්‍රතිවර්තන පිළිවෙළ මුහුණු පහළට</translation>
 <translation id="4646534391647090355">දැන් මාව එතැනට ගෙන යන්න</translation>
+<translation id="4652266463001779298">ඉඩ නොදේ</translation>
 <translation id="4658638640878098064">ඉහළ වම ස්ටේපල් කරන්න</translation>
 <translation id="4660119392514473465">දැන් ඔබට පෞද්ගලිකව බ්‍රවුස් කළ හැකි අතර, මෙම උපාංගය භාවිතා කරන වෙනත් පුද්ගලයින් ඔබගේ ක්‍රියාකාරකම් නොදකිනු ඇත. කෙසේ වෙතත්, බාගැනීම්, පිටුසන් සහ කියවීම් ලැයිස්තු අයිතම සුරකිනු ඇත.</translation>
 <translation id="4668929960204016307">,</translation>
@@ -1713,6 +1717,7 @@
 <translation id="734600844861828519">11x15</translation>
 <translation id="7346048084945669753">අනුබද්ධ වී ඇත්තේ:</translation>
 <translation id="7349430561505560861">A4-Extra</translation>
+<translation id="7349921148288539306">ඔබ මෙම ටැබය වසන තෙක් ඉඩ දේ</translation>
 <translation id="7352651011704765696">යමක් වැරදිනි</translation>
 <translation id="7353601530677266744">විධාන පේළිය</translation>
 <translation id="7359588939039777303">වෙළඳ දැන්වීම් අවහිරයි.</translation>
@@ -1855,6 +1860,7 @@
 <translation id="7800304661137206267"><ph name="CIPHER" /> පණිවිඩ සහතික කිරීම සඳහා  සහ <ph name="MAC" /> යතුරු  ලෙස සහිතව <ph name="KX" /> භාවිතයෙන් සබැඳුම සංකේතනය කර ඇත.</translation>
 <translation id="7802523362929240268">අඩවිය නිත්‍යානුකූලයි</translation>
 <translation id="780301667611848630">එපා, ස්තූතියි</translation>
+<translation id="7805571567667010077">ඔබේ සංවිධානය විසින් කළමනාකරණය කරනු ලැබේ</translation>
 <translation id="7805768142964895445">තත්වය</translation>
 <translation id="7812922009395017822">Mir</translation>
 <translation id="7813600968533626083">Chrome වෙතින් වන යෝජනාවලින් ඉවත් කරන්නද?</translation>
@@ -1950,6 +1956,7 @@
 <translation id="8175796834047840627">ඔබ පුරනය වී සිටින බැවින් Chrome ඔබට ඔබේ කාඩ්පත් ඔබේ Google ගිණුමට සුරැකීම පිරිනමයි. ඔබට මෙම හැසිරීම සැකසීම් තුළ වෙනස් කළ හැක.</translation>
 <translation id="8176440868214972690">සැකසීම් හෝ ප්‍රතිපත්ති වැනි, පහත සඳහන් වෙබ් අඩවි වෙත මෙම උපාංගයේ පරිපාලක යම් තොරතුරු යවා ඇත.</translation>
 <translation id="8184538546369750125">ගෝලීය පෙරනිමිය භාවිතා කරන්න (අවසර)</translation>
+<translation id="8190193880870196235">දිගුවක් මගින් කළමනාකරණය කෙරේ</translation>
 <translation id="8193086767630290324">රහසිගත ලෙස ලකුණු කළ දත්ත සම්බන්ධව ගත් ක්‍රියා</translation>
 <translation id="8194797478851900357">ගෙන යාම &amp;පසුගමනය කරන්න</translation>
 <translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" ID සමඟ වැරදි යාවත් ලිපිනයක්.</translation>
@@ -2049,6 +2056,7 @@
 <translation id="8541158209346794904">බ්ලූටූත් උපාංගය</translation>
 <translation id="8542014550340843547">පහළට තුන් වරක් ස්ටේපල් කරන්න</translation>
 <translation id="8543181531796978784">ඔබට <ph name="BEGIN_ERROR_LINK" />අනාවරණය කර ගැනීමේ ගැටලුවක් වාර්තා කිරීමට<ph name="END_ERROR_LINK" /> හෝ, ඔබට ඔබගේ ආරක්ෂාව සඳහා වන අවදානම වැටහෙන්නේ නම්, <ph name="BEGIN_LINK" />මෙම අනාරක්ෂිත වෙබ් අඩවිය වෙත පිවිසීමට<ph name="END_LINK" /> හැකිය.</translation>
+<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{අවසරය යළි සකසන්න}one{අවසර යළි සකසන්න}other{අවසර යළි සකසන්න}}</translation>
 <translation id="8557066899867184262">CVC ඔබේ කාඩ්පත පිටුපස පිහිටා ඇත.</translation>
 <translation id="8558485628462305855">වැඩි දියුණු කළ යතාර්ථ අන්තර්ගතය බැලීමට, ARCore යාවත්කාලීන කරන්න</translation>
 <translation id="8559762987265718583">ඔබගේ උපාංගයේ දිනය සහ වේලාව (<ph name="DATE_AND_TIME" />) නිවැරදි නොවන නිසා <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> වෙත පෞද්ගලික සම්බන්ධයක් සෑදිය නොහැකියි.</translation>
diff --git a/components/strings/components_strings_sw.xtb b/components/strings/components_strings_sw.xtb
index d97fa3a..9e93015 100644
--- a/components/strings/components_strings_sw.xtb
+++ b/components/strings/components_strings_sw.xtb
@@ -380,6 +380,7 @@
 <translation id="2310021320168182093">Chou2 (Bahasha)</translation>
 <translation id="2316887270356262533">Huongeza nafasi isiyozidi MB 1. Baadhi ya tovuti huenda zikapakia polepole zaidi utakapozivinjari tena.</translation>
 <translation id="2317259163369394535"><ph name="DOMAIN" /> inahitaji jina la mtumiaji na nenosiri.</translation>
+<translation id="2328651992442742497">Inaruhusiwa (chaguomsingi)</translation>
 <translation id="2330137317877982892"><ph name="CREDIT_CARD" />, muda wa matumizi utakwisha <ph name="EXPIRATION_DATE_ABBR" /></translation>
 <translation id="2337852623177822836">Mipangilio inadhibitiwa na msimamizi wako</translation>
 <translation id="2340263603246777781"><ph name="ORIGIN" /> inataka kuoanisha</translation>
@@ -428,6 +429,7 @@
 <translation id="2498091847651709837">Changanua kadi mpya</translation>
 <translation id="2501278716633472235">Rudi nyuma</translation>
 <translation id="2505268675989099013">Linda Akaunti</translation>
+<translation id="2512101340618156538">Hairuhusiwi (chaguomsingi)</translation>
 <translation id="2515629240566999685">Kuangalia uthabiti wa mawimbi katika eneo lako</translation>
 <translation id="2521385132275182522">Bana chini kulia</translation>
 <translation id="2523886232349826891">Imehifadhiwa kwenye kifaa hiki pekee</translation>
@@ -963,6 +965,7 @@
 <translation id="4434045419905280838">Madirisha ibukizi/kuelekeza kwingine</translation>
 <translation id="4435702339979719576">Kad ya Posta)</translation>
 <translation id="443673843213245140">Matumizi ya proksi yamelemazwa lakini usanidi wa proksi wazi umebainishwa.</translation>
+<translation id="4460315069258617173">Inaruhusiwa hadi utakapofunga vichupo vya tovuti hii</translation>
 <translation id="4464826014807964867">Tovuti zenye maelezo kutoka kwa shirika lako</translation>
 <translation id="4476953670630786061">Fomu hii si salama. Kipengele cha kujaza kiotomatiki kimezimwa.</translation>
 <translation id="4477350412780666475">Wimbo Unaofuata</translation>
@@ -1004,6 +1007,7 @@
 <translation id="464342062220857295">Vipengele vya utafutaji</translation>
 <translation id="4644670975240021822">Mpangilio uliopinduliwa zikiangalia chini</translation>
 <translation id="4646534391647090355">Nipeleke kwenye sehemu hiyo sasa</translation>
+<translation id="4652266463001779298">Hairuhusiwi</translation>
 <translation id="4658638640878098064">Toboa juu kushoto</translation>
 <translation id="4660119392514473465">Sasa unaweza kuvinjari kwa faragha na watu wengine wanaotumia kifaa hiki hawataona shughuli zako. Hata hivyo, vipakuliwa, alamisho na vipengee vya orodha ya kusoma vitahifadhiwa.</translation>
 <translation id="4668929960204016307">,</translation>
@@ -1713,6 +1717,7 @@
 <translation id="734600844861828519">11x15</translation>
 <translation id="7346048084945669753">Ni mshirika:</translation>
 <translation id="7349430561505560861">A4-Extra</translation>
+<translation id="7349921148288539306">Inaruhusiwa hadi utakapofunga kichupo hiki</translation>
 <translation id="7352651011704765696">Hitilafu fulani imetokea</translation>
 <translation id="7353601530677266744">Mbinu ya Amri</translation>
 <translation id="7359588939039777303">Matangazo yamezuiwa.</translation>
@@ -1855,6 +1860,7 @@
 <translation id="7800304661137206267">Muunganisho umesimbwa fiche kwa kutumia <ph name="CIPHER" />, kwa <ph name="MAC" /> ya uthibitishaji wa ujumbe na <ph name="KX" /> kama utaratibu muhimu wa ubadilishanaji.</translation>
 <translation id="7802523362929240268">Tovuti hii ni sahihi</translation>
 <translation id="780301667611848630">Hapana</translation>
+<translation id="7805571567667010077">Inadhibitiwa na shirika lako</translation>
 <translation id="7805768142964895445">Hali</translation>
 <translation id="7812922009395017822">Mir</translation>
 <translation id="7813600968533626083">Ungependa kuondoa pendekezo la fomu kutoka kwenye Chrome?</translation>
@@ -1950,6 +1956,7 @@
 <translation id="8175796834047840627">Chrome ina huduma ya kuhifadhi kadi zako kwenye Akaunti yako ya Google kwa sababu umeingia katika akaunti. Unaweza kubadilisha hali hii katika mipangilio.</translation>
 <translation id="8176440868214972690">Msimamizi wa kifaa hiki ametuma maelezo fulani kwenye tovuti zifuatazo, kama vile mipangilio au sera.</translation>
 <translation id="8184538546369750125">Tumia chaguomsingi la duniani (Ruhusu)</translation>
+<translation id="8190193880870196235">Inadhibitiwa na kiendelezi</translation>
 <translation id="8193086767630290324">Hatua zilizochukuliwa kwenye data iliyotiwa alama kuwa ni ya siri</translation>
 <translation id="8194797478851900357">Tendua hatua</translation>
 <translation id="8201077131113104583">URL ya sasisho si sahihi kwa kiendelezi chenye Kitambulisho "<ph name="EXTENSION_ID" />".</translation>
@@ -2047,6 +2054,7 @@
 <translation id="8541158209346794904">Kifaa cha Bluetooth</translation>
 <translation id="8542014550340843547">Bana mara tatu chini</translation>
 <translation id="8543181531796978784">Unaweza <ph name="BEGIN_ERROR_LINK" />kuripoti tatizo la ugunduzi<ph name="END_ERROR_LINK" /> au, ikiwa unaelewa kiwango cha hatari kinachoweza kutokea, <ph name="BEGIN_LINK" />tembelea tovuti hii isiyo salama<ph name="END_LINK" />.</translation>
+<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Badilisha ruhusa}other{Badilisha ruhusa}}</translation>
 <translation id="8557066899867184262">CVC inapatikana nyuma ya kadi yako.</translation>
 <translation id="8558485628462305855">Sasisha ARCore ili uangalie maudhui ya uhalisia ulioboreshwa</translation>
 <translation id="8559762987265718583">Muunganisho wa faragha kwenye <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hauwezi kupatikana kwa sababu tarehe na wakati wa kifaa chako (<ph name="DATE_AND_TIME" />) si sahihi.</translation>
diff --git a/components/strings/components_strings_uz.xtb b/components/strings/components_strings_uz.xtb
index 5c245ac..87fc76f 100644
--- a/components/strings/components_strings_uz.xtb
+++ b/components/strings/components_strings_uz.xtb
@@ -380,6 +380,7 @@
 <translation id="2310021320168182093">Chou2 (Envelope)</translation>
 <translation id="2316887270356262533">Xotiradan 1 MB tozalanadi. Bundan keyin ba’zi veb-saytlar sekinroq yuklanishi mumkin.</translation>
 <translation id="2317259163369394535"><ph name="DOMAIN" /> domeniga kirish uchun login va parolni kiritish zarur.</translation>
+<translation id="2328651992442742497">Ruxsat etilgan (standart)</translation>
 <translation id="2330137317877982892"><ph name="CREDIT_CARD" />, muddati: <ph name="EXPIRATION_DATE_ABBR" /></translation>
 <translation id="2337852623177822836">Sozlamani administrator boshqaradi</translation>
 <translation id="2340263603246777781"><ph name="ORIGIN" /> qurilmangizga ulanmoqchi</translation>
@@ -428,6 +429,7 @@
 <translation id="2498091847651709837">Yangi kartani skanerlash</translation>
 <translation id="2501278716633472235">Ortga qaytish</translation>
 <translation id="2505268675989099013">Hisobni himoyalash</translation>
+<translation id="2512101340618156538">Ruxsat berilmagan (standart)</translation>
 <translation id="2515629240566999685">Mobil aloqa signalini tekshirish</translation>
 <translation id="2521385132275182522">Quyi oʻngdan steplerlash</translation>
 <translation id="2523886232349826891">Faqat shu qurilmada saqlanadi</translation>
@@ -959,6 +961,7 @@
 <translation id="4434045419905280838">Qalquvchi oyna va yo‘naltirishlar</translation>
 <translation id="4435702339979719576">Postcard)</translation>
 <translation id="443673843213245140">Proksi-server o‘chiq, lekin uning sozlamalari aniq belgilangan.</translation>
+<translation id="4460315069258617173">Bu sayt uchun varaqlar yopilmaguncha ruxsat etilgan</translation>
 <translation id="4464826014807964867">Tashkilotingiz axborot yuborgan saytlar</translation>
 <translation id="4476953670630786061">Bu shakl xavfsiz emas. Avtomatik kiritish faolsizlantirildi.</translation>
 <translation id="4477350412780666475">Keyingi trek</translation>
@@ -1000,6 +1003,7 @@
 <translation id="464342062220857295">Funksiyalar qidiruvi</translation>
 <translation id="4644670975240021822">Teskari tartibda orqa tomonida</translation>
 <translation id="4646534391647090355">Hoziroq ochish</translation>
+<translation id="4652266463001779298">Ruxsat berilmagan</translation>
 <translation id="4658638640878098064">Yuqori chapdan steplerlash</translation>
 <translation id="4660119392514473465">Inkognito rejimida bajargan amallaringiz ushbu qurilmaning boshqa foydalanuvchilariga koʻrinmaydi. Biroq bukmarklar va yuklab olingan fayllar saqlanib qoladi.</translation>
 <translation id="4668929960204016307">,</translation>
@@ -1710,6 +1714,7 @@
 <translation id="734600844861828519">11x15</translation>
 <translation id="7346048084945669753">Tasarrufidami:</translation>
 <translation id="7349430561505560861">A4-Extra</translation>
+<translation id="7349921148288539306">Bu varaq yopilmaguncha ruxsat etilgan</translation>
 <translation id="7352651011704765696">Xatolik yuz berdi.</translation>
 <translation id="7353601530677266744">Buyruqlar qatori</translation>
 <translation id="7359588939039777303">Reklamalar bloklandi.</translation>
@@ -1852,6 +1857,7 @@
 <translation id="7800304661137206267">Xabarlar haqiqiyligi tekshiruvi uchun <ph name="KX" /> algoritmli <ph name="MAC" />, kalitlar almashinuvi uchun esa <ph name="CIPHER" /> mexanizmidan foydalanilmoqda.</translation>
 <translation id="7802523362929240268">Bu – xavfsiz sayt</translation>
 <translation id="780301667611848630">Kerak emas</translation>
+<translation id="7805571567667010077">Tashkilot tomonidan boshqariladi</translation>
 <translation id="7805768142964895445">Holat</translation>
 <translation id="7812922009395017822">Mir</translation>
 <translation id="7813600968533626083">Bu taklif Chrome’dan o‘chirib tashlansinmi?</translation>
@@ -1947,6 +1953,7 @@
 <translation id="8175796834047840627">Hisobingizga kirganingiz uchun Chrome kartalarni Google hisobingizga saqlashni taklif qilmoqda. Buni sozlamalar orqali oʻzgartirish mumkin.</translation>
 <translation id="8176440868214972690">Bu qurilma administratori quyidagi saytlarga sozlamalar va qoidalar kabi ayrim axborotlarni yubordi.</translation>
 <translation id="8184538546369750125">Global parametrdan foydalanish (ruxsat berish)</translation>
+<translation id="8190193880870196235">Kengaytma tomonidan boshqariladi</translation>
 <translation id="8193086767630290324">Maʼlumotlar bilan bajariladigan amallar maxfiy hisoblanadi</translation>
 <translation id="8194797478851900357">&amp;Ko‘chirib o‘tkazishni bekor qilish</translation>
 <translation id="8201077131113104583">“<ph name="EXTENSION_ID" />” identifikatoriga ega kengaytmani yangilash uchun yaroqsiz URL kiritildi</translation>
@@ -2046,6 +2053,7 @@
 <translation id="8541158209346794904">Bluetooth qurilma</translation>
 <translation id="8542014550340843547">Quyidan 3 marta steplerlash</translation>
 <translation id="8543181531796978784">Siz <ph name="BEGIN_ERROR_LINK" />aniqlangan muammo haqida xabar berishingiz<ph name="END_ERROR_LINK" /> yoki shaxsiy ma’lumotlaringizni xavf ostiga qo‘yishga tayyor bo‘lsangiz, <ph name="BEGIN_LINK" />ushbu xavfli saytga kirishingiz mumkin<ph name="END_LINK" />.</translation>
+<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Ruxsatni tiklash}other{Ruxsatlarni tiklash}}</translation>
 <translation id="8557066899867184262">CVC kod kartangizning orqa tomonida joylashgan.</translation>
 <translation id="8558485628462305855">Virtual reallik kontentini ochish uchun ARCore ilovasini yangilang</translation>
 <translation id="8559762987265718583">Tizimdagi sana va vaqt sozlamalari (<ph name="DATE_AND_TIME" />) noto‘g‘ri bo‘lganligi sababli <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> domeni bilan havfsiz aloqa o‘rnatib bo‘lmadi.</translation>
diff --git a/components/strings/components_strings_zh-HK.xtb b/components/strings/components_strings_zh-HK.xtb
index 1b94255..a0a8619 100644
--- a/components/strings/components_strings_zh-HK.xtb
+++ b/components/strings/components_strings_zh-HK.xtb
@@ -377,6 +377,7 @@
 <translation id="2310021320168182093">Chou2 (信封)</translation>
 <translation id="2316887270356262533">釋出的快取不到 1 MB。在您下次瀏覽部分網站時,載入速度可能會變慢。</translation>
 <translation id="2317259163369394535"><ph name="DOMAIN" /> 要求提供使用者名稱和密碼。</translation>
+<translation id="2328651992442742497">已允許 (預設)</translation>
 <translation id="2330137317877982892"><ph name="CREDIT_CARD" />,到期日:<ph name="EXPIRATION_DATE_ABBR" /></translation>
 <translation id="2337852623177822836">由管理員控制的設定</translation>
 <translation id="2340263603246777781"><ph name="ORIGIN" /> 要求與下列藍牙裝置配對</translation>
@@ -425,6 +426,7 @@
 <translation id="2498091847651709837">掃描新的信用卡</translation>
 <translation id="2501278716633472235">返回</translation>
 <translation id="2505268675989099013">保護帳戶</translation>
+<translation id="2512101340618156538">不允許 (預設)</translation>
 <translation id="2515629240566999685">檢查您所在地區的網絡訊號</translation>
 <translation id="2521385132275182522">釘裝 (右下方)</translation>
 <translation id="2523886232349826891">只會儲存至此裝置</translation>
@@ -954,6 +956,7 @@
 <translation id="4434045419905280838">彈出式視窗和重新導向</translation>
 <translation id="4435702339979719576">明信片</translation>
 <translation id="443673843213245140">雖然已停用 Proxy,不過已明確指定了 Proxy 設定。</translation>
+<translation id="4460315069258617173">權限於此網站的分頁關閉時到期</translation>
 <translation id="4464826014807964867">有來自您機構資料的網站</translation>
 <translation id="4476953670630786061">此表格不安全,自動填入功能已關閉。</translation>
 <translation id="4477350412780666475">下一首曲目</translation>
@@ -995,6 +998,7 @@
 <translation id="464342062220857295">搜尋功能</translation>
 <translation id="4644670975240021822">相反順序 (正面朝下)</translation>
 <translation id="4646534391647090355">立即前往下載中心</translation>
+<translation id="4652266463001779298">不允許</translation>
 <translation id="4658638640878098064">釘裝 (左上方)</translation>
 <translation id="4660119392514473465">現在您可私下瀏覽內容,而使用這部電腦的其他使用者將無法看到您的活動。不過,您的下載檔案、書籤和閱讀清單項目仍會保留在裝置上。</translation>
 <translation id="4668929960204016307">,</translation>
@@ -1706,6 +1710,7 @@
 <translation id="734600844861828519">11x15</translation>
 <translation id="7346048084945669753">是否已建立關聯:</translation>
 <translation id="7349430561505560861">A4-Extra</translation>
+<translation id="7349921148288539306">權限於此分頁關閉時到期</translation>
 <translation id="7352651011704765696">發生問題</translation>
 <translation id="7353601530677266744">命令列</translation>
 <translation id="7359588939039777303">已封鎖廣告。</translation>
@@ -1848,6 +1853,7 @@
 <translation id="7800304661137206267">連線採用 <ph name="CIPHER" /> 加密,並設有 <ph name="MAC" /> 訊息驗證及 <ph name="KX" /> 金鑰交換機制。</translation>
 <translation id="7802523362929240268">合法網站</translation>
 <translation id="780301667611848630">不用了,謝謝</translation>
+<translation id="7805571567667010077">由您的機構管理</translation>
 <translation id="7805768142964895445">狀態</translation>
 <translation id="7812922009395017822">Mir</translation>
 <translation id="7813600968533626083">要從 Chrome 中移除表格建議嗎?</translation>
@@ -1943,6 +1949,7 @@
 <translation id="8175796834047840627">由於您已登入,因此 Chrome 提議將您的付款卡儲存至 Google 帳戶。您可以在設定中變更此行為。</translation>
 <translation id="8176440868214972690">此裝置的管理員已將一些資訊 (例如設定或政策) 傳送到以下網站。</translation>
 <translation id="8184538546369750125">使用全域預設值 (允許)</translation>
+<translation id="8190193880870196235">由擴充程式管理</translation>
 <translation id="8193086767630290324">在標示為機密的資料所採取的行動</translation>
 <translation id="8194797478851900357">復原移動(&amp;U)</translation>
 <translation id="8201077131113104583">無效的擴充功能 (ID:<ph name="EXTENSION_ID" />) 更新網址。</translation>
@@ -2042,6 +2049,7 @@
 <translation id="8541158209346794904">藍牙裝置</translation>
 <translation id="8542014550340843547">三釘 (底部)</translation>
 <translation id="8543181531796978784">您可以<ph name="BEGIN_ERROR_LINK" />報告偵測問題<ph name="END_ERROR_LINK" />;或如果您瞭解安全性風險,也可以<ph name="BEGIN_LINK" />瀏覽這個不安全的網站<ph name="END_LINK" />。</translation>
+<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{重設權限}other{重設權限}}</translation>
 <translation id="8557066899867184262">信用卡驗證碼 (CVC) 位於信用卡背面。</translation>
 <translation id="8558485628462305855">如要觀看擴張實境內容,請先更新 ARCore</translation>
 <translation id="8559762987265718583">您裝置的日期和時間 (<ph name="DATE_AND_TIME" />) 不正確,因此無法建立私人連線至 <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />。</translation>
diff --git a/components/user_manager/known_user_unittest.cc b/components/user_manager/known_user_unittest.cc
index 996df18..5b2d2af 100644
--- a/components/user_manager/known_user_unittest.cc
+++ b/components/user_manager/known_user_unittest.cc
@@ -403,14 +403,14 @@
   }
 }
 
-// Test failing on linux-chromeos-chrome (crbug.com/1198519)
-TEST_F(KnownUserTest, DISABLED_RemovePrefOnReservedPref) {
+TEST_F(KnownUserTest, RemovePrefOnReservedPref) {
   KnownUser known_user(local_state());
   const std::string kReservedPrefName = "device_id";
 
   known_user.SetStringPref(kDefaultAccountId, kReservedPrefName, "value");
-  ASSERT_DEATH(known_user.RemovePref(kDefaultAccountId, kReservedPrefName),
-               ".*Check failed.*");
+  // Don't verify the message because on some builds CHECK failures do not print
+  // debug messages (https://crbug.com/1198519).
+  ASSERT_DEATH(known_user.RemovePref(kDefaultAccountId, kReservedPrefName), "");
 }
 
 TEST_F(KnownUserTest, GaiaIdMigrationStatus) {
diff --git a/components/user_manager/user.cc b/components/user_manager/user.cc
index 1766663..e0359a0 100644
--- a/components/user_manager/user.cc
+++ b/components/user_manager/user.cc
@@ -197,11 +197,6 @@
   return GetType() == user_manager::USER_TYPE_ACTIVE_DIRECTORY;
 }
 
-bool User::IsChildOrDeprecatedSupervised() const {
-  UserType type = GetType();
-  return type == USER_TYPE_SUPERVISED_DEPRECATED || type == USER_TYPE_CHILD;
-}
-
 bool User::IsChild() const {
   return GetType() == USER_TYPE_CHILD;
 }
@@ -250,7 +245,6 @@
       return true;
     case user_manager::USER_TYPE_GUEST:
     case user_manager::USER_TYPE_PUBLIC_ACCOUNT:
-    case user_manager::USER_TYPE_SUPERVISED_DEPRECATED:
     case user_manager::USER_TYPE_KIOSK_APP:
     case user_manager::USER_TYPE_ARC_KIOSK_APP:
     case user_manager::USER_TYPE_ACTIVE_DIRECTORY:
diff --git a/components/user_manager/user.h b/components/user_manager/user.h
index a0758f6..3607e04b 100644
--- a/components/user_manager/user.h
+++ b/components/user_manager/user.h
@@ -102,10 +102,6 @@
   // Returns true if it's Active Directory user.
   virtual bool IsActiveDirectoryUser() const;
 
-  // Returns true if user is child or deprecated legacy supervised.
-  // TODO(crbug/1155729): Remove and replace with IsChild().
-  virtual bool IsChildOrDeprecatedSupervised() const;
-
   // Returns true if user is child.
   virtual bool IsChild() const;
 
diff --git a/components/user_manager/user_manager.cc b/components/user_manager/user_manager.cc
index fd01464..e5b3465 100644
--- a/components/user_manager/user_manager.cc
+++ b/components/user_manager/user_manager.cc
@@ -115,7 +115,7 @@
       LOG(FATAL) << "Incorrect child user type " << user_type;
     }
 
-    // TODO (rsorokin): Check for reverse: account_id AD type should imply
+    // TODO(rsorokin): Check for reverse: account_id AD type should imply
     // AD user type.
     if (user_type == USER_TYPE_ACTIVE_DIRECTORY &&
         account_id.GetAccountType() != AccountType::ACTIVE_DIRECTORY) {
@@ -129,9 +129,6 @@
   if (is_child)
     return USER_TYPE_CHILD;
 
-  if (IsDeprecatedSupervisedAccountId(account_id))
-    return USER_TYPE_SUPERVISED_DEPRECATED;
-
   if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY)
     return USER_TYPE_ACTIVE_DIRECTORY;
 
diff --git a/components/user_manager/user_manager.h b/components/user_manager/user_manager.h
index 1bd8c2a..4a8b48c8 100644
--- a/components/user_manager/user_manager.h
+++ b/components/user_manager/user_manager.h
@@ -325,8 +325,7 @@
   virtual bool IsGaiaUserAllowed(const User& user) const = 0;
 
   // Returns true if |user| is allowed depending on device policies.
-  // Accepted user types: USER_TYPE_REGULAR, USER_TYPE_GUEST,
-  // USER_TYPE_SUPERVISED_DEPRECATED, USER_TYPE_CHILD.
+  // Accepted user types: USER_TYPE_REGULAR, USER_TYPE_GUEST, USER_TYPE_CHILD.
   virtual bool IsUserAllowed(const User& user) const = 0;
 
   // Returns "Local State" PrefService instance.
diff --git a/components/user_manager/user_type.h b/components/user_manager/user_type.h
index ac1677a..a751f4a 100644
--- a/components/user_manager/user_type.h
+++ b/components/user_manager/user_type.h
@@ -24,16 +24,13 @@
   // ephemeral.
   USER_TYPE_GUEST = 1,
 
-  /* USER_TYPE_RETAIL_MODE = 2, // deprecated */
+  // USER_TYPE_RETAIL_MODE = 2, // deprecated
 
   // Public account user, logs in without authentication. Available only if
   // enabled through device policy. No Gaia account. Always ephemeral.
   USER_TYPE_PUBLIC_ACCOUNT = 3,
 
-  // Legacy supervised user, being deprecated. Logs in only with local
-  // authentication. No Gaia account. Never ephemeral. Could have a sync token
-  // to fetch some basic account info.
-  USER_TYPE_SUPERVISED_DEPRECATED = 4,
+  // USER_TYPE_SUPERVISED_DEPRECATED = 4,
 
   // Kiosk users used to launch application in a single app mode. Logs in
   // without authentications. No Gaia user account. Uses device robot account.
diff --git a/components/viz/service/debugger/viz_debugger.cc b/components/viz/service/debugger/viz_debugger.cc
index c86cef4..29ba312 100644
--- a/components/viz/service/debugger/viz_debugger.cc
+++ b/components/viz/service/debugger/viz_debugger.cc
@@ -32,11 +32,13 @@
 VizDebugger::FilterBlock::FilterBlock(const std::string file_str,
                                       const std::string func_str,
                                       const std::string anno_str,
-                                      bool is_active)
+                                      bool is_active,
+                                      bool is_enabled)
     : file(std::move(file_str)),
       func(std::move(func_str)),
       anno(std::move(anno_str)),
-      active(is_active) {}
+      active(is_active),
+      enabled(is_enabled) {}
 
 VizDebugger::FilterBlock::~FilterBlock() = default;
 
@@ -181,7 +183,7 @@
 void VizDebugger::ApplyFilters(VizDebugger::StaticSource* src) {
   // In the case of no filters we disable this source.
   src->active = false;
-
+  src->enabled = false;
   // TODO(petermcneeley): We should probably make this string filtering more
   // optimal. However, for the most part it the cost is only paid on the
   // application of new filters.
@@ -198,6 +200,7 @@
         simple_match(src->func, filter_block.func) &&
         simple_match(src->anno, filter_block.anno)) {
       src->active = filter_block.active;
+      src->enabled = filter_block.enabled;
     }
   }
 }
@@ -289,6 +292,7 @@
     const base::Value* func = filter.FindPath("selector.func");
     const base::Value* anno = filter.FindPath("selector.anno");
     const base::Value* active = filter.FindPath("active");
+    const base::Value* enabled = filter.FindPath("enabled");
 
     if (!active) {
       LOG(ERROR) << "Missing filter props in json: " << json;
@@ -305,8 +309,9 @@
       return (filter_str ? filter_str->GetString() : std::string());
     };
 
-    new_filters_.emplace_back(check_str(file), check_str(func), check_str(anno),
-                              active->GetBool());
+    new_filters_.emplace_back(
+        check_str(file), check_str(func), check_str(anno), active->GetBool(),
+        (enabled && enabled->is_bool()) ? enabled->GetBool() : true);
   }
 
   apply_new_filters_next_frame_ = true;
diff --git a/components/viz/service/debugger/viz_debugger.h b/components/viz/service/debugger/viz_debugger.h
index 6b945e53..7d698ee 100644
--- a/components/viz/service/debugger/viz_debugger.h
+++ b/components/viz/service/debugger/viz_debugger.h
@@ -49,13 +49,15 @@
                  int file_line,
                  const char* func_name);
     inline bool IsActive() const { return active; }
-    const char* anno;
-    const char* file;
-    const char* func;
-    const int line;
+    inline bool IsEnabled() const { return enabled; }
+    const char* anno = nullptr;
+    const char* file = nullptr;
+    const char* func = nullptr;
+    const int line = 0;
 
-    int reg_index;
-    bool active;
+    int reg_index = 0;
+    bool active = false;
+    bool enabled = false;
   };
 
   struct DrawOption {
@@ -173,13 +175,15 @@
     FilterBlock(const std::string file_str,
                 const std::string func_str,
                 const std::string anno_str,
-                bool is_active);
+                bool is_active,
+                bool is_enabled);
     ~FilterBlock();
     FilterBlock(const FilterBlock& other);
     std::string file;
     std::string func;
     std::string anno;
-    bool active;
+    bool active = false;
+    bool enabled = false;
   };
 
   // Synchronize access to the variables in the block below as it is mutated by
@@ -262,6 +266,20 @@
 
 #define DBG_DRAW_RECT(anno, rect) DBG_DRAW_RECT_OPT(anno, DBG_OPT_BLACK, rect)
 
+#define DBG_FLAG_FBOOL(anno, fun_name)                                    \
+  namespace {                                                             \
+  bool fun_name() {                                                       \
+    if (viz::VizDebugger::IsEnabled()) {                                  \
+      static viz::VizDebugger::StaticSource dcs(anno, __FILE__, __LINE__, \
+                                                __func__);                \
+      if (dcs.IsEnabled()) {                                              \
+        return true;                                                      \
+      }                                                                   \
+    }                                                                     \
+    return false;                                                         \
+  }                                                                       \
+  }  // namespace
+
 #else  //  !BUILDFLAG(USE_VIZ_DEBUGGER)
 
 #define VIZ_DEBUGGER_IS_ON() false
@@ -325,6 +343,11 @@
 
 #define DBG_DRAW_RECT(anno, rect) DBG_DRAW_RECT_OPT(anno, DBG_OPT_BLACK, rect)
 
+#define DBG_FLAG_FBOOL(anno, fun_name)       \
+  namespace {                                \
+  constexp bool fun_name() { return false; } \
+  }
+
 #endif  // BUILDFLAG(USE_VIZ_DEBUGGER)
 
 #endif  // COMPONENTS_VIZ_SERVICE_DEBUGGER_VIZ_DEBUGGER_H_
diff --git a/components/viz/service/debugger/viz_debugger_unittest.cc b/components/viz/service/debugger/viz_debugger_unittest.cc
index 0b2b39e2a..7aa307b 100644
--- a/components/viz/service/debugger/viz_debugger_unittest.cc
+++ b/components/viz/service/debugger/viz_debugger_unittest.cc
@@ -58,6 +58,7 @@
   std::string func;
   std::string file;
   bool active = true;
+  bool enabled = true;
 };
 
 static_assert(sizeof(VizDebuggerInternal) == sizeof(VizDebugger),
@@ -89,6 +90,7 @@
 
       full_filter.SetKey("selector", std::move(selector));
       full_filter.SetBoolean("active", each.active);
+      full_filter.SetBoolean("enabled", each.enabled);
       filters_list.Append(std::move(full_filter));
     }
     filters_json.SetKey("filters", std::move(filters_list));
@@ -387,6 +389,26 @@
   }
 }
 
+constexpr const char kTestFlagFunctionAnnoName[] = "testflagfunctionanno";
+
+DBG_FLAG_FBOOL(kTestFlagFunctionAnnoName, check_flag_enabled)
+
+static bool FlagFunctionTestEnable() {
+  return check_flag_enabled();
+}
+
+TEST_F(VisualDebuggerTest, TestDebugFlagAnnoAndFunction) {
+  GetInternal()->ForceEnabled();
+
+  // Set our test flag to be disabled.
+  SetFilter({TestFilter({kTestFlagFunctionAnnoName, "", "", true, false})});
+  EXPECT_FALSE(FlagFunctionTestEnable());
+  SetFilter({TestFilter({kTestFlagFunctionAnnoName, "", "", true, true})});
+  EXPECT_TRUE(FlagFunctionTestEnable());
+  SetFilter({TestFilter({kTestFlagFunctionAnnoName, "", "", true, false})});
+  EXPECT_FALSE(FlagFunctionTestEnable());
+}
+
 }  // namespace
 }  // namespace viz
 #endif  // VIZ_DEBUGGER_IS_ON()
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index be3984b7..fbf7fab3 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -5169,19 +5169,7 @@
   destroyed_watcher.Wait();
 }
 
-class AccessibilityWinUIASelectivelyEnabledBrowserTest
-    : public AccessibilityWinUIABrowserTest {
- protected:
-  void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kSelectiveUIAEnablement);
-
-    AccessibilityWinUIABrowserTest::SetUp();
-  }
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-IN_PROC_BROWSER_TEST_F(AccessibilityWinUIASelectivelyEnabledBrowserTest,
+IN_PROC_BROWSER_TEST_F(AccessibilityWinUIABrowserTest,
                        RequestingTopLevelElementEnablesWebAccessibility) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
 
@@ -5202,43 +5190,10 @@
   uia->ElementFromHandle(hwnd, &root);
   ASSERT_NE(nullptr, root.Get());
 
-  // Native API support should now be enabled.
-  ui::AXMode expected_mode = ui::AXMode::kNativeAPIs;
-  EXPECT_EQ(expected_mode, content::BrowserAccessibilityStateImpl::GetInstance()
-                               ->GetAccessibilityMode());
-
-  // Now get the fragment root's first (only) child.
-  Microsoft::WRL::ComPtr<IUIAutomationTreeWalker> tree_walker;
-  uia->get_RawViewWalker(&tree_walker);
-  Microsoft::WRL::ComPtr<IUIAutomationElement> first_child;
-  tree_walker->GetFirstChildElement(root.Get(), &first_child);
-  ASSERT_NE(nullptr, first_child.Get());
-
-  base::win::ScopedBstr name;
-  ASSERT_HRESULT_SUCCEEDED(first_child->get_CurrentName(name.Receive()));
-
   // Web content accessibility support should now be enabled.
-  expected_mode |= ui::AXMode::kWebContents;
-  EXPECT_EQ(expected_mode, content::BrowserAccessibilityStateImpl::GetInstance()
-                               ->GetAccessibilityMode());
-
-  Microsoft::WRL::ComPtr<IUnknown> text_pattern_unknown;
-  ASSERT_HRESULT_SUCCEEDED(
-      first_child->GetCurrentPattern(UIA_TextPatternId, &text_pattern_unknown));
-  EXPECT_EQ(nullptr, text_pattern_unknown.Get());
-
-  // Now check that inline text box support is enabled as well.
-  expected_mode |= ui::AXMode::kInlineTextBoxes;
-  EXPECT_EQ(expected_mode, content::BrowserAccessibilityStateImpl::GetInstance()
-                               ->GetAccessibilityMode());
-
-  Microsoft::WRL::ComPtr<IUIAutomationElement> labelled_by;
-  ASSERT_HRESULT_SUCCEEDED(first_child->get_CurrentLabeledBy(&labelled_by));
-
-  // Now check that we have complete accessibility support enabled.
-  expected_mode |= ui::AXMode::kScreenReader;
-  EXPECT_EQ(expected_mode, content::BrowserAccessibilityStateImpl::GetInstance()
-                               ->GetAccessibilityMode());
+  EXPECT_EQ(ui::kAXModeComplete,
+            content::BrowserAccessibilityStateImpl::GetInstance()
+                ->GetAccessibilityMode());
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityWinUIABrowserTest,
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_win.cc b/content/browser/accessibility/browser_accessibility_state_impl_win.cc
index a15418f..9c1ea74 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl_win.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl_win.cc
@@ -74,38 +74,18 @@
     BrowserAccessibilityStateImpl::GetInstance()->OnAccessibilityApiUsage();
   }
 
-  void OnBasicUIAutomationUsed() override {
-    AddAXModeForUIA(ui::AXMode::kNativeAPIs);
-  }
-
-  void OnAdvancedUIAutomationUsed() override {
-    AddAXModeForUIA(ui::AXMode::kWebContents);
-  }
-
-  void OnProbableUIAutomationScreenReaderDetected() override {
-    // Same as kAXModeComplete but without kHTML as it is not needed for UIA.
-    AddAXModeForUIA(ui::kAXModeCompleteNoHTML);
-  }
-
-  void OnTextPatternRequested() override {
-    AddAXModeForUIA(ui::AXMode::kInlineTextBoxes);
-  }
-
-  void AddAXModeForUIA(ui::AXMode mode) {
+  void OnUIAutomationUsed() override {
     DCHECK(::switches::IsExperimentalAccessibilityPlatformUIAEnabled());
 
     // Firing a UIA event can cause UIA to call back into our APIs, don't
     // consider this to be usage.
     if (firing_uia_events_)
       return;
-
     // UI Automation insulates providers from knowing about the client(s) asking
-    // for information. When IsSelectiveUIAEnablement is Enabled, we turn on
-    // various parts of accessibility depending on what APIs have been called.
-    if (!features::IsSelectiveUIAEnablementEnabled())
-      mode = ui::kAXModeComplete;
+    // for information. When UI Automation is requested, assume the presence of
+    // a full-fledged accessibility technology and enable full support.
     BrowserAccessibilityStateImpl::GetInstance()->AddAccessibilityModeFlags(
-        mode);
+        ui::kAXModeComplete);
     BrowserAccessibilityStateImpl::GetInstance()->OnAccessibilityApiUsage();
   }
 
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index a3a6beb..eefad1a6 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -22,7 +22,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/time/time.h"
 #include "build/build_config.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/isolated_origin_util.h"
@@ -799,8 +798,9 @@
 // time is needed rather than leaving the interval open ended, so that we can
 // enforce a max delay here and in RenderProcessHost. https://crbug.com/1181838
 ChildProcessSecurityPolicyImpl::ChildProcessSecurityPolicyImpl()
-    : browsing_instance_cleanup_delay_in_seconds_(
-          RenderFrameHostImpl::kKeepAliveHandleFactoryTimeoutInSeconds + 2) {
+    : browsing_instance_cleanup_delay_(
+          RenderProcessHostImpl::kKeepAliveHandleFactoryTimeout +
+          base::TimeDelta::FromSeconds(2)) {
   // We know about these schemes and believe them to be safe.
   RegisterWebSafeScheme(url::kHttpScheme);
   RegisterWebSafeScheme(url::kHttpsScheme);
@@ -2354,15 +2354,14 @@
         ChildProcessSecurityPolicyImpl::GetInstance();
     policy->RemoveOptInIsolatedOriginsForBrowsingInstanceInternal(id);
   };
-  if (browsing_instance_cleanup_delay_in_seconds_ > 0) {
+  if (browsing_instance_cleanup_delay_ > base::TimeDelta()) {
     // Do the actual state cleanup after posting a task to the IO thread, to
     // give a chance for any last unprocessed tasks to be handled. The cleanup
     // itself locks the data structures and can safely happen from either
     // thread.
     GetIOThreadTaskRunner({})->PostDelayedTask(
         FROM_HERE, base::BindOnce(task_closure, browsing_instance_id),
-        base::TimeDelta::FromSeconds(
-            browsing_instance_cleanup_delay_in_seconds_));
+        browsing_instance_cleanup_delay_);
   } else {
     // Since this is just used in tests, it's ok to do it on either thread.
     task_closure(browsing_instance_id);
diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h
index f197319..44eaddd9 100644
--- a/content/browser/child_process_security_policy_impl.h
+++ b/content/browser/child_process_security_policy_impl.h
@@ -20,6 +20,7 @@
 #include "base/memory/singleton.h"
 #include "base/synchronization/lock.h"
 #include "base/thread_annotations.h"
+#include "base/time/time.h"
 #include "content/browser/can_commit_status.h"
 #include "content/browser/isolated_origin_util.h"
 #include "content/browser/isolation_context.h"
@@ -647,7 +648,8 @@
   // Allows tests to modify the delay in cleaning up BrowsingInstanceIds. If the
   // delay is set to zero, cleanup happens immediately.
   void SetBrowsingInstanceCleanupDelayForTesting(int64_t delay_in_seconds) {
-    browsing_instance_cleanup_delay_in_seconds_ = delay_in_seconds;
+    browsing_instance_cleanup_delay_ =
+        base::TimeDelta::FromSeconds(delay_in_seconds);
   }
 
  private:
@@ -1011,7 +1013,7 @@
   // TODO(wjmaclean): we know the IncrementKeepAliveRefCount API needs
   // improvement, and with it the BrowsingInstance cleanup here can also be
   // improved.
-  int64_t browsing_instance_cleanup_delay_in_seconds_;
+  base::TimeDelta browsing_instance_cleanup_delay_;
 
   DISALLOW_COPY_AND_ASSIGN(ChildProcessSecurityPolicyImpl);
 };
diff --git a/content/browser/loader/prefetch_browsertest_base.cc b/content/browser/loader/prefetch_browsertest_base.cc
index 64804ae4..f6cd502 100644
--- a/content/browser/loader/prefetch_browsertest_base.cc
+++ b/content/browser/loader/prefetch_browsertest_base.cc
@@ -118,30 +118,27 @@
   // Execute the JavaScript code to trigger the followup navigation from the
   // current page.
   EXPECT_TRUE(
-      ExecJs(shell()->web_contents(),
-             base::StringPrintf("location.href = '%s';", url.spec().c_str())));
+      ExecJs(shell()->web_contents(), JsReplace("location.href = $1;", url)));
   EXPECT_EQ(title16, title_watcher.WaitAndGetTitle());
 }
 
 void PrefetchBrowserTestBase::WaitUntilLoaded(const GURL& url) {
   std::string script = R"(
-new Promise((resolve) => {
-  const url = $1;
-  if (performance.getEntriesByName(url).length > 0) {
-    resolve();
-    return;
-  }
-  new PerformanceObserver((list) => {
-    if (list.getEntriesByName(url).length > 0) {
-      resolve();
-    }
-  }).observe({ entryTypes: ['resource'] });
-}).then(() => {
-  window.domAutomationController.send(true);
-}))";
+    new Promise((resolve) => {
+      const url = $1;
+      if (performance.getEntriesByName(url).length > 0) {
+        resolve();
+        return;
+      }
+      new PerformanceObserver((list) => {
+        if (list.getEntriesByName(url).length > 0) {
+          resolve();
+        }
+      }).observe({ entryTypes: ['resource'] });
+    })
+  )";
 
-  ASSERT_EQ(true, EvalJs(shell()->web_contents(), JsReplace(script, url),
-                         EXECUTE_SCRIPT_USE_MANUAL_REPLY));
+  ASSERT_TRUE(ExecJs(shell()->web_contents(), JsReplace(script, url)));
 }
 
 // static
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 0eaa437..86c2df1 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -373,6 +373,14 @@
 
 namespace {
 
+constexpr int kSubframeProcessShutdownLongDelayInMSec = 8 * 1000;
+static_assert(kSubframeProcessShutdownLongDelayInMSec +
+                      RenderViewHostImpl::kUnloadTimeoutInMSec <
+                  RenderProcessHostImpl::kKeepAliveHandleFactoryTimeoutInMSec,
+              "The maximum process shutdown delay should not exceed the "
+              "keepalive timeout. This has security implications, see "
+              "https://crbug.com/1177674.");
+
 #if defined(OS_ANDROID)
 const void* const kRenderFrameHostAndroidKey = &kRenderFrameHostAndroidKey;
 #endif  // OS_ANDROID
@@ -941,7 +949,9 @@
 
   static constexpr base::TimeDelta kShortDelay =
       base::TimeDelta::FromSeconds(2);
-  static constexpr base::TimeDelta kLongDelay = base::TimeDelta::FromSeconds(8);
+  static constexpr base::TimeDelta kLongDelay =
+      base::TimeDelta::FromMilliseconds(
+          kSubframeProcessShutdownLongDelayInMSec);
   // Added to delay if based on recent performance (i.e., |kHistoryBased| and
   // |kHistoryBasedLong|) to account for small variations in timing.
   static constexpr base::TimeDelta kDelayBuffer =
@@ -1461,9 +1471,9 @@
               BrowserThread::GetTaskRunnerForThread(
                   ServiceWorkerContext::GetCoreThreadId()))),
       frame_token_(frame_token),
-      keep_alive_handle_factory_(agent_scheduling_group_.GetProcess(),
-                                 base::TimeDelta::FromSeconds(
-                                     kKeepAliveHandleFactoryTimeoutInSeconds)),
+      keep_alive_handle_factory_(
+          agent_scheduling_group_.GetProcess(),
+          RenderProcessHostImpl::kKeepAliveHandleFactoryTimeout),
       subframe_unload_timeout_(RenderViewHostImpl::kUnloadTimeout),
       media_device_id_salt_base_(
           BrowserContext::CreateRandomMediaDeviceIDSalt()),
@@ -3082,10 +3092,10 @@
 
     // We change the lifecycle state to kRunningUnloadHandlers at the end of
     // this method to wait until OnUnloadACK() is invoked.
-    // But for subframes, we delay process shutdown if unload event handlers
-    // are set in order to avoid an immediate process shutdown on a page with an
-    // OOPIF navigating cross-process. Also we have the maximum delay limit
-    // for security reasons. See, crbug entries for the following comments.
+    // For subframes, process shutdown may be delayed for two reasons:
+    // (1) to allow the process to be potentially reused by future navigations
+    // withjin a short time window, and
+    // (2) to give the subframe unload handlers a chance to execute.
     if (!frame_tree_node_->IsMainFrame() && IsActive()) {
       base::TimeDelta subframe_shutdown_timeout =
           delegate_->IsBeingDestroyed()
@@ -3096,17 +3106,15 @@
       // have a chance to execute by delaying process cleanup. This will prevent
       // the process from shutting down immediately in the case where this is
       // the last active frame in the process. See https://crbug.com/852204.
+      // Note that in the majority of cases, this is not necessary now that we
+      // keep track of pending delete RenderFrameHost
+      // (https://crbug.com/609963), but there are still a few exceptions where
+      // this is needed (https://crbug.com/1014550).
       const base::TimeDelta unload_handler_timeout =
           has_unload_handlers() ? subframe_unload_timeout_ : base::TimeDelta();
 
       if (!subframe_shutdown_timeout.is_zero() ||
           !unload_handler_timeout.is_zero()) {
-        // Don't delay shutdown longer than the maximum delay for renderer
-        // processes, enforced for security reasons (crbug.com/1177674).
-        DCHECK_LE(subframe_shutdown_timeout + unload_handler_timeout,
-                  base::TimeDelta::FromSeconds(
-                      kKeepAliveHandleFactoryTimeoutInSeconds));
-
         RenderProcessHostImpl* process =
             static_cast<RenderProcessHostImpl*>(GetProcess());
         process->DelayProcessShutdown(subframe_shutdown_timeout,
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 06ba84b..2727e4a 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -269,10 +269,6 @@
   using IsClipboardPasteContentAllowedCallback =
       ContentBrowserClient::IsClipboardPasteContentAllowedCallback;
 
-  // Exposed as a public constant to share with other entities that need to
-  // accommodate frame/process shutdown delays.
-  static const int kKeepAliveHandleFactoryTimeoutInSeconds = 30;
-
   // An accessibility reset is only allowed to prevent very rare corner cases
   // or race conditions where the browser and renderer get out of sync. If
   // this happens more than this many times, kill the renderer.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 9b07757..2bbf363 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1691,6 +1691,10 @@
 const unsigned int RenderProcessHostImpl::kMaxFrameDepthForPriority =
     std::numeric_limits<unsigned int>::max();
 
+// static
+const base::TimeDelta RenderProcessHostImpl::kKeepAliveHandleFactoryTimeout =
+    base::TimeDelta::FromMilliseconds(kKeepAliveHandleFactoryTimeoutInMSec);
+
 RenderProcessHostImpl::RenderProcessHostImpl(
     BrowserContext* browser_context,
     StoragePartitionImpl* storage_partition_impl,
@@ -2339,11 +2343,14 @@
     tracker->IncrementSiteProcessCount(site_info, GetID());
   }
 
+  // Don't delay shutdown longer than the maximum delay for renderer process,
+  // enforced for security reasons (https://crbug.com/1177674).
   GetUIThreadTaskRunner({})->PostDelayedTask(
       FROM_HERE,
       base::BindOnce(&RenderProcessHostImpl::CancelProcessShutdownDelay,
                      weak_factory_.GetWeakPtr(), site_info),
-      subframe_shutdown_timeout + unload_handler_timeout);
+      std::min(subframe_shutdown_timeout + unload_handler_timeout,
+               kKeepAliveHandleFactoryTimeout));
 
   time_spent_running_unload_handlers_ = unload_handler_timeout;
 }
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 18f90f71..f0a01469 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -28,6 +28,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/sequence_bound.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "content/browser/child_process_launcher.h"
@@ -178,6 +179,11 @@
   // Special depth used when there are no PriorityClients.
   static const unsigned int kMaxFrameDepthForPriority;
 
+  // Exposed as a public constant to share with other entities that need to
+  // accommodate frame/process shutdown delays.
+  static constexpr int kKeepAliveHandleFactoryTimeoutInMSec = 30 * 1000;
+  static const base::TimeDelta kKeepAliveHandleFactoryTimeout;
+
   // Create a new RenderProcessHost. The storage partition for the process
   // is retrieved from |browser_context| based on information in
   // |site_instance|. The default storage partition is selected if
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index ba5556e..fc0290b 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -97,6 +97,8 @@
       public IPC::Listener,
       public base::RefCounted<RenderViewHostImpl> {
  public:
+  static constexpr int kUnloadTimeoutInMSec = 500;
+
   // Convenience function, just like RenderViewHost::FromID.
   static RenderViewHostImpl* FromID(int process_id, int routing_id);
 
@@ -347,7 +349,7 @@
   // Delay to wait on closing the WebContents for a beforeunload/unload handler
   // to fire.
   static constexpr base::TimeDelta kUnloadTimeout =
-      base::TimeDelta::FromMilliseconds(500);
+      base::TimeDelta::FromMilliseconds(kUnloadTimeoutInMSec);
 
   // The RenderWidgetHost.
   const std::unique_ptr<RenderWidgetHostImpl> render_widget_host_;
diff --git a/content/browser/web_package/web_bundle_browsertest.cc b/content/browser/web_package/web_bundle_browsertest.cc
index 8421201a..cedd9bc 100644
--- a/content/browser/web_package/web_bundle_browsertest.cc
+++ b/content/browser/web_package/web_bundle_browsertest.cc
@@ -2074,7 +2074,7 @@
 }
 
 // TODO(https://crbug.com/1225178): flaky
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_ANDROID)
 #define MAYBE_ParseMetadataCrash DISABLED_ParseMetadataCrash
 #else
 #define MAYBE_ParseMetadataCrash ParseMetadataCrash
@@ -2093,7 +2093,13 @@
       console_message);
 }
 
-IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, ParseResponseCrash) {
+// TODO(https://crbug.com/1225178): flaky
+#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_ANDROID)
+#define MAYBE_ParseResponseCrash DISABLED_ParseResponseCrash
+#else
+#define MAYBE_ParseResponseCrash ParseResponseCrash
+#endif
+IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, MAYBE_ParseResponseCrash) {
   base::FilePath test_file_path = GetTestDataPath("mocked.wbn");
   MockParserFactory mock_factory({GURL(kTestPageUrl)}, test_file_path);
   mock_factory.SimulateParseResponseCrash();
diff --git a/docs/testing/chromeos_debugging_tips.md b/docs/testing/chromeos_debugging_tips.md
index aa0627a..ea92f84 100644
--- a/docs/testing/chromeos_debugging_tips.md
+++ b/docs/testing/chromeos_debugging_tips.md
@@ -103,7 +103,7 @@
 
 - Finally, run the Tast test on the device via the `cros_run_test` tool under
   `//third_party/chromite/bin/`. eg:
-  `cros_run_test --device $DEVICE_IP --tast ui.ChromeLogin`. See [here] for more
+  `cros_run_test --device $DEVICE_IP --tast login.Chrome`. See [here] for more
   info on cros_run_test.
 
 ## Telemetry
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h
index 0e7b326..07329c3 100644
--- a/extensions/browser/extension_event_histogram_value.h
+++ b/extensions/browser/extension_event_histogram_value.h
@@ -467,8 +467,8 @@
   PRINTING_ON_JOB_STATUS_CHANGED = 445,
   DECLARATIVE_NET_REQUEST_ON_RULE_MATCHED_DEBUG = 446,
   TERMINAL_PRIVATE_ON_SETTINGS_CHANGED = 447,
-  AUTOFILL_ASSISTANT_PRIVATE_ON_ACTIONS_CHANGED = 448,
-  AUTOFILL_ASSISTANT_PRIVATE_ON_STATUS_MESSAGE_CHANGED = 449,
+  DELETED_AUTOFILL_ASSISTANT_PRIVATE_ON_ACTIONS_CHANGED = 448,
+  DELETED_AUTOFILL_ASSISTANT_PRIVATE_ON_STATUS_MESSAGE_CHANGED = 449,
   BLUETOOTH_PRIVATE_ON_DEVICE_ADDRESS_CHANGED = 450,
   PASSWORDS_PRIVATE_ON_ACCOUNT_STORAGE_OPT_IN_STATE_CHANGED = 451,
   ACCESSIBILITY_PRIVATE_ON_CUSTOM_SPOKEN_FEEDBACK_TOGGLED = 452,
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 6fb318b..5f08cb1 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1498,11 +1498,11 @@
   PRINTING_SUBMITJOB = 1435,
   IDENTITYPRIVATE_SETCONSENTRESULT = 1436,
   PRINTING_CANCELJOB = 1437,
-  AUTOFILLASSISTANTPRIVATE_CREATE = 1438,
-  AUTOFILLASSISTANTPRIVATE_START = 1439,
-  AUTOFILLASSISTANTPRIVATE_GETSTATE = 1440,
-  AUTOFILLASSISTANTPRIVATE_PERFORMACTION = 1441,
-  AUTOFILLASSISTANTPRIVATE_PROVIDEUSERDATA = 1442,
+  DELETED_AUTOFILLASSISTANTPRIVATE_CREATE = 1438,
+  DELETED_AUTOFILLASSISTANTPRIVATE_START = 1439,
+  DELETED_AUTOFILLASSISTANTPRIVATE_GETSTATE = 1440,
+  DELETED_AUTOFILLASSISTANTPRIVATE_PERFORMACTION = 1441,
+  DELETED_AUTOFILLASSISTANTPRIVATE_PROVIDEUSERDATA = 1442,
   PASSWORDSPRIVATE_ISOPTEDINFORACCOUNTSTORAGE = 1443,
   AUTOTESTPRIVATE_PINSHELFICON = 1444,
   AUTOTESTPRIVATE_WAITFOROVERVIEWSTATE = 1445,
diff --git a/extensions/browser/service_worker_task_queue.cc b/extensions/browser/service_worker_task_queue.cc
index 43c91c2..d1714e5 100644
--- a/extensions/browser/service_worker_task_queue.cc
+++ b/extensions/browser/service_worker_task_queue.cc
@@ -648,9 +648,10 @@
 
 void ServiceWorkerTaskQueue::StopObserving(
     content::ServiceWorkerContext* service_worker_context) {
-  auto iter = observing_worker_contexts_.find(service_worker_context);
-  DCHECK(iter != observing_worker_contexts_.end());
-  observing_worker_contexts_.erase(iter);
+  // TODO(crbug.com/1222759): Investigate when the DCHECK's condition can be
+  // false.
+  DCHECK(observing_worker_contexts_.count(service_worker_context) > 0u);
+  observing_worker_contexts_.erase(service_worker_context);
   if (!observing_worker_contexts_.count(service_worker_context))
     service_worker_context->RemoveObserver(this);
 }
diff --git a/extensions/common/mojom/api_permission_id.mojom b/extensions/common/mojom/api_permission_id.mojom
index 96e136b1..6b3432643 100644
--- a/extensions/common/mojom/api_permission_id.mojom
+++ b/extensions/common/mojom/api_permission_id.mojom
@@ -249,7 +249,7 @@
   kPrintingMetrics = 223,
   kPrinting = 224,
   kCrashReportPrivate = 225,
-  kAutofillAssistantPrivate = 226,
+  kDeleted_AutofillAssistantPrivate = 226,
   kEnterpriseNetworkingAttributes = 227,
   kSearch = 228,
   kTabGroups = 229,
diff --git a/extensions/common/mojom/frame.mojom b/extensions/common/mojom/frame.mojom
index 62bd78f..1ac1a54b 100644
--- a/extensions/common/mojom/frame.mojom
+++ b/extensions/common/mojom/frame.mojom
@@ -123,6 +123,7 @@
   // The reply is sent back to the renderer with the response data (if any) is
   // one of the base::Value types, wrapped as the first element in a LIST
   // typed Value.
+  [UnlimitedSize]
   Request(RequestParams params) => (bool success,
                                     mojo_base.mojom.ListValue response_wrapper,
                                     string error);
diff --git a/extensions/docs/extension_and_app_types.md b/extensions/docs/extension_and_app_types.md
index f6c854a..c11a884 100644
--- a/extensions/docs/extension_and_app_types.md
+++ b/extensions/docs/extension_and_app_types.md
@@ -9,8 +9,15 @@
 
 [TOC]
 
-![Summary of extension types showing browser extensions, packaged/platform apps,
-and hosted/bookmark apps](extension_types.png)
+## Extension types hierarchy
+
+* Extensions
+  * Browser extensions
+  * Packaged Apps aka Chrome Apps:
+    * Packaged App ("v1") - deprecated
+    * Platform App ("v2") - deprecated
+  * Hosted Apps - deprecated
+    * Bookmark Apps - deprecated
 
 ## Browser extensions
 
@@ -54,7 +61,8 @@
 in the manifest, which provides the script that runs when the app is
 launched.
 
-*Platform apps are deprecated on non-Chrome OS platforms.*
+*Platform apps are deprecated, and will be [supported until June 2022](
+https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html).*
 
 ### Packaged app (legacy)
 
@@ -87,29 +95,44 @@
 `manifest.json`, which provides http/https URL that is loaded when the app is
 launched.
 
-*Hosted apps are deprecated on non-Chrome OS platforms.*
+*Hosted apps are deprecated, and will be [supported until June 2022](
+https://blog.chromium.org/2020/08/changes-to-chrome-app-support-timeline.html).*
 
 ### Bookmark app
 
-A bookmark app is a simplified hosted app that Chrome creates on demand. When
-the user taps "More Tools > Add to desktop..." (or "Add to shelf" on Chrome OS)
-in the Chrome menu, Chrome creates a barebones app whose manifest specifies the
-current tab's URL. A shortcut to this URL appears in chrome://apps using the
-site's favicon.
+Prior to Oct 2020, bookmark apps were based on the Extensions system. At that
+point they were migrated to the [Web App](#Web App) system, but are still called
+bookmark apps. This section is about bookmark apps based on Extensions
+(deprecated).
 
-Chrome then creates a desktop shortcut that will open a browser window with
-flags that specify the app and profile. Activating the icon launches the
+A bookmark app was a simplified hosted app that Chrome created on demand. When
+the user tapped "More Tools > Add to desktop..." (or "Add to shelf" on Chrome
+OS) in the Chrome menu, Chrome created a barebones app whose manifest specified
+the current tab's URL. A shortcut to this URL appeared in chrome://apps using
+the site's favicon.
+
+Chrome then created a desktop shortcut that would open a browser window with
+flags that specify the app and profile. Activating the icon launched the
 "bookmarked" URL in a tab or a window.
 
 A bookmark app's `manifest.json` identifies it as a hosted app. However, in the
 C++ code, the `Extension` object will return true from its `from_bookmark()`
 method.
 
-### Progressive Web App (PWA)
+*Bookmark apps based on Extensions are deprecated.*
 
-When Progressive Web Apps are installed on desktop a bookmark app is created.
-The bookmark app in this case will capture navigations to its scope and opens
-them in a dedicated app window instead of the existing browser context.
+### Web App
+
+When Progressive Web Apps (PWAs) are installed on desktop a
+[Web App](/chrome/browser/web_applications/README.md) is created (no longer
+based on the Extensions system since Oct 2020). The web app may capture
+navigations to its scope and open them in a dedicated app window instead of the
+existing browser context.
+
+Due to the migration from bookmark apps, web apps are often still referred to as
+bookmark apps in code and documentation. Not to be confused with "shortcut
+apps", which are web apps that Chrome creates on demand when the user taps "More
+Tools > Create Shortcut...".
 
 ## Ambiguity surrounding the term "Extension"
 
diff --git a/extensions/docs/extension_types.png b/extensions/docs/extension_types.png
deleted file mode 100644
index 5d66c16..0000000
--- a/extensions/docs/extension_types.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index cabf4b1..1322b97 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -208,7 +208,10 @@
   ]
   deps = [
     "//base",
+    "//ios/chrome/app/strings:ios_chromium_strings_grit",
+    "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/util",
+    "//ios/chrome/common/ui/util:dynamic_type_util",
   ]
 }
 
diff --git a/ios/chrome/app/enterprise_loading_screen_view_controller.mm b/ios/chrome/app/enterprise_loading_screen_view_controller.mm
index 4c91e4d..4f07ee7a1 100644
--- a/ios/chrome/app/enterprise_loading_screen_view_controller.mm
+++ b/ios/chrome/app/enterprise_loading_screen_view_controller.mm
@@ -4,48 +4,130 @@
 
 #import "ios/chrome/app/enterprise_loading_screen_view_controller.h"
 
+#import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
+#include "ios/chrome/common/ui/util/dynamic_type_util.h"
+#include "ios/chrome/grit/ios_chromium_strings.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-// TODO(crbug.com/1178818): implement final UI.
+namespace {
+
+// All the following values are from "ios/chrome/app/resources/LaunchScreen.xib"
+// and should be in sync so that the transition between app launch screen and
+// the enterprise launch screen is invisible for the users.
+constexpr CGFloat kBottomMargin = 20;
+constexpr CGFloat kLogoMultiplier = 0.381966;
+constexpr CGFloat kBrandWidth = 107;
+
+constexpr CGFloat kStatusWidth = 195;
+
+}  // namespace
+
+@interface EnterpriseLoadScreenViewController ()
+
+// Text displayed during the loading.
+@property(nonatomic, strong) UILabel* loadingLabel;
+
+@end
+
 @implementation EnterpriseLoadScreenViewController
 
+#pragma mark - UIViewController
+
 - (void)viewDidLoad {
   [super viewDidLoad];
 
-  self.view.backgroundColor = UIColor.whiteColor;
+  self.view.backgroundColor = [UIColor colorNamed:kBackgroundColor];
 
+  UIImageView* logo = [self createLogoView];
+  UIImageView* brand = [self createBrandView];
+  UIStackView* status = [self createStatusView];
+
+  UIStackView* mainStackView =
+      [[UIStackView alloc] initWithArrangedSubviews:@[ logo, status, brand ]];
+  mainStackView.axis = UILayoutConstraintAxisVertical;
+  mainStackView.translatesAutoresizingMaskIntoConstraints = NO;
+  mainStackView.distribution = UIStackViewDistributionEqualSpacing;
+  mainStackView.alignment = UIStackViewAlignmentCenter;
+
+  [self.view addSubview:mainStackView];
+
+  [NSLayoutConstraint activateConstraints:@[
+    [logo.widthAnchor constraintEqualToAnchor:self.view.widthAnchor
+                                   multiplier:kLogoMultiplier],
+    [logo.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
+    [brand.bottomAnchor
+        constraintEqualToAnchor:self.view.layoutMarginsGuide.bottomAnchor
+                       constant:-kBottomMargin],
+    [brand.widthAnchor constraintEqualToConstant:kBrandWidth],
+    [status.widthAnchor constraintEqualToConstant:kStatusWidth],
+    [mainStackView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor],
+    [mainStackView.centerXAnchor
+        constraintEqualToAnchor:self.view.centerXAnchor],
+  ]];
+}
+
+- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
+  [super traitCollectionDidChange:previousTraitCollection];
+
+  // Limit the size of text to avoid truncation.
+  self.loadingLabel.font = PreferredFontForTextStyleWithMaxCategory(
+      UIFontTextStyleBody, self.traitCollection.preferredContentSizeCategory,
+      UIContentSizeCategoryExtraExtraExtraLarge);
+}
+
+#pragma mark - Private
+
+// Creates and configures the logo image.
+- (UIImageView*)createLogoView {
   UIImage* logo = [UIImage imageNamed:@"launchscreen_app_logo"];
-  UIImageView* imageView = [[UIImageView alloc] initWithImage:logo];
-  imageView.contentMode = UIViewContentModeScaleAspectFit;
+  UIImageView* logoImageView = [[UIImageView alloc] initWithImage:logo];
+  logoImageView.contentMode = UIViewContentModeScaleAspectFit;
+  logoImageView.translatesAutoresizingMaskIntoConstraints = NO;
+  return logoImageView;
+}
 
-  UILabel* label = [[UILabel alloc] init];
-  label.text = @"[Test string] Loading enterprise policies...";
-  label.adjustsFontSizeToFitWidth = YES;
+// Creates and configures the brand name image.
+- (UIImageView*)createBrandView {
+  UIImage* brandNameLogo = [UIImage imageNamed:@"launchscreen_brand_name"];
+  UIImageView* brandImageView =
+      [[UIImageView alloc] initWithImage:brandNameLogo];
+  brandImageView.contentMode = UIViewContentModeScaleAspectFit;
+  brandImageView.translatesAutoresizingMaskIntoConstraints = NO;
+  return brandImageView;
+}
+
+// Creates and configures the status view which contains the loading spinner and
+// loading text.
+- (UIStackView*)createStatusView {
+  self.loadingLabel = [[UILabel alloc] init];
+  // Chrome's localization utilities aren't available at this stage, so this
+  // method uses the native iOS API.
+  self.loadingLabel.text =
+      NSLocalizedString(@"IDS_IOS_FIRST_RUN_LAUNCH_SCREEN_ENTERPRISE", @"");
+
+  // Limit the size of text to avoid truncation.
+  self.loadingLabel.font = PreferredFontForTextStyleWithMaxCategory(
+      UIFontTextStyleBody, self.traitCollection.preferredContentSizeCategory,
+      UIContentSizeCategoryExtraExtraExtraLarge);
+
+  self.loadingLabel.numberOfLines = 0;
+  self.loadingLabel.textColor = [UIColor colorNamed:kGrey600Color];
+  self.loadingLabel.textAlignment = NSTextAlignmentCenter;
 
   UIActivityIndicatorView* spinner = [[UIActivityIndicatorView alloc] init];
   [spinner startAnimating];
 
-  UIStackView* statusStackView =
-      [[UIStackView alloc] initWithArrangedSubviews:@[ spinner, label ]];
-  statusStackView.axis = UILayoutConstraintAxisHorizontal;
+  UIStackView* statusStackView = [[UIStackView alloc]
+      initWithArrangedSubviews:@[ spinner, self.loadingLabel ]];
+  statusStackView.axis = UILayoutConstraintAxisVertical;
   statusStackView.translatesAutoresizingMaskIntoConstraints = NO;
-  statusStackView.distribution = UIStackViewDistributionEqualSpacing;
-  statusStackView.spacing = 7;
-
-  UIStackView* mainStackView = [[UIStackView alloc]
-      initWithArrangedSubviews:@[ imageView, statusStackView ]];
-  mainStackView.axis = UILayoutConstraintAxisVertical;
-  mainStackView.translatesAutoresizingMaskIntoConstraints = NO;
-  mainStackView.distribution = UIStackViewDistributionEqualSpacing;
-
-  [self.view addSubview:mainStackView];
-  AddSameConstraintsWithInsets(
-      mainStackView, self.view,
-      ChromeDirectionalEdgeInsetsMake(100, 20, 100, 20));
+  statusStackView.alignment = UIStackViewAlignmentCenter;
+  statusStackView.spacing = UIStackViewSpacingUseSystem;
+  return statusStackView;
 }
 
 @end
diff --git a/ios/chrome/app/resources/chrome_localize_strings_config.plist b/ios/chrome/app/resources/chrome_localize_strings_config.plist
index 3ad01dd..f7e8602 100644
--- a/ios/chrome/app/resources/chrome_localize_strings_config.plist
+++ b/ios/chrome/app/resources/chrome_localize_strings_config.plist
@@ -21,6 +21,7 @@
 				<string>IDS_IOS_SAFE_MODE_CRASH_REPORT_SENT</string>
 				<string>IDS_IOS_SAFE_MODE_RELOAD_CHROME</string>
 				<string>IDS_IOS_SAFE_MODE_AW_SNAP</string>
+				<string>IDS_IOS_FIRST_RUN_LAUNCH_SCREEN_ENTERPRISE</string>
 				<string>IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_DESCRIPTION</string>
 				<string>IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_SWITCH_WINDOW_ACTION</string>
 			</array>
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd
index 62d502cd..bb9f2d7 100644
--- a/ios/chrome/app/strings/ios_chromium_strings.grd
+++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -241,6 +241,9 @@
       <message name="IDS_IOS_FACE_ID_USAGE_DESCRIPTION" desc="Specifies the reason for using the device's Face ID capabilities.">
         Chromium uses Face ID to ensure authorized access to your passwords.
       </message>
+      <message name="IDS_IOS_FIRST_RUN_LAUNCH_SCREEN_ENTERPRISE" desc="The text of the launch screen presented to the user on First Run when the browser is managed [iOS only]">
+        Your organization is setting up Chromium...
+      </message>
       <message name="IDS_IOS_FIRST_RUN_SIGNIN_SUBTITLE" desc="Subtitle of the screen suggesting to the user to sign in">
         To get the most out of Chromium, sign in to Chromium with your Google Account
       </message>
diff --git a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_FIRST_RUN_LAUNCH_SCREEN_ENTERPRISE.png.sha1 b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_FIRST_RUN_LAUNCH_SCREEN_ENTERPRISE.png.sha1
new file mode 100644
index 0000000..0faa192
--- /dev/null
+++ b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_FIRST_RUN_LAUNCH_SCREEN_ENTERPRISE.png.sha1
@@ -0,0 +1 @@
+7c8a0e9581eb60e6ddf6d375557f4b113b6234b5
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd
index 74272a9..2b67cc7 100644
--- a/ios/chrome/app/strings/ios_google_chrome_strings.grd
+++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -241,6 +241,9 @@
       <message name="IDS_IOS_FACE_ID_USAGE_DESCRIPTION" desc="Specifies the reason for using the device's Face ID capabilities.">
         Chrome uses Face ID to ensure authorized access to your passwords.
       </message>
+      <message name="IDS_IOS_FIRST_RUN_LAUNCH_SCREEN_ENTERPRISE" desc="The text of the launch screen presented to the user on First Run when the browser is managed [iOS only]">
+        Your organization is setting up Chrome...
+      </message>
       <message name="IDS_IOS_FIRST_RUN_SIGNIN_SUBTITLE" desc="Subtitle of the screen suggesting to the user to sign in">
         To get the most out of Chrome, sign in to Chrome with your Google Account
       </message>
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_FIRST_RUN_LAUNCH_SCREEN_ENTERPRISE.png.sha1 b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_FIRST_RUN_LAUNCH_SCREEN_ENTERPRISE.png.sha1
new file mode 100644
index 0000000..0faa192
--- /dev/null
+++ b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_FIRST_RUN_LAUNCH_SCREEN_ENTERPRISE.png.sha1
@@ -0,0 +1 @@
+7c8a0e9581eb60e6ddf6d375557f4b113b6234b5
\ No newline at end of file
diff --git a/ios/chrome/app/strings/resources/ios_strings_af.xtb b/ios/chrome/app/strings/resources/ios_strings_af.xtb
index aea1f66..9140895 100644
--- a/ios/chrome/app/strings/resources/ios_strings_af.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_af.xtb
@@ -236,6 +236,7 @@
 <translation id="3371831930909698441">Vertaal is beskikbaar. Opsies is naby die onderkant van die skerm beskikbaar.</translation>
 <translation id="3393920035788932672">Opspringers word toegelaat</translation>
 <translation id="3399930248910934354">Maak Chrome-instellings oop</translation>
+<translation id="3404744938087714423">Afmelding skakel sinkronisering af.</translation>
 <translation id="3425644765244388016">Kaartbynaam</translation>
 <translation id="3433057996795775706">As hierdie wagwoord uitgevee word, sal dit nie jou rekening op <ph name="WEBSITE" /> uitvee nie. Verander jou wagwoord op <ph name="WEBSITE" /> om dit veilig van ander mense te hou.</translation>
 <translation id="3443810440409579745">Oortjie is ontvang.</translation>
@@ -268,6 +269,7 @@
 <translation id="3607167657931203000">Outovuldata</translation>
 <translation id="3609785682760573515">Sinkroniseer tans …</translation>
 <translation id="3638472932233958418">Laai webbladsye vooraf</translation>
+<translation id="3648013730801605241"><ph name="BEGIN_LINK" />Soekgeskiedenis<ph name="END_LINK" /> en <ph name="BEGIN_LINK" />ander soorte aktiwiteit<ph name="END_LINK" /> sal dalk in jou Google-rekening gestoor word wanneer jy aangemeld is. Jy kan dit enige tyd uitvee.</translation>
 <translation id="3661160521073045932">Opstellingprofiel is beskikbaar</translation>
 <translation id="3670030362669914947">Nommer</translation>
 <translation id="3691593122358196899">Geboekmerk in <ph name="FOLDER_TITLE" /></translation>
@@ -647,6 +649,10 @@
 <translation id="734758817008927353">Opsies om 'n kaart te stoor</translation>
 <translation id="7348502496356775519">Boekmerk</translation>
 <translation id="7353432112255316844">Verifieer dis jy</translation>
+<translation id="7376492662175718683">Jy sal nie uit jou Google-rekening afgemeld word nie. <ph name="BEGIN_LINK" />Ander soorte aktiwiteit<ph name="END_LINK" /> sal dalk in jou Google-rekening gestoor word wanneer jy aangemeld is. Jy kan dit enige tyd uitvee.
+
+        
+Jou soekenjin is <ph name="DSE_NAME" />. Sien hul instruksies om jou soekgeskiedenis uit te vee, indien nodig.</translation>
 <translation id="7383797227493018512">Leeslys</translation>
 <translation id="7398893703713203428">Skep skakel</translation>
 <translation id="739941347996872055">Vorige oortjie</translation>
@@ -789,6 +795,10 @@
 <ph name="BEGIN_LINK" />Kom meer te wete<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">Boekmerke</translation>
 <translation id="8840513115188359703">Jy sal nie uit jou Google-rekening afgemeld word nie.</translation>
+<translation id="8851300969441660830">Jy sal nie uit jou Google-rekening afgemeld word nie. <ph name="BEGIN_LINK" />Ander soorte aktiwiteit<ph name="END_LINK" /> sal dalk in jou Google-rekening gestoor word wanneer jy aangemeld is. Jy kan dit enige tyd uitvee.
+
+
+Sien jou soekenjin se instruksies om jou soekgeskiedenis uit te vee, indien nodig.</translation>
 <translation id="8868471676553493380">{count,plural, =1{{count} oortjie}other{{count} oortjies}}</translation>
 <translation id="8870413625673593573">Onlangs toegemaak</translation>
 <translation id="8876882697946675716">Hou jou toestelle gesinkroniseer</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ja.xtb b/ios/chrome/app/strings/resources/ios_strings_ja.xtb
index 6227e96..714c877 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ja.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ja.xtb
@@ -236,6 +236,7 @@
 <translation id="3371831930909698441">翻訳が利用可能です。画面の下の方にオプションがあります。</translation>
 <translation id="3393920035788932672">ポップアップ許可済み</translation>
 <translation id="3399930248910934354">Chrome の設定を開く</translation>
+<translation id="3404744938087714423">ログアウトすると、同期がオフになります。</translation>
 <translation id="3425644765244388016">カードのニックネーム</translation>
 <translation id="3433057996795775706">このパスワードを削除しても、<ph name="WEBSITE" /> のアカウントは削除されません。他のサイトに被害が及ばないように、<ph name="WEBSITE" /> でパスワードを変更してください。</translation>
 <translation id="3443810440409579745">タブが共有されました。</translation>
@@ -268,6 +269,7 @@
 <translation id="3607167657931203000">自動入力のデータ</translation>
 <translation id="3609785682760573515">同期しています...</translation>
 <translation id="3638472932233958418">ウェブページのプリロード</translation>
+<translation id="3648013730801605241">ログイン中は Google アカウントに<ph name="BEGIN_LINK" />検索履歴<ph name="END_LINK" />や<ph name="BEGIN_LINK" />その他のアクティビティ<ph name="END_LINK" />が保存される可能性があります。保存されたデータはいつでも削除できます。</translation>
 <translation id="3661160521073045932">設定プロファイルを使用できます</translation>
 <translation id="3670030362669914947">番号</translation>
 <translation id="3691593122358196899">「<ph name="FOLDER_TITLE" />」にブックマークしました</translation>
@@ -647,6 +649,10 @@
 <translation id="734758817008927353">カードの保存オプション</translation>
 <translation id="7348502496356775519">ブックマーク</translation>
 <translation id="7353432112255316844">本人確認</translation>
+<translation id="7376492662175718683">Google アカウントへのログイン状態は維持されます。ログイン中は Google アカウントに<ph name="BEGIN_LINK" />その他のアクティビティ<ph name="END_LINK" />が保存される可能性があります。保存されたデータはいつでも削除できます。
+
+        
+検索エンジンは <ph name="DSE_NAME" /> に設定されています。検索履歴を削除する場合は、検索エンジンの手順をご確認ください(該当する場合)。</translation>
 <translation id="7383797227493018512">リーディング リスト</translation>
 <translation id="7398893703713203428">リンクを作成</translation>
 <translation id="739941347996872055">前のタブ</translation>
@@ -789,6 +795,10 @@
 <ph name="BEGIN_LINK" />詳細<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">ブックマーク</translation>
 <translation id="8840513115188359703">Google アカウントへのログイン状態は維持されます。</translation>
+<translation id="8851300969441660830">Google アカウントへのログイン状態は維持されます。ログイン中は Google アカウントに<ph name="BEGIN_LINK" />その他のアクティビティ<ph name="END_LINK" />が保存される可能性があります。保存されたデータはいつでも削除できます。
+
+
+検索履歴を削除する場合は、お使いの検索エンジンの手順をご確認ください(該当する場合)。</translation>
 <translation id="8868471676553493380">{count,plural, =1{{count} 個のタブ}other{{count} 個のタブ}}</translation>
 <translation id="8870413625673593573">最近閉じたタブ</translation>
 <translation id="8876882697946675716">デバイスを同期したままにする</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_si.xtb b/ios/chrome/app/strings/resources/ios_strings_si.xtb
index 6632a92..15340e9a 100644
--- a/ios/chrome/app/strings/resources/ios_strings_si.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_si.xtb
@@ -236,6 +236,7 @@
 <translation id="3371831930909698441">පරිවර්තනය ලැබේ. තිරයේ පහළට ආසන්නව විකල්ප ලබා ගත හැක.</translation>
 <translation id="3393920035788932672">උත්පතන වලට ඉඩ දෙන ලද</translation>
 <translation id="3399930248910934354">Chrome සැකසීම් විවෘත කරන්න</translation>
+<translation id="3404744938087714423">වැරීම සමමුහුර්ත කිරීම ක්‍රියාවිරහිත කරනු ඇත.</translation>
 <translation id="3425644765244388016">කාඩ්පත් අපනාමය</translation>
 <translation id="3433057996795775706">මෙම මුරපදය මැකීම <ph name="WEBSITE" /> මත ඔබේ ගිණුම මකන්නේ නැත. එය අන් අයගෙන් ආරක්ෂිතව තබා ගැනීමට <ph name="WEBSITE" /> හි ඔබගේ මුරපදය වෙනස් කරන්න.</translation>
 <translation id="3443810440409579745">ලැබූ පටිත්ත.</translation>
@@ -268,6 +269,7 @@
 <translation id="3607167657931203000">ස්වයං පිරවුම් දත්ත</translation>
 <translation id="3609785682760573515">සමමු වේ...</translation>
 <translation id="3638472932233958418">පෙර පූරණ වෙබ් පිටු</translation>
+<translation id="3648013730801605241"><ph name="BEGIN_LINK" />සෙවීම් ඉතිහාසය<ph name="END_LINK" /> සහ <ph name="BEGIN_LINK" />ක්‍රියාකාරකම්වල වෙනත් ආකාර<ph name="END_LINK" /> ඔබ පුරන විට ඔබගේ Google ගිණුමේ සුරැකිය හැකිය. ඔබට ඒවා ඕනෑම අවස්ථාවක මැකිය හැකිය.</translation>
 <translation id="3661160521073045932">වින්‍යාසකරණ පැතිකඩක් ලබා ගත හැකිය</translation>
 <translation id="3670030362669914947">අංකය</translation>
 <translation id="3691593122358196899"><ph name="FOLDER_TITLE" /> වෙත පිටුසන් යොදන ලදී</translation>
@@ -647,6 +649,10 @@
 <translation id="734758817008927353">කාඩ්පත සුරැකීමට විකල්ප</translation>
 <translation id="7348502496356775519">පිටුසන</translation>
 <translation id="7353432112255316844">ඒ ඔබ බව සත්‍යාපනය කරන්න</translation>
+<translation id="7376492662175718683">ඔබව ඔබගේ Google ගිණුමෙන් නොවරනු ඇත. <ph name="BEGIN_LINK" />ක්‍රියාකාරකම්වල වෙනත් ආකාර<ph name="END_LINK" /> ඔබ පුරන විට ඔබගේ Google ගිණුමේ සුරැකිය හැකිය. ඔබට ඒවා ඕනෑම අවස්ථාවක මැකිය හැකිය.
+
+        
+ඔබගේ සෙවීම් යන්ත්‍රය වන්නේ <ph name="DSE_NAME" />. අදාළ වන්නේ නම්, ඔබගේ සෙවීම් ඉතිහාසය මැකීම සඳහා ඔවුන්ගේ උපදෙස් බලන්න.</translation>
 <translation id="7383797227493018512">කියවීම් ලැයිස්තුව</translation>
 <translation id="7398893703713203428">සබැඳියක් තනන්න</translation>
 <translation id="739941347996872055">පෙර ටැබය</translation>
@@ -789,6 +795,10 @@
 <ph name="BEGIN_LINK" />තව දැන ගන්න<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">පිටුසන්</translation>
 <translation id="8840513115188359703">ඔබව ඔබගේ Google ගිණුමෙන් වරනය නොවනු ඇත</translation>
+<translation id="8851300969441660830">ඔබව ඔබගේ Google ගිණුමෙන් නොවරනු ඇත. <ph name="BEGIN_LINK" />ක්‍රියාකාරකම්වල වෙනත් ආකාර<ph name="END_LINK" /> ඔබ පුරන විට ඔබගේ Google ගිණුමේ සුරැකිය හැකිය. ඔබට ඒවා ඕනෑම අවස්ථාවක මැකිය හැකිය.
+
+
+අදාළ වන්නේ නම්, ඔබගේ සෙවීම් ඉතිහාසය මැකීම සඳහා ඔබගේ සෙවීම් යන්ත්‍රයේ උපදෙස් බලන්න.</translation>
 <translation id="8868471676553493380">{count,plural, =1{ටැබ {count}}one{ටැබ {count}}other{ටැබ {count}}}</translation>
 <translation id="8870413625673593573">මෑතකදී වසන ලද</translation>
 <translation id="8876882697946675716">ඔබගේ උපාංග සමමුහුර්තව තබා ගන්න</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_sw.xtb b/ios/chrome/app/strings/resources/ios_strings_sw.xtb
index 8c9e6ad3..959c953 100644
--- a/ios/chrome/app/strings/resources/ios_strings_sw.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_sw.xtb
@@ -236,6 +236,7 @@
 <translation id="3371831930909698441">Huduma ya Tafsiri inapatikana. Chaguo zinapatikana karibu na sehemu ya chini ya skrini.</translation>
 <translation id="3393920035788932672">Ibukizi zimeruhusiwa</translation>
 <translation id="3399930248910934354">Fungua Mipangilio ya Chrome</translation>
+<translation id="3404744938087714423">Hatua ya kuondoka kwenye akaunti huzima kipengele cha kusawazisha.</translation>
 <translation id="3425644765244388016">Jina la Kuwakilisha Kadi</translation>
 <translation id="3433057996795775706">Hatua ya kufuta nenosiri hili haitafuta akaunti yako kwenye <ph name="WEBSITE" />. Badilisha nenosiri lako kwenye <ph name="WEBSITE" /> ili ulilinde dhidi ya watu wengine.</translation>
 <translation id="3443810440409579745">Umepokea kichupo.</translation>
@@ -268,6 +269,7 @@
 <translation id="3607167657931203000">Jaza Data Kiotomatiki</translation>
 <translation id="3609785682760573515">Inasawazisha...</translation>
 <translation id="3638472932233958418">Pakia Kurasa za wavuti Mapema</translation>
+<translation id="3648013730801605241">Huenda <ph name="BEGIN_LINK" />historia ya mambo uliyotafuta<ph name="END_LINK" /> na <ph name="BEGIN_LINK" />aina nyingine za shughuli<ph name="END_LINK" /> zikahifadhiwa kwenye Akaunti yako ya Google ukiwa umeingia katika akaunti. Unaweza kuzifuta wakati wowote.</translation>
 <translation id="3661160521073045932">Wasifu wa Mipangilio Unapatikana</translation>
 <translation id="3670030362669914947">Nambari</translation>
 <translation id="3691593122358196899">Imetiwa alamisho kwenye <ph name="FOLDER_TITLE" /></translation>
@@ -647,6 +649,10 @@
 <translation id="734758817008927353">Chaguo za Kuhifadhi Kadi</translation>
 <translation id="7348502496356775519">Alamisha</translation>
 <translation id="7353432112255316844">Thibitisha Kwamba Ni Wewe</translation>
+<translation id="7376492662175718683">Hutaondolewa katika Akaunti yako ya Google. Huenda <ph name="BEGIN_LINK" />aina nyingine za shughuli<ph name="END_LINK" /> zikahifadhiwa kwenye Akaunti yako ya Google ukiwa umeingia katika akaunti. Unaweza kuzifuta wakati wowote.
+
+        
+Mtambo wako wa kutafuta ni <ph name="DSE_NAME" />. Angalia maagizo ya mtambo huo wa kutafuta, ikiwa yapo, kuhusu jinsi ya kufuta historia ya mambo uliyotafuta.</translation>
 <translation id="7383797227493018512">Orodha ya Kusoma</translation>
 <translation id="7398893703713203428">Weka Kiungo</translation>
 <translation id="739941347996872055">Kichupo Kilichotangulia</translation>
@@ -789,6 +795,10 @@
 <ph name="BEGIN_LINK" />Pata maelezo zaidi<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">Alamisho</translation>
 <translation id="8840513115188359703">Hutaondolewa katika Akaunti yako ya Google.</translation>
+<translation id="8851300969441660830">Hutaondolewa katika Akaunti yako ya Google. Huenda <ph name="BEGIN_LINK" />aina nyingine za shughuli<ph name="END_LINK" /> zikahifadhiwa kwenye Akaunti yako ya Google ukiwa umeingia katika akaunti. Unaweza kuzifuta wakati wowote.
+
+
+Angalia maagizo ya mtambo wako wa kutafuta, ikiwa yapo, kuhusu jinsi ya kufuta historia ya mambo uliyotafuta.</translation>
 <translation id="8868471676553493380">{count,plural, =1{Kichupo {count}}other{Vichupo {count}}}</translation>
 <translation id="8870413625673593573">Zilizofungwa Hivi Karibuni</translation>
 <translation id="8876882697946675716">Hakikisha Vifaa Vyako Vinasawazishwa</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_uz.xtb b/ios/chrome/app/strings/resources/ios_strings_uz.xtb
index 3d87598..215ce6b 100644
--- a/ios/chrome/app/strings/resources/ios_strings_uz.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_uz.xtb
@@ -236,6 +236,7 @@
 <translation id="3371831930909698441">Tarjima mavjud. Parametrlar ekranning quyi qismiga yaqinroq joyda</translation>
 <translation id="3393920035788932672">Qalqib chiquvchi oynalarga ruxsat</translation>
 <translation id="3399930248910934354">Chrome sozlamalarini oching</translation>
+<translation id="3404744938087714423">Hisobdan chiqsangiz, sinxronizatsiya oʻchiriladi.</translation>
 <translation id="3425644765244388016">Karta nomi</translation>
 <translation id="3433057996795775706">Bu parol olib tashlangani bilan <ph name="WEBSITE" /> hisobingiz oʻchib ketmaydi. Boshqalardan himoyalash maqsadida <ph name="WEBSITE" /> hisobingiz parolini almashtiring.</translation>
 <translation id="3443810440409579745">Varaq qabul qilindi.</translation>
@@ -268,6 +269,7 @@
 <translation id="3607167657931203000">Avto-to‘ldirish ma’l-ri</translation>
 <translation id="3609785682760573515">Sinxronlanmoqda...</translation>
 <translation id="3638472932233958418">Oldindan yuklash</translation>
+<translation id="3648013730801605241">Google hisobingizga kirganingizda <ph name="BEGIN_LINK" />Qidiruv tarixi<ph name="END_LINK" /> va <ph name="BEGIN_LINK" />boshqa shakldagi harakatlaringiz<ph name="END_LINK" /> hisobingizga saqlanishi mumkin. Ularni istalgan vaqt oʻchirish mumkin.</translation>
 <translation id="3661160521073045932">Profil konfiguratsiyasi mavjud</translation>
 <translation id="3670030362669914947">Raqam</translation>
 <translation id="3691593122358196899">Xatcho‘p “<ph name="FOLDER_TITLE" />” jildiga saqlandi</translation>
@@ -647,6 +649,10 @@
 <translation id="734758817008927353">Kartalarni saqlash parametrlari</translation>
 <translation id="7348502496356775519">Bukmark</translation>
 <translation id="7353432112255316844">Bu siz ekaningizni isbotlang</translation>
+<translation id="7376492662175718683">Google hisobingizdan chiqmaysiz. Google hisobingizga kirganingizda <ph name="BEGIN_LINK" />boshqa shakldagi harakatlaringiz<ph name="END_LINK" /> hisobingizga saqlanishi mumkin. Ularni istalgan vaqt oʻchirish mumkin.
+
+        
+Qidiruv tizimingiz: <ph name="DSE_NAME" />. Imkon boʻlsa, qidiruv tarixini qanday tozalash haqidagi koʻrsatmalarni oching.</translation>
 <translation id="7383797227493018512">Mutolaa ro‘yxati</translation>
 <translation id="7398893703713203428">Havola yaratish</translation>
 <translation id="739941347996872055">Avvalgi varaq</translation>
@@ -789,6 +795,10 @@
 <ph name="BEGIN_LINK" />Batafsil<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">Bukmarklar</translation>
 <translation id="8840513115188359703">Google hisobingizdan chiqmaysiz.</translation>
+<translation id="8851300969441660830">Google hisobingizdan chiqmaysiz. Google hisobingizga kirganingizda <ph name="BEGIN_LINK" />boshqa shakldagi harakatlaringiz<ph name="END_LINK" /> hisobingizga saqlanishi mumkin. Ularni istalgan vaqt oʻchirish mumkin.
+
+
+Imkon boʻlsa, qidiruv tarixini qanday tozalash haqidagi qidiruv tizimi koʻrsatmalarini oching.</translation>
 <translation id="8868471676553493380">{count,plural, =1{{count} ta varaq}other{{count} ta varaq}}</translation>
 <translation id="8870413625673593573">Yaqinda yopilganlar</translation>
 <translation id="8876882697946675716">Qurilmalaringizni sinxronlab boring</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_zh-HK.xtb b/ios/chrome/app/strings/resources/ios_strings_zh-HK.xtb
index d486e2c..713647a7 100644
--- a/ios/chrome/app/strings/resources/ios_strings_zh-HK.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_zh-HK.xtb
@@ -236,6 +236,7 @@
 <translation id="3371831930909698441">有可以用嘅翻譯。你可以喺接近畫面底部附近搵到選項。</translation>
 <translation id="3393920035788932672">已允許的彈出式視窗</translation>
 <translation id="3399930248910934354">開啟 Chrome 設定</translation>
+<translation id="3404744938087714423">登出會同時關閉同步功能。</translation>
 <translation id="3425644765244388016">信用卡暱稱</translation>
 <translation id="3433057996795775706">刪除此密碼不會刪除您在 <ph name="WEBSITE" /> 的帳戶。請變更您在 <ph name="WEBSITE" /> 的密碼,以免被他人盜用。</translation>
 <translation id="3443810440409579745">已收到分頁。</translation>
@@ -268,6 +269,7 @@
 <translation id="3607167657931203000">自動填入資料</translation>
 <translation id="3609785682760573515">同步處理中…</translation>
 <translation id="3638472932233958418">預先載入網頁</translation>
+<translation id="3648013730801605241">在您登入後,<ph name="BEGIN_LINK" />搜尋記錄<ph name="END_LINK" />和<ph name="BEGIN_LINK" />其他形式的活動<ph name="END_LINK" />可能會儲存至您的 Google 帳戶。您隨時可刪除這些資料。</translation>
 <translation id="3661160521073045932">有可用的設定描述檔。</translation>
 <translation id="3670030362669914947">號碼</translation>
 <translation id="3691593122358196899">已將書籤加入到「<ph name="FOLDER_TITLE" />」</translation>
@@ -645,6 +647,10 @@
 <translation id="734758817008927353">付款卡儲存選項</translation>
 <translation id="7348502496356775519">加入書籤</translation>
 <translation id="7353432112255316844">驗證身分</translation>
+<translation id="7376492662175718683">您不會因此登出 Google 帳戶。在您登入後,<ph name="BEGIN_LINK" />其他形式的活動<ph name="END_LINK" />可能會儲存至您的 Google 帳戶。您隨時可刪除這些資料。
+
+        
+您的搜尋引擎是「<ph name="DSE_NAME" />」。建議您查看搜尋引擎的搜尋記錄刪除指示 (如有)。</translation>
 <translation id="7383797227493018512">閱讀清單</translation>
 <translation id="7398893703713203428">建立連結</translation>
 <translation id="739941347996872055">上一個分頁</translation>
@@ -787,6 +793,10 @@
 <ph name="BEGIN_LINK" />瞭解詳情<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">書籤</translation>
 <translation id="8840513115188359703">您不會因此登出 Google 帳戶。</translation>
+<translation id="8851300969441660830">您不會因此登出 Google 帳戶。在您登入後,<ph name="BEGIN_LINK" />其他形式的活動<ph name="END_LINK" />可能會儲存至您的 Google 帳戶。您隨時可刪除這些資料。
+
+
+建議您查看搜尋引擎的搜尋記錄刪除指示 (如有)。</translation>
 <translation id="8868471676553493380">{count,plural, =1{{count} 個分頁}other{{count} 個分頁}}</translation>
 <translation id="8870413625673593573">最近關閉的分頁</translation>
 <translation id="8876882697946675716">讓您的裝置保持同步</translation>
diff --git a/ios/chrome/browser/providers/BUILD.gn b/ios/chrome/browser/providers/BUILD.gn
index fb627df4..45c4dbcd 100644
--- a/ios/chrome/browser/providers/BUILD.gn
+++ b/ios/chrome/browser/providers/BUILD.gn
@@ -51,6 +51,9 @@
     # The target providing the ChromeBrowserProvider factory.
     ":chromium_provider_factory",
 
+    # The individual API implementations.
+    "//ios/chrome/browser/providers/modals:chromium_modals",
+
     # The provider API needs to provide MaterialDesignComponent API (as the
     # internal provider provides an alternate implementation).
     "//ios/third_party/material_components_ios:material_components_ios+bundle",
diff --git a/ios/chrome/browser/providers/modals/BUILD.gn b/ios/chrome/browser/providers/modals/BUILD.gn
new file mode 100644
index 0000000..24e493d
--- /dev/null
+++ b/ios/chrome/browser/providers/modals/BUILD.gn
@@ -0,0 +1,9 @@
+# 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.
+
+source_set("chromium_modals") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [ "chromium_modals.mm" ]
+  deps = [ "//ios/public/provider/chrome/browser/modals:modals_api" ]
+}
diff --git a/ios/chrome/browser/providers/modals/chromium_modals.mm b/ios/chrome/browser/providers/modals/chromium_modals.mm
new file mode 100644
index 0000000..c9dc0dff
--- /dev/null
+++ b/ios/chrome/browser/providers/modals/chromium_modals.mm
@@ -0,0 +1,23 @@
+// 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.
+
+#import "ios/public/provider/chrome/browser/modals/modals_api.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace ios {
+namespace provider {
+
+void DismissModalsForCollectionView(UICollectionView*) {
+  // Chromium implementation does nothing.
+}
+
+void DismissModalsForTableView(UITableView*) {
+  // Chromium implementation does nothing.
+}
+
+}  // namespace provider
+}  // namespace ios
diff --git a/ios/chrome/browser/signin/authentication_service.h b/ios/chrome/browser/signin/authentication_service.h
index d6b4535..998efdd 100644
--- a/ios/chrome/browser/signin/authentication_service.h
+++ b/ios/chrome/browser/signin/authentication_service.h
@@ -86,23 +86,12 @@
   // credentials to ensure the value is up to date.
   bool HasPrimaryIdentity(signin::ConsentLevel consent_level) const;
 
-  // Returns true if the user is signed in.
-  // While the AuthenticationService is in background, this will reload the
-  // credentials to ensure the value is up to date.
-  // DEPRECATED, use HasPrimaryIdentity().
-  virtual bool IsAuthenticated() const;
-
   // Returns true if the user is signed in and the identity is considered
   // managed.
   // Virtual for testing.
   virtual bool HasPrimaryIdentityManaged(
       signin::ConsentLevel consent_level) const;
 
-  // Returns true if the user is signed in and the identity is considered
-  // managed.
-  // DEPRECATED, use HasPrimaryIdentityManaged().
-  virtual bool IsAuthenticatedIdentityManaged() const;
-
   // Retrieves the identity of the currently authenticated user or |nil| if
   // either the user is not authenticated, or is authenticated through
   // ClientLogin.
@@ -110,13 +99,6 @@
   virtual ChromeIdentity* GetPrimaryIdentity(
       signin::ConsentLevel consent_level) const;
 
-  // Retrieves the identity of the currently authenticated user or |nil| if
-  // either the user is not authenticated, or is authenticated through
-  // ClientLogin.
-  // Virtual for testing.
-  // DEPRECATED, use HasPrimaryIdentityManaged().
-  virtual ChromeIdentity* GetAuthenticatedIdentity() const;
-
   // Grants signin::ConsentLevel::kSignin to |identity|.
   // This method does not set up Sync-the-feature for the identity.
   // Virtual for testing.
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm
index fa65e25..e0fc705 100644
--- a/ios/chrome/browser/signin/authentication_service.mm
+++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -260,10 +260,6 @@
   return account_manager_service_->GetIdentityWithGaiaID(authenticated_gaia_id);
 }
 
-ChromeIdentity* AuthenticationService::GetAuthenticatedIdentity() const {
-  return GetPrimaryIdentity(signin::ConsentLevel::kSignin);
-}
-
 void AuthenticationService::SignIn(ChromeIdentity* identity) {
   CHECK(signin::IsSigninAllowed(pref_service_));
   DCHECK(account_manager_service_->IsValidIdentity(identity));
@@ -575,11 +571,3 @@
     ApproveAccountList();
   }
 }
-
-bool AuthenticationService::IsAuthenticated() const {
-  return HasPrimaryIdentity(signin::ConsentLevel::kSignin);
-}
-
-bool AuthenticationService::IsAuthenticatedIdentityManaged() const {
-  return HasPrimaryIdentityManaged(signin::ConsentLevel::kSignin);
-}
diff --git a/ios/chrome/browser/ui/authentication/DEPS b/ios/chrome/browser/ui/authentication/DEPS
index f79e7c6..d8c3dc4 100644
--- a/ios/chrome/browser/ui/authentication/DEPS
+++ b/ios/chrome/browser/ui/authentication/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+components/consent_auditor",
+  "+components/signin/internal/identity_manager/account_capabilities_constants.h",
 ]
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/BUILD.gn b/ios/chrome/browser/ui/authentication/signin/user_signin/BUILD.gn
index 61c5d53..41aedc1 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/BUILD.gn
@@ -104,6 +104,7 @@
   deps = [
     "//base",
     "//base/test:test_support",
+    "//components/signin/internal/identity_manager",
     "//components/signin/ios/browser:features",
     "//components/signin/public/base",
     "//ios/chrome/app/strings",
@@ -114,6 +115,7 @@
     "//ios/chrome/browser/ui/settings:constants",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
     "//ios/chrome/test/earl_grey:switches",
+    "//ios/public/provider/chrome/browser/signin",
     "//ios/public/provider/chrome/browser/signin:constants",
     "//ios/public/provider/chrome/browser/signin:fake_chrome_identity",
     "//ios/testing/earl_grey:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/authentication/signin/user_signin/upgrade_signin_promo_egtest.mm b/ios/chrome/browser/ui/authentication/signin/user_signin/upgrade_signin_promo_egtest.mm
index e23f0ca..f2ec813 100644
--- a/ios/chrome/browser/ui/authentication/signin/user_signin/upgrade_signin_promo_egtest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/user_signin/upgrade_signin_promo_egtest.mm
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #import "base/test/ios/wait_util.h"
+#import "components/signin/internal/identity_manager/account_capabilities_constants.h"
 #import "components/signin/public/base/signin_switches.h"
 #import "ios/chrome/browser/chrome_switches.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey.h"
@@ -12,6 +13,7 @@
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/chrome/test/earl_grey/test_switches.h"
+#import "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h"
 #import "ios/testing/earl_grey/app_launch_manager.h"
 #import "ios/testing/earl_grey/earl_grey_test.h"
@@ -23,6 +25,10 @@
 
 namespace {
 
+// Capability name for canOfferExtendedChromeSyncPromos.
+const NSString* kCanOfferExtendedChromeSyncPromos = [NSString
+    stringWithUTF8String:kCanOfferExtendedChromeSyncPromosCapabilityName];
+
 // Matcher for the sign-in recall promo.
 id<GREYMatcher> SigninRecallPromo() {
   return grey_accessibilityID(kUnifiedConsentScrollViewIdentifier);
@@ -44,7 +50,6 @@
 AppLaunchConfiguration AppConfigurationForRelaunch() {
   AppLaunchConfiguration config;
   config.features_enabled.push_back(switches::kForceStartupSigninPromo);
-  config.features_disabled.push_back(switches::kMinorModeSupport);
   config.additional_args.push_back(std::string("--") +
                                    switches::kEnableSigninRecallPromo);
 
@@ -53,6 +58,15 @@
   return config;
 }
 
+// Wait for |timeout| in seconds.
+void WaitForInterval(NSTimeInterval timeout) {
+  XCTestExpectation* neverFulfilled =
+      [[XCTestExpectation alloc] initWithDescription:@"Wait"];
+  XCTWaiterResult result = [XCTWaiter waitForExpectations:@[ neverFulfilled ]
+                                                  timeout:timeout];
+  GREYAssertTrue(result == XCTWaiterResultTimedOut, @"Did not complete wait");
+}
+
 }  // namespace
 
 // Tests the upgrade sign-in promo restrictions.
@@ -70,6 +84,7 @@
 - (void)testStartupSigninPromoNoRestrictions {
   // Create the config to relaunch Chrome.
   AppLaunchConfiguration config = AppConfigurationForRelaunch();
+  config.features_disabled.push_back(switches::kMinorModeSupport);
 
   // Relaunch the app to take the configuration into account.
   [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
@@ -85,6 +100,7 @@
 
   // Create the config to relaunch Chrome.
   AppLaunchConfiguration config = AppConfigurationForRelaunch();
+  config.features_disabled.push_back(switches::kMinorModeSupport);
   // Add the switch to make sure that fakeIdentity1 is known at startup to avoid
   // automatic sign out.
   config.additional_args.push_back(std::string("-") +
@@ -92,6 +108,34 @@
 
   // Relaunch the app to take the configuration into account.
   [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
+  WaitForInterval(5.0);
+
+  [[EarlGrey selectElementWithMatcher:SigninRecallPromo()]
+      assertWithMatcher:grey_notVisible()];
+}
+
+// Tests that the sign-in promo is not visible at start-up for an account
+// with minor mode restrictions.
+- (void)testStartupSigninPromoNotShownForMinor {
+  FakeChromeIdentity* fakeIdentity = [SigninEarlGrey fakeIdentity1];
+  [SigninEarlGrey addFakeIdentity:fakeIdentity];
+  [SigninEarlGrey setCapabilities:@{
+    kCanOfferExtendedChromeSyncPromos : [NSNumber
+        numberWithInt:static_cast<int>(
+                          ios::ChromeIdentityCapabilityResult::kFalse)]
+  }
+                      forIdentity:fakeIdentity];
+
+  // Create the config to relaunch Chrome.
+  AppLaunchConfiguration config = AppConfigurationForRelaunch();
+  config.features_enabled.push_back(switches::kMinorModeSupport);
+  // Sets up FakeChromeIdentityService for use in scene_controller.mm.
+  config.additional_args.push_back(std::string("-") +
+                                   test_switches::kSignInAtStartup);
+
+  // Relaunch the app to take the configuration into account.
+  [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
+  WaitForInterval(5.0);
 
   [[EarlGrey selectElementWithMatcher:SigninRecallPromo()]
       assertWithMatcher:grey_notVisible()];
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey.h b/ios/chrome/browser/ui/authentication/signin_earl_grey.h
index 4d5e07b..9d4c743 100644
--- a/ios/chrome/browser/ui/authentication/signin_earl_grey.h
+++ b/ios/chrome/browser/ui/authentication/signin_earl_grey.h
@@ -32,6 +32,10 @@
 // Adds |fakeIdentity| to the fake identity service.
 - (void)addFakeIdentity:(FakeChromeIdentity*)fakeIdentity;
 
+// Maps |capabilities| to the |fakeIdentity|. Check fails if the
+// |fakeIdentity| has not been added to the fake identity service.
+- (void)setCapabilities:(NSDictionary*)capabilities forIdentity:fakeIdentity;
+
 // Removes |fakeIdentity| from the fake identity service asynchronously to
 // simulate identity removal from the device.
 - (void)forgetFakeIdentity:(FakeChromeIdentity*)fakeIdentity;
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey.mm b/ios/chrome/browser/ui/authentication/signin_earl_grey.mm
index ba34317..750adc9 100644
--- a/ios/chrome/browser/ui/authentication/signin_earl_grey.mm
+++ b/ios/chrome/browser/ui/authentication/signin_earl_grey.mm
@@ -31,6 +31,12 @@
   [SigninEarlGreyAppInterface addFakeIdentity:fakeIdentity];
 }
 
+- (void)setCapabilities:(NSDictionary*)capabilities
+            forIdentity:(FakeChromeIdentity*)fakeIdentity {
+  [SigninEarlGreyAppInterface setCapabilities:capabilities
+                                  forIdentity:fakeIdentity];
+}
+
 - (void)forgetFakeIdentity:(FakeChromeIdentity*)fakeIdentity {
   [SigninEarlGreyAppInterface forgetFakeIdentity:fakeIdentity];
 }
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.h b/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.h
index e6892a3..1b0d128e 100644
--- a/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.h
+++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.h
@@ -27,6 +27,11 @@
 // Adds |fakeIdentity| to the fake identity service.
 + (void)addFakeIdentity:(FakeChromeIdentity*)fakeIdentity;
 
+// Maps |capabilities| to the |fakeIdentity|.
+// Must be called after |addFakeIdentity|.
++ (void)setCapabilities:(NSDictionary*)capabilities
+            forIdentity:(FakeChromeIdentity*)fakeIdentity;
+
 // Removes |fakeIdentity| from the fake chrome identity service asynchronously
 // to simulate identity removal from the device.
 + (void)forgetFakeIdentity:(FakeChromeIdentity*)fakeIdentity;
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.mm b/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.mm
index 2f9edff..6377ccd 100644
--- a/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.mm
+++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_app_interface.mm
@@ -51,6 +51,12 @@
       fakeIdentity);
 }
 
++ (void)setCapabilities:(NSDictionary*)capabilities
+            forIdentity:(FakeChromeIdentity*)fakeIdentity {
+  ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
+      ->SetCapabilities(fakeIdentity, capabilities);
+}
+
 + (void)forgetFakeIdentity:(FakeChromeIdentity*)fakeIdentity {
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->ForgetIdentity(fakeIdentity, nil);
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
index 56a74e8..5cc91a6b 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
@@ -531,8 +531,8 @@
 // if the user is signed in. If not signed in, the default identity from
 // AccountManagerService.
 - (ChromeIdentity*)defaultIdentity {
-  if (self.authService->IsAuthenticated()) {
-    return self.authService->GetAuthenticatedIdentity();
+  if (self.authService->HasPrimaryIdentity(signin::ConsentLevel::kSignin)) {
+    return self.authService->GetPrimaryIdentity(signin::ConsentLevel::kSignin);
   }
   DCHECK(self.accountManagerService);
   return self.accountManagerService->GetDefaultIdentity();
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm
index 079afca..2a7a5f2 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm
@@ -501,7 +501,8 @@
 // Tests the mediator stops observing objects when the incognito BVC is
 // destroyed. Waiting for dealloc was causing a race condition with the
 // autorelease pool, and some times a DCHECK will be hit.
-- (void)testOpeningIncognitoTabsDoNotLeak {
+// TODO(crbug.com/1227124) Flaky test.
+- (void)DISABLED_testOpeningIncognitoTabsDoNotLeak {
   const GURL URL = self.testServer->GetURL(kFormHTMLFile);
   std::string webViewText("Profile form");
   [AutofillAppInterface saveExampleProfile];
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 84e006d..e0809c7 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -3783,19 +3783,25 @@
 
   __weak BrowserViewController* weakSelf = self;
   GURL link = params.link_url;
+  bool isLink = link.is_valid();
+  GURL imageUrl = params.src_url;
+  bool isImage = imageUrl.is_valid();
+
   const GURL& lastCommittedURL = webState->GetLastCommittedURL();
+  web::Referrer referrer(lastCommittedURL, web::ReferrerPolicyDefault);
 
   NSMutableArray<UIMenuElement*>* menuElements = [[NSMutableArray alloc] init];
-
-  NSString* title;
+  MenuScenario menuScenario = isImage && isLink
+                                  ? MenuScenario::kContextMenuImageLink
+                                  : isImage ? MenuScenario::kContextMenuImage
+                                            : MenuScenario::kContextMenuLink;
 
   ActionFactory* actionFactory =
       [[ActionFactory alloc] initWithBrowser:self.browser
-                                    scenario:MenuScenario::kContextMenuLink];
+                                    scenario:menuScenario];
 
   if (link.SchemeIs(url::kJavaScriptScheme)) {
     // Open.
-    title = l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_OPEN);
     UIAction* open = [actionFactory actionToOpenJavascriptWithBlock:^{
       [weakSelf openJavascript:base::SysUTF8ToNSString(link.GetContent())];
     }];
@@ -3803,8 +3809,6 @@
   }
 
   if (web::UrlHasWebScheme(link)) {
-    web::Referrer referrer(lastCommittedURL, web::ReferrerPolicyDefault);
-
     // Open in New Tab.
     UIAction* openNewTab = [actionFactory actionToOpenInNewTabWithBlock:^{
       BrowserViewController* strongSelf = weakSelf;
@@ -3836,13 +3840,80 @@
       [menuElements addObject:openNewWindow];
     }
 
-    // TODO(crbug.com/1140387): Add to reading list action.
+    if (link.SchemeIsHTTPOrHTTPS()) {
+      NSString* innerText = params.link_text;
+      if ([innerText length] > 0) {
+        // Add to reading list.
+        UIAction* addToReadingList =
+            [actionFactory actionToAddToReadingListWithBlock:^{
+              [weakSelf addToReadingListURL:link title:innerText];
+            }];
+        [menuElements addObject:addToReadingList];
+      }
+    }
 
     // Copy Link.
     UIAction* copyLink = [actionFactory actionToCopyURL:link];
     [menuElements addObject:copyLink];
+  }
 
-    // TODO(crbug.com/1140387): Share action.
+  if (isImage) {
+    // Save Image.
+    UIAction* saveImage = [actionFactory actionSaveImageWithBlock:^{
+      [weakSelf.imageSaver saveImageAtURL:imageUrl
+                                 referrer:referrer
+                                 webState:weakSelf.currentWebState];
+    }];
+    [menuElements addObject:saveImage];
+
+    // Copy Image.
+    UIAction* copyImage = [actionFactory actionCopyImageWithBlock:^{
+      [weakSelf.imageCopier copyImageAtURL:imageUrl
+                                  referrer:referrer
+                                  webState:weakSelf.currentWebState];
+    }];
+    [menuElements addObject:copyImage];
+
+    // Open Image.
+    UIAction* openImage = [actionFactory actionOpenImageWithURL:imageUrl
+                                                     completion:nil];
+    [menuElements addObject:openImage];
+
+    // Open Image in new tab.
+    UrlLoadParams loadParams = UrlLoadParams::InNewTab(imageUrl);
+    loadParams.SetInBackground(YES);
+    loadParams.web_params.referrer = referrer;
+    loadParams.in_incognito = self.isOffTheRecord;
+    loadParams.append_to = kCurrentTab;
+    loadParams.origin_point = [params.view convertPoint:params.location
+                                                 toView:nil];
+    UIAction* openImageInNewTab =
+        [actionFactory actionOpenImageInNewTabWithUrlLoadParams:loadParams
+                                                     completion:nil];
+    [menuElements addObject:openImageInNewTab];
+
+    // Search by image.
+    TemplateURLService* service =
+        ios::TemplateURLServiceFactory::GetForBrowserState(self.browserState);
+    if (search_engines::SupportsSearchByImage(service)) {
+      const TemplateURL* defaultURL = service->GetDefaultSearchProvider();
+      NSString* title = l10n_util::GetNSStringF(
+          IDS_IOS_CONTEXT_MENU_SEARCHWEBFORIMAGE, defaultURL->short_name());
+      UIAction* searchByImage = [actionFactory
+          actionSearchImageWithTitle:title
+                               Block:^{
+                                 ImageFetchTabHelper* image_fetcher =
+                                     ImageFetchTabHelper::FromWebState(
+                                         self.currentWebState);
+                                 DCHECK(image_fetcher);
+                                 image_fetcher->GetImageData(
+                                     imageUrl, referrer, ^(NSData* data) {
+                                       [weakSelf searchByImageData:data
+                                                             atURL:imageUrl];
+                                     });
+                               }];
+      [menuElements addObject:searchByImage];
+    }
   }
 
   // Truncate context meny titles that originate from URLs, leaving text titles
@@ -3856,7 +3927,7 @@
 
   UIContextMenuActionProvider actionProvider =
       ^(NSArray<UIMenuElement*>* suggestedActions) {
-        RecordMenuShown(MenuScenario::kContextMenuLink);
+        RecordMenuShown(menuScenario);
         return [UIMenu menuWithTitle:menuTitle children:menuElements];
       };
 
diff --git a/ios/chrome/browser/ui/menu/BUILD.gn b/ios/chrome/browser/ui/menu/BUILD.gn
index f277ce1..4420d6b 100644
--- a/ios/chrome/browser/ui/menu/BUILD.gn
+++ b/ios/chrome/browser/ui/menu/BUILD.gn
@@ -14,18 +14,22 @@
   deps = [
     "resources:bookmark",
     "resources:close",
+    "resources:copy",
     "resources:copy_link_url",
     "resources:delete",
+    "resources:download",
     "resources:edit",
     "resources:mark_read",
     "resources:move_folder",
     "resources:offline",
     "resources:open",
+    "resources:open_image_in_new_tab",
     "resources:open_in_incognito",
     "resources:open_in_new_tab",
     "resources:open_new_window",
     "resources:read_later",
     "resources:remove",
+    "resources:search_image",
     "resources:share",
     "//base",
     "//ios/chrome/app/strings",
@@ -58,18 +62,22 @@
     ":menu",
     "resources:bookmark",
     "resources:close",
+    "resources:copy",
     "resources:copy_link_url",
     "resources:delete",
+    "resources:download",
     "resources:edit",
     "resources:mark_read",
     "resources:move_folder",
     "resources:offline",
     "resources:open",
+    "resources:open_image_in_new_tab",
     "resources:open_in_incognito",
     "resources:open_in_new_tab",
     "resources:open_new_window",
     "resources:read_later",
     "resources:remove",
+    "resources:search_image",
     "resources:share",
     "//base",
     "//base/test:test_support",
@@ -79,6 +87,7 @@
     "//ios/chrome/browser/main:test_support",
     "//ios/chrome/browser/sessions:test_support",
     "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/url_loading",
     "//ios/web/public/test",
     "//testing/gtest",
     "//third_party/ocmock",
diff --git a/ios/chrome/browser/ui/menu/action_factory.h b/ios/chrome/browser/ui/menu/action_factory.h
index ae684874..193fb4f 100644
--- a/ios/chrome/browser/ui/menu/action_factory.h
+++ b/ios/chrome/browser/ui/menu/action_factory.h
@@ -122,6 +122,28 @@
 // Creates a UIAction instance for closing a tab.
 - (UIAction*)actionToCloseTabWithBlock:(ProceduralBlock)block;
 
+// Creates a UIAction instance for saving an image.
+- (UIAction*)actionSaveImageWithBlock:(ProceduralBlock)block;
+
+// Creates a UIAction instance for copying an image.
+- (UIAction*)actionCopyImageWithBlock:(ProceduralBlock)block;
+
+// Creates a UIAction instance for opening an image |URL| in current tab and
+// invoke the given |completion| block after execution.
+- (UIAction*)actionOpenImageWithURL:(const GURL)URL
+                         completion:(ProceduralBlock)completion;
+
+// Creates a UIAction instance for opening an image |params| in a new tab and
+// invoke the given |completion| block after execution.
+- (UIAction*)actionOpenImageInNewTabWithUrlLoadParams:(UrlLoadParams)params
+                                           completion:
+                                               (ProceduralBlock)completion;
+
+// Creates a UIAction instance for searching an image with given search service
+// |title|. Invokes the given |completion| block after execution.
+- (UIAction*)actionSearchImageWithTitle:(NSString*)title
+                                  Block:(ProceduralBlock)block;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_MENU_ACTION_FACTORY_H_
diff --git a/ios/chrome/browser/ui/menu/action_factory.mm b/ios/chrome/browser/ui/menu/action_factory.mm
index 233285f6..f0ba8e3 100644
--- a/ios/chrome/browser/ui/menu/action_factory.mm
+++ b/ios/chrome/browser/ui/menu/action_factory.mm
@@ -275,4 +275,67 @@
   return action;
 }
 
+- (UIAction*)actionSaveImageWithBlock:(ProceduralBlock)block {
+  UIAction* action = [self
+      actionWithTitle:l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_SAVEIMAGE)
+                image:[UIImage imageNamed:@"download"]
+                 type:MenuActionType::Save
+                block:block];
+  return action;
+}
+
+- (UIAction*)actionCopyImageWithBlock:(ProceduralBlock)block {
+  UIAction* action = [self
+      actionWithTitle:l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_COPYIMAGE)
+                image:[UIImage imageNamed:@"copy"]
+                 type:MenuActionType::Copy
+                block:block];
+  return action;
+}
+
+- (UIAction*)actionOpenImageWithURL:(const GURL)URL
+                         completion:(ProceduralBlock)completion {
+  UrlLoadingBrowserAgent* loadingAgent =
+      UrlLoadingBrowserAgent::FromBrowser(self.browser);
+  UIAction* action = [self
+      actionWithTitle:l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENIMAGE)
+                image:[UIImage imageNamed:@"open"]
+                 type:MenuActionType::OpenInCurrentTab
+                block:^{
+                  loadingAgent->Load(UrlLoadParams::InCurrentTab(URL));
+                  if (completion) {
+                    completion();
+                  }
+                }];
+  return action;
+}
+
+- (UIAction*)actionOpenImageInNewTabWithUrlLoadParams:(UrlLoadParams)params
+                                           completion:
+                                               (ProceduralBlock)completion {
+  UrlLoadingBrowserAgent* loadingAgent =
+      UrlLoadingBrowserAgent::FromBrowser(self.browser);
+  UIAction* action =
+      [self actionWithTitle:l10n_util::GetNSString(
+                                IDS_IOS_CONTENT_CONTEXT_OPENIMAGENEWTAB)
+                      image:[UIImage imageNamed:@"open_image_in_new_tab"]
+                       type:MenuActionType::OpenInNewTab
+                      block:^{
+                        loadingAgent->Load(params);
+                        if (completion) {
+                          completion();
+                        }
+                      }];
+  return action;
+}
+
+- (UIAction*)actionSearchImageWithTitle:(NSString*)title
+                                  Block:(ProceduralBlock)block {
+  UIAction* action = [self actionWithTitle:title
+                                     image:[UIImage imageNamed:@"search_image"]
+                                      type:MenuActionType::SearchImage
+                                     block:block];
+  return action;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/menu/action_factory_unittest.mm b/ios/chrome/browser/ui/menu/action_factory_unittest.mm
index d8e2fa93..953c30b 100644
--- a/ios/chrome/browser/ui/menu/action_factory_unittest.mm
+++ b/ios/chrome/browser/ui/menu/action_factory_unittest.mm
@@ -12,6 +12,7 @@
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/menu/menu_action_type.h"
 #import "ios/chrome/browser/ui/menu/menu_histograms.h"
+#import "ios/chrome/browser/url_loading/url_loading_params.h"
 #import "ios/chrome/grit/ios_strings.h"
 #import "testing/gmock/include/gmock/gmock.h"
 #import "testing/gtest/include/gtest/gtest.h"
@@ -450,3 +451,87 @@
     EXPECT_EQ(expectedImage, actionWithBlock.image);
   }
 }
+
+// Tests that the save image action has the right title and image.
+TEST_F(ActionFactoryTest, SaveImageAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    UIImage* expectedImage = [UIImage imageNamed:@"download"];
+    NSString* expectedTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_SAVEIMAGE);
+
+    UIAction* action = [factory actionSaveImageWithBlock:^{
+    }];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_EQ(expectedImage, action.image);
+  }
+}
+
+// Tests that the copy image action has the right title and image.
+TEST_F(ActionFactoryTest, CopyImageAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    UIImage* expectedImage = [UIImage imageNamed:@"copy"];
+    NSString* expectedTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_COPYIMAGE);
+
+    UIAction* action = [factory actionCopyImageWithBlock:^{
+    }];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_EQ(expectedImage, action.image);
+  }
+}
+
+// Tests that the open image action has the right title and image.
+TEST_F(ActionFactoryTest, OpenImageAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    GURL testURL = GURL("https://example.com/logo.png");
+
+    UIImage* expectedImage = [UIImage imageNamed:@"open"];
+    NSString* expectedTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENIMAGE);
+
+    UIAction* action = [factory actionOpenImageWithURL:testURL
+                                            completion:^{
+                                            }];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_EQ(expectedImage, action.image);
+  }
+}
+
+// Tests that the open image in new tab action has the right title and image.
+TEST_F(ActionFactoryTest, OpenImageInNewTabAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    GURL testURL = GURL("https://example.com/logo.png");
+    UrlLoadParams testParams = UrlLoadParams::InNewTab(testURL);
+
+    UIImage* expectedImage = [UIImage imageNamed:@"open_image_in_new_tab"];
+    NSString* expectedTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
+
+    UIAction* action =
+        [factory actionOpenImageInNewTabWithUrlLoadParams:testParams
+                                               completion:^{
+                                               }];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_EQ(expectedImage, action.image);
+  }
+}
diff --git a/ios/chrome/browser/ui/menu/menu_action_type.h b/ios/chrome/browser/ui/menu/menu_action_type.h
index b47065e..ad2569a 100644
--- a/ios/chrome/browser/ui/menu/menu_action_type.h
+++ b/ios/chrome/browser/ui/menu/menu_action_type.h
@@ -28,7 +28,10 @@
   AddToBookmarks = 16,
   CloseTab = 17,
   EditBookmark = 18,
-  kMaxValue = EditBookmark
+  Save = 19,
+  OpenInCurrentTab = 20,
+  SearchImage = 21,
+  kMaxValue = SearchImage
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_MENU_MENU_ACTION_TYPE_H_
diff --git a/ios/chrome/browser/ui/menu/resources/BUILD.gn b/ios/chrome/browser/ui/menu/resources/BUILD.gn
index f13283b27..2ce80d3d 100644
--- a/ios/chrome/browser/ui/menu/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/menu/resources/BUILD.gn
@@ -20,6 +20,14 @@
   ]
 }
 
+imageset("copy") {
+  sources = [
+    "copy.imageset/Contents.json",
+    "copy.imageset/copy@2x.png",
+    "copy.imageset/copy@3x.png",
+  ]
+}
+
 imageset("copy_link_url") {
   sources = [
     "copy_link_url.imageset/Contents.json",
@@ -36,6 +44,14 @@
   ]
 }
 
+imageset("download") {
+  sources = [
+    "download.imageset/Contents.json",
+    "download.imageset/download@2x.png",
+    "download.imageset/download@3x.png",
+  ]
+}
+
 imageset("edit") {
   sources = [
     "edit.imageset/Contents.json",
@@ -44,6 +60,14 @@
   ]
 }
 
+imageset("open_image_in_new_tab") {
+  sources = [
+    "open_image_in_new_tab.imageset/Contents.json",
+    "open_image_in_new_tab.imageset/open_image_in_new_tab@2x.png",
+    "open_image_in_new_tab.imageset/open_image_in_new_tab@3x.png",
+  ]
+}
+
 imageset("open_in_incognito") {
   sources = [
     "open_in_incognito.imageset/Contents.json",
@@ -84,6 +108,14 @@
   ]
 }
 
+imageset("search_image") {
+  sources = [
+    "search_image.imageset/Contents.json",
+    "search_image.imageset/search_image@2x.png",
+    "search_image.imageset/search_image@3x.png",
+  ]
+}
+
 imageset("share") {
   sources = [
     "share.imageset/Contents.json",
diff --git a/ios/chrome/browser/ui/menu/resources/copy.imageset/Contents.json b/ios/chrome/browser/ui/menu/resources/copy.imageset/Contents.json
new file mode 100644
index 0000000..c6d95d4
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/copy.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "copy@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "copy@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "template-rendering-intent": "template"
+  }
+}
diff --git a/ios/chrome/browser/ui/menu/resources/copy.imageset/copy@2x.png b/ios/chrome/browser/ui/menu/resources/copy.imageset/copy@2x.png
new file mode 100644
index 0000000..ad0edb3
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/copy.imageset/copy@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/menu/resources/copy.imageset/copy@3x.png b/ios/chrome/browser/ui/menu/resources/copy.imageset/copy@3x.png
new file mode 100644
index 0000000..6a26b18
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/copy.imageset/copy@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/menu/resources/download.imageset/Contents.json b/ios/chrome/browser/ui/menu/resources/download.imageset/Contents.json
new file mode 100644
index 0000000..3689350
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/download.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "download@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "download@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "template-rendering-intent": "template"
+  }
+}
diff --git a/ios/chrome/browser/ui/menu/resources/download.imageset/download@2x.png b/ios/chrome/browser/ui/menu/resources/download.imageset/download@2x.png
new file mode 100644
index 0000000..6b07810
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/download.imageset/download@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/menu/resources/download.imageset/download@3x.png b/ios/chrome/browser/ui/menu/resources/download.imageset/download@3x.png
new file mode 100644
index 0000000..e712f939
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/download.imageset/download@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/menu/resources/open_image_in_new_tab.imageset/Contents.json b/ios/chrome/browser/ui/menu/resources/open_image_in_new_tab.imageset/Contents.json
new file mode 100644
index 0000000..34ad58b2
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/open_image_in_new_tab.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "open_image_in_new_tab@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "open_image_in_new_tab@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "template-rendering-intent": "template"
+  }
+}
diff --git a/ios/chrome/browser/ui/menu/resources/open_image_in_new_tab.imageset/open_image_in_new_tab@2x.png b/ios/chrome/browser/ui/menu/resources/open_image_in_new_tab.imageset/open_image_in_new_tab@2x.png
new file mode 100644
index 0000000..420f8ad9
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/open_image_in_new_tab.imageset/open_image_in_new_tab@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/menu/resources/open_image_in_new_tab.imageset/open_image_in_new_tab@3x.png b/ios/chrome/browser/ui/menu/resources/open_image_in_new_tab.imageset/open_image_in_new_tab@3x.png
new file mode 100644
index 0000000..acf9fd4
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/open_image_in_new_tab.imageset/open_image_in_new_tab@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/menu/resources/search_image.imageset/Contents.json b/ios/chrome/browser/ui/menu/resources/search_image.imageset/Contents.json
new file mode 100644
index 0000000..0ec8c28b
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/search_image.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "search_image@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "search_image@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "template-rendering-intent": "template"
+  }
+}
diff --git a/ios/chrome/browser/ui/menu/resources/search_image.imageset/search_image@2x.png b/ios/chrome/browser/ui/menu/resources/search_image.imageset/search_image@2x.png
new file mode 100644
index 0000000..9797cae5
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/search_image.imageset/search_image@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/menu/resources/search_image.imageset/search_image@3x.png b/ios/chrome/browser/ui/menu/resources/search_image.imageset/search_image@3x.png
new file mode 100644
index 0000000..9b8959f
--- /dev/null
+++ b/ios/chrome/browser/ui/menu/resources/search_image.imageset/search_image@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm
index e3337275..e4c57f5 100644
--- a/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.mm
@@ -98,15 +98,12 @@
   BOOL _closeSettingsOnAddAccount;
   std::unique_ptr<signin::IdentityManagerObserverBridge>
       _identityManagerObserver;
-  // Modal alert for sign out.
-  AlertCoordinator* _alertCoordinator;
   // Whether an authentication operation is in progress (e.g switch accounts,
   // sign out).
   BOOL _authenticationOperationInProgress;
   // Whether the view controller is currently being dismissed and new dismiss
   // requests should be ignored.
   BOOL _isBeingDismissed;
-  ios::DismissASMViewControllerBlock _dimissAccountDetailsViewControllerBlock;
   ResizedAvatarCache* _avatarCache;
   std::unique_ptr<ChromeIdentityServiceObserverBridge> _identityServiceObserver;
 
@@ -114,6 +111,13 @@
   NSDictionary<NSString*, TableViewItem*>* _identityMap;
 }
 
+// Modal alert for sign out.
+@property(nonatomic, strong) AlertCoordinator* alertCoordinator;
+
+// Callback to dismiss MyGoogle (Account Detail).
+@property(nonatomic, copy)
+    ios::DismissASMViewControllerBlock dismissAccountDetailsViewControllerBlock;
+
 // Modal alert for confirming account removal.
 @property(nonatomic, strong) AlertCoordinator* removeAccountCoordinator;
 
@@ -177,8 +181,8 @@
 }
 
 - (void)settingsWillBeDismissed {
-  [_alertCoordinator stop];
-  _alertCoordinator = nil;
+  [self.alertCoordinator stop];
+  self.alertCoordinator = nil;
   [self.signoutCoordinator stop];
   self.signoutCoordinator = nil;
   [self.removeAccountCoordinator stop];
@@ -455,9 +459,9 @@
 
   [self reloadData];
   if (![self authService]->HasPrimaryIdentity(signin::ConsentLevel::kSignin) &&
-      _dimissAccountDetailsViewControllerBlock) {
-    _dimissAccountDetailsViewControllerBlock(/*animated=*/YES);
-    _dimissAccountDetailsViewControllerBlock = nil;
+      self.dismissAccountDetailsViewControllerBlock) {
+    self.dismissAccountDetailsViewControllerBlock(/*animated=*/YES);
+    self.dismissAccountDetailsViewControllerBlock = nil;
   }
   // Only attempt to pop the top-most view controller once the account list
   // has been dismissed.
@@ -467,7 +471,7 @@
 #pragma mark - Authentication operations
 
 - (void)showAddAccount {
-  DCHECK(!_alertCoordinator);
+  DCHECK(!self.alertCoordinator);
   _authenticationOperationInProgress = YES;
 
   __weak __typeof(self) weakSelf = self;
@@ -492,8 +496,8 @@
 
 - (void)showAccountDetails:(ChromeIdentity*)identity
                   itemView:(UIView*)itemView {
-  DCHECK(!_alertCoordinator);
-  _alertCoordinator = [[ActionSheetCoordinator alloc]
+  DCHECK(!self.alertCoordinator);
+  self.alertCoordinator = [[ActionSheetCoordinator alloc]
       initWithBaseViewController:self
                          browser:_browser
                            title:nil
@@ -502,7 +506,7 @@
                             view:itemView];
   __weak __typeof(self) weakSelf = self;
   if (signin::IsSSOEditingEnabled()) {
-    [_alertCoordinator
+    [self.alertCoordinator
         addItemWithTitle:l10n_util::GetNSString(
                              IDS_IOS_MANAGE_YOUR_GOOGLE_ACCOUNT_TITLE)
                   action:^{
@@ -510,42 +514,42 @@
                   }
                    style:UIAlertActionStyleDefault];
   }
-  [_alertCoordinator
+  [self.alertCoordinator
       addItemWithTitle:l10n_util::GetNSString(
                            IDS_IOS_REMOVE_GOOGLE_ACCOUNT_TITLE)
                 action:^{
                   [weakSelf handleRemoveSecondaryAccountWithIdentity:identity];
                 }
                  style:UIAlertActionStyleDestructive];
-  [_alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
-                               action:^() {
-                                 [weakSelf handleAlertCoordinatorCancel];
-                               }
-                                style:UIAlertActionStyleCancel];
-  [_alertCoordinator start];
+  [self.alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
+                                   action:^() {
+                                     [weakSelf handleAlertCoordinatorCancel];
+                                   }
+                                    style:UIAlertActionStyleCancel];
+  [self.alertCoordinator start];
 }
 
-// Handles the manage Google account action from |_alertCoordinator|.
+// Handles the manage Google account action from |self.alertCoordinator|.
 // Action sheet created in |showAccountDetails:itemView:|
 - (void)handleManageGoogleAccountWithIdentity:(ChromeIdentity*)identity {
-  DCHECK(_alertCoordinator);
-  // |_alertCoordinator| should not be stopped, since the coordinator has been
-  // confirmed.
-  _alertCoordinator = nil;
-  _dimissAccountDetailsViewControllerBlock =
+  DCHECK(self.alertCoordinator);
+  // |self.alertCoordinator| should not be stopped, since the coordinator has
+  // been confirmed.
+  self.alertCoordinator = nil;
+  self.dismissAccountDetailsViewControllerBlock =
       ios::GetChromeBrowserProvider()
           .GetChromeIdentityService()
           ->PresentAccountDetailsController(identity, self,
                                             /*animated=*/YES);
 }
 
-// Handles the secondary account remove action from |_alertCoordinator|.
+// Handles the secondary account remove action from |self.alertCoordinator|.
 // Action sheet created in |showAccountDetails:itemView:|
 - (void)handleRemoveSecondaryAccountWithIdentity:(ChromeIdentity*)identity {
-  DCHECK(_alertCoordinator);
-  // |_alertCoordinator| should not be stopped, since the coordinator has been
-  // confirmed.
-  _alertCoordinator = nil;
+  DCHECK(self.alertCoordinator);
+  // |self.alertCoordinator| should not be stopped, since the coordinator has
+  // been confirmed.
+  self.alertCoordinator = nil;
   DCHECK(!self.removeAccountCoordinator);
   NSString* title =
       l10n_util::GetNSStringF(IDS_IOS_REMOVE_ACCOUNT_ALERT_TITLE,
@@ -610,7 +614,7 @@
 
 - (void)showSignOutWithClearData:(BOOL)forceClearData
                         itemView:(UIView*)itemView {
-  DCHECK(!_alertCoordinator);
+  DCHECK(!self.alertCoordinator);
   DCHECK(!base::FeatureList::IsEnabled(signin::kSimplifySignOutIOS));
   if (_authenticationOperationInProgress ||
       self != [self.navigationController topViewController]) {
@@ -636,7 +640,7 @@
     actionStyle = UIAlertActionStyleDefault;
   }
 
-  _alertCoordinator =
+  self.alertCoordinator =
       [[ActionSheetCoordinator alloc] initWithBaseViewController:self
                                                          browser:_browser
                                                            title:nil
@@ -645,28 +649,28 @@
                                                             view:itemView];
 
   __weak AccountsTableViewController* weakSelf = self;
-  [_alertCoordinator
+  [self.alertCoordinator
       addItemWithTitle:signOutTitle
                 action:^{
                   [weakSelf handleSignOutWithForceClearData:forceClearData];
                 }
                  style:actionStyle];
-  [_alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
-                               action:^() {
-                                 [weakSelf handleAlertCoordinatorCancel];
-                               }
-                                style:UIAlertActionStyleCancel];
-  [_alertCoordinator start];
+  [self.alertCoordinator addItemWithTitle:l10n_util::GetNSString(IDS_CANCEL)
+                                   action:^() {
+                                     [weakSelf handleAlertCoordinatorCancel];
+                                   }
+                                    style:UIAlertActionStyleCancel];
+  [self.alertCoordinator start];
 }
 
 - (void)handleSignOutWithForceClearData:(BOOL)forceClearData {
   if (!_browser)
     return;
 
-  // |_alertCoordinator| should not be stopped, since the coordinator has been
-  // confirmed.
-  DCHECK(_alertCoordinator);
-  _alertCoordinator = nil;
+  // |self.alertCoordinator| should not be stopped, since the coordinator has
+  // been confirmed.
+  DCHECK(self.alertCoordinator);
+  self.alertCoordinator = nil;
 
   AuthenticationService* authService = [self authService];
   if (authService->HasPrimaryIdentity(signin::ConsentLevel::kSignin)) {
@@ -701,12 +705,12 @@
   }
 }
 
-// Handles the cancel action for |_alertCoordinator|.
+// Handles the cancel action for |self.alertCoordinator|.
 - (void)handleAlertCoordinatorCancel {
-  DCHECK(_alertCoordinator);
-  // |_alertCoordinator| should not be stopped, since the coordinator has been
-  // cancelled.
-  _alertCoordinator = nil;
+  DCHECK(self.alertCoordinator);
+  // |self.alertCoordinator| should not be stopped, since the coordinator has
+  // been cancelled.
+  self.alertCoordinator = nil;
 }
 
 // Sets |_authenticationOperationInProgress| to NO and pops this accounts
@@ -739,7 +743,7 @@
         popViewControllerOrCloseSettingsAnimated:YES];
   };
   if (self.presentedViewController) {
-    // If |self| is presenting a view controller (like |_alertCoordinator|,
+    // If |self| is presenting a view controller (like |self.alertCoordinator|,
     // |_removeAccountCoordinator| or the account detail view controller, it
     // has to be dismissed before |self| can be poped from the navigation
     // controller.
diff --git a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_af.xtb b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_af.xtb
index 84f0a0fa..07ce57a2 100644
--- a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_af.xtb
+++ b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_af.xtb
@@ -26,6 +26,7 @@
 <translation id="8190452200642501331">Wys besonderhede</translation>
 <translation id="8219905600827687498">Voorgestelde wagwoorde</translation>
 <translation id="8300526662653766176">Stel 'n wagkode</translation>
+<translation id="8332511935157148552">Geen wagwoorde gevind nie</translation>
 <translation id="8518521100965196752">Om wagwoorde te gebruik, moet jy eers 'n wagkode op jou toestel stel.</translation>
 <translation id="8877181643142698531">URL</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_ja.xtb b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_ja.xtb
index 0238f62..4019413 100644
--- a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_ja.xtb
+++ b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_ja.xtb
@@ -26,6 +26,7 @@
 <translation id="8190452200642501331">詳細を表示します</translation>
 <translation id="8219905600827687498">パスワードの候補</translation>
 <translation id="8300526662653766176">パスコードの設定</translation>
+<translation id="8332511935157148552">パスワードは見つかりませんでした</translation>
 <translation id="8518521100965196752">パスワードを使用するには、まずデバイスにパスコードを設定する必要があります。</translation>
 <translation id="8877181643142698531">URL</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_si.xtb b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_si.xtb
index 7e8d21b..13965ac 100644
--- a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_si.xtb
+++ b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_si.xtb
@@ -26,6 +26,7 @@
 <translation id="8190452200642501331">විස්තර පෙන්වන්න</translation>
 <translation id="8219905600827687498">යෝජිත මුරපද</translation>
 <translation id="8300526662653766176">මුරකේතයක් සකසන්න</translation>
+<translation id="8332511935157148552">මුරපද හමු නොවිය</translation>
 <translation id="8518521100965196752">මුරපද භාවිත කිරීමට, ඔබ ප්‍රථමයෙන් ඔබේ උපාංගයේ මුරකේතයක් සැකසිය යුතුය.</translation>
 <translation id="8877181643142698531">URL</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_sw.xtb b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_sw.xtb
index 1dd23340..d90f3b4 100644
--- a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_sw.xtb
+++ b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_sw.xtb
@@ -26,6 +26,7 @@
 <translation id="8190452200642501331">Onyesha Maelezo</translation>
 <translation id="8219905600827687498">Manenosiri Yanayopendekezwa</translation>
 <translation id="8300526662653766176">Weka Nambari ya Siri</translation>
+<translation id="8332511935157148552">Hakuna Manenosiri Yaliyopatikana</translation>
 <translation id="8518521100965196752">Ili utumie manenosiri, ni lazima kwanza uweke nambari ya siri kwenye kifaa chako.</translation>
 <translation id="8877181643142698531">URL</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_uz.xtb b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_uz.xtb
index a58d119..f64ef12b 100644
--- a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_uz.xtb
+++ b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_uz.xtb
@@ -26,6 +26,7 @@
 <translation id="8190452200642501331">Tafsilotlarni ochish</translation>
 <translation id="8219905600827687498">Tavsiya etilgan parollar</translation>
 <translation id="8300526662653766176">Maxfiy kodni belgilang</translation>
+<translation id="8332511935157148552">Hech qanday parol topilmadi</translation>
 <translation id="8518521100965196752">Parollarni ishlatish uchun qurilmangizni maxfiy kod bilan qulflang.</translation>
 <translation id="8877181643142698531">URL</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_zh-HK.xtb b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_zh-HK.xtb
index 259e6df..02db269 100644
--- a/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_zh-HK.xtb
+++ b/ios/chrome/credential_provider_extension/strings/resources/ios_credential_provider_extension_strings_zh-HK.xtb
@@ -26,6 +26,7 @@
 <translation id="8190452200642501331">顯示詳情</translation>
 <translation id="8219905600827687498">建議的密碼</translation>
 <translation id="8300526662653766176">設定密碼</translation>
+<translation id="8332511935157148552">找不到密碼</translation>
 <translation id="8518521100965196752">如要使用密碼,您必須先在裝置上設定密碼。</translation>
 <translation id="8877181643142698531">網址</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
index feda25a..2dacd39623 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-4e50594e528d939ed938a845a92ca70d96c8a140
\ No newline at end of file
+5de0d14b3b6ec8ae1ad21bf79839e46cd4ceae40
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
index 48a1265..a9b39c8 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-5b95f3d4ff4ce5dfec8a7359bad62e2af782f45e
\ No newline at end of file
+7b3773a7abacd3c8091febe073324c8161593f94
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
index 9beb419..36aa3f3 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-a52d32f65390a7e1203a657423170c9d7ba35171
\ No newline at end of file
+4fbb35adec3fc76e2f30ac1a52c4d963df5037b3
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
index 71873d0..b8b90471 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-37e25c56c3492d60b6ce669edb63bccbc5af49f3
\ No newline at end of file
+f4b559cb0372e90f7a9116fa13fcf6069dde84c3
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
index 32b5c57..278e503 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-25806834900d60c1b39eb01f41c757015888b8ac
\ No newline at end of file
+7f2fdca24e1d4f6ee68d69490c62257716410187
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
index d0e571d..91e8076 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-8c1b41d544716d3f8416cd501876f809dcc532ec
\ No newline at end of file
+3536289ffaecc83437560dd3d3162a4c379acde2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
index a085953b..6baabff 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-2778b5b5231299ba30322e649ea5bbf5ebde8773
\ No newline at end of file
+f3f574a957908465895ee8e596b9206cefa0ca5c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
index 4a61e8d7..e59e11643 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-a84b723fcafdc911224593c3b631d6d066926721
\ No newline at end of file
+127e1794b2b6714fdb664563a840f00f7212646d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
index a84ce60..4973e61 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-5609532fcbde7837dff7891e94bae883e92dad28
\ No newline at end of file
+5ca2d79140850cc53da8109e66d6bd44a3720d1e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
index 6b533193..d622eff 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-b7cc10da7a8ed6af3f231baa7d9f8c57ab467799
\ No newline at end of file
+b88e5b52ce6213672a150c2f79f58d3ef829d378
\ No newline at end of file
diff --git a/ios/public/provider/chrome/browser/BUILD.gn b/ios/public/provider/chrome/browser/BUILD.gn
index e318e12..afb5f3a1 100644
--- a/ios/public/provider/chrome/browser/BUILD.gn
+++ b/ios/public/provider/chrome/browser/BUILD.gn
@@ -43,6 +43,13 @@
   ]
 }
 
+group("provider_api") {
+  deps = [
+    # The individual APIs.
+    "//ios/public/provider/chrome/browser/modals:modals_api",
+  ]
+}
+
 source_set("test_support") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
@@ -87,6 +94,9 @@
     # The target providing the ChromeBrowserProvider factory.
     ":test_provider_factory",
 
+    # The individual API implementations.
+    "//ios/public/provider/chrome/browser/modals:test_modals",
+
     # The provider API needs to provide MaterialDesignComponent API (as the
     # internal provider provides an alternate implementation).
     "//ios/third_party/material_components_ios:material_components_ios+bundle",
diff --git a/ios/public/provider/chrome/browser/modals/BUILD.gn b/ios/public/provider/chrome/browser/modals/BUILD.gn
index d879eb3..ce4c2353 100644
--- a/ios/public/provider/chrome/browser/modals/BUILD.gn
+++ b/ios/public/provider/chrome/browser/modals/BUILD.gn
@@ -9,3 +9,15 @@
     "modals_provider.mm",
   ]
 }
+
+source_set("modals_api") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [ "modals_api.h" ]
+}
+
+source_set("test_modals") {
+  testonly = true
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [ "test_modals.mm" ]
+  deps = [ ":modals_api" ]
+}
diff --git a/ios/public/provider/chrome/browser/modals/modals_api.h b/ios/public/provider/chrome/browser/modals/modals_api.h
new file mode 100644
index 0000000..0360201
--- /dev/null
+++ b/ios/public/provider/chrome/browser/modals/modals_api.h
@@ -0,0 +1,22 @@
+// 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.
+
+#ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_MODALS_MODALS_API_H_
+#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_MODALS_MODALS_API_H_
+
+#import <UIKit/UIKit.h>
+
+namespace ios {
+namespace provider {
+
+// Dismisses any modals presented from a |collection_view| item.
+void DismissModalsForCollectionView(UICollectionView* collection_view);
+
+// Dismisses any modals presented from a |table_view| cell.
+void DismissModalsForTableView(UITableView* table_view);
+
+}  // namespace provider
+}  // namespace ios
+
+#endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_MODALS_MODALS_API_H_
diff --git a/ios/public/provider/chrome/browser/modals/test_modals.mm b/ios/public/provider/chrome/browser/modals/test_modals.mm
new file mode 100644
index 0000000..d2ecca7d
--- /dev/null
+++ b/ios/public/provider/chrome/browser/modals/test_modals.mm
@@ -0,0 +1,23 @@
+// 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.
+
+#import "ios/public/provider/chrome/browser/modals/modals_api.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace ios {
+namespace provider {
+
+void DismissModalsForCollectionView(UICollectionView*) {
+  // Test implementation does nothing.
+}
+
+void DismissModalsForTableView(UITableView*) {
+  // Test implementation does nothing.
+}
+
+}  // namespace provider
+}  // namespace ios
diff --git a/ios/public/provider/chrome/browser/signin/BUILD.gn b/ios/public/provider/chrome/browser/signin/BUILD.gn
index aa80521..afb814a 100644
--- a/ios/public/provider/chrome/browser/signin/BUILD.gn
+++ b/ios/public/provider/chrome/browser/signin/BUILD.gn
@@ -92,6 +92,7 @@
     ":signin",
     "//base",
     "//base/test:test_support",
+    "//components/signin/internal/identity_manager",
     "//testing/gmock",
     "//testing/gtest",
   ]
diff --git a/ios/public/provider/chrome/browser/signin/DEPS b/ios/public/provider/chrome/browser/signin/DEPS
index 15993b0..816ed07 100644
--- a/ios/public/provider/chrome/browser/signin/DEPS
+++ b/ios/public/provider/chrome/browser/signin/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+components/sync/driver/trusted_vault_client.h",
   "+components/signin/internal/identity_manager/account_capabilities_constants.h",
+  "+components/signin/public/base/signin_metrics.h",
 ]
 
 specific_include_rules = {
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
index e7b795f..4a69d64 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
@@ -7,6 +7,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/sys_string_conversions.h"
 #import "components/signin/internal/identity_manager/account_capabilities_constants.h"
+#include "components/signin/public/base/signin_metrics.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
 #include "ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h"
@@ -81,17 +82,48 @@
   }
 };
 
-}  // anonymous namespace
+// Helper struct for computing the result of fetching account capabilities.
+struct FetchCapabilitiesResult {
+  FetchCapabilitiesResult() = default;
+  ~FetchCapabilitiesResult() = default;
 
-namespace {
-ChromeIdentityCapabilityResult CapabilityResultFromNSNumber(NSNumber* result) {
-  DCHECK(result);
-  int resultInt = [result intValue];
-  DCHECK_GE(resultInt,
-            static_cast<int>(ChromeIdentityCapabilityResult::kFalse));
-  DCHECK_LE(resultInt,
-            static_cast<int>(ChromeIdentityCapabilityResult::kUnknown));
-  return static_cast<ChromeIdentityCapabilityResult>(resultInt);
+  ChromeIdentityCapabilityResult capability_value;
+  signin_metrics::FetchAccountCapabilitiesFromSystemLibraryResult fetch_result;
+};
+
+// Computes the value of fetching account capabilities.
+FetchCapabilitiesResult ComputeFetchCapabilitiesResult(
+    NSNumber* capability_value,
+    NSError* error) {
+  FetchCapabilitiesResult result;
+  if (error) {
+    result.capability_value = ChromeIdentityCapabilityResult::kUnknown;
+    result.fetch_result = signin_metrics::
+        FetchAccountCapabilitiesFromSystemLibraryResult::kErrorGeneric;
+  } else if (!capability_value) {
+    result.capability_value = ChromeIdentityCapabilityResult::kUnknown;
+    result.fetch_result =
+        signin_metrics::FetchAccountCapabilitiesFromSystemLibraryResult::
+            kErrorMissingCapability;
+  } else {
+    int capability_value_int = capability_value.intValue;
+    switch (capability_value_int) {
+      case static_cast<int>(ChromeIdentityCapabilityResult::kFalse):
+      case static_cast<int>(ChromeIdentityCapabilityResult::kTrue):
+      case static_cast<int>(ChromeIdentityCapabilityResult::kUnknown):
+        result.capability_value =
+            static_cast<ChromeIdentityCapabilityResult>(capability_value_int);
+        result.fetch_result = signin_metrics::
+            FetchAccountCapabilitiesFromSystemLibraryResult::kSuccess;
+        break;
+      default:
+        result.capability_value = ChromeIdentityCapabilityResult::kUnknown;
+        result.fetch_result =
+            signin_metrics::FetchAccountCapabilitiesFromSystemLibraryResult::
+                kErrorUnexpectedValue;
+    }
+  }
+  return result;
 }
 
 }  // namespace
@@ -220,11 +252,16 @@
         base::UmaHistogramTimes(
             "Signin.AccountCapabilities.GetFromSystemLibraryDuration",
             base::TimeTicks::Now() - fetch_start);
-        if (!completion) {
-          return;
-        }
-        completion(CapabilityResultFromNSNumber(
-            [capabilities objectForKey:canOfferExtendedChromeSyncPromos]));
+
+        FetchCapabilitiesResult result = ComputeFetchCapabilitiesResult(
+            [capabilities objectForKey:canOfferExtendedChromeSyncPromos],
+            error);
+        base::UmaHistogramEnumeration(
+            "Signin.AccountCapabilities.GetFromSystemLibraryResult",
+            result.fetch_result);
+
+        if (completion)
+          completion(result.capability_value);
       });
 }
 
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service_unittest.mm b/ios/public/provider/chrome/browser/signin/chrome_identity_service_unittest.mm
index 373d8a6..feb129d09 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service_unittest.mm
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service_unittest.mm
@@ -7,6 +7,8 @@
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_mock_clock_override.h"
+#include "components/signin/internal/identity_manager/account_capabilities_constants.h"
+#include "components/signin/public/base/signin_metrics.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h"
 #import "testing/gmock/include/gmock/gmock.h"
 #import "testing/gtest/include/gtest/gtest.h"
@@ -17,6 +19,8 @@
 #error "This file requires ARC support."
 #endif
 
+using signin_metrics::FetchAccountCapabilitiesFromSystemLibraryResult;
+
 namespace ios {
 namespace {
 
@@ -62,63 +66,134 @@
 
 class ChromeIdentityServiceTest : public PlatformTest {
  public:
-  ChromeIdentityServiceTest() = default;
+  ChromeIdentityServiceTest() {
+    identity_ = [FakeChromeIdentity identityWithEmail:@"foo@bar.com"
+                                               gaiaID:@"foo_bar_id"
+                                                 name:@"Foo"];
+  }
   ~ChromeIdentityServiceTest() override = default;
 
  protected:
   ChromeIdentityCapabilityResult FetchCanOfferExtendedSyncPromos(
       ChromeIdentity* identity,
       int capability_value) {
+    base::HistogramTester histogramTester;
+    ChromeIdentityCapabilityResult result = FetchCanOfferExtendedSyncPromos(
+        identity, [NSNumber numberWithInt:capability_value], /*error=*/nil);
+    histogramTester.ExpectUniqueSample(
+        "Signin.AccountCapabilities.GetFromSystemLibraryResult",
+        FetchAccountCapabilitiesFromSystemLibraryResult::kSuccess, 1);
+    return result;
+  }
+
+  ChromeIdentityCapabilityResult FetchCanOfferExtendedSyncPromos(
+      ChromeIdentity* identity,
+      NSNumber* capability_value,
+      NSError* error) {
     __block ChromeIdentityCapabilityResult fetched_capability_result;
     service_.CanOfferExtendedSyncPromos(
         identity, ^(ChromeIdentityCapabilityResult result) {
           fetched_capability_result = result;
         });
-    EXPECT_NSEQ(@[ @"accountcapabilities/gi2tklldmfya" ],
+    EXPECT_NSEQ(@[ @(kCanOfferExtendedChromeSyncPromosCapabilityName) ],
                 service_.fetch_capabilities_request().capabilities);
     EXPECT_EQ(identity, service_.fetch_capabilities_request().identity);
 
-    NSNumber* capability_val_number = [NSNumber numberWithInt:capability_value];
-    service_.RunFinishCapabilitiesCompletion(
-        @{@"accountcapabilities/gi2tklldmfya" : capability_val_number},
-        /*error=*/nil);
+    NSDictionary* capability_values = capability_value ? @{
+      @(kCanOfferExtendedChromeSyncPromosCapabilityName) : capability_value
+    }
+                                                       : nil;
+    service_.RunFinishCapabilitiesCompletion(capability_values, error);
     return fetched_capability_result;
   }
 
+  FakeChromeIdentity* identity_;
   TestChromeIdentityService service_;
 };
 
 TEST_F(ChromeIdentityServiceTest, CanOfferExtendedSyncPromos) {
-  FakeChromeIdentity* identity =
-      [FakeChromeIdentity identityWithEmail:@"foo@bar.com"
-                                     gaiaID:@"foo_bar_id"
-                                       name:@"Foo"];
-
   EXPECT_EQ(ChromeIdentityCapabilityResult::kFalse,
-            FetchCanOfferExtendedSyncPromos(identity,
+            FetchCanOfferExtendedSyncPromos(identity_,
                                             /*capability_value=*/0));
 
   EXPECT_EQ(ChromeIdentityCapabilityResult::kTrue,
-            FetchCanOfferExtendedSyncPromos(identity,
+            FetchCanOfferExtendedSyncPromos(identity_,
                                             /*capability_value=*/1));
 
   EXPECT_EQ(ChromeIdentityCapabilityResult::kUnknown,
-            FetchCanOfferExtendedSyncPromos(identity,
+            FetchCanOfferExtendedSyncPromos(identity_,
                                             /*capability_value=*/2));
 }
 
-TEST_F(ChromeIdentityServiceTest, CanOfferExtendedSyncPromos_Histogram) {
-  FakeChromeIdentity* identity =
-      [FakeChromeIdentity identityWithEmail:@"foo@bar.com"
-                                     gaiaID:@"foo_bar_id"
-                                       name:@"Foo"];
+TEST_F(ChromeIdentityServiceTest,
+       CanOfferExtendedSyncPromos_MissingCapability) {
+  base::HistogramTester histogramTester;
+  EXPECT_EQ(ChromeIdentityCapabilityResult::kUnknown,
+            FetchCanOfferExtendedSyncPromos(identity_, /*capability_value=*/nil,
+                                            /*error=*/nil));
+  histogramTester.ExpectUniqueSample(
+      "Signin.AccountCapabilities.GetFromSystemLibraryResult",
+      FetchAccountCapabilitiesFromSystemLibraryResult::kErrorMissingCapability,
+      1);
+}
 
+TEST_F(ChromeIdentityServiceTest,
+       CanOfferExtendedSyncPromos_UnexpectedCapabilityValue) {
+  base::HistogramTester histogramTester;
+  // Capability value of 100 is out of range.
+  EXPECT_EQ(ChromeIdentityCapabilityResult::kUnknown,
+            FetchCanOfferExtendedSyncPromos(
+                identity_, /*capability_value=*/[NSNumber numberWithInt:100],
+                /*error=*/nil));
+  histogramTester.ExpectUniqueSample(
+      "Signin.AccountCapabilities.GetFromSystemLibraryResult",
+      FetchAccountCapabilitiesFromSystemLibraryResult::kErrorUnexpectedValue,
+      1);
+}
+
+TEST_F(ChromeIdentityServiceTest, CanOfferExtendedSyncPromos_Error) {
+  NSError* error = [NSError errorWithDomain:@"test" code:-100 userInfo:nil];
+
+  {
+    base::HistogramTester histogramTester;
+    EXPECT_EQ(ChromeIdentityCapabilityResult::kUnknown,
+              FetchCanOfferExtendedSyncPromos(identity_,
+                                              /*capability_value=*/nil, error));
+    histogramTester.ExpectUniqueSample(
+        "Signin.AccountCapabilities.GetFromSystemLibraryResult",
+        FetchAccountCapabilitiesFromSystemLibraryResult::kErrorGeneric, 1);
+  }
+
+  {
+    base::HistogramTester histogramTester;
+    EXPECT_EQ(
+        ChromeIdentityCapabilityResult::kUnknown,
+        FetchCanOfferExtendedSyncPromos(
+            identity_, /*capability_value=*/[NSNumber numberWithInt:0], error));
+    histogramTester.ExpectUniqueSample(
+        "Signin.AccountCapabilities.GetFromSystemLibraryResult",
+        FetchAccountCapabilitiesFromSystemLibraryResult::kErrorGeneric, 1);
+  }
+  {
+    base::HistogramTester histogramTester;
+    EXPECT_EQ(
+        ChromeIdentityCapabilityResult::kUnknown,
+        FetchCanOfferExtendedSyncPromos(
+            identity_, /*capability_value=*/[NSNumber numberWithInt:1], error));
+    histogramTester.ExpectUniqueSample(
+        "Signin.AccountCapabilities.GetFromSystemLibraryResult",
+        FetchAccountCapabilitiesFromSystemLibraryResult::kErrorGeneric, 1);
+  }
+}
+
+TEST_F(ChromeIdentityServiceTest, CanOfferExtendedSyncPromos_Histogram) {
   base::HistogramTester histogramTester;
   base::ScopedMockClockOverride clock;
-  service_.CanOfferExtendedSyncPromos(identity, /*callback=*/nil);
+  service_.CanOfferExtendedSyncPromos(identity_, /*callback=*/nil);
   clock.Advance(base::TimeDelta::FromMinutes(1));
   service_.RunFinishCapabilitiesCompletion(
-      @{@"accountcapabilities/gi2tklldmfya" : @0}, /*error=*/nil);
+      @{@(kCanOfferExtendedChromeSyncPromosCapabilityName) : @0},
+      /*error=*/nil);
   histogramTester.ExpectUniqueTimeSample(
       "Signin.AccountCapabilities.GetFromSystemLibraryDuration",
       base::TimeDelta::FromMinutes(1),
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h
index aad132c..3be7016 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h
@@ -76,9 +76,6 @@
   // Sets up the mock methods for integration tests.
   void SetUpForIntegrationTests();
 
-  // Adds the identities subject to minor mode restrictions given their name.
-  void AddMinorModeIdentities(NSArray* identitiesName);
-
   // Adds the managed identities given their name.
   void AddManagedIdentities(NSArray* identitiesName);
 
@@ -92,6 +89,11 @@
   // When set to true, call to GetAccessToken() fakes a MDM error.
   void SetFakeMDMError(bool fakeMDMError);
 
+  // Adds a mapping from the |identity| to the capability name -> capability
+  // result value used when calling FetchCapabilities.
+  // Assumes the |identity| has been added to the available identities.
+  void SetCapabilities(ChromeIdentity* identity, NSDictionary* capabilities);
+
   // Waits until all asynchronous callbacks have been completed by the service.
   // Returns true on successful completion.
   bool WaitForServiceCallbacksToComplete();
@@ -99,8 +101,15 @@
   // Triggers an update notification for |identity|.
   void TriggerIdentityUpdateNotification(ChromeIdentity* identity);
 
+ protected:
+  void FetchCapabilities(
+      NSArray* capabilities,
+      ChromeIdentity* identity,
+      ChromeIdentityCapabilitiesFetchCompletionBlock completion);
+
  private:
   NSMutableArray<ChromeIdentity*>* identities_;
+  NSMutableDictionary<NSString*, NSDictionary*>* capabilitiesByIdentity_;
 
   // If true, call to GetAccessToken() fakes a MDM error.
   bool _fakeMDMError;
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm
index 42e71b58..c05fcad 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm
@@ -129,6 +129,7 @@
 
 FakeChromeIdentityService::FakeChromeIdentityService()
     : identities_([[NSMutableArray alloc] init]),
+      capabilitiesByIdentity_([[NSMutableDictionary alloc] init]),
       _fakeMDMError(false),
       _pendingCallback(0) {}
 
@@ -184,6 +185,7 @@
     ChromeIdentity* identity,
     ForgetIdentityCallback callback) {
   [identities_ removeObject:identity];
+  [capabilitiesByIdentity_ removeObjectForKey:identity.gaiaID];
   FireIdentityListChanged(/*keychain_reload=*/false);
   if (callback) {
     // Forgetting an identity is normally an asynchronous operation (that
@@ -278,6 +280,7 @@
 void FakeChromeIdentityService::SimulateForgetIdentityFromOtherApp(
     ChromeIdentity* identity) {
   [identities_ removeObject:identity];
+  [capabilitiesByIdentity_ removeObjectForKey:identity.gaiaID];
   FireChromeIdentityReload();
 }
 
@@ -298,18 +301,6 @@
   }
 }
 
-void FakeChromeIdentityService::AddMinorModeIdentities(
-    NSArray* identitiesNames) {
-  for (NSString* name in identitiesNames) {
-    NSString* email = [NSString
-        stringWithFormat:@"%@%@", name, kMinorModeIdentityEmailSuffix];
-    NSString* gaiaID = [NSString stringWithFormat:kIdentityGaiaIDFormat, name];
-    [identities_ addObject:[FakeChromeIdentity identityWithEmail:email
-                                                          gaiaID:gaiaID
-                                                            name:name]];
-  }
-}
-
 void FakeChromeIdentityService::AddIdentities(NSArray* identitiesNames) {
   for (NSString* name in identitiesNames) {
     NSString* email = [NSString stringWithFormat:kIdentityEmailFormat, name];
@@ -327,6 +318,12 @@
   FireIdentityListChanged(/*keychain_reload=*/false);
 }
 
+void FakeChromeIdentityService::SetCapabilities(ChromeIdentity* identity,
+                                                NSDictionary* capabilities) {
+  DCHECK([identities_ containsObject:identity]);
+  [capabilitiesByIdentity_ setObject:capabilities forKey:identity.gaiaID];
+}
+
 void FakeChromeIdentityService::SetFakeMDMError(bool fakeMDMError) {
   _fakeMDMError = fakeMDMError;
 }
@@ -343,4 +340,26 @@
   FireProfileDidUpdate(identity);
 }
 
+void FakeChromeIdentityService::FetchCapabilities(
+    NSArray* capabilities,
+    ChromeIdentity* identity,
+    ChromeIdentityCapabilitiesFetchCompletionBlock completion) {
+  NSMutableDictionary* result = [[NSMutableDictionary alloc] init];
+  NSDictionary* capabilitiesForIdentity =
+      capabilitiesByIdentity_[identity.gaiaID];
+  for (NSString* capability : capabilities) {
+    // Set capability result as unknown if not set in capabilitiesByIdentity_.
+    NSNumber* capabilityResult =
+        [NSNumber numberWithInt:static_cast<int>(
+                                    ChromeIdentityCapabilityResult::kUnknown)];
+    if ([capabilitiesForIdentity objectForKey:capability]) {
+      capabilityResult = capabilitiesForIdentity[capability];
+    }
+    [result setObject:capabilityResult forKey:capability];
+  }
+  if (completion) {
+    completion(result, nil);
+  }
+}
+
 }  // namespace ios
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service_constants.h b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service_constants.h
index 987b821..6b1fff5 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service_constants.h
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service_constants.h
@@ -12,9 +12,6 @@
 // Email suffix used for managed accounts.
 extern NSString* const kManagedIdentityEmailSuffix;
 
-// Email suffix used for accounts subject to minor mode restrictions.
-extern NSString* const kMinorModeIdentityEmailSuffix;
-
 }  // namespace ios
 
 #endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SIGNIN_FAKE_CHROME_IDENTITY_SERVICE_CONSTANTS_H_
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service_constants.mm b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service_constants.mm
index 4252c84..dd44004 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service_constants.mm
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service_constants.mm
@@ -12,6 +12,4 @@
 
 NSString* const kManagedIdentityEmailSuffix = @"@google.com";
 
-NSString* const kMinorModeIdentityEmailSuffix = @"@minor-mode";
-
 }  // namespace ios
diff --git a/media/gpu/test/video_encoder/decoder_buffer_validator.cc b/media/gpu/test/video_encoder/decoder_buffer_validator.cc
index 14551448..f67bcab 100644
--- a/media/gpu/test/video_encoder/decoder_buffer_validator.cc
+++ b/media/gpu/test/video_encoder/decoder_buffer_validator.cc
@@ -417,11 +417,10 @@
   }
 
   if (metadata.vp9 && metadata.vp9->temporal_up_switch) {
-    // Temporal up-switch, invalidate any non-base-layer frames with lower
+    // Temporal up-switch, invalidate any buffers containing frames with higher
     // temporal id.
     for (auto& buffer : reference_buffers_) {
-      if (buffer && buffer->temporal_id > 0 &&
-          buffer->temporal_id < new_buffer_state.temporal_id) {
+      if (buffer && buffer->temporal_id > new_buffer_state.temporal_id) {
         buffer.reset();
       }
     }
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
index a18a09b..3940a180 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
@@ -372,8 +372,9 @@
 
   output_buffer_byte_size_ = encoder_->GetBitstreamBufferSize();
 
-  va_surface_release_cb_ = BindToCurrentLoop(base::BindRepeating(
-      &VaapiVideoEncodeAccelerator::RecycleVASurfaceID, encoder_weak_this_));
+  va_surface_release_cb_ = BindToCurrentLoop(
+      base::BindRepeating(&VaapiVideoEncodeAccelerator::RecycleVASurfaceID,
+                          encoder_weak_this_, &available_va_surface_ids_));
 
   visible_rect_ = gfx::Rect(config.input_visible_size);
   expected_input_coded_size_ = VideoFrame::DetermineAlignedSize(
@@ -447,15 +448,6 @@
 }
 
 void VaapiVideoEncodeAccelerator::RecycleVASurfaceID(
-    VASurfaceID va_surface_id) {
-  DVLOGF(4) << "va_surface_id: " << va_surface_id;
-  DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_);
-
-  available_va_surface_ids_.push_back(va_surface_id);
-  EncodePendingInputs();
-}
-
-void VaapiVideoEncodeAccelerator::RecycleVPPVASurfaceID(
     std::vector<VASurfaceID>* va_surfaces,
     VASurfaceID va_surface_id) {
   DVLOGF(4) << "va_surface_id: " << va_surface_id;
@@ -561,8 +553,8 @@
 
 scoped_refptr<VASurface>
 VaapiVideoEncodeAccelerator::BlitSurfaceWithCreateVppIfNeeded(
-    const scoped_refptr<VideoFrame>& frame,
-    const scoped_refptr<VASurface>& input_surface,
+    const VASurface& input_surface,
+    const gfx::Rect& input_visible_rect,
     const gfx::Size& encode_size,
     size_t num_va_surfaces) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_);
@@ -598,7 +590,7 @@
 
     vpp_va_surface_release_cb_[encode_size] =
         BindToCurrentLoop(base::BindRepeating(
-            &VaapiVideoEncodeAccelerator::RecycleVPPVASurfaceID,
+            &VaapiVideoEncodeAccelerator::RecycleVASurfaceID,
             encoder_weak_this_, &available_vpp_va_surface_ids_[encode_size]));
   }
 
@@ -609,13 +601,13 @@
                     base::BindOnce(vpp_va_surface_release_cb_[encode_size]));
   available_vpp_va_surface_ids_[encode_size].pop_back();
   if (!vpp_vaapi_wrapper_[encode_size]->BlitSurface(
-          *input_surface, *blit_surface, frame->visible_rect(),
+          input_surface, *blit_surface, input_visible_rect,
           gfx::Rect(encode_size))) {
     NOTIFY_ERROR(kPlatformFailureError,
                  "Failed BlitSurface on frame size: "
-                     << frame->coded_size().ToString()
-                     << " (visible rect: " << frame->visible_rect().ToString()
-                     << ") -> frame size: " << encode_size.ToString());
+                     << input_surface.size().ToString()
+                     << " (visible rect: " << input_visible_rect.ToString()
+                     << ") -> encode size: " << encode_size.ToString());
     return nullptr;
   }
   return blit_surface;
@@ -710,9 +702,9 @@
     DCHECK(native_input_mode_);
     // Simulcast mode, allocate the same number of surfaces as reconstructed
     // surfaces when create vpp.
-    input_surface = BlitSurfaceWithCreateVppIfNeeded(frame, input_surface,
-                                                     aligned_va_surface_size_,
-                                                     num_frames_in_flight_ + 1);
+    input_surface = BlitSurfaceWithCreateVppIfNeeded(
+        *input_surface, frame->visible_rect(), aligned_va_surface_size_,
+        num_frames_in_flight_ + 1);
     DCHECK(input_surface);
   }
 
@@ -722,7 +714,8 @@
     // K-SVC mode, allocate surfaces as input and reconstructed surfaces for
     // lower layer when create vpp.
     input_surface = BlitSurfaceWithCreateVppIfNeeded(
-        frame, input_surface, encode_size, (num_frames_in_flight_ + 1) * 2);
+        *input_surface, visible_rect_, encode_size,
+        (num_frames_in_flight_ + 1) * 2);
     DCHECK(input_surface);
 
     reconstructed_surface =
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.h b/media/gpu/vaapi/vaapi_video_encode_accelerator.h
index 454af29..7b442b089 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator.h
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.h
@@ -98,12 +98,12 @@
   void DestroyTask();
   void FlushTask(FlushCallback flush_callback);
 
-  // Blits input surface to dest size surface and return processed surface, if
-  // |vpp_vaapi_wrapper| is empty, this will create it and corresponding
-  // surfaces.
+  // Blits |input_surface| to an internally-allocated |input_visible_rect|
+  // surface, returning it. If |vpp_vaapi_wrapper_| is empty, this will create
+  // it and corresponding surfaces. Returns nullptr on failure.
   scoped_refptr<VASurface> BlitSurfaceWithCreateVppIfNeeded(
-      const scoped_refptr<VideoFrame>& frame,
-      const scoped_refptr<VASurface>& input_surface,
+      const VASurface& input_surface,
+      const gfx::Rect& input_visible_rect,
       const gfx::Size& encode_size,
       size_t num_va_surfaces);
 
@@ -128,13 +128,9 @@
   void ExecuteEncode(VASurfaceID va_surface_id);
 
   // Callback that returns a no longer used VASurfaceID to
-  // |available_va_surface_ids_| for reuse.
-  void RecycleVASurfaceID(VASurfaceID va_surface_id);
-
-  // Callback that returns a no longer used VASurfaceID to
-  // |available_vpp_va_surface_ids_| for reuse.
-  void RecycleVPPVASurfaceID(std::vector<VASurfaceID>* va_surfaces,
-                             VASurfaceID va_surface_id);
+  // |va_surfaces| for reuse and kicks EncodePendingInputs() again.
+  void RecycleVASurfaceID(std::vector<VASurfaceID>* va_surfaces,
+                          VASurfaceID va_surface_id);
 
   // Returns a bitstream buffer to the client if both a previously executed job
   // awaits to be completed and we have bitstream buffers available to download
diff --git a/media/gpu/vaapi/vp9_svc_layers.cc b/media/gpu/vaapi/vp9_svc_layers.cc
index 99a65036..2419530 100644
--- a/media/gpu/vaapi/vp9_svc_layers.cc
+++ b/media/gpu/vaapi/vp9_svc_layers.cc
@@ -30,8 +30,13 @@
 }  // namespace
 
 struct VP9SVCLayers::FrameConfig {
-  FrameConfig(size_t layer_index, FrameFlags first, FrameFlags second)
-      : layer_index_(layer_index), buffer_flags_{first, second} {}
+  FrameConfig(size_t layer_index,
+              FrameFlags first,
+              FrameFlags second,
+              bool temporal_up_switch)
+      : layer_index_(layer_index),
+        buffer_flags_{first, second},
+        temporal_up_switch_(temporal_up_switch) {}
   FrameConfig() = delete;
 
   // VP9SVCLayers uses 2 reference frame slots for each spatial layer, and
@@ -70,10 +75,12 @@
   }
 
   size_t layer_index() const { return layer_index_; }
+  bool temporal_up_switch() const { return temporal_up_switch_; }
 
  private:
   const size_t layer_index_;
   const FrameFlags buffer_flags_[kMaxNumUsedRefFramesEachSpatialLayer];
+  const bool temporal_up_switch_;
 };
 
 namespace {
@@ -87,15 +94,15 @@
       // In this case, the number of spatial layers must great than 1.
       // TL0 references and updates the 'first' buffer.
       // [TL0]---[TL0]
-      return {FrameConfig(0, kReferenceAndUpdate, kNone)};
+      return {FrameConfig(0, kReferenceAndUpdate, kNone, true)};
     case 2:
       // TL0 references and updates the 'first' buffer.
       // TL1 references 'first' buffer.
       //      [TL1]
       //     /
       // [TL0]-----[TL0]
-      return {FrameConfig(0, kReferenceAndUpdate, kNone),
-              FrameConfig(1, kReference, kNone)};
+      return {FrameConfig(0, kReferenceAndUpdate, kNone, true),
+              FrameConfig(1, kReference, kNone, true)};
     case 3:
       // TL0 references and updates the 'first' buffer.
       // TL1 references 'first' and updates 'second'.
@@ -104,10 +111,10 @@
       //    _/   [TL1]--/
       //   /_______/
       // [TL0]--------------[TL0]
-      return {FrameConfig(0, kReferenceAndUpdate, kNone),
-              FrameConfig(2, kReference, kNone),
-              FrameConfig(1, kReference, kUpdate),
-              FrameConfig(2, kNone, kReference)};
+      return {FrameConfig(0, kReferenceAndUpdate, kNone, true),
+              FrameConfig(2, kReference, kNone, true),
+              FrameConfig(1, kReference, kUpdate, true),
+              FrameConfig(2, kNone, kReference, true)};
     default:
       NOTREACHED();
       return {};
@@ -304,6 +311,7 @@
     FillVp9MetadataForEncoding(&(*picture->metadata_for_encoding),
                                /*reference_frame_indices=*/{});
     UpdateRefFramesPatternIndex(/*refresh_frame_indices=*/{0, 1});
+    picture->metadata_for_encoding->temporal_up_switch = true;
 
     DVLOGF(4)
         << "Frame num: " << frame_num_
@@ -351,6 +359,8 @@
   FillVp9MetadataForEncoding(&(*picture->metadata_for_encoding),
                              reference_frame_indices);
   UpdateRefFramesPatternIndex(refresh_frame_indices);
+  picture->metadata_for_encoding->temporal_up_switch =
+      temporal_layers_config.temporal_up_switch();
   spatial_idx_++;
 }
 
@@ -381,7 +391,6 @@
   // |has_reference| is true if a frame in the same spatial layer is referred.
   if (frame_num_ != 0)
     metadata->has_reference = !reference_frame_indices.empty();
-  metadata->temporal_up_switch = true;
   metadata->reference_lower_spatial_layers =
       frame_num_ == 0 && (spatial_idx_ != 0);
   metadata->temporal_idx = temp_temporal_layers_id;
@@ -399,13 +408,6 @@
         p_diff = temporal_pattern_size_;
       metadata->p_diffs.push_back(p_diff);
     }
-
-    const uint8_t ref_temporal_layers_id =
-        temporal_layers_reference_pattern_
-            [pattern_index_of_ref_frames_slots_[i] % temporal_pattern_size_]
-                .layer_index();
-    metadata->temporal_up_switch &=
-        (ref_temporal_layers_id != temp_temporal_layers_id);
   }
 }
 
diff --git a/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc b/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc
index e3d5f413..40b821143 100644
--- a/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc
+++ b/media/gpu/vaapi/vp9_vaapi_video_encoder_delegate_unittest.cc
@@ -152,6 +152,44 @@
   return bitrate_allocation;
 }
 
+VideoBitrateAllocation CreateBitrateAllocationWithActiveLayers(
+    const VideoBitrateAllocation& bitrate_allocation,
+    const std::vector<size_t>& active_layers) {
+  VideoBitrateAllocation new_bitrate_allocation;
+  for (size_t si : active_layers) {
+    for (size_t ti = 0; ti < VideoBitrateAllocation::kMaxTemporalLayers; ++ti) {
+      const int bps = bitrate_allocation.GetBitrateBps(si, ti);
+      new_bitrate_allocation.SetBitrate(si, ti, bps);
+    }
+  }
+
+  return new_bitrate_allocation;
+}
+
+VideoBitrateAllocation AdaptBitrateAllocation(
+    const VideoBitrateAllocation& bitrate_allocation) {
+  VideoBitrateAllocation new_bitrate_allocation;
+  size_t new_si = 0;
+  for (size_t si = 0; si < VideoBitrateAllocation::kMaxSpatialLayers; ++si) {
+    int sum = 0;
+    for (size_t ti = 0; ti < VideoBitrateAllocation::kMaxTemporalLayers; ++ti)
+      sum += bitrate_allocation.GetBitrateBps(si, ti);
+    if (sum == 0) {
+      // The spatial layer is disabled.
+      continue;
+    }
+
+    for (size_t ti = 0; ti < VideoBitrateAllocation::kMaxTemporalLayers; ++ti) {
+      const int bps = bitrate_allocation.GetBitrateBps(si, ti);
+      new_bitrate_allocation.SetBitrate(new_si, ti, bps);
+    }
+
+    new_si++;
+  }
+
+  return new_bitrate_allocation;
+}
+
 std::vector<gfx::Size> GetDefaultSpatialLayerResolutions(
     size_t num_spatial_layers) {
   constexpr gfx::Size& kDefaultSize =
@@ -182,7 +220,7 @@
   const size_t num_spatial_layers = spatial_layer_resolutions.size();
   for (size_t sid = 0; sid < num_spatial_layers; ++sid) {
     int bitrate_sum = 0;
-    for (size_t tid = 0; tid < num_temporal_layers; tid++) {
+    for (size_t tid = 0; tid < num_temporal_layers; ++tid) {
       size_t idx = sid * num_temporal_layers + tid;
       bitrate_sum += bitrate_allocation.GetBitrateBps(sid, tid);
       if (arg.layer_target_bitrate[idx] != bitrate_sum / 1000)
@@ -252,6 +290,8 @@
   MOCK_METHOD0(OnError, void());
 
  protected:
+  void ResetEncoder();
+
   void InitializeVP9VaapiVideoEncoderDelegate(size_t num_spatial_layers,
                                               size_t num_temporal_layers);
   void EncodeConstantQuantizationParameterSequence(
@@ -262,33 +302,38 @@
       uint8_t expected_temporal_layer_id,
       uint8_t expected_spatial_layer_id);
   void UpdateRatesTest(size_t num_spatial_layers, size_t num_temporal_layers);
+  void UpdateRatesAndEncode(
+      const VideoBitrateAllocation& bitrate_allocation,
+      uint32_t framerate,
+      bool valid_rates_request,
+      bool is_key_pic,
+      const std::vector<gfx::Size>& expected_spatial_layer_resolutions,
+      size_t expected_temporal_layers,
+      size_t expected_temporal_layer_id);
 
  private:
   std::unique_ptr<VaapiVideoEncoderDelegate::EncodeJob> CreateEncodeJob(
       bool keyframe,
       const scoped_refptr<VASurface>& va_surface,
       const scoped_refptr<VP9Picture>& picture);
-  void UpdateRatesAndEncode(
-      const VideoBitrateAllocation& bitrate_allocation,
-      uint32_t framerate,
-      bool is_key_pic,
-      const std::vector<gfx::Size>& expected_spatial_layer_resolutions,
-      size_t expected_temporal_layers,
-      size_t expected_temporal_layer_id);
 
   std::unique_ptr<VP9VaapiVideoEncoderDelegate> encoder_;
   scoped_refptr<MockVaapiWrapper> mock_vaapi_wrapper_;
   MockVP9RateControl* mock_rate_ctrl_ = nullptr;
 };
 
-void VP9VaapiVideoEncoderDelegateTest::SetUp() {
-  mock_vaapi_wrapper_ = base::MakeRefCounted<MockVaapiWrapper>();
-  ASSERT_TRUE(mock_vaapi_wrapper_);
-
+void VP9VaapiVideoEncoderDelegateTest::ResetEncoder() {
   encoder_ = std::make_unique<VP9VaapiVideoEncoderDelegate>(
       mock_vaapi_wrapper_,
       base::BindRepeating(&VP9VaapiVideoEncoderDelegateTest::OnError,
                           base::Unretained(this)));
+}
+
+void VP9VaapiVideoEncoderDelegateTest::SetUp() {
+  mock_vaapi_wrapper_ = base::MakeRefCounted<MockVaapiWrapper>();
+  ASSERT_TRUE(mock_vaapi_wrapper_);
+
+  ResetEncoder();
   EXPECT_CALL(*this, OnError()).Times(0);
 }
 
@@ -408,6 +453,7 @@
 void VP9VaapiVideoEncoderDelegateTest::UpdateRatesAndEncode(
     const VideoBitrateAllocation& bitrate_allocation,
     uint32_t framerate,
+    bool valid_rates_request,
     bool is_key_pic,
     const std::vector<gfx::Size>& expected_spatial_layer_resolutions,
     size_t expected_temporal_layers,
@@ -420,18 +466,29 @@
   EXPECT_TRUE(encoder_->UpdateRates(bitrate_allocation, framerate));
   EXPECT_TRUE(encoder_->pending_update_rates_.has_value());
 
-  EXPECT_CALL(*mock_rate_ctrl_,
-              UpdateRateControl(MatchRtcConfigWithRates(
-                  bitrate_allocation, framerate, expected_temporal_layers,
-                  expected_spatial_layer_resolutions)))
+  // The pending update rates request is applied in GetSVCLayerResolutions().
+  if (!valid_rates_request) {
+    EXPECT_TRUE(encoder_->GetSVCLayerResolutions().empty());
+    return;
+  }
+
+  // VideoBitrateAllocation is adapted if some spatial layers are deactivated.
+  const VideoBitrateAllocation adapted_bitrate_allocation =
+      AdaptBitrateAllocation(bitrate_allocation);
+
+  EXPECT_CALL(*mock_rate_ctrl_, UpdateRateControl(MatchRtcConfigWithRates(
+                                    adapted_bitrate_allocation, framerate,
+                                    expected_temporal_layers,
+                                    expected_spatial_layer_resolutions)))
       .Times(1)
       .WillOnce(Return());
 
-  // The pending update rates request is applied in GetSVCLayerResolutions().
   EXPECT_EQ(encoder_->GetSVCLayerResolutions(),
             expected_spatial_layer_resolutions);
 
-  EXPECT_EQ(encoder_->current_params_.bitrate_allocation, bitrate_allocation);
+  EXPECT_FALSE(encoder_->pending_update_rates_.has_value());
+  EXPECT_EQ(encoder_->current_params_.bitrate_allocation,
+            adapted_bitrate_allocation);
   EXPECT_EQ(encoder_->current_params_.framerate, framerate);
 
   const size_t num_spatial_layers = expected_spatial_layer_resolutions.size();
@@ -458,7 +515,8 @@
                                      uint32_t bitrate, uint32_t framerate) {
     auto bitrate_allocation = GetDefaultVideoBitrateAllocation(
         num_spatial_layers, num_temporal_layers, bitrate);
-    UpdateRatesAndEncode(bitrate_allocation, framerate, is_key_pic,
+    UpdateRatesAndEncode(bitrate_allocation, framerate,
+                         /*valid_rates_request=*/true, is_key_pic,
                          spatial_layer_resolutions, num_temporal_layers,
                          expected_temporal_layer_id);
   };
@@ -530,8 +588,8 @@
   constexpr size_t kKeyFrameInterval = 20;
   const std::vector<gfx::Size> layer_sizes =
       GetDefaultSpatialLayerResolutions(num_spatial_layers);
-  for (size_t j = 0; j < kNumKeyFrames; j++) {
-    for (size_t i = 0; i < kKeyFrameInterval; i++) {
+  for (size_t j = 0; j < kNumKeyFrames; ++j) {
+    for (size_t i = 0; i < kKeyFrameInterval; ++i) {
       for (size_t sid = 0; sid < num_spatial_layers; ++sid) {
         const bool keyframe = (i == 0 && sid == 0);
         std::array<bool, kVp9NumRefsPerFrame> ref_frames_used;
@@ -554,8 +612,139 @@
   UpdateRatesTest(num_spatial_layers, num_temporal_layers);
 }
 
-// TODO(crbug.com/1186051): Add the test case to activate and deactivate spatial
-// layers.
+TEST_P(VP9VaapiVideoEncoderDelegateTest, DeactivateActivateSpatialLayers) {
+  const size_t num_spatial_layers = GetParam().num_spatial_layers;
+  const size_t num_temporal_layers = GetParam().num_temporal_layers;
+  if (num_spatial_layers == 1)
+    GTEST_SKIP() << "Skip a single spatial layer";
+
+  InitializeVP9VaapiVideoEncoderDelegate(num_spatial_layers,
+                                         num_temporal_layers);
+
+  const std::vector<std::vector<size_t>> kActivateExercise[2] = {
+      {
+          // Two spatial layers.
+          {0},     // Deactivate the top layer.
+          {0, 1},  // Activate the top layer.
+          {1},     // Deactivate the bottom layer.
+          {0, 1},  // Activate the bottom layer.
+      },
+      {
+          // Three spatial layers.
+          {0, 1},  // Deactivate the top layer.
+          {1},     // Deactivate the bottom layer.
+          {0},  // Activate the bottom layer and deactivate the top two layers.
+          {1,
+           2},  // Activate the top two layers and deactivate the bottom layer.
+          {0, 1, 2},  // Activate the bottom layer.
+          {2},        // Deactivate the bottom two layers.
+          {0, 1, 2},  // Activate the bottom two layers.
+      },
+  };
+
+  const VideoBitrateAllocation kDefaultBitrateAllocation =
+      GetDefaultVideoBitrateAllocation(
+          num_spatial_layers, num_temporal_layers,
+          kDefaultVideoEncodeAcceleratorConfig.bitrate.target());
+  const std::vector<gfx::Size> kDefaultSpatialLayers =
+      GetDefaultSpatialLayerResolutions(num_spatial_layers);
+  const uint32_t kFramerate =
+      *kDefaultVideoEncodeAcceleratorConfig.initial_framerate;
+
+  for (auto& active_layers : kActivateExercise[num_spatial_layers - 2]) {
+    const VideoBitrateAllocation bitrate_allocation =
+        CreateBitrateAllocationWithActiveLayers(kDefaultBitrateAllocation,
+                                                active_layers);
+    std::vector<gfx::Size> spatial_layer_resolutions;
+    for (size_t active_sid : active_layers)
+      spatial_layer_resolutions.emplace_back(kDefaultSpatialLayers[active_sid]);
+
+    // Always is_key_pic=true and temporal_layer_id=0 because the active spatial
+    // layers are changed.
+    UpdateRatesAndEncode(bitrate_allocation, kFramerate,
+                         /*valid_rates_request=*/true,
+                         /*is_key_pic=*/true, spatial_layer_resolutions,
+                         num_temporal_layers,
+                         /*expected_temporal_layer_id=*/0u);
+  }
+}
+
+TEST_P(VP9VaapiVideoEncoderDelegateTest, FailsWithInvalidSpatialLayers) {
+  const size_t num_spatial_layers = GetParam().num_spatial_layers;
+  const size_t num_temporal_layers = GetParam().num_temporal_layers;
+  const VideoBitrateAllocation kDefaultBitrateAllocation =
+      GetDefaultVideoBitrateAllocation(
+          num_spatial_layers, num_temporal_layers,
+          kDefaultVideoEncodeAcceleratorConfig.bitrate.target());
+  std::vector<VideoBitrateAllocation> invalid_bitrate_allocations;
+  constexpr int kBitrate = 1234;
+  auto bitrate_allocation = kDefaultBitrateAllocation;
+  // Activate one more top spatial layer.
+  ASSERT_LE(num_spatial_layers + 1, VideoBitrateAllocation::kMaxSpatialLayers);
+  bitrate_allocation.SetBitrate(num_spatial_layers, /*temporal_index=*/0,
+                                kBitrate);
+  invalid_bitrate_allocations.push_back(bitrate_allocation);
+
+  // Deactivate a middle spatial layer.
+  if (num_spatial_layers == 3) {
+    bitrate_allocation = kDefaultBitrateAllocation;
+    for (size_t ti = 0; ti < VideoBitrateAllocation::kMaxTemporalLayers; ++ti)
+      bitrate_allocation.SetBitrate(1, ti, 0u);
+    invalid_bitrate_allocations.push_back(bitrate_allocation);
+  }
+
+  // Increase the number of temporal layers.
+  bitrate_allocation = kDefaultBitrateAllocation;
+  ASSERT_LE(num_temporal_layers + 1,
+            VideoBitrateAllocation::kMaxTemporalLayers);
+  for (size_t si = 0; si < num_spatial_layers; ++si)
+    bitrate_allocation.SetBitrate(si, num_temporal_layers, kBitrate);
+  invalid_bitrate_allocations.push_back(bitrate_allocation);
+
+  // Decrease the number of temporal layers.
+  if (num_temporal_layers > 1) {
+    bitrate_allocation = kDefaultBitrateAllocation;
+    for (size_t si = 0; si < num_spatial_layers; ++si)
+      bitrate_allocation.SetBitrate(si, num_temporal_layers - 1, 0u);
+    invalid_bitrate_allocations.push_back(bitrate_allocation);
+  }
+
+  // Set 0 in the bottom temporal layer.
+  if (num_temporal_layers > 1) {
+    bitrate_allocation = kDefaultBitrateAllocation;
+    bitrate_allocation.SetBitrate(/*spatial_index=*/0, /*temporal_index=*/0,
+                                  0u);
+    invalid_bitrate_allocations.push_back(bitrate_allocation);
+  }
+
+  // Set 0 in the middle temporal layer
+  if (num_temporal_layers == 3) {
+    bitrate_allocation = kDefaultBitrateAllocation;
+    bitrate_allocation.SetBitrate(/*spatial_index=*/0, /*temporal_index=*/1,
+                                  0u);
+    invalid_bitrate_allocations.push_back(bitrate_allocation);
+  }
+
+  const uint32_t kFramerate =
+      *kDefaultVideoEncodeAcceleratorConfig.initial_framerate;
+  for (const auto& bitrate_allocation : invalid_bitrate_allocations) {
+    InitializeVP9VaapiVideoEncoderDelegate(num_spatial_layers,
+                                           num_temporal_layers);
+
+    // The values of expected_spatial_layer_resolutions, is_key_pic,
+    // expected_temporal_layers and expected_temporal_layer_id are meaningless
+    // because UpdateRatesAndEncode will returns before checking them due to the
+    // invalid VideoBitrateAllocation request.
+    UpdateRatesAndEncode(bitrate_allocation, kFramerate,
+                         /*valid_rates_request=*/false,
+                         /*is_key_pic=*/true,
+                         /*expected_spatial_layer_resolutions=*/{},
+                         /*expected_temporal_layers=*/0u,
+                         /*expected_temporal_layer_id=*/0u);
+
+    ResetEncoder();
+  }
+}
 
 INSTANTIATE_TEST_SUITE_P(
     ,
diff --git a/net/tools/quic/quic_simple_server.cc b/net/tools/quic/quic_simple_server.cc
index f50b948..06bfde5 100644
--- a/net/tools/quic/quic_simple_server.cc
+++ b/net/tools/quic/quic_simple_server.cc
@@ -192,7 +192,10 @@
     // packet whose payload is larger than our receive buffer. Do not act on 0
     // as that indicates that we received a UDP packet with an empty payload.
     // In both cases, the socket should still be usable.
-    if (result != ERR_MSG_TOO_BIG && result != 0) {
+    // Also do not act on ERR_CONNECTION_RESET as this is happening when the
+    // network service restarts on Windows.
+    if (result != ERR_MSG_TOO_BIG && result != ERR_CONNECTION_RESET &&
+        result != 0) {
       Shutdown();
       return;
     }
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 411573b..d8b22af 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -10388,7 +10388,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M91",
-              "revision": "version:91.0.4472.160"
+              "revision": "version:91.0.4472.161"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -10474,7 +10474,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.96"
+              "revision": "version:92.0.4515.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -10646,7 +10646,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M91",
-              "revision": "version:91.0.4472.160"
+              "revision": "version:91.0.4472.161"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -10732,7 +10732,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.96"
+              "revision": "version:92.0.4515.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index a611eaac..14789dd8 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -53730,7 +53730,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M91",
-              "revision": "version:91.0.4472.160"
+              "revision": "version:91.0.4472.161"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -53817,7 +53817,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.96"
+              "revision": "version:92.0.4515.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -53991,7 +53991,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M91",
-              "revision": "version:91.0.4472.160"
+              "revision": "version:91.0.4472.161"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -54078,7 +54078,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.96"
+              "revision": "version:92.0.4515.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -54324,7 +54324,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M91",
-              "revision": "version:91.0.4472.160"
+              "revision": "version:91.0.4472.161"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -54410,7 +54410,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.96"
+              "revision": "version:92.0.4515.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -54582,7 +54582,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M91",
-              "revision": "version:91.0.4472.160"
+              "revision": "version:91.0.4472.161"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -54668,7 +54668,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.96"
+              "revision": "version:92.0.4515.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -54914,7 +54914,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M91",
-              "revision": "version:91.0.4472.160"
+              "revision": "version:91.0.4472.161"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -55000,7 +55000,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.96"
+              "revision": "version:92.0.4515.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -55172,7 +55172,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M91",
-              "revision": "version:91.0.4472.160"
+              "revision": "version:91.0.4472.161"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -55258,7 +55258,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.96"
+              "revision": "version:92.0.4515.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/filters/linux-lacros.browser_tests.filter b/testing/buildbot/filters/linux-lacros.browser_tests.filter
index 4b035bf..3fb03a1 100644
--- a/testing/buildbot/filters/linux-lacros.browser_tests.filter
+++ b/testing/buildbot/filters/linux-lacros.browser_tests.filter
@@ -6,8 +6,6 @@
 -AdsPageLoadMetricsObserverBrowserTest.PageAdDensityMultipleFrames
 -AdsPageLoadMetricsObserverBrowserTest.PageAdDensityRecordsPageMax
 -All/DownloadReferrerPolicyTest.SaveLinkAsReferrerPolicy*
-# TODO(https://crbug.com/1125474): Emphemeral guest profile support.
--All/GuestProfileMenuClickTest.ProfileMenuClickTest_*
 -All/HostedAppProcessModelTest.BackgroundPageWithAppCoveringDifferentSites/0
 -All/HostedOrWebAppTest.CtrlClickLink/HostedApp
 -All/HostedOrWebAppTest.CtrlClickLink/WebApp
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 7f7d5ba..380c9f7 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -416,7 +416,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M92',
-          'revision': 'version:92.0.4515.96',
+          'revision': 'version:92.0.4515.97',
         }
       ],
     },
@@ -440,7 +440,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M91',
-          'revision': 'version:91.0.4472.160',
+          'revision': 'version:91.0.4472.161',
         }
       ],
     },
@@ -488,7 +488,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M92',
-          'revision': 'version:92.0.4515.96',
+          'revision': 'version:92.0.4515.97',
         }
       ],
     },
@@ -512,7 +512,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M91',
-          'revision': 'version:91.0.4472.160',
+          'revision': 'version:91.0.4472.161',
         }
       ],
     },
@@ -560,7 +560,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M92',
-          'revision': 'version:92.0.4515.96',
+          'revision': 'version:92.0.4515.97',
         }
       ],
     },
@@ -584,7 +584,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M91',
-          'revision': 'version:91.0.4472.160',
+          'revision': 'version:91.0.4472.161',
         }
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 00faa34..bb04878 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1095,6 +1095,25 @@
             ]
         }
     ],
+    "AutofillIgnoreAutocompleteForImport": [
+        {
+            "platforms": [
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "AutofillIgnoreAutocompleteForImport"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillKeyboardAccessory": [
         {
             "platforms": [
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 976f062..241db85a 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -3050,6 +3050,8 @@
       optional array of integer parentIndex
       # `Node`'s nodeType.
       optional array of integer nodeType
+      # Type of the shadow root the `Node` is in. String values are equal to the `ShadowRootType` enum.
+      optional RareStringData shadowRootType
       # `Node`'s nodeName.
       optional array of StringIndex nodeName
       # `Node`'s nodeValue.
diff --git a/third_party/blink/renderer/core/clipboard/system_clipboard.cc b/third_party/blink/renderer/core/clipboard/system_clipboard.cc
index c1ccc7e6..fb8f46c 100644
--- a/third_party/blink/renderer/core/clipboard/system_clipboard.cc
+++ b/third_party/blink/renderer/core/clipboard/system_clipboard.cc
@@ -122,14 +122,15 @@
 #if defined(OS_WIN)
   ReplaceNewlinesWithWindowsStyleNewlines(text);
 #endif
-  clipboard_->WriteText(NonNullString(text));
+  if (clipboard_.is_bound())
+    clipboard_->WriteText(NonNullString(text));
 }
 
 String SystemClipboard::ReadHTML(KURL& url,
                                  unsigned& fragment_start,
                                  unsigned& fragment_end) {
   String html;
-  if (IsValidBufferType(buffer_)) {
+  if (IsValidBufferType(buffer_) && clipboard_.is_bound()) {
     clipboard_->ReadHtml(buffer_, &html, &url,
                          static_cast<uint32_t*>(&fragment_start),
                          static_cast<uint32_t*>(&fragment_end));
@@ -145,6 +146,8 @@
 void SystemClipboard::WriteHTML(const String& markup,
                                 const KURL& document_url,
                                 SmartReplaceOption smart_replace_option) {
+  if (!clipboard_.is_bound())
+    return;
   clipboard_->WriteHtml(NonNullString(markup), document_url);
   if (smart_replace_option == kCanSmartReplace)
     clipboard_->WriteSmartPasteMarker();
@@ -160,7 +163,8 @@
 }
 
 void SystemClipboard::WriteSvg(const String& markup) {
-  clipboard_->WriteSvg(NonNullString(markup));
+  if (clipboard_.is_bound())
+    clipboard_->WriteSvg(NonNullString(markup));
 }
 
 String SystemClipboard::ReadRTF() {
@@ -209,6 +213,8 @@
   SkBitmap bitmap;
   if (sk_sp<SkImage> sk_image = paint_image.GetSwSkImage())
     sk_image->asLegacyBitmap(&bitmap);
+  if (!clipboard_.is_bound())
+    return;
   // The bitmap backing a canvas can be in non-native skia pixel order (aka
   // RGBA when kN32_SkColorType is BGRA-ordered, or higher bit-depth color-types
   // like F16. The IPC to the browser requires the bitmap to be in N32 format
@@ -237,7 +243,8 @@
 }
 
 void SystemClipboard::WriteImage(const SkBitmap& bitmap) {
-  clipboard_->WriteImage(bitmap);
+  if (clipboard_.is_bound())
+    clipboard_->WriteImage(bitmap);
 }
 
 mojom::blink::ClipboardFilesPtr SystemClipboard::ReadFiles() {
@@ -258,6 +265,8 @@
 
 void SystemClipboard::WriteDataObject(DataObject* data_object) {
   DCHECK(data_object);
+  if (!clipboard_.is_bound())
+    return;
   // This plagiarizes the logic in DropDataBuilder::Build, but only extracts the
   // data needed for the implementation of WriteDataObject.
   //
@@ -268,7 +277,6 @@
   // TODO(slangley): Use a mojo struct to send web_drag_data and allow receiving
   // side to extract the data required.
   // TODO(dcheng): Properly support text/uri-list here.
-
   HashMap<String, String> custom_data;
   WebDragData data = data_object->ToWebDragData();
   for (const WebDragData::Item& item : data.Items()) {
@@ -288,12 +296,14 @@
 }
 
 void SystemClipboard::CommitWrite() {
-  clipboard_->CommitWrite();
+  if (clipboard_.is_bound())
+    clipboard_->CommitWrite();
 }
 
 void SystemClipboard::CopyToFindPboard(const String& text) {
 #if defined(OS_MAC)
-  clipboard_->WriteStringToFindPboard(text);
+  if (clipboard_.is_bound())
+    clipboard_->WriteStringToFindPboard(text);
 #endif
 }
 
diff --git a/third_party/blink/renderer/core/fetch/bytes_uploader.cc b/third_party/blink/renderer/core/fetch/bytes_uploader.cc
index eed6dde..38be3de 100644
--- a/third_party/blink/renderer/core/fetch/bytes_uploader.cc
+++ b/third_party/blink/renderer/core/fetch/bytes_uploader.cc
@@ -45,10 +45,10 @@
 void BytesUploader::StartReading(
     mojo::ScopedDataPipeProducerHandle upload_pipe) {
   DVLOG(3) << this << " StartReading()";
-  DCHECK(get_size_callback_);
   DCHECK(upload_pipe);
-  if (upload_pipe_) {
-    // Replay was asked by net/ service.
+  if (!get_size_callback_ || upload_pipe_) {
+    // When StartReading() is called while |upload_pipe_| is valid, it means
+    // replay was asked by the network service.
     CloseOnError();
     return;
   }
@@ -88,8 +88,6 @@
 void BytesUploader::WriteDataOnPipe() {
   DVLOG(3) << this << " WriteDataOnPipe(). consumer_->GetPublicState()="
            << consumer_->GetPublicState();
-  DCHECK(upload_pipe_);
-  DCHECK(get_size_callback_);
   if (!upload_pipe_.is_valid())
     return;
 
@@ -116,8 +114,7 @@
     const MojoResult mojo_result = upload_pipe_->WriteData(
         buffer, &written_bytes, MOJO_WRITE_DATA_FLAG_NONE);
     DVLOG(3) << "  upload_pipe_->WriteData()=" << mojo_result
-             << ", mojo_written=" << written_bytes
-             << ", consumer_->EndRead()=" << consumer_result;
+             << ", mojo_written=" << written_bytes;
     if (mojo_result == MOJO_RESULT_SHOULD_WAIT) {
       // Wait for the pipe to have more capacity available
       consumer_result = consumer_->EndRead(0);
@@ -130,6 +127,8 @@
     }
 
     consumer_result = consumer_->EndRead(written_bytes);
+    DVLOG(3) << "  consumer_->EndRead()=" << consumer_result;
+
     if (!base::CheckAdd(total_size_, written_bytes)
              .AssignIfValid(&total_size_)) {
       CloseOnError();
@@ -154,16 +153,16 @@
 
 void BytesUploader::Close() {
   DVLOG(3) << this << " Close(). total_size=" << total_size_;
-  DCHECK(get_size_callback_);
-  std::move(get_size_callback_).Run(net::OK, total_size_);
+  if (get_size_callback_)
+    std::move(get_size_callback_).Run(net::OK, total_size_);
   consumer_->Cancel();
   Dispose();
 }
 
 void BytesUploader::CloseOnError() {
   DVLOG(3) << this << " CloseOnError(). total_size=" << total_size_;
-  DCHECK(get_size_callback_);
-  std::move(get_size_callback_).Run(net::ERR_FAILED, total_size_);
+  if (get_size_callback_)
+    std::move(get_size_callback_).Run(net::ERR_FAILED, total_size_);
   consumer_->Cancel();
   Dispose();
 }
diff --git a/third_party/blink/renderer/core/fetch/bytes_uploader_test.cc b/third_party/blink/renderer/core/fetch/bytes_uploader_test.cc
index 88bc060..627c8e8 100644
--- a/third_party/blink/renderer/core/fetch/bytes_uploader_test.cc
+++ b/third_party/blink/renderer/core/fetch/bytes_uploader_test.cc
@@ -17,7 +17,10 @@
 using testing::_;
 using testing::InSequence;
 using testing::Invoke;
+using testing::NiceMock;
 using testing::Return;
+using testing::StrictMock;
+
 namespace blink {
 
 typedef testing::StrictMock<testing::MockFunction<void(int)>> Checkpoint;
@@ -32,20 +35,21 @@
   MOCK_METHOD1(SetClient, void(Client*));
   MOCK_METHOD0(ClearClient, void());
   MOCK_METHOD0(Cancel, void());
-  MOCK_CONST_METHOD0(GetPublicState, PublicState());
+  PublicState GetPublicState() const override { return state_; }
+  void SetPublicState(PublicState state) { state_ = state; }
   MOCK_CONST_METHOD0(GetError, Error());
   MOCK_CONST_METHOD0(DebugName, String());
+
+ private:
+  PublicState state_ = PublicState::kReadableOrWaiting;
 };
 
 class BytesUploaderTest : public ::testing::Test {
  public:
-  void InitializeBytesUploader(uint32_t capacity = 100u) {
-    mock_bytes_consumer_ = MakeGarbageCollected<MockBytesConsumer>();
-    EXPECT_CALL(*mock_bytes_consumer_, GetPublicState())
-        .WillRepeatedly(Return(BytesConsumer::PublicState::kReadableOrWaiting));
-
+  void InitializeBytesUploader(MockBytesConsumer* mock_bytes_consumer,
+                               uint32_t capacity = 100u) {
     bytes_uploader_ = MakeGarbageCollected<BytesUploader>(
-        mock_bytes_consumer_, remote_.BindNewPipeAndPassReceiver(),
+        mock_bytes_consumer, remote_.BindNewPipeAndPassReceiver(),
         Thread::Current()->GetTaskRunner());
 
     const MojoCreateDataPipeOptions data_pipe_options{
@@ -55,29 +59,27 @@
               mojo::CreateDataPipe(&data_pipe_options, writable_, readable_));
   }
 
-  MockBytesConsumer& Mock() const { return *mock_bytes_consumer_; }
   mojo::ScopedDataPipeProducerHandle& Writable() { return writable_; }
   mojo::ScopedDataPipeConsumerHandle& Readable() { return readable_; }
   mojo::Remote<ChunkedDataPipeGetter>& Remote() { return remote_; }
 
- private:
+ protected:
   Persistent<BytesUploader> bytes_uploader_;
-  Persistent<MockBytesConsumer> mock_bytes_consumer_;
 
+ private:
   mojo::ScopedDataPipeProducerHandle writable_;
   mojo::ScopedDataPipeConsumerHandle readable_;
   mojo::Remote<ChunkedDataPipeGetter> remote_;
 };
 
 TEST_F(BytesUploaderTest, Create) {
-  MockBytesConsumer* mock_bytes_consumer =
-      MakeGarbageCollected<MockBytesConsumer>();
+  auto* mock_bytes_consumer =
+      MakeGarbageCollected<StrictMock<MockBytesConsumer>>();
+
   Checkpoint checkpoint;
   {
     InSequence s;
     EXPECT_CALL(checkpoint, Call(1));
-    EXPECT_CALL(*mock_bytes_consumer, GetPublicState())
-        .WillRepeatedly(Return(BytesConsumer::PublicState::kReadableOrWaiting));
   }
 
   checkpoint.Call(1);
@@ -91,8 +93,8 @@
 // TODO(yoichio): Needs BytesConsumer state tests.
 
 TEST_F(BytesUploaderTest, ReadEmpty) {
-  InitializeBytesUploader();
-
+  auto* mock_bytes_consumer =
+      MakeGarbageCollected<StrictMock<MockBytesConsumer>>();
   base::MockCallback<ChunkedDataPipeGetter::GetSizeCallback> get_size_callback;
   Checkpoint checkpoint;
   {
@@ -100,18 +102,17 @@
 
     EXPECT_CALL(checkpoint, Call(1));
     EXPECT_CALL(checkpoint, Call(2));
-    EXPECT_CALL(Mock(), SetClient(_));
-    EXPECT_CALL(Mock(), GetPublicState())
-        .WillRepeatedly(Return(BytesConsumer::PublicState::kReadableOrWaiting));
-    EXPECT_CALL(Mock(), BeginRead(_, _))
+    EXPECT_CALL(*mock_bytes_consumer, SetClient(_));
+    EXPECT_CALL(*mock_bytes_consumer, BeginRead(_, _))
         .WillOnce(Return(BytesConsumer::Result::kDone));
-    EXPECT_CALL(Mock(), Cancel());
+    EXPECT_CALL(*mock_bytes_consumer, Cancel());
     EXPECT_CALL(get_size_callback, Run(net::OK, 0u));
 
     EXPECT_CALL(checkpoint, Call(3));
   }
 
   checkpoint.Call(1);
+  InitializeBytesUploader(mock_bytes_consumer);
   Remote()->GetSize(get_size_callback.Get());
   Remote()->StartReading(std::move(Writable()));
 
@@ -127,32 +128,31 @@
 }
 
 TEST_F(BytesUploaderTest, ReadSmall) {
-  InitializeBytesUploader();
-
+  auto* mock_bytes_consumer =
+      MakeGarbageCollected<StrictMock<MockBytesConsumer>>();
   base::MockCallback<ChunkedDataPipeGetter::GetSizeCallback> get_size_callback;
   Checkpoint checkpoint;
   {
     InSequence s;
     EXPECT_CALL(checkpoint, Call(1));
     EXPECT_CALL(checkpoint, Call(2));
-    EXPECT_CALL(Mock(), SetClient(_));
-    EXPECT_CALL(Mock(), GetPublicState())
-        .WillRepeatedly(Return(BytesConsumer::PublicState::kReadableOrWaiting));
-    EXPECT_CALL(Mock(), BeginRead(_, _))
+    EXPECT_CALL(*mock_bytes_consumer, SetClient(_));
+    EXPECT_CALL(*mock_bytes_consumer, BeginRead(_, _))
         .WillOnce(Invoke([](const char** buffer, size_t* size) {
           *size = 6;
           *buffer = "foobar";
           return BytesConsumer::Result::kOk;
         }));
-    EXPECT_CALL(Mock(), EndRead(6u))
+    EXPECT_CALL(*mock_bytes_consumer, EndRead(6u))
         .WillOnce(Return(BytesConsumer::Result::kDone));
-    EXPECT_CALL(Mock(), Cancel());
+    EXPECT_CALL(*mock_bytes_consumer, Cancel());
     EXPECT_CALL(get_size_callback, Run(net::OK, 6u));
 
     EXPECT_CALL(checkpoint, Call(3));
   }
 
   checkpoint.Call(1);
+  InitializeBytesUploader(mock_bytes_consumer);
   Remote()->GetSize(get_size_callback.Get());
   Remote()->StartReading(std::move(Writable()));
 
@@ -169,8 +169,8 @@
 }
 
 TEST_F(BytesUploaderTest, ReadOverPipeCapacity) {
-  InitializeBytesUploader(10u);
-
+  auto* mock_bytes_consumer =
+      MakeGarbageCollected<StrictMock<MockBytesConsumer>>();
   base::MockCallback<ChunkedDataPipeGetter::GetSizeCallback> get_size_callback;
   Checkpoint checkpoint;
   {
@@ -178,42 +178,41 @@
 
     EXPECT_CALL(checkpoint, Call(1));
     EXPECT_CALL(checkpoint, Call(2));
-    EXPECT_CALL(Mock(), SetClient(_));
-    EXPECT_CALL(Mock(), GetPublicState())
-        .WillRepeatedly(Return(BytesConsumer::PublicState::kReadableOrWaiting));
-    EXPECT_CALL(Mock(), BeginRead(_, _))
+    EXPECT_CALL(*mock_bytes_consumer, SetClient(_));
+    EXPECT_CALL(*mock_bytes_consumer, BeginRead(_, _))
         .WillOnce(Invoke([](const char** buffer, size_t* size) {
           *size = 12;
           *buffer = "foobarFOOBAR";
           return BytesConsumer::Result::kOk;
         }));
-    EXPECT_CALL(Mock(), EndRead(10u))
+    EXPECT_CALL(*mock_bytes_consumer, EndRead(10u))
         .WillOnce(Return(BytesConsumer::Result::kOk));
 
-    EXPECT_CALL(Mock(), BeginRead(_, _))
+    EXPECT_CALL(*mock_bytes_consumer, BeginRead(_, _))
         .WillOnce(Invoke([](const char** buffer, size_t* size) {
           *size = 2;
           *buffer = "AR";
           return BytesConsumer::Result::kOk;
         }));
-    EXPECT_CALL(Mock(), EndRead(0u))
+    EXPECT_CALL(*mock_bytes_consumer, EndRead(0u))
         .WillOnce(Return(BytesConsumer::Result::kOk));
 
     EXPECT_CALL(checkpoint, Call(3));
     EXPECT_CALL(checkpoint, Call(4));
-    EXPECT_CALL(Mock(), BeginRead(_, _))
+    EXPECT_CALL(*mock_bytes_consumer, BeginRead(_, _))
         .WillOnce(Invoke([](const char** buffer, size_t* size) {
           *size = 2;
           *buffer = "AR";
           return BytesConsumer::Result::kOk;
         }));
-    EXPECT_CALL(Mock(), EndRead(2u))
+    EXPECT_CALL(*mock_bytes_consumer, EndRead(2u))
         .WillOnce(Return(BytesConsumer::Result::kDone));
-    EXPECT_CALL(Mock(), Cancel());
+    EXPECT_CALL(*mock_bytes_consumer, Cancel());
     EXPECT_CALL(get_size_callback, Run(net::OK, 12u));
   }
 
   checkpoint.Call(1);
+  InitializeBytesUploader(mock_bytes_consumer, 10u);
   Remote()->GetSize(get_size_callback.Get());
   Remote()->StartReading(std::move(Writable()));
 
@@ -238,4 +237,15 @@
   EXPECT_STREQ("AR", buffer2);
 }
 
+TEST_F(BytesUploaderTest, StartReadingWithoutGetSize) {
+  auto* mock_bytes_consumer =
+      MakeGarbageCollected<NiceMock<MockBytesConsumer>>();
+  InitializeBytesUploader(mock_bytes_consumer);
+
+  Remote()->StartReading(std::move(Writable()));
+  test::RunPendingTasks();
+  // The operation is rejected, and the connection is shut down.
+  EXPECT_FALSE(Remote().is_connected());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 0794b49..45756c1 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -131,6 +131,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
 #include "third_party/blink/renderer/platform/scheduler/public/dummy_schedulers.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/storage/blink_storage_key.h"
 #include "third_party/blink/renderer/platform/timer.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/widget/frame_widget.h"
@@ -2114,4 +2115,8 @@
   return document_->UkmSourceID();
 }
 
+void LocalDOMWindow::SetStorageKey(const BlinkStorageKey& storage_key) {
+  storage_key_ = storage_key;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index b04965e..b37537b 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -47,6 +47,7 @@
 #include "third_party/blink/renderer/core/loader/frame_loader.h"
 #include "third_party/blink/renderer/core/scroll/scrollable_area.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/storage/blink_storage_key.h"
 #include "third_party/blink/renderer/platform/supplementable.h"
 #include "third_party/blink/renderer/platform/wtf/casting.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -431,6 +432,9 @@
   ukm::UkmRecorder* UkmRecorder() override;
   ukm::SourceId UkmSourceID() const override;
 
+  const BlinkStorageKey& GetStorageKey() const { return storage_key_; }
+  void SetStorageKey(const BlinkStorageKey& storage_key);
+
  protected:
   // EventTarget overrides.
   void AddedEventListener(const AtomicString& event_type,
@@ -548,6 +552,9 @@
   // this UKM is logged.
   // TODO(crbug.com/1112491): Remove when no longer needed.
   Deque<ukm::SourceId> post_message_ukm_recorded_source_ids_;
+
+  // The storage key for this LocalDomWindow.
+  BlinkStorageKey storage_key_;
 };
 
 template <>
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
index 656443e..0e74c56 100644
--- a/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.cc
@@ -399,6 +399,7 @@
                   .setParentIndex(std::make_unique<protocol::Array<int>>())
                   .setNodeType(std::make_unique<protocol::Array<int>>())
                   .setNodeName(std::make_unique<protocol::Array<int>>())
+                  .setShadowRootType(StringData())
                   .setNodeValue(std::make_unique<protocol::Array<int>>())
                   .setBackendNodeId(std::make_unique<protocol::Array<int>>())
                   .setAttributes(
@@ -501,6 +502,10 @@
       static_cast<int>(node->getNodeType()));
   nodes->getNodeName(nullptr)->emplace_back(AddString(node->nodeName()));
   nodes->getNodeValue(nullptr)->emplace_back(AddString(node_value));
+  if (node->IsInShadowTree()) {
+    SetRare(nodes->getShadowRootType(nullptr), index,
+            InspectorDOMAgent::GetShadowRootType(node->ContainingShadowRoot()));
+  }
   nodes->getBackendNodeId(nullptr)->emplace_back(
       IdentifiersFactory::IntIdForNode(node));
   nodes->getAttributes(nullptr)->emplace_back(
diff --git a/third_party/blink/renderer/core/layout/geometry/physical_rect.cc b/third_party/blink/renderer/core/layout/geometry/physical_rect.cc
index 3a749050..00a6001 100644
--- a/third_party/blink/renderer/core/layout/geometry/physical_rect.cc
+++ b/third_party/blink/renderer/core/layout/geometry/physical_rect.cc
@@ -27,6 +27,13 @@
   return distance;
 }
 
+LayoutUnit PhysicalRect::SquaredDistanceTo(const PhysicalOffset& point) const {
+  LayoutUnit diff_x =
+      point.left - clampTo<LayoutUnit>(point.left, X(), Right());
+  LayoutUnit diff_y = point.top - clampTo<LayoutUnit>(point.top, Y(), Bottom());
+  return diff_x * diff_x + diff_y * diff_y;
+}
+
 bool PhysicalRect::Contains(const PhysicalRect& other) const {
   return offset.left <= other.offset.left && offset.top <= other.offset.top &&
          Right() >= other.Right() && Bottom() >= other.Bottom();
diff --git a/third_party/blink/renderer/core/layout/geometry/physical_rect.h b/third_party/blink/renderer/core/layout/geometry/physical_rect.h
index 4679982..0ff388c 100644
--- a/third_party/blink/renderer/core/layout/geometry/physical_rect.h
+++ b/third_party/blink/renderer/core/layout/geometry/physical_rect.h
@@ -82,6 +82,10 @@
   // Each distance is zero if |this| contains |target| in that direction.
   PhysicalSize DistanceAsSize(PhysicalOffset target) const;
 
+  // Returns square of the distance from |point| to the closest edge of |this|.
+  // This function returns 0 if |this| contains |point|.
+  LayoutUnit SquaredDistanceTo(const PhysicalOffset& point) const;
+
   bool Contains(const PhysicalRect&) const;
   bool Contains(LayoutUnit px, LayoutUnit py) const {
     return px >= offset.left && px < Right() && py >= offset.top &&
diff --git a/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc b/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc
index 418bddc..b9bd748 100644
--- a/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc
+++ b/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc
@@ -66,6 +66,44 @@
   EXPECT_EQ(expected, actual);
 }
 
+TEST(PhysicalRectTest, SquaredDistanceTo) {
+  PhysicalRect rect(0, 0, 200, 200);
+  EXPECT_EQ(200, rect.SquaredDistanceTo(PhysicalOffset(-10, -10)))
+      << "over the top-left corner";
+  EXPECT_EQ(0, rect.SquaredDistanceTo(PhysicalOffset(0, 0)))
+      << "on the top-left corner";
+  EXPECT_EQ(100, rect.SquaredDistanceTo(PhysicalOffset(10, -10)))
+      << "over the top edge";
+  EXPECT_EQ(0, rect.SquaredDistanceTo(PhysicalOffset(10, 0)))
+      << "on the top edge";
+  EXPECT_EQ(200, rect.SquaredDistanceTo(PhysicalOffset(210, -10)))
+      << "over the top-right corner";
+  EXPECT_EQ(0, rect.SquaredDistanceTo(PhysicalOffset(200, 0)))
+      << "on the top-right corner";
+  EXPECT_EQ(100, rect.SquaredDistanceTo(PhysicalOffset(210, 10)))
+      << "over the right edge";
+  EXPECT_EQ(0, rect.SquaredDistanceTo(PhysicalOffset(200, 10)))
+      << "on the right edge";
+  EXPECT_EQ(200, rect.SquaredDistanceTo(PhysicalOffset(210, 210)))
+      << "over the bottom-right corner";
+  EXPECT_EQ(0, rect.SquaredDistanceTo(PhysicalOffset(200, 200)))
+      << "on the bottom-right corner";
+  EXPECT_EQ(10000, rect.SquaredDistanceTo(PhysicalOffset(100, 300)))
+      << "over the bottom edge";
+  EXPECT_EQ(0, rect.SquaredDistanceTo(PhysicalOffset(100, 200)))
+      << "on the bottom edge";
+  EXPECT_EQ(401, rect.SquaredDistanceTo(PhysicalOffset(-20, 201)))
+      << "over the bottom-left corner";
+  EXPECT_EQ(0, rect.SquaredDistanceTo(PhysicalOffset(0, 200)))
+      << "on the bottom-left corner";
+  EXPECT_EQ(9, rect.SquaredDistanceTo(PhysicalOffset(-3, 100)))
+      << "over the left edge";
+  EXPECT_EQ(0, rect.SquaredDistanceTo(PhysicalOffset(0, 3)))
+      << "on the left edge";
+
+  EXPECT_EQ(0, rect.SquaredDistanceTo(PhysicalOffset(10, 190))) << "contained";
+}
+
 TEST(PhysicalRectTest, InclusiveIntersect) {
   PhysicalRect rect(11, 12, 0, 0);
   EXPECT_TRUE(rect.InclusiveIntersect(PhysicalRect(11, 12, 13, 14)));
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index dbcbc108..5b04314 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -893,52 +893,25 @@
     const auto* const text_combine = DynamicTo<LayoutNGTextCombine>(Parent());
     const NGPhysicalBoxFragment* container_fragment = nullptr;
     PhysicalOffset point_in_container_fragment;
-    if (!IsSVGInlineText()) {
-      for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
-        DCHECK(&cursor.ContainerFragment());
-        if (container_fragment != &cursor.ContainerFragment()) {
-          container_fragment = &cursor.ContainerFragment();
+    DCHECK(!IsSVGInlineText());
+    for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
+      DCHECK(&cursor.ContainerFragment());
+      if (container_fragment != &cursor.ContainerFragment()) {
+        container_fragment = &cursor.ContainerFragment();
+        point_in_container_fragment =
+            point_in_contents - container_fragment->OffsetFromOwnerLayoutBox();
+        if (UNLIKELY(text_combine)) {
           point_in_container_fragment =
-              point_in_contents -
-              container_fragment->OffsetFromOwnerLayoutBox();
-          if (UNLIKELY(text_combine)) {
-            point_in_container_fragment = text_combine->AdjustOffsetForHitTest(
-                point_in_container_fragment);
-          }
-        }
-        if (!EnclosingIntRect(cursor.Current().RectInContainerFragment())
-                 .Contains(FlooredIntPoint(point_in_container_fragment)))
-          continue;
-        if (auto position_with_affinity =
-                cursor.PositionForPointInChild(point_in_container_fragment)) {
-          // Note: Due by Bidi adjustment, |position_with_affinity| isn't
-          // relative to this.
-          return AdjustForEditingBoundary(position_with_affinity);
+              text_combine->AdjustOffsetForHitTest(point_in_container_fragment);
         }
       }
-    } else {
-      NGInlineCursor last_hit_cursor;
-      for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
-        DCHECK(&cursor.ContainerFragment());
-        if (container_fragment != &cursor.ContainerFragment()) {
-          container_fragment = &cursor.ContainerFragment();
-          point_in_container_fragment =
-              point_in_contents -
-              container_fragment->OffsetFromOwnerLayoutBox();
-        }
-        point_in_container_fragment = cursor.CurrentItem()->MapPointInContainer(
-            point_in_container_fragment);
-        if (!cursor.Current().RectInContainerFragment().Contains(
-                point_in_container_fragment))
-          continue;
-        if (cursor.PositionForPointInChild(point_in_container_fragment))
-          last_hit_cursor = cursor;
-      }
-      if (last_hit_cursor) {
-        auto position_with_affinity = last_hit_cursor.PositionForPointInChild(
-            point_in_container_fragment);
-        // Note: Due by Bidi adjustment, |position_with_affinity| isn't relative
-        // to this.
+      if (!EnclosingIntRect(cursor.Current().RectInContainerFragment())
+               .Contains(FlooredIntPoint(point_in_container_fragment)))
+        continue;
+      if (auto position_with_affinity =
+              cursor.PositionForPointInChild(point_in_container_fragment)) {
+        // Note: Due by Bidi adjustment, |position_with_affinity| isn't
+        // relative to this.
         return AdjustForEditingBoundary(position_with_affinity);
       }
     }
diff --git a/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc
index 771d5a55..7f360b0 100644
--- a/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc
@@ -296,8 +296,9 @@
   GatherChildren(&base, &sub_sup_pairs, &prescripts, &first_prescript_index,
                  &container_builder_);
   ChildrenAndMetrics sub_metrics, sup_metrics;
+  ChildAndMetrics prescripts_metrics;
   if (prescripts)
-    LayoutAndGetMetrics(prescripts);
+    prescripts_metrics = LayoutAndGetMetrics(prescripts);
   for (auto sub_sup_pair : sub_sup_pairs) {
     if (sub_sup_pair.sub)
       sub_metrics.emplace_back(LayoutAndGetMetrics(sub_sup_pair.sub));
@@ -356,6 +357,14 @@
   container_builder_.AddChild(base_metrics.result->PhysicalFragment(),
                               base_offset);
   base.StoreMargins(ConstraintSpace(), base_metrics.margins);
+  if (prescripts) {
+    LogicalOffset prescripts_offset(inline_offset,
+                                    ascent - prescripts_metrics.ascent +
+                                        prescripts_metrics.margins.block_start);
+    container_builder_.AddChild(prescripts_metrics.result->PhysicalFragment(),
+                                prescripts_offset);
+    prescripts.StoreMargins(ConstraintSpace(), prescripts_metrics.margins);
+  }
   inline_offset += base_metrics.inline_size + base_metrics.margins.inline_end;
 
   // Position post scripts if needed.
diff --git a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc
index 821fa98..72c7bb8 100644
--- a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.cc
@@ -4,6 +4,9 @@
 
 #include "third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h"
 
+#include <limits>
+
+#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h"
@@ -182,6 +185,28 @@
              result, *local_location, accumulated_offset, action);
 }
 
+PositionWithAffinity LayoutNGSVGText::PositionForPoint(
+    const PhysicalOffset& point_in_contents) const {
+  NOT_DESTROYED();
+  FloatPoint point(point_in_contents.left, point_in_contents.top);
+  float min_distance = std::numeric_limits<float>::max();
+  const LayoutSVGInlineText* closest_inline_text = nullptr;
+  for (const LayoutObject* descendant = FirstChild(); descendant;
+       descendant = descendant->NextInPreOrder(this)) {
+    const auto* text = DynamicTo<LayoutSVGInlineText>(descendant);
+    if (!text)
+      continue;
+    float distance = descendant->ObjectBoundingBox().SquaredDistanceTo(point);
+    if (distance >= min_distance)
+      continue;
+    min_distance = distance;
+    closest_inline_text = text;
+  }
+  if (!closest_inline_text)
+    return CreatePositionWithAffinity(0);
+  return closest_inline_text->PositionForPoint(point_in_contents);
+}
+
 void LayoutNGSVGText::SetNeedsPositioningValuesUpdate() {
   NOT_DESTROYED();
   // We resolve text layout attributes in CollectInlines().
diff --git a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h
index cf17fcd..a9d75bf 100644
--- a/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h
+++ b/third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h
@@ -38,6 +38,8 @@
                    const HitTestLocation& hit_test_location,
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction action) override;
+  PositionWithAffinity PositionForPoint(
+      const PhysicalOffset& point_in_contents) const override;
 
   // LayoutBox override:
   bool CreatesNewFormattingContext() const override;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
index c8d546dc..4fa62afb 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
@@ -26,10 +26,13 @@
 #include "third_party/blink/renderer/core/css/css_font_selector.h"
 #include "third_party/blink/renderer/core/css/font_size_functions.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
+#include "third_party/blink/renderer/core/editing/editing_utilities.h"
 #include "third_party/blink/renderer/core/editing/position_with_affinity.h"
 #include "third_party/blink/renderer/core/editing/text_affinity.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
 #include "third_party/blink/renderer/core/layout/ng/svg/layout_ng_svg_text.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
 #include "third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h"
@@ -175,16 +178,59 @@
   return it->value.HasX() || it->value.HasY();
 }
 
+FloatRect LayoutSVGInlineText::ObjectBoundingBox() const {
+  NOT_DESTROYED();
+  if (!IsInLayoutNGInlineFormattingContext())
+    return FloatLinesBoundingBox();
+
+  FloatRect bounds;
+  NGInlineCursor cursor;
+  cursor.MoveTo(*this);
+  for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
+    const NGFragmentItem& item = *cursor.CurrentItem();
+    if (item.Type() == NGFragmentItem::kSvgText)
+      bounds.Unite(item.ObjectBoundingBox());
+  }
+  return bounds;
+}
+
 PositionWithAffinity LayoutSVGInlineText::PositionForPoint(
     const PhysicalOffset& point) const {
   NOT_DESTROYED();
   DCHECK_GE(GetDocument().Lifecycle().GetState(),
             DocumentLifecycle::kPrePaintClean);
 
-  if (IsInLayoutNGInlineFormattingContext())
-    return LayoutText::PositionForPoint(point);
-  // TODO(layout-dev): Remove this function entirely after eliminating the
-  // legacy layout.
+  if (IsInLayoutNGInlineFormattingContext()) {
+    NGInlineCursor cursor;
+    cursor.MoveTo(*this);
+    NGInlineCursor last_hit_cursor;
+    PhysicalOffset last_hit_transformed_point;
+    LayoutUnit closest_distance = LayoutUnit::Max();
+    for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
+      PhysicalOffset transformed_point =
+          cursor.CurrentItem()->MapPointInContainer(point);
+      PhysicalRect item_rect = cursor.Current().RectInContainerFragment();
+      LayoutUnit distance;
+      if (!item_rect.Contains(transformed_point) ||
+          !cursor.PositionForPointInChild(transformed_point))
+        distance = item_rect.SquaredDistanceTo(transformed_point);
+      // Intentionally apply '<=', not '<', because we'd like to choose a later
+      // item.
+      if (distance <= closest_distance) {
+        closest_distance = distance;
+        last_hit_cursor = cursor;
+        last_hit_transformed_point = transformed_point;
+      }
+    }
+    if (last_hit_cursor) {
+      auto position_with_affinity =
+          last_hit_cursor.PositionForPointInChild(last_hit_transformed_point);
+      // Note: Due by Bidi adjustment, |position_with_affinity| isn't relative
+      // to this.
+      return AdjustForEditingBoundary(position_with_affinity);
+    }
+    return CreatePositionWithAffinity(0);
+  }
 
   if (!HasInlineFragments() || !TextLength())
     return CreatePositionWithAffinity(0);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h
index da64906f..f190d9c 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h
@@ -70,6 +70,7 @@
     NOT_DESTROYED();
     return "LayoutSVGInlineText";
   }
+  PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
 
  private:
   void TextDidChange() override;
@@ -78,10 +79,7 @@
 
   void AddMetricsFromRun(const TextRun&, bool& last_character_was_white_space);
 
-  FloatRect ObjectBoundingBox() const override {
-    NOT_DESTROYED();
-    return FloatLinesBoundingBox();
-  }
+  FloatRect ObjectBoundingBox() const override;
 
   bool IsOfType(LayoutObjectType type) const override {
     NOT_DESTROYED();
@@ -89,7 +87,6 @@
            LayoutText::IsOfType(type);
   }
 
-  PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
   LayoutRect LocalCaretRect(
       const InlineBox*,
       int caret_offset,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index 11a4cb0..efd9c5f 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -465,8 +465,8 @@
 
   LayoutObject* layout_object = closest_descendant;
   AffineTransform transform = layout_object->LocalToSVGParentTransform();
-  transform.Translate(To<LayoutSVGText>(layout_object)->Location().X(),
-                      To<LayoutSVGText>(layout_object)->Location().Y());
+  transform.Translate(To<LayoutBox>(layout_object)->Location().X(),
+                      To<LayoutBox>(layout_object)->Location().Y());
   while (layout_object) {
     layout_object = layout_object->Parent();
     if (layout_object->IsSVGRoot())
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
index b3153f2..4d352bc 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
@@ -455,7 +455,7 @@
   // containers that could contain LayoutSVGTexts that are closer.
   for (LayoutObject* child = layout_object->SlowLastChild(); child;
        child = child->PreviousSibling()) {
-    if (child->IsSVGText()) {
+    if (child->IsSVGText() || child->IsNGSVGText()) {
       float distance = DistanceToChildLayoutObject(child, point);
       if (distance >= closest_text.distance)
         continue;
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.h b/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
index 428e485b..1625ee43 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
@@ -121,6 +121,7 @@
       const LayoutObject*);
   static float CalculateScreenFontSizeScalingFactor(const LayoutObject*);
 
+  // This returns a LayoutSVGText, a LayoutNGSVGText, or nullptr.
   static LayoutObject* FindClosestLayoutSVGText(const LayoutObject*,
                                                 const FloatPoint&);
 
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 497ea78..8404d319 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -119,6 +119,7 @@
 #include "third_party/blink/renderer/platform/network/network_utils.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
+#include "third_party/blink/renderer/platform/storage/blink_storage_key.h"
 #include "third_party/blink/renderer/platform/web_test_support.h"
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
@@ -2151,6 +2152,10 @@
 
   SecurityContext& security_context = frame_->DomWindow()->GetSecurityContext();
   security_context.SetSandboxFlags(sandbox_flags_);
+
+  // TODO(https://crbug.com/1224901): Send storage key with the commit params
+  // and use the storage key sent by the browser directly here.
+  frame_->DomWindow()->SetStorageKey(BlinkStorageKey(security_origin));
   // Conceptually, SecurityOrigin doesn't have to be initialized after sandbox
   // flags are applied, but there's a UseCounter in SetSecurityOrigin() that
   // wants to inspect sandbox flags.
diff --git a/third_party/blink/renderer/core/loader/document_loader_test.cc b/third_party/blink/renderer/core/loader/document_loader_test.cc
index 5d3a968..3228432 100644
--- a/third_party/blink/renderer/core/loader/document_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/document_loader_test.cc
@@ -24,6 +24,7 @@
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
 #include "third_party/blink/renderer/platform/loader/static_data_navigation_body_loader.h"
+#include "third_party/blink/renderer/platform/storage/blink_storage_key.h"
 #include "third_party/blink/renderer/platform/testing/histogram_tester.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
@@ -431,6 +432,26 @@
   EXPECT_FALSE(local_frame->GetDocument()->DeferredCompositorCommitIsAllowed());
 }
 
+TEST_F(DocumentLoaderTest, NavigationToAboutBlank) {
+  const KURL& requestor_url =
+      KURL(NullURL(), "https://subdomain.example.com/foo.html");
+  WebViewImpl* web_view_impl =
+      web_view_helper_.InitializeAndLoad("https://example.com/foo.html");
+
+  const KURL& about_blank_url = KURL(NullURL(), "about:blank");
+  std::unique_ptr<WebNavigationParams> params =
+      std::make_unique<WebNavigationParams>();
+  params->url = about_blank_url;
+  params->sandbox_flags = network::mojom::WebSandboxFlags::kNone;
+  params->requestor_origin = WebSecurityOrigin::Create(WebURL(requestor_url));
+  LocalFrame* local_frame =
+      To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
+  local_frame->Loader().CommitNavigation(std::move(params), nullptr);
+
+  EXPECT_EQ(BlinkStorageKey(SecurityOrigin::Create(requestor_url)),
+            local_frame->DomWindow()->GetStorageKey());
+}
+
 TEST_F(DocumentLoaderTest, SameOriginNavigation) {
   const KURL& requestor_url =
       KURL(NullURL(), "https://www.example.com/foo.html");
@@ -447,6 +468,8 @@
       To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
   local_frame->Loader().CommitNavigation(std::move(params), nullptr);
 
+  EXPECT_EQ(BlinkStorageKey(SecurityOrigin::Create(same_origin_url)),
+            local_frame->DomWindow()->GetStorageKey());
   EXPECT_TRUE(local_frame->Loader()
                   .GetDocumentLoader()
                   ->LastNavigationHadTrustedInitiator());
@@ -468,6 +491,8 @@
       To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
   local_frame->Loader().CommitNavigation(std::move(params), nullptr);
 
+  EXPECT_EQ(BlinkStorageKey(SecurityOrigin::Create(other_origin_url)),
+            local_frame->DomWindow()->GetStorageKey());
   EXPECT_FALSE(local_frame->Loader()
                    .GetDocumentLoader()
                    ->LastNavigationHadTrustedInitiator());
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
index 19fb1f30c..d0d49c6 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
@@ -5,6 +5,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "cc/layers/picture_layer.h"
+#include "cc/layers/recording_source.h"
 #include "cc/layers/surface_layer.h"
 #include "cc/trees/compositor_commit_data.h"
 #include "cc/trees/effect_node.h"
@@ -2359,4 +2360,37 @@
   remote_frame->Detach();
 }
 
+// While not required for correctness, it is important for performance that
+// snapped backgrounds use solid color layers which avoid tiling.
+TEST_P(CompositingSimTest, SolidColorLayersWithSnapping) {
+  InitializeWithHTML(R"HTML(
+      <!DOCTYPE html>
+      <style>
+        #snapDown {
+          width: 60.1px;
+          height: 100px;
+          will-change: opacity;
+          background: blue;
+        }
+        #snapUp {
+          width: 60.9px;
+          height: 100px;
+          will-change: opacity;
+          background: blue;
+        }
+      </style>
+      <div id="snapDown"></div>
+      <div id="snapUp"></div>
+  )HTML");
+
+  Compositor().BeginFrame();
+
+  auto* snap_down =
+      static_cast<const cc::PictureLayer*>(CcLayerByDOMElementId("snapDown"));
+  EXPECT_TRUE(snap_down->GetRecordingSourceForTesting()->is_solid_color());
+  auto* snap_up =
+      static_cast<const cc::PictureLayer*>(CcLayerByDOMElementId("snapUp"));
+  EXPECT_TRUE(snap_up->GetRecordingSourceForTesting()->is_solid_color());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
index d21438f..6e6e4ab 100644
--- a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -195,7 +195,7 @@
                                          IntRect(0, 0, 50, 100),
                                          PaintInvalidationReason::kGeometry},
                   RasterInvalidationInfo{object, object->DebugName(),
-                                         IntRect(0, 0, 101, 71),
+                                         IntRect(0, 0, 101, 70),
                                          PaintInvalidationReason::kGeometry}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 
@@ -208,7 +208,7 @@
                                          IntRect(0, 0, 50, 100),
                                          PaintInvalidationReason::kGeometry},
                   RasterInvalidationInfo{object, object->DebugName(),
-                                         IntRect(0, 0, 101, 71),
+                                         IntRect(0, 0, 101, 70),
                                          PaintInvalidationReason::kGeometry}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 }
@@ -230,7 +230,7 @@
                                          IntRect(0, 0, 100, 200),
                                          PaintInvalidationReason::kGeometry},
                   RasterInvalidationInfo{object, object->DebugName(),
-                                         IntRect(0, 0, 202, 142),
+                                         IntRect(0, 0, 202, 140),
                                          PaintInvalidationReason::kGeometry}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 
@@ -243,7 +243,7 @@
                                          IntRect(0, 0, 100, 200),
                                          PaintInvalidationReason::kGeometry},
                   RasterInvalidationInfo{object, object->DebugName(),
-                                         IntRect(0, 0, 202, 142),
+                                         IntRect(0, 0, 202, 140),
                                          PaintInvalidationReason::kGeometry}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 }
@@ -269,7 +269,7 @@
   UpdateAllLifecyclePhasesForTest();
   EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
               UnorderedElementsAre(RasterInvalidationInfo{
-                  object, object->DebugName(), IntRect(0, 0, 50, 100),
+                  object, object->DebugName(), IntRect(0, 1, 50, 99),
                   PaintInvalidationReason::kGeometry}));
   GetDocument().View()->SetTracksRasterInvalidations(false);
 }
diff --git a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
index c413d004..6dfc71c 100644
--- a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
+++ b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.cc
@@ -373,13 +373,13 @@
   return node;
 }
 
-SanitizerConfig* Sanitizer::config() const {
+SanitizerConfig* Sanitizer::getConfiguration() const {
   return SanitizerConfigCopy(config_dictionary_
                                  ? config_dictionary_.Get()
                                  : SanitizerConfigImpl::defaultConfig());
 }
 
-SanitizerConfig* Sanitizer::defaultConfig() {
+SanitizerConfig* Sanitizer::getDefaultConfiguration() {
   return SanitizerConfigCopy(SanitizerConfigImpl::defaultConfig());
 }
 
diff --git a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
index fe41344..77ba12f 100644
--- a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
+++ b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.h
@@ -49,8 +49,8 @@
                        const String& markup,
                        ExceptionState& exception_state);
 
-  SanitizerConfig* config() const;
-  static SanitizerConfig* defaultConfig();
+  SanitizerConfig* getConfiguration() const;
+  static SanitizerConfig* getDefaultConfiguration();
 
   // Implementation of ElementSanitizer::SetSanitizedHTML, so that we have
   // all the sanitizer logic in one place.
diff --git a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
index e2d4bd7..699ac7d 100644
--- a/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
+++ b/third_party/blink/renderer/modules/sanitizer_api/sanitizer.idl
@@ -17,7 +17,7 @@
   [MeasureAs=SanitizerAPIToString, CallWith=ScriptState, RaisesException] DOMString sanitizeToString(SanitizerInput input);
   [MeasureAs=SanitizerAPISanitizeFor, CallWith=ScriptState, RaisesException] Element? sanitizeFor(DOMString element, DOMString markup);
 
-  [MeasureAs=SanitizerAPIGetConfig] SanitizerConfig config();
-  [MeasureAs=SanitizerAPIGetDefaultConfig] static SanitizerConfig defaultConfig();
+  [MeasureAs=SanitizerAPIGetConfig] SanitizerConfig getConfiguration();
+  [MeasureAs=SanitizerAPIGetDefaultConfig] static SanitizerConfig getDefaultConfiguration();
 };
 
diff --git a/third_party/blink/renderer/platform/graphics/dark_mode_filter_helper.cc b/third_party/blink/renderer/platform/graphics/dark_mode_filter_helper.cc
index a101ba4..731f1e0 100644
--- a/third_party/blink/renderer/platform/graphics/dark_mode_filter_helper.cc
+++ b/third_party/blink/renderer/platform/graphics/dark_mode_filter_helper.cc
@@ -98,10 +98,8 @@
   if (!context->IsDarkModeEnabled())
     return;
 
-  // Gradient generated images should not be classified by SkPixmap and apply
-  // filter to all image inversion policies.
+  // Gradient generated images should not be classified by SkPixmap
   if (image->IsGradientGeneratedImage()) {
-    flags->setColorFilter(context->GetDarkModeFilter()->GetImageFilter());
     return;
   }
 
diff --git a/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc b/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
index 756ae7f..c0a6b4d 100644
--- a/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
@@ -207,4 +207,48 @@
   return false;
 }
 
+IntRect DrawingDisplayItem::TightenVisualRect(
+    const IntRect& visual_rect,
+    sk_sp<const PaintRecord>& record) {
+  DCHECK(ShouldTightenVisualRect(record));
+
+  const auto* op = record->GetFirstOp();
+  if (!op->IsPaintOpWithFlags())
+    return visual_rect;
+
+  const auto& flags = static_cast<const cc::PaintOpWithFlags*>(op)->flags;
+  // The following can cause the painted output to be outside the paint op rect.
+  if (flags.getStyle() != cc::PaintFlags::kFill_Style || flags.getLooper() ||
+      flags.getMaskFilter() || flags.getImageFilter() || flags.getShader()) {
+    return visual_rect;
+  }
+
+  // TODO(pdr): Consider using |PaintOp::GetBounds| which is a more complete
+  // implementation of the logic below.
+
+  IntRect item_rect;
+  switch (op->GetType()) {
+    case cc::PaintOpType::DrawRect:
+      item_rect =
+          EnclosingIntRect(static_cast<const cc::DrawRectOp*>(op)->rect);
+      break;
+    case cc::PaintOpType::DrawIRect:
+      item_rect = IntRect(static_cast<const cc::DrawIRectOp*>(op)->rect);
+      break;
+    case cc::PaintOpType::DrawRRect:
+      item_rect = EnclosingIntRect(
+          static_cast<const cc::DrawRRectOp*>(op)->rrect.rect());
+      break;
+    // TODO(pdr): Support image PaintOpTypes such as DrawImage{Rect}.
+    // TODO(pdr): Consider checking PaintOpType::DrawTextBlob too.
+    default:
+      return visual_rect;
+  }
+
+  // TODO(pdr): Enable this DCHECK which enforces that the original visual rect
+  // was correct and fully contains the recording.
+  // DCHECK(visual_rect.Contains(item_rect));
+  return item_rect;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h b/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h
index a2e17ab5..70dea862 100644
--- a/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h
+++ b/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h
@@ -57,6 +57,16 @@
 
   bool CalculateKnownToBeOpaque(const PaintRecord*) const;
 
+  // Improve the visual rect using the paint record. This can improve solid
+  // color analysis in cases when the painted content was snapped but the
+  // visual rect was not. Check |ShouldTightenVisualRect| before calling.
+  static IntRect TightenVisualRect(const IntRect& visual_rect,
+                                   sk_sp<const PaintRecord>& record);
+  static bool ShouldTightenVisualRect(sk_sp<const PaintRecord>& record) {
+    // We only have an optimization to tighten the visual rect for a single op.
+    return record && record->size() == 1;
+  }
+
   sk_sp<const PaintRecord> record_;
 };
 
@@ -68,7 +78,9 @@
                                               sk_sp<const PaintRecord> record)
     : DisplayItem(client,
                   type,
-                  visual_rect,
+                  UNLIKELY(ShouldTightenVisualRect(record))
+                      ? TightenVisualRect(visual_rect, record)
+                      : visual_rect,
                   /* draws_content*/ record && record->size()),
       record_(DrawsContent() ? std::move(record) : nullptr) {
   DCHECK(IsDrawing());
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 8f1dd339..63956b5 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1214,14 +1214,6 @@
 
 # ====== MathMLCore-only tests from here ======
 
-crbug.com/6606 external/wpt/mathml/presentation-markup/direction/direction-006.html [ Failure ]
-crbug.com/6606 external/wpt/mathml/presentation-markup/direction/direction-009.html [ Failure ]
-crbug.com/6606 external/wpt/mathml/presentation-markup/direction/direction.html [ Failure ]
-crbug.com/6606 external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html [ Failure ]
-crbug.com/6606 external/wpt/mathml/presentation-markup/mrow/legacy-mrow-like-elements-001.html [ Failure ]
-crbug.com/6606 external/wpt/mathml/presentation-markup/operators/mo-axis-height-1.html [ Failure ]
-crbug.com/6606 external/wpt/mathml/presentation-markup/scripts/cramped-001.html [ Failure ]
-
 # These tests fail because we don't support MathML ink metrics.
 crbug.com/1125137 external/wpt/mathml/presentation-markup/fractions/frac-parameters-gap-001.html [ Failure ]
 crbug.com/1125137 external/wpt/mathml/presentation-markup/fractions/frac-parameters-gap-002.html [ Failure ]
@@ -1238,6 +1230,7 @@
 crbug.com/1124298 external/wpt/mathml/presentation-markup/spaces/space-like-004.html [ Failure ]
 
 # These tests fail because we don't support MathML tables.
+crbug.com/1125111 external/wpt/mathml/presentation-markup/direction/direction-006.html [ Failure ]
 crbug.com/1125111 external/wpt/mathml/presentation-markup/tables/table-001.html [ Failure ]
 crbug.com/1125111 external/wpt/mathml/presentation-markup/tables/table-002.html [ Failure ]
 crbug.com/1125111 external/wpt/mathml/presentation-markup/tables/table-axis-height.html [ Failure ]
@@ -1252,6 +1245,7 @@
 # These tests fail because we don't parse math display values according to the spec.
 crbug.com/1127222 external/wpt/css/css-display/display-math-on-pseudo-elements-001.html [ Failure ]
 crbug.com/1127222 external/wpt/css/css-display/display-math-on-pseudo-elements-002.html [ Failure ]
+crbug.com/1127222 external/wpt/mathml/presentation-markup/mrow/legacy-mrow-like-elements-001.html [ Failure ]
 
 # This test fails on windows. It should really be made more reliable and take
 # into account fallback parameters.
@@ -4155,8 +4149,6 @@
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/custom/focus-ring.svg [ Failure ]
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/custom/focus-ring-text.svg [ Failure ]
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/custom/gradient-userSpaceOnUse-with-percentage.svg [ Pass Skip ]
-crbug.com/1179585 virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container.xhtml [ Failure ]
-crbug.com/1179585 virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-standalone.svg [ Failure ]
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/custom/svg-root-with-opacity.html [ Failure Pass ]
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/custom/text-match-highlight.html [ Failure ]
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/custom/transformed-outlines.svg [ Failure ]
@@ -4182,9 +4174,6 @@
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/text/getextentofchar-nonbmp.html [ Failure ]
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/text/non-invertible-matrix-text.svg [ Failure Pass ]
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/text/selection-background-color.xhtml [ Failure ]
-crbug.com/1179585 virtual/layout_ng_svg_text/svg/text/selection-dragging-outside-1.html [ Failure ]
-crbug.com/1179585 virtual/layout_ng_svg_text/svg/text/selection-dragging-outside-2.html [ Failure ]
-crbug.com/1179585 virtual/layout_ng_svg_text/svg/text/selection-dragging-outside-3.html [ Failure ]
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/text/selection-styles.xhtml [ Failure ]
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/text/surrogate-pair-attribute-positions.html [ Failure Pass ]
 crbug.com/1179585 virtual/layout_ng_svg_text/svg/text/text-decorations-in-scaled-pattern.svg [ Failure ]
@@ -4901,7 +4890,7 @@
 crbug.com/1207342 http/tests/devtools/console/worker-eval-contains-stack.js [ Pass Failure ]
 crbug.com/1207342 http/tests/devtools/console/nested-worker-eval-contains-stack.js [ Pass Failure ]
 crbug.com/1207342 http/tests/devtools/console/console-error-on-call-frame.js [ Pass Failure ]
-crbug.com/1207342 http/tests/devtools/console/console-context-selector.js [ Pass Failure ]
+crbug.com/1207342 crbug.com/1046784 http/tests/devtools/console/console-context-selector.js [ Pass Failure Timeout ]
 crbug.com/1207342 http/tests/devtools/indexeddb/live-update-indexeddb-content.js [ Pass Failure ]
 crbug.com/1207342 http/tests/devtools/compiler-source-mapping-debug.js [ Pass Failure ]
 crbug.com/1207342 http/tests/devtools/network/parse-form-data.js [ Pass Failure ]
@@ -4993,7 +4982,7 @@
 crbug.com/1207342 http/tests/inspector-protocol/cpu-profiler/record-cpu-profile-with-cpu-throttling.js [ Pass Failure ]
 crbug.com/1207342 http/tests/inspector-protocol/page/frameScheduledNavigation.js [ Pass Failure ]
 crbug.com/1207342 http/tests/devtools/persistence/persistence-external-change-breakpoints.js [ Pass Failure ]
-crbug.com/1207342 http/tests/devtools/sources/debugger-pause/debugger-pause-infinite-loop.js [ Pass Failure ]
+crbug.com/1207342 crbug.com/1135652 http/tests/devtools/sources/debugger-pause/debugger-pause-infinite-loop.js [ Pass Failure Timeout ]
 
 # Sheriff 2018-04-13
 crbug.com/833655 [ Linux ] media/controls/closed-captions-dynamic-update.html [ Skip ]
@@ -5888,8 +5877,6 @@
 
 crbug.com/1058888 [ Linux ] animations/animationworklet/peek-updated-composited-property-on-main.html [ Failure Pass ]
 
-crbug.com/1091665 [ Debug ] external/wpt/html/cross-origin-embedder-policy/reporting-navigation.https.html [ Failure Pass ]
-
 # [virtual/...]external/wpt/web-animation test flakes
 crbug.com/1064065 virtual/threaded/external/wpt/css/css-animations/event-dispatch.tentative.html [ Failure Pass ]
 
@@ -7309,3 +7296,7 @@
 
 # Sheriff 2021-07-07
 crbug.com/1227092 [ Win ] virtual/scroll-unification/fast/events/selection-autoscroll-borderbelt.html [ Failure Pass ]
+
+# Sheriff 2021-07-12
+crbug.com/1228149 virtual/shared_array_buffer_on_desktop/http/tests/devtools/sources/debugger-ui/debugger-inline-values.js [ Pass Timeout ]
+crbug.com/1228149 virtual/shared_array_buffer_on_desktop/http/tests/devtools/sources/debugger-ui/debugger-inline-values-frames.js [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting-navigation.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting-navigation.https.html
index ab274be..dea8947 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting-navigation.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting-navigation.https.html
@@ -5,6 +5,7 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/common/get-host-info.sub.js"></script>
+<script src="./credentialless/resources/common.js"></script>
 <script>
 const {ORIGIN, REMOTE_ORIGIN} = get_host_info();
 const COEP = '|header(cross-origin-embedder-policy,require-corp)';
@@ -67,16 +68,25 @@
   return parent;
 }
 
-async function observeReports(global) {
+async function observeReports(global, expected_count) {
   const reports = [];
-  const observer = new global.ReportingObserver((rs) => {
-    for (const r of rs) {
-      reports.push(r.toJSON());
-    }
-  });
-  observer.observe();
+  const receivedEveryReports = new Promise(resolve => {
+    if (expected_count == 0)
+      resolve();
 
-  // Wait 5000ms for reports to settle.
+    const observer = new global.ReportingObserver((rs) => {
+      for (const r of rs) {
+        reports.push(r.toJSON());
+      }
+      if (expected_count <= reports.length)
+        resolve();
+    });
+    observer.observe();
+
+  });
+
+  // Wait 5000 ms more to catch additionnal unexpected reports.
+  await receivedEveryReports;
   await new Promise(r => step_timeout(r, 5000));
   return reports;
 }
@@ -125,30 +135,31 @@
       loadFrames(t, testcase.parent, withEmptyFrame, targetUrl)
           .then(t.step_func(parent => {
         const contextUrl = parent.src ? parent.src : 'about:blank';
-        observeReports(parent.contentWindow).then(t.step_func(reports => {
-          assert_equals(reports.length, testcase.reports.length);
-          for (let i = 0; i < reports.length; i += 1) {
-            const report = reports[i];
-            switch (testcase.reports[i]) {
-              case 'CORP':
-                checkCorpReport(report, contextUrl, targetUrl, 'enforce');
-                break;
-              case 'CORP-RO':
-                checkCorpReport(report, contextUrl, targetUrl, 'reporting');
-                break;
-              case 'NAV':
-                checkCoepMismatchReport(report, contextUrl, targetUrl, 'enforce');
-                break;
-              case 'NAV-RO':
-                checkCoepMismatchReport(report, contextUrl, targetUrl, 'reporting');
-                break;
-              default:
-                assert_unreached(
-                  'Unexpected report expeaction: ' + testcase.reports[i]);
+        observeReports(parent.contentWindow, testcase.reports.length)
+          .then(t.step_func(reports => {
+            assert_equals(reports.length, testcase.reports.length);
+            for (let i = 0; i < reports.length; i += 1) {
+              const report = reports[i];
+              switch (testcase.reports[i]) {
+                case 'CORP':
+                  checkCorpReport(report, contextUrl, targetUrl, 'enforce');
+                  break;
+                case 'CORP-RO':
+                  checkCorpReport(report, contextUrl, targetUrl, 'reporting');
+                  break;
+                case 'NAV':
+                  checkCoepMismatchReport(report, contextUrl, targetUrl, 'enforce');
+                  break;
+                case 'NAV-RO':
+                  checkCoepMismatchReport(report, contextUrl, targetUrl, 'reporting');
+                  break;
+                default:
+                  assert_unreached(
+                    'Unexpected report expeaction: ' + testcase.reports[i]);
+              }
             }
-          }
-          t.done();
-        })).catch(t.step_func(e => { throw e; }));
+            t.done();
+          })).catch(t.step_func(e => { throw e; }));
       })).catch(t.step_func(e => { throw e; }));
     }, `parent: ${desc(testcase.parent)}, target: ${desc(testcase.target)}, ` +
        `with empty frame: ${withEmptyFrame}`);
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting-subresource-corp.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting-subresource-corp.https.html
index 9bcf37b..e56124a 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting-subresource-corp.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-embedder-policy/reporting-subresource-corp.https.html
@@ -20,8 +20,27 @@
   '?pipe=header(cross-origin-embedder-policy,require-corp)' +
   `|header(cross-origin-embedder-policy-report-only,require-corp)`;
 
-function wait(ms) {
-  return new Promise(resolve => step_timeout(resolve, ms));
+async function observeReports(global, expected_count) {
+  const reports = [];
+  const receivedEveryReports = new Promise(resolve => {
+    if (expected_count == 0)
+      resolve();
+
+    const observer = new global.ReportingObserver((rs) => {
+      for (const r of rs) {
+        reports.push(r.toJSON());
+      }
+      if (expected_count <= reports.length)
+        resolve();
+    });
+    observer.observe();
+
+  });
+
+  await receivedEveryReports;
+  // Wait 500ms more to catch additionnal unexpected reports.
+  await new Promise(r => step_timeout(r, 500));
+  return reports;
 }
 
 function checkReport(report, contextUrl, blockedUrl, disposition, destination) {
@@ -33,23 +52,15 @@
   assert_equals(report.body.destination, destination);
 }
 
-async function fetchInFrame(t, frameUrl, url) {
-  const reports = [];
+async function fetchInFrame(t, frameUrl, url, expected_count) {
   const frame = await with_iframe(frameUrl);
   t.add_cleanup(() => frame.remove());
 
-  const observer = new frame.contentWindow.ReportingObserver((rs) => {
-    for (const report of rs) {
-      reports.push(report.toJSON());
-    }
-  });
-  observer.observe();
   const init = { mode: 'no-cors', cache: 'no-store' };
+  let future_reports = observeReports(frame.contentWindow, expected_count);
   await frame.contentWindow.fetch(url, init).catch(() => {});
 
-  // Wait 200ms for reports to settle.
-  await wait(200);
-  return reports;
+  return await future_reports;
 }
 
 async function fetchInWorker(workerOrPort, url) {
@@ -84,13 +95,13 @@
 const ENVIRONMENTS = [{
   tag: 'document',
   contextUrl: FRAME_URL,
-  run: async (test, url) => {
-    return await fetchInFrame(test, FRAME_URL, url);
+  run: async (test, url, expected_count) => {
+    return await fetchInFrame(test, FRAME_URL, url, expected_count);
   },
 }, {
   tag: 'dedicated worker',
   contextUrl: WORKER_URL,
-  run: async (test, url) => {
+  run: async (test, url, expected_count) => {
     const worker = new Worker(WORKER_URL);
     worker.addEventListener('error', test.unreached_func('Worker.onerror'));
     test.add_cleanup(() => worker.terminate());
@@ -99,7 +110,7 @@
 }, {
   tag: 'shared worker',
   contextUrl: WORKER_URL,
-  run: async (test, url) => {
+  run: async (test, url, expected_count) => {
     const worker = new SharedWorker(WORKER_URL);
     worker.addEventListener('error', test.unreached_func('Worker.onerror'));
     return await fetchInWorker(worker.port, url);
@@ -107,7 +118,7 @@
 }, {
   tag: 'service worker',
   contextUrl: WORKER_URL,
-  run: async (test, url) => {
+  run: async (test, url, expected_count) => {
     // As we don't want the service worker to control any page, generate a
     // one-time scope.
     const SCOPE = new URL(`resources/${token()}.html`, location).pathname;
@@ -121,7 +132,7 @@
 }, {
   tag: 'between service worker and page',
   contextUrl: REPORTING_FRAME_URL,
-  run: async (test, url) => {
+  run: async (test, url, expected_count) => {
     // Here we use a Service Worker without COEP.
     const WORKER_URL = `${ORIGIN}${BASE}/sw.js`;
     const reg = await service_worker_unregister_and_register(
@@ -130,36 +141,34 @@
     const worker = reg.installing || reg.waiting || reg.active;
     worker.addEventListener('error', test.unreached_func('Worker.onerror'));
     return await fetchInFrame(
-      test, REPORTING_FRAME_URL, url);
+      test, REPORTING_FRAME_URL, url, expected_count);
   },
 }];
 
 const CASES = [{
   name: 'same-origin',
   url: '/common/text-plain.txt',
-  check: (reports, url, contextUrl) => {
-    assert_equals(reports.length, 0);
-  }
+  expected_count: 0,
+  check: (reports, url, contextUrl) => {}
 }, {
   name: 'blocked by CORP: same-origin',
   url: `${REMOTE_ORIGIN}${BASE}/nothing-same-origin-corp.txt`,
-  check: (reports, url, contextUrl) => {
-    assert_equals(reports.length, 0);
-  }
+  expected_count: 0,
+  check: (reports, url, contextUrl) => {}
 }, {
   name: 'blocked due to COEP',
   url: `${REMOTE_ORIGIN}/common/text-plain.txt`,
+  expected_count: 2,
   check: (reports, contextUrl, url) => {
-    assert_equals(reports.length, 2);
     checkReport(reports[0], contextUrl, url, 'reporting', '');
     checkReport(reports[1], contextUrl, url, 'enforce', '');
   }
 }, {
   name: 'blocked during redirect',
   url: `${ORIGIN}/common/redirect.py?location=` +
-       encodeURIComponent(`${REMOTE_ORIGIN}/common/text-plain.txt`),
+    encodeURIComponent(`${REMOTE_ORIGIN}/common/text-plain.txt`),
+   expected_count: 2,
   check: (reports, contextUrl, url) => {
-    assert_equals(reports.length, 2);
     checkReport(reports[0], contextUrl, url, 'reporting', '');
     checkReport(reports[1], contextUrl, url, 'enforce', '');
   },
@@ -168,8 +177,10 @@
 for (const env of ENVIRONMENTS) {
   for (const testcase of CASES) {
     promise_test(async (t) => {
-      const reports = await env.run(t, testcase.url);
+      const reports = await env.run(
+        t, testcase.url, testcase.expected_count);
 
+      assert_equals(reports.length, testcase.expected_count);
       testcase.check(reports, env.contextUrl, testcase.url);
     }, `[${env.tag}] ${testcase.name}`);
   }
@@ -177,24 +188,16 @@
 
 // A test for a non-empty destination.
 promise_test(async (t) => {
-  const reports = [];
   const frame = await with_iframe(FRAME_URL);
   t.add_cleanup(() => frame.remove());
 
-  const observer = new frame.contentWindow.ReportingObserver((rs) => {
-    for (const report of rs) {
-      reports.push(report.toJSON());
-    }
-  });
-  observer.observe();
   const url = `${REMOTE_ORIGIN}/common/utils.js`;
   const script = frame.contentDocument.createElement('script');
   script.src = url;
+  const future_reports = observeReports(frame.contentWindow, 2);
   frame.contentDocument.body.appendChild(script);
 
-  // Wait 200ms for reports to settle.
-  await wait(200);
-
+  const reports = await future_reports;
   assert_equals(reports.length, 2);
   checkReport(reports[0], FRAME_URL, url, 'reporting', 'script');
   checkReport(reports[1], FRAME_URL, url, 'enforce', 'script');
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-expected.txt
new file mode 100644
index 0000000..ca57d09
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/direction/direction-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Check direction assert_equals: expected "ltr" but got "rtl"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy-expected.txt
new file mode 100644
index 0000000..dbcd828
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy-expected.txt
@@ -0,0 +1,12 @@
+This is a testharness.js-based test.
+FAIL operator stretching inside Mrow assert_greater_than_equal: expected a number greater than or equal to 100 but got 11
+FAIL operator stretching inside Sqrt assert_greater_than_equal: expected a number greater than or equal to 100 but got 11
+FAIL operator stretching inside Style assert_greater_than_equal: expected a number greater than or equal to 100 but got 11
+FAIL operator stretching inside Error assert_greater_than_equal: expected a number greater than or equal to 100 but got 11
+FAIL operator stretching inside Phantom assert_greater_than_equal: expected a number greater than or equal to 100 but got 11
+FAIL operator stretching inside Math assert_greater_than_equal: expected a number greater than or equal to 100 but got 11
+FAIL operator stretching inside Menclose assert_greater_than_equal: expected a number greater than or equal to 100 but got 11
+FAIL operator stretching inside Mpadded assert_greater_than_equal: expected a number greater than or equal to 100 but got 11
+FAIL operator stretching inside Unknown assert_greater_than_equal: expected a number greater than or equal to 100 but got 11
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/mo-axis-height-1-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/mo-axis-height-1-expected.txt
new file mode 100644
index 0000000..2ed9275
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/mo-axis-height-1-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL AxisHeight (size variant) assert_approx_equals: mo: size expected 140 +/- 5 but got 11
+FAIL AxisHeight (glyph assembly) assert_approx_equals: mo: size expected 300 +/- 5 but got 11
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/cramped-001-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/cramped-001-expected.txt
new file mode 100644
index 0000000..ce7faae
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/cramped-001-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS child of non-cramped element
+PASS child of cramped element
+PASS child of msqrt
+PASS child of mroot
+PASS child of mfrac
+FAIL child of msub assert_greater_than: subscript should be cramped expected a number greater than 25 but got 20
+PASS child of msup
+FAIL child of msubsup assert_greater_than: subscript should be cramped expected a number greater than 25 but got 20
+FAIL child of munder assert_less_than: underscript should not be cramped expected a number less than 25 but got 49.984375
+PASS child of mover (non-accent overscript)
+FAIL child of munderover (non-accent overscript) assert_less_than: underscript should not be cramped expected a number less than 25 but got 49.984375
+PASS accent child of mover (accent overscript)
+FAIL accent child of munderover (accent overscript) assert_less_than: underscript should not be cramped expected a number less than 25 but got 49.984375
+FAIL mmultiscripts assert_greater_than: post-subscript should be cramped expected a number greater than 25 but got 20
+PASS element with specified CSS math-style
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-6.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-6.html
new file mode 100644
index 0000000..9666c80f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-6.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mprescripts</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<meta name="assert" content="Position and size of mprescripts in mmultiscript element.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+  math, mspace {
+    font: 25px/1 Ahem;
+  }
+</style>
+<script>
+  /* This test does not use a font with a MATH table and does not verify layout
+     rules in a very strict way. */
+
+  setup({ explicit_done: true });
+  window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+  function runTests() {
+      Array.from(document.getElementsByTagName("mprescripts")).
+          forEach(prescript => {
+              let prescript_box = prescript.getBoundingClientRect();
+              let mmultiscripts = prescript.parentNode;
+              let name = mmultiscripts.getAttribute("data-name");
+              test(function() {
+                  assert_true(MathMLFeatureDetection.has_mspace());
+                  var e = 1;
+                  let base_box = mmultiscripts.firstElementChild.getBoundingClientRect();
+                  assert_approx_equals(prescript_box.left, base_box.left, e, `${name}, left`);
+                  assert_approx_equals((prescript_box.top + prescript_box.bottom) / 2, (base_box.top + base_box.bottom) / 2, e, `${name}, top`);
+
+                  if (name == "prescripts with padding/border/margin") {
+                      assert_approx_equals(prescript_box.width, 2*(15 + 25), e, `${name}, width`);
+                      assert_approx_equals(prescript_box.height, 2*(10 + 20), e, `${name}, height`);
+                  } else {
+                      assert_approx_equals(prescript_box.width, 0, e, `${name}, width`);
+                      assert_approx_equals(prescript_box.height, 0, e, `${name}, height`);
+                  }
+              }, `mprescripts coordinates and sizes (${name})`);
+          });
+
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+  <p>
+    <math>
+      <mmultiscripts data-name="2 postscripts">
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mprescripts/>
+      </mmultiscripts>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mmultiscripts data-name="2 prescripts">
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mprescripts/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+      </mmultiscripts>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mmultiscripts data-name="2 prescripts, 4 postscripts">
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mprescripts/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+      </mmultiscripts>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mmultiscripts data-name="4 prescripts, 2 postscripts">
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mprescripts/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+      </mmultiscripts>
+    </math>
+  </p>
+  <p>
+    <math>
+      <mmultiscripts data-name="prescripts with padding/border/margin">
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mprescripts style="background: blue;
+                            padding-top: 10px; border-top: 20px solid green;
+                            padding-bottom: 10px; border-bottom: 20px solid green;
+                            padding-left: 15px; border-left: 25px solid green;
+                            padding-right: 15px; border-right: 25px solid green;
+                            margin-top: 50px;"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+        <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+      </mmultiscripts>
+    </math>
+  </p>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/block-shift-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/block-shift-repaint-expected.txt
index 9aeadae..af3658bf 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/block-shift-repaint-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/block-shift-repaint-expected.txt
@@ -6,8 +6,6 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 353, 60, 38],
-        [8, 338, 60, 38],
         [8, 248, 60, 30],
         [8, 218, 60, 30],
         [8, 188, 60, 30],
@@ -16,7 +14,9 @@
         [8, 98, 60, 30],
         [8, 68, 60, 30],
         [8, 38, 60, 30],
-        [8, 8, 60, 30]
+        [8, 8, 60, 30],
+        [8, 353, 60, 8],
+        [8, 338, 60, 8]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
index 683ddc2..02a3d82 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -16,11 +16,11 @@
     {
       "name": "LayoutNGBlockFlow (positioned) DIV",
       "position": [50, 50],
-      "bounds": [251, 251],
+      "bounds": [250, 250],
       "contentsOpaqueForText": true,
       "backgroundColor": "#FF0000",
       "invalidations": [
-        [50, 50, 201, 201]
+        [50, 50, 200, 200]
       ]
     }
   ],
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/subpixel-offset-scaled-transform-composited-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/subpixel-offset-scaled-transform-composited-expected.txt
index 94a303f0..134708a 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/subpixel-offset-scaled-transform-composited-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/subpixel-offset-scaled-transform-composited-expected.txt
@@ -8,8 +8,8 @@
     },
     {
       "name": "LayoutNGBlockFlow (relative positioned) DIV id='child1' class='child composited'",
-      "bounds": [2, 1],
-      "contentsOpaqueForText": true,
+      "bounds": [1, 1],
+      "contentsOpaque": true,
       "backgroundColor": "#0000FF",
       "transform": 2
     },
@@ -22,8 +22,8 @@
     },
     {
       "name": "LayoutNGBlockFlow (relative positioned) DIV id='child3' class='child'",
-      "bounds": [2, 1],
-      "contentsOpaqueForText": true,
+      "bounds": [1, 1],
+      "contentsOpaque": true,
       "backgroundColor": "#0000FF",
       "transform": 6
     },
@@ -36,8 +36,8 @@
     },
     {
       "name": "LayoutNGBlockFlow (relative positioned) DIV id='child5' class='child composited'",
-      "bounds": [2, 1],
-      "contentsOpaqueForText": true,
+      "bounds": [1, 1],
+      "contentsOpaque": true,
       "backgroundColor": "#0000FF",
       "transform": 11
     },
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/subpixel-offset-scaled-will-change-transform-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/subpixel-offset-scaled-will-change-transform-expected.txt
index 3181759..79c74cf 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/subpixel-offset-scaled-will-change-transform-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/compositing/subpixel-offset-scaled-will-change-transform-expected.txt
@@ -22,8 +22,8 @@
     },
     {
       "name": "LayoutNGBlockFlow (relative positioned) DIV id='child3' class='child'",
-      "bounds": [2, 1],
-      "contentsOpaqueForText": true,
+      "bounds": [1, 1],
+      "contentsOpaque": true,
       "backgroundColor": "#0000FF",
       "transform": 6
     },
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/flexbox/repaint-expected.txt
index 698c8f9..cdb6e55 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/flexbox/repaint-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/flexbox/repaint-expected.txt
@@ -6,7 +6,8 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [138, 128, 654, 100],
+        [139, 128, 653, 100],
+        [138, 128, 636, 99],
         [400, 128, 392, 180],
         [8, 228, 392, 80],
         [148, 128, 252, 180],
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/flexbox/repaint-rtl-column-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
index 4738c15..a029c79 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
@@ -8,9 +8,9 @@
       "invalidations": [
         [8, 116, 200, 252],
         [8, 68, 200, 145],
-        [13, 124, 190, 351],
-        [13, 121, 190, 351],
-        [13, 218, 190, 350]
+        [13, 218, 190, 350],
+        [13, 125, 190, 350],
+        [13, 121, 190, 350]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/iframe-rounding-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/iframe-rounding-expected.txt
index 7c92f08e..7228a4ce88 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/iframe-rounding-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/iframe-rounding-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [19, 18, 101, 100]
+        [20, 18, 100, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-10-expected.txt
index 00576589f..4671413 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-10-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -15,8 +15,8 @@
         [14, 440, 355, 39],
         [14, 420, 355, 39],
         [65, 400, 304, 19],
-        [14, 363, 48, 65],
-        [14, 374, 48, 64]
+        [14, 374, 48, 64],
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-3-expected.txt
index e54a5f0..c3aa5f6 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-3-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -14,8 +14,8 @@
         [14, 80, 355, 119],
         [14, 460, 355, 59],
         [14, 440, 339, 79],
-        [356, 423, 64, 81],
-        [372, 403, 48, 81]
+        [356, 423, 64, 80],
+        [372, 403, 48, 80]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-4-expected.txt
index 6aebc83..419db37a 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-4-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -14,7 +14,7 @@
         [14, 80, 355, 119],
         [14, 420, 355, 39],
         [65, 400, 304, 19],
-        [372, 403, 48, 81]
+        [372, 403, 48, 80]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-5-expected.txt
index 596b0ca8..307c7f8 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-5-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -13,7 +13,7 @@
         [14, 400, 356, 59],
         [14, 80, 355, 119],
         [14, 440, 355, 79],
-        [14, 363, 48, 65]
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-8-expected.txt
index 22b01304..7c9148c 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-8-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -13,7 +13,7 @@
         [14, 440, 356, 79],
         [14, 80, 355, 119],
         [14, 400, 355, 59],
-        [14, 363, 48, 65]
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-9-expected.txt
index c0828c5..2f8433c7 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-9-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -15,8 +15,8 @@
         [14, 440, 355, 39],
         [14, 420, 355, 39],
         [65, 400, 304, 19],
-        [14, 383, 48, 65],
-        [14, 363, 48, 65]
+        [14, 383, 48, 64],
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
index bdbe389..a7f9b8bb 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
@@ -6,9 +6,9 @@
       "contentsOpaque": true,
       "backgroundColor": "#008000",
       "invalidations": [
-        [8, 174, 500, 168],
         [8, 341, 500, 167],
-        [8, 8, 500, 167]
+        [8, 8, 500, 167],
+        [8, 175, 500, 166]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/repaint-subrect-grid-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/repaint-subrect-grid-expected.txt
index 4c3c896..fc4ce0b 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/repaint-subrect-grid-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/repaint-subrect-grid-expected.txt
@@ -6,16 +6,16 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [45, 18, 20, 19],
-        [36, 36, 19, 19],
-        [36, 0, 19, 19],
-        [27, 18, 19, 19],
-        [18, 36, 19, 19],
-        [18, 0, 19, 19],
-        [9, 18, 19, 19],
-        [0, 36, 19, 19],
-        [0, 0, 19, 19],
-        [0, 18, 10, 19]
+        [18, 37, 19, 18],
+        [18, 0, 19, 18],
+        [46, 18, 18, 19],
+        [28, 18, 18, 19],
+        [9, 18, 18, 19],
+        [37, 37, 18, 18],
+        [37, 0, 18, 18],
+        [0, 37, 18, 18],
+        [0, 0, 18, 18],
+        [0, 18, 9, 19]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invalidate-cell-in-row-with-offset-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invalidate-cell-in-row-with-offset-expected.txt
index d831a6dc..b9a55f55 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invalidate-cell-in-row-with-offset-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invalidate-cell-in-row-with-offset-expected.txt
@@ -8,8 +8,9 @@
     },
     {
       "name": "LayoutNGTableRow TR",
-      "bounds": [214, 102],
-      "contentsOpaqueForText": true,
+      "bounds": [102, 102],
+      "contentsOpaque": true,
+      "backgroundColor": "#FF0000",
       "transform": 1
     },
     {
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invisible-tbody-visible-td-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
index 09ab61c..6a0c442 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [9, 9, 198, 198]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invisible-tr-visible-td-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invisible-tr-visible-td-expected.txt
index 09ab61c..6a0c442 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invisible-tr-visible-td-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/invisible-tr-visible-td-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [9, 9, 198, 198]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-col-background-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-col-background-expected.txt
index e80f225..91f836d 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-col-background-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-col-background-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 108, 106, 104]
+        [10, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-col-background-offset-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-col-background-offset-expected.txt
index 194e06ed..cfc850e4 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-col-background-offset-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-col-background-offset-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 108, 210, 104]
+        [114, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
index dafdb21..759f42f 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [11, 45, 100, 26]
+        [11, 46, 100, 25]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
index 991945e..ba8136f 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
@@ -6,8 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [85, 70, 91, 92],
-        [84, 70, 91, 92]
+        [85, 70, 90, 91]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-align1-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-align1-expected.txt
index aa50214..fc4e8a8 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-align1-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-align1-expected.txt
@@ -6,10 +6,10 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [120, 33, 20, 21],
-        [0, 33, 20, 21],
         [120, 80, 20, 20],
-        [0, 80, 20, 20]
+        [120, 34, 20, 20],
+        [0, 80, 20, 20],
+        [0, 34, 20, 20]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-align2-expected.txt
index d1beab8..17d55d8d 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/vertical-align2-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [200, 146, 100, 101],
+        [200, 146, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/block-shift-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/block-shift-repaint-expected.txt
new file mode 100644
index 0000000..af3658bf
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/block-shift-repaint-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [8, 248, 60, 30],
+        [8, 218, 60, 30],
+        [8, 188, 60, 30],
+        [8, 158, 60, 30],
+        [8, 128, 60, 30],
+        [8, 98, 60, 30],
+        [8, 68, 60, 30],
+        [8, 38, 60, 30],
+        [8, 8, 60, 30],
+        [8, 353, 60, 8],
+        [8, 338, 60, 8]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
new file mode 100644
index 0000000..02a3d82
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -0,0 +1,39 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [200, 200],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "position": [50, 50],
+      "bounds": [250, 250],
+      "contentsOpaqueForText": true,
+      "backgroundColor": "#FF0000",
+      "invalidations": [
+        [50, 50, 200, 200]
+      ]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-expected.txt
new file mode 100644
index 0000000..cdb6e55
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-expected.txt
@@ -0,0 +1,19 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [139, 128, 653, 100],
+        [138, 128, 636, 99],
+        [400, 128, 392, 180],
+        [8, 228, 392, 80],
+        [148, 128, 252, 180],
+        [8, 128, 140, 100]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-rtl-column-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
new file mode 100644
index 0000000..a029c79
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
@@ -0,0 +1,18 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [8, 116, 200, 252],
+        [8, 68, 200, 145],
+        [13, 218, 190, 350],
+        [13, 125, 190, 350],
+        [13, 121, 190, 350]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/iframe-rounding-expected.txt
similarity index 64%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/iframe-rounding-expected.txt
index 5ac61c0..7228a4ce88 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/iframe-rounding-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [20, 18, 100, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-10-expected.txt
new file mode 100644
index 0000000..4671413
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 355, 39],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [14, 374, 48, 64],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-3-expected.txt
new file mode 100644
index 0000000..c3aa5f6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 400, 406, 59],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 339, 79],
+        [356, 423, 64, 80],
+        [372, 403, 48, 80]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-4-expected.txt
new file mode 100644
index 0000000..419db37a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -0,0 +1,22 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 460, 407, 59],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [372, 403, 48, 80]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-5-expected.txt
new file mode 100644
index 0000000..307c7f8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -0,0 +1,21 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [49, 360, 372, 39],
+        [14, 400, 356, 59],
+        [14, 80, 355, 119],
+        [14, 440, 355, 79],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-8-expected.txt
new file mode 100644
index 0000000..7c9148c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -0,0 +1,21 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 360, 407, 39],
+        [14, 440, 356, 79],
+        [14, 80, 355, 119],
+        [14, 400, 355, 59],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-9-expected.txt
new file mode 100644
index 0000000..2f8433c7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 355, 39],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [14, 383, 48, 64],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
new file mode 100644
index 0000000..a7f9b8bb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [8, 341, 500, 167],
+        [8, 8, 500, 167],
+        [8, 175, 500, 166]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/repaint-subrect-grid-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/repaint-subrect-grid-expected.txt
new file mode 100644
index 0000000..fc4ce0b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/repaint-subrect-grid-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [18, 37, 19, 18],
+        [18, 0, 19, 18],
+        [46, 18, 18, 19],
+        [28, 18, 18, 19],
+        [9, 18, 18, 19],
+        [37, 37, 18, 18],
+        [37, 0, 18, 18],
+        [0, 37, 18, 18],
+        [0, 0, 18, 18],
+        [0, 18, 9, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
similarity index 64%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
index 5ac61c0..6a0c442 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tr-visible-td-expected.txt
similarity index 64%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tr-visible-td-expected.txt
index 5ac61c0..6a0c442 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tr-visible-td-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-expected.txt
similarity index 63%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-expected.txt
index 5ac61c0..91f836d 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [10, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-offset-expected.txt
similarity index 63%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-offset-expected.txt
index 5ac61c0..cfc850e4 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-offset-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [114, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
similarity index 64%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
index 5ac61c0..759f42f 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [11, 46, 100, 25]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
similarity index 64%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
index 5ac61c0..ba8136f 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [85, 70, 90, 91]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/vertical-align1-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/vertical-align1-expected.txt
new file mode 100644
index 0000000..fc4e8a8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/vertical-align1-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [120, 80, 20, 20],
+        [120, 34, 20, 20],
+        [0, 80, 20, 20],
+        [0, 34, 20, 20]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/vertical-align2-expected.txt
similarity index 67%
copy from third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/vertical-align2-expected.txt
index 279af1b..17d55d8d 100644
--- a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/backface-visibility-interop/paint/invalidation/vertical-align2-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [200, 146, 100, 101],
+        [200, 146, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/block-shift-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/block-shift-repaint-expected.txt
new file mode 100644
index 0000000..af3658bf
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/block-shift-repaint-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [8, 248, 60, 30],
+        [8, 218, 60, 30],
+        [8, 188, 60, 30],
+        [8, 158, 60, 30],
+        [8, 128, 60, 30],
+        [8, 98, 60, 30],
+        [8, 68, 60, 30],
+        [8, 38, 60, 30],
+        [8, 8, 60, 30],
+        [8, 353, 60, 8],
+        [8, 338, 60, 8]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
new file mode 100644
index 0000000..02a3d82
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -0,0 +1,39 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [200, 200],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "position": [50, 50],
+      "bounds": [250, 250],
+      "contentsOpaqueForText": true,
+      "backgroundColor": "#FF0000",
+      "invalidations": [
+        [50, 50, 200, 200]
+      ]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/compositing/subpixel-offset-scaled-will-change-transform-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/compositing/subpixel-offset-scaled-will-change-transform-expected.txt
new file mode 100644
index 0000000..79c74cf
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/compositing/subpixel-offset-scaled-will-change-transform-expected.txt
@@ -0,0 +1,175 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='child1' class='child composited'",
+      "bounds": [1, 1],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='child2' class='child scale composited'",
+      "bounds": [1, 1],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 4
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='child3' class='child'",
+      "bounds": [1, 1],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 6
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='child4' class='child scale'",
+      "bounds": [1, 1],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 8
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='child5' class='child composited'",
+      "bounds": [1, 1],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 10
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='child6' class='child scale composited'",
+      "bounds": [1, 1],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 12
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [40, 0, 0, 0],
+        [0, 40, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [9, 58, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [40, 0, 0, 0],
+        [0, 40, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0]
+    },
+    {
+      "id": 5,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 108, 0, 1]
+      ]
+    },
+    {
+      "id": 6,
+      "parent": 5,
+      "transform": [
+        [40, 0, 0, 0],
+        [0, 40, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0]
+    },
+    {
+      "id": 7,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 158, 0, 1]
+      ]
+    },
+    {
+      "id": 8,
+      "parent": 7,
+      "transform": [
+        [40, 0, 0, 0],
+        [0, 40, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0]
+    },
+    {
+      "id": 9,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 208, 0, 1]
+      ]
+    },
+    {
+      "id": 10,
+      "parent": 9,
+      "transform": [
+        [40, 0, 0, 0],
+        [0, 40, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0]
+    },
+    {
+      "id": 11,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 258, 0, 1]
+      ]
+    },
+    {
+      "id": 12,
+      "parent": 11,
+      "transform": [
+        [40, 0, 0, 0],
+        [0, 40, 0, 0],
+        [0, 0, 1, 0],
+        [0, 0, 0, 1]
+      ],
+      "origin": [0, 0]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-expected.txt
new file mode 100644
index 0000000..cdb6e55
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-expected.txt
@@ -0,0 +1,19 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [139, 128, 653, 100],
+        [138, 128, 636, 99],
+        [400, 128, 392, 180],
+        [8, 228, 392, 80],
+        [148, 128, 252, 180],
+        [8, 128, 140, 100]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-rtl-column-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
new file mode 100644
index 0000000..a029c79
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
@@ -0,0 +1,18 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [8, 116, 200, 252],
+        [8, 68, 200, 145],
+        [13, 218, 190, 350],
+        [13, 125, 190, 350],
+        [13, 121, 190, 350]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/iframe-rounding-expected.txt
similarity index 64%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/iframe-rounding-expected.txt
index 5ac61c0..7228a4ce88 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/iframe-rounding-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [20, 18, 100, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-10-expected.txt
new file mode 100644
index 0000000..4671413
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 355, 39],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [14, 374, 48, 64],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-3-expected.txt
new file mode 100644
index 0000000..c3aa5f6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 400, 406, 59],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 339, 79],
+        [356, 423, 64, 80],
+        [372, 403, 48, 80]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-4-expected.txt
new file mode 100644
index 0000000..419db37a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -0,0 +1,22 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 460, 407, 59],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [372, 403, 48, 80]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-5-expected.txt
new file mode 100644
index 0000000..307c7f8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -0,0 +1,21 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [49, 360, 372, 39],
+        [14, 400, 356, 59],
+        [14, 80, 355, 119],
+        [14, 440, 355, 79],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-8-expected.txt
new file mode 100644
index 0000000..7c9148c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -0,0 +1,21 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 360, 407, 39],
+        [14, 440, 356, 79],
+        [14, 80, 355, 119],
+        [14, 400, 355, 59],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-9-expected.txt
new file mode 100644
index 0000000..2f8433c7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 355, 39],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [14, 383, 48, 64],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
new file mode 100644
index 0000000..a7f9b8bb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [8, 341, 500, 167],
+        [8, 8, 500, 167],
+        [8, 175, 500, 166]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/repaint-subrect-grid-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/repaint-subrect-grid-expected.txt
new file mode 100644
index 0000000..fc4ce0b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/repaint-subrect-grid-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [18, 37, 19, 18],
+        [18, 0, 19, 18],
+        [46, 18, 18, 19],
+        [28, 18, 18, 19],
+        [9, 18, 18, 19],
+        [37, 37, 18, 18],
+        [37, 0, 18, 18],
+        [0, 37, 18, 18],
+        [0, 0, 18, 18],
+        [0, 18, 9, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
similarity index 64%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
index 5ac61c0..6a0c442 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tr-visible-td-expected.txt
similarity index 64%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tr-visible-td-expected.txt
index 5ac61c0..6a0c442 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tr-visible-td-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-expected.txt
similarity index 63%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-expected.txt
index 5ac61c0..91f836d 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [10, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-offset-expected.txt
similarity index 63%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-offset-expected.txt
index 5ac61c0..cfc850e4 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-offset-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [114, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
similarity index 64%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
index 5ac61c0..759f42f 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [11, 46, 100, 25]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
similarity index 64%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
index 5ac61c0..ba8136f 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [85, 70, 90, 91]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/vertical-align1-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/vertical-align1-expected.txt
new file mode 100644
index 0000000..fc4e8a8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/vertical-align1-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [120, 80, 20, 20],
+        [120, 34, 20, 20],
+        [0, 80, 20, 20],
+        [0, 34, 20, 20]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/vertical-align2-expected.txt
similarity index 67%
copy from third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
copy to third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/vertical-align2-expected.txt
index 279af1b..17d55d8d 100644
--- a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/transform-interop-disabled/paint/invalidation/vertical-align2-expected.txt
@@ -1,12 +1,12 @@
 {
   "layers": [
     {
-      "name": "Scrolling Contents Layer",
+      "name": "Scrolling background of LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [200, 146, 100, 101],
+        [200, 146, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
index 90cce2e..a24acd8 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
@@ -1,4 +1,4 @@
-Tests DOMSnapshot.getSnapshot exports layout tree nodes associated with pseudo elements.
+Tests DOMSnapshot.captureSnapshot exports layout tree nodes associated with pseudo elements.
 {
     documents : [
         [0] : {
@@ -737,6 +737,7 @@
                         [7] : 43
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
index 1fdd398..17a27fb 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -19,7 +19,7 @@
       "bounds": [251, 251],
       "backgroundColor": "#FF0000",
       "invalidations": [
-        [50, 50, 201, 201]
+        [50, 50, 200, 200]
       ],
       "transform": 1
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/flexbox/repaint-expected.txt
new file mode 100644
index 0000000..8f30dcb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/flexbox/repaint-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [139, 128, 653, 100],
+        [138, 168, 636, 19],
+        [138, 128, 636, 19],
+        [138, 188, 627, 19],
+        [138, 148, 620, 19],
+        [138, 208, 573, 19],
+        [400, 128, 392, 180],
+        [8, 228, 392, 80],
+        [148, 128, 252, 180],
+        [8, 128, 140, 100]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-10-expected.txt
index 10abddc..8f467b4 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-10-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -38,8 +38,8 @@
         [302, 440, 66, 19],
         [65, 420, 64, 19],
         [370, 360, 51, 19],
-        [14, 363, 48, 65],
         [14, 374, 48, 64],
+        [14, 363, 48, 64],
         [401, 520, 20, 19],
         [349, 440, 20, 19]
       ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-3-expected.txt
index 639b2001..76005c5 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-3-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -39,10 +39,10 @@
         [302, 440, 66, 19],
         [287, 480, 65, 19],
         [242, 440, 65, 19],
-        [356, 423, 64, 81],
+        [356, 423, 64, 80],
         [362, 400, 58, 19],
         [370, 360, 51, 19],
-        [372, 403, 48, 81],
+        [372, 403, 48, 80],
         [401, 520, 20, 19]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-4-expected.txt
index e4befe587b..243b6eb 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-4-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -36,7 +36,7 @@
         [302, 440, 66, 19],
         [65, 420, 64, 19],
         [370, 360, 51, 19],
-        [372, 403, 48, 81],
+        [372, 403, 48, 80],
         [401, 520, 20, 19]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-5-expected.txt
index cd6d78f..fcc88fa 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-5-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -40,7 +40,7 @@
         [245, 440, 65, 19],
         [65, 420, 64, 19],
         [370, 360, 51, 19],
-        [14, 363, 48, 65],
+        [14, 363, 48, 64],
         [49, 420, 40, 19],
         [401, 520, 20, 19],
         [350, 400, 20, 19]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-6-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-6-expected.txt
index ad807638..b8abdc44 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-6-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-6-expected.txt
@@ -21,7 +21,7 @@
         [306, 340, 114, 19],
         [65, 380, 89, 19],
         [370, 360, 51, 19],
-        [14, 363, 48, 65]
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-9-expected.txt
index e0fa9bc8..362553f6 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-9-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -45,9 +45,9 @@
         [302, 440, 66, 19],
         [65, 420, 64, 19],
         [370, 360, 51, 19],
-        [14, 383, 48, 65],
-        [14, 363, 48, 65],
-        [372, 243, 48, 49],
+        [14, 383, 48, 64],
+        [14, 363, 48, 64],
+        [372, 243, 48, 48],
         [401, 520, 20, 19],
         [349, 440, 20, 19]
       ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/overflow/line-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/overflow/line-overflow-expected.txt
index 9ce993ee..2a655c1 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/overflow/line-overflow-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/overflow/line-overflow-expected.txt
@@ -16,7 +16,8 @@
         [8, 122, 64, 19],
         [149, 122, 54, 19],
         [72, 122, 42, 19],
-        [114, 92, 35, 49]
+        [114, 92, 35, 30],
+        [114, 122, 35, 19]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/replace-col-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/replace-col-expected.txt
index 18fbff9..786f475 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/replace-col-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/replace-col-expected.txt
@@ -6,9 +6,9 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 82, 56, 26],
-        [8, 132, 56, 24],
-        [8, 108, 56, 24]
+        [10, 132, 52, 22],
+        [10, 108, 52, 22],
+        [10, 84, 52, 22]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt
index ffd7e21..e54df4cb 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt
@@ -6,8 +6,8 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [0, 52, 106, 238],
-        [0, 292, 106, 236]
+        [2, 52, 102, 238],
+        [2, 292, 102, 236]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/vertical-align1-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/vertical-align1-expected.txt
index 16d141a..db6f62b2 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/vertical-align1-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/vertical-align1-expected.txt
@@ -7,10 +7,10 @@
       "backgroundColor": "#FFFFFF",
       "invalidations": [
         [20, 0, 100, 100],
-        [120, 33, 20, 21],
-        [0, 33, 20, 21],
         [120, 80, 20, 20],
-        [0, 80, 20, 20]
+        [120, 34, 20, 20],
+        [0, 80, 20, 20],
+        [0, 34, 20, 20]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/vertical-align2-expected.txt
index 19c2c02..62f8311 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/vertical-align2-expected.txt
@@ -8,7 +8,7 @@
       "invalidations": [
         [300, 0, 200, 200],
         [0, 0, 200, 200],
-        [200, 146, 100, 101],
+        [200, 146, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
new file mode 100644
index 0000000..17a27fb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -0,0 +1,39 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV",
+      "bounds": [200, 200],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV)",
+      "position": [42, 42],
+      "bounds": [251, 251],
+      "backgroundColor": "#FF0000",
+      "invalidations": [
+        [50, 50, 200, 200]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-expected.txt
new file mode 100644
index 0000000..8f30dcb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [139, 128, 653, 100],
+        [138, 168, 636, 19],
+        [138, 128, 636, 19],
+        [138, 188, 627, 19],
+        [138, 148, 620, 19],
+        [138, 208, 573, 19],
+        [400, 128, 392, 180],
+        [8, 228, 392, 80],
+        [148, 128, 252, 180],
+        [8, 128, 140, 100]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-10-expected.txt
new file mode 100644
index 0000000..8f467b4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -0,0 +1,49 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 540, 407, 19],
+        [14, 560, 406, 19],
+        [14, 520, 387, 19],
+        [14, 480, 354, 19],
+        [89, 580, 331, 19],
+        [65, 360, 306, 19],
+        [65, 400, 304, 19],
+        [14, 340, 292, 19],
+        [14, 320, 264, 19],
+        [14, 260, 259, 19],
+        [14, 300, 256, 19],
+        [56, 460, 255, 19],
+        [14, 280, 252, 19],
+        [128, 420, 241, 19],
+        [14, 460, 226, 19],
+        [14, 500, 219, 19],
+        [243, 240, 177, 19],
+        [14, 440, 172, 19],
+        [65, 440, 171, 19],
+        [266, 280, 154, 19],
+        [270, 300, 150, 19],
+        [273, 260, 147, 19],
+        [278, 320, 142, 19],
+        [240, 460, 128, 19],
+        [186, 440, 116, 19],
+        [235, 440, 115, 19],
+        [306, 340, 114, 19],
+        [65, 380, 89, 19],
+        [14, 580, 75, 19],
+        [302, 440, 66, 19],
+        [65, 420, 64, 19],
+        [370, 360, 51, 19],
+        [14, 374, 48, 64],
+        [14, 363, 48, 64],
+        [401, 520, 20, 19],
+        [349, 440, 20, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-3-expected.txt
new file mode 100644
index 0000000..76005c5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -0,0 +1,51 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 540, 407, 19],
+        [14, 560, 406, 19],
+        [14, 520, 387, 19],
+        [89, 580, 331, 19],
+        [65, 360, 306, 19],
+        [65, 400, 304, 19],
+        [14, 340, 292, 19],
+        [65, 420, 288, 19],
+        [14, 480, 288, 19],
+        [14, 320, 264, 19],
+        [14, 260, 259, 19],
+        [14, 300, 256, 19],
+        [14, 280, 252, 19],
+        [128, 420, 241, 19],
+        [14, 460, 226, 19],
+        [243, 240, 177, 19],
+        [14, 440, 172, 19],
+        [266, 280, 154, 19],
+        [14, 500, 151, 19],
+        [270, 300, 150, 19],
+        [273, 260, 147, 19],
+        [278, 320, 142, 19],
+        [215, 460, 137, 19],
+        [240, 460, 128, 19],
+        [186, 440, 116, 19],
+        [306, 340, 114, 19],
+        [133, 440, 109, 19],
+        [65, 380, 89, 19],
+        [14, 580, 75, 19],
+        [302, 480, 66, 19],
+        [302, 440, 66, 19],
+        [287, 480, 65, 19],
+        [242, 440, 65, 19],
+        [356, 423, 64, 80],
+        [362, 400, 58, 19],
+        [370, 360, 51, 19],
+        [372, 403, 48, 80],
+        [401, 520, 20, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-4-expected.txt
new file mode 100644
index 0000000..243b6eb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -0,0 +1,45 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 540, 407, 19],
+        [14, 560, 406, 19],
+        [14, 520, 387, 19],
+        [89, 580, 331, 19],
+        [65, 360, 306, 19],
+        [65, 400, 304, 19],
+        [14, 340, 292, 19],
+        [14, 480, 288, 19],
+        [14, 320, 264, 19],
+        [14, 260, 259, 19],
+        [14, 300, 256, 19],
+        [14, 280, 252, 19],
+        [128, 420, 241, 19],
+        [14, 460, 226, 19],
+        [243, 240, 177, 19],
+        [14, 440, 172, 19],
+        [266, 280, 154, 19],
+        [14, 500, 151, 19],
+        [270, 300, 150, 19],
+        [273, 260, 147, 19],
+        [278, 320, 142, 19],
+        [282, 480, 138, 19],
+        [240, 460, 128, 19],
+        [186, 440, 116, 19],
+        [306, 340, 114, 19],
+        [65, 380, 89, 19],
+        [14, 580, 75, 19],
+        [302, 440, 66, 19],
+        [65, 420, 64, 19],
+        [370, 360, 51, 19],
+        [372, 403, 48, 80],
+        [401, 520, 20, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-5-expected.txt
new file mode 100644
index 0000000..fcc88fa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -0,0 +1,51 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 540, 407, 19],
+        [14, 560, 406, 19],
+        [14, 520, 387, 19],
+        [89, 580, 331, 19],
+        [49, 360, 322, 19],
+        [65, 400, 304, 19],
+        [49, 400, 302, 19],
+        [14, 340, 292, 19],
+        [14, 480, 288, 19],
+        [88, 420, 281, 19],
+        [14, 320, 264, 19],
+        [14, 260, 259, 19],
+        [14, 300, 256, 19],
+        [14, 280, 252, 19],
+        [14, 460, 226, 19],
+        [181, 460, 187, 19],
+        [243, 240, 177, 19],
+        [14, 440, 172, 19],
+        [266, 280, 154, 19],
+        [14, 500, 151, 19],
+        [270, 300, 150, 19],
+        [273, 260, 147, 19],
+        [278, 320, 142, 19],
+        [229, 480, 139, 19],
+        [186, 440, 116, 19],
+        [306, 340, 114, 19],
+        [134, 440, 111, 19],
+        [65, 380, 89, 19],
+        [49, 380, 89, 19],
+        [14, 580, 75, 19],
+        [302, 440, 66, 19],
+        [245, 440, 65, 19],
+        [65, 420, 64, 19],
+        [370, 360, 51, 19],
+        [14, 363, 48, 64],
+        [49, 420, 40, 19],
+        [401, 520, 20, 19],
+        [350, 400, 20, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-8-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-8-expected.txt
index 5ac61c0..f02ec31 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [8, 74, 418, 526]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-9-expected.txt
new file mode 100644
index 0000000..362553f6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -0,0 +1,57 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 540, 407, 19],
+        [14, 560, 406, 19],
+        [14, 360, 406, 19],
+        [14, 520, 387, 19],
+        [14, 340, 387, 19],
+        [14, 300, 385, 19],
+        [14, 320, 358, 19],
+        [14, 480, 354, 19],
+        [89, 580, 331, 19],
+        [14, 280, 328, 19],
+        [65, 400, 304, 19],
+        [14, 260, 263, 19],
+        [56, 460, 255, 19],
+        [128, 420, 241, 19],
+        [189, 200, 231, 19],
+        [14, 240, 229, 19],
+        [193, 220, 227, 19],
+        [14, 460, 226, 19],
+        [14, 500, 219, 19],
+        [14, 220, 179, 19],
+        [243, 240, 177, 19],
+        [14, 200, 175, 19],
+        [14, 440, 172, 19],
+        [65, 440, 171, 19],
+        [212, 240, 156, 19],
+        [266, 280, 154, 19],
+        [270, 300, 150, 19],
+        [273, 260, 147, 19],
+        [277, 180, 143, 19],
+        [278, 320, 142, 19],
+        [65, 380, 142, 19],
+        [240, 460, 128, 19],
+        [186, 440, 116, 19],
+        [235, 440, 115, 19],
+        [306, 340, 114, 19],
+        [14, 580, 75, 19],
+        [302, 440, 66, 19],
+        [65, 420, 64, 19],
+        [370, 360, 51, 19],
+        [14, 383, 48, 64],
+        [14, 363, 48, 64],
+        [372, 243, 48, 48],
+        [401, 520, 20, 19],
+        [349, 440, 20, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/overflow/line-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/overflow/line-overflow-expected.txt
new file mode 100644
index 0000000..2a655c1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/overflow/line-overflow-expected.txt
@@ -0,0 +1,25 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [8, 182, 195, 19],
+        [8, 102, 192, 19],
+        [8, 162, 168, 19],
+        [8, 142, 151, 19],
+        [8, 202, 139, 19],
+        [8, 82, 129, 19],
+        [103, 142, 94, 19],
+        [8, 122, 64, 19],
+        [149, 122, 54, 19],
+        [72, 122, 42, 19],
+        [114, 92, 35, 30],
+        [114, 122, 35, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tr-visible-td-expected.txt
similarity index 88%
rename from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
rename to third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tr-visible-td-expected.txt
index 5ac61c0..d79c3a8 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tr-visible-td-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [8, 8, 200, 200]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
index 5ac61c0..a1e15602 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [61, 45, 50, 25]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/vertical-align1-expected.txt
similarity index 60%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/vertical-align1-expected.txt
index 5ac61c0..db6f62b2 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/vertical-align1-expected.txt
@@ -6,7 +6,11 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [20, 0, 100, 100],
+        [120, 80, 20, 20],
+        [120, 34, 20, 20],
+        [0, 80, 20, 20],
+        [0, 34, 20, 20]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/vertical-align2-expected.txt
similarity index 73%
copy from third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
copy to third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/vertical-align2-expected.txt
index 279af1b..62f8311 100644
--- a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/backface-visibility-interop/paint/invalidation/vertical-align2-expected.txt
@@ -6,7 +6,9 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [200, 146, 100, 101],
+        [300, 0, 200, 200],
+        [0, 0, 200, 200],
+        [200, 146, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
index 90cce2e..a24acd8 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
@@ -1,4 +1,4 @@
-Tests DOMSnapshot.getSnapshot exports layout tree nodes associated with pseudo elements.
+Tests DOMSnapshot.captureSnapshot exports layout tree nodes associated with pseudo elements.
 {
     documents : [
         [0] : {
@@ -737,6 +737,7 @@
                         [7] : 43
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
new file mode 100644
index 0000000..17a27fb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -0,0 +1,39 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutBlockFlow (positioned) DIV",
+      "bounds": [200, 200],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (positioned) DIV)",
+      "position": [42, 42],
+      "bounds": [251, 251],
+      "backgroundColor": "#FF0000",
+      "invalidations": [
+        [50, 50, 200, 200]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-expected.txt
new file mode 100644
index 0000000..8f30dcb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [139, 128, 653, 100],
+        [138, 168, 636, 19],
+        [138, 128, 636, 19],
+        [138, 188, 627, 19],
+        [138, 148, 620, 19],
+        [138, 208, 573, 19],
+        [400, 128, 392, 180],
+        [8, 228, 392, 80],
+        [148, 128, 252, 180],
+        [8, 128, 140, 100]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-10-expected.txt
new file mode 100644
index 0000000..8f467b4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -0,0 +1,49 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 540, 407, 19],
+        [14, 560, 406, 19],
+        [14, 520, 387, 19],
+        [14, 480, 354, 19],
+        [89, 580, 331, 19],
+        [65, 360, 306, 19],
+        [65, 400, 304, 19],
+        [14, 340, 292, 19],
+        [14, 320, 264, 19],
+        [14, 260, 259, 19],
+        [14, 300, 256, 19],
+        [56, 460, 255, 19],
+        [14, 280, 252, 19],
+        [128, 420, 241, 19],
+        [14, 460, 226, 19],
+        [14, 500, 219, 19],
+        [243, 240, 177, 19],
+        [14, 440, 172, 19],
+        [65, 440, 171, 19],
+        [266, 280, 154, 19],
+        [270, 300, 150, 19],
+        [273, 260, 147, 19],
+        [278, 320, 142, 19],
+        [240, 460, 128, 19],
+        [186, 440, 116, 19],
+        [235, 440, 115, 19],
+        [306, 340, 114, 19],
+        [65, 380, 89, 19],
+        [14, 580, 75, 19],
+        [302, 440, 66, 19],
+        [65, 420, 64, 19],
+        [370, 360, 51, 19],
+        [14, 374, 48, 64],
+        [14, 363, 48, 64],
+        [401, 520, 20, 19],
+        [349, 440, 20, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-3-expected.txt
new file mode 100644
index 0000000..76005c5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -0,0 +1,51 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 540, 407, 19],
+        [14, 560, 406, 19],
+        [14, 520, 387, 19],
+        [89, 580, 331, 19],
+        [65, 360, 306, 19],
+        [65, 400, 304, 19],
+        [14, 340, 292, 19],
+        [65, 420, 288, 19],
+        [14, 480, 288, 19],
+        [14, 320, 264, 19],
+        [14, 260, 259, 19],
+        [14, 300, 256, 19],
+        [14, 280, 252, 19],
+        [128, 420, 241, 19],
+        [14, 460, 226, 19],
+        [243, 240, 177, 19],
+        [14, 440, 172, 19],
+        [266, 280, 154, 19],
+        [14, 500, 151, 19],
+        [270, 300, 150, 19],
+        [273, 260, 147, 19],
+        [278, 320, 142, 19],
+        [215, 460, 137, 19],
+        [240, 460, 128, 19],
+        [186, 440, 116, 19],
+        [306, 340, 114, 19],
+        [133, 440, 109, 19],
+        [65, 380, 89, 19],
+        [14, 580, 75, 19],
+        [302, 480, 66, 19],
+        [302, 440, 66, 19],
+        [287, 480, 65, 19],
+        [242, 440, 65, 19],
+        [356, 423, 64, 80],
+        [362, 400, 58, 19],
+        [370, 360, 51, 19],
+        [372, 403, 48, 80],
+        [401, 520, 20, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-4-expected.txt
new file mode 100644
index 0000000..243b6eb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -0,0 +1,45 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 540, 407, 19],
+        [14, 560, 406, 19],
+        [14, 520, 387, 19],
+        [89, 580, 331, 19],
+        [65, 360, 306, 19],
+        [65, 400, 304, 19],
+        [14, 340, 292, 19],
+        [14, 480, 288, 19],
+        [14, 320, 264, 19],
+        [14, 260, 259, 19],
+        [14, 300, 256, 19],
+        [14, 280, 252, 19],
+        [128, 420, 241, 19],
+        [14, 460, 226, 19],
+        [243, 240, 177, 19],
+        [14, 440, 172, 19],
+        [266, 280, 154, 19],
+        [14, 500, 151, 19],
+        [270, 300, 150, 19],
+        [273, 260, 147, 19],
+        [278, 320, 142, 19],
+        [282, 480, 138, 19],
+        [240, 460, 128, 19],
+        [186, 440, 116, 19],
+        [306, 340, 114, 19],
+        [65, 380, 89, 19],
+        [14, 580, 75, 19],
+        [302, 440, 66, 19],
+        [65, 420, 64, 19],
+        [370, 360, 51, 19],
+        [372, 403, 48, 80],
+        [401, 520, 20, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-5-expected.txt
new file mode 100644
index 0000000..fcc88fa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -0,0 +1,51 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 540, 407, 19],
+        [14, 560, 406, 19],
+        [14, 520, 387, 19],
+        [89, 580, 331, 19],
+        [49, 360, 322, 19],
+        [65, 400, 304, 19],
+        [49, 400, 302, 19],
+        [14, 340, 292, 19],
+        [14, 480, 288, 19],
+        [88, 420, 281, 19],
+        [14, 320, 264, 19],
+        [14, 260, 259, 19],
+        [14, 300, 256, 19],
+        [14, 280, 252, 19],
+        [14, 460, 226, 19],
+        [181, 460, 187, 19],
+        [243, 240, 177, 19],
+        [14, 440, 172, 19],
+        [266, 280, 154, 19],
+        [14, 500, 151, 19],
+        [270, 300, 150, 19],
+        [273, 260, 147, 19],
+        [278, 320, 142, 19],
+        [229, 480, 139, 19],
+        [186, 440, 116, 19],
+        [306, 340, 114, 19],
+        [134, 440, 111, 19],
+        [65, 380, 89, 19],
+        [49, 380, 89, 19],
+        [14, 580, 75, 19],
+        [302, 440, 66, 19],
+        [245, 440, 65, 19],
+        [65, 420, 64, 19],
+        [370, 360, 51, 19],
+        [14, 363, 48, 64],
+        [49, 420, 40, 19],
+        [401, 520, 20, 19],
+        [350, 400, 20, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-8-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-8-expected.txt
index 5ac61c0..f02ec31 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [8, 74, 418, 526]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-9-expected.txt
new file mode 100644
index 0000000..362553f6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -0,0 +1,57 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 540, 407, 19],
+        [14, 560, 406, 19],
+        [14, 360, 406, 19],
+        [14, 520, 387, 19],
+        [14, 340, 387, 19],
+        [14, 300, 385, 19],
+        [14, 320, 358, 19],
+        [14, 480, 354, 19],
+        [89, 580, 331, 19],
+        [14, 280, 328, 19],
+        [65, 400, 304, 19],
+        [14, 260, 263, 19],
+        [56, 460, 255, 19],
+        [128, 420, 241, 19],
+        [189, 200, 231, 19],
+        [14, 240, 229, 19],
+        [193, 220, 227, 19],
+        [14, 460, 226, 19],
+        [14, 500, 219, 19],
+        [14, 220, 179, 19],
+        [243, 240, 177, 19],
+        [14, 200, 175, 19],
+        [14, 440, 172, 19],
+        [65, 440, 171, 19],
+        [212, 240, 156, 19],
+        [266, 280, 154, 19],
+        [270, 300, 150, 19],
+        [273, 260, 147, 19],
+        [277, 180, 143, 19],
+        [278, 320, 142, 19],
+        [65, 380, 142, 19],
+        [240, 460, 128, 19],
+        [186, 440, 116, 19],
+        [235, 440, 115, 19],
+        [306, 340, 114, 19],
+        [14, 580, 75, 19],
+        [302, 440, 66, 19],
+        [65, 420, 64, 19],
+        [370, 360, 51, 19],
+        [14, 383, 48, 64],
+        [14, 363, 48, 64],
+        [372, 243, 48, 48],
+        [401, 520, 20, 19],
+        [349, 440, 20, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/overflow/line-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/overflow/line-overflow-expected.txt
new file mode 100644
index 0000000..2a655c1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/overflow/line-overflow-expected.txt
@@ -0,0 +1,25 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [8, 182, 195, 19],
+        [8, 102, 192, 19],
+        [8, 162, 168, 19],
+        [8, 142, 151, 19],
+        [8, 202, 139, 19],
+        [8, 82, 129, 19],
+        [103, 142, 94, 19],
+        [8, 122, 64, 19],
+        [149, 122, 54, 19],
+        [72, 122, 42, 19],
+        [114, 92, 35, 30],
+        [114, 122, 35, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tr-visible-td-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tr-visible-td-expected.txt
index 5ac61c0..d79c3a8 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tr-visible-td-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [8, 8, 200, 200]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
index 5ac61c0..a1e15602 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [61, 45, 50, 25]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/vertical-align1-expected.txt
similarity index 60%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/vertical-align1-expected.txt
index 5ac61c0..db6f62b2 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/vertical-align1-expected.txt
@@ -6,7 +6,11 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [20, 0, 100, 100],
+        [120, 80, 20, 20],
+        [120, 34, 20, 20],
+        [0, 80, 20, 20],
+        [0, 34, 20, 20]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/vertical-align2-expected.txt
similarity index 73%
copy from third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
copy to third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/vertical-align2-expected.txt
index 279af1b..62f8311 100644
--- a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/virtual/transform-interop-disabled/paint/invalidation/vertical-align2-expected.txt
@@ -6,7 +6,9 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [200, 146, 100, 101],
+        [300, 0, 200, 200],
+        [0, 0, 200, 200],
+        [200, 146, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt b/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt
index 0d65e8b..cf38a63 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt
@@ -274,6 +274,7 @@
                     value : [
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt b/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt
index cf9f613..58553e9 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt
@@ -168,6 +168,7 @@
                     value : [
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                         [0] : 8
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt b/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt
index 2c4ba696..c225d0b 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt
@@ -265,6 +265,7 @@
                     value : [
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt b/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
index 2dc7643..10890dbe 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/highdpi/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
@@ -1,4 +1,4 @@
-Tests DOMSnapshot.getSnapshot exports layout tree nodes associated with pseudo elements.
+Tests DOMSnapshot.captureSnapshot exports layout tree nodes associated with pseudo elements.
 {
     documents : [
         [0] : {
@@ -785,6 +785,7 @@
                         [7] : 44
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt b/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt
index 0d65e8b..cf38a63 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt
@@ -274,6 +274,7 @@
                     value : [
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt b/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt
index cf9f613..58553e9 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt
@@ -168,6 +168,7 @@
                     value : [
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                         [0] : 8
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt b/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt
index 2c4ba696..c225d0b 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt
@@ -265,6 +265,7 @@
                     value : [
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt b/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
index 2dc7643..10890dbe 100644
--- a/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/highdpi/virtual/stable/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
@@ -1,4 +1,4 @@
-Tests DOMSnapshot.getSnapshot exports layout tree nodes associated with pseudo elements.
+Tests DOMSnapshot.captureSnapshot exports layout tree nodes associated with pseudo elements.
 {
     documents : [
         [0] : {
@@ -785,6 +785,7 @@
                         [7] : 44
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/http/tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/http/tests/webexposed/global-interface-listing-expected.txt
index d6bb293..a5a32f8 100644
--- a/third_party/blink/web_tests/http/tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/http/tests/webexposed/global-interface-listing-expected.txt
@@ -8154,10 +8154,10 @@
     method constructor
     setter zoomAndPan
 interface Sanitizer
-    static method defaultConfig
+    static method getDefaultConfiguration
     attribute @@toStringTag
-    method config
     method constructor
+    method getConfiguration
     method sanitize
     method sanitizeFor
     method sanitizeToString
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt
index f7a6815f..9a8ff79 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2-expected.txt
@@ -274,6 +274,7 @@
                     value : [
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2.js b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2.js
index 2a3c507..161202f 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2.js
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree2.js
@@ -19,7 +19,7 @@
     response.result.strings[response.result.documents[0].frameId] = '';
     testRunner.log(
         response.result, undefined,
-        ['documentURL', 'frameId', 'backendNodeId']);
+        ['documentURL', 'frameId', 'backendNodeId', 'shadowRootType']);
   }
   testRunner.completeTest();
 })
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt
index bfdd158..c2827d8 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3-expected.txt
@@ -168,6 +168,7 @@
                     value : [
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                         [0] : 8
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3.js b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3.js
index c38fed8..70291ab0 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3.js
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/captureSnapshot-ua-shadow-tree3.js
@@ -17,7 +17,7 @@
     response.result.strings[response.result.documents[0].frameId] = '';
     testRunner.log(
         response.result, undefined,
-        ['documentURL', 'frameId', 'backendNodeId', 'bounds']);
+        ['documentURL', 'frameId', 'backendNodeId', 'bounds', 'shadowRootType']);
   }
   testRunner.completeTest();
 })
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt
index a107c16..adb9746 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details-expected.txt
@@ -265,6 +265,7 @@
                     value : [
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details.js b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details.js
index a3ddf4a..0d7b4c9 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details.js
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-details.js
@@ -10,7 +10,7 @@
     response.result.strings[response.result.documents[0].frameId] = '';
     testRunner.log(
         response.result, undefined,
-        ['documentURL', 'frameId', 'backendNodeId']);
+        ['documentURL', 'frameId', 'backendNodeId', 'shadowRootType']);
   }
   testRunner.completeTest();
 })
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
index 4209eaab..44f2cc20 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element-expected.txt
@@ -1,4 +1,4 @@
-Tests DOMSnapshot.getSnapshot exports layout tree nodes associated with pseudo elements.
+Tests DOMSnapshot.captureSnapshot exports layout tree nodes associated with pseudo elements.
 {
     documents : [
         [0] : {
@@ -785,6 +785,7 @@
                         [7] : 44
                     ]
                 }
+                shadowRootType : <object>
                 textValue : {
                     index : [
                     ]
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element.js b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element.js
index 892bd819..cbb595b 100644
--- a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element.js
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-pseudo-element.js
@@ -1,5 +1,5 @@
 (async function(testRunner) {
-  var {page, session, dp} = await testRunner.startURL('../resources/dom-snapshot-pseudo-element.html', 'Tests DOMSnapshot.getSnapshot exports layout tree nodes associated with pseudo elements.');
+  var {page, session, dp} = await testRunner.startURL('../resources/dom-snapshot-pseudo-element.html', 'Tests DOMSnapshot.captureSnapshot exports layout tree nodes associated with pseudo elements.');
 
   var response = await dp.DOMSnapshot.captureSnapshot({'computedStyles': ['font-weight', 'color'], 'includeEventListeners': true});
   if (response.error) {
@@ -11,7 +11,7 @@
     response.result.strings[response.result.documents[0].frameId] = '';
     testRunner.log(
         response.result, undefined,
-        ['documentURL', 'baseURL', 'frameId', 'backendNodeId']);
+        ['documentURL', 'baseURL', 'frameId', 'backendNodeId', 'shadowRootType']);
   }
   testRunner.completeTest();
 })
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-shadow-root-type-expected.txt b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-shadow-root-type-expected.txt
new file mode 100644
index 0000000..3d0c0f0
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-shadow-root-type-expected.txt
@@ -0,0 +1,22 @@
+Tests that DOMSnapshot.captureSnapshot properly reports shadow root types
+node:  value=undefined name=#document shadowRootType=undefined
+node:  value=undefined name=HTML shadowRootType=undefined
+node:  value=undefined name=HEAD shadowRootType=undefined
+node:  value=undefined name=BODY shadowRootType=undefined
+node:  value= name=#text shadowRootType=undefined
+node:  value=undefined name=HOST-ELEMENT shadowRootType=undefined
+node:  value= name=#text shadowRootType=open
+node:  value=undefined name=H2 shadowRootType=open
+node:  value=Open shadow root name=#text shadowRootType=open
+node:  value= name=#text shadowRootType=open
+node:  value= name=#text shadowRootType=undefined
+node:  value=undefined name=HOST-ELEMENT shadowRootType=undefined
+node:  value= name=#text shadowRootType=closed
+node:  value=undefined name=H2 shadowRootType=closed
+node:  value=Closes shadow root name=#text shadowRootType=closed
+node:  value= name=#text shadowRootType=closed
+node:  value= name=#text shadowRootType=undefined
+node:  value=undefined name=TEXTAREA shadowRootType=undefined
+node:  value=test for ua shadow roots are not returned by DOMSnapshot.captureSnapshot name=#text shadowRootType=undefined
+node:  value= name=#text shadowRootType=undefined
+
diff --git a/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-shadow-root-type.js b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-shadow-root-type.js
new file mode 100644
index 0000000..716df84
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom-snapshot/dom-snapshot-captureSnapshot-shadow-root-type.js
@@ -0,0 +1,36 @@
+(async function(testRunner) {
+  const {dp} = await testRunner.startHTML(`
+    <html>
+    <body>
+      <host-element>
+        <template shadowroot="open">
+          <h2>Open shadow root</h2>
+        </template>
+      </host-element>
+      <host-element>
+        <template shadowroot="closed">
+          <h2>Closes shadow root</h2>
+        </template>
+      </host-element>
+      <textarea>test for ua shadow roots are not returned by DOMSnapshot.captureSnapshot</textarea>
+    </body>
+    </html>`, 'Tests that DOMSnapshot.captureSnapshot properly reports shadow root types');
+
+  const { result } = await dp.DOMSnapshot.captureSnapshot({'computedStyles': []});
+  const nodeValue = result.documents[0].nodes.nodeValue;
+  const shadowRootType = result.documents[0].nodes.shadowRootType;
+  const shadowRootTypes = new Map(shadowRootType.index.map((nodeIdx, i) => {
+    return [nodeIdx, result.strings[shadowRootType.value[i]]];
+  }));
+  for (let i = 0; i < nodeValue.length; i++) {
+    const value = nodeValue[i];
+    const nodeName = result.documents[0].nodes.nodeName[i];
+    testRunner.log([
+      'node: ',
+      'value=' + String(result.strings[value]).trim(),
+      'name=' + result.strings[nodeName],
+      'shadowRootType=' + shadowRootTypes.get(i),
+    ].join(' '));
+  }
+  testRunner.completeTest();
+})
diff --git a/third_party/blink/web_tests/paint/invalidation/block-shift-repaint-expected.txt b/third_party/blink/web_tests/paint/invalidation/block-shift-repaint-expected.txt
index 2490b0f7..34c70dd6 100644
--- a/third_party/blink/web_tests/paint/invalidation/block-shift-repaint-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/block-shift-repaint-expected.txt
@@ -6,8 +6,6 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 353, 60, 38],
-        [8, 338, 60, 38],
         [8, 248, 60, 30],
         [8, 218, 60, 30],
         [8, 188, 60, 30],
@@ -16,7 +14,9 @@
         [8, 98, 60, 30],
         [8, 68, 60, 30],
         [8, 38, 60, 30],
-        [8, 8, 60, 30]
+        [8, 8, 60, 30],
+        [8, 353, 60, 8],
+        [8, 338, 60, 8]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/blink/web_tests/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
index 6bc15bd..49006ad 100644
--- a/third_party/blink/web_tests/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -19,7 +19,7 @@
       "bounds": [251, 251],
       "backgroundColor": "#FF0000",
       "invalidations": [
-        [50, 50, 201, 201]
+        [50, 50, 200, 200]
       ],
       "transform": 1
     }
diff --git a/third_party/blink/web_tests/paint/invalidation/flexbox/repaint-rtl-column-expected.txt b/third_party/blink/web_tests/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
index 28dfb65..977c73cb0 100644
--- a/third_party/blink/web_tests/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
@@ -8,9 +8,9 @@
       "invalidations": [
         [8, 116, 200, 252],
         [8, 68, 200, 145],
-        [13, 124, 190, 351],
-        [13, 121, 190, 351],
-        [13, 218, 190, 350]
+        [13, 218, 190, 350],
+        [13, 125, 190, 350],
+        [13, 121, 190, 350]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/iframe-rounding-expected.txt b/third_party/blink/web_tests/paint/invalidation/iframe-rounding-expected.txt
index 76dcc793..98e8df68 100644
--- a/third_party/blink/web_tests/paint/invalidation/iframe-rounding-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/iframe-rounding-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [19, 18, 101, 100]
+        [20, 18, 100, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt b/third_party/blink/web_tests/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
index 51d4b99..bf767ade 100644
--- a/third_party/blink/web_tests/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
@@ -6,9 +6,9 @@
       "contentsOpaque": true,
       "backgroundColor": "#008000",
       "invalidations": [
-        [8, 174, 500, 168],
         [8, 341, 500, 167],
-        [8, 8, 500, 167]
+        [8, 8, 500, 167],
+        [8, 175, 500, 166]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/repaint-subrect-grid-expected.txt b/third_party/blink/web_tests/paint/invalidation/repaint-subrect-grid-expected.txt
index 4338e6b..e128fc2 100644
--- a/third_party/blink/web_tests/paint/invalidation/repaint-subrect-grid-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/repaint-subrect-grid-expected.txt
@@ -6,16 +6,16 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [45, 18, 20, 19],
-        [36, 36, 19, 19],
-        [36, 0, 19, 19],
-        [27, 18, 19, 19],
-        [18, 36, 19, 19],
-        [18, 0, 19, 19],
-        [9, 18, 19, 19],
-        [0, 36, 19, 19],
-        [0, 0, 19, 19],
-        [0, 18, 10, 19]
+        [18, 37, 19, 18],
+        [18, 0, 19, 18],
+        [46, 18, 18, 19],
+        [28, 18, 18, 19],
+        [9, 18, 18, 19],
+        [37, 37, 18, 18],
+        [37, 0, 18, 18],
+        [0, 37, 18, 18],
+        [0, 0, 18, 18],
+        [0, 18, 9, 19]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/table/invisible-tbody-visible-td-expected.txt b/third_party/blink/web_tests/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
index 32afb69..7fe3897 100644
--- a/third_party/blink/web_tests/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [9, 9, 198, 198]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/table/invisible-tr-visible-td-expected.txt b/third_party/blink/web_tests/paint/invalidation/table/invisible-tr-visible-td-expected.txt
index 32afb69..7fe3897 100644
--- a/third_party/blink/web_tests/paint/invalidation/table/invisible-tr-visible-td-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/table/invisible-tr-visible-td-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [9, 9, 198, 198]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/table/table-col-background-expected.txt b/third_party/blink/web_tests/paint/invalidation/table/table-col-background-expected.txt
index 8309fc9..649c1df 100644
--- a/third_party/blink/web_tests/paint/invalidation/table/table-col-background-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/table/table-col-background-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 108, 106, 104]
+        [10, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/table/table-col-background-offset-expected.txt b/third_party/blink/web_tests/paint/invalidation/table/table-col-background-offset-expected.txt
index bbe6ed0..87a1409 100644
--- a/third_party/blink/web_tests/paint/invalidation/table/table-col-background-offset-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/table/table-col-background-offset-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 108, 210, 104]
+        [114, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt b/third_party/blink/web_tests/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
index 6ad3d54..e976dd3d 100644
--- a/third_party/blink/web_tests/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [11, 45, 100, 26]
+        [11, 46, 100, 25]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt b/third_party/blink/web_tests/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
index 02a551d..090fa790 100644
--- a/third_party/blink/web_tests/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
@@ -6,8 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [85, 70, 91, 92],
-        [84, 70, 91, 92]
+        [85, 70, 90, 91]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/vertical-align1-expected.txt b/third_party/blink/web_tests/paint/invalidation/vertical-align1-expected.txt
index 625b77f..7a4b120 100644
--- a/third_party/blink/web_tests/paint/invalidation/vertical-align1-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/vertical-align1-expected.txt
@@ -6,10 +6,10 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [120, 33, 20, 21],
-        [0, 33, 20, 21],
         [120, 80, 20, 20],
-        [0, 80, 20, 20]
+        [120, 34, 20, 20],
+        [0, 80, 20, 20],
+        [0, 34, 20, 20]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/flexbox/repaint-expected.txt
index ffb4395..902471c3 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/flexbox/repaint-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/flexbox/repaint-expected.txt
@@ -6,7 +6,8 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [138, 128, 654, 100],
+        [139, 128, 653, 100],
+        [138, 128, 636, 99],
         [400, 128, 392, 180],
         [8, 228, 392, 80],
         [148, 128, 252, 180],
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-10-expected.txt
index 67b07da..236acf7 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-10-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -15,8 +15,8 @@
         [14, 440, 355, 39],
         [14, 420, 355, 39],
         [65, 400, 304, 19],
-        [14, 363, 48, 65],
-        [14, 374, 48, 64]
+        [14, 374, 48, 64],
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-3-expected.txt
index 5d47f47..df2e588 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-3-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -14,8 +14,8 @@
         [14, 80, 355, 119],
         [14, 460, 355, 59],
         [14, 440, 339, 79],
-        [356, 423, 64, 81],
-        [372, 403, 48, 81]
+        [356, 423, 64, 80],
+        [372, 403, 48, 80]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-4-expected.txt
index 8cb6323..7d080da 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-4-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -14,7 +14,7 @@
         [14, 80, 355, 119],
         [14, 420, 355, 39],
         [65, 400, 304, 19],
-        [372, 403, 48, 81]
+        [372, 403, 48, 80]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-5-expected.txt
index 52c2d80..4623fcc 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-5-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -13,7 +13,7 @@
         [14, 400, 356, 59],
         [14, 80, 355, 119],
         [14, 440, 355, 79],
-        [14, 363, 48, 65]
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt
index cae3db4..18f80629 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -13,7 +13,7 @@
         [14, 440, 356, 79],
         [14, 80, 355, 119],
         [14, 400, 355, 59],
-        [14, 363, 48, 65]
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-9-expected.txt
index 69429ef..02a33aa 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-9-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -15,8 +15,8 @@
         [14, 440, 355, 39],
         [14, 420, 355, 39],
         [65, 400, 304, 19],
-        [14, 383, 48, 65],
-        [14, 363, 48, 65]
+        [14, 383, 48, 64],
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/vertical-align2-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
copy to third_party/blink/web_tests/platform/linux/paint/invalidation/vertical-align2-expected.txt
index 279af1b..dbf1dff 100644
--- a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/vertical-align2-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [200, 146, 100, 101],
+        [200, 146, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-expected.txt
new file mode 100644
index 0000000..902471c3
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-expected.txt
@@ -0,0 +1,19 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [139, 128, 653, 100],
+        [138, 128, 636, 99],
+        [400, 128, 392, 180],
+        [8, 228, 392, 80],
+        [148, 128, 252, 180],
+        [8, 128, 140, 100]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-10-expected.txt
new file mode 100644
index 0000000..236acf7
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 355, 39],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [14, 374, 48, 64],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-3-expected.txt
new file mode 100644
index 0000000..df2e588
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 400, 406, 59],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 339, 79],
+        [356, 423, 64, 80],
+        [372, 403, 48, 80]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-4-expected.txt
new file mode 100644
index 0000000..7d080da
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -0,0 +1,22 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 460, 407, 59],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [372, 403, 48, 80]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-5-expected.txt
new file mode 100644
index 0000000..4623fcc
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -0,0 +1,21 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [49, 360, 372, 39],
+        [14, 400, 356, 59],
+        [14, 80, 355, 119],
+        [14, 440, 355, 79],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-8-expected.txt
new file mode 100644
index 0000000..18f80629
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -0,0 +1,21 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 360, 407, 39],
+        [14, 440, 356, 79],
+        [14, 80, 355, 119],
+        [14, 400, 355, 59],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-9-expected.txt
new file mode 100644
index 0000000..02a33aa
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 355, 39],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [14, 383, 48, 64],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/vertical-align2-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
copy to third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/vertical-align2-expected.txt
index 279af1b..dbf1dff 100644
--- a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/vertical-align2-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [200, 146, 100, 101],
+        [200, 146, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-expected.png
new file mode 100644
index 0000000..3171785
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-standalone-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-standalone-expected.png
new file mode 100644
index 0000000..3171785
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-standalone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-expected.txt
new file mode 100644
index 0000000..902471c3
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-expected.txt
@@ -0,0 +1,19 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [139, 128, 653, 100],
+        [138, 128, 636, 99],
+        [400, 128, 392, 180],
+        [8, 228, 392, 80],
+        [148, 128, 252, 180],
+        [8, 128, 140, 100]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-10-expected.txt
new file mode 100644
index 0000000..236acf7
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 355, 39],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [14, 374, 48, 64],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-3-expected.txt
new file mode 100644
index 0000000..df2e588
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 400, 406, 59],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 339, 79],
+        [356, 423, 64, 80],
+        [372, 403, 48, 80]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-4-expected.txt
new file mode 100644
index 0000000..7d080da
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -0,0 +1,22 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 460, 407, 59],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [372, 403, 48, 80]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-5-expected.txt
new file mode 100644
index 0000000..4623fcc
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -0,0 +1,21 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [49, 360, 372, 39],
+        [14, 400, 356, 59],
+        [14, 80, 355, 119],
+        [14, 440, 355, 79],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-8-expected.txt
new file mode 100644
index 0000000..18f80629
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -0,0 +1,21 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [14, 360, 407, 39],
+        [14, 440, 356, 79],
+        [14, 80, 355, 119],
+        [14, 400, 355, 59],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-9-expected.txt
new file mode 100644
index 0000000..02a33aa
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [14, 520, 408, 79],
+        [14, 240, 407, 139],
+        [14, 180, 407, 79],
+        [65, 360, 356, 39],
+        [14, 80, 355, 119],
+        [14, 460, 355, 59],
+        [14, 440, 355, 39],
+        [14, 420, 355, 39],
+        [65, 400, 304, 19],
+        [14, 383, 48, 64],
+        [14, 363, 48, 64]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/vertical-align2-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
copy to third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/vertical-align2-expected.txt
index 279af1b..dbf1dff 100644
--- a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/transform-interop-disabled/paint/invalidation/vertical-align2-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [200, 146, 100, 101],
+        [200, 146, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt
index f964225..a6c58d66 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt
@@ -8,8 +8,7 @@
       "invalidations": [
         [8, 155, 32, 18],
         [8, 119, 32, 18],
-        [8, 137, 24, 18],
-        [8, 119, 1, 19]
+        [8, 137, 24, 18]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/flexbox/repaint-expected.txt
index 029a6c2..51e75afe 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/flexbox/repaint-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/flexbox/repaint-expected.txt
@@ -6,7 +6,8 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [138, 116, 654, 90],
+        [139, 116, 653, 90],
+        [138, 116, 651, 90],
         [148, 116, 644, 108],
         [400, 116, 392, 162],
         [8, 224, 392, 54],
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-1-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-1-expected.txt
index b66a1680..917a5a91 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-1-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-1-expected.txt
@@ -17,8 +17,8 @@
         [14, 386, 355, 36],
         [65, 368, 304, 18],
         [378, 138, 70, 30],
-        [14, 353, 48, 65],
-        [14, 335, 48, 65]
+        [14, 353, 48, 64],
+        [14, 335, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-10-expected.txt
index a51889f..f956e87 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-10-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -14,8 +14,8 @@
         [14, 404, 355, 36],
         [65, 386, 304, 36],
         [65, 368, 304, 18],
-        [14, 353, 48, 65],
-        [14, 364, 48, 64]
+        [14, 364, 48, 64],
+        [14, 353, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-3-expected.txt
index e67aaa4..b91b28e 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-3-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -13,8 +13,8 @@
         [14, 80, 355, 108],
         [14, 422, 355, 54],
         [14, 404, 355, 36],
-        [356, 389, 64, 81],
-        [372, 371, 48, 81]
+        [356, 389, 64, 80],
+        [372, 371, 48, 80]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-4-expected.txt
index a8e5cd0c8..2157a3b 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-4-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -14,7 +14,7 @@
         [14, 404, 355, 36],
         [65, 386, 304, 36],
         [65, 368, 304, 18],
-        [372, 371, 48, 81]
+        [372, 371, 48, 80]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-5-expected.txt
index 0384260..c0bc348 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-5-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -13,7 +13,7 @@
         [14, 422, 355, 54],
         [14, 404, 355, 36],
         [49, 368, 321, 54],
-        [14, 353, 48, 65]
+        [14, 353, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-8-expected.txt
index bd9e206..babf0c5 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-8-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -12,7 +12,7 @@
         [14, 368, 356, 54],
         [14, 80, 355, 108],
         [14, 404, 355, 72],
-        [14, 353, 48, 65]
+        [14, 353, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/remove-inline-after-layout-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/remove-inline-after-layout-expected.txt
index 3560f18..d34b307 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/remove-inline-after-layout-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/remove-inline-after-layout-expected.txt
@@ -7,8 +7,8 @@
       "backgroundColor": "#FFFFFF",
       "invalidations": [
         [111, 194, 182, 18],
-        [292, 108, 101, 100],
-        [111, 108, 101, 100],
+        [293, 108, 100, 100],
+        [112, 108, 100, 100],
         [108, 194, 4, 18]
       ]
     }
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/remove-inline-layer-after-layout-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/remove-inline-layer-after-layout-expected.txt
index 3560f18..d34b307 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/remove-inline-layer-after-layout-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/remove-inline-layer-after-layout-expected.txt
@@ -7,8 +7,8 @@
       "backgroundColor": "#FFFFFF",
       "invalidations": [
         [111, 194, 182, 18],
-        [292, 108, 101, 100],
-        [111, 108, 101, 100],
+        [293, 108, 100, 100],
+        [112, 108, 100, 100],
         [108, 194, 4, 18]
       ]
     }
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/caret-invalidation-in-overflow-scroll-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/caret-invalidation-in-overflow-scroll-expected.txt
index 88258ba..9e1f6db 100644
--- a/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/caret-invalidation-in-overflow-scroll-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/caret-invalidation-in-overflow-scroll-expected.txt
@@ -6,8 +6,8 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [409, 11, 2, 15],
-        [406, 11, 2, 15]
+        [410, 11, 1, 15],
+        [407, 11, 1, 15]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/vertical-align2-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
copy to third_party/blink/web_tests/platform/mac/paint/invalidation/vertical-align2-expected.txt
index 279af1b..dbf1dff 100644
--- a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/vertical-align2-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [200, 146, 100, 101],
+        [200, 146, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-expected.png b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-expected.png
new file mode 100644
index 0000000..508adc2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-standalone-expected.png b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-standalone-expected.png
new file mode 100644
index 0000000..508adc2
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/custom/mouse-move-on-svg-container-standalone-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/flexbox/repaint-expected.txt
index 8d16b6977..3822c8c 100644
--- a/third_party/blink/web_tests/platform/win/paint/invalidation/flexbox/repaint-expected.txt
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/flexbox/repaint-expected.txt
@@ -6,7 +6,8 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [138, 128, 654, 100],
+        [139, 128, 653, 100],
+        [138, 128, 651, 99],
         [400, 128, 392, 160],
         [8, 228, 392, 60],
         [148, 128, 252, 160],
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-1-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-1-expected.txt
index ea7e175..4af121a 100644
--- a/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-1-expected.txt
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-1-expected.txt
@@ -13,8 +13,8 @@
         [14, 420, 355, 79],
         [14, 380, 355, 59],
         [378, 138, 70, 30],
-        [14, 363, 48, 65],
-        [14, 343, 48, 65]
+        [14, 363, 48, 64],
+        [14, 343, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-10-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-10-expected.txt
index 20d2a2d..a45e8a0 100644
--- a/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-10-expected.txt
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-10-expected.txt
@@ -12,8 +12,8 @@
         [14, 80, 355, 119],
         [14, 440, 355, 59],
         [65, 380, 304, 59],
-        [14, 363, 48, 65],
-        [14, 374, 48, 64]
+        [14, 374, 48, 64],
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-3-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-3-expected.txt
index 5b76263..8e58308 100644
--- a/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-3-expected.txt
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-3-expected.txt
@@ -13,7 +13,7 @@
         [14, 440, 355, 59],
         [14, 420, 339, 39],
         [65, 380, 304, 59],
-        [356, 383, 64, 81]
+        [356, 383, 64, 80]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-4-expected.txt
index 3a82310f..f32b5795 100644
--- a/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-4-expected.txt
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -12,7 +12,7 @@
         [14, 440, 407, 59],
         [14, 80, 355, 119],
         [65, 380, 304, 59],
-        [372, 383, 48, 81]
+        [372, 383, 48, 80]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-5-expected.txt
index c33ae5e..3d2d2b5d0 100644
--- a/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-5-expected.txt
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -12,7 +12,7 @@
         [14, 80, 355, 119],
         [14, 420, 355, 79],
         [49, 380, 320, 59],
-        [14, 363, 48, 65]
+        [14, 363, 48, 64]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/vertical-align2-expected.txt
similarity index 88%
rename from third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
rename to third_party/blink/web_tests/platform/win/paint/invalidation/vertical-align2-expected.txt
index 279af1b..ff3c326 100644
--- a/third_party/blink/web_tests/paint/invalidation/vertical-align2-expected.txt
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/vertical-align2-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [200, 146, 100, 101],
+        [200, 147, 100, 100],
         [200, 100, 100, 100]
       ]
     }
diff --git a/third_party/blink/web_tests/virtual/anonymous-iframe/http/tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/anonymous-iframe/http/tests/webexposed/global-interface-listing-expected.txt
index b90a8bc..1e8742a4 100644
--- a/third_party/blink/web_tests/virtual/anonymous-iframe/http/tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/anonymous-iframe/http/tests/webexposed/global-interface-listing-expected.txt
@@ -8156,10 +8156,10 @@
     method constructor
     setter zoomAndPan
 interface Sanitizer
-    static method defaultConfig
+    static method getDefaultConfiguration
     attribute @@toStringTag
-    method config
     method constructor
+    method getConfiguration
     method sanitize
     method sanitizeFor
     method sanitizeToString
diff --git a/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/block-shift-repaint-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/block-shift-repaint-expected.txt
new file mode 100644
index 0000000..34c70dd6
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/block-shift-repaint-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [8, 248, 60, 30],
+        [8, 218, 60, 30],
+        [8, 188, 60, 30],
+        [8, 158, 60, 30],
+        [8, 128, 60, 30],
+        [8, 98, 60, 30],
+        [8, 68, 60, 30],
+        [8, 38, 60, 30],
+        [8, 8, 60, 30],
+        [8, 353, 60, 8],
+        [8, 338, 60, 8]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
new file mode 100644
index 0000000..49006ad
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -0,0 +1,39 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [200, 200],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV)",
+      "position": [42, 42],
+      "bounds": [251, 251],
+      "backgroundColor": "#FF0000",
+      "invalidations": [
+        [50, 50, 200, 200]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-rtl-column-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
new file mode 100644
index 0000000..977c73cb0
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
@@ -0,0 +1,18 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [8, 116, 200, 252],
+        [8, 68, 200, 145],
+        [13, 218, 190, 350],
+        [13, 125, 190, 350],
+        [13, 121, 190, 350]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/iframe-rounding-expected.txt
similarity index 87%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/iframe-rounding-expected.txt
index 5ac61c0..98e8df68 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/iframe-rounding-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [20, 18, 100, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
new file mode 100644
index 0000000..bf767ade
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [8, 341, 500, 167],
+        [8, 8, 500, 167],
+        [8, 175, 500, 166]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/repaint-subrect-grid-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/repaint-subrect-grid-expected.txt
new file mode 100644
index 0000000..e128fc2
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/repaint-subrect-grid-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [18, 37, 19, 18],
+        [18, 0, 19, 18],
+        [46, 18, 18, 19],
+        [28, 18, 18, 19],
+        [9, 18, 18, 19],
+        [37, 37, 18, 18],
+        [37, 0, 18, 18],
+        [0, 37, 18, 18],
+        [0, 0, 18, 18],
+        [0, 18, 9, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
index 5ac61c0..7fe3897 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tr-visible-td-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tr-visible-td-expected.txt
index 5ac61c0..7fe3897 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/invisible-tr-visible-td-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-expected.txt
similarity index 87%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-expected.txt
index 5ac61c0..649c1df 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [10, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-offset-expected.txt
similarity index 86%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-offset-expected.txt
index 5ac61c0..87a1409 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/table-col-background-offset-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [114, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
index 5ac61c0..e976dd3d 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [11, 46, 100, 25]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
index 5ac61c0..090fa790 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [85, 70, 90, 91]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/vertical-align1-expected.txt
similarity index 66%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/vertical-align1-expected.txt
index 5ac61c0..7a4b120 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/backface-visibility-interop/paint/invalidation/vertical-align1-expected.txt
@@ -6,7 +6,10 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [120, 80, 20, 20],
+        [120, 34, 20, 20],
+        [0, 80, 20, 20],
+        [0, 34, 20, 20]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/virtual/dark-mode-default/dark-mode/images/gradient-expected.png b/third_party/blink/web_tests/virtual/dark-mode-default/dark-mode/images/gradient-expected.png
index c024f62a..da69f70 100644
--- a/third_party/blink/web_tests/virtual/dark-mode-default/dark-mode/images/gradient-expected.png
+++ b/third_party/blink/web_tests/virtual/dark-mode-default/dark-mode/images/gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/dark-mode-images-filter-all/dark-mode/images/gradient-expected.png b/third_party/blink/web_tests/virtual/dark-mode-images-filter-all/dark-mode/images/gradient-expected.png
index c024f62a..da69f70 100644
--- a/third_party/blink/web_tests/virtual/dark-mode-images-filter-all/dark-mode/images/gradient-expected.png
+++ b/third_party/blink/web_tests/virtual/dark-mode-images-filter-all/dark-mode/images/gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/dark-mode-images-filter-none/dark-mode/images/gradient-expected.png b/third_party/blink/web_tests/virtual/dark-mode-images-filter-none/dark-mode/images/gradient-expected.png
index c024f62a..da69f70 100644
--- a/third_party/blink/web_tests/virtual/dark-mode-images-filter-none/dark-mode/images/gradient-expected.png
+++ b/third_party/blink/web_tests/virtual/dark-mode-images-filter-none/dark-mode/images/gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/dark-mode-images-grayscale/dark-mode/images/gradient-expected.png b/third_party/blink/web_tests/virtual/dark-mode-images-grayscale/dark-mode/images/gradient-expected.png
index 82de5789..da69f70 100644
--- a/third_party/blink/web_tests/virtual/dark-mode-images-grayscale/dark-mode/images/gradient-expected.png
+++ b/third_party/blink/web_tests/virtual/dark-mode-images-grayscale/dark-mode/images/gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/block-shift-repaint-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/block-shift-repaint-expected.txt
new file mode 100644
index 0000000..34c70dd6
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/block-shift-repaint-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [8, 248, 60, 30],
+        [8, 218, 60, 30],
+        [8, 188, 60, 30],
+        [8, 158, 60, 30],
+        [8, 128, 60, 30],
+        [8, 98, 60, 30],
+        [8, 68, 60, 30],
+        [8, 38, 60, 30],
+        [8, 8, 60, 30],
+        [8, 353, 60, 8],
+        [8, 338, 60, 8]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
new file mode 100644
index 0000000..49006ad
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -0,0 +1,39 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [200, 200],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV)",
+      "position": [42, 42],
+      "bounds": [251, 251],
+      "backgroundColor": "#FF0000",
+      "invalidations": [
+        [50, 50, 200, 200]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [8, 8, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-rtl-column-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
new file mode 100644
index 0000000..977c73cb0
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
@@ -0,0 +1,18 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [8, 116, 200, 252],
+        [8, 68, 200, 145],
+        [13, 218, 190, 350],
+        [13, 125, 190, 350],
+        [13, 121, 190, 350]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/iframe-rounding-expected.txt
similarity index 87%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/iframe-rounding-expected.txt
index 5ac61c0..98e8df68 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/iframe-rounding-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [20, 18, 100, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
new file mode 100644
index 0000000..bf767ade
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/multicol/multicol-with-overflowing-block-rl-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [8, 341, 500, 167],
+        [8, 8, 500, 167],
+        [8, 175, 500, 166]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/repaint-subrect-grid-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/repaint-subrect-grid-expected.txt
new file mode 100644
index 0000000..e128fc2
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/repaint-subrect-grid-expected.txt
@@ -0,0 +1,23 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [18, 37, 19, 18],
+        [18, 0, 19, 18],
+        [46, 18, 18, 19],
+        [28, 18, 18, 19],
+        [9, 18, 18, 19],
+        [37, 37, 18, 18],
+        [37, 0, 18, 18],
+        [0, 37, 18, 18],
+        [0, 0, 18, 18],
+        [0, 18, 9, 19]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
index 5ac61c0..7fe3897 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tbody-visible-td-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tr-visible-td-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tr-visible-td-expected.txt
index 5ac61c0..7fe3897 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/invisible-tr-visible-td-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [9, 9, 99, 198]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-expected.txt
similarity index 87%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-expected.txt
index 5ac61c0..649c1df 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [10, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-offset-expected.txt
similarity index 86%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-offset-expected.txt
index 5ac61c0..87a1409 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/table-col-background-offset-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [114, 110, 102, 100]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
index 5ac61c0..e976dd3d 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/table/table-two-pass-layout-overpaint-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [11, 46, 100, 25]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
similarity index 88%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
index 5ac61c0..090fa790 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/transform/invalidation-with-scale-transform-expected.txt
@@ -6,7 +6,7 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [85, 70, 90, 91]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/vertical-align1-expected.txt
similarity index 66%
copy from third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
copy to third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/vertical-align1-expected.txt
index 5ac61c0..7a4b120 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/table/table-row-expected.txt
+++ b/third_party/blink/web_tests/virtual/transform-interop-disabled/paint/invalidation/vertical-align1-expected.txt
@@ -6,7 +6,10 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [8, 10, 106, 100]
+        [120, 80, 20, 20],
+        [120, 34, 20, 20],
+        [0, 80, 20, 20],
+        [0, 34, 20, 20]
       ]
     }
   ]
diff --git a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-query-config.https.tenative.html b/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-query-config.https.tenative.html
index 51505c6..71e25fa 100644
--- a/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-query-config.https.tenative.html
+++ b/third_party/blink/web_tests/wpt_internal/sanitizer-api/sanitizer-query-config.https.tenative.html
@@ -21,23 +21,23 @@
 
   test(t => {
     // Quick sanity test: Test a few default values.
-    assert_in_array("div", Sanitizer.defaultConfig().allowElements);
-    assert_false(Sanitizer.defaultConfig().allowElements.includes("script"));
-    assert_false(Sanitizer.defaultConfig().allowElements.includes("noscript"));
+    assert_in_array("div", Sanitizer.getDefaultConfiguration().allowElements);
+    assert_false(Sanitizer.getDefaultConfiguration().allowElements.includes("script"));
+    assert_false(Sanitizer.getDefaultConfiguration().allowElements.includes("noscript"));
 
-    assert_true("span" in Sanitizer.defaultConfig().allowAttributes);
-    assert_false("onclick" in Sanitizer.defaultConfig().allowAttributes);
+    assert_true("span" in Sanitizer.getDefaultConfiguration().allowAttributes);
+    assert_false("onclick" in Sanitizer.getDefaultConfiguration().allowAttributes);
 
-    assert_false("dropElements" in Sanitizer.defaultConfig());
-    assert_false("blockElements" in Sanitizer.defaultConfig());
-    assert_false("dropAttributes" in Sanitizer.defaultConfig());
-    assert_false(Sanitizer.defaultConfig().allowCustomElements);
-  }, "SanitizerAPI defaultConfig()");
+    assert_false("dropElements" in Sanitizer.getDefaultConfiguration());
+    assert_false("blockElements" in Sanitizer.getDefaultConfiguration());
+    assert_false("dropAttributes" in Sanitizer.getDefaultConfiguration());
+    assert_false(Sanitizer.getDefaultConfiguration().allowCustomElements);
+  }, "SanitizerAPI getDefaultConfiguration()");
 
   test(t => {
-    assert_deep_equals(Sanitizer.defaultConfig(),
-                       new Sanitizer().config());
-  }, "SanitizerAPI config() on default created Sanitizer");
+    assert_deep_equals(Sanitizer.getDefaultConfiguration(),
+                       new Sanitizer().getConfiguration());
+  }, "SanitizerAPI getConfiguration() on default created Sanitizer");
 
   test(t => {
     const configs = [{
@@ -52,8 +52,8 @@
       allowCustomElements: false,
     }];
     for (const config of configs)
-      assert_deep_equals(config, new Sanitizer(config).config());
-  }, "SanitizerAPI config() reflects creation config.");
+      assert_deep_equals(config, new Sanitizer(config).getConfiguration());
+  }, "SanitizerAPI getConfiguration() reflects creation config.");
 </script>
 </body>
 </html>
diff --git a/third_party/closure_compiler/externs/users_private.js b/third_party/closure_compiler/externs/users_private.js
index 2ba7185c..ca7c745 100644
--- a/third_party/closure_compiler/externs/users_private.js
+++ b/third_party/closure_compiler/externs/users_private.js
@@ -20,7 +20,6 @@
  *   displayEmail: string,
  *   name: string,
  *   isOwner: boolean,
- *   isSupervised: boolean,
  *   isChild: boolean
  * }}
  */
diff --git a/third_party/zlib/google/zip_internal.cc b/third_party/zlib/google/zip_internal.cc
index 354fbf8..653a2ab 100644
--- a/third_party/zlib/google/zip_internal.cc
+++ b/third_party/zlib/google/zip_internal.cc
@@ -243,7 +243,7 @@
 // Returns a zip_fileinfo struct with the time represented by |file_time|.
 zip_fileinfo TimeToZipFileInfo(const base::Time& file_time) {
   base::Time::Exploded file_time_parts;
-  file_time.LocalExplode(&file_time_parts);
+  file_time.UTCExplode(&file_time_parts);
 
   zip_fileinfo zip_info = {};
   if (file_time_parts.year >= 1980) {
diff --git a/third_party/zlib/google/zip_reader.cc b/third_party/zlib/google/zip_reader.cc
index 1910cf2..8ddd8df 100644
--- a/third_party/zlib/google/zip_reader.cc
+++ b/third_party/zlib/google/zip_reader.cc
@@ -129,7 +129,7 @@
   exploded_time.second = raw_file_info.tmu_date.tm_sec;
   exploded_time.millisecond = 0;
 
-  if (!base::Time::FromLocalExploded(exploded_time, &last_modified_))
+  if (!base::Time::FromUTCExploded(exploded_time, &last_modified_))
     last_modified_ = base::Time::UnixEpoch();
 }
 
diff --git a/third_party/zlib/google/zip_reader_unittest.cc b/third_party/zlib/google/zip_reader_unittest.cc
index b203cb5..e5bb4b4 100644
--- a/third_party/zlib/google/zip_reader_unittest.cc
+++ b/third_party/zlib/google/zip_reader_unittest.cc
@@ -288,7 +288,7 @@
 
   // The expected time stamp: 2009-05-29 06:22:20
   base::Time::Exploded exploded = {};  // Zero-clear.
-  current_entry_info->last_modified().LocalExplode(&exploded);
+  current_entry_info->last_modified().UTCExplode(&exploded);
   EXPECT_EQ(2009, exploded.year);
   EXPECT_EQ(5, exploded.month);
   EXPECT_EQ(29, exploded.day_of_month);
@@ -357,7 +357,7 @@
 
   // The expected time stamp: 2009-05-31 15:49:52
   base::Time::Exploded exploded = {};  // Zero-clear.
-  current_entry_info->last_modified().LocalExplode(&exploded);
+  current_entry_info->last_modified().UTCExplode(&exploded);
   EXPECT_EQ(2009, exploded.year);
   EXPECT_EQ(5, exploded.month);
   EXPECT_EQ(31, exploded.day_of_month);
diff --git a/third_party/zlib/google/zip_unittest.cc b/third_party/zlib/google/zip_unittest.cc
index 2d2e66a..03d389e 100644
--- a/third_party/zlib/google/zip_unittest.cc
+++ b/third_party/zlib/google/zip_unittest.cc
@@ -297,11 +297,11 @@
     // supports, which is 2 seconds. Note that between this call to Time::Now()
     // and zip::Zip() the clock can advance a bit, hence the use of EXPECT_GE.
     base::Time::Exploded now_parts;
-    base::Time::Now().LocalExplode(&now_parts);
+    base::Time::Now().UTCExplode(&now_parts);
     now_parts.second = now_parts.second & ~1;
     now_parts.millisecond = 0;
     base::Time now_time;
-    EXPECT_TRUE(base::Time::FromLocalExploded(now_parts, &now_time));
+    EXPECT_TRUE(base::Time::FromUTCExploded(now_parts, &now_time));
 
     EXPECT_EQ(1, base::WriteFile(src_file, "1", 1));
     EXPECT_TRUE(base::TouchFile(src_file, base::Time::Now(), test_mtime));
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 0fc9f04..4d5289c 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -39,8 +39,8 @@
 # https://chromium.googlesource.com/chromium/src/+/main/docs/updating_clang.md
 # Reverting problematic clang rolls is safe, though.
 # This is the output of `git describe` and is usable as a commit-ish.
-CLANG_REVISION = 'llvmorg-13-init-14732-g8a7b5ebf'
-CLANG_SUB_REVISION = 2
+CLANG_REVISION = 'llvmorg-13-init-15040-gc10947b5'
+CLANG_SUB_REVISION = 1
 
 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION)
 RELEASE_VERSION = '13.0.0'
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 2aa500c..5a24f1e0 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -996,6 +996,13 @@
   <int value="5" label="Request was cancelled"/>
 </enum>
 
+<enum name="AccountCapabilitiesGetFromSystemLibraryResult">
+  <int value="0" label="Success"/>
+  <int value="1" label="Error (Generic)"/>
+  <int value="20" label="Error (Missing Capability)"/>
+  <int value="21" label="Error (Unexpected Value)"/>
+</enum>
+
 <enum name="AccountChooserDismissalReason">
   <int value="0" label="Canceled"/>
   <int value="1" label="Credential chosen"/>
@@ -20056,7 +20063,6 @@
   <int value="108" label="Extension install friction"/>
   <int value="109" label="File handling permission request"/>
   <int value="110" label="Enterprise confirmation"/>
-  <int value="111" label="App Identity Update Confirmation"/>
 </enum>
 
 <enum name="DialogOriginRelationship">
@@ -27072,9 +27078,10 @@
   <int value="445" label="PRINTING_ON_JOB_STATUS_CHANGED"/>
   <int value="446" label="DECLARATIVE_NET_REQUEST_ON_RULE_MATCHED_DEBUG"/>
   <int value="447" label="TERMINAL_PRIVATE_ON_SETTINGS_CHANGED"/>
-  <int value="448" label="AUTOFILL_ASSISTANT_PRIVATE_ON_ACTIONS_CHANGED"/>
+  <int value="448"
+      label="DELETED_AUTOFILL_ASSISTANT_PRIVATE_ON_ACTIONS_CHANGED"/>
   <int value="449"
-      label="AUTOFILL_ASSISTANT_PRIVATE_ON_STATUS_MESSAGE_CHANGED"/>
+      label="DELETED_AUTOFILL_ASSISTANT_PRIVATE_ON_STATUS_MESSAGE_CHANGED"/>
   <int value="450" label="BLUETOOTH_PRIVATE_ON_DEVICE_ADDRESS_CHANGED"/>
   <int value="451"
       label="PASSWORDS_PRIVATE_ON_ACCOUNT_STORAGE_OPT_IN_STATE_CHANGED"/>
@@ -28617,11 +28624,11 @@
   <int value="1435" label="PRINTING_SUBMITJOB"/>
   <int value="1436" label="IDENTITYPRIVATE_SETCONSENTRESULT"/>
   <int value="1437" label="PRINTING_CANCELJOB"/>
-  <int value="1438" label="AUTOFILLASSISTANTPRIVATE_CREATE"/>
-  <int value="1439" label="AUTOFILLASSISTANTPRIVATE_START"/>
-  <int value="1440" label="AUTOFILLASSISTANTPRIVATE_GETSTATE"/>
-  <int value="1441" label="AUTOFILLASSISTANTPRIVATE_PERFORMACTION"/>
-  <int value="1442" label="AUTOFILLASSISTANTPRIVATE_PROVIDEUSERDATA"/>
+  <int value="1438" label="DELETED_AUTOFILLASSISTANTPRIVATE_CREATE"/>
+  <int value="1439" label="DELETED_AUTOFILLASSISTANTPRIVATE_START"/>
+  <int value="1440" label="DELETED_AUTOFILLASSISTANTPRIVATE_GETSTATE"/>
+  <int value="1441" label="DELETED_AUTOFILLASSISTANTPRIVATE_PERFORMACTION"/>
+  <int value="1442" label="DELETED_AUTOFILLASSISTANTPRIVATE_PROVIDEUSERDATA"/>
   <int value="1443" label="PASSWORDSPRIVATE_ISOPTEDINFORACCOUNTSTORAGE"/>
   <int value="1444" label="AUTOTESTPRIVATE_PINSHELFICON"/>
   <int value="1445" label="AUTOTESTPRIVATE_WAITFOROVERVIEWSTATE"/>
@@ -29360,7 +29367,7 @@
   <int value="223" label="kPrintingMetrics"/>
   <int value="224" label="kPrinting"/>
   <int value="225" label="kCrashReportPrivate"/>
-  <int value="226" label="kAutofillAssistantPrivate"/>
+  <int value="226" label="kDeleted_AutofillAssistantPrivate"/>
   <int value="227" label="kEnterpriseNetworkingAttributes"/>
   <int value="228" label="kSearch"/>
   <int value="229" label="kTabGroups"/>
@@ -43106,6 +43113,9 @@
   <int value="16" label="Add to Bookmarks"/>
   <int value="17" label="Close Tab"/>
   <int value="18" label="Edit Bookmark"/>
+  <int value="19" label="Save"/>
+  <int value="20" label="Open in Current Tab"/>
+  <int value="21" label="Search Image"/>
 </enum>
 
 <enum name="IOSMenuScenario">
@@ -47680,7 +47690,6 @@
   <int value="-880087793" label="OmniboxPedalsBatch2:enabled"/>
   <int value="-879055117" label="ClipboardContentSetting:enabled"/>
   <int value="-879031960" label="FetchKeepaliveTimeoutSetting:disabled"/>
-  <int value="-879024703" label="pwa-update-dialog-for-name-and-icon:enabled"/>
   <int value="-876773120" label="TabbedAppOverflowMenuActionBar:enabled"/>
   <int value="-876148583" label="ArcBootCompletedBroadcast:disabled"/>
   <int value="-875217114"
@@ -50588,7 +50597,6 @@
   <int value="1569982806" label="BentoBar:enabled"/>
   <int value="1570178909" label="NewOverviewLayout:enabled"/>
   <int value="1571998166" label="DetectingHeavyPages:disabled"/>
-  <int value="1572464760" label="pwa-update-dialog-for-name-and-icon:disabled"/>
   <int value="1573860827" label="EnableImeSandbox:enabled"/>
   <int value="1575978252" label="PasswordLeakDetection:enabled"/>
   <int value="1577205328"
@@ -73581,7 +73589,7 @@
   <int value="1" label="Guest"/>
   <int value="2" label="New Regular"/>
   <int value="3" label="Public Account"/>
-  <int value="4" label="Locally Managed"/>
+  <int value="4" label="(Obsolete) Locally Managed"/>
   <int value="5" label="Kiosk App"/>
   <int value="6" label="Regular Supervised"/>
   <int value="7" label="ARC Kiosk"/>
@@ -82580,7 +82588,7 @@
   <int value="1" label="Guest"/>
   <int value="2" label="Retail Mode"/>
   <int value="3" label="Public Account"/>
-  <int value="4" label="Locally Managed"/>
+  <int value="4" label="(Obsolete) Locally Managed"/>
   <int value="5" label="Kiosk App"/>
   <int value="6" label="Regular Supervised"/>
   <int value="7" label="ARC Kiosk"/>
diff --git a/tools/metrics/histograms/histograms_xml/signin/histograms.xml b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
index 257eaff..e4401cb 100644
--- a/tools/metrics/histograms/histograms_xml/signin/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/signin/histograms.xml
@@ -78,6 +78,21 @@
   </token>
 </histogram>
 
+<histogram name="Signin.AccountCapabilities.GetFromSystemLibraryResult"
+    enum="AccountCapabilitiesGetFromSystemLibraryResult"
+    expires_after="2021-12-31">
+  <owner>aliceywang@chromium.org</owner>
+  <owner>fernandex@chromium.org</owner>
+  <owner>msarda@chromium.org</owner>
+  <owner>triploblastic@chromium.org</owner>
+  <owner>chrome-signin-team@google.com</owner>
+  <summary>
+    This histogram records the outcome of the account capabilities fetch
+    operation. This is recorded only on Android and iOS where Chrome fetches the
+    account capabilities from the system library.
+  </summary>
+</histogram>
+
 <histogram name="Signin.AccountConsistencyPromoAction"
     enum="AccountConsistencyPromoAction" expires_after="2022-01-02">
   <owner>bsazonov@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 3fc1b4c..2cda690 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,16 +1,16 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "fc16465bcb6efa46ecace50ff0e6652677606407",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/71d582b360331087630937eaec1d194f0c0b78fb/trace_processor_shell.exe"
+            "hash": "b1b2bf383645661b4c6790657863c46cec02121d",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/10a3658d9f6b470ba970e2bea95f19b1fd2e9cf2/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "ddc997a4e4f511df26d68ef6fbf625057bfc1e41",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/71d582b360331087630937eaec1d194f0c0b78fb/trace_processor_shell"
+            "hash": "430c7a66ec2369760e6bb6a27174d7229b4f9fcf",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/10a3658d9f6b470ba970e2bea95f19b1fd2e9cf2/trace_processor_shell"
         },
         "linux": {
-            "hash": "48cdc66c153d782040e5d700f46ec65465f591e6",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/71d582b360331087630937eaec1d194f0c0b78fb/trace_processor_shell"
+            "hash": "d1a365306fac2e7d54fa5e336286811d2d7f6252",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/10a3658d9f6b470ba970e2bea95f19b1fd2e9cf2/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index 74c9fcf..a93d625 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -91,16 +91,6 @@
 bool IsIChromeAccessibleEnabled() {
   return base::FeatureList::IsEnabled(::features::kIChromeAccessible);
 }
-
-const base::Feature kSelectiveUIAEnablement{"SelectiveUIAEnablement",
-                                            base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Returns true if accessibility will be selectively enabled depending on the
-// UIA APIs that are called, allowing non-screenreader usage to enable less of
-// the accessibility system.
-bool IsSelectiveUIAEnablementEnabled() {
-  return base::FeatureList::IsEnabled(::features::kSelectiveUIAEnablement);
-}
 #endif  // defined(OS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h
index 2cfd580..8b081a1 100644
--- a/ui/accessibility/accessibility_features.h
+++ b/ui/accessibility/accessibility_features.h
@@ -75,13 +75,6 @@
 // Returns true if the IChromeAccessible COM API is enabled.
 AX_BASE_EXPORT bool IsIChromeAccessibleEnabled();
 
-AX_BASE_EXPORT extern const base::Feature kSelectiveUIAEnablement;
-
-// Returns true if accessibility will be selectively enabled depending on the
-// UIA APIs that are called, allowing non-screenreader usage to enable less of
-// the accessibility system.
-AX_BASE_EXPORT bool IsSelectiveUIAEnablementEnabled();
-
 #endif  // defined(OS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/ui/accessibility/ax_mode.h b/ui/accessibility/ax_mode.h
index 0bb0d50..6bac8eb 100644
--- a/ui/accessibility/ax_mode.h
+++ b/ui/accessibility/ax_mode.h
@@ -121,13 +121,6 @@
                                         AXMode::kInlineTextBoxes |
                                         AXMode::kScreenReader | AXMode::kHTML);
 
-// Similar to kAXModeComplete, used when an AT that requires full accessibility
-// access, but does not need all HTML properties or attributes.
-static constexpr AXMode kAXModeCompleteNoHTML(AXMode::kNativeAPIs |
-                                              AXMode::kWebContents |
-                                              AXMode::kInlineTextBoxes |
-                                              AXMode::kScreenReader);
-
 // For debugging, test assertions, etc.
 AX_BASE_EXPORT std::ostream& operator<<(std::ostream& stream,
                                         const AXMode& mode);
diff --git a/ui/accessibility/platform/ax_fragment_root_win.cc b/ui/accessibility/platform/ax_fragment_root_win.cc
index fa7624a..7a180e4 100644
--- a/ui/accessibility/platform/ax_fragment_root_win.cc
+++ b/ui/accessibility/platform/ax_fragment_root_win.cc
@@ -326,7 +326,7 @@
   // Automation. Signal observers when we're asked for a platform object on it.
   for (WinAccessibilityAPIUsageObserver& observer :
        GetWinAccessibilityAPIUsageObserverList()) {
-    observer.OnBasicUIAutomationUsed();
+    observer.OnUIAutomationUsed();
   }
   return platform_node_.Get();
 }
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index c727ff3..6fb0a48 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -4185,7 +4185,6 @@
                                                      IUnknown** result) {
   WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_PATTERN_PROVIDER);
   WIN_ACCESSIBILITY_API_PERF_HISTOGRAM(UMA_API_GET_PATTERN_PROVIDER);
-  NotifyAPIObserverForPatternRequest(pattern_id);
   return GetPatternProviderImpl(pattern_id, result);
 }
 
@@ -4218,9 +4217,6 @@
     // Collapse all unknown property IDs into a single bucket.
     base::UmaHistogramSparse("Accessibility.WinAPIs.GetPropertyValue", 0);
   }
-
-  NotifyAPIObserverForPropertyRequest(property_id);
-
   return GetPropertyValueImpl(property_id, result);
 }
 
@@ -8234,92 +8230,6 @@
   SanitizeStringAttributeForIA2(input, output);
 }
 
-void AXPlatformNodeWin::NotifyAPIObserverForPatternRequest(
-    PATTERNID pattern_id) const {
-  bool probable_advanced_client_detected = false;
-  bool text_pattern_support_needed = false;
-  switch (pattern_id) {
-    case UIA_TextPatternId:
-    case UIA_TextChildPatternId:
-      // These properties require information gated behind the kInlineTextBoxes
-      // AXMode. See kInlineTextBoxes for details.
-      text_pattern_support_needed = true;
-      break;
-    // These properties require more advanced accessibility features to be
-    // enabled See kScreenReader for details.
-    case UIA_RangeValuePatternId:
-    case UIA_TableItemPatternId:
-      probable_advanced_client_detected = true;
-      break;
-  }
-
-  for (WinAccessibilityAPIUsageObserver& observer :
-       GetWinAccessibilityAPIUsageObserverList()) {
-    if (probable_advanced_client_detected)
-      observer.OnAdvancedUIAutomationUsed();
-    if (text_pattern_support_needed)
-      observer.OnTextPatternRequested();
-  }
-}
-void AXPlatformNodeWin::NotifyAPIObserverForPropertyRequest(
-    PROPERTYID property_id) const {
-  bool probable_advanced_client_detected = false;
-  bool probable_screen_reader_detected = false;
-  switch (property_id) {
-    // These properties are used by non-screenreader UIA clients. They should
-    // not cause additional enablement.
-    case UIA_ControlTypePropertyId:
-    case UIA_HasKeyboardFocusPropertyId:
-    case UIA_IsControlElementPropertyId:
-    case UIA_FrameworkIdPropertyId:
-    case UIA_IsEnabledPropertyId:
-      break;
-    //  These properties are not currently implemented and should not cause
-    //  enablement.
-    case UIA_AnnotationTypesPropertyId:
-    case UIA_CenterPointPropertyId:
-    case UIA_FillColorPropertyId:
-    case UIA_FillTypePropertyId:
-    case UIA_HeadingLevelPropertyId:
-    case UIA_ItemTypePropertyId:
-    case UIA_OutlineColorPropertyId:
-    case UIA_OutlineThicknessPropertyId:
-    case UIA_RotationPropertyId:
-    case UIA_SizePropertyId:
-    case UIA_VisualEffectsPropertyId:
-      break;
-    // These properties are provided by UIA Core; we should not implement, and
-    // they should not cause enablement.
-    case UIA_BoundingRectanglePropertyId:
-    case UIA_NativeWindowHandlePropertyId:
-    case UIA_ProcessIdPropertyId:
-    case UIA_ProviderDescriptionPropertyId:
-    case UIA_RuntimeIdPropertyId:
-      break;
-    // These properties are indicative of a screenreader, we should enable full
-    // accessibility support.
-    case UIA_AriaRolePropertyId:
-    case UIA_LabeledByPropertyId:
-    case UIA_LiveSettingPropertyId:
-    case UIA_LevelPropertyId:
-    case UIA_DescribedByPropertyId:
-      probable_screen_reader_detected = true;
-      probable_advanced_client_detected = true;
-      break;
-    default:
-      // All other properties should cause us to enable.
-      probable_advanced_client_detected = true;
-  }
-
-  for (WinAccessibilityAPIUsageObserver& observer :
-       GetWinAccessibilityAPIUsageObserverList()) {
-    if (probable_advanced_client_detected)
-      observer.OnAdvancedUIAutomationUsed();
-    if (probable_screen_reader_detected)
-      observer.OnProbableUIAutomationScreenReaderDetected();
-  }
-}
-
 // static
 void AXPlatformNodeWin::SanitizeStringAttributeForIA2(const std::string& input,
                                                       std::string* output) {
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index 91f114d..84a21ed 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -341,10 +341,7 @@
   virtual void OnIAccessible2Used() = 0;
   virtual void OnScreenReaderHoneyPotQueried() = 0;
   virtual void OnAccNameCalled() = 0;
-  virtual void OnBasicUIAutomationUsed() = 0;
-  virtual void OnAdvancedUIAutomationUsed() = 0;
-  virtual void OnProbableUIAutomationScreenReaderDetected() = 0;
-  virtual void OnTextPatternRequested() = 0;
+  virtual void OnUIAutomationUsed() = 0;
   virtual void StartFiringUIAEvents() = 0;
   virtual void EndFiringUIAEvents() = 0;
 };
@@ -1473,9 +1470,6 @@
       const std::wstring& active_composition_text,
       bool is_composition_committed);
 
-  void NotifyAPIObserverForPatternRequest(PATTERNID pattern_id) const;
-  void NotifyAPIObserverForPropertyRequest(PROPERTYID property_id) const;
-
   // Return true if the given element is valid enough to be returned as a value
   // for a UIA relation property (e.g. ControllerFor).
   static bool IsValidUiaRelationTarget(AXPlatformNode* ax_platform_node);
diff --git a/ui/base/ime/chromeos/input_method_chromeos.cc b/ui/base/ime/chromeos/input_method_chromeos.cc
index cf849cf5..75bd936 100644
--- a/ui/base/ime/chromeos/input_method_chromeos.cc
+++ b/ui/base/ime/chromeos/input_method_chromeos.cc
@@ -133,7 +133,7 @@
       if (ExecuteCharacterComposer(*event)) {
         // Treating as PostIME event if character composer handles key event and
         // generates some IME event,
-        return ProcessKeyEventPostIME(event, false,
+        return ProcessKeyEventPostIME(event,
                                       /* handled */ true,
                                       /* stopped_propagation */ true);
       }
@@ -166,7 +166,7 @@
     }
   }
   if (event->type() == ET_KEY_PRESSED || event->type() == ET_KEY_RELEASED) {
-    ignore_result(ProcessKeyEventPostIME(event, false, is_handled,
+    ignore_result(ProcessKeyEventPostIME(event, is_handled,
                                          /* stopped_propagation */ false));
   }
   handling_key_event_ = false;
@@ -511,7 +511,6 @@
 
 ui::EventDispatchDetails InputMethodChromeOS::ProcessKeyEventPostIME(
     ui::KeyEvent* event,
-    bool skip_process_filtered,
     bool handled,
     bool stopped_propagation) {
   TextInputClient* client = GetTextInputClient();
@@ -521,7 +520,7 @@
     return DispatchKeyEventPostIME(event);
   }
 
-  if (event->type() == ET_KEY_PRESSED && handled && !skip_process_filtered) {
+  if (event->type() == ET_KEY_PRESSED && handled) {
     ui::EventDispatchDetails dispatch_details =
         ProcessFilteredKeyPressEvent(event);
     if (event->stopped_propagation()) {
diff --git a/ui/base/ime/chromeos/input_method_chromeos.h b/ui/base/ime/chromeos/input_method_chromeos.h
index 3fb7169ba..899513e9 100644
--- a/ui/base/ime/chromeos/input_method_chromeos.h
+++ b/ui/base/ime/chromeos/input_method_chromeos.h
@@ -90,7 +90,6 @@
   // Process a key returned from the input method.
   virtual ui::EventDispatchDetails ProcessKeyEventPostIME(
       ui::KeyEvent* event,
-      bool skip_process_filtered,
       bool handled,
       bool stopped_propagation) WARN_UNUSED_RESULT;
 
diff --git a/ui/base/ime/chromeos/input_method_chromeos_unittest.cc b/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
index cef1ef6..abb4023 100644
--- a/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
+++ b/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
@@ -74,17 +74,14 @@
   // Overridden from InputMethodChromeOS:
   ui::EventDispatchDetails ProcessKeyEventPostIME(
       ui::KeyEvent* key_event,
-      bool skip_process_filtered,
       bool handled,
       bool stopped_propagation) override {
     ui::EventDispatchDetails details =
-        InputMethodChromeOS::ProcessKeyEventPostIME(
-            key_event, skip_process_filtered, handled, stopped_propagation);
-    if (!skip_process_filtered) {
-      process_key_event_post_ime_args_.event = *key_event;
-      process_key_event_post_ime_args_.handled = handled;
-      ++process_key_event_post_ime_call_count_;
-    }
+        InputMethodChromeOS::ProcessKeyEventPostIME(key_event, handled,
+                                                    stopped_propagation);
+    process_key_event_post_ime_args_.event = *key_event;
+    process_key_event_post_ime_args_.handled = handled;
+    ++process_key_event_post_ime_call_count_;
     return details;
   }
   void CommitText(
@@ -1155,7 +1152,7 @@
                       0,
                       DomKey::DeadKeyFromCombiningCharacter('^'),
                       EventTimeForNow());
-  ime_->ProcessKeyEventPostIME(&eventA, false, true, true);
+  ime_->ProcessKeyEventPostIME(&eventA, true, true);
 
   const ui::KeyEvent& key_event = dispatched_key_event_;
 
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index 4004814..50e5cab8 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -244,9 +244,6 @@
     Unable to view Linux files
   </message>
 
-  <message name="IDS_FILE_BROWSER_EMPTY_FOLDER" desc="Label shown in an empty folder.">
-    Nothing to see here...
-  </message>
   <message name="IDS_FILE_BROWSER_NEW_FOLDER_BUTTON_LABEL" desc="Label on the 'New folder' button.">
     New folder
   </message>
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index 1a88e82..20625fb 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -249,6 +249,16 @@
   }
 
   /**
+   * @return {boolean} True if it's on a Linux native volume.
+   */
+  isOnNative() {
+    const rootType = this.getCurrentRootType();
+    return rootType != null && !util.isRecentRootType(rootType) &&
+        VolumeManagerCommon.VolumeType.isNative(
+            VolumeManagerCommon.getVolumeTypeFromRootType(rootType));
+  }
+
+  /**
    * @param {VolumeManagerCommon.VolumeType} volumeType Volume Type
    * @return {boolean} True if current root volume type is equal to specified
    *     volume type.
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 2df4358..3a43a3c 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
@@ -2204,7 +2204,7 @@
 
     // TODO(crbug/1226915) Make it work with MTP.
     const isOnEligibleLocation =
-        !util.isZipPackEnabled() || !fileManager.directoryModel.isOnMTP();
+        !util.isZipPackEnabled() || fileManager.directoryModel.isOnNative();
 
     event.canExecute = dirEntry && !fileManager.directoryModel.isReadOnly() &&
         isOnEligibleLocation && selection && selection.totalCount > 0;
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index f06aba39..bf16ae6 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -576,10 +576,6 @@
                 <div id="sort-column-asc" hidden>$i18n{COLUMN_ASC_SORT_MESSAGE}</div>
                 <div id="sort-column-desc" hidden>$i18n{COLUMN_DESC_SORT_MESSAGE}</div>
                 <div id="external-link-label" hidden>$i18n{EXTERNAL_LINK_MESSAGE}</div>
-                <div id="empty-folder" hidden>
-                  <div class="image"></div>
-                  <span id="empty-folder-label" class="label">$i18n{EMPTY_FOLDER}</span>
-                </div>
                 <div class="detail-table" id="detail-table" tabindex="0">
                 </div>
                 <grid class="thumbnail-grid" tabindex="0" hidden></grid>
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/BundleLanguageTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/BundleLanguageTest.java
index 0a25b31..82d2a24 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/BundleLanguageTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/BundleLanguageTest.java
@@ -18,6 +18,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.weblayer.TestWebLayer;
 import org.chromium.weblayer.shell.InstrumentationActivity;
 
@@ -28,6 +29,7 @@
 
 /** Tests that translations work correctly for Java strings inside bundles. */
 @RunWith(WebLayerJUnit4ClassRunner.class)
+@DisabledTest(message = "crbug.com/1226712")
 public class BundleLanguageTest {
     private static final String WEBLAYER_SPECIFIC_STRING =
             "string/infobar_missing_location_permission_text";