diff --git a/DEPS b/DEPS
index a343726..03d7e5e 100644
--- a/DEPS
+++ b/DEPS
@@ -299,15 +299,15 @@
   # 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': '504ccf45fba464bf74b396cc686494629f37b718',
+  'skia_revision': 'c1407387eeaf31674891a4d12505970d3237e86f',
   # 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': '5532a667175e9b1a2597111ab674e8ba09c8d505',
+  'v8_revision': 'a6505e5f6d22a63788a3ee59f44ca539774fbe4c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'f5f6704c1cf00faa87a8b55eec0988600a8128e6',
+  'angle_revision': '8d75490aa47bc2be90e8b1bbeaae495bdf0a37e9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -319,7 +319,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '62956948e445c5bc67d3f299e0003c34a3030523',
+  'boringssl_revision': '02bc0949e5cac0e1ee82c6f365f5a6c3cfd0cfa9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
@@ -371,7 +371,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'bbb14e46563c14a055b394f18b117e504e98d4ab',
+  'catapult_revision': '2fa93b2332b7a27c3066bef8d7ba9de2a5e1ab2e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -415,7 +415,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '3ae10bb874bd495b9334b42a1c1bddec00ec53cb',
+  'dawn_revision': 'e9424a009a62bacb7ba8e027bf7c8c3de4fb19d9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -451,7 +451,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling crabbyavif
   # and whatever else without interference from each other.
-  'crabbyavif_revision': '02d0fad2c512380b7270d6e704c86521075d7d54',
+  'crabbyavif_revision': 'b097e11df62db2a6b8561f60aeae0718901122cb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Speedometer main
   # and whatever else without interference from each other.
@@ -519,7 +519,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
-  'llvm_libc_revision':    '27ee0730164e6f101985f057c6ad23a9ba7710f6',
+  'llvm_libc_revision':    '9aefa1cede964571c0b0ef41460cc5c3bbc6b4b8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
@@ -837,143 +837,143 @@
     'objects': [
       {
         # The Android libclang_rt.builtins libraries are currently only included in the Linux clang package.
-        'object_name': 'Linux_x64/clang-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': 'dee83e0a8b35564c277a7902a7872a77f4170b4380f9053acd3e1cb9a502a69c',
-        'size_bytes': 55555048,
-        'generation': 1746105739973602,
+        'object_name': 'Linux_x64/clang-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '5f69279b3697166facfc354634157e0a8a32fa6e36864200ad8a8f85add3f3f6',
+        'size_bytes': 55654416,
+        'generation': 1747138963230938,
         'condition': '(host_os == "linux" or checkout_android) and non_git_source',
       },
       {
-        'object_name': 'Linux_x64/clang-tidy-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': 'bb8684fb985a35cc680bda9161735c409e6409106497f4ec0253ff9e07dd6912',
-        'size_bytes': 13555996,
-        'generation': 1746105739988254,
+        'object_name': 'Linux_x64/clang-tidy-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '9c9cd089b46f36232d7553d03a0b30cf509f5e42b2113fe8172ba14f905b91df',
+        'size_bytes': 13597708,
+        'generation': 1747138963497696,
         'condition': 'host_os == "linux" and checkout_clang_tidy and non_git_source',
       },
       {
-        'object_name': 'Linux_x64/clangd-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '5074d634984fa526b868126ead41c013de337edf36b369422005cb4a0edb95dc',
-        'size_bytes': 13762680,
-        'generation': 1746105740081588,
+        'object_name': 'Linux_x64/clangd-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': 'cf580450a46e262d899c2d48fff2b6ea8f6691a6bcfc0c280f87d8b6da088e5f',
+        'size_bytes': 13854788,
+        'generation': 1747138963598582,
         'condition': 'host_os == "linux" and checkout_clangd and non_git_source',
       },
       {
-        'object_name': 'Linux_x64/llvm-code-coverage-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': 'fa46a9d107f515d0a16c41ae5751a2a4be7be34a550f315a1506fcfb17327936',
-        'size_bytes': 2294512,
-        'generation': 1746105740273331,
+        'object_name': 'Linux_x64/llvm-code-coverage-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '1a3488e55d62bda48d09b69fb4e5267ac64247258dc51fd9dabdb7fe5d66da4c',
+        'size_bytes': 2297996,
+        'generation': 1747138964068040,
         'condition': 'host_os == "linux" and checkout_clang_coverage_tools and non_git_source',
       },
       {
-        'object_name': 'Linux_x64/llvmobjdump-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '4041ca56834653e78338f50aa6590c8160bc6b522bdcddbd533027d9116e4994',
-        'size_bytes': 5694452,
-        'generation': 1746105740224915,
+        'object_name': 'Linux_x64/llvmobjdump-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': 'efb127c69ac198284ff3622cd173e9dc4839d0bed33dbcaa96501db169607a2e',
+        'size_bytes': 5701128,
+        'generation': 1747138963789285,
         'condition': '((checkout_linux or checkout_mac or checkout_android) and host_os == "linux") and non_git_source',
       },
       {
-        'object_name': 'Mac/clang-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '5ee059eddd55064d3e638b83db4c7843f5448bb74c62c474b5f5652a5631cb85',
-        'size_bytes': 51962684,
-        'generation': 1746105741728605,
+        'object_name': 'Mac/clang-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '3d83bd33ae0a0331ba8e23340023ae05174128503d94116cd8a855913fca88c7',
+        'size_bytes': 52212572,
+        'generation': 1747138966013176,
         'condition': 'host_os == "mac" and host_cpu == "x64"',
       },
       {
-        'object_name': 'Mac/clang-mac-runtime-library-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '8482f9c688466057de438a15ff01d62ea1f0e2b709f3e7a470cdd452c81da731',
-        'size_bytes': 989704,
-        'generation': 1746105749642530,
+        'object_name': 'Mac/clang-mac-runtime-library-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '809b6f72718d9bcbf25ad6ab80517f215ed2526435a095ee9bceb5ed40f989a2',
+        'size_bytes': 993800,
+        'generation': 1747138984414942,
         'condition': 'checkout_mac and not host_os == "mac"',
       },
       {
-        'object_name': 'Mac/clang-tidy-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': 'e23d1a41409e2637f662cb9306d3269ea1c4f41ae1aa70f14369b6463de95c03',
-        'size_bytes': 13610744,
-        'generation': 1746105741733748,
+        'object_name': 'Mac/clang-tidy-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': 'c1fd7930eadede03470cbc8d38697669c6254069da2f6bd58328a8654d68f70d',
+        'size_bytes': 13699584,
+        'generation': 1747138966324770,
         'condition': 'host_os == "mac" and host_cpu == "x64" and checkout_clang_tidy',
       },
       {
-        'object_name': 'Mac/clangd-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '6921b4b53cdf8bc80fcad184e229c4f38a49463390016eed65f12fa547f24950',
-        'size_bytes': 14998636,
-        'generation': 1746105741782145,
+        'object_name': 'Mac/clangd-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '3aa82177f6e03da693d93aa9f8052fa669af1bd897359a20eaf01379db0924b8',
+        'size_bytes': 15136432,
+        'generation': 1747138966446697,
         'condition': 'host_os == "mac" and host_cpu == "x64" and checkout_clangd',
       },
       {
-        'object_name': 'Mac/llvm-code-coverage-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '0b41a82139b4a107f1a2a149d438b600685cbab5c0f81c8d0459f2711503460b',
-        'size_bytes': 2263096,
-        'generation': 1746105741945685,
+        'object_name': 'Mac/llvm-code-coverage-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '1f8d0d65f9d027707890c28433b0bfe29e32551008e9f3c1b9803318ede2bfc6',
+        'size_bytes': 2272500,
+        'generation': 1747138966854415,
         'condition': 'host_os == "mac" and host_cpu == "x64" and checkout_clang_coverage_tools',
       },
       {
-        'object_name': 'Mac_arm64/clang-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '99c31f2e700274ade6b25205597510a5c665f17dd9ddaa03b89c9659ec387fd4',
-        'size_bytes': 43999184,
-        'generation': 1746105751053626,
+        'object_name': 'Mac_arm64/clang-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '2d5660c50637a7ee6e5501525e7588bb255cdfd48e792b12b86ae7113c31b8ae',
+        'size_bytes': 44214476,
+        'generation': 1747138986010150,
         'condition': 'host_os == "mac" and host_cpu == "arm64"',
       },
       {
-        'object_name': 'Mac_arm64/clang-tidy-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '78280eb8dceeaa330fb53ec8249c740db0f369f3b6d6857c65337dc5a21b3160',
-        'size_bytes': 11773472,
-        'generation': 1746105751166820,
+        'object_name': 'Mac_arm64/clang-tidy-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': 'c17b6d7d112ff54699477d5fc7f5009e7b650d263d127cad4f8406f8df914996',
+        'size_bytes': 11838956,
+        'generation': 1747138986259606,
         'condition': 'host_os == "mac" and host_cpu == "arm64" and checkout_clang_tidy',
       },
       {
-        'object_name': 'Mac_arm64/clangd-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': 'f2de67c31e6ce01485b4cc0a76567809319021c4523609b93ab1804252f95ddc',
-        'size_bytes': 12044048,
-        'generation': 1746105751239361,
+        'object_name': 'Mac_arm64/clangd-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': 'd6c134df8273fe9c4c2b5ff5786f2ceeb9ed5f251e223e55edbc0cd7aa772e83',
+        'size_bytes': 12115024,
+        'generation': 1747138986359326,
         'condition': 'host_os == "mac" and host_cpu == "arm64" and checkout_clangd',
       },
       {
-        'object_name': 'Mac_arm64/llvm-code-coverage-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': 'a2c44380d13276f1c3393abff82e8d397c893a912b157bea44b0006bd35fe618',
-        'size_bytes': 1974668,
-        'generation': 1746105751515503,
+        'object_name': 'Mac_arm64/llvm-code-coverage-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '82ca9187d1fd5ed14266612339b921d560b1008f92e1719255b755ff882d23e3',
+        'size_bytes': 1982036,
+        'generation': 1747138986831545,
         'condition': 'host_os == "mac" and host_cpu == "arm64" and checkout_clang_coverage_tools',
       },
       {
-        'object_name': 'Win/clang-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '9362a0993354be586748f4148493e2b9cc63a898aa85fea301f2de0e60ecbd93',
-        'size_bytes': 47049060,
-        'generation': 1746105761436952,
+        'object_name': 'Win/clang-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '39e17b8282b9f1e3cbc6b22d3144696728c867f3ae66694b0125c3ed60755401',
+        'size_bytes': 47250032,
+        'generation': 1747139012194774,
         'condition': 'host_os == "win"',
       },
       {
-        'object_name': 'Win/clang-tidy-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': 'c55a73aa688dfa2e6195b1dc233079504f1ed9a95c8e8a92582add133bb8a240',
-        'size_bytes': 13414380,
-        'generation': 1746105761440911,
+        'object_name': 'Win/clang-tidy-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '9dec82a917bd55947e39891137ba5c13663ca94d2c102d56eb52b9b176365910',
+        'size_bytes': 13492960,
+        'generation': 1747139012510054,
         'condition': 'host_os == "win" and checkout_clang_tidy',
       },
       {
-        'object_name': 'Win/clang-win-runtime-library-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': 'c42cfa237dbd6841d61013051de739775fe0ae3187ff5fecc7ed243de2941da6',
-        'size_bytes': 2484424,
-        'generation': 1746105769629959,
+        'object_name': 'Win/clang-win-runtime-library-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '220abd9ce9a85446a2e7879aab3c1f2f5393665f6b13b067f8cec565ae7d36eb',
+        'size_bytes': 2486856,
+        'generation': 1747139033547001,
         'condition': 'checkout_win and not host_os == "win"',
       },
       {
-        'object_name': 'Win/clangd-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': 'fcf5bfeccbca8a2445d579093c9d7da87dff142b223f24f25d87f6e2e6e15c50',
-        'size_bytes': 13840260,
-        'generation': 1746105761501287,
+        'object_name': 'Win/clangd-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '81fa230b6311e3e50147cae3acd6d2c83c1bef13ff46df3df3d580ca911e9d15',
+        'size_bytes': 13918432,
+        'generation': 1747139013351355,
        'condition': 'host_os == "win" and checkout_clangd',
       },
       {
-        'object_name': 'Win/llvm-code-coverage-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '1a5e31c5e69ea7b84fdfbff27024670cf2eec538c68fc4213a5bcf576263b0ca',
-        'size_bytes': 2370540,
-        'generation': 1746105761636379,
+        'object_name': 'Win/llvm-code-coverage-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '611b9689c3d3e80ab7485e698f6b67e0df328b5407f30f177c29fe394b81a13e',
+        'size_bytes': 2378584,
+        'generation': 1747139013764369,
         'condition': 'host_os == "win" and checkout_clang_coverage_tools',
       },
       {
-        'object_name': 'Win/llvmobjdump-llvmorg-21-init-9266-g09006611-2.tar.xz',
-        'sha256sum': '3ac42a8e816d1fa89594bfe882d033b6c351551b055b9d78867a2b3d24ac2451',
-        'size_bytes': 5698696,
-        'generation': 1746105761558030,
+        'object_name': 'Win/llvmobjdump-llvmorg-21-init-11777-gfd3fecfc-1.tar.xz',
+        'sha256sum': '67a05210ee38b2f575df3cc1feb04ed36b4186748c2d769e2201572b413305fe',
+        'size_bytes': 5698204,
+        'generation': 1747139013159526,
         'condition': '(checkout_linux or checkout_mac or checkout_android) and host_os == "win"',
       },
     ]
@@ -984,31 +984,31 @@
     'bucket': 'chromium-browser-clang',
     'objects': [
       {
-        'object_name': 'Linux_x64/rust-toolchain-c8f94230282a8e8c1148f3e657f0199aad909228-1-llvmorg-21-init-9266-g09006611.tar.xz',
-        'sha256sum': '378c432f7739bb5da11aad7b3a2687f8252565eae5f0dcfc55c39a15382c519c',
-        'size_bytes': 118598336,
-        'generation': 1745271335898717,
+        'object_name': 'Linux_x64/rust-toolchain-4a0969e06dbeaaa43914d2d00b2e843d49aa3886-1-llvmorg-21-init-11777-gfd3fecfc.tar.xz',
+        'sha256sum': 'df1573701599cb7d00c1050b71636a436320b8ad47bb09cb46d6e96b3f8ac585',
+        'size_bytes': 118529212,
+        'generation': 1747160498430964,
         'condition': 'host_os == "linux" and non_git_source',
       },
       {
-        'object_name': 'Mac/rust-toolchain-c8f94230282a8e8c1148f3e657f0199aad909228-1-llvmorg-21-init-9266-g09006611.tar.xz',
-        'sha256sum': 'bf05c8b5e90d6904de02dca9b3e4cb5e45a1a56207e7af1fbb3a10707704a26a',
-        'size_bytes': 111932536,
-        'generation': 1745271337336068,
+        'object_name': 'Mac/rust-toolchain-4a0969e06dbeaaa43914d2d00b2e843d49aa3886-1-llvmorg-21-init-11777-gfd3fecfc.tar.xz',
+        'sha256sum': '83836493c8a81b212c20e16666c6b918bff28748f4d6685c5107eb7e9d16f6fe',
+        'size_bytes': 111691772,
+        'generation': 1747160500088595,
         'condition': 'host_os == "mac" and host_cpu == "x64"',
       },
       {
-        'object_name': 'Mac_arm64/rust-toolchain-c8f94230282a8e8c1148f3e657f0199aad909228-1-llvmorg-21-init-9266-g09006611.tar.xz',
-        'sha256sum': '1aec99f479ff28cefe44ed739844833e016a1da255cf3c17d79e59a273246615',
-        'size_bytes': 101605468,
-        'generation': 1745271339727037,
+        'object_name': 'Mac_arm64/rust-toolchain-4a0969e06dbeaaa43914d2d00b2e843d49aa3886-1-llvmorg-21-init-11777-gfd3fecfc.tar.xz',
+        'sha256sum': 'd975e322a2e5c680b54f27a6545c63c0de2c5367ca6ffefda04de491d6b76553',
+        'size_bytes': 102206348,
+        'generation': 1747160501743827,
         'condition': 'host_os == "mac" and host_cpu == "arm64"',
       },
       {
-        'object_name': 'Win/rust-toolchain-c8f94230282a8e8c1148f3e657f0199aad909228-1-llvmorg-21-init-9266-g09006611.tar.xz',
-        'sha256sum': 'b291520613a3ebc415e4576a7fa31d840a5ebf4ab9be6e9dc5d90062dc001c1e',
-        'size_bytes': 193280372,
-        'generation': 1745271341223097,
+        'object_name': 'Win/rust-toolchain-4a0969e06dbeaaa43914d2d00b2e843d49aa3886-1-llvmorg-21-init-11777-gfd3fecfc.tar.xz',
+        'sha256sum': '25c51b4c2e0e8b4e974973f0357b12ecb645a0a7a136f9e0a6604e87c21acc7a',
+        'size_bytes': 193582440,
+        'generation': 1747160503376785,
         'condition': 'host_os == "win"',
       },
     ],
@@ -1486,7 +1486,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '2135957a97f443f1db1b70e4379f0d808684e977',
+    '458624d042c10f66119db1ede7220e141e4eda26',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1978,7 +1978,7 @@
 
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'a9cc320bf761323906c614f7040cb1dc22fcc858',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c273e3eb6202ef710a9cbf48fc99437a56a13631',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -4424,7 +4424,7 @@
 
   'src/chrome/browser/glic/resources/internal': {
       'url': Var('chrome_git') + '/chrome/browser/glic/resources/internal.git' + '@' +
-        'aeb59fb12f8363ded7b2f1052956e538808c5daf',
+        '3784a743ccebd82808a50e14e99db28643e95bac',
       'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index c8e9897..f598597 100644
--- a/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1244,6 +1244,11 @@
     getter highWaterMark
     getter size
     method constructor
+interface CreateMonitor : EventTarget
+    attribute @@toStringTag
+    getter ondownloadprogress
+    method constructor
+    setter ondownloadprogress
 interface Credential
     attribute @@toStringTag
     getter id
@@ -5129,6 +5134,16 @@
     setter composite
     setter pseudoElement
     setter target
+interface LanguageDetector
+    static method availability
+    static method create
+    attribute @@toStringTag
+    getter expectedInputLanguages
+    getter inputQuota
+    method constructor
+    method destroy
+    method detect
+    method measureInputUsage
 interface LargestContentfulPaint : PerformanceEntry
     attribute @@toStringTag
     getter element
diff --git a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
index bffbfe5..2dc3cfb 100644
--- a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
@@ -7292,6 +7292,11 @@
     attribute @@toStringTag
     method constructor
     method queryFeatureSupport
+interface QuotaExceededError : DOMException
+    attribute @@toStringTag
+    getter quota
+    getter requested
+    method constructor
 interface RTCCertificate
     attribute @@toStringTag
     getter expires
diff --git a/ash/capture_mode/capture_mode_controller.cc b/ash/capture_mode/capture_mode_controller.cc
index 2ae8f4c8..3a6b791 100644
--- a/ash/capture_mode/capture_mode_controller.cc
+++ b/ash/capture_mode/capture_mode_controller.cc
@@ -711,8 +711,7 @@
              : nullptr;
 }
 
-void CaptureModeController::ShowSearchResultsPanel(
-    const gfx::ImageSkia& image) {
+void CaptureModeController::ShowSearchResultsPanel() {
   // We should not use `CanShowSunfishUi` here, as that could change between
   // sending the region and receiving a URL (for example, if the Sunfish policy
   // changes).
@@ -759,13 +758,6 @@
   }
 
   // Note at this point the session may no longer be active.
-  auto* search_results_panel = GetSearchResultsPanel();
-  // The Lens Web API implementation has its own searchbox, so there's no need
-  // to set the thumbnail image.
-  if (!features::IsSunfishLensWebEnabled()) {
-    search_results_panel->SetSearchBoxImage(image);
-  }
-
   if (should_end_session) {
     Stop();
   }
@@ -807,13 +799,6 @@
 
 void CaptureModeController::OnLocatedEventDragged() {
   if (IsSearchResultsPanelVisible()) {
-    // Clear the search box text for the next time the panel is opened. Note we
-    // don't need to reset the image or URL since the panel will always be
-    // re-opened with those. Only necessary if the Lens Web API implementation
-    // is not enabled and we are still using the native search box.
-    if (!features::IsSunfishLensWebEnabled()) {
-      GetSearchResultsPanel()->SetSearchBoxText(std::u16string());
-    }
     search_results_panel_widget_->Hide();
   }
 }
@@ -2070,8 +2055,6 @@
     return;
   }
 
-  gfx::ImageSkia image_skia = gfx::ImageSkia();
-  if (features::IsSunfishLensWebEnabled()) {
     const gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmap);
     const bool is_standalone_session =
         capture_mode_session_->active_behavior()->behavior_type() ==
@@ -2086,24 +2069,11 @@
         base::BindRepeating(&CaptureModeController::OnLensWebError,
                             weak_ptr_factory_.GetWeakPtr(),
                             image_search_token));
-  } else {
-    image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
-    // `OnSearchUrlFetched()` will be invoked with `image` when the server
-    // response is fetched.
-    delegate_->SendRegionSearch(
-        bitmap, user_capture_region_,
-        base::BindRepeating(&CaptureModeController::OnSearchUrlFetched,
-                            weak_ptr_factory_.GetWeakPtr(),
-                            user_capture_region_, image_skia),
-        base::BindRepeating(&CaptureModeController::OnLensTextDetectionComplete,
-                            weak_ptr_factory_.GetWeakPtr(),
-                            image_search_token));
-  }
 
   // Immediately show the search results panel, with a loading animation in
   // place of the web contents. We will replace it once we receive the URL from
   // the server.
-  ShowSearchResultsPanel(image_skia);
+    ShowSearchResultsPanel();
 }
 
 void CaptureModeController::OnTextDetectionComplete(
diff --git a/ash/capture_mode/capture_mode_controller.h b/ash/capture_mode/capture_mode_controller.h
index 06af9617..59cf270 100644
--- a/ash/capture_mode/capture_mode_controller.h
+++ b/ash/capture_mode/capture_mode_controller.h
@@ -151,9 +151,8 @@
   // Returns the search results panel, or nullptr if none exists.
   SearchResultsPanel* GetSearchResultsPanel() const;
 
-  // Shows the results panel. `image` is only needed for the thumbnail if the
-  // Lens Web feature flag is disabled.
-  void ShowSearchResultsPanel(const gfx::ImageSkia& image);
+  // Shows the results panel.
+  void ShowSearchResultsPanel();
 
   // Navigates the Sunfish search results panel to the given URL, if the panel
   // is available.
diff --git a/ash/capture_mode/capture_mode_session.cc b/ash/capture_mode/capture_mode_session.cc
index 2d686a49..21b334c8 100644
--- a/ash/capture_mode/capture_mode_session.cc
+++ b/ash/capture_mode/capture_mode_session.cc
@@ -1801,16 +1801,14 @@
     return;
   }
 
-  // If the search results panel is visible, and the textfield has
-  // pseudo focus or the panel is actually focused, we will let the search
-  // results panel handle key events (i.e., pressing Enter/Return to make a
-  // multimodal search) until it calls `TakeFocus` to return focus back to the
-  // focus cycler. As an exception, pressing ESC can still be used to exit the
-  // session.
+  // If the search results panel is visible, and the panel is actually focused,
+  // we will let the search results panel handle key events (i.e., pressing
+  // Enter/Return to make a multimodal search) until it calls `TakeFocus` to
+  // return focus back to the focus cycler. As an exception, pressing ESC can
+  // still be used to exit the session.
   ui::KeyboardCode key_code = event->key_code();
   if (controller_->IsSearchResultsPanelVisible() &&
-      (controller_->GetSearchResultsPanel()->IsTextfieldPseudoFocused() ||
-       controller_->GetSearchResultsPanel()->HasFocus()) &&
+      controller_->GetSearchResultsPanel()->HasFocus() &&
       key_code != ui::VKEY_ESCAPE) {
     return;
   }
diff --git a/ash/capture_mode/search_results_panel.cc b/ash/capture_mode/search_results_panel.cc
index 2d71f681..6626038 100644
--- a/ash/capture_mode/search_results_panel.cc
+++ b/ash/capture_mode/search_results_panel.cc
@@ -34,8 +34,6 @@
 #include "ui/views/controls/focus_ring.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/widget/widget_delegate.h"
@@ -50,16 +48,8 @@
 const std::u16string kSearchBoxPlaceholderText = u"Add to your search";
 inline constexpr gfx::Insets kPanelPadding =
     gfx::Insets(capture_mode::kPanelPaddingSize);
-inline constexpr int kSearchBoxHeight = 48;
-inline constexpr int kSearchBoxRadius = 24;
-inline constexpr int kSearchBoxImageRadius = 8;
-inline constexpr gfx::Insets kSearchBoxViewSpacing = gfx::Insets::VH(12, 0);
 inline constexpr gfx::Insets kSearchResultsViewSpacing =
     gfx::Insets::TLBR(12, 0, 0, 0);
-inline constexpr gfx::Insets kSearchImageSpacing =
-    gfx::Insets::TLBR(8, 16, 8, 12);
-inline constexpr gfx::Insets kSearchTextfieldSpacing =
-    gfx::Insets::TLBR(14, 0, 14, 16);
 
 // Returns the target container window for the panel widget.
 aura::Window* GetParentContainer(aura::Window* root, bool is_active) {
@@ -75,104 +65,6 @@
 
 }  // namespace
 
-// TODO: crbug.com/377764351 - Fix the textfield being too far to the left when
-// the region is very narrow (height >> width).
-// `SunfishSearchBoxView` contains an image thumbnail and a textfield.
-class SunfishSearchBoxView : public views::View,
-                             public views::TextfieldController {
-  METADATA_HEADER(SunfishSearchBoxView, views::View)
-
- public:
-  SunfishSearchBoxView() {
-    SetLayoutManager(std::make_unique<views::FlexLayout>())
-        ->SetOrientation(views::LayoutOrientation::kHorizontal)
-        .SetMainAxisAlignment(views::LayoutAlignment::kStart)
-        .SetCrossAxisAlignment(views::LayoutAlignment::kStretch)
-        .SetCollapseMargins(true);
-    // TODO(b/356878705): Replace with the captured region screenshot when the
-    // backend is hooked up. Currently using the search icon as a placeholder.
-    AddChildView(views::Builder<views::ImageView>()
-                     .CopyAddressTo(&image_view_)
-                     .SetImage(ui::ImageModel::FromVectorIcon(
-                         vector_icons::kGoogleColorIcon))
-                     .SetProperty(views::kMarginsKey, kSearchImageSpacing)
-                     .Build());
-    AddChildView(
-        views::Builder<views::Textfield>()
-            .CopyAddressTo(&textfield_)
-            .SetController(this)
-            .SetTextInputType(ui::TEXT_INPUT_TYPE_TEXT)
-            .SetPlaceholderText(kSearchBoxPlaceholderText)
-            .SetFontList(TypographyProvider::Get()->ResolveTypographyToken(
-                TypographyToken::kCrosBody2))
-            .SetProperty(views::kMarginsKey, kSearchTextfieldSpacing)
-            .SetProperty(views::kFlexBehaviorKey,
-                         views::FlexSpecification(
-                             views::LayoutOrientation::kHorizontal,
-                             views::MinimumFlexSizeRule::kPreferred,
-                             views::MaximumFlexSizeRule::kUnbounded))
-            .SetBackgroundEnabled(false)
-            .SetBorder(nullptr)
-            .Build());
-
-    SetBackground(views::CreateRoundedRectBackground(
-        cros_tokens::kCrosSysSystemOnBase1, kSearchBoxRadius));
-
-    SetPreferredSize(gfx::Size(capture_mode::kSearchResultsPanelWebViewWidth,
-                               kSearchBoxHeight));
-
-    image_view_->SetPaintToLayer();
-    image_view_->layer()->SetFillsBoundsOpaquely(false);
-    image_view_->layer()->SetRoundedCornerRadius(
-        gfx::RoundedCornersF(kSearchBoxImageRadius));
-  }
-  SunfishSearchBoxView(const SunfishSearchBoxView&) = delete;
-  SunfishSearchBoxView& operator=(const SunfishSearchBoxView&) = delete;
-  ~SunfishSearchBoxView() override = default;
-
-  void SetImage(const gfx::ImageSkia& image) {
-    if (image.isNull()) {
-      return;
-    }
-    // Resize the image to fit in the searchbox, keeping the same aspect ratio.
-    const int target_height = height();
-    const int target_width = (image.width() * target_height) / image.height();
-    image_view_->SetImage(ui::ImageModel::FromImageSkia(image));
-    image_view_->SetImageSize(gfx::Size(target_width, target_height));
-  }
-
-  // views::TextfieldController:
-  bool HandleKeyEvent(views::Textfield* sender,
-                      const ui::KeyEvent& event) override {
-    if (sender->GetText().empty()) {
-      return false;
-    }
-
-    if (!textfield_->HasFocus()) {
-      return false;
-    }
-
-    if (event.type() == ui::EventType::kKeyPressed &&
-        event.key_code() == ui::VKEY_RETURN) {
-      CaptureModeController::Get()->SendMultimodalSearch(
-          image_view_->GetImage(), base::UTF16ToUTF8(sender->GetText()));
-      return true;
-    }
-
-    return false;
-  }
-
- private:
-  friend class SearchResultsPanel;
-
-  // Owned by the views hierarchy.
-  raw_ptr<views::ImageView> image_view_;
-  raw_ptr<views::Textfield> textfield_;
-};
-
-BEGIN_METADATA(SunfishSearchBoxView)
-END_METADATA
-
 SearchResultsPanel::SearchResultsPanel() {
   // We should not use `CanShowSunfishUi` here, as that could change between
   // sending the region and receiving a URL which will then create this view
@@ -222,13 +114,6 @@
                           .WithAlignment(views::LayoutAlignment::kEnd)))
           .Build());
 
-  // Lens Web API uses its own sticky search box, so there's no need to create a
-  // native one.
-  if (!features::IsSunfishLensWebEnabled()) {
-    search_box_view_ = AddChildView(std::make_unique<SunfishSearchBoxView>());
-    search_box_view_->SetProperty(views::kMarginsKey, kSearchBoxViewSpacing);
-  }
-
   SetBackground(views::CreateRoundedRectBackground(
       cros_tokens::kCrosSysSystemBaseElevated, kPanelCornerRadius));
   SetPaintToLayer();
@@ -254,14 +139,6 @@
   CaptureModeSessionFocusCycler::HighlightHelper::Install(animation_view);
   CaptureModeSessionFocusCycler::HighlightHelper::Get(animation_view)
       ->SetUpFocusPredicate();
-
-  if (!features::IsSunfishLensWebEnabled()) {
-    CaptureModeSessionFocusCycler::HighlightHelper::Install(
-        search_box_view_->textfield_);
-    CaptureModeSessionFocusCycler::HighlightHelper::Get(
-        search_box_view_->textfield_)
-        ->SetUpFocusPredicate();
-  }
 }
 
 SearchResultsPanel::~SearchResultsPanel() = default;
@@ -285,10 +162,6 @@
   return widget;
 }
 
-views::Textfield* SearchResultsPanel::GetSearchBoxTextfield() const {
-  return search_box_view_ ? search_box_view_->textfield_ : nullptr;
-}
-
 std::vector<CaptureModeSessionFocusCycler::HighlightableView*>
 SearchResultsPanel::GetHighlightableItems() const {
   std::vector<CaptureModeSessionFocusCycler::HighlightableView*>
@@ -296,12 +169,6 @@
   CHECK(close_button_);
   highlightable_items.push_back(
       CaptureModeSessionFocusCycler::HighlightHelper::Get(close_button_.get()));
-  if (!features::IsSunfishLensWebEnabled()) {
-    CHECK(search_box_view_);
-    highlightable_items.push_back(
-        CaptureModeSessionFocusCycler::HighlightHelper::Get(
-            search_box_view_->textfield_.get()));
-  }
   return highlightable_items;
 }
 
@@ -337,16 +204,6 @@
   search_results_view_->Navigate(url);
 }
 
-void SearchResultsPanel::SetSearchBoxImage(const gfx::ImageSkia& image) {
-  CHECK(search_box_view_);
-  search_box_view_->SetImage(image);
-}
-
-void SearchResultsPanel::SetSearchBoxText(const std::u16string& text) {
-  CHECK(search_box_view_);
-  search_box_view_->textfield_->SetText(text);
-}
-
 void SearchResultsPanel::RefreshStackingOrder(aura::Window* new_root) {
   aura::Window* native_window = GetWidget()->GetNativeWindow();
   // While the capture mode session is active, we parent the panel to its own
@@ -356,17 +213,6 @@
   views::Widget::ReparentNativeView(native_window, new_parent);
 }
 
-bool SearchResultsPanel::IsTextfieldPseudoFocused() const {
-  if (features::IsSunfishLensWebEnabled()) {
-    return false;
-  }
-
-  CHECK(search_box_view_);
-  return CaptureModeSessionFocusCycler::HighlightHelper::Get(
-             search_box_view_->textfield_)
-      ->has_focus();
-}
-
 void SearchResultsPanel::ShowLoadingAnimation() {
   if (GetViewByID(capture_mode::kLoadingAnimationViewId)) {
     return;
diff --git a/ash/capture_mode/search_results_panel.h b/ash/capture_mode/search_results_panel.h
index 30aa235..53e70f4 100644
--- a/ash/capture_mode/search_results_panel.h
+++ b/ash/capture_mode/search_results_panel.h
@@ -19,13 +19,11 @@
 
 namespace views {
 class Button;
-class Textfield;
 }  // namespace views
 
 namespace ash {
 
 class AshWebView;
-class SunfishSearchBoxView;
 
 // Container for the search results view and other UI such as the search box,
 // close button, etc.
@@ -49,8 +47,6 @@
     return GetViewByID(capture_mode::kLoadingAnimationViewId);
   }
 
-  views::Textfield* GetSearchBoxTextfield() const;
-
   // Gets the highlightable views for the search results panel, which may
   // include the close button and the search box textfield. Does not include
   // the web contents or animation as they need to be handled separately.
@@ -68,18 +64,12 @@
 
   // Sets the search box URL, image thumbnail, and text.
   virtual void Navigate(const GURL& url);
-  virtual void SetSearchBoxImage(const gfx::ImageSkia& image);
-  void SetSearchBoxText(const std::u16string& text);
 
   // Refreshes the panel z-order. If `new_root` is not null, capture mode
   // session is active and will be used to determine the panel root. Else the
   // panel will be re-stacked on its native window's root window.
   void RefreshStackingOrder(aura::Window* new_root);
 
-  // Returns true if the `CaptureModeSessionFocusCycler::HighlightHelper` for
-  // this view has focus, otherwise returns false.
-  bool IsTextfieldPseudoFocused() const;
-
   // Shows and plays a loading animation in place of the web contents.
   void ShowLoadingAnimation();
 
@@ -106,7 +96,6 @@
   void RefreshPanelBounds();
 
   // Owned by the views hierarchy.
-  raw_ptr<SunfishSearchBoxView> search_box_view_ = nullptr;
   raw_ptr<AshWebView> search_results_view_ = nullptr;
   raw_ptr<views::Button> close_button_;
 
diff --git a/ash/capture_mode/sunfish_unittest.cc b/ash/capture_mode/sunfish_unittest.cc
index 709f8d7b..82b0d4f1 100644
--- a/ash/capture_mode/sunfish_unittest.cc
+++ b/ash/capture_mode/sunfish_unittest.cc
@@ -1664,7 +1664,7 @@
   // Mock getting a new response from the server. Test the panel is updated.
   EXPECT_CALL(*search_results_panel, Navigate(testing::_));
 
-  controller->ShowSearchResultsPanel(gfx::ImageSkia());
+  controller->ShowSearchResultsPanel();
   controller->NavigateSearchResultsPanel(GURL("kTestUrl2"));
 }
 
@@ -2745,41 +2745,6 @@
   LeftClickOn(search_button);
 }
 
-// TODO: crbug.com/398259275 - Remove this class and remove or integrate each
-// test when the Lens Web API implementation is enabled by default.
-class SunfishLensWebTest : public SunfishTestBase {
- public:
-  SunfishLensWebTest() {
-    scoped_feature_list_.InitWithFeatures(
-        /*enabled_features=*/{features::kSunfishFeature,
-                              features::kSunfishLensWeb},
-        /*disabled_features=*/{{}});
-  }
-  SunfishLensWebTest(const SunfishLensWebTest&) = delete;
-  SunfishLensWebTest& operator=(const SunfishLensWebTest&) = delete;
-  ~SunfishLensWebTest() override = default;
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-// Tests that the native search box is removed from the search results panel
-// when the Lens Web API implementation is enabled.
-TEST_F(SunfishLensWebTest, NoNativeSearchBox) {
-  views::Widget::InitParams params(
-      views::Widget::InitParams::CLIENT_OWNS_WIDGET,
-      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
-  params.bounds = gfx::Rect{capture_mode::kSearchResultsPanelTotalWidth,
-                            capture_mode::kSearchResultsPanelTotalHeight};
-  params.parent =
-      Shell::GetContainer(Shell::GetPrimaryRootWindow(),
-                          kShellWindowId_CaptureModeSearchResultsPanel);
-  auto widget = std::make_unique<views::Widget>(std::move(params));
-  auto* search_results_panel =
-      widget->SetContentsView(std::make_unique<SearchResultsPanel>());
-  EXPECT_FALSE(search_results_panel->GetSearchBoxTextfield());
-}
-
 using SunfishDisplayMetricsTest = SunfishTest;
 
 // TODO(crbug.com/388564694): Enable after resolving flakiness.
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 42f2960..93bfc1cd 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -2095,7 +2095,7 @@
 // go/ongoing-ui
 BASE_FEATURE(kOngoingProcesses,
              "OngoingProcesses",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // If enabled, enrollment screen will allow for automatically adding the
 // authenticated user to the device.
@@ -2829,18 +2829,6 @@
              "SunfishFeature",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// Changes the Sunfish feature to use the Lens Web API instead of the
-// Chromnient-like query.
-BASE_FEATURE(kSunfishLensWeb,
-             "SunfishLensWeb",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
-// Changes the Sunfish copy text functionality to use the Lens Web API instead
-// of the Chromnient-like query.
-BASE_FEATURE(kSunfishLensWebCopyText,
-             "SunfishLensWebCopyText",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Enable the suspend state machine to better handle suspend accelerators.
 BASE_FEATURE(kSuspendStateMachine,
              "SuspendStateMachine",
@@ -4610,16 +4598,6 @@
   return base::FeatureList::IsEnabled(kSunfishFeature);
 }
 
-bool IsSunfishLensWebEnabled() {
-  return IsSunfishFeatureEnabled() &&
-         base::FeatureList::IsEnabled(kSunfishLensWeb);
-}
-
-bool IsSunfishLensWebCopyTextEnabled() {
-  return IsSunfishLensWebEnabled() &&
-         base::FeatureList::IsEnabled(kSunfishLensWebCopyText);
-}
-
 bool IsSuspendStateMachineEnabled() {
   return base::FeatureList::IsEnabled(kSuspendStateMachine);
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 20216dc..d25b1ec 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -934,8 +934,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSnoopingProtection);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSplitKeyboardRefactor);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSunfishFeature);
-COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSunfishLensWeb);
-COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSunfishLensWebCopyText);
 COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kSuspendStateMachine);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kSystemJapanesePhysicalTyping);
diff --git a/ash/frame/default_frame_header_unittest.cc b/ash/frame/default_frame_header_unittest.cc
index 9639ce5e..c80b3a9 100644
--- a/ash/frame/default_frame_header_unittest.cc
+++ b/ash/frame/default_frame_header_unittest.cc
@@ -14,8 +14,6 @@
 #include "base/i18n/rtl.h"
 #include "base/memory/raw_ptr.h"
 #include "base/test/icu_test_util.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/time/time.h"
 #include "chromeos/ui/base/window_properties.h"
 #include "chromeos/ui/frame/caption_buttons/frame_back_button.h"
 #include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h"
@@ -45,19 +43,7 @@
 
 namespace ash {
 
-class DefaultFrameHeaderTest : public AshTestBase {
- public:
-  DefaultFrameHeaderTest()
-      : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
-  DefaultFrameHeaderTest(const DefaultFrameHeaderTest&) = delete;
-  DefaultFrameHeaderTest& operator=(const DefaultFrameHeaderTest&) = delete;
-  ~DefaultFrameHeaderTest() override = default;
-
-  void AdvanceClock(base::TimeDelta delay) {
-    task_environment()->AdvanceClock(delay);
-    task_environment()->RunUntilIdle();
-  }
-};
+using DefaultFrameHeaderTest = AshTestBase;
 
 // Ensure the title text is vertically aligned with the window icon.
 TEST_F(DefaultFrameHeaderTest, TitleIconAlignment) {
@@ -335,33 +321,4 @@
   EXPECT_TRUE(win_0->layer()->damaged_region().Contains(layer_bounds));
 }
 
-// Ensure that the number of frame color changes is recorded as metrics.
-TEST_F(DefaultFrameHeaderTest, FrameColorChangeMetrics) {
-  const auto app_type = chromeos::AppType::ARC_APP;
-  auto win0 = CreateAppWindow(gfx::Rect(300, 300), app_type);
-  Widget* widget = Widget::GetWidgetForNativeWindow(win0.get());
-  DefaultFrameHeader* frame_header =
-      static_cast<DefaultFrameHeader*>(FrameHeader::Get(widget));
-
-  const auto frame_color_change_histogram =
-      chromeos::FrameColorMetricsHelper::GetFrameColorChangeHistogramName(
-          app_type);
-  base::HistogramTester histogram_tester;
-
-  win0->SetProperty(kFrameActiveColorKey, SkColorSetRGB(70, 70, 70));
-  win0->SetProperty(kFrameInactiveColorKey, SkColorSetRGB(70, 70, 70));
-  frame_header->UpdateFrameColors();
-
-  constexpr base::TimeDelta kFrameColorTracingTime = base::Seconds(3);
-  // Advances the mock clock in the task environment because the metrics is
-  // recorded `kFrameColorTracingTime` after the `frame_header` is instantiated.
-  AdvanceClock(kFrameColorTracingTime);
-
-  histogram_tester.ExpectTotalCount(frame_color_change_histogram, 1);
-
-  // The recorded number of frame color changes should be at least 1.
-  EXPECT_GE(histogram_tester.GetAllSamples(frame_color_change_histogram)[0].min,
-            1);
-}
-
 }  // namespace ash
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 64c39c9..b5f88ad 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -1186,7 +1186,8 @@
   const bool has_visible_snap_group =
       snap_group_controller &&
       snap_group_controller->GetTopmostVisibleSnapGroup(
-          shelf_native_window->GetRootWindow());
+          shelf_native_window->GetRootWindow(),
+          /*topwindow_only=*/false);
   const bool maximized =
       in_split_view_mode || has_visible_snap_group ||
       state_.window_state == WorkspaceWindowState::kFullscreen ||
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 500c580..d6cea7f 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -655,9 +655,9 @@
       SplitViewController::Get(root_window_)->InSplitViewMode();
   SnapGroupController* snap_group_controller = SnapGroupController::Get();
   const bool should_report_split_view_metrics =
-      in_split_view ||
-      (snap_group_controller &&
-       snap_group_controller->GetTopmostVisibleSnapGroup(root_window_));
+      in_split_view || (snap_group_controller &&
+                        snap_group_controller->GetTopmostVisibleSnapGroup(
+                            root_window_, /*topwindow_only=*/true));
   // OverviewGrid in splitscreen does not include the window to be activated.
   if (!item_list_.empty() || should_report_split_view_metrics) {
     const bool minimized_in_tablet =
@@ -2663,7 +2663,8 @@
   const bool both_snapped_windows =
       state == SplitViewController::State::kBothSnapped ||
       (snap_group_controller &&
-       snap_group_controller->GetTopmostVisibleSnapGroup(root_window_));
+       snap_group_controller->GetTopmostVisibleSnapGroup(
+           root_window_, /*topwindow_only=*/true));
   if (both_snapped_windows || unsnappable_window_activated ||
       (split_view_controller->InClamshellSplitViewMode() &&
        overview_session_->IsEmpty())) {
diff --git a/ash/wm/snap_group/snap_group_controller.cc b/ash/wm/snap_group/snap_group_controller.cc
index a7a1530..e2f728bb 100644
--- a/ash/wm/snap_group/snap_group_controller.cc
+++ b/ash/wm/snap_group/snap_group_controller.cc
@@ -287,7 +287,8 @@
 }
 
 SnapGroup* SnapGroupController::GetTopmostVisibleSnapGroup(
-    const aura::Window* target_root) const {
+    const aura::Window* target_root,
+    bool topwindow_only) const {
   for (const aura::Window* top_window : GetActiveDeskAppWindowsInZOrder(
            const_cast<aura::Window*>(target_root))) {
     // Skip to the topmost window on `target_root`, ignoring occlusion-exempt
@@ -302,7 +303,9 @@
       return snap_group;
     }
     // Else if `top_window` does not belong to a snap group, we are done.
-    break;
+    if (topwindow_only) {
+      break;
+    }
   }
   return nullptr;
 }
diff --git a/ash/wm/snap_group/snap_group_controller.h b/ash/wm/snap_group/snap_group_controller.h
index 278281c..cb9c989 100644
--- a/ash/wm/snap_group/snap_group_controller.h
+++ b/ash/wm/snap_group/snap_group_controller.h
@@ -89,7 +89,10 @@
   SnapGroup* GetSnapGroupForGivenWindow(const aura::Window* window) const;
 
   // Returns the topmost fully visible non-occluded snap group on `target_root`.
-  SnapGroup* GetTopmostVisibleSnapGroup(const aura::Window* target_root) const;
+  // If `topwindow_only` is true, it return null if the top window isn't in a
+  // snap group. If false, it will search until it finds a snap group.
+  SnapGroup* GetTopmostVisibleSnapGroup(const aura::Window* target_root,
+                                        bool topwindow_only) const;
 
   // Returns the topmost snap group in unminimized state.
   SnapGroup* GetTopmostSnapGroup() const;
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc
index d9b71b08..e0b23ef 100644
--- a/ash/wm/snap_group/snap_group_unittest.cc
+++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -2375,6 +2375,22 @@
   EXPECT_EQ(ShelfBackgroundType::kMaximized,
             shelf_layout_manager->shelf_background_type());
 
+  // Creating a window on top shouldn't affect the shelf background type.
+  std::unique_ptr<aura::Window> w3(CreateAppWindow());
+  EXPECT_EQ(ShelfBackgroundType::kMaximized,
+            shelf_layout_manager->shelf_background_type());
+
+  // Enter & exit overview the background type should still be kMaximized.
+  ToggleOverview();
+  ToggleOverview();
+  EXPECT_EQ(ShelfBackgroundType::kMaximized,
+            shelf_layout_manager->shelf_background_type());
+
+  // The background type should still be kMaximized after closing it.
+  w3.reset();
+  EXPECT_EQ(ShelfBackgroundType::kMaximized,
+            shelf_layout_manager->shelf_background_type());
+
   // Drag `w1` out to break the group.
   event_generator->MoveMouseTo(w1->GetBoundsInScreen().top_center());
   aura::test::TestWindowDelegate().set_window_component(HTCAPTION);
@@ -10490,8 +10506,8 @@
   // At this point `w4` is active but a single snapped window. Recall the group
   // for `w1` and `w2` so we can start snap to replace.
   wm::ActivateWindow(w1.get());
-  ASSERT_TRUE(
-      snap_group_controller->GetTopmostVisibleSnapGroup(w1->GetRootWindow()));
+  ASSERT_TRUE(snap_group_controller->GetTopmostVisibleSnapGroup(
+      w1->GetRootWindow(), /*topwindow_only=*/true));
 
   // Snap to replace `w5` in the 1st snap group. Test we don't record.
   std::unique_ptr<aura::Window> w5(CreateAppWindow());
diff --git a/base/allocator/partition_allocator/src/partition_alloc/pointers/instance_tracer.h b/base/allocator/partition_allocator/src/partition_alloc/pointers/instance_tracer.h
index 87190a63..c8e55d7b 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/pointers/instance_tracer.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/pointers/instance_tracer.h
@@ -5,33 +5,25 @@
 #ifndef PARTITION_ALLOC_POINTERS_INSTANCE_TRACER_H_
 #define PARTITION_ALLOC_POINTERS_INSTANCE_TRACER_H_
 
+#include <stdint.h>
+
+#include "partition_alloc/buildflags.h"
+#include "partition_alloc/partition_alloc_base/compiler_specific.h"
+
+#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_INSTANCE_TRACER)
 #include <array>
 #include <atomic>
 #include <cstdint>
 #include <utility>
 #include <vector>
 
-#include "partition_alloc/buildflags.h"
-#include "partition_alloc/partition_alloc_base/compiler_specific.h"
 #include "partition_alloc/partition_alloc_base/component_export.h"
 #include "partition_alloc/partition_alloc_base/cxx20_is_constant_evaluated.h"
+#endif
 
 namespace base::internal {
 
-#if !PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_INSTANCE_TRACER)
-
-// When the buildflag is disabled, use a minimal no-state implementation so
-// sizeof(raw_ptr<T>) == sizeof(T*).
-class InstanceTracer {
- public:
-  constexpr uint64_t owner_id() const { return 0; }
-
-  constexpr static void Trace([[maybe_unused]] uint64_t owner_id,
-                              [[maybe_unused]] uintptr_t address) {}
-  constexpr static void Untrace([[maybe_unused]] uint64_t owner_id) {}
-};
-
-#else
+#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_INSTANCE_TRACER)
 
 class PA_TRIVIAL_ABI InstanceTracer {
  public:
@@ -93,7 +85,20 @@
   uint64_t owner_id_ = 0;
 };
 
-#endif
+#else
+
+// When the buildflag is disabled, use a minimal no-state implementation so
+// sizeof(raw_ptr<T>) == sizeof(T*).
+class InstanceTracer {
+ public:
+  constexpr uint64_t owner_id() const { return 0; }
+
+  constexpr static void Trace([[maybe_unused]] uint64_t owner_id,
+                              [[maybe_unused]] uintptr_t address) {}
+  constexpr static void Untrace([[maybe_unused]] uint64_t owner_id) {}
+};
+
+#endif  // PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_INSTANCE_TRACER)
 
 }  // namespace base::internal
 
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py
index 9f4927a..dbba2a2 100644
--- a/build/android/PRESUBMIT.py
+++ b/build/android/PRESUBMIT.py
@@ -86,8 +86,9 @@
   })
 
   pytests = [
-      J('.', 'list_class_verification_failures_test.py'),
       J('.', 'convert_dex_profile_tests.py'),
+      J('.', 'list_class_verification_failures_test.py'),
+      J('.', 'test_runner_test.py'),
       J('gyp', 'compile_java_tests.py'),
       J('gyp', 'create_unwind_table_tests.py'),
       J('gyp', 'dex_test.py'),
diff --git a/build/android/test_runner_test.py b/build/android/test_runner_test.py
index b2a75a93..93794cc 100755
--- a/build/android/test_runner_test.py
+++ b/build/android/test_runner_test.py
@@ -78,3 +78,8 @@
     self.exc_recorder.clear_stacktrace.assert_called_once()
     self.exc_recorder.register.assert_called_once()
     self.mm_recorder.clear.assert_called_once()
+
+
+if __name__ == '__main__':
+  # Suppress logging messages.
+  unittest.main(buffer=True)
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 94fc4b4..5a58de1 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -626,13 +626,6 @@
         default_toolchain != "//build/toolchain/cros:target") {
       cflags += [ "-Wa,--crel,--allow-experimental-crel" ]
     }
-
-    # TODO(crbug.com/413427035): Remove once
-    # https://github.com/llvm/llvm-project/pull/136867/ is landed.
-    if (!is_win && !llvm_android_mainline &&
-        default_toolchain != "//build/toolchain/cros:target") {
-      cflags += [ "-fextend-variable-liveness=none" ]
-    }
   }
 
   # C11/C++11 compiler flags setup.
diff --git a/build/rust/std/gnrt_config.toml b/build/rust/std/gnrt_config.toml
index d920be2..b394cca 100644
--- a/build/rust/std/gnrt_config.toml
+++ b/build/rust/std/gnrt_config.toml
@@ -46,10 +46,6 @@
 # The build script conditionally generates a file; it's simplest to just paste
 # raw GN into the output. (crbug.com/1470653)
 extra_kv = { include_coverage = false, raw_gn = 'if (current_cpu == "arm64") { build_script_outputs = ["outlined_atomics.rs"] }' }
-extra_src_roots = [
-  # compiler_builtins depends on libm on windows crbug.com/1472681
-  '../libm',
-]
 extra_build_script_src_roots = [
   '../configure.rs',
 ]
diff --git a/build/rust/std/rules/BUILD.gn b/build/rust/std/rules/BUILD.gn
index a3e6cec..8ae649d 100644
--- a/build/rust/std/rules/BUILD.gn
+++ b/build/rust/std/rules/BUILD.gn
@@ -300,235 +300,236 @@
 }
 cargo_crate("compiler_builtins") {
   crate_type = "rlib"
-  crate_root = "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/lib.rs"
+  crate_root = "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/lib.rs"
   sources = [
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/aarch64.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/aarch64_linux.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/arm.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/arm_linux.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/add.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/cmp.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/conv.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/div.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/extend.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/mul.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/pow.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/sub.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/traits.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/float/trunc.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/hexagon.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/addsub.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/big.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/bswap.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/leading_zeros.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/mul.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/sdiv.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/shift.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/specialized_div_rem/asymmetric.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/specialized_div_rem/binary_long.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/specialized_div_rem/delegate.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/specialized_div_rem/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/specialized_div_rem/norm_shift.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/specialized_div_rem/trifecta.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/trailing_zeros.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/traits.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/int/udiv.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/lib.miri.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/lib.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/macros.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/math.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/mem/impls.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/mem/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/mem/x86_64.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/probestack.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/riscv.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/x86.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/x86_64.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/aarch64.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/aarch64_linux.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/arm.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/arm_linux.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/avr.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/add.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/cmp.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/conv.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/div.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/extend.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/mul.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/pow.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/sub.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/traits.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/float/trunc.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/hexagon.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/addsub.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/big.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/bswap.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/leading_zeros.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/mul.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/sdiv.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/shift.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/specialized_div_rem/asymmetric.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/specialized_div_rem/binary_long.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/specialized_div_rem/delegate.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/specialized_div_rem/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/specialized_div_rem/norm_shift.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/specialized_div_rem/trifecta.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/trailing_zeros.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/traits.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/int/udiv.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/lib.miri.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/lib.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/macros.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/acos.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/acosf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/acosh.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/acoshf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/arch/aarch64.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/arch/i586.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/arch/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/arch/wasm32.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/arch/x86.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/arch/x86/detect.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/arch/x86/fma.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/asin.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/asinf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/asinh.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/asinhf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/atan.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/atan2.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/atan2f.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/atanf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/atanh.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/atanhf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/cbrt.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/cbrtf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/ceil.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/copysign.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/copysignf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/copysignf128.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/copysignf16.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/cos.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/cosf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/cosh.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/coshf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/erf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/erff.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/exp.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/exp10.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/exp10f.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/exp2.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/exp2f.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/expf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/expm1.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/expm1f.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/expo2.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fabs.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fabsf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fabsf128.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fabsf16.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fdim.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fdimf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fdimf128.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fdimf16.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/floor.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/floorf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/floorf128.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/floorf16.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fma.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fmin_fmax.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fminimum_fmaximum.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fminimum_fmaximum_num.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fmod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fmodf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fmodf128.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/fmodf16.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/frexp.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/frexpf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/ceil.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/copysign.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fabs.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fdim.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/floor.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fma.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fma_wide.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fmax.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fmaximum.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fmaximum_num.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fmin.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fminimum.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fminimum_num.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/fmod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/rint.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/round.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/scalbn.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/sqrt.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/generic/trunc.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/hypot.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/hypotf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/ilogb.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/ilogbf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/j0.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/j0f.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/j1.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/j1f.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/jn.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/jnf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/k_cos.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/k_cosf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/k_expo2.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/k_expo2f.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/k_sin.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/k_sinf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/k_tan.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/k_tanf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/ldexp.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/ldexpf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/ldexpf128.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/ldexpf16.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/lgamma.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/lgamma_r.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/lgammaf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/lgammaf_r.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/log.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/log10.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/log10f.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/log1p.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/log1pf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/log2.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/log2f.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/logf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/modf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/modff.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/nextafter.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/nextafterf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/pow.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/powf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/rem_pio2.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/rem_pio2_large.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/rem_pio2f.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/remainder.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/remainderf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/remquo.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/remquof.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/rint.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/round.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/roundeven.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/roundf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/roundf128.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/roundf16.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/scalbn.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/scalbnf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/scalbnf128.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/scalbnf16.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/sin.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/sincos.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/sincosf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/sinf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/sinh.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/sinhf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/sqrt.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/sqrtf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/sqrtf128.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/sqrtf16.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/support/big.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/support/big/tests.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/support/env.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/support/feature_detect.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/support/float_traits.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/support/hex_float.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/support/int_traits.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/support/macros.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/support/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/tan.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/tanf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/tanh.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/tanhf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/tgamma.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/tgammaf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/trunc.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/truncf.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/truncf128.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/libm_math/truncf16.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/math/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/mem/impls.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/mem/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/mem/x86_64.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/probestack.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/riscv.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/x86.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/x86_64.rs",
   ]
-  inputs = [
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/acos.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/acosf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/acosh.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/acoshf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/arch/aarch64.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/arch/i586.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/arch/i686.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/arch/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/arch/wasm32.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/asin.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/asinf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/asinh.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/asinhf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/atan.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/atan2.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/atan2f.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/atanf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/atanh.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/atanhf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/cbrt.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/cbrtf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/ceil.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/ceilf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/ceilf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/ceilf16.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/copysign.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/copysignf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/copysignf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/copysignf16.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/cos.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/cosf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/cosh.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/coshf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/erf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/erff.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/exp.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/exp10.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/exp10f.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/exp2.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/exp2f.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/expf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/expm1.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/expm1f.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/expo2.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fabs.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fabsf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fabsf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fabsf16.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fdim.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fdimf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fdimf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fdimf16.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/floor.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/floorf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/floorf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/floorf16.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fma.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fma_wide.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fmin_fmax.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fminimum_fmaximum.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fminimum_fmaximum_num.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fmod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fmodf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fmodf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/fmodf16.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/frexp.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/frexpf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/ceil.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/copysign.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/fabs.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/fdim.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/floor.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/fmax.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/fmaximum.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/fmaximum_num.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/fmin.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/fminimum.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/fminimum_num.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/fmod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/rint.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/round.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/scalbn.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/sqrt.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/generic/trunc.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/hypot.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/hypotf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/ilogb.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/ilogbf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/j0.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/j0f.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/j1.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/j1f.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/jn.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/jnf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/k_cos.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/k_cosf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/k_expo2.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/k_expo2f.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/k_sin.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/k_sinf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/k_tan.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/k_tanf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/ldexp.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/ldexpf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/ldexpf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/ldexpf16.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/lgamma.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/lgamma_r.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/lgammaf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/lgammaf_r.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/log.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/log10.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/log10f.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/log1p.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/log1pf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/log2.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/log2f.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/logf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/modf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/modff.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/nextafter.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/nextafterf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/pow.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/powf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/rem_pio2.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/rem_pio2_large.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/rem_pio2f.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/remainder.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/remainderf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/remquo.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/remquof.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/rint.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/round.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/roundeven.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/roundf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/roundf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/roundf16.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/scalbn.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/scalbnf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/scalbnf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/scalbnf16.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/sin.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/sincos.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/sincosf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/sinf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/sinh.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/sinhf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/sqrt.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/sqrtf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/sqrtf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/sqrtf16.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/support/big/tests.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/support/big.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/support/env.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/support/float_traits.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/support/hex_float.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/support/int_traits.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/support/macros.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/support/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/tan.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/tanf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/tanh.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/tanhf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/tgamma.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/tgammaf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/trunc.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/truncf.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/truncf128.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../libm/src/math/truncf16.rs",
-  ]
+  inputs = []
   no_std = true
 
   # Unit tests skipped. Generate with --with-tests to include them.
   build_native_rust_unit_tests = false
   edition = "2021"
-  cargo_pkg_version = "0.1.155"
+  cargo_pkg_version = "0.1.157"
   cargo_pkg_authors = "Jorge Aparicio <japaricious@gmail.com>"
   cargo_pkg_name = "compiler_builtins"
-  cargo_pkg_description = "Compiler intrinsics used by the Rust compiler. Also available for other targets if necessary!"
+  cargo_pkg_description = "Compiler intrinsics used by the Rust compiler."
   library_configs -= [
     "//build/config/compiler:chromium_code",
     "//build/config/compiler:disallow_unstable_features",
@@ -549,13 +550,12 @@
   }
   features = [
     "compiler-builtins",
-    "core",
     "default",
     "rustc-dep-of-std",
   ]
-  build_root = "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/build.rs"
-  build_sources = [ "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/build.rs" ]
-  build_script_inputs = [ "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.155/src/../configure.rs" ]
+  build_root = "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/build.rs"
+  build_sources = [ "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/build.rs" ]
+  build_script_inputs = [ "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/compiler_builtins-0.1.157/src/../configure.rs" ]
   rustenv = [
     "CFG_DISABLE_UNSTABLE_FEATURES=0",
     "STD_ENV_ARCH=$rust_target_arch",
@@ -1264,34 +1264,35 @@
 }
 cargo_crate("hashbrown") {
   crate_type = "rlib"
-  crate_root = "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/lib.rs"
+  crate_root = "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/lib.rs"
   sources = [
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/control/bitmask.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/control/group/generic.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/control/group/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/control/group/neon.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/control/group/sse2.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/control/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/control/tag.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/external_trait_impls/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/external_trait_impls/rayon/helpers.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/external_trait_impls/rayon/map.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/external_trait_impls/rayon/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/external_trait_impls/rayon/raw.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/external_trait_impls/rayon/set.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/external_trait_impls/rayon/table.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/external_trait_impls/serde.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/lib.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/macros.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/map.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/raw/alloc.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/raw/mod.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/raw_entry.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/rustc_entry.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/scopeguard.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/set.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/table.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.2/src/util.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/control/bitmask.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/control/group/generic.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/control/group/lsx.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/control/group/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/control/group/neon.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/control/group/sse2.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/control/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/control/tag.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/external_trait_impls/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/external_trait_impls/rayon/helpers.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/external_trait_impls/rayon/map.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/external_trait_impls/rayon/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/external_trait_impls/rayon/raw.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/external_trait_impls/rayon/set.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/external_trait_impls/rayon/table.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/external_trait_impls/serde.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/lib.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/macros.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/map.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/raw/alloc.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/raw/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/raw_entry.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/rustc_entry.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/scopeguard.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/set.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/table.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/hashbrown-0.15.3/src/util.rs",
   ]
   inputs = []
   no_std = true
@@ -1299,7 +1300,7 @@
   # Unit tests skipped. Generate with --with-tests to include them.
   build_native_rust_unit_tests = false
   edition = "2021"
-  cargo_pkg_version = "0.15.2"
+  cargo_pkg_version = "0.15.3"
   cargo_pkg_authors = "Amanieu d'Antras <amanieu@gmail.com>"
   cargo_pkg_name = "hashbrown"
   cargo_pkg_description = "A Rust port of Google's SwissTable hash map"
@@ -1329,7 +1330,6 @@
     "compiler_builtins",
     "core",
     "nightly",
-    "raw-entry",
     "rustc-dep-of-std",
     "rustc-internal-api",
   ]
@@ -1348,188 +1348,188 @@
 if (!is_win) {
   cargo_crate("libc") {
     crate_type = "rlib"
-    crate_root = "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/lib.rs"
+    crate_root = "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/lib.rs"
     sources = [
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/fuchsia/aarch64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/fuchsia/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/fuchsia/riscv64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/fuchsia/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/hermit.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/lib.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/macros.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/primitives.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/psp.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/sgx.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/solid/aarch64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/solid/arm.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/solid/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/switch.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/teeos/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/trusty.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/aix/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/aix/powerpc64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/apple/b32/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/apple/b64/aarch64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/apple/b64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/apple/b64/x86_64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/apple/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/dragonfly/errno.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/dragonfly/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/aarch64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/arm.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd11/b32.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd12/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd13/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd14/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd15/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/freebsd15/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/powerpc.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/powerpc64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/riscv64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/x86.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/freebsdlike/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/netbsd/aarch64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/netbsd/arm.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/netbsd/mips.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/netbsd/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/netbsd/powerpc.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/netbsd/riscv64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/netbsd/sparc64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/netbsd/x86.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/netbsd/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/openbsd/aarch64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/openbsd/arm.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/openbsd/mips64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/openbsd/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/openbsd/powerpc.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/openbsd/powerpc64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/openbsd/riscv64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/openbsd/sparc64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/openbsd/x86.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/bsd/netbsdlike/openbsd/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/cygwin/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/haiku/b32.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/haiku/b64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/haiku/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/haiku/native.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/haiku/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/hurd/b32.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/hurd/b64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/hurd/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/android/b32/arm.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/android/b32/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/android/b32/x86/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/android/b64/aarch64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/android/b64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/android/b64/riscv64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/android/b64/x86_64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/android/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/emscripten/lfs64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/emscripten/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/arch/generic/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/arch/mips/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/arch/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/arch/powerpc/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/arch/sparc/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b32/arm/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b32/csky/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b32/m68k/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b32/mips/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b32/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b32/powerpc.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b32/riscv32/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b32/sparc/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b32/x86/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/aarch64/ilp32.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/aarch64/lp64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/loongarch64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/mips64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/s390x.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/gnu/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b32/arm/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b32/hexagon.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b32/mips/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b32/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b32/powerpc.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b32/riscv32/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b32/x86/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b64/loongarch64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b64/mips64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b64/powerpc64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b64/riscv64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b64/s390x.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b64/wasm32/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b64/wasm32/wali.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/b64/x86_64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/lfs64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/musl/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/uclibc/arm/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/uclibc/mips/mips32/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/uclibc/mips/mips64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/uclibc/mips/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/uclibc/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/uclibc/x86_64/l4re.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/uclibc/x86_64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/linux/uclibc/x86_64/other.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/linux_like/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/newlib/aarch64/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/newlib/arm/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/newlib/espidf/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/newlib/generic.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/newlib/horizon/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/newlib/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/newlib/powerpc/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/newlib/rtems/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/newlib/vita/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/nto/aarch64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/nto/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/nto/neutrino.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/nto/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/nuttx/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/redox/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/solarish/compat.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/solarish/illumos.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/solarish/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/solarish/solaris.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/solarish/x86.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/solarish/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/unix/solarish/x86_common.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/vxworks/aarch64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/vxworks/arm.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/vxworks/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/vxworks/powerpc.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/vxworks/powerpc64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/vxworks/riscv32.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/vxworks/riscv64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/vxworks/x86.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/vxworks/x86_64.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/wasi/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/wasi/p2.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/windows/gnu/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/windows/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/windows/msvc/mod.rs",
-      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/src/xous.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/fuchsia/aarch64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/fuchsia/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/fuchsia/riscv64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/fuchsia/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/hermit.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/lib.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/macros.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/primitives.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/psp.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/sgx.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/solid/aarch64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/solid/arm.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/solid/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/switch.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/teeos/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/trusty.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/aix/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/aix/powerpc64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/apple/b32/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/apple/b64/aarch64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/apple/b64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/apple/b64/x86_64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/apple/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/dragonfly/errno.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/dragonfly/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/aarch64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/arm.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd11/b32.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd12/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd13/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd13/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd14/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd14/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd15/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/freebsd15/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/powerpc.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/powerpc64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/riscv64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/x86.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/freebsdlike/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/netbsd/aarch64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/netbsd/arm.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/netbsd/mips.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/netbsd/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/netbsd/powerpc.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/netbsd/riscv64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/netbsd/sparc64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/netbsd/x86.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/netbsd/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/openbsd/aarch64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/openbsd/arm.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/openbsd/mips64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/openbsd/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/openbsd/powerpc.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/openbsd/powerpc64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/openbsd/riscv64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/openbsd/sparc64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/openbsd/x86.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/bsd/netbsdlike/openbsd/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/cygwin/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/haiku/b32.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/haiku/b64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/haiku/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/haiku/native.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/haiku/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/hurd/b32.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/hurd/b64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/hurd/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/android/b32/arm.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/android/b32/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/android/b32/x86/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/android/b64/aarch64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/android/b64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/android/b64/riscv64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/android/b64/x86_64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/android/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/emscripten/lfs64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/emscripten/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/arch/generic/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/arch/mips/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/arch/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/arch/powerpc/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/arch/sparc/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b32/arm/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b32/csky/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b32/m68k/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b32/mips/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b32/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b32/powerpc.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b32/riscv32/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b32/sparc/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b32/x86/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/aarch64/ilp32.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/aarch64/lp64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/loongarch64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/mips64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/s390x.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/gnu/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b32/arm/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b32/hexagon.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b32/mips/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b32/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b32/powerpc.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b32/riscv32/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b32/x86/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b64/loongarch64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b64/mips64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b64/powerpc64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b64/riscv64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b64/s390x.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b64/wasm32/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b64/wasm32/wali.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/b64/x86_64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/lfs64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/musl/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/uclibc/arm/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/uclibc/mips/mips32/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/uclibc/mips/mips64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/uclibc/mips/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/uclibc/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/uclibc/x86_64/l4re.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/uclibc/x86_64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/linux/uclibc/x86_64/other.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/linux_like/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/newlib/aarch64/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/newlib/arm/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/newlib/espidf/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/newlib/generic.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/newlib/horizon/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/newlib/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/newlib/powerpc/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/newlib/rtems/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/newlib/vita/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/nto/aarch64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/nto/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/nto/neutrino.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/nto/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/nuttx/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/redox/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/solarish/compat.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/solarish/illumos.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/solarish/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/solarish/solaris.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/solarish/x86.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/solarish/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/unix/solarish/x86_common.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/vxworks/aarch64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/vxworks/arm.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/vxworks/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/vxworks/powerpc.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/vxworks/powerpc64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/vxworks/riscv32.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/vxworks/riscv64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/vxworks/x86.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/vxworks/x86_64.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/wasi/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/wasi/p2.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/windows/gnu/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/windows/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/windows/msvc/mod.rs",
+      "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/src/xous.rs",
     ]
     inputs = []
     no_std = true
@@ -1537,7 +1537,7 @@
     # Unit tests skipped. Generate with --with-tests to include them.
     build_native_rust_unit_tests = false
     edition = "2021"
-    cargo_pkg_version = "0.2.171"
+    cargo_pkg_version = "0.2.172"
     cargo_pkg_authors = "The Rust Project Developers"
     cargo_pkg_name = "libc"
     cargo_pkg_description = "Raw FFI bindings to platform libraries like libc."
@@ -1561,8 +1561,8 @@
       "rustc-dep-of-std",
       "rustc-std-workspace-core",
     ]
-    build_root = "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/build.rs"
-    build_sources = [ "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.171/build.rs" ]
+    build_root = "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/build.rs"
+    build_sources = [ "//third_party/rust-toolchain/lib/rustlib/src/rust/library/vendor/libc-0.2.172/build.rs" ]
     rustenv = [
       "CFG_DISABLE_UNSTABLE_FEATURES=0",
       "STD_ENV_ARCH=$rust_target_arch",
@@ -2598,7 +2598,6 @@
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/anonymous_pipe/unsupported.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/anonymous_pipe/windows.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/args/common.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/args/hermit.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/args/mod.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/args/sgx.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/args/uefi.rs",
@@ -2611,6 +2610,18 @@
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/args/zkvm.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/backtrace.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/cmath.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/common.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/hermit.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/mod.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/sgx.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/solid.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/uefi.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/unix.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/unsupported.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/wasi.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/windows.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/xous.rs",
+    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env/zkvm.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/env_consts.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/exit_guard.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/fd/hermit.rs",
@@ -2777,7 +2788,6 @@
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/pal/xous/thread.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/pal/xous/time.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/pal/zkvm/abi.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/pal/zkvm/env.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/pal/zkvm/mod.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/pal/zkvm/os.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/std/src/sys/path/mod.rs",
@@ -3073,7 +3083,6 @@
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/stdarch/crates/std_detect/src/detect/os/linux/aarch64.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/stdarch/crates/std_detect/src/detect/os/linux/arm.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/stdarch/crates/std_detect/src/detect/os/linux/auxvec.rs",
-    "//third_party/rust-toolchain/lib/rustlib/src/rust/library/stdarch/crates/std_detect/src/detect/os/linux/cpuinfo.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/stdarch/crates/std_detect/src/detect/os/linux/loongarch.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/stdarch/crates/std_detect/src/detect/os/linux/mips.rs",
     "//third_party/rust-toolchain/lib/rustlib/src/rust/library/stdarch/crates/std_detect/src/detect/os/linux/mod.rs",
diff --git a/chrome/VERSION b/chrome/VERSION
index 75a23288..040574e 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=138
 MINOR=0
-BUILD=7180
+BUILD=7181
 PATCH=0
diff --git a/chrome/browser/actor/BUILD.gn b/chrome/browser/actor/BUILD.gn
index db6fdf42..406ab8c 100644
--- a/chrome/browser/actor/BUILD.gn
+++ b/chrome/browser/actor/BUILD.gn
@@ -104,6 +104,7 @@
     "//chrome/browser/optimization_guide:test_support",
     "//chrome/browser/safe_browsing",
     "//chrome/browser/ui:ui",
+    "//chrome/browser/ui:ui_features",
     "//chrome/browser/ui/zoom:zoom",
     "//chrome/test:test_support",
     "//chrome/test:test_support_ui",
diff --git a/chrome/browser/actor/actor_coordinator_browsertest.cc b/chrome/browser/actor/actor_coordinator_browsertest.cc
index 970c140..1aae0a9 100644
--- a/chrome/browser/actor/actor_coordinator_browsertest.cc
+++ b/chrome/browser/actor/actor_coordinator_browsertest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/glic/glic_keyed_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/actor.mojom-forward.h"
 #include "chrome/common/actor/action_result.h"
 #include "chrome/common/chrome_features.h"
diff --git a/chrome/browser/actor/tools/history_tool.cc b/chrome/browser/actor/tools/history_tool.cc
index 09ba189..8876f58ab 100644
--- a/chrome/browser/actor/tools/history_tool.cc
+++ b/chrome/browser/actor/tools/history_tool.cc
@@ -6,12 +6,14 @@
 
 #include "base/time/time.h"
 #include "chrome/browser/actor/tools/tool_callbacks.h"
+#include "chrome/common/actor.mojom.h"
 #include "chrome/common/actor/action_result.h"
 #include "components/tabs/public/tab_interface.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
+#include "net/base/net_errors.h"
 #include "third_party/abseil-cpp/absl/strings/str_format.h"
 
 namespace {
@@ -36,18 +38,21 @@
 HistoryTool::~HistoryTool() = default;
 
 void HistoryTool::Validate(ValidateCallback callback) {
-  // TODO(crbug.com/409558980): Add distinct error codes.
   NavigationController& controller = web_contents()->GetController();
-  if ((direction_ == kBack && !controller.CanGoBack()) ||
-      (direction_ == kForward && !controller.CanGoForward())) {
-    PostResponseTask(std::move(callback), MakeErrorResult());
-    return;
+  mojom::ActionResultPtr result;
+
+  if (direction_ == kBack && !controller.CanGoBack()) {
+    result = MakeResult(mojom::ActionResultCode::kHistoryNoBackEntries);
+  } else if (direction_ == kForward && !controller.CanGoForward()) {
+    result = MakeResult(mojom::ActionResultCode::kHistoryNoForwardEntries);
+  } else {
+    result = MakeOkResult();
   }
 
   // TODO(crbug.com/402731599): Additional validation here (e.g. is URL in
   // allowlist).
 
-  PostResponseTask(std::move(callback), MakeOkResult());
+  PostResponseTask(std::move(callback), std::move(result));
 }
 
 void HistoryTool::Invoke(InvokeCallback callback) {
@@ -120,12 +125,31 @@
     return;
   }
 
-  // TODO(crbug.com/409558980): Add distinct error codes.
   if (in_flight_navigation_ids_.erase(navigation_handle->GetNavigationId())) {
-    auto result =
-        (navigation_handle->HasCommitted() && !navigation_handle->IsErrorPage())
-            ? MakeOkResult()
-            : MakeErrorResult();
+    mojom::ActionResultPtr result;
+    auto details_msg = [](NavigationHandle* handle) {
+      std::string msg;
+      if (handle->GetNavigationDiscardReason()) {
+        msg = absl::StrFormat("DiscardReason[%d] ",
+                              handle->GetNavigationDiscardReason().value());
+      }
+      if (handle->GetNetErrorCode() != net::OK) {
+        msg +=
+            absl::StrFormat("ErrorCode[%s]",
+                            net::ErrorToShortString(handle->GetNetErrorCode()));
+      }
+      return msg;
+    };
+
+    if (!navigation_handle->HasCommitted()) {
+      result = MakeResult(mojom::ActionResultCode::kHistoryFailedBeforeCommit,
+                          details_msg(navigation_handle));
+    } else if (navigation_handle->IsErrorPage()) {
+      result = MakeResult(mojom::ActionResultCode::kHistoryErrorPage,
+                          details_msg(navigation_handle));
+    } else {
+      result = MakeOkResult();
+    }
     FinishToolInvocationIfNeeded(std::move(result));
   }
 }
diff --git a/chrome/browser/actor/tools/tools_browsertest.cc b/chrome/browser/actor/tools/tools_browsertest.cc
index f4caee5..f65505ac 100644
--- a/chrome/browser/actor/tools/tools_browsertest.cc
+++ b/chrome/browser/actor/tools/tools_browsertest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/actor/actor_test_util.h"
 #include "chrome/browser/actor/tools/wait_tool.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
 #include "chrome/common/actor.mojom.h"
@@ -1125,7 +1126,8 @@
   {
     TestFuture<mojom::ActionResultPtr> result;
     actor_coordinator().Act(MakeHistoryForward(), result.GetCallback());
-    ExpectErrorResult(result, mojom::ActionResultCode::kError);
+    ExpectErrorResult(result,
+                      mojom::ActionResultCode::kHistoryNoForwardEntries);
     EXPECT_EQ(web_contents()->GetURL(), url_second);
   }
 
@@ -1138,7 +1140,7 @@
   {
     TestFuture<mojom::ActionResultPtr> result;
     actor_coordinator().Act(MakeHistoryBack(), result.GetCallback());
-    ExpectErrorResult(result, mojom::ActionResultCode::kError);
+    ExpectErrorResult(result, mojom::ActionResultCode::kHistoryNoBackEntries);
     EXPECT_EQ(web_contents()->GetURL(), url_second);
   }
 }
diff --git a/chrome/browser/ai/ai_language_model.cc b/chrome/browser/ai/ai_language_model.cc
index 64c3414b..97ec35d 100644
--- a/chrome/browser/ai/ai_language_model.cc
+++ b/chrome/browser/ai/ai_language_model.cc
@@ -580,26 +580,56 @@
     mojo::PendingRemote<blink::mojom::AIManagerCreateLanguageModelClient>
         create_client,
     std::optional<uint32_t> token_count) {
-  mojo::Remote<blink::mojom::AIManagerCreateLanguageModelClient> client(
-      std::move(create_client));
   if (!initial_session_ || !token_count) {
-    client->OnError(
-        blink::mojom::AIManagerCreateClientError::kUnableToCreateSession);
+    mojo::Remote<blink::mojom::AIManagerCreateLanguageModelClient>(
+        std::move(create_client))
+        ->OnError(
+            blink::mojom::AIManagerCreateClientError::kUnableToCreateSession);
     return;
   }
 
   uint32_t max_tokens = context_->max_tokens();
   if (*token_count > max_tokens) {
-    client->OnError(
-        blink::mojom::AIManagerCreateClientError::kInitialInputTooLarge);
+    mojo::Remote<blink::mojom::AIManagerCreateLanguageModelClient>(
+        std::move(create_client))
+        ->OnError(
+            blink::mojom::AIManagerCreateClientError::kInitialInputTooLarge);
     return;
   }
 
-  if (input) {
-    // `context_` will track how many tokens are remaining after the initial
-    // prompts. The initial prompts cannot be evicted.
-    context_ = std::make_unique<Context>(max_tokens - *token_count);
+  // `context_` will track how many tokens are remaining after the initial
+  // prompts. The initial prompts cannot be evicted.
+  context_ = std::make_unique<Context>(max_tokens - *token_count);
 
+  if (input) {
+    auto safety_input = CreateStringMessage(*input);
+    safety_checker_->RunRequestChecks(
+        safety_input,
+        base::BindOnce(&AILanguageModel::InitializeSafetyChecksComplete,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(input),
+                       std::move(create_client)));
+  } else {
+    InitializeSafetyChecksComplete(nullptr, std::move(create_client),
+                                   optimization_guide::SafetyChecker::Result());
+  }
+}
+
+void AILanguageModel::InitializeSafetyChecksComplete(
+    on_device_model::mojom::InputPtr input,
+    mojo::PendingRemote<blink::mojom::AIManagerCreateLanguageModelClient>
+        create_client,
+    optimization_guide::SafetyChecker::Result safety_result) {
+  mojo::Remote<blink::mojom::AIManagerCreateLanguageModelClient> client(
+      std::move(create_client));
+  // TODO(crbug.com/415808003): Add more fine grained errors on safety check
+  // failure.
+  if (safety_result.failed_to_run || safety_result.is_unsafe ||
+      safety_result.is_unsupported_language) {
+    client->OnError(
+        blink::mojom::AIManagerCreateClientError::kUnableToCreateSession);
+    return;
+  }
+  if (input) {
     // No ContextClient is passed here since this operation should never be
     // cancelled unless the session is destroyed.
     initial_session_->Append(MakeAppendOptions(std::move(input)), {});
diff --git a/chrome/browser/ai/ai_language_model.h b/chrome/browser/ai/ai_language_model.h
index 26afc43..36f89e6 100644
--- a/chrome/browser/ai/ai_language_model.h
+++ b/chrome/browser/ai/ai_language_model.h
@@ -155,6 +155,11 @@
       mojo::PendingRemote<blink::mojom::AIManagerCreateLanguageModelClient>
           create_client,
       std::optional<uint32_t> token_count);
+  void InitializeSafetyChecksComplete(
+      on_device_model::mojom::InputPtr input,
+      mojo::PendingRemote<blink::mojom::AIManagerCreateLanguageModelClient>
+          create_client,
+      optimization_guide::SafetyChecker::Result safety_result);
 
   void ForkInternal(
       mojo::PendingRemote<blink::mojom::AIManagerCreateLanguageModelClient>
diff --git a/chrome/browser/ai/ai_language_model_unittest.cc b/chrome/browser/ai/ai_language_model_unittest.cc
index 5258322..f4245c5 100644
--- a/chrome/browser/ai/ai_language_model_unittest.cc
+++ b/chrome/browser/ai/ai_language_model_unittest.cc
@@ -821,6 +821,33 @@
   EXPECT_EQ(measure_future.Get(), std::string("UfooEM").size());
 }
 
+TEST_F(AILanguageModelTest, TextSafetyInitialPrompts) {
+  auto config = CreateConfig();
+  config.set_can_skip_text_safety(false);
+  fake_broker_.UpdateModelAdaptation(
+      optimization_guide::FakeAdaptationAsset({.config = config}));
+  auto safety_config = CreateSafetyConfig();
+  auto* check = safety_config.add_request_check();
+  check->mutable_input_template()->Add(
+      FieldSubstitution("%s", StringValueField()));
+  optimization_guide::FakeSafetyModelAsset safety_asset(
+      std::move(safety_config));
+  fake_broker_.UpdateSafetyModel(safety_asset.model_info());
+
+  base::test::TestFuture<blink::mojom::AIManagerCreateClientError> future;
+  AITestUtils::MockCreateLanguageModelClient language_model_client;
+  EXPECT_CALL(language_model_client, OnError(_)).WillOnce([&](auto error) {
+    future.SetValue(error);
+  });
+
+  auto options = blink::mojom::AILanguageModelCreateOptions::New();
+  options->initial_prompts.push_back(MakePrompt(Role::kSystem, "unsafe"));
+  GetAIManagerRemote()->CreateLanguageModel(
+      language_model_client.BindNewPipeAndPassRemote(), std::move(options));
+  EXPECT_EQ(future.Take(),
+            blink::mojom::AIManagerCreateClientError::kUnableToCreateSession);
+}
+
 TEST_F(AILanguageModelTest, TextSafetyInput) {
   auto config = CreateConfig();
   config.set_can_skip_text_safety(false);
diff --git a/chrome/browser/ash/boca/on_task/on_task_session_manager_browsertest.cc b/chrome/browser/ash/boca/on_task/on_task_session_manager_browsertest.cc
index 20b99ae..e06d2f9 100644
--- a/chrome/browser/ash/boca/on_task/on_task_session_manager_browsertest.cc
+++ b/chrome/browser/ash/boca/on_task/on_task_session_manager_browsertest.cc
@@ -445,6 +445,63 @@
 }
 
 IN_PROC_BROWSER_TEST_F(OnTaskSessionManagerBrowserTest,
+                       ShouldSkipCountdownWhenPauseDuringLockedModeCountdown) {
+  content::TestNavigationObserver navigation_observer((GURL(kTestUrl1)));
+  navigation_observer.StartWatchingNewWebContents();
+
+  // Start OnTask session and spawn one tab outside the homepage tab.
+  GetOnTaskSessionManager()->OnSessionStarted(kSessionId,
+                                              ::boca::UserIdentity());
+  ::boca::Bundle bundle;
+  bundle.add_content_configs()->set_url(kTestUrl1);
+  GetOnTaskSessionManager()->OnBundleUpdated(bundle);
+  navigation_observer.Wait();
+
+  Browser* const boca_app_browser = FindBocaSystemWebAppBrowser();
+  ASSERT_THAT(boca_app_browser, NotNull());
+  ASSERT_TRUE(boca_app_browser->IsLockedForOnTask());
+  auto* const tab_strip_model = boca_app_browser->tab_strip_model();
+  ASSERT_EQ(tab_strip_model->count(), 2);
+  tab_strip_model->ActivateTabAt(1);
+  EXPECT_EQ(tab_strip_model->GetActiveWebContents()->GetVisibleURL(),
+            GURL(kTestUrl1));
+
+  // Lock the boca app.
+  bundle.set_locked(true);
+  GetOnTaskSessionManager()->OnBundleUpdated(bundle);
+  ASSERT_FALSE(platform_util::IsBrowserLockedFullscreen(boca_app_browser));
+
+  // Pause the boca app.
+  bundle.set_lock_to_app_home(true);
+  GetOnTaskSessionManager()->OnBundleUpdated(bundle);
+  ASSERT_TRUE(platform_util::IsBrowserLockedFullscreen(boca_app_browser));
+  EXPECT_FALSE(chromeos::wm::CanFloatWindow(
+      boca_app_browser->window()->GetNativeWindow()));
+  const auto* const browser_view =
+      BrowserView::GetBrowserViewForBrowser(boca_app_browser);
+  // Wait until immersive mode is disabled in pause mode.
+  ASSERT_TRUE(base::test::RunUntil([&]() {
+    return !browser_view->immersive_mode_controller()->IsEnabled();
+  }));
+  EXPECT_EQ(tab_strip_model->GetActiveWebContents()->GetVisibleURL(),
+            GURL(kChromeBocaAppUntrustedIndexURL));
+
+  // Unpause the boca app.
+  bundle.set_lock_to_app_home(false);
+  GetOnTaskSessionManager()->OnBundleUpdated(bundle);
+  ASSERT_TRUE(platform_util::IsBrowserLockedFullscreen(boca_app_browser));
+  EXPECT_FALSE(chromeos::wm::CanFloatWindow(
+      boca_app_browser->window()->GetNativeWindow()));
+  EXPECT_TRUE(browser_view->immersive_mode_controller()->IsEnabled());
+
+  // Unlock the Boca app to unblock test teardown that involves browser window
+  // close.
+  bundle.set_locked(false);
+  GetOnTaskSessionManager()->OnBundleUpdated(bundle);
+  EXPECT_FALSE(platform_util::IsBrowserLockedFullscreen(boca_app_browser));
+}
+
+IN_PROC_BROWSER_TEST_F(OnTaskSessionManagerBrowserTest,
                        ShouldNotLockBocaSWAInAppReloadIfLockInProgress) {
   content::TestNavigationObserver navigation_observer((GURL(kTestUrl1)));
   navigation_observer.StartWatchingNewWebContents();
diff --git a/chrome/browser/ash/smb_client/smb_url.cc b/chrome/browser/ash/smb_client/smb_url.cc
index 2cc4afc2..4179cf28 100644
--- a/chrome/browser/ash/smb_client/smb_url.cc
+++ b/chrome/browser/ash/smb_client/smb_url.cc
@@ -133,8 +133,9 @@
   url::StdStringCanonOutput canonical_output(&url_);
 
   url::Component scheme;
-  if (!url::CanonicalizeScheme(url.c_str(), initial_parsed.scheme,
-                               &canonical_output, &scheme)) {
+  if (!url::CanonicalizeScheme(
+          initial_parsed.scheme.as_string_view_on(url.c_str()),
+          &canonical_output, &scheme)) {
     Reset();
     return;
   }
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
index c0e1f21e..92259b4 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -12,6 +12,7 @@
 #include "base/strings/cstring_view.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "chrome/browser/ui/lens/lens_overlay_entry_point_controller.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "chrome/browser/autocomplete/document_suggestions_service_factory.h"
@@ -41,6 +42,7 @@
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/omnibox/omnibox_pedal_implementations.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
@@ -537,6 +539,21 @@
   return history_embeddings::IsHistoryEmbeddingsSettingVisible(profile_);
 }
 
+bool ChromeAutocompleteProviderClient::IsLensEnabled() const {
+#if !BUILDFLAG(IS_ANDROID)
+  if (auto* lens_search_controller =
+          GetLensSearchController(GetWebContents(web_contents_getter_))) {
+    // Guaranteed to exist if lens_search_controller is not null.
+    return lens_search_controller->GetTabInterface()
+        ->GetBrowserWindowInterface()
+        ->GetFeatures()
+        .lens_overlay_entry_point_controller()
+        ->IsEnabled();
+  }
+#endif
+  return false;
+}
+
 base::CallbackListSubscription
 ChromeAutocompleteProviderClient::GetLensSuggestInputsWhenReady(
     LensOverlaySuggestInputsCallback callback) const {
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
index 0f8c25c..bd8cd189 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
@@ -121,6 +121,7 @@
   bool IsSharingHubAvailable() const override;
   bool IsHistoryEmbeddingsEnabled() const override;
   bool IsHistoryEmbeddingsSettingVisible() const override;
+  bool IsLensEnabled() const override;
   base::CallbackListSubscription GetLensSuggestInputsWhenReady(
       LensOverlaySuggestInputsCallback callback) const override;
   base::WeakPtr<AutocompleteProviderClient> GetWeakPtr() override;
diff --git a/chrome/browser/background/glic/BUILD.gn b/chrome/browser/background/glic/BUILD.gn
index dfb0b9f..98de8e7 100644
--- a/chrome/browser/background/glic/BUILD.gn
+++ b/chrome/browser/background/glic/BUILD.gn
@@ -66,6 +66,7 @@
     "//chrome/browser/glic:glic",
     "//chrome/browser/status_icons:status_icons",
     "//chrome/browser/ui",
+    "//chrome/browser/ui:ui_features",
     "//chrome/browser/ui/webui/whats_new:whats_new",
     "//chrome/common:chrome_features",
     "//chrome/test:test_support",
diff --git a/chrome/browser/background/glic/glic_status_icon_unittest.cc b/chrome/browser/background/glic/glic_status_icon_unittest.cc
index 3f2f0c3..782ecbda 100644
--- a/chrome/browser/background/glic/glic_status_icon_unittest.cc
+++ b/chrome/browser/background/glic/glic_status_icon_unittest.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/status_icons/status_icon.h"
 #include "chrome/browser/status_icons/status_tray.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/webui/whats_new/whats_new_ui.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/fake_profile_manager.h"
diff --git a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java
index 4033112..c7900ff 100644
--- a/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java
+++ b/chrome/browser/collaboration/android/java/src/org/chromium/chrome/browser/collaboration/CollaborationIntegrationTest.java
@@ -208,7 +208,11 @@
         mActivityTestRule.loadUrlInNewTab(mUrl);
 
         final AtomicBoolean joinCalled = new AtomicBoolean();
-        mDataSharingUIDelegate.setShowJoinFlowRunnable(() -> joinCalled.set(true));
+        Callback<Boolean> callback =
+                (success) -> {
+                    joinCalled.set(true);
+                };
+        mDataSharingUIDelegate.setShowJoinFlowCallback(callback);
         setFakePreviewData();
 
         // Verify that the fullscreen sign-in promo is shown and accept.
diff --git a/chrome/browser/contextual_cueing/BUILD.gn b/chrome/browser/contextual_cueing/BUILD.gn
index bc6e7a0..4c20fd8c 100644
--- a/chrome/browser/contextual_cueing/BUILD.gn
+++ b/chrome/browser/contextual_cueing/BUILD.gn
@@ -85,6 +85,7 @@
     "//chrome/browser:global_features",
     "//chrome/browser/content_extraction",
     "//chrome/browser/optimization_guide:test_support",
+    "//chrome/browser/ui:ui_features",
     "//chrome/common:buildflags",
     "//chrome/test:test_support",
     "//components/sync_preferences:test_support",
diff --git a/chrome/browser/contextual_cueing/contextual_cueing_helper_unittest.cc b/chrome/browser/contextual_cueing/contextual_cueing_helper_unittest.cc
index 87ae3758..e0cee5b 100644
--- a/chrome/browser/contextual_cueing/contextual_cueing_helper_unittest.cc
+++ b/chrome/browser/contextual_cueing/contextual_cueing_helper_unittest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/page_content_annotations/page_content_extraction_service.h"
 #include "chrome/browser/page_content_annotations/page_content_extraction_service_factory.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
diff --git a/chrome/browser/contextual_cueing/contextual_cueing_service_browsertest.cc b/chrome/browser/contextual_cueing/contextual_cueing_service_browsertest.cc
index 1d10714..318d176 100644
--- a/chrome/browser/contextual_cueing/contextual_cueing_service_browsertest.cc
+++ b/chrome/browser/contextual_cueing/contextual_cueing_service_browsertest.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/FakeDataSharingUIDelegateImpl.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/FakeDataSharingUIDelegateImpl.java
index d26e753..67212c5 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/FakeDataSharingUIDelegateImpl.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/FakeDataSharingUIDelegateImpl.java
@@ -20,10 +20,12 @@
 @NullMarked
 public class FakeDataSharingUIDelegateImpl implements DataSharingUIDelegate {
 
-    private @Nullable Runnable mShowJoinFlowRunnable;
     private @Nullable Callback<Boolean> mShowCreateFlowCallback;
-    private @Nullable Runnable mShowManageFlowRunnable;
+    private @Nullable Callback<Boolean> mShowJoinFlowCallback;
+    private @Nullable Callback<Boolean> mShowManageFlowCallback;
     private @Nullable DataSharingCreateUiConfig mCreateUiConfig;
+    private @Nullable DataSharingJoinUiConfig mJoinUiConfig;
+    private @Nullable DataSharingManageUiConfig mManageUiConfig;
 
     public FakeDataSharingUIDelegateImpl() {}
 
@@ -45,13 +47,21 @@
 
     @Override
     public String showJoinFlow(DataSharingJoinUiConfig joinUiConfig) {
-        if (mShowJoinFlowRunnable != null) mShowJoinFlowRunnable.run();
+        assert this.mJoinUiConfig == null;
+        this.mJoinUiConfig = joinUiConfig;
+        if (mShowJoinFlowCallback != null) {
+            mShowJoinFlowCallback.onResult(true);
+        }
         return "";
     }
 
     @Override
     public String showManageFlow(DataSharingManageUiConfig manageUiConfig) {
-        if (mShowManageFlowRunnable != null) mShowManageFlowRunnable.run();
+        assert this.mManageUiConfig == null;
+        this.mManageUiConfig = manageUiConfig;
+        if (mShowManageFlowCallback != null) {
+            mShowManageFlowCallback.onResult(true);
+        }
         return "";
     }
 
@@ -62,19 +72,19 @@
     @Override
     public void destroyFlow(String sessionId) {}
 
-    /* Set a runnable to be called when showJoinFlow() is called. */
-    public void setShowJoinFlowRunnable(Runnable runnable) {
-        mShowJoinFlowRunnable = runnable;
-    }
-
     /* Set a callback to be called when showCreateFlow() is called. */
     public void setShowCreateFlowCallback(Callback<Boolean> callback) {
         mShowCreateFlowCallback = callback;
     }
 
-    /* Set a runnable to be called when showManageFlow() is called. */
-    public void setShowManageFlowRunnable(Runnable runnable) {
-        mShowManageFlowRunnable = runnable;
+    /* Set a callback to be called when showJoinFlow() is called. */
+    public void setShowJoinFlowCallback(Callback<Boolean> callback) {
+        mShowJoinFlowCallback = callback;
+    }
+
+    /* Set a callback to be called when showManageFlow() is called. */
+    public void setShowManageFlowCallback(Callback<Boolean> callback) {
+        mShowManageFlowCallback = callback;
     }
 
     /* Creates group data and calls onGroupCreatedWithWait when showCreateFlow() is called. */
diff --git a/chrome/browser/enterprise/client_certificates/cert_utils.cc b/chrome/browser/enterprise/client_certificates/cert_utils.cc
index f993222..47bc1b91 100644
--- a/chrome/browser/enterprise/client_certificates/cert_utils.cc
+++ b/chrome/browser/enterprise/client_certificates/cert_utils.cc
@@ -11,6 +11,11 @@
 #include "components/enterprise/client_certificates/core/private_key_types.h"
 #include "components/enterprise/client_certificates/core/unexportable_private_key_factory.h"
 
+#if BUILDFLAG(IS_WIN)
+#include "components/enterprise/client_certificates/core/features.h"
+#include "components/enterprise/client_certificates/core/win/windows_software_private_key_factory.h"
+#endif  // BUILDFLAG(IS_WIN)
+
 namespace client_certificates {
 
 namespace {
@@ -34,6 +39,18 @@
     sub_factories.insert_or_assign(PrivateKeySource::kUnexportableKey,
                                    std::move(unexportable_key_factory));
   }
+
+#if BUILDFLAG(IS_WIN)
+  if (features::AreWindowsSoftwareKeysEnabled()) {
+    auto windows_software_key_factory =
+        WindowsSoftwarePrivateKeyFactory::TryCreate();
+    if (windows_software_key_factory) {
+      sub_factories.insert_or_assign(PrivateKeySource::kOsSoftwareKey,
+                                     std::move(windows_software_key_factory));
+    }
+  }
+#endif  // BUILDFLAG(IS_WIN)
+
   sub_factories.insert_or_assign(PrivateKeySource::kSoftwareKey,
                                  std::make_unique<ECPrivateKeyFactory>());
 
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.cc b/chrome/browser/extensions/api/cookies/cookies_api.cc
index d4d7cfd..c40f736 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_api.cc
@@ -138,12 +138,8 @@
 
 CookiesEventRouter::CookiesEventRouter(content::BrowserContext* context)
     : profile_(Profile::FromBrowserContext(context)),
-      profile_observation_(this)
-#if !BUILDFLAG(IS_ANDROID)
-      ,
-      otr_profile_observation_(this)
-#endif
-{
+      profile_observation_(this),
+      otr_profile_observation_(this) {
   MaybeStartListening();
   profile_observation_.Observe(profile_);
 }
@@ -226,9 +222,7 @@
   }
 
   DCHECK(!otr_receiver_.is_bound());
-#if !BUILDFLAG(IS_ANDROID)
   otr_profile_observation_.Observe(off_the_record);
-#endif
   BindToCookieManager(&otr_receiver_, off_the_record);
 }
 
@@ -239,9 +233,7 @@
           ? original_profile->GetPrimaryOTRProfile(/*create_if_needed=*/true)
           : nullptr;
   if (profile == otr_profile) {
-#if !BUILDFLAG(IS_ANDROID)
     otr_profile_observation_.Reset();
-#endif
     otr_receiver_.reset();
   }
 }
@@ -261,9 +253,7 @@
   }
 
   if (!otr_receiver_.is_bound() && otr_profile) {
-#if !BUILDFLAG(IS_ANDROID)
     otr_profile_observation_.Observe(otr_profile);
-#endif
     BindToCookieManager(&otr_receiver_, otr_profile);
   }
 }
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.h b/chrome/browser/extensions/api/cookies/cookies_api.h
index 5e01d7b..645f423e 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.h
+++ b/chrome/browser/extensions/api/cookies/cookies_api.h
@@ -89,11 +89,7 @@
 
   base::ScopedObservation<Profile, ProfileObserver> profile_observation_;
 
-#if !BUILDFLAG(IS_ANDROID)
-  // TODO(crbug.com/414825266): This is causing check failure on clank.
-  // Fix the root cause and remove `!ifdef android`.
   base::ScopedObservation<Profile, ProfileObserver> otr_profile_observation_;
-#endif
 
   // To listen to cookie changes in both the original and the off the record
   // profiles, we need a pair of bindings, as well as a pair of
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index 33a7308c..719f71e 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -681,7 +681,14 @@
       << "a specific tab id.";
 }
 
-IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType, IncognitoBasic) {
+// TODO(crbug.com/414519997): Flaky on Linux_ASan_LSan.
+#if defined(SANITIZER_LINUX)
+#define MAYBE_IncognitoBasic DISABLED_IncognitoBasic
+#else
+#define MAYBE_IncognitoBasic IncognitoBasic
+#endif
+IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType,
+                       MAYBE_IncognitoBasic) {
   ExtensionTestMessageListener ready_listener("ready");
   ASSERT_TRUE(embedded_test_server()->Start());
   scoped_refptr<const Extension> extension =
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index f2ae7a8..067c5c07 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -356,12 +356,8 @@
   // in the manifest.
   if (!popup_string->empty()) {
     popup_url = extension()->GetResourceURL(*popup_string);
-    // Validate popup is same-origin (only for this extension). We do not
-    // validate the file exists (like we do in manifest validation) because an
-    // extension could potentially intercept the request with a service worker
-    // and dynamically provide content.
-    if (!extension()->origin().IsSameOriginWith(popup_url)) {
-      return RespondNow(Error(manifest_errors::kInvalidExtensionOriginPopup));
+    if (!popup_url.is_valid()) {
+      return RespondNow(Error(manifest_errors::kInvalidExtensionPopupPath));
     }
   }
 
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc b/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
index db8633d..6c9e5e36 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
@@ -1198,7 +1198,7 @@
   auto get_script = [](int tab_id, const char* popup_input) {
     constexpr char kSetPopup[] = R"(setPopup({tabId: %d, popup: '%s'}, "%s");)";
     return base::StringPrintf(kSetPopup, tab_id, popup_input,
-                              manifest_errors::kInvalidExtensionOriginPopup);
+                              manifest_errors::kInvalidExtensionPopupPath);
   };
 
   content::RenderFrameHost* navigated_host = ui_test_utils::NavigateToURL(
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
index 5733c45..d6eb366 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -20,7 +20,7 @@
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_enums.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
@@ -298,11 +298,11 @@
   const base::TimeTicks start_time = base::TimeTicks::Now();
   IndicatorChangeObserver observer(browser());
   while (!base::Contains(GetTabAlertStatesForContents(contents),
-                         TabAlertState::TAB_CAPTURING)) {
+                         tabs::TabAlert::TAB_CAPTURING)) {
     if (base::TimeTicks::Now() - start_time >
             TestTimeouts::action_max_timeout()) {
       EXPECT_THAT(GetTabAlertStatesForContents(contents),
-                  ::testing::Contains(TabAlertState::TAB_CAPTURING));
+                  ::testing::Contains(tabs::TabAlert::TAB_CAPTURING));
       return;
     }
     observer.WaitForTabChange();
diff --git a/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc b/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc
index 37e82c6..050e49ed 100644
--- a/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc
+++ b/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc
@@ -398,7 +398,7 @@
   }
 
   TabStripModel* source_tab_strip = source_browser->tab_strip_model();
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       source_tab_strip->DetachTabGroupForInsertion(group);
   target_tab_strip->InsertDetachedTabGroupAt(std::move(detached_group),
                                              new_index);
diff --git a/chrome/browser/extensions/api/tab_groups/tab_groups_api_apitest.cc b/chrome/browser/extensions/api/tab_groups/tab_groups_api_apitest.cc
index 6c357f5..16f9008 100644
--- a/chrome/browser/extensions/api/tab_groups/tab_groups_api_apitest.cc
+++ b/chrome/browser/extensions/api/tab_groups/tab_groups_api_apitest.cc
@@ -77,7 +77,7 @@
   TestEventRouterObserver event_observer(
       EventRouter::Get(browser()->profile()));
 
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       browser()->tab_strip_model()->DetachTabGroupForInsertion(group);
 
   event_observer.WaitForEventWithName(api::tab_groups::OnRemoved::kEventName);
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index 8a3b929..833d62b9 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -1765,7 +1765,7 @@
   TestEventRouterObserver event_observer(
       EventRouter::Get(browser()->profile()));
 
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       browser()->tab_strip_model()->DetachTabGroupForInsertion(group);
 
   event_observer.WaitForEventWithName(api::tabs::OnUpdated::kEventName);
diff --git a/chrome/browser/extensions/chrome_url_request_util.cc b/chrome/browser/extensions/chrome_url_request_util.cc
index 2a904ccf..4ec6c633 100644
--- a/chrome/browser/extensions/chrome_url_request_util.cc
+++ b/chrome/browser/extensions/chrome_url_request_util.cc
@@ -298,10 +298,11 @@
 
   const base::FilePath request_relative_path =
       extensions::file_util::ExtensionURLToRelativeFilePath(request.url);
-  if (!ExtensionsBrowserClient::Get()
-           ->GetComponentExtensionResourceManager()
-           ->IsComponentExtensionResource(extension_resources_path,
-                                          request_relative_path, resource_id)) {
+  auto* manager =
+      ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager();
+  CHECK(manager);
+  if (!manager->IsComponentExtensionResource(
+          extension_resources_path, request_relative_path, resource_id)) {
     return base::FilePath();
   }
   DCHECK_NE(0, *resource_id);
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index c2b4aff..4bb691e 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -326,7 +326,13 @@
   DCHECK(!system_->is_ready());  // Can't redo init.
   DCHECK_EQ(registry_->enabled_extensions().size(), 0u);
 
+// TODO(crbug.com/417617863): Skip loading component extensions until the
+// startup crash is fixed on desktop Android (see bug).
+#if BUILDFLAG(ENABLE_EXTENSIONS)
   component_loader_->LoadAll();
+#else
+  LOG(WARNING) << "Skipping component extension load.";
+#endif
   bool load_saved_extensions = true;
   bool load_command_line_extensions =
       extension_registrar_->extensions_enabled();
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 836a9ed1..9ebf3ae 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -4103,6 +4103,9 @@
 }
 #endif  // defined(ENABLE_BLOCKLIST_TESTS)
 
+// TODO(crbug.com/417617863): Skip loading component extensions until the
+// startup crash is fixed on desktop Android (see bug).
+#if BUILDFLAG(ENABLE_EXTENSIONS)
 // Tests blocking then unblocking enabled component extensions after the service
 // has been initialized.
 TEST_F(ExtensionServiceTest, BlockAndUnblockEnabledComponentExtension) {
@@ -4123,6 +4126,7 @@
   // Component extension should never block.
   AssertExtensionBlocksAndUnblocks(false, good0);
 }
+#endif
 
 // Tests blocking then unblocking a theme after the service has been
 // initialized.
@@ -4205,6 +4209,9 @@
   EXPECT_EQ(0u, registry()->enabled_extensions().size());
 }
 
+// TODO(crbug.com/417617863): Skip loading component extensions until the
+// startup crash is fixed on desktop Android (see bug).
+#if BUILDFLAG(ENABLE_EXTENSIONS)
 // Tests that component extensions are not blocklisted by policy.
 TEST_F(ExtensionServiceTest, ComponentExtensionAllowlisted) {
   InitializeEmptyExtensionServiceWithTestingPrefs();
@@ -4286,6 +4293,7 @@
                   ->active_permissions()
                   .HasAPIPermission(APIPermissionID::kTab));
 }
+#endif
 
 // Tests that policy-installed extensions are not blocklisted by policy.
 TEST_F(ExtensionServiceTest, PolicyInstalledExtensionsAllowlisted) {
@@ -6976,6 +6984,9 @@
       loaded_extensions()[2]->url()));
 }
 
+// TODO(crbug.com/417617863): Skip loading component extensions until the
+// startup crash is fixed on desktop Android (see bug).
+#if BUILDFLAG(ENABLE_EXTENSIONS)
 // Tests ComponentLoader::Add().
 TEST_F(ExtensionServiceTest, ComponentExtensions) {
   // Component extensions should work even when extensions are disabled.
@@ -7012,6 +7023,7 @@
   ASSERT_EQ(1u, registry()->enabled_extensions().size());
   EXPECT_EQ(extension_id, (*registry()->enabled_extensions().begin())->id());
 }
+#endif
 
 TEST_F(ExtensionServiceTest, InstallPriorityExternalUpdateUrl) {
   InitializeEmptyExtensionService();
diff --git a/chrome/browser/glic/BUILD.gn b/chrome/browser/glic/BUILD.gn
index 66a1e6d..3e3827c4 100644
--- a/chrome/browser/glic/BUILD.gn
+++ b/chrome/browser/glic/BUILD.gn
@@ -180,6 +180,7 @@
     "//chrome/browser/ui:browser_element_identifiers",
     "//chrome/browser/ui:browser_list",
     "//chrome/browser/ui:browser_navigator_params_headers",
+    "//chrome/browser/ui:ui_features",
     "//chrome/browser/ui/browser_window:browser_window",
     "//chrome/browser/ui/tabs:tab_strip",
     "//chrome/browser/ui/user_education",
@@ -249,6 +250,7 @@
   deps = [
     ":glic",
     ":impl",
+    "//chrome/browser/ui:ui_features",
     "//components/signin/public/identity_manager:test_support",
     "//ui/events:test_support",
   ]
@@ -280,6 +282,7 @@
     "//chrome/browser/prefs:prefs",
     "//chrome/browser/status_icons:status_icons",
     "//chrome/browser/ui",
+    "//chrome/browser/ui:ui_features",
     "//chrome/common:chrome_features",
     "//chrome/test:test_support",
     "//components/live_caption:constants",
@@ -316,6 +319,7 @@
     "//chrome/browser/policy:test_support",
     "//chrome/browser/prefs:prefs",
     "//chrome/browser/ui",
+    "//chrome/browser/ui:ui_features",
     "//chrome/common:constants",
     "//chrome/test:test_support",
     "//chrome/test:test_support_ui",
diff --git a/chrome/browser/glic/browser_ui/glic_button_controller_unittest.cc b/chrome/browser/glic/browser_ui/glic_button_controller_unittest.cc
index 3aa9c5bb..080ae66 100644
--- a/chrome/browser/glic/browser_ui/glic_button_controller_unittest.cc
+++ b/chrome/browser/glic/browser_ui/glic_button_controller_unittest.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/global_features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/glic/browser_ui/glic_tab_indicator_helper_interactive_uitest.cc b/chrome/browser/glic/browser_ui/glic_tab_indicator_helper_interactive_uitest.cc
index 870e8cb..5149de8 100644
--- a/chrome/browser/glic/browser_ui/glic_tab_indicator_helper_interactive_uitest.cc
+++ b/chrome/browser/glic/browser_ui/glic_tab_indicator_helper_interactive_uitest.cc
@@ -8,7 +8,7 @@
 #include "chrome/browser/glic/test_support/interactive_glic_test.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
-#include "chrome/browser/ui/tabs/tab_enums.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/tab_close_button.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
@@ -28,7 +28,7 @@
 namespace {
 
 class TabAlertStateObserver
-    : public ui::test::PollingStateObserver<std::vector<TabAlertState>> {
+    : public ui::test::PollingStateObserver<std::vector<tabs::TabAlert>> {
  public:
   TabAlertStateObserver(Browser* browser, int tab_index)
       : PollingStateObserver([browser, tab_index]() {
@@ -39,7 +39,7 @@
             auto* const tab = tab_strip->tab_at(tab_index);
             return tab->data().alert_state;
           }
-          return std::vector<TabAlertState>();
+          return std::vector<tabs::TabAlert>();
         }) {}
   ~TabAlertStateObserver() override = default;
 };
@@ -60,12 +60,12 @@
   ~GlicTabIndicatorHelperUiTest() override = default;
 
   static auto IsAccessing() {
-    return testing::Matcher<std::vector<TabAlertState>>(
-        testing::Contains(TabAlertState::GLIC_ACCESSING));
+    return testing::Matcher<std::vector<tabs::TabAlert>>(
+        testing::Contains(tabs::TabAlert::GLIC_ACCESSING));
   }
   static auto IsNotAccessing() {
-    return testing::Matcher<std::vector<TabAlertState>>(
-        testing::Not(testing::Contains(TabAlertState::GLIC_ACCESSING)));
+    return testing::Matcher<std::vector<tabs::TabAlert>>(
+        testing::Not(testing::Contains(tabs::TabAlert::GLIC_ACCESSING)));
   }
 
   GURL GetTestUrl() const {
diff --git a/chrome/browser/glic/e2e_test/BUILD.gn b/chrome/browser/glic/e2e_test/BUILD.gn
index c3c4e951..c43630a 100644
--- a/chrome/browser/glic/e2e_test/BUILD.gn
+++ b/chrome/browser/glic/e2e_test/BUILD.gn
@@ -32,6 +32,7 @@
     "//chrome/browser/glic:impl",
     "//chrome/browser/glic:test_support",
     "//chrome/browser/signin/e2e_tests:test_support",
+    "//chrome/browser/ui:ui_features",
     "//chrome/common:constants",
     "//chrome/test:test_support",
     "//chrome/test:test_support_ui",
diff --git a/chrome/browser/glic/e2e_test/glic_e2e_test.cc b/chrome/browser/glic/e2e_test/glic_e2e_test.cc
index 0cc9838..ded413aa 100644
--- a/chrome/browser/glic/e2e_test/glic_e2e_test.cc
+++ b/chrome/browser/glic/e2e_test/glic_e2e_test.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/signin/e2e_tests/signin_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
diff --git a/chrome/browser/glic/fre/glic_fre.mojom b/chrome/browser/glic/fre/glic_fre.mojom
index 6556a27c..f69f3a6 100644
--- a/chrome/browser/glic/fre/glic_fre.mojom
+++ b/chrome/browser/glic/fre/glic_fre.mojom
@@ -34,6 +34,7 @@
   WebUiStateChanged(FreWebUiState new_state);
 };
 
+// LINT.IfChange(FreWebUiState)
 enum FreWebUiState {
   // Glic fre app controller not started.
   kUninitialized,
@@ -54,4 +55,5 @@
   kOffline,
   // Web view is displayed.
   kReady,
-};
\ No newline at end of file
+};
+// LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:FreWebUiState)
\ No newline at end of file
diff --git a/chrome/browser/glic/fre/glic_fre_controller.cc b/chrome/browser/glic/fre/glic_fre_controller.cc
index aa83a816e..646d00a 100644
--- a/chrome/browser/glic/fre/glic_fre_controller.cc
+++ b/chrome/browser/glic/fre/glic_fre_controller.cc
@@ -52,21 +52,23 @@
 GlicFreController::~GlicFreController() = default;
 
 void GlicFreController::WebUiStateChanged(mojom::FreWebUiState new_state) {
-  if (webui_state_ != new_state) {
-    // UI State has changed
-    webui_state_ = new_state;
-    webui_state_callback_list_.Notify(webui_state_);
-
-    // It is possible for the FRE to open directly in an error state. In this
-    // case, we should not record the FRE load time metric if the content is
-    // loaded at a later point.
-    if (new_state == mojom::FreWebUiState::kError ||
-        new_state == mojom::FreWebUiState::kOffline) {
-      show_start_time_ = base::TimeTicks();
-    }
-
-    RecordMetricsIfDialogIsShowingAndReady();
+  if (webui_state_ == new_state) {
+    return;
   }
+
+  // UI State has changed
+  webui_state_ = new_state;
+  webui_state_callback_list_.Notify(webui_state_);
+
+  // It is possible for the FRE to open directly in an error state. In this
+  // case, we should not record the FRE load time metric if the content is
+  // loaded at a later point.
+  if (new_state == mojom::FreWebUiState::kError ||
+      new_state == mojom::FreWebUiState::kOffline) {
+    show_start_time_ = base::TimeTicks();
+  }
+
+  RecordMetricsIfDialogIsShowingAndReady();
 }
 
 base::CallbackListSubscription GlicFreController::AddWebUiStateChangedCallback(
@@ -216,6 +218,8 @@
 }
 
 void GlicFreController::DismissFre() {
+  base::UmaHistogramEnumeration("Glic.FreModalWebUiState.FinishState",
+                                webui_state_);
   web_contents_ = nullptr;
   source_browser_ = nullptr;
   if (fre_view_ || fre_widget_) {
diff --git a/chrome/browser/glic/fre/glic_fre_controller_unittest.cc b/chrome/browser/glic/fre/glic_fre_controller_unittest.cc
index 950061e..061b97d 100644
--- a/chrome/browser/glic/fre/glic_fre_controller_unittest.cc
+++ b/chrome/browser/glic/fre/glic_fre_controller_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/glic/glic_pref_names.h"
 #include "chrome/browser/global_features.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/glic/glic_browsertest.cc b/chrome/browser/glic/glic_browsertest.cc
index dfa3025..ebf829e4 100644
--- a/chrome/browser/glic/glic_browsertest.cc
+++ b/chrome/browser/glic/glic_browsertest.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/glic/test_support/glic_test_util.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/webui_url_constants.h"
diff --git a/chrome/browser/glic/glic_enabling.cc b/chrome/browser/glic/glic_enabling.cc
index 287f682f..b2e14a0 100644
--- a/chrome/browser/glic/glic_enabling.cc
+++ b/chrome/browser/glic/glic_enabling.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/glic/glic_enabling_browsertest.cc b/chrome/browser/glic/glic_enabling_browsertest.cc
index fff1ede3..4c5c8c7f 100644
--- a/chrome/browser/glic/glic_enabling_browsertest.cc
+++ b/chrome/browser/glic/glic_enabling_browsertest.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_test_util.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/glic/glic_enabling_unittest.cc b/chrome/browser/glic/glic_enabling_unittest.cc
index 4e916c7..ea757510 100644
--- a/chrome/browser/glic/glic_enabling_unittest.cc
+++ b/chrome/browser/glic/glic_enabling_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/glic/test_support/glic_test_util.h"
 #include "chrome/browser/global_features.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/glic/glic_metrics_unittest.cc b/chrome/browser/glic/glic_metrics_unittest.cc
index f78b956..15b5b880 100644
--- a/chrome/browser/glic/glic_metrics_unittest.cc
+++ b/chrome/browser/glic/glic_metrics_unittest.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/status_icons/status_icon.h"
 #include "chrome/browser/status_icons/status_icon_menu_model.h"
 #include "chrome/browser/status_icons/status_tray.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
diff --git a/chrome/browser/glic/glic_profile_manager_browsertest.cc b/chrome/browser/glic/glic_profile_manager_browsertest.cc
index 38c670a..d6b6395 100644
--- a/chrome/browser/glic/glic_profile_manager_browsertest.cc
+++ b/chrome/browser/glic/glic_profile_manager_browsertest.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/test_browser_window.h"
diff --git a/chrome/browser/glic/glic_user_status_browsertest.cc b/chrome/browser/glic/glic_user_status_browsertest.cc
index 4f50aec7..b3c8607 100644
--- a/chrome/browser/glic/glic_user_status_browsertest.cc
+++ b/chrome/browser/glic/glic_user_status_browsertest.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/glic/host/context/glic_page_context_eligibility_observer_browsertest.cc b/chrome/browser/glic/host/context/glic_page_context_eligibility_observer_browsertest.cc
index b6a57ca..36f4d3eb 100644
--- a/chrome/browser/glic/host/context/glic_page_context_eligibility_observer_browsertest.cc
+++ b/chrome/browser/glic/host/context/glic_page_context_eligibility_observer_browsertest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/public/tab_features.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
diff --git a/chrome/browser/glic/host/guest_util_browsertest.cc b/chrome/browser/glic/host/guest_util_browsertest.cc
index 6fb8f33..07cba9c 100644
--- a/chrome/browser/glic/host/guest_util_browsertest.cc
+++ b/chrome/browser/glic/host/guest_util_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/webui_url_constants.h"
diff --git a/chrome/browser/glic/resources/internal b/chrome/browser/glic/resources/internal
index aeb59fb..3784a74 160000
--- a/chrome/browser/glic/resources/internal
+++ b/chrome/browser/glic/resources/internal
@@ -1 +1 @@
-Subproject commit aeb59fb12f8363ded7b2f1052956e538808c5daf
+Subproject commit 3784a743ccebd82808a50e14e99db28643e95bac
diff --git a/chrome/browser/glic/test_support/interactive_glic_test.h b/chrome/browser/glic/test_support/interactive_glic_test.h
index 6f5c84cd..eb3c688 100644
--- a/chrome/browser/glic/test_support/interactive_glic_test.h
+++ b/chrome/browser/glic/test_support/interactive_glic_test.h
@@ -30,6 +30,7 @@
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/glic/widget/glic_window_controller.h b/chrome/browser/glic/widget/glic_window_controller.h
index 01bc4d3..ae3d4dd 100644
--- a/chrome/browser/glic/widget/glic_window_controller.h
+++ b/chrome/browser/glic/widget/glic_window_controller.h
@@ -212,13 +212,11 @@
   //   * Waiting for glic to load (the open animation has finished, but the
   //     glic window contents is not yet ready)
   //   * Open (aka showing, visible)
-  //   * Detaching
   //   * ClosingToReopenDetached
   enum class State {
     kClosed,
     kWaitingForGlicToLoad,
     kOpen,
-    kDetaching,
     kClosingToReopenDetached,
   };
   virtual State state() const = 0;
diff --git a/chrome/browser/glic/widget/glic_window_controller_impl.cc b/chrome/browser/glic/widget/glic_window_controller_impl.cc
index c970f082..79fd550 100644
--- a/chrome/browser/glic/widget/glic_window_controller_impl.cc
+++ b/chrome/browser/glic/widget/glic_window_controller_impl.cc
@@ -73,7 +73,6 @@
 
 // Default value for adding a buffer to the attachment zone.
 constexpr static int kAttachmentBuffer = 20;
-constexpr static int kDetachYDistance = 36;
 constexpr static int kInitialPositionBuffer = 4;
 constexpr static int kMaxWidgetSize = 16'384;
 
@@ -882,19 +881,12 @@
   if (state_ != State::kOpen || !attached_browser_) {
     return;
   }
-  SetWindowState(State::kDetaching);
+
   if (!AlwaysDetached()) {
     // TODO(crbug.com/410629338): Reimplement attachment.
   }
 
-  // Move down a little bit when detaching.
-  gfx::Point new_position = glic_widget_->GetWindowBoundsInScreen().origin();
-  new_position.set_y(new_position.y() + kDetachYDistance);
-
-  glic_window_animator_->AnimatePosition(
-      new_position, kAnimationDuration,
-      base::BindOnce(&GlicWindowControllerImpl::DetachFinished,
-                     weak_ptr_factory_.GetWeakPtr()));
+  NOTIMPLEMENTED();
 }
 
 void GlicWindowControllerImpl::DetachFinished() {
@@ -935,9 +927,8 @@
   glic_size_ = size;
   glic_service_->metrics()->OnGlicWindowResize();
 
-  const bool in_resizable_state = state_ == State::kOpen ||
-                                  state_ == State::kWaitingForGlicToLoad ||
-                                  state_ == State::kDetaching;
+  const bool in_resizable_state =
+      state_ == State::kOpen || state_ == State::kWaitingForGlicToLoad;
 
   // TODO(https://crbug.com/379164689): Drive resize animations for error states
   // from the browser. For now, we allow animations during the waiting state.
@@ -1112,6 +1103,9 @@
   // lead to crashes.
   if (!in_move_loop_) {
     in_move_loop_ = true;
+#if BUILDFLAG(IS_MAC)
+    GetGlicWidget()->SetCapture(nullptr);
+#endif
     const views::Widget::MoveLoopSource move_loop_source =
         views::Widget::MoveLoopSource::kMouse;
     if (!AlwaysDetached()) {
@@ -1411,8 +1405,7 @@
 }
 
 void GlicWindowControllerImpl::MaybeAdjustSizeForDisplay(bool animate) {
-  if (state_ == State::kOpen || state_ == State::kWaitingForGlicToLoad ||
-      state_ == State::kDetaching) {
+  if (state_ == State::kOpen || state_ == State::kWaitingForGlicToLoad) {
     const auto target_size = GetLastRequestedSizeClamped();
     if (target_size != glic_window_animator_->GetCurrentTargetBounds().size()) {
       glic_window_animator_->AnimateSize(
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
index 1240a025..7f1c3a8 100644
--- a/chrome/browser/lifetime/browser_close_manager_browsertest.cc
+++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
@@ -43,6 +43,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/mac/auth_session_request.mm b/chrome/browser/mac/auth_session_request.mm
index 769d5099..7cb84e87 100644
--- a/chrome/browser/mac/auth_session_request.mm
+++ b/chrome/browser/mac/auth_session_request.mm
@@ -177,9 +177,7 @@
     std::string scheme) {
   url::RawCanonOutputT<char> canon_output;
   url::Component component;
-  bool result = url::CanonicalizeScheme(
-      scheme.data(), url::Component(0, static_cast<int>(scheme.size())),
-      &canon_output, &component);
+  bool result = url::CanonicalizeScheme(scheme, &canon_output, &component);
   if (!result)
     return std::nullopt;
 
diff --git a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
index 0a08f0f1..092801c 100644
--- a/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
+++ b/chrome/browser/media/cast_mirroring_service_host_browsertest.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/media/router/media_router_feature.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_enums.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
@@ -437,11 +437,11 @@
   // Run the browser until the indicator turns on.
   const base::TimeTicks start_time = base::TimeTicks::Now();
   while (!base::Contains(GetTabAlertStatesForContents(contents),
-                         TabAlertState::TAB_CAPTURING)) {
+                         tabs::TabAlert::TAB_CAPTURING)) {
     if (base::TimeTicks::Now() - start_time >
         TestTimeouts::action_max_timeout()) {
       EXPECT_THAT(GetTabAlertStatesForContents(contents),
-                  ::testing::Contains(TabAlertState::TAB_CAPTURING));
+                  ::testing::Contains(tabs::TabAlert::TAB_CAPTURING));
       return;
     }
     observer.WaitForTabChange();
diff --git a/chrome/browser/net/device_bound_sessions_browsertest.cc b/chrome/browser/net/device_bound_sessions_browsertest.cc
index fda677b9..3d07e49 100644
--- a/chrome/browser/net/device_bound_sessions_browsertest.cc
+++ b/chrome/browser/net/device_bound_sessions_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chrome/test/base/web_feature_histogram_tester.h"
+#include "components/metrics/content/subprocess_metrics_provider.h"
 #include "components/unexportable_keys/features.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/browser_test.h"
@@ -19,6 +20,7 @@
 #include "net/cookies/canonical_cookie_test_helpers.h"
 #include "net/device_bound_sessions/session_access.h"
 #include "net/device_bound_sessions/session_key.h"
+#include "net/device_bound_sessions/session_usage.h"
 #include "net/device_bound_sessions/test_support.h"
 #include "net/test/embedded_test_server/http_response.h"
 #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom.h"
@@ -280,4 +282,55 @@
             2);
 }
 
+IN_PROC_BROWSER_TEST_F(DeviceBoundSessionBrowserTest, NotDeferredLogs) {
+  base::HistogramTester histogram_tester;
+
+  base::test::TestFuture<SessionAccess> future;
+  DeviceBoundSessionAccessObserver observer(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      future.GetRepeatingCallback<const SessionAccess&>());
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL("/resource_triggered_dbsc_registration")));
+
+  ASSERT_TRUE(future.Wait());
+
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/ensure_authenticated")));
+
+  metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
+  histogram_tester.ExpectBucketCount(
+      "Net.DeviceBoundSessions.RequestDeferralDecision",
+      /*sample=*/net::device_bound_sessions::SessionUsage::kInScopeNotDeferred,
+      /*expected_count=*/1);
+}
+
+IN_PROC_BROWSER_TEST_F(DeviceBoundSessionBrowserTest, DeferredLogs) {
+  base::HistogramTester histogram_tester;
+
+  content::WebContents* web_contents =
+      chrome_test_utils::GetActiveWebContents(this);
+  {
+    base::test::TestFuture<SessionAccess> future;
+    DeviceBoundSessionAccessObserver observer(
+        web_contents, future.GetRepeatingCallback<const SessionAccess&>());
+    ASSERT_TRUE(ui_test_utils::NavigateToURL(
+        browser(), embedded_test_server()->GetURL(
+                       "/resource_triggered_dbsc_registration")));
+    ASSERT_TRUE(future.Wait());
+  }
+
+  // Force a refresh.
+  ASSERT_TRUE(
+      content::ExecJs(web_contents, "cookieStore.delete('auth_cookie')"));
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/ensure_authenticated")));
+
+  metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
+  histogram_tester.ExpectBucketCount(
+      "Net.DeviceBoundSessions.RequestDeferralDecision",
+      /*sample=*/net::device_bound_sessions::SessionUsage::kDeferred,
+      /*expected_count=*/1);
+}
+
 }  // namespace
diff --git a/chrome/browser/net/reporting_browsertest.cc b/chrome/browser/net/reporting_browsertest.cc
index 58b5b93..47f73960 100644
--- a/chrome/browser/net/reporting_browsertest.cc
+++ b/chrome/browser/net/reporting_browsertest.cc
@@ -737,7 +737,7 @@
   const std::string* url = report.FindString("url");
   const base::Value::Dict* body = report.FindDict("body");
   const std::string* reason = body->FindString("reason");
-  const std::string* is_top_level = body->FindString("is_top_level");
+  const std::optional<bool> is_top_level = body->FindBool("is_top_level");
   const std::string* visibility_state = body->FindString("visibility_state");
 
   EXPECT_EQ("crash", *type);
@@ -746,10 +746,10 @@
   // When the `kCrashReportingAPIMoreContextData` flag is enabled, expect the
   // extra CrashReportBody context bits to be present.
   if (GetParam()) {
-    EXPECT_EQ("true", *is_top_level);
+    EXPECT_TRUE(*is_top_level);
     EXPECT_EQ("visible", *visibility_state);
   } else {
-    EXPECT_EQ(nullptr, is_top_level);
+    EXPECT_EQ(std::nullopt, is_top_level);
     EXPECT_EQ(nullptr, visibility_state);
   }
 }
@@ -830,15 +830,15 @@
   const std::string* url = report.FindString("url");
   const base::Value::Dict* body = report.FindDict("body");
   const std::string* reason = body->FindString("reason");
-  const std::string* is_top_level = body->FindString("is_top_level");
+  const std::optional<bool> is_top_level = body->FindBool("is_top_level");
 
   EXPECT_EQ("crash", *type);
   EXPECT_EQ(*url, iframe_url);
   EXPECT_EQ("unresponsive", *reason);
   if (GetParam()) {
-    EXPECT_EQ("false", *is_top_level);
+    EXPECT_FALSE(*is_top_level);
   } else {
-    EXPECT_EQ(nullptr, is_top_level);
+    EXPECT_EQ(std::nullopt, is_top_level);
   }
 }
 
diff --git a/chrome/browser/performance_timeline_browsertest.cc b/chrome/browser/performance_timeline_browsertest.cc
index 81375e80..68d4af11 100644
--- a/chrome/browser/performance_timeline_browsertest.cc
+++ b/chrome/browser/performance_timeline_browsertest.cc
@@ -33,8 +33,7 @@
             });
           })();
         )",
-        extension->GetResourceURL(extension->url(), "content_script.js")
-            .spec());
+        extension->GetResourceURL("content_script.js").spec());
     EXPECT_EQ(content::EvalJs(web_contents(), script_code).error, "");
   }
 
diff --git a/chrome/browser/profiles/gaia_info_update_service_unittest.cc b/chrome/browser/profiles/gaia_info_update_service_unittest.cc
index d29a380..297cb69 100644
--- a/chrome/browser/profiles/gaia_info_update_service_unittest.cc
+++ b/chrome/browser/profiles/gaia_info_update_service_unittest.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/browser/signin/test_signin_client_builder.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/exceptions/ReadAloudUnsupportedException.java b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/exceptions/ReadAloudUnsupportedException.java
index c82d2bcb..0b2b62c 100644
--- a/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/exceptions/ReadAloudUnsupportedException.java
+++ b/chrome/browser/readaloud/android/java/src/org/chromium/chrome/browser/readaloud/exceptions/ReadAloudUnsupportedException.java
@@ -24,8 +24,6 @@
                 RejectionReason.CONTENT_TOO_LARGE, RejectionReason.INVALID_URL,
                 RejectionReason.DISALLOWED_FOR_READOUT, RejectionReason.BAD_REQUEST,
         RejectionReason.EXPIRED_CONTENT_VERSION, RejectionReason.UNSUPPORTED_EMAIL_FORMAT,
-                RejectionReason.UNSUPPORTED_TUPLE_DATA_EXTRACTION,
-                RejectionReason.UNSUPPORTED_LATTICE_REVIEW_DATA_EXTRACTION,
                 RejectionReason.DISALLOWED_FOR_TRANSLATION, RejectionReason.COUNT
     })
     // This must be kept in sync with readaloud/enums.xml values
@@ -68,10 +66,6 @@
         int EXPIRED_CONTENT_VERSION = 16;
         // We don't support this kind of email.
         int UNSUPPORTED_EMAIL_FORMAT = 17;
-        // There is no Tuple data available for this url.
-        int UNSUPPORTED_TUPLE_DATA_EXTRACTION = 18;
-        // There is no LatticeReview data available for this url.
-        int UNSUPPORTED_LATTICE_REVIEW_DATA_EXTRACTION = 19;
         // The content is not allowed to be translated.
         int DISALLOWED_FOR_TRANSLATION = 20;
         int COUNT = 21;
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/os_japanese_dictionary_entry_row.html b/chrome/browser/resources/ash/settings/os_languages_page/os_japanese_dictionary_entry_row.html
index 8e6994d..140e1a2 100644
--- a/chrome/browser/resources/ash/settings/os_languages_page/os_japanese_dictionary_entry_row.html
+++ b/chrome/browser/resources/ash/settings/os_languages_page/os_japanese_dictionary_entry_row.html
@@ -24,7 +24,8 @@
   }
 
   .delete-icon {
-    --cr-icon-button-size: 20px;
+    --cr-icon-button-size: 32px;
+    --cr-icon-button-icon-size: 20px;
     align-self: center;
   }
 </style>
diff --git a/chrome/browser/resources/connectors_internals/connectors_utils.ts b/chrome/browser/resources/connectors_internals/connectors_utils.ts
index 619da95..4d1693bd 100644
--- a/chrome/browser/resources/connectors_internals/connectors_utils.ts
+++ b/chrome/browser/resources/connectors_internals/connectors_utils.ts
@@ -9,6 +9,7 @@
   [KeyTrustLevel.UNSPECIFIED]: 'Unspecified',
   [KeyTrustLevel.HW]: 'HW',
   [KeyTrustLevel.OS]: 'OS',
+  [KeyTrustLevel.OS_SOFTWARE]: 'OS Storage',
 };
 
 const KeyTypeStringMap = {
diff --git a/chrome/browser/resources/connectors_internals/managed_client_certificate.ts b/chrome/browser/resources/connectors_internals/managed_client_certificate.ts
index 0851864..0d80a31 100644
--- a/chrome/browser/resources/connectors_internals/managed_client_certificate.ts
+++ b/chrome/browser/resources/connectors_internals/managed_client_certificate.ts
@@ -110,6 +110,10 @@
           key: 'Public Key Hash',
           value: managedIdentity.loadedKeyInfo.encodedSpkiHash,
         },
+        {
+          key: 'Has SSL Key',
+          value: managedIdentity.loadedKeyInfo.hasSslKey.toString(),
+        },
       ]);
 
       if (managedIdentity.loadedKeyInfo.keyUploadStatus) {
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts
index 73eba14..832c0aa 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -22,7 +22,6 @@
 import {minOverflowLengthToScroll} from './common.js';
 import type {LanguageToastElement} from './language_toast.js';
 import {NodeStore} from './node_store.js';
-import {ReadAloudHighlighter} from './read_aloud/highlighter.js';
 import {SpeechController} from './read_aloud/speech_controller.js';
 import type {SpeechListener} from './read_aloud/speech_controller.js';
 import {VoicePackController} from './read_aloud/voice_pack_controller.js';
@@ -124,8 +123,6 @@
   private notificationManager_ = VoiceNotificationManager.getInstance();
   private logger_: ReadAnythingLogger = ReadAnythingLogger.getInstance();
   private styleUpdater_: AppStyleUpdater;
-  private highlighter_: ReadAloudHighlighter =
-      ReadAloudHighlighter.getInstance();
   private nodeStore_: NodeStore = NodeStore.getInstance();
   private voicePackController_: VoicePackController =
       VoicePackController.getInstance();
@@ -214,7 +211,11 @@
       }
 
       const {anchorNodeId, anchorOffset, focusNodeId, focusOffset} =
-          this.getSelectedIds();
+          this.isReadAloudEnabled_ ?
+          this.speechController_.getSelectionAdjustedForHighlights(
+              selection.anchorNode, selection.anchorOffset, selection.focusNode,
+              selection.focusOffset) :
+          this.getSelection();
       if (!anchorNodeId || !focusNodeId) {
         return;
       }
@@ -233,12 +234,8 @@
             anchorNodeId, anchorOffset, focusNodeId, focusOffset);
       }
 
-      // If there's been a selection, clear the current Read Aloud highlight.
-      if (anchorNodeId && focusNodeId) {
-        // If speech is resumed, this won't be restored.
-        // TODO: crbug.com/40927698 - Restore the previous highlight after
-        // speech is resumed after a selection.
-        this.highlighter_.clearHighlightFormatting();
+      if (this.isReadAloudEnabled_) {
+        this.speechController_.onSelectionChange();
       }
     };
 
@@ -826,34 +823,6 @@
     this.speechController_.onPreviousGranularityClick();
   }
 
-  private getSelectedIds(): {
-    anchorNodeId: number|undefined,
-    anchorOffset: number,
-    focusNodeId: number|undefined,
-    focusOffset: number,
-  } {
-    const {anchorNode, anchorOffset, focusNode, focusOffset} =
-        this.getSelection();
-    let anchorNodeId = this.nodeStore_.getAxId(anchorNode);
-    let focusNodeId = this.nodeStore_.getAxId(focusNode);
-    let adjustedAnchorOffset = anchorOffset;
-    let adjustedFocusOffset = focusOffset;
-    if (!anchorNodeId) {
-      anchorNodeId = this.highlighter_.getAncestorId(anchorNode);
-      adjustedAnchorOffset += this.highlighter_.getOffsetInAncestor(anchorNode);
-    }
-    if (!focusNodeId) {
-      focusNodeId = this.highlighter_.getAncestorId(focusNode);
-      adjustedFocusOffset += this.highlighter_.getOffsetInAncestor(focusNode);
-    }
-    return {
-      anchorNodeId: anchorNodeId,
-      anchorOffset: adjustedAnchorOffset,
-      focusNodeId: focusNodeId,
-      focusOffset: adjustedFocusOffset,
-    };
-  }
-
   protected onSelectVoice_(
       event: CustomEvent<{selectedVoice: SpeechSynthesisVoice}>) {
     event.preventDefault();
diff --git a/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts b/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts
index abce0b51..f334db9 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_aloud/speech_controller.ts
@@ -130,6 +130,34 @@
         (source === PauseActionSource.VOICE_SETTINGS_CHANGE);
   }
 
+  getSelectionAdjustedForHighlights(
+      anchorNode: Node, anchorOffset: number, focusNode: Node,
+      focusOffset: number): {
+    anchorNodeId: number|undefined,
+    anchorOffset: number,
+    focusNodeId: number|undefined,
+    focusOffset: number,
+  } {
+    let anchorNodeId = this.nodeStore_.getAxId(anchorNode);
+    let focusNodeId = this.nodeStore_.getAxId(focusNode);
+    let adjustedAnchorOffset = anchorOffset;
+    let adjustedFocusOffset = focusOffset;
+    if (!anchorNodeId) {
+      anchorNodeId = this.highlighter_.getAncestorId(anchorNode);
+      adjustedAnchorOffset += this.highlighter_.getOffsetInAncestor(anchorNode);
+    }
+    if (!focusNodeId) {
+      focusNodeId = this.highlighter_.getAncestorId(focusNode);
+      adjustedFocusOffset += this.highlighter_.getOffsetInAncestor(focusNode);
+    }
+    return {
+      anchorNodeId: anchorNodeId,
+      anchorOffset: adjustedAnchorOffset,
+      focusNodeId: focusNodeId,
+      focusOffset: adjustedFocusOffset,
+    };
+  }
+
   initializeSpeechTree(startingNodeId?: number) {
     if (startingNodeId && !this.model_.getFirstTextNode()) {
       this.model_.setFirstTextNode(startingNodeId);
@@ -147,6 +175,13 @@
     chrome.readingMode.preprocessTextForSpeech();
   }
 
+  onSelectionChange() {
+    // If speech is resumed, this won't be restored.
+    // TODO: crbug.com/40927698 - Restore the previous highlight after
+    // speech is resumed after a selection.
+    this.highlighter_.clearHighlightFormatting();
+  }
+
   // If the screen is locked during speech, we should stop speaking.
   onLockScreen() {
     if (this.isSpeechActive()) {
diff --git a/chrome/browser/safety_hub/android/unused_site_permissions_bridge.cc b/chrome/browser/safety_hub/android/unused_site_permissions_bridge.cc
index f8d35523..a39be235 100644
--- a/chrome/browser/safety_hub/android/unused_site_permissions_bridge.cc
+++ b/chrome/browser/safety_hub/android/unused_site_permissions_bridge.cc
@@ -118,10 +118,7 @@
   RevokedPermissionsService* service =
       RevokedPermissionsServiceFactory::GetForProfile(profile);
   CHECK(service);
-
-  for (const auto& permissions_data : permissions_data_list) {
-    service->StorePermissionInRevokedPermissionSetting(permissions_data);
-  }
+  service->RestoreDeletedRevokedPermissionsList(permissions_data_list);
 }
 
 std::vector<std::u16string> ContentSettingsTypeToString(
diff --git a/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc b/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc
index 6a355952..588dffd 100644
--- a/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_preferences_sync_test.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/sync/test/integration/sync_service_impl_harness.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 2149941..460c80d 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -5834,7 +5834,9 @@
   public_deps = [
     "//base",
     "//build:branding_buildflags",
+    "//chrome/browser:browser_process",
     "//chrome/common:buildflags",
+    "//components/variations/service:service",
     "//extensions/buildflags",
   ]
   deps = [
diff --git a/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderCoordinator.java b/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderCoordinator.java
index 24a92d2e..d0b1c99d 100644
--- a/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderCoordinator.java
+++ b/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderCoordinator.java
@@ -204,7 +204,7 @@
     private void onInsetsRectsUpdated(Rect widestUnoccludedRect) {
         // mActivity is only set to null in destroy().
         boolean isOnExternalDisplay =
-                DisplayUtil.isContextInDefaultDisplay(assumeNonNull(mActivity));
+                !DisplayUtil.isContextInDefaultDisplay(assumeNonNull(mActivity));
         mHeuristicResult =
                 checkIsInDesktopWindow(
                         mCaptionBarRectProvider, mHeuristicResult, isOnExternalDisplay);
diff --git a/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderCoordinatorUnitTest.java b/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderCoordinatorUnitTest.java
index 9387ba84..c67173f 100644
--- a/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderCoordinatorUnitTest.java
+++ b/chrome/browser/ui/android/desktop_windowing/java/src/org/chromium/chrome/browser/ui/desktop_windowing/AppHeaderCoordinatorUnitTest.java
@@ -73,15 +73,15 @@
 public class AppHeaderCoordinatorUnitTest {
     @Implements(DisplayUtil.class)
     static class ShadowDisplayUtil {
-        private static boolean sIsOnExternalDisplay;
+        private static boolean sIsOnDefaultDisplay;
 
-        private static void setOnExternalDisplay(boolean isOnExternalDisplay) {
-            sIsOnExternalDisplay = isOnExternalDisplay;
+        private static void setOnDefaultDisplay(boolean isOnDefaultDisplay) {
+            sIsOnDefaultDisplay = isOnDefaultDisplay;
         }
 
         @Implementation
         public static boolean isContextInDefaultDisplay(Context context) {
-            return sIsOnExternalDisplay;
+            return sIsOnDefaultDisplay;
         }
     }
 
@@ -120,7 +120,7 @@
 
     @Before
     public void setup() {
-        ShadowDisplayUtil.setOnExternalDisplay(false);
+        ShadowDisplayUtil.setOnDefaultDisplay(true);
         mActivityScenarioRule.getScenario().onActivity(activity -> mSpyActivity = spy(activity));
         mEdgeToEdgeStateProvider = new EdgeToEdgeStateProvider(mSpyActivity.getWindow());
         mSpyRootView = spy(mSpyActivity.getWindow().getDecorView());
@@ -203,7 +203,7 @@
                 HistogramWatcher.newSingleRecordWatcher(
                         "Android.DesktopWindowHeuristicResult3",
                         DesktopWindowHeuristicResult.DISALLOWED_ON_EXTERNAL_DISPLAY);
-        ShadowDisplayUtil.setOnExternalDisplay(true);
+        ShadowDisplayUtil.setOnDefaultDisplay(false);
         updateFeatureParams(/* enableOnExternalDisplay= */ false);
         setupWithLeftAndRightBoundingRect();
         notifyInsetsRectObserver();
@@ -216,7 +216,7 @@
 
     @Test
     public void enabledOnExternalDisplayWhenAllowed() {
-        ShadowDisplayUtil.setOnExternalDisplay(true);
+        ShadowDisplayUtil.setOnDefaultDisplay(false);
         updateFeatureParams(/* enableOnExternalDisplay= */ true);
         setupWithLeftAndRightBoundingRect();
         notifyInsetsRectObserver();
diff --git a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
index 3d99b7f..0f3d070 100644
--- a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
+++ b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
@@ -1312,12 +1312,6 @@
     std::move(on_search_url_fetched_callback_).Run(final_url);
   }
 
-  // No other actions to take if we are not using the Lens Web API for Copy
-  // Text.
-  if (!ash::features::IsSunfishLensWebCopyTextEnabled()) {
-    return;
-  }
-
   // Get the vsr ID from the redirect URL so it can be used again in the
   // /qfmetadata request.
   std::string vsr_id;
diff --git a/chrome/browser/ui/ash/capture_mode/sunfish_browsertest.cc b/chrome/browser/ui/ash/capture_mode/sunfish_browsertest.cc
index 6dbfd601..dd00075 100644
--- a/chrome/browser/ui/ash/capture_mode/sunfish_browsertest.cc
+++ b/chrome/browser/ui/ash/capture_mode/sunfish_browsertest.cc
@@ -98,7 +98,7 @@
   VerifyActiveBehavior(BehaviorType::kSunfish);
 
   // Simulate showing the panel while the session is active.
-  controller->ShowSearchResultsPanel(gfx::ImageSkia());
+  controller->ShowSearchResultsPanel();
   controller->NavigateSearchResultsPanel(GURL("kTestUrl1"));
   ASSERT_TRUE(controller->IsActive());
   auto* search_results_view =
@@ -158,7 +158,7 @@
   VerifyActiveBehavior(BehaviorType::kSunfish);
 
   // Simulate showing the panel while the session is active.
-  controller->ShowSearchResultsPanel(gfx::ImageSkia());
+  controller->ShowSearchResultsPanel();
   controller->NavigateSearchResultsPanel(GURL("kTestUrl1"));
   ASSERT_TRUE(controller->IsActive());
   auto* search_results_view =
diff --git a/chrome/browser/ui/autofill/BUILD.gn b/chrome/browser/ui/autofill/BUILD.gn
index 41d56125..0863d727 100644
--- a/chrome/browser/ui/autofill/BUILD.gn
+++ b/chrome/browser/ui/autofill/BUILD.gn
@@ -152,10 +152,6 @@
     "//components/password_manager/core/browser:metrics_util",
     "//components/password_manager/core/browser:password_form",
     "//components/password_manager/core/browser/form_parsing",
-    "//components/plus_addresses:features",
-    "//components/plus_addresses:hats_utils",
-    "//components/plus_addresses:types",
-    "//components/plus_addresses/resources/strings",
     "//components/profile_metrics",
     "//components/security_state/content",
     "//components/strings:components_strings_grit",
@@ -207,7 +203,7 @@
       "//chrome/browser/ui/webui/signin:login",
       "//components/autofill_ai/core/browser",
       "//components/password_manager/core/browser/features:password_features",
-      "//components/plus_addresses",
+      "//components/plus_addresses/resources/strings",
       "//extensions/browser",
     ]
 
@@ -471,7 +467,6 @@
       "//components/password_manager/core/browser/password_store:test_support",
       "//components/password_manager/core/common",
       "//components/plus_addresses:blocklist_data",
-      "//components/plus_addresses:plus_address_blocklist_proto",
       "//components/plus_addresses:test_support",
       "//components/plus_addresses/resources/strings",
       "//components/signin/public/base",
diff --git a/chrome/browser/ui/browser_command_controller_browsertest.cc b/chrome/browser/ui/browser_command_controller_browsertest.cc
index 9a64d235..3058a75 100644
--- a/chrome/browser/ui/browser_command_controller_browsertest.cc
+++ b/chrome/browser/ui/browser_command_controller_browsertest.cc
@@ -32,6 +32,7 @@
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog_browsertest.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_ui.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/test_browser_window.h"
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 488381a2..6e5347d 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -455,6 +455,8 @@
         browser->tab_strip_model()->GetWebContentsAt(selected_index));
   }
 
+  base::UmaHistogramCounts100("TabStrip.Tab.ReloadCount", selected_tabs.size());
+
   for (WebContents* const selected_tab : selected_tabs) {
     // Skip this tab if it is no longer part of this tabstrip. N.B. we do this
     // instead of using WeakPtr<WebContents> because we do not want to reload
@@ -1133,7 +1135,7 @@
         Browser::Create(Browser::CreateParams(browser->profile(), true));
   }
 
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       browser->tab_strip_model()->DetachTabGroupForInsertion(group);
   new_browser->tab_strip_model()->InsertDetachedTabGroupAt(
       std::move(detached_group), 0);
@@ -1258,7 +1260,7 @@
                                Browser* target,
                                tab_groups::TabGroupId group) {
   CHECK(source->tab_strip_model()->group_model()->ContainsTabGroup(group));
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       source->tab_strip_model()->DetachTabGroupForInsertion(group);
   target->tab_strip_model()->InsertDetachedTabGroupAt(std::move(detached_group),
                                                       0);
diff --git a/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager.cc b/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager.cc
index 9ef2c046..55753fd 100644
--- a/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager.cc
+++ b/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager.cc
@@ -134,6 +134,14 @@
       ContentSettingsType::REVOKED_ABUSIVE_NOTIFICATION_PERMISSIONS, {});
 }
 
+void AbusiveNotificationPermissionsManager::RestoreDeletedRevokedPermission(
+    const ContentSettingsPattern& primary_pattern,
+    content_settings::ContentSettingConstraints constraints) {
+  safety_hub_util::SetRevokedAbusiveNotificationPermission(
+      hcsm_.get(), primary_pattern.ToRepresentativeUrl(), /*is_ignored=*/false,
+      constraints);
+}
+
 const base::Clock* AbusiveNotificationPermissionsManager::GetClock() {
   if (clock_for_testing_) {
     return clock_for_testing_;
diff --git a/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager.h b/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager.h
index ac8a6caa..c34fd8b 100644
--- a/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager.h
+++ b/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager.h
@@ -71,6 +71,13 @@
       const ContentSettingsPattern& primary_pattern,
       const ContentSettingsPattern& secondary_pattern);
 
+  // Restores REVOKED_ABUSIVE_NOTIFICATION_PERMISSIONS entry for the
+  // primary_pattern after it was deleted after user
+  // has accepted the revocation (via `ClearRevokedPermissionsList()`).
+  void RestoreDeletedRevokedPermission(
+      const ContentSettingsPattern& primary_pattern,
+      content_settings::ContentSettingConstraints constraints);
+
   // If there's a clock for testing, return that. Otherwise, return an instance
   // of a default clock.
   const base::Clock* GetClock();
diff --git a/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager_unittest.cc b/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager_unittest.cc
index fc67ace..bfc603d 100644
--- a/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager_unittest.cc
+++ b/chrome/browser/ui/safety_hub/abusive_notification_permissions_manager_unittest.cc
@@ -372,6 +372,27 @@
 }
 
 TEST_F(AbusiveNotificationPermissionsManagerTest,
+       RestoreDeletedRevokedPermissionsList) {
+  auto manager =
+      AbusiveNotificationPermissionsManager(mock_database_manager(), hcsm());
+  RunUntilSafeBrowsingChecksComplete(&manager);
+
+  content_settings::ContentSettingConstraints constraints;
+  manager.RestoreDeletedRevokedPermission(
+      ContentSettingsPattern::FromURLNoWildcard(GURL(url1)),
+      constraints.Clone());
+  manager.RestoreDeletedRevokedPermission(
+      ContentSettingsPattern::FromURLNoWildcard(GURL(url2)),
+      constraints.Clone());
+
+  ContentSettingsForOneType content_settings =
+      safety_hub_util::GetRevokedAbusiveNotificationPermissions(hcsm());
+  EXPECT_EQ(content_settings.size(), 2u);
+  EXPECT_TRUE(IsUrlInContentSettings(content_settings, url1));
+  EXPECT_TRUE(IsUrlInContentSettings(content_settings, url2));
+}
+
+TEST_F(AbusiveNotificationPermissionsManagerTest,
        SetRevokedAbusiveNotificationPermission) {
   AddAbusiveNotification(url1, ContentSetting::CONTENT_SETTING_ALLOW);
   AddAbusiveNotification(url2, ContentSetting::CONTENT_SETTING_ALLOW);
diff --git a/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.cc b/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.cc
index 6f529af..8b89def0d 100644
--- a/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.cc
+++ b/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.cc
@@ -483,6 +483,30 @@
       ContentSettingsType::REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS, {});
 }
 
+void DisruptiveNotificationPermissionsManager::RestoreDeletedRevokedPermission(
+    const ContentSettingsPattern& primary_pattern,
+    content_settings::ContentSettingConstraints constraints) {
+  GURL url = primary_pattern.ToRepresentativeUrl();
+  base::Value engagement_as_value = hcsm_->GetWebsiteSetting(
+      url, GURL(), ContentSettingsType::NOTIFICATION_INTERACTIONS);
+  if (engagement_as_value.is_none() || !engagement_as_value.is_dict()) {
+    return;
+  }
+
+  ContentSettingHelper(*hcsm_).PersistRevocationEntry(
+      url,
+      RevocationEntry{
+          .revocation_state = RevocationState::kRevoked,
+          .site_engagement = site_engagement_service_->GetScore(url),
+          .daily_notification_count = permissions::
+              NotificationsEngagementService::GetDailyAverageNotificationCount(
+                  engagement_as_value.GetDict()),
+          .timestamp = clock_->Now(),
+          .created_at = constraints.expiration() - constraints.lifetime(),
+          .lifetime = constraints.lifetime(),
+      });
+}
+
 bool DisruptiveNotificationPermissionsManager::IsNotificationDisruptive(
     const GURL& url,
     int daily_notification_count) {
diff --git a/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.h b/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.h
index a10b03e..7b902ab6 100644
--- a/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.h
+++ b/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager.h
@@ -146,6 +146,14 @@
       const ContentSettingsPattern& primary_pattern,
       const ContentSettingsPattern& secondary_pattern);
 
+  // Restores REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS entry for the
+  // primary_pattern after it was deleted after user has accepted the revocation
+  // (via `ClearRevokedPermissionsList()`). Only restores the value if there is
+  // a matching notification engagement entry.
+  void RestoreDeletedRevokedPermission(
+      const ContentSettingsPattern& primary_pattern,
+      content_settings::ContentSettingConstraints constraints);
+
   // If the URL is in the revoke or proposed revoke list, report a false
   // positive and record metrics.
   static void MaybeReportFalsePositive(Profile* profile,
diff --git a/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager_unittest.cc b/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager_unittest.cc
index 7968804..8c3d3a55b 100644
--- a/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager_unittest.cc
+++ b/chrome/browser/ui/safety_hub/disruptive_notification_permissions_manager_unittest.cc
@@ -810,6 +810,28 @@
 }
 
 TEST_F(DisruptiveNotificationPermissionsManagerRevocationTest,
+       RestoreDeletedRevokedPermission) {
+  GURL url("https://www.example1.com");
+
+  SetDailyAverageNotificationCount(url, 3);
+  site_engagement_service()->ResetBaseScoreForURL(url, 1.0);
+
+  content_settings::ContentSettingConstraints constraints;
+  manager()->RestoreDeletedRevokedPermission(
+      ContentSettingsPattern::FromURLNoWildcard(url), constraints.Clone());
+
+  std::optional<RevocationEntry> revocation_entry =
+      ContentSettingHelper(*hcsm()).GetRevocationEntry(url);
+
+  EXPECT_THAT(revocation_entry,
+              Optional(Field(&RevocationEntry::has_reported_proposal, false)));
+  EXPECT_THAT(revocation_entry,
+              Optional(Field(&RevocationEntry::site_engagement, 1.0)));
+  EXPECT_THAT(revocation_entry,
+              Optional(Field(&RevocationEntry::daily_notification_count, 3)));
+}
+
+TEST_F(DisruptiveNotificationPermissionsManagerRevocationTest,
        UpdateNotificationContentSettingsChanged) {
   GURL url("https://chrome.test/");
   ContentSettingHelper(*hcsm()).PersistRevocationEntry(
diff --git a/chrome/browser/ui/safety_hub/revoked_permissions_service.cc b/chrome/browser/ui/safety_hub/revoked_permissions_service.cc
index d44c0761..de674475 100644
--- a/chrome/browser/ui/safety_hub/revoked_permissions_service.cc
+++ b/chrome/browser/ui/safety_hub/revoked_permissions_service.cc
@@ -168,6 +168,30 @@
   return constraint;
 }
 
+bool IsUnusedPermissionRevocation(PermissionsRevocationType revocation_type) {
+  return revocation_type == PermissionsRevocationType::kUnusedPermissions ||
+         revocation_type == PermissionsRevocationType::
+                                kUnusedPermissionsAndAbusiveNotifications ||
+         revocation_type == PermissionsRevocationType::
+                                kUnusedPermissionsAndDisruptiveNotifications;
+}
+
+bool IsAbusiveNotificationPermissionRevocation(
+    PermissionsRevocationType revocation_type) {
+  return revocation_type ==
+             PermissionsRevocationType::kAbusiveNotificationPermissions ||
+         revocation_type == PermissionsRevocationType::
+                                kUnusedPermissionsAndAbusiveNotifications;
+}
+
+bool IsDisruptiveNotificationPermissionRevocation(
+    PermissionsRevocationType revocation_type) {
+  return revocation_type ==
+             PermissionsRevocationType::kDisruptiveNotificationPermissions ||
+         revocation_type == PermissionsRevocationType::
+                                kUnusedPermissionsAndDisruptiveNotifications;
+}
+
 }  // namespace
 
 // static
@@ -667,7 +691,7 @@
   // revoked settings if necessary.
   is_unused_site_revocation_running = false;
 
-  StorePermissionInRevokedPermissionSetting(
+  StorePermissionInUnusedSitePermissionSetting(
       unused_site_permission_types, permissions_data.chooser_permissions_data,
       permissions_data.constraints.Clone(), permissions_data.primary_pattern,
       ContentSettingsPattern::Wildcard());
@@ -1045,7 +1069,7 @@
 
     // Store revoked permissions on HCSM.
     if (!revoked_permissions.empty()) {
-      StorePermissionInRevokedPermissionSetting(
+      StorePermissionInUnusedSitePermissionSetting(
           revoked_permissions, chooser_permissions_data, std::nullopt,
           primary_pattern, secondary_pattern);
     }
@@ -1071,18 +1095,36 @@
   is_unused_site_revocation_running = false;
 }
 
-void RevokedPermissionsService::StorePermissionInRevokedPermissionSetting(
-    const PermissionsData& permissions_data) {
-  // The |secondary_pattern| for
-  // |ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS| is always wildcard.
-  StorePermissionInRevokedPermissionSetting(
-      permissions_data.permission_types,
-      permissions_data.chooser_permissions_data,
-      permissions_data.constraints.Clone(), permissions_data.primary_pattern,
-      ContentSettingsPattern::Wildcard());
+void RevokedPermissionsService::RestoreDeletedRevokedPermissionsList(
+    const std::vector<PermissionsData>& permissions_data_list) {
+  for (const auto& permissions_data : permissions_data_list) {
+    if (IsUnusedPermissionRevocation(permissions_data.revocation_type)) {
+      StorePermissionInUnusedSitePermissionSetting(
+          permissions_data.permission_types,
+          permissions_data.chooser_permissions_data,
+          permissions_data.constraints.Clone(),
+          permissions_data.primary_pattern, ContentSettingsPattern::Wildcard());
+    }
+
+    if (IsAbusiveNotificationAutoRevocationEnabled() &&
+        IsAbusiveNotificationPermissionRevocation(
+            permissions_data.revocation_type)) {
+      abusive_notification_manager_->RestoreDeletedRevokedPermission(
+          permissions_data.primary_pattern,
+          permissions_data.constraints.Clone());
+    }
+
+    if (disruptive_notification_manager_ &&
+        IsDisruptiveNotificationPermissionRevocation(
+            permissions_data.revocation_type)) {
+      disruptive_notification_manager_->RestoreDeletedRevokedPermission(
+          permissions_data.primary_pattern,
+          permissions_data.constraints.Clone());
+    }
+  }
 }
 
-void RevokedPermissionsService::StorePermissionInRevokedPermissionSetting(
+void RevokedPermissionsService::StorePermissionInUnusedSitePermissionSetting(
     const std::set<ContentSettingsType>& permissions,
     const base::Value::Dict& chooser_permissions_data,
     const std::optional<content_settings::ContentSettingConstraints> constraint,
diff --git a/chrome/browser/ui/safety_hub/revoked_permissions_service.h b/chrome/browser/ui/safety_hub/revoked_permissions_service.h
index f919b88..c46ef08 100644
--- a/chrome/browser/ui/safety_hub/revoked_permissions_service.h
+++ b/chrome/browser/ui/safety_hub/revoked_permissions_service.h
@@ -199,9 +199,10 @@
   // the user. Does not change permissions themselves.
   void ClearRevokedPermissionsList();
 
-  // Stores revoked permissions data on HCSM.
-  void StorePermissionInRevokedPermissionSetting(
-      const PermissionsData& permission_data);
+  // Restores the list of revoked permissions after it was deleted after user
+  // has accepted the revocation (via `ClearRevokedPermissionsList()`).
+  void RestoreDeletedRevokedPermissionsList(
+      const std::vector<PermissionsData>& permissions_data_list);
 
   // Returns the list of all permissions that have been revoked.
   std::unique_ptr<RevokedPermissionsResult> GetRevokedPermissions();
@@ -272,7 +273,7 @@
   void RevokeUnusedPermissions();
 
   // Stores revoked permissions data on HCSM.
-  void StorePermissionInRevokedPermissionSetting(
+  void StorePermissionInUnusedSitePermissionSetting(
       const std::set<ContentSettingsType>& permissions,
       const base::Value::Dict& chooser_permissions_data,
       const std::optional<content_settings::ContentSettingConstraints>
diff --git a/chrome/browser/ui/safety_hub/revoked_permissions_service_unittest.cc b/chrome/browser/ui/safety_hub/revoked_permissions_service_unittest.cc
index d244503..db0143e 100644
--- a/chrome/browser/ui/safety_hub/revoked_permissions_service_unittest.cc
+++ b/chrome/browser/ui/safety_hub/revoked_permissions_service_unittest.cc
@@ -23,6 +23,7 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/permissions/notifications_engagement_service_factory.h"
 #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
 #include "chrome/browser/ui/safety_hub/abusive_notification_permissions_manager.h"
 #include "chrome/browser/ui/safety_hub/mock_safe_browsing_database_manager.h"
@@ -1280,6 +1281,58 @@
   ExpectRevokedDisruptiveNotificationPermissionSize(0U);
 }
 
+TEST_P(RevokedPermissionsServiceTest, RestoreClearedRevokedPermissionsList) {
+  if (ShouldSetupAbusiveNotificationSites()) {
+    SetupAbusiveNotificationSite(url2, ContentSetting::CONTENT_SETTING_ASK);
+    SetupAbusiveNotificationSite(url3, ContentSetting::CONTENT_SETTING_ASK);
+    SetupRevokedAbusiveNotificationSite(url2);
+    SetupRevokedAbusiveNotificationSite(url3);
+    ExpectRevokedAbusiveNotificationPermissionSize(2U);
+  }
+  if (ShouldSetupUnusedSites()) {
+    SetupRevokedUnusedPermissionSite(url1);
+    SetupRevokedUnusedPermissionSite(url2);
+    EXPECT_EQ(2U, GetRevokedUnusedPermissions(hcsm()).size());
+  }
+  if (ShouldSetupDisruptiveSites()) {
+    auto* notifications_engagement_service =
+        NotificationsEngagementServiceFactory::GetForProfile(profile());
+    notifications_engagement_service->RecordNotificationDisplayed(GURL(url4),
+                                                                  21);
+    SetupRevokedDisruptiveNotificationSite(url4);
+  }
+
+  auto new_service = std::make_unique<RevokedPermissionsService>(
+      profile(), profile()->GetPrefs());
+  auto opt_result = new_service->GetCachedResult();
+  EXPECT_TRUE(opt_result.has_value());
+  auto* result =
+      static_cast<RevokedPermissionsService::RevokedPermissionsResult*>(
+          opt_result.value().get());
+  auto revoked_permissions_list = result->GetRevokedPermissions();
+  std::vector<PermissionsData> revoked_permissions_vector{
+      std::begin(revoked_permissions_list), std::end(revoked_permissions_list)};
+
+  // Revoked permissions list should be empty after clearing the revoked
+  // permissions list.
+  service()->ClearRevokedPermissionsList();
+  EXPECT_EQ(0U, GetRevokedUnusedPermissions(hcsm()).size());
+  ExpectRevokedAbusiveNotificationPermissionSize(0U);
+  ExpectRevokedDisruptiveNotificationPermissionSize(0U);
+
+  service()->RestoreDeletedRevokedPermissionsList(revoked_permissions_vector);
+
+  if (ShouldSetupUnusedSites()) {
+    EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 2u);
+  }
+  if (ShouldSetupAbusiveNotificationSites()) {
+    ExpectRevokedAbusiveNotificationPermissionSize(2U);
+  }
+  if (ShouldSetupDisruptiveSites()) {
+    ExpectRevokedDisruptiveNotificationPermissionSize(1U);
+  }
+}
+
 TEST_P(RevokedPermissionsServiceTest, RecordRegrantMetricForAllowAgain) {
   SetupRevokedUnusedPermissionSite(url1);
   SetupRevokedUnusedPermissionSite(url2);
diff --git a/chrome/browser/ui/tabs/BUILD.gn b/chrome/browser/ui/tabs/BUILD.gn
index 5a6c098..27e2b31 100644
--- a/chrome/browser/ui/tabs/BUILD.gn
+++ b/chrome/browser/ui/tabs/BUILD.gn
@@ -280,6 +280,7 @@
       "//chrome/browser/ui:browser_list",
       "//chrome/browser/ui/color:color_headers",
       "//chrome/browser/ui/startup:startup_tab",
+      "//chrome/browser/ui/tabs/alert:tab_alert",
       "//components/collaboration/public:public",
       "//components/keyed_service/core",
       "//components/tabs:public",
diff --git a/chrome/browser/ui/tabs/alert/BUILD.gn b/chrome/browser/ui/tabs/alert/BUILD.gn
new file mode 100644
index 0000000..47ae9fc
--- /dev/null
+++ b/chrome/browser/ui/tabs/alert/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2021 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_win || is_mac || is_linux || is_chromeos || is_android)
+
+import("//chrome/common/features.gni")
+
+source_set("tab_alert") {
+  public = [ "tab_alert.h" ]
+}
diff --git a/chrome/browser/ui/tabs/alert/tab_alert.h b/chrome/browser/ui/tabs/alert/tab_alert.h
new file mode 100644
index 0000000..0ba9dc9
--- /dev/null
+++ b/chrome/browser/ui/tabs/alert/tab_alert.h
@@ -0,0 +1,29 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_TABS_ALERT_TAB_ALERT_H_
+#define CHROME_BROWSER_UI_TABS_ALERT_TAB_ALERT_H_
+
+namespace tabs {
+// Alert states for a tab. Any number of these (or none) may apply at once.
+enum class TabAlert {
+  MEDIA_RECORDING,        // Audio/Video [both] being recorded, consumed by tab.
+  TAB_CAPTURING,          // Tab contents being captured.
+  AUDIO_PLAYING,          // Audible audio is playing from the tab.
+  AUDIO_MUTING,           // Tab audio is being muted.
+  BLUETOOTH_CONNECTED,    // Tab is connected to a BT Device.
+  BLUETOOTH_SCAN_ACTIVE,  // Tab is actively scanning for BT devices.
+  USB_CONNECTED,          // Tab is connected to a USB device.
+  HID_CONNECTED,          // Tab is connected to a HID device.
+  SERIAL_CONNECTED,       // Tab is connected to a serial device.
+  PIP_PLAYING,            // Tab contains a video in Picture-in-Picture mode.
+  DESKTOP_CAPTURING,      // Desktop contents being recorded, consumed by tab.
+  VR_PRESENTING_IN_HEADSET,  // VR content is being presented in a headset.
+  AUDIO_RECORDING,           // Audio [only] being recorded, consumed by tab.
+  VIDEO_RECORDING,           // Video [only] being recorded, consumed by tab.
+  GLIC_ACCESSING,            // Glic is accessing the tab's contents.
+};
+}  // namespace tabs
+
+#endif  // CHROME_BROWSER_UI_TABS_ALERT_TAB_ALERT_H_
diff --git a/chrome/browser/ui/tabs/features.cc b/chrome/browser/ui/tabs/features.cc
index 1ea0ada..221adc86 100644
--- a/chrome/browser/ui/tabs/features.cc
+++ b/chrome/browser/ui/tabs/features.cc
@@ -6,7 +6,7 @@
 
 #include "base/feature_list.h"
 #include "chrome/browser/buildflags.h"
-#include "chrome/common/chrome_features.h"
+#include "chrome/browser/ui/ui_features.h"
 
 namespace tabs {
 
diff --git a/chrome/browser/ui/tabs/tab_enums.h b/chrome/browser/ui/tabs/tab_enums.h
index 281589db..b83c85b0 100644
--- a/chrome/browser/ui/tabs/tab_enums.h
+++ b/chrome/browser/ui/tabs/tab_enums.h
@@ -5,25 +5,6 @@
 #ifndef CHROME_BROWSER_UI_TABS_TAB_ENUMS_H_
 #define CHROME_BROWSER_UI_TABS_TAB_ENUMS_H_
 
-// Alert states for a tab. Any number of these (or none) may apply at once.
-enum class TabAlertState {
-  MEDIA_RECORDING,        // Audio/Video [both] being recorded, consumed by tab.
-  TAB_CAPTURING,          // Tab contents being captured.
-  AUDIO_PLAYING,          // Audible audio is playing from the tab.
-  AUDIO_MUTING,           // Tab audio is being muted.
-  BLUETOOTH_CONNECTED,    // Tab is connected to a BT Device.
-  BLUETOOTH_SCAN_ACTIVE,  // Tab is actively scanning for BT devices.
-  USB_CONNECTED,          // Tab is connected to a USB device.
-  HID_CONNECTED,          // Tab is connected to a HID device.
-  SERIAL_CONNECTED,       // Tab is connected to a serial device.
-  PIP_PLAYING,            // Tab contains a video in Picture-in-Picture mode.
-  DESKTOP_CAPTURING,      // Desktop contents being recorded, consumed by tab.
-  VR_PRESENTING_IN_HEADSET,  // VR content is being presented in a headset.
-  AUDIO_RECORDING,           // Audio [only] being recorded, consumed by tab.
-  VIDEO_RECORDING,           // Video [only] being recorded, consumed by tab.
-  GLIC_ACCESSING,            // Glic is accessing the tab's contents.
-};
-
 // State indicating if the user is following the web feed of the site loaded in
 // a tab.
 enum class TabWebFeedFollowState {
diff --git a/chrome/browser/ui/tabs/tab_renderer_data.h b/chrome/browser/ui/tabs/tab_renderer_data.h
index ce89504..5a37dde 100644
--- a/chrome/browser/ui/tabs/tab_renderer_data.h
+++ b/chrome/browser/ui/tabs/tab_renderer_data.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/process/kill.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_network_state.h"
 #include "ui/base/models/image_model.h"
@@ -63,7 +64,7 @@
   bool show_icon = true;
   bool pinned = false;
   bool blocked = false;
-  std::vector<TabAlertState> alert_state;
+  std::vector<tabs::TabAlert> alert_state;
   bool should_hide_throbber = false;
   bool should_render_empty_title = false;
   bool should_themify_favicon = false;
diff --git a/chrome/browser/ui/tabs/tab_renderer_data_unittest.cc b/chrome/browser/ui/tabs/tab_renderer_data_unittest.cc
index ae3753d..c6c11ed 100644
--- a/chrome/browser/ui/tabs/tab_renderer_data_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_renderer_data_unittest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/resource_coordinator/utils.h"
 #include "chrome/browser/ui/performance_controls/tab_resource_usage_tab_helper.h"
 #include "chrome/browser/ui/tab_ui_helper.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/test_util.h"
@@ -288,7 +289,7 @@
       TabRendererData::FromTabInModel(&tab_strip_model_, index);
   EXPECT_NE(data.alert_state.end(),
             std::find(data.alert_state.begin(), data.alert_state.end(),
-                      TabAlertState::AUDIO_PLAYING));
+                      tabs::TabAlert::AUDIO_PLAYING));
 }
 
 TEST_F(TabRendererDataTest, ShouldHideThrobber) {
diff --git a/chrome/browser/ui/tabs/tab_strip_api/BUILD.gn b/chrome/browser/ui/tabs/tab_strip_api/BUILD.gn
index eadb3ff9..7c9c2a4 100644
--- a/chrome/browser/ui/tabs/tab_strip_api/BUILD.gn
+++ b/chrome/browser/ui/tabs/tab_strip_api/BUILD.gn
@@ -29,7 +29,7 @@
         },
         {
           mojom = "tabs_api.mojom.TabAlertState"
-          cpp = "::TabAlertState"
+          cpp = "::tabs::TabAlert"
         },
         {
           mojom = "tabs_api.mojom.TabNetworkState"
@@ -40,6 +40,7 @@
         "//chrome/browser/ui/tabs/tab_strip_api/tab_id.h",
         "//chrome/browser/ui/tabs/tab_strip_api/tab_id_traits.h",
         "//chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.h",
+        "//chrome/browser/ui/tabs/alert/tab_alert.h",
       ]
       traits_sources = [
         "//chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.cc",
diff --git a/chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.h b/chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.h
index d2b547d..2e52a0a8 100644
--- a/chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.h
+++ b/chrome/browser/ui/tabs/tab_strip_api/tab_enum_traits.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_TABS_TAB_STRIP_API_TAB_ENUM_TRAITS_H_
 #define CHROME_BROWSER_UI_TABS_TAB_STRIP_API_TAB_ENUM_TRAITS_H_
 
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_network_state.h"
 #include "chrome/browser/ui/tabs/tab_strip_api/tab_strip_api.mojom.h"
@@ -22,7 +23,7 @@
 };
 
 using MojoTabAlertState = tabs_api::mojom::TabAlertState;
-using NativeTabAlertState = enum TabAlertState;
+using NativeTabAlertState = enum tabs::TabAlert;
 
 // TabAlertState Enum mapping.
 template <>
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 58b53b3..bb27ffe 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -28,6 +28,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
@@ -171,13 +172,14 @@
   return std::make_unique<TabGroupModel>(controller);
 }
 
-DetachedTabGroup::DetachedTabGroup(
-    std::unique_ptr<tabs::TabGroupTabCollection> collection,
+DetachedTabCollection::DetachedTabCollection(
+    std::variant<std::unique_ptr<tabs::TabGroupTabCollection>,
+                 std::unique_ptr<tabs::SplitTabCollection>> collection,
     std::optional<int> active_index)
     : collection_(std::move(collection)), active_index_(active_index) {}
 
-DetachedTabGroup::~DetachedTabGroup() = default;
-DetachedTabGroup::DetachedTabGroup(DetachedTabGroup&&) = default;
+DetachedTabCollection::~DetachedTabCollection() = default;
+DetachedTabCollection::DetachedTabCollection(DetachedTabCollection&&) = default;
 
 DetachedTab::DetachedTab(int index_before_any_removals,
                          int index_at_time_of_removal,
@@ -403,7 +405,8 @@
   return std::move(notifications.detached_tab[0]);
 }
 
-std::unique_ptr<DetachedTabGroup> TabStripModel::DetachTabGroupForInsertion(
+std::unique_ptr<DetachedTabCollection>
+TabStripModel::DetachTabGroupForInsertion(
     const tab_groups::TabGroupId group_id) {
   ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
@@ -414,14 +417,21 @@
 }
 
 gfx::Range TabStripModel::InsertDetachedTabGroupAt(
-    std::unique_ptr<DetachedTabGroup> group,
+    std::unique_ptr<DetachedTabCollection> group,
     int index) {
   ReentrancyCheck reentrancy_check(&reentrancy_guard_);
   CHECK(group_model_);
-  CHECK(!group_model_->ContainsTabGroup(group->collection_->GetTabGroupId()));
+  CHECK(std::holds_alternative<std::unique_ptr<tabs::TabGroupTabCollection>>(
+      group->collection_));
+
+  tabs::TabGroupTabCollection* group_collection =
+      std::get<std::unique_ptr<tabs::TabGroupTabCollection>>(group->collection_)
+          .get();
+
+  CHECK(!group_model_->ContainsTabGroup(group_collection->GetTabGroupId()));
 
   // Notify tab is added to model.
-  for (tabs::TabInterface* tab : *(group->collection_)) {
+  for (tabs::TabInterface* tab : *(group_collection)) {
     static_cast<tabs::TabModel*>(tab)->OnAddedToModel(this);
   }
 
@@ -441,7 +451,7 @@
   }
 }
 
-std::unique_ptr<DetachedTabGroup> TabStripModel::DetachTabGroupImpl(
+std::unique_ptr<DetachedTabCollection> TabStripModel::DetachTabGroupImpl(
     const tab_groups::TabGroupId& group_id) {
   // Prepare for group to be removed.
   const gfx::Range tabs_in_group =
@@ -571,20 +581,26 @@
       active_tab_removed
           ? group_collection->GetIndexOfTabRecursive(active_tab_model)
           : std::nullopt;
-  return std::make_unique<DetachedTabGroup>(std::move(group_collection),
-                                            active_index_in_group);
+  return std::make_unique<DetachedTabCollection>(std::move(group_collection),
+                                                 active_index_in_group);
 }
 
 gfx::Range TabStripModel::InsertDetachedTabGroupImpl(
-    std::unique_ptr<DetachedTabGroup> detached_group,
+    std::unique_ptr<DetachedTabCollection> detached_group,
     int index) {
-  CHECK(detached_group->collection_);
+  CHECK(std::holds_alternative<std::unique_ptr<tabs::TabGroupTabCollection>>(
+      detached_group->collection_));
+
+  std::unique_ptr<tabs::TabGroupTabCollection> group_collection =
+      std::move(std::get<std::unique_ptr<tabs::TabGroupTabCollection>>(
+          detached_group->collection_));
+  CHECK(group_collection);
+
+  tabs::TabGroupTabCollection* group_collection_ptr = group_collection.get();
 
   const tab_groups::TabGroupId& group_id =
-      detached_group->collection_->GetTabGroupId();
-  tabs::TabGroupTabCollection* group_collection =
-      detached_group->collection_.get();
-  for (const tabs::TabInterface* tab : *group_collection) {
+      group_collection_ptr->GetTabGroupId();
+  for (const tabs::TabInterface* tab : *group_collection_ptr) {
     delegate()->WillAddWebContents(tab->GetContents());
   }
 
@@ -593,14 +609,12 @@
   const bool tab_strip_empty_initially = empty();
 
   // Add the group collection.
-  group_model_->AddTabGroup(
-      std::move(detached_group->collection_->GetTabGroup()),
-      base::PassKey<TabStripModel>());
-  contents_data_->InsertTabGroupAt(std::move(detached_group->collection_),
-                                   index);
+  group_model_->AddTabGroup(std::move(group_collection_ptr->GetTabGroup()),
+                            base::PassKey<TabStripModel>());
+  contents_data_->InsertTabGroupAt(std::move(group_collection), index);
 
   for (int i = index;
-       i < index + static_cast<int>(group_collection->TabCountRecursive());
+       i < index + static_cast<int>(group_collection_ptr->TabCountRecursive());
        i++) {
     selection_model_.IncrementFrom(index);
   }
@@ -615,7 +629,7 @@
   ValidateTabStripModel();
 
   std::set<split_tabs::SplitTabId> splits_in_group;
-  for (tabs::TabInterface* tab : *group_collection) {
+  for (tabs::TabInterface* tab : *group_collection_ptr) {
     static_cast<tabs::TabModel*>(tab)->DidInsert(
         base::PassKey<TabStripModel>());
 
@@ -644,7 +658,7 @@
   OnChange(change, selection);
 
   // Send group attach notification.
-  NotifyTabGroupAttached(group_collection);
+  NotifyTabGroupAttached(group_collection_ptr);
 
   // Send split attach notification
   for (const split_tabs::SplitTabId& split_id : splits_in_group) {
@@ -2107,7 +2121,10 @@
       if (!delegate_->CanReload()) {
         break;
       }
-      for (int index : GetIndicesForCommand(context_index)) {
+      const std::vector<int> indices = GetIndicesForCommand(context_index);
+      base::UmaHistogramCounts100("TabStrip.Tab.ContextMenuReloadCount",
+                                  indices.size());
+      for (int index : indices) {
         WebContents* tab = GetWebContentsAt(index);
         if (tab) {
           tab->GetController().Reload(content::ReloadType::NORMAL, true);
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 6ae8930..1b33376 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -73,17 +73,20 @@
   std::unique_ptr<TabGroupModel> Create(TabGroupController* controller);
 };
 
-// Holds the collection object for the group. Have DetachedTabGroup object as a
-// container of the collection_ so client does not need to worry or deal with
-// the collection object.
-struct DetachedTabGroup {
-  DetachedTabGroup(std::unique_ptr<tabs::TabGroupTabCollection> collection,
-                   std::optional<int> active_index);
-  DetachedTabGroup(const DetachedTabGroup&) = delete;
-  DetachedTabGroup& operator=(const DetachedTabGroup&) = delete;
-  ~DetachedTabGroup();
-  DetachedTabGroup(DetachedTabGroup&&);
-  std::unique_ptr<tabs::TabGroupTabCollection> collection_;
+// Have DetachedTabCollection object as a container of the `collection_` so
+// client does not need to worry or deal with the collection object.
+struct DetachedTabCollection {
+  DetachedTabCollection(
+      std::variant<std::unique_ptr<tabs::TabGroupTabCollection>,
+                   std::unique_ptr<tabs::SplitTabCollection>> collection,
+      std::optional<int> active_index);
+  DetachedTabCollection(const DetachedTabCollection&) = delete;
+  DetachedTabCollection& operator=(const DetachedTabCollection&) = delete;
+  ~DetachedTabCollection();
+  DetachedTabCollection(DetachedTabCollection&&);
+  std::variant<std::unique_ptr<tabs::TabGroupTabCollection>,
+               std::unique_ptr<tabs::SplitTabCollection>>
+      collection_;
   // Store the index of tab that was active in the detached group.
   std::optional<int> active_index_ = std::nullopt;
 };
@@ -278,12 +281,13 @@
   // Removes the group collection from the collection hierarchy and passes it to
   // the client. The client can re-insert into another tabstrip using
   // `InsertDetachedGroupAt` without destroying the group.
-  std::unique_ptr<DetachedTabGroup> DetachTabGroupForInsertion(
+  std::unique_ptr<DetachedTabCollection> DetachTabGroupForInsertion(
       const tab_groups::TabGroupId group_id);
 
   // Inserts a detached tab group into the tabstrip starting at `index`.
-  gfx::Range InsertDetachedTabGroupAt(std::unique_ptr<DetachedTabGroup> group,
-                                      int index);
+  gfx::Range InsertDetachedTabGroupAt(
+      std::unique_ptr<DetachedTabCollection> group,
+      int index);
 
   // Closes the WebContents at the specified index. This causes the
   // WebContents to be destroyed, but it may not happen immediately.
@@ -876,11 +880,11 @@
       TabStripModelChange::RemoveReason web_contents_remove_reason,
       tabs::TabInterface::DetachReason tab_detach_reason);
 
-  std::unique_ptr<DetachedTabGroup> DetachTabGroupImpl(
+  std::unique_ptr<DetachedTabCollection> DetachTabGroupImpl(
       const tab_groups::TabGroupId& group);
 
   gfx::Range InsertDetachedTabGroupImpl(
-      std::unique_ptr<DetachedTabGroup> detached_group,
+      std::unique_ptr<DetachedTabCollection> detached_group,
       int index);
 
   // We batch send notifications. This has two benefits:
diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
index c743618..2f9a529 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
@@ -905,10 +905,14 @@
 
   tab_groups::TabGroupId group_id =
       tabstrip()->AddToNewGroup(std::vector<int>{1, 2});
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       tabstrip()->DetachTabGroupForInsertion(group_id);
+  tabs::TabGroupTabCollection* group_collection =
+      std::get<std::unique_ptr<tabs::TabGroupTabCollection>>(
+          detached_group->collection_)
+          .get();
 
-  EXPECT_EQ(detached_group->collection_->TabCountRecursive(), 2u);
+  EXPECT_EQ(group_collection->TabCountRecursive(), 2u);
   EXPECT_FALSE(tabstrip()->group_model()->ContainsTabGroup(group_id));
   EXPECT_EQ(tabstrip()->count(), 4);
 
@@ -939,7 +943,7 @@
   tabstrip()->ActivateTabAt(2);
   tabstrip()->ForgetAllOpeners();
   tabstrip()->SetOpenerOfWebContentsAt(0, tabstrip()->GetWebContentsAt(1));
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       tabstrip()->DetachTabGroupForInsertion(group_id);
 
   EXPECT_EQ(tabstrip()->active_index(), 0);
@@ -1003,10 +1007,14 @@
   split_tabs::SplitTabId split_id =
       tabstrip()->AddToNewSplit({3}, split_tabs::SplitTabLayout::kVertical);
 
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       tabstrip()->DetachTabGroupForInsertion(group_id);
+  tabs::TabGroupTabCollection* group_collection =
+      std::get<std::unique_ptr<tabs::TabGroupTabCollection>>(
+          detached_group->collection_)
+          .get();
 
-  EXPECT_EQ(detached_group->collection_->TabCountRecursive(), 3u);
+  EXPECT_EQ(group_collection->TabCountRecursive(), 3u);
   EXPECT_FALSE(tabstrip()->group_model()->ContainsTabGroup(group_id));
   EXPECT_EQ(tabstrip()->count(), 2);
 
@@ -1038,7 +1046,7 @@
   tab_groups::TabGroupId group_id =
       tabstrip()->AddToNewGroup(std::vector<int>{1, 2});
   tabstrip()->ActivateTabAt(1);
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       tabstrip()->DetachTabGroupForInsertion(group_id);
 
   tabs::TabInterface* active_tab = tabstrip()->GetActiveTab();
diff --git a/chrome/browser/ui/tabs/tab_utils.cc b/chrome/browser/ui/tabs/tab_utils.cc
index 2eb6c95..16d9767 100644
--- a/chrome/browser/ui/tabs/tab_utils.cc
+++ b/chrome/browser/ui/tabs/tab_utils.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/recently_audible_helper.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/vr/vr_tab_helper.h"
@@ -29,9 +30,9 @@
 #include "chrome/browser/glic/resources/grit/glic_browser_resources.h"
 #endif
 
-std::vector<TabAlertState> GetTabAlertStatesForContents(
+std::vector<tabs::TabAlert> GetTabAlertStatesForContents(
     content::WebContents* contents) {
-  std::vector<TabAlertState> states;
+  std::vector<tabs::TabAlert> states;
   if (!contents) {
     return states;
   }
@@ -46,50 +47,50 @@
     // with tooltip that notes all the states in play.
     if (indicator->IsCapturingWindow(contents) ||
         indicator->IsCapturingDisplay(contents)) {
-      states.push_back(TabAlertState::DESKTOP_CAPTURING);
+      states.push_back(tabs::TabAlert::DESKTOP_CAPTURING);
     }
     if (indicator->IsBeingMirrored(contents)) {
-      states.push_back(TabAlertState::TAB_CAPTURING);
+      states.push_back(tabs::TabAlert::TAB_CAPTURING);
     }
 
     if (indicator->IsCapturingAudio(contents) &&
         indicator->IsCapturingVideo(contents)) {
-      states.push_back(TabAlertState::MEDIA_RECORDING);
+      states.push_back(tabs::TabAlert::MEDIA_RECORDING);
     } else if (indicator->IsCapturingAudio(contents)) {
-      states.push_back(TabAlertState::AUDIO_RECORDING);
+      states.push_back(tabs::TabAlert::AUDIO_RECORDING);
     } else if (indicator->IsCapturingVideo(contents)) {
-      states.push_back(TabAlertState::VIDEO_RECORDING);
+      states.push_back(tabs::TabAlert::VIDEO_RECORDING);
     }
   }
 
   if (contents->IsCapabilityActive(
           content::WebContentsCapabilityType::kBluetoothConnected)) {
-    states.push_back(TabAlertState::BLUETOOTH_CONNECTED);
+    states.push_back(tabs::TabAlert::BLUETOOTH_CONNECTED);
   }
 
   if (contents->IsCapabilityActive(
           content::WebContentsCapabilityType::kBluetoothScanning)) {
-    states.push_back(TabAlertState::BLUETOOTH_SCAN_ACTIVE);
+    states.push_back(tabs::TabAlert::BLUETOOTH_SCAN_ACTIVE);
   }
 
   if (contents->IsCapabilityActive(content::WebContentsCapabilityType::kUSB)) {
-    states.push_back(TabAlertState::USB_CONNECTED);
+    states.push_back(tabs::TabAlert::USB_CONNECTED);
   }
 
   if (contents->IsCapabilityActive(content::WebContentsCapabilityType::kHID)) {
-    states.push_back(TabAlertState::HID_CONNECTED);
+    states.push_back(tabs::TabAlert::HID_CONNECTED);
   }
 
   if (contents->IsCapabilityActive(
           content::WebContentsCapabilityType::kSerial)) {
-    states.push_back(TabAlertState::SERIAL_CONNECTED);
+    states.push_back(tabs::TabAlert::SERIAL_CONNECTED);
   }
 
 #if BUILDFLAG(ENABLE_GLIC)
   glic::GlicKeyedService* glic_service = glic::GlicKeyedService::Get(
       Profile::FromBrowserContext(contents->GetBrowserContext()));
   if (glic_service && glic_service->IsContextAccessIndicatorShown(contents)) {
-    states.push_back(TabAlertState::GLIC_ACCESSING);
+    states.push_back(tabs::TabAlert::GLIC_ACCESSING);
   }
 #endif
 
@@ -98,12 +99,12 @@
   // because most VR content has audio and its usage is implied by the VR
   // icon.
   if (vr::VrTabHelper::IsContentDisplayedInHeadset(contents)) {
-    states.push_back(TabAlertState::VR_PRESENTING_IN_HEADSET);
+    states.push_back(tabs::TabAlert::VR_PRESENTING_IN_HEADSET);
   }
 
   if (contents->HasPictureInPictureVideo() ||
       contents->HasPictureInPictureDocument()) {
-    states.push_back(TabAlertState::PIP_PLAYING);
+    states.push_back(tabs::TabAlert::PIP_PLAYING);
   }
 
   // Only tabs have a RecentlyAudibleHelper, but this function is abused for
@@ -116,58 +117,58 @@
   }
   if (audible) {
     if (contents->IsAudioMuted()) {
-      states.push_back(TabAlertState::AUDIO_MUTING);
+      states.push_back(tabs::TabAlert::AUDIO_MUTING);
     }
-    states.push_back(TabAlertState::AUDIO_PLAYING);
+    states.push_back(tabs::TabAlert::AUDIO_PLAYING);
   }
 
   return states;
 }
 
-std::u16string GetTabAlertStateText(const TabAlertState alert_state) {
+std::u16string GetTabAlertStateText(const tabs::TabAlert alert_state) {
   switch (alert_state) {
-    case TabAlertState::AUDIO_PLAYING:
+    case tabs::TabAlert::AUDIO_PLAYING:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_AUDIO_PLAYING);
-    case TabAlertState::AUDIO_MUTING:
+    case tabs::TabAlert::AUDIO_MUTING:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_AUDIO_MUTING);
-    case TabAlertState::MEDIA_RECORDING:
+    case tabs::TabAlert::MEDIA_RECORDING:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_MEDIA_RECORDING);
-    case TabAlertState::AUDIO_RECORDING:
+    case tabs::TabAlert::AUDIO_RECORDING:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_AUDIO_RECORDING);
-    case TabAlertState::VIDEO_RECORDING:
+    case tabs::TabAlert::VIDEO_RECORDING:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_VIDEO_RECORDING);
-    case TabAlertState::TAB_CAPTURING:
+    case tabs::TabAlert::TAB_CAPTURING:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_TAB_CAPTURING);
-    case TabAlertState::BLUETOOTH_CONNECTED:
+    case tabs::TabAlert::BLUETOOTH_CONNECTED:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_BLUETOOTH_CONNECTED);
-    case TabAlertState::BLUETOOTH_SCAN_ACTIVE:
+    case tabs::TabAlert::BLUETOOTH_SCAN_ACTIVE:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_BLUETOOTH_SCAN_ACTIVE);
-    case TabAlertState::USB_CONNECTED:
+    case tabs::TabAlert::USB_CONNECTED:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_USB_CONNECTED);
-    case TabAlertState::HID_CONNECTED:
+    case tabs::TabAlert::HID_CONNECTED:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_HID_CONNECTED);
-    case TabAlertState::SERIAL_CONNECTED:
+    case tabs::TabAlert::SERIAL_CONNECTED:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_SERIAL_CONNECTED);
-    case TabAlertState::PIP_PLAYING:
+    case tabs::TabAlert::PIP_PLAYING:
       return l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_ALERT_STATE_PIP_PLAYING);
-    case TabAlertState::DESKTOP_CAPTURING:
+    case tabs::TabAlert::DESKTOP_CAPTURING:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_DESKTOP_CAPTURING);
-    case TabAlertState::VR_PRESENTING_IN_HEADSET:
+    case tabs::TabAlert::VR_PRESENTING_IN_HEADSET:
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_VR_PRESENTING);
-    case TabAlertState::GLIC_ACCESSING:
+    case tabs::TabAlert::GLIC_ACCESSING:
 #if BUILDFLAG(ENABLE_GLIC)
       return l10n_util::GetStringUTF16(
           IDS_TOOLTIP_TAB_ALERT_STATE_GLIC_ACCESSING);
diff --git a/chrome/browser/ui/tabs/tab_utils.h b/chrome/browser/ui/tabs/tab_utils.h
index 83e3a69c..c5aa63f 100644
--- a/chrome/browser/ui/tabs/tab_utils.h
+++ b/chrome/browser/ui/tabs/tab_utils.h
@@ -19,6 +19,10 @@
 class WebContents;
 }  // namespace content
 
+namespace tabs {
+enum class TabAlert;
+}  // namespace tabs
+
 struct LastMuteMetadata
     : public content::WebContentsUserData<LastMuteMetadata> {
   TabMutedReason reason = TabMutedReason::NONE;
@@ -35,11 +39,11 @@
 // privacy, i.e. if only one is to be shown, it should be the first.
 // TabAlertState::NONE will never be present in the list; an empty list
 // is returned instead.
-std::vector<TabAlertState> GetTabAlertStatesForContents(
+std::vector<tabs::TabAlert> GetTabAlertStatesForContents(
     content::WebContents* contents);
 
 // Returns a localized string describing the |alert_state|.
-std::u16string GetTabAlertStateText(const TabAlertState alert_state);
+std::u16string GetTabAlertStateText(const tabs::TabAlert alert_state);
 
 // Sets whether all audio output from |contents| is muted, along with the
 // |reason| it is to be muted/unmuted (via UI or extension API).  When |reason|
diff --git a/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model_browsertest.cc b/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model_browsertest.cc
index 77effcf..e36c74f 100644
--- a/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model_browsertest.cc
+++ b/chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model_browsertest.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model_factory.h"
 #include "chrome/browser/ui/toolbar/toolbar_pref_names.h"
-#include "chrome/common/chrome_features.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/ui/toolbar/toolbar_pref_names.cc b/chrome/browser/ui/toolbar/toolbar_pref_names.cc
index 4dd7496..2ac0c02 100644
--- a/chrome/browser/ui/toolbar/toolbar_pref_names.cc
+++ b/chrome/browser/ui/toolbar/toolbar_pref_names.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ui/toolbar/toolbar_pref_names.h"
 
 #include "chrome/browser/ui/actions/chrome_action_id.h"
-#include "chrome/common/chrome_features.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "ui/actions/actions.h"
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 25a35fdf..9309686 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -8,7 +8,9 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "chrome/browser/browser_process.h"
 #include "components/search/ntp_features.h"
+#include "components/variations/service/variations_service.h"
 #include "components/webui/flags/feature_entry.h"
 #include "ui/base/ui_base_features.h"
 
@@ -413,4 +415,37 @@
              "TabStripBrowserApi",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kTabstripComboButton,
+             "TabstripComboButton",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+const base::FeatureParam<bool> kTabstripComboButtonHasBackground{
+    &kTabstripComboButton, "has_background", false};
+
+const base::FeatureParam<bool> kTabstripComboButtonHasReverseButtonOrder{
+    &kTabstripComboButton, "reverse_button_order", false};
+
+const base::FeatureParam<bool> kTabSearchToolbarButton{
+    &kTabstripComboButton, "tab_search_toolbar_button", false};
+
+bool IsTabSearchMoving() {
+  return base::FeatureList::IsEnabled(features::kTabstripComboButton);
+}
+
+bool HasTabstripComboButtonWithBackground() {
+  return IsTabSearchMoving() &&
+         features::kTabstripComboButtonHasBackground.Get() &&
+         !features::kTabSearchToolbarButton.Get();
+}
+
+bool HasTabstripComboButtonWithReverseButtonOrder() {
+  return IsTabSearchMoving() &&
+         features::kTabstripComboButtonHasReverseButtonOrder.Get() &&
+         !features::kTabSearchToolbarButton.Get();
+}
+
+bool HasTabSearchToolbarButton() {
+  return IsTabSearchMoving() && features::kTabSearchToolbarButton.Get();
+}
+
 }  // namespace features
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index 1adaa40..fd90bcf 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -270,6 +270,17 @@
 // Controls whether to use the TabStrip browser api's controller.
 BASE_DECLARE_FEATURE(kTabStripBrowserApi);
 
+// Controls where tab search lives in the browser.
+BASE_DECLARE_FEATURE(kTabstripComboButton);
+extern const base::FeatureParam<bool> kTabstripComboButtonHasBackground;
+extern const base::FeatureParam<bool> kTabstripComboButtonHasReverseButtonOrder;
+extern const base::FeatureParam<bool> kTabSearchToolbarButton;
+extern const base::FeatureParam<bool> kLaunchedTabSearchToolbarButton;
+bool IsTabSearchMoving();
+bool HasTabstripComboButtonWithBackground();
+bool HasTabstripComboButtonWithReverseButtonOrder();
+bool HasTabSearchToolbarButton();
+
 }  // namespace features
 
 #endif  // CHROME_BROWSER_UI_UI_FEATURES_H_
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_button_base.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_button_base.cc
index 6c1ba43..9f4eee4 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_button_base.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_button_base.cc
@@ -10,6 +10,8 @@
 #include "chrome/browser/ui/views/bookmarks/bookmark_button_util.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h"
+#include "ui/compositor/layer.h"
+#include "ui/views/animation/ink_drop.h"
 #include "ui/views/controls/button/label_button_border.h"
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/highlight_path_generator.h"
@@ -21,6 +23,13 @@
   SetImageLabelSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric(
       DISTANCE_RELATED_LABEL_HORIZONTAL_LIST));
   views::InstallPillHighlightPathGenerator(this);
+
+#if BUILDFLAG(IS_WIN)
+  // Paint image(s) to a layer so that the canvas is snapped to pixel
+  // boundaries.
+  image_container_view()->SetPaintToLayer();
+  image_container_view()->layer()->SetFillsBoundsOpaquely(false);
+#endif
 }
 
 // MenuButton:
@@ -29,5 +38,18 @@
   return bookmark_button_util::CreateBookmarkButtonBorder();
 }
 
+#if BUILDFLAG(IS_WIN)
+void BookmarkMenuButtonBase::AddLayerToRegion(ui::Layer* new_layer,
+                                              views::LayerRegion region) {
+  ink_drop_container()->SetVisible(true);
+  ink_drop_container()->AddLayerToRegion(new_layer, region);
+}
+
+void BookmarkMenuButtonBase::RemoveLayerFromRegions(ui::Layer* old_layer) {
+  ink_drop_container()->RemoveLayerFromRegions(old_layer);
+  ink_drop_container()->SetVisible(false);
+}
+#endif
+
 BEGIN_METADATA(BookmarkMenuButtonBase)
 END_METADATA
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_button_base.h b/chrome/browser/ui/views/bookmarks/bookmark_menu_button_base.h
index 45e54d1a..348776c 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_button_base.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_button_base.h
@@ -7,6 +7,7 @@
 
 #include <string_view>
 
+#include "build/buildflag.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/views/controls/button/menu_button.h"
@@ -24,6 +25,11 @@
   // MenuButton:
   std::unique_ptr<views::LabelButtonBorder> CreateDefaultBorder()
       const override;
+#if BUILDFLAG(IS_WIN)
+  void AddLayerToRegion(ui::Layer* new_layer,
+                        views::LayerRegion region) override;
+  void RemoveLayerFromRegions(ui::Layer* old_layer) override;
+#endif
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_BOOKMARKS_BOOKMARK_MENU_BUTTON_BASE_H_
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_overflow_button.cc b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_overflow_button.cc
index b7d3795..c0d82b53 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_overflow_button.cc
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_overflow_button.cc
@@ -22,7 +22,9 @@
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/color/color_provider.h"
+#include "ui/compositor/layer.h"
 #include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/animation/ink_drop.h"
 #include "ui/views/controls/button/label_button_border.h"
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/highlight_path_generator.h"
@@ -48,6 +50,13 @@
       DISTANCE_RELATED_LABEL_HORIZONTAL_LIST));
   SetProperty(views::kElementIdentifierKey,
               kSavedTabGroupOverflowButtonElementId);
+
+#if BUILDFLAG(IS_WIN)
+  // Paint image(s) to a layer so that the canvas is snapped to pixel
+  // boundaries.
+  image_container_view()->SetPaintToLayer();
+  image_container_view()->layer()->SetFillsBoundsOpaquely(false);
+#endif
 }
 
 SavedTabGroupOverflowButton::~SavedTabGroupOverflowButton() = default;
@@ -77,6 +86,19 @@
   return;
 }
 
+#if BUILDFLAG(IS_WIN)
+void SavedTabGroupOverflowButton::AddLayerToRegion(ui::Layer* new_layer,
+                                                   views::LayerRegion region) {
+  ink_drop_container()->SetVisible(true);
+  ink_drop_container()->AddLayerToRegion(new_layer, region);
+}
+
+void SavedTabGroupOverflowButton::RemoveLayerFromRegions(ui::Layer* old_layer) {
+  ink_drop_container()->RemoveLayerFromRegions(old_layer);
+  ink_drop_container()->SetVisible(false);
+}
+#endif
+
 BEGIN_METADATA(SavedTabGroupOverflowButton)
 END_METADATA
 
diff --git a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_overflow_button.h b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_overflow_button.h
index 1bf502c..e19c531 100644
--- a/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_overflow_button.h
+++ b/chrome/browser/ui/views/bookmarks/saved_tab_groups/saved_tab_group_overflow_button.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_BOOKMARKS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_OVERFLOW_BUTTON_H_
 #define CHROME_BROWSER_UI_VIEWS_BOOKMARKS_SAVED_TAB_GROUPS_SAVED_TAB_GROUP_OVERFLOW_BUTTON_H_
 
+#include "build/buildflag.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/button/menu_button.h"
 
@@ -25,6 +26,11 @@
   std::unique_ptr<views::LabelButtonBorder> CreateDefaultBorder()
       const override;
   void OnThemeChanged() override;
+#if BUILDFLAG(IS_WIN)
+  void AddLayerToRegion(ui::Layer* new_layer,
+                        views::LayerRegion region) override;
+  void RemoveLayerFromRegions(ui::Layer* old_layer) override;
+#endif
 };
 
 }  // namespace tab_groups
diff --git a/chrome/browser/ui/views/commerce/product_specifications_button_browsertest.cc b/chrome/browser/ui/views/commerce/product_specifications_button_browsertest.cc
index 2a112838..7cba8a6 100644
--- a/chrome/browser/ui/views/commerce/product_specifications_button_browsertest.cc
+++ b/chrome/browser/ui/views/commerce/product_specifications_button_browsertest.cc
@@ -12,11 +12,11 @@
 #include "chrome/browser/ui/commerce/product_specifications_entry_point_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_prefs.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/tab_strip_region_view.h"
 #include "chrome/browser/ui/views/tabs/tab_search_button.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_action_container.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/views/chrome_views_test_base.h"
 #include "components/commerce/core/commerce_feature_list.h"
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index eefb48c2..047ba69 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -88,6 +88,7 @@
 #include "chrome/browser/ui/sharing_hub/sharing_hub_bubble_controller.h"
 #include "chrome/browser/ui/sharing_hub/sharing_hub_bubble_view.h"
 #include "chrome/browser/ui/sync/one_click_signin_links_delegate_impl.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_tab_data.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/shared_tab_group_feedback_controller.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
@@ -4263,66 +4264,66 @@
   }
 
   // Alert tab states.
-  std::optional<TabAlertState> alert = tabstrip_->GetTabAlertState(index);
+  std::optional<tabs::TabAlert> alert = tabstrip_->GetTabAlertState(index);
   if (alert.has_value()) {
     switch (alert.value()) {
-      case TabAlertState::AUDIO_PLAYING:
+      case tabs::TabAlert::AUDIO_PLAYING:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_AUDIO_PLAYING_FORMAT, title);
         break;
-      case TabAlertState::USB_CONNECTED:
+      case tabs::TabAlert::USB_CONNECTED:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_USB_CONNECTED_FORMAT, title);
         break;
-      case TabAlertState::BLUETOOTH_CONNECTED:
+      case tabs::TabAlert::BLUETOOTH_CONNECTED:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_BLUETOOTH_CONNECTED_FORMAT, title);
         break;
-      case TabAlertState::BLUETOOTH_SCAN_ACTIVE:
+      case tabs::TabAlert::BLUETOOTH_SCAN_ACTIVE:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_BLUETOOTH_SCAN_ACTIVE_FORMAT, title);
         break;
-      case TabAlertState::HID_CONNECTED:
+      case tabs::TabAlert::HID_CONNECTED:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_HID_CONNECTED_FORMAT, title);
         break;
-      case TabAlertState::SERIAL_CONNECTED:
+      case tabs::TabAlert::SERIAL_CONNECTED:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_SERIAL_CONNECTED_FORMAT, title);
         break;
-      case TabAlertState::MEDIA_RECORDING:
+      case tabs::TabAlert::MEDIA_RECORDING:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_MEDIA_RECORDING_FORMAT, title);
         break;
-      case TabAlertState::AUDIO_RECORDING:
+      case tabs::TabAlert::AUDIO_RECORDING:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_AUDIO_RECORDING_FORMAT, title);
         break;
-      case TabAlertState::VIDEO_RECORDING:
+      case tabs::TabAlert::VIDEO_RECORDING:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_VIDEO_RECORDING_FORMAT, title);
         break;
-      case TabAlertState::AUDIO_MUTING:
+      case tabs::TabAlert::AUDIO_MUTING:
         title = l10n_util::GetStringFUTF16(IDS_TAB_AX_LABEL_AUDIO_MUTING_FORMAT,
                                            title);
         break;
-      case TabAlertState::TAB_CAPTURING:
+      case tabs::TabAlert::TAB_CAPTURING:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_TAB_CAPTURING_FORMAT, title);
         break;
-      case TabAlertState::PIP_PLAYING:
+      case tabs::TabAlert::PIP_PLAYING:
         title = l10n_util::GetStringFUTF16(IDS_TAB_AX_LABEL_PIP_PLAYING_FORMAT,
                                            title);
         break;
-      case TabAlertState::DESKTOP_CAPTURING:
+      case tabs::TabAlert::DESKTOP_CAPTURING:
         title = l10n_util::GetStringFUTF16(
             IDS_TAB_AX_LABEL_DESKTOP_CAPTURING_FORMAT, title);
         break;
-      case TabAlertState::VR_PRESENTING_IN_HEADSET:
+      case tabs::TabAlert::VR_PRESENTING_IN_HEADSET:
         title =
             l10n_util::GetStringFUTF16(IDS_TAB_AX_LABEL_VR_PRESENTING, title);
         break;
-      case TabAlertState::GLIC_ACCESSING:
+      case tabs::TabAlert::GLIC_ACCESSING:
 #if BUILDFLAG(ENABLE_GLIC)
         title =
             l10n_util::GetStringFUTF16(IDS_TAB_AX_LABEL_GLIC_ACCESSING, title);
diff --git a/chrome/browser/ui/views/frame/browser_view_unittest.cc b/chrome/browser/ui/views/frame/browser_view_unittest.cc
index 5431782..1f61f48 100644
--- a/chrome/browser/ui/views/frame/browser_view_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_unittest.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/performance_controls/tab_resource_usage_tab_helper.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/tab_activity_simulator.h"
 #include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -482,7 +483,7 @@
 
   Tab* tab = browser_view()->tabstrip()->tab_at(0);
   TabRendererData start_media;
-  start_media.alert_state = {TabAlertState::AUDIO_PLAYING};
+  start_media.alert_state = {tabs::TabAlert::AUDIO_PLAYING};
   tab->SetData(std::move(start_media));
   EXPECT_EQ(SubBrowserName(u"about:blank - Audio playing - ", u""),
             browser_view()->GetAccessibleWindowTitleForChannelAndProfile(
diff --git a/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest.cc b/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest.cc
index e0e9f4b..d3157ca 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest.cc
+++ b/chrome/browser/ui/views/frame/system_menu_model_builder_browsertest.cc
@@ -5,6 +5,7 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
index fe7aa57c..9521ccb 100644
--- a/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/tab_strip_region_view_interactive_uitest.cc
@@ -10,13 +10,13 @@
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/features.h"
 #include "chrome/browser/ui/tabs/tab_strip_prefs.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/tab_strip_region_view.h"
 #include "chrome/browser/ui/views/tabs/new_tab_button.h"
 #include "chrome/browser/ui/views/tabs/tab_search_button.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_combo_button.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/browser_test.h"
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc
index 8753aa8..9b54387 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc
@@ -3,12 +3,18 @@
 // found in the LICENSE file.
 
 #include "build/build_config.h"
+#include "chrome/browser/ui/actions/chrome_action_id.h"
+#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
+#include "chrome/browser/ui/page_action/page_action_icon_type.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
 #include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
+#include "chrome/browser/ui/views/page_action/page_action_view.h"
 #include "chrome/browser/ui/views/page_info/page_info_bubble_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+#include "chrome/browser/ui/views/translate/translate_bubble_controller.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "content/public/test/browser_test.h"
@@ -80,15 +86,25 @@
       web_contents, translate::TRANSLATE_STEP_AFTER_TRANSLATE, "en", "fr",
       translate::TranslateErrors::NONE, true);
 
-  PageActionIconView* icon_view =
-      browser_view->toolbar_button_provider()->GetPageActionIconView(
-          PageActionIconType::kTranslate);
+  views::View* icon_view;
+  if (IsPageActionMigrated(PageActionIconType::kTranslate)) {
+    icon_view = browser_view->toolbar_button_provider()->GetPageActionView(
+        kActionShowTranslate);
+  } else {
+    icon_view = browser_view->toolbar_button_provider()->GetPageActionIconView(
+        PageActionIconType::kTranslate);
+  }
+
   ASSERT_TRUE(icon_view);
   EXPECT_TRUE(icon_view->GetVisible());
 
   // Ensure the bubble's widget is visible, but inactive. Active widgets are
   // focused by accessibility, so not of concern.
-  views::Widget* widget = icon_view->GetBubble()->GetWidget();
+  views::Widget* widget = browser()
+                              ->GetFeatures()
+                              .translate_bubble_controller()
+                              ->GetTranslateBubble()
+                              ->GetWidget();
   widget->Deactivate();
   widget->ShowInactive();
   EXPECT_TRUE(widget->IsVisible());
diff --git a/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc b/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc
index e824643..003adf2 100644
--- a/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc
+++ b/chrome/browser/ui/views/side_panel/side_panel_interactive_uitest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
 #include "chrome/browser/ui/toolbar/bookmark_sub_menu_model.h"
 #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/side_panel/side_panel.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h"
@@ -26,7 +27,6 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/interaction/interaction_test_util_browser.h"
 #include "chrome/test/interaction/interactive_browser_test.h"
diff --git a/chrome/browser/ui/views/tabs/alert_indicator_button.cc b/chrome/browser/ui/views/tabs/alert_indicator_button.cc
index 25262f5..85672a1 100644
--- a/chrome/browser/ui/views/tabs/alert_indicator_button.cc
+++ b/chrome/browser/ui/views/tabs/alert_indicator_button.cc
@@ -13,6 +13,7 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/layout_constants.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_slot_controller.h"
 #include "chrome/common/chrome_features.h"
@@ -90,28 +91,28 @@
 }
 
 ui::ImageModel GetTabAlertIndicatorImageForPressedState(
-    TabAlertState alert_state,
+    tabs::TabAlert alert_state,
     ui::ColorId button_color) {
   switch (alert_state) {
-    case TabAlertState::AUDIO_PLAYING:
+    case tabs::TabAlert::AUDIO_PLAYING:
       return AlertIndicatorButton::GetTabAlertIndicatorImage(
-          TabAlertState::AUDIO_MUTING, button_color);
-    case TabAlertState::AUDIO_MUTING:
+          tabs::TabAlert::AUDIO_MUTING, button_color);
+    case tabs::TabAlert::AUDIO_MUTING:
       return AlertIndicatorButton::GetTabAlertIndicatorImage(
-          TabAlertState::AUDIO_PLAYING, button_color);
-    case TabAlertState::MEDIA_RECORDING:
-    case TabAlertState::AUDIO_RECORDING:
-    case TabAlertState::VIDEO_RECORDING:
-    case TabAlertState::TAB_CAPTURING:
-    case TabAlertState::BLUETOOTH_CONNECTED:
-    case TabAlertState::USB_CONNECTED:
-    case TabAlertState::PIP_PLAYING:
-    case TabAlertState::DESKTOP_CAPTURING:
-    case TabAlertState::BLUETOOTH_SCAN_ACTIVE:
-    case TabAlertState::HID_CONNECTED:
-    case TabAlertState::SERIAL_CONNECTED:
-    case TabAlertState::VR_PRESENTING_IN_HEADSET:
-    case TabAlertState::GLIC_ACCESSING:
+          tabs::TabAlert::AUDIO_PLAYING, button_color);
+    case tabs::TabAlert::MEDIA_RECORDING:
+    case tabs::TabAlert::AUDIO_RECORDING:
+    case tabs::TabAlert::VIDEO_RECORDING:
+    case tabs::TabAlert::TAB_CAPTURING:
+    case tabs::TabAlert::BLUETOOTH_CONNECTED:
+    case tabs::TabAlert::USB_CONNECTED:
+    case tabs::TabAlert::PIP_PLAYING:
+    case tabs::TabAlert::DESKTOP_CAPTURING:
+    case tabs::TabAlert::BLUETOOTH_SCAN_ACTIVE:
+    case tabs::TabAlert::HID_CONNECTED:
+    case tabs::TabAlert::SERIAL_CONNECTED:
+    case tabs::TabAlert::VR_PRESENTING_IN_HEADSET:
+    case tabs::TabAlert::GLIC_ACCESSING:
       return AlertIndicatorButton::GetTabAlertIndicatorImage(alert_state,
                                                              button_color);
   }
@@ -162,22 +163,22 @@
 AlertIndicatorButton::~AlertIndicatorButton() = default;
 
 void AlertIndicatorButton::TransitionToAlertState(
-    std::optional<TabAlertState> next_state) {
+    std::optional<tabs::TabAlert> next_state) {
   if (next_state == alert_state_) {
     return;
   }
 
-  std::optional<TabAlertState> previous_alert_showing_state =
+  std::optional<tabs::TabAlert> previous_alert_showing_state =
       showing_alert_state_;
 
   if (next_state) {
     UpdateIconForAlertState(next_state.value());
   }
 
-  if ((alert_state_ == TabAlertState::AUDIO_PLAYING &&
-       next_state == TabAlertState::AUDIO_MUTING) ||
-      (alert_state_ == TabAlertState::AUDIO_MUTING &&
-       next_state == TabAlertState::AUDIO_PLAYING)) {
+  if ((alert_state_ == tabs::TabAlert::AUDIO_PLAYING &&
+       next_state == tabs::TabAlert::AUDIO_MUTING) ||
+      (alert_state_ == tabs::TabAlert::AUDIO_MUTING &&
+       next_state == tabs::TabAlert::AUDIO_PLAYING)) {
     // Instant user feedback: No fade animation.
     showing_alert_state_ = next_state;
     fade_animation_.reset();
@@ -208,8 +209,8 @@
   const bool was_enabled = GetEnabled();
 
   bool enable = base::FeatureList::IsEnabled(media::kEnableTabMuting) &&
-                (alert_state_ == TabAlertState::AUDIO_PLAYING ||
-                 alert_state_ == TabAlertState::AUDIO_MUTING);
+                (alert_state_ == tabs::TabAlert::AUDIO_PLAYING ||
+                 alert_state_ == tabs::TabAlert::AUDIO_MUTING);
 
   // If the tab is not the currently-active tab, make sure it is wide enough
   // before enabling click-to-mute.  This ensures that there is enough click
@@ -229,8 +230,8 @@
 }
 
 void AlertIndicatorButton::OnParentTabButtonColorChanged() {
-  if (alert_state_ == TabAlertState::AUDIO_PLAYING ||
-      alert_state_ == TabAlertState::AUDIO_MUTING) {
+  if (alert_state_ == tabs::TabAlert::AUDIO_PLAYING ||
+      alert_state_ == tabs::TabAlert::AUDIO_MUTING) {
     UpdateIconForAlertState(alert_state_.value());
   }
 }
@@ -268,13 +269,13 @@
   // instant feedback.  In the very unlikely event that the mute toggle fails,
   // TransitionToAlertState() will be called again, via another code path, to
   // set the image to be consistent with the final outcome.
-  if (alert_state_ == TabAlertState::AUDIO_PLAYING) {
+  if (alert_state_ == tabs::TabAlert::AUDIO_PLAYING) {
     base::RecordAction(base::UserMetricsAction("AlertIndicatorButton_Mute"));
-    TransitionToAlertState(TabAlertState::AUDIO_MUTING);
+    TransitionToAlertState(tabs::TabAlert::AUDIO_MUTING);
   } else {
-    DCHECK(alert_state_ == TabAlertState::AUDIO_MUTING);
+    DCHECK(alert_state_ == tabs::TabAlert::AUDIO_MUTING);
     base::RecordAction(base::UserMetricsAction("AlertIndicatorButton_Unmute"));
-    TransitionToAlertState(TabAlertState::AUDIO_PLAYING);
+    TransitionToAlertState(tabs::TabAlert::AUDIO_PLAYING);
   }
 
   GetTab()->controller()->ToggleTabAudioMute(GetTab());
@@ -325,15 +326,15 @@
 
 std::unique_ptr<gfx::Animation>
 AlertIndicatorButton::CreateTabAlertIndicatorFadeAnimation(
-    std::optional<TabAlertState> alert_state) {
-  if (alert_state == TabAlertState::MEDIA_RECORDING ||
-      alert_state == TabAlertState::AUDIO_RECORDING ||
-      alert_state == TabAlertState::VIDEO_RECORDING ||
-      alert_state == TabAlertState::TAB_CAPTURING ||
-      alert_state == TabAlertState::DESKTOP_CAPTURING) {
-    if ((alert_state == TabAlertState::MEDIA_RECORDING ||
-         alert_state == TabAlertState::AUDIO_RECORDING ||
-         alert_state == TabAlertState::VIDEO_RECORDING) &&
+    std::optional<tabs::TabAlert> alert_state) {
+  if (alert_state == tabs::TabAlert::MEDIA_RECORDING ||
+      alert_state == tabs::TabAlert::AUDIO_RECORDING ||
+      alert_state == tabs::TabAlert::VIDEO_RECORDING ||
+      alert_state == tabs::TabAlert::TAB_CAPTURING ||
+      alert_state == tabs::TabAlert::DESKTOP_CAPTURING) {
+    if ((alert_state == tabs::TabAlert::MEDIA_RECORDING ||
+         alert_state == tabs::TabAlert::AUDIO_RECORDING ||
+         alert_state == tabs::TabAlert::VIDEO_RECORDING) &&
         camera_mic_indicator_start_time_ == base::Time()) {
       camera_mic_indicator_start_time_ = base::Time::Now();
     }
@@ -380,53 +381,53 @@
 // Returns a cached image, to be shown by the alert indicator for the given
 // `alert_state`.  Uses the global ui::ResourceBundle shared instance.
 ui::ImageModel AlertIndicatorButton::GetTabAlertIndicatorImage(
-    TabAlertState alert_state,
+    tabs::TabAlert alert_state,
     ui::ColorId button_color) {
   const gfx::VectorIcon* icon = nullptr;
   int image_width = GetLayoutConstant(TAB_ALERT_INDICATOR_ICON_WIDTH);
   switch (alert_state) {
-    case TabAlertState::AUDIO_PLAYING:
+    case tabs::TabAlert::AUDIO_PLAYING:
       icon = &vector_icons::kVolumeUpChromeRefreshIcon;
       break;
-    case TabAlertState::AUDIO_MUTING:
+    case tabs::TabAlert::AUDIO_MUTING:
       icon = &vector_icons::kVolumeOffChromeRefreshIcon;
       break;
-    case TabAlertState::MEDIA_RECORDING:
-    case TabAlertState::AUDIO_RECORDING:
-    case TabAlertState::VIDEO_RECORDING:
-    case TabAlertState::DESKTOP_CAPTURING:
+    case tabs::TabAlert::MEDIA_RECORDING:
+    case tabs::TabAlert::AUDIO_RECORDING:
+    case tabs::TabAlert::VIDEO_RECORDING:
+    case tabs::TabAlert::DESKTOP_CAPTURING:
       icon = &vector_icons::kRadioButtonCheckedIcon;
       break;
-    case TabAlertState::TAB_CAPTURING:
+    case tabs::TabAlert::TAB_CAPTURING:
       icon = &vector_icons::kCaptureIcon;
 
       // Tab capturing and presenting icon uses a different width compared to
       // the other tab alert indicator icons.
       image_width = GetLayoutConstant(TAB_ALERT_INDICATOR_CAPTURE_ICON_WIDTH);
       break;
-    case TabAlertState::BLUETOOTH_CONNECTED:
+    case tabs::TabAlert::BLUETOOTH_CONNECTED:
       icon = &vector_icons::kBluetoothConnectedIcon;
       break;
-    case TabAlertState::BLUETOOTH_SCAN_ACTIVE:
+    case tabs::TabAlert::BLUETOOTH_SCAN_ACTIVE:
       icon = &vector_icons::kBluetoothScanningChromeRefreshIcon;
       break;
-    case TabAlertState::USB_CONNECTED:
+    case tabs::TabAlert::USB_CONNECTED:
       icon = &vector_icons::kUsbChromeRefreshIcon;
       icon = &kTabUsbConnectedIcon;
       break;
-    case TabAlertState::HID_CONNECTED:
+    case tabs::TabAlert::HID_CONNECTED:
       icon = &vector_icons::kVideogameAssetChromeRefreshIcon;
       break;
-    case TabAlertState::SERIAL_CONNECTED:
+    case tabs::TabAlert::SERIAL_CONNECTED:
       icon = &vector_icons::kSerialPortChromeRefreshIcon;
       break;
-    case TabAlertState::PIP_PLAYING:
+    case tabs::TabAlert::PIP_PLAYING:
       icon = &vector_icons::kPictureInPictureAltIcon;
       break;
-    case TabAlertState::VR_PRESENTING_IN_HEADSET:
+    case tabs::TabAlert::VR_PRESENTING_IN_HEADSET:
       icon = &vector_icons::kCardboardIcon;
       break;
-    case TabAlertState::GLIC_ACCESSING:
+    case tabs::TabAlert::GLIC_ACCESSING:
 #if BUILDFLAG(ENABLE_GLIC)
       icon =
           &glic::GlicVectorIconManager::GetVectorIcon(IDR_GLIC_ACCESSING_ICON);
@@ -440,34 +441,34 @@
 }
 
 ui::ImageModel AlertIndicatorButton::GetTabAlertIndicatorImageForHoverCard(
-    TabAlertState alert_state) {
+    tabs::TabAlert alert_state) {
   switch (alert_state) {
-    case TabAlertState::MEDIA_RECORDING:
-    case TabAlertState::AUDIO_RECORDING:
-    case TabAlertState::VIDEO_RECORDING:
-    case TabAlertState::DESKTOP_CAPTURING:
+    case tabs::TabAlert::MEDIA_RECORDING:
+    case tabs::TabAlert::AUDIO_RECORDING:
+    case tabs::TabAlert::VIDEO_RECORDING:
+    case tabs::TabAlert::DESKTOP_CAPTURING:
       return AlertIndicatorButton::GetTabAlertIndicatorImage(
           alert_state, kColorHoverCardTabAlertMediaRecordingIcon);
-    case TabAlertState::TAB_CAPTURING:
-    case TabAlertState::PIP_PLAYING:
-    case TabAlertState::GLIC_ACCESSING:
+    case tabs::TabAlert::TAB_CAPTURING:
+    case tabs::TabAlert::PIP_PLAYING:
+    case tabs::TabAlert::GLIC_ACCESSING:
       return AlertIndicatorButton::GetTabAlertIndicatorImage(
           alert_state, kColorHoverCardTabAlertPipPlayingIcon);
-    case TabAlertState::AUDIO_PLAYING:
-    case TabAlertState::AUDIO_MUTING:
-    case TabAlertState::BLUETOOTH_CONNECTED:
-    case TabAlertState::BLUETOOTH_SCAN_ACTIVE:
-    case TabAlertState::USB_CONNECTED:
-    case TabAlertState::HID_CONNECTED:
-    case TabAlertState::SERIAL_CONNECTED:
-    case TabAlertState::VR_PRESENTING_IN_HEADSET:
+    case tabs::TabAlert::AUDIO_PLAYING:
+    case tabs::TabAlert::AUDIO_MUTING:
+    case tabs::TabAlert::BLUETOOTH_CONNECTED:
+    case tabs::TabAlert::BLUETOOTH_SCAN_ACTIVE:
+    case tabs::TabAlert::USB_CONNECTED:
+    case tabs::TabAlert::HID_CONNECTED:
+    case tabs::TabAlert::SERIAL_CONNECTED:
+    case tabs::TabAlert::VR_PRESENTING_IN_HEADSET:
       return AlertIndicatorButton::GetTabAlertIndicatorImage(
           alert_state, kColorHoverCardTabAlertAudioPlayingIcon);
   }
   NOTREACHED();
 }
 
-void AlertIndicatorButton::UpdateIconForAlertState(TabAlertState state) {
+void AlertIndicatorButton::UpdateIconForAlertState(tabs::TabAlert state) {
   const ui::ColorId color = parent_tab_->GetAlertIndicatorColor(state);
   const ui::ImageModel indicator_image =
       GetTabAlertIndicatorImage(state, color);
diff --git a/chrome/browser/ui/views/tabs/alert_indicator_button.h b/chrome/browser/ui/views/tabs/alert_indicator_button.h
index 141497c..c7d7e313 100644
--- a/chrome/browser/ui/views/tabs/alert_indicator_button.h
+++ b/chrome/browser/ui/views/tabs/alert_indicator_button.h
@@ -23,6 +23,10 @@
 class AnimationDelegate;
 }  // namespace gfx
 
+namespace tabs {
+enum class TabAlert;
+}  // namespace tabs
+
 // This is an ImageButton subclass that serves as both the alert indicator icon
 // (audio, tab capture, etc.), and as a mute button.  It is meant to only be
 // used as a child view of Tab.
@@ -41,26 +45,26 @@
   AlertIndicatorButton& operator=(const AlertIndicatorButton&) = delete;
   ~AlertIndicatorButton() override;
 
-  static ui::ImageModel GetTabAlertIndicatorImage(TabAlertState alert_state,
+  static ui::ImageModel GetTabAlertIndicatorImage(tabs::TabAlert alert_state,
                                                   ui::ColorId button_color);
 
   static ui::ImageModel GetTabAlertIndicatorImageForHoverCard(
-      TabAlertState alert_state);
+      tabs::TabAlert alert_state);
 
-  // Returns the current TabAlertState except, while the indicator image is
-  // fading out, returns the prior TabAlertState.
-  std::optional<TabAlertState> showing_alert_state() const {
+  // Returns the current TabAlert except, while the indicator image is
+  // fading out, returns the prior TabAlert.
+  std::optional<tabs::TabAlert> showing_alert_state() const {
     return showing_alert_state_;
   }
 
   // Calls ResetImages(), starts fade animations, and activates/deactivates
   // button functionality as appropriate.
-  void TransitionToAlertState(std::optional<TabAlertState> next_state);
+  void TransitionToAlertState(std::optional<tabs::TabAlert> next_state);
 
   // Determines whether the AlertIndicatorButton will be clickable for toggling
   // muting.  This should be called whenever the active/inactive state of a tab
   // has changed.  Internally, TransitionToAlertState() and OnBoundsChanged()
-  // calls this when the TabAlertState or the bounds have changed.
+  // calls this when the TabAlert or the bounds have changed.
   void UpdateEnabledForMuteToggle();
 
   // Called when the parent tab's button color changes.  Determines whether
@@ -97,24 +101,24 @@
   // indicator to alert the user that recording, tab capture, or audio playback
   // has started/stopped.
   std::unique_ptr<gfx::Animation> CreateTabAlertIndicatorFadeAnimation(
-      std::optional<TabAlertState> alert_state);
+      std::optional<tabs::TabAlert> alert_state);
 
   // Returns the tab (parent view) of this AlertIndicatorButton.
   Tab* GetTab();
 
   // Resets the images to display on the button to reflect `state` and the
   // parent tab's button color.  Should be called when either of these changes.
-  void UpdateIconForAlertState(TabAlertState state);
+  void UpdateIconForAlertState(tabs::TabAlert state);
 
   const raw_ptr<Tab> parent_tab_;
 
-  std::optional<TabAlertState> alert_state_;
+  std::optional<tabs::TabAlert> alert_state_;
 
   // Alert indicator fade-in/out animation (i.e., only on show/hide, not a
   // continuous animation).
   std::unique_ptr<gfx::AnimationDelegate> fade_animation_delegate_;
   std::unique_ptr<gfx::Animation> fade_animation_;
-  std::optional<TabAlertState> showing_alert_state_;
+  std::optional<tabs::TabAlert> showing_alert_state_;
 
   // The time when the alert indicator is displayed when a camera and/or a
   // microphone are captured.
diff --git a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
index 8fd4d8e..8e267520 100644
--- a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.cc
@@ -1169,7 +1169,7 @@
     TabDragContext* attached_context,
     std::unique_ptr<TabDragController> controller,
     std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
-                             std::unique_ptr<DetachedTabGroup>>>
+                             std::unique_ptr<DetachedTabCollection>>>
         owned_tabs_and_groups) {
   // We should already have detached by the time we get here.
   CHECK(!attached_context_);
@@ -1227,7 +1227,7 @@
       index++;
     } else {
       auto group = std::move(
-          *std::get_if<std::unique_ptr<DetachedTabGroup>>(&tab_or_group));
+          *std::get_if<std::unique_ptr<DetachedTabCollection>>(&tab_or_group));
       // If it's a group - we add it to the tabstrip. This will add all the
       // tabs.
       const gfx::Range group_indices =
@@ -1279,7 +1279,7 @@
 
 std::tuple<std::unique_ptr<TabDragController>,
            std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
-                                    std::unique_ptr<DetachedTabGroup>>>>
+                                    std::unique_ptr<DetachedTabCollection>>>>
 TabDragController::Detach(ReleaseCapture release_capture) {
   TRACE_EVENT1("views", "TabDragController::Detach", "release_capture",
                release_capture);
@@ -1326,7 +1326,7 @@
       attached_model->GetGroupsDestroyedFromRemovingIndices(dragged_indices);
 
   std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
-                           std::unique_ptr<DetachedTabGroup>>>
+                           std::unique_ptr<DetachedTabCollection>>>
       owned_tabs_and_groups;
   for (TabDragData& tab_drag_datum : drag_data_.tab_drag_data_) {
     const int index =
diff --git a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h
index 388524da..d7b8af8 100644
--- a/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h
+++ b/chrome/browser/ui/views/tabs/dragging/tab_drag_controller.h
@@ -59,7 +59,7 @@
 class TabStripScrollSession;
 class WindowFinder;
 class TabStripScrollSession;
-struct DetachedTabGroup;
+struct DetachedTabCollection;
 
 // TabDragController is responsible for managing the tab dragging session. When
 // the user presses the mouse on a tab a new TabDragController is created and
@@ -352,7 +352,7 @@
       TabDragContext* attached_context,
       std::unique_ptr<TabDragController> controller,
       std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
-                               std::unique_ptr<DetachedTabGroup>>>
+                               std::unique_ptr<DetachedTabCollection>>>
           owned_tabs_and_groups);
 
   // Sets up dragging in `attached_context_`. The dragged tabs must already
@@ -365,7 +365,7 @@
   // nullptr.
   std::tuple<std::unique_ptr<TabDragController>,
              std::vector<std::variant<std::unique_ptr<tabs::TabModel>,
-                                      std::unique_ptr<DetachedTabGroup>>>>
+                                      std::unique_ptr<DetachedTabCollection>>>>
   Detach(ReleaseCapture release_capture);
 
   // Detach from `attached_context_` and attach to `target_context` instead.
diff --git a/chrome/browser/ui/views/tabs/fade_footer_view.cc b/chrome/browser/ui/views/tabs/fade_footer_view.cc
index 1e9c2de..913a7c2 100644
--- a/chrome/browser/ui/views/tabs/fade_footer_view.cc
+++ b/chrome/browser/ui/views/tabs/fade_footer_view.cc
@@ -8,6 +8,7 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/layout_constants.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/views/tabs/alert_indicator_button.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -124,7 +125,7 @@
 // -----------------------------------------------------------------------
 
 void FadeAlertFooterRow::SetData(const AlertFooterRowData& data) {
-  std::optional<TabAlertState> alert_state = data.alert_state;
+  std::optional<tabs::TabAlert> alert_state = data.alert_state;
   if (data.should_show_discard_status) {
     std::u16string row_text;
     if (data.memory_savings_in_bytes > 0) {
diff --git a/chrome/browser/ui/views/tabs/fade_footer_view.h b/chrome/browser/ui/views/tabs/fade_footer_view.h
index 2df0381..696a7ca 100644
--- a/chrome/browser/ui/views/tabs/fade_footer_view.h
+++ b/chrome/browser/ui/views/tabs/fade_footer_view.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/views/tabs/fade_view.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/gfx/geometry/size.h"
@@ -15,8 +14,12 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/flex_layout.h"
 
+namespace tabs {
+enum class TabAlert;
+}  // namespace tabs
+
 struct AlertFooterRowData {
-  std::optional<TabAlertState> alert_state;
+  std::optional<tabs::TabAlert> alert_state;
   bool should_show_discard_status = false;
   int64_t memory_savings_in_bytes = 0;
 };
diff --git a/chrome/browser/ui/views/tabs/glic_button_browsertest.cc b/chrome/browser/ui/views/tabs/glic_button_browsertest.cc
index 903b6083..f78440b 100644
--- a/chrome/browser/ui/views/tabs/glic_button_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/glic_button_browsertest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/glic/test_support/glic_test_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/tab_strip_region_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_action_container.h"
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 8867580..c34a8256 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -31,6 +31,7 @@
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_tab_data.h"
 #include "chrome/browser/ui/tabs/tab_style.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
@@ -846,7 +847,7 @@
       controller_->GetGroupColorId(group().value()));
 }
 
-ui::ColorId Tab::GetAlertIndicatorColor(TabAlertState state) const {
+ui::ColorId Tab::GetAlertIndicatorColor(tabs::TabAlert state) const {
   const ui::ColorProvider* color_provider = GetColorProvider();
   if (!color_provider) {
     return gfx::kPlaceholderColor;
@@ -854,25 +855,25 @@
 
   int group;
   switch (state) {
-    case TabAlertState::MEDIA_RECORDING:
-    case TabAlertState::AUDIO_RECORDING:
-    case TabAlertState::VIDEO_RECORDING:
-    case TabAlertState::DESKTOP_CAPTURING:
+    case tabs::TabAlert::MEDIA_RECORDING:
+    case tabs::TabAlert::AUDIO_RECORDING:
+    case tabs::TabAlert::VIDEO_RECORDING:
+    case tabs::TabAlert::DESKTOP_CAPTURING:
       group = 0;
       break;
-    case TabAlertState::TAB_CAPTURING:
-    case TabAlertState::PIP_PLAYING:
-    case TabAlertState::GLIC_ACCESSING:
+    case tabs::TabAlert::TAB_CAPTURING:
+    case tabs::TabAlert::PIP_PLAYING:
+    case tabs::TabAlert::GLIC_ACCESSING:
       group = 1;
       break;
-    case TabAlertState::AUDIO_PLAYING:
-    case TabAlertState::AUDIO_MUTING:
-    case TabAlertState::BLUETOOTH_CONNECTED:
-    case TabAlertState::BLUETOOTH_SCAN_ACTIVE:
-    case TabAlertState::USB_CONNECTED:
-    case TabAlertState::HID_CONNECTED:
-    case TabAlertState::SERIAL_CONNECTED:
-    case TabAlertState::VR_PRESENTING_IN_HEADSET:
+    case tabs::TabAlert::AUDIO_PLAYING:
+    case tabs::TabAlert::AUDIO_MUTING:
+    case tabs::TabAlert::BLUETOOTH_CONNECTED:
+    case tabs::TabAlert::BLUETOOTH_SCAN_ACTIVE:
+    case tabs::TabAlert::USB_CONNECTED:
+    case tabs::TabAlert::HID_CONNECTED:
+    case tabs::TabAlert::SERIAL_CONNECTED:
+    case tabs::TabAlert::VR_PRESENTING_IN_HEADSET:
       group = 2;
       break;
   }
@@ -1055,7 +1056,7 @@
 
 // static
 std::u16string Tab::GetTooltipText(const std::u16string& title,
-                                   std::optional<TabAlertState> alert_state) {
+                                   std::optional<tabs::TabAlert> alert_state) {
   if (!alert_state) {
     return title;
   }
@@ -1069,8 +1070,8 @@
 }
 
 // static
-std::optional<TabAlertState> Tab::GetAlertStateToShow(
-    const std::vector<TabAlertState>& alert_states) {
+std::optional<tabs::TabAlert> Tab::GetAlertStateToShow(
+    const std::vector<tabs::TabAlert>& alert_states) {
   if (alert_states.empty()) {
     return std::nullopt;
   }
@@ -1264,7 +1265,7 @@
   if (!alert_indicator_button_ || !alert_indicator_button_->GetVisible()) {
     base::RecordAction(UserMetricsAction("CloseTab_NoAlertIndicator"));
   } else if (GetAlertStateToShow(data_.alert_state) ==
-             TabAlertState::AUDIO_PLAYING) {
+             tabs::TabAlert::AUDIO_PLAYING) {
     base::RecordAction(UserMetricsAction("CloseTab_AudioIndicator"));
   } else {
     base::RecordAction(UserMetricsAction("CloseTab_RecordingIndicator"));
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 6894d79..13e379a 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -43,6 +43,10 @@
 class View;
 }  // namespace views
 
+namespace tabs {
+enum class TabAlert;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //
 //  A View that renders a Tab in a TabStrip.
@@ -116,7 +120,7 @@
   std::optional<SkColor> GetGroupColor() const;
 
   // Returns the color used for the alert indicator icon.
-  ui::ColorId GetAlertIndicatorColor(TabAlertState state) const;
+  ui::ColorId GetAlertIndicatorColor(tabs::TabAlert state) const;
 
   // Returns true if this tab is the active tab.
   bool IsActive() const;
@@ -179,11 +183,11 @@
   // Exposed publicly for tests.
   static std::u16string GetTooltipText(
       const std::u16string& title,
-      std::optional<TabAlertState> alert_state);
+      std::optional<tabs::TabAlert> alert_state);
 
   // Returns an alert state to be shown among given alert states.
-  static std::optional<TabAlertState> GetAlertStateToShow(
-      const std::vector<TabAlertState>& alert_states);
+  static std::optional<tabs::TabAlert> GetAlertStateToShow(
+      const std::vector<tabs::TabAlert>& alert_states);
 
   bool showing_close_button_for_testing() const {
     return showing_close_button_;
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
index 19a3d6c2..2926468 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
@@ -31,6 +31,10 @@
 class ImageSkia;
 }
 
+namespace tabs {
+enum class TabAlert;
+}
+
 class Tab;
 class TabStyle;
 class FadeLabelView;
@@ -104,7 +108,7 @@
   raw_ptr<FadeLabelView> domain_label_ = nullptr;
   raw_ptr<ThumbnailView> thumbnail_view_ = nullptr;
   raw_ptr<FooterView> footer_view_ = nullptr;
-  std::optional<TabAlertState> alert_state_;
+  std::optional<tabs::TabAlert> alert_state_;
   const raw_ptr<const TabStyle> tab_style_;
 
   const InitParams bubble_params_;
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_hover_card_controller_interactive_uitest.cc
index d9b3a563..f704389d 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_controller_interactive_uitest.cc
@@ -19,8 +19,8 @@
 #include "chrome/browser/ui/performance_controls/tab_resource_usage_tab_helper.h"
 #include "chrome/browser/ui/performance_controls/test_support/memory_metrics_refresh_waiter.h"
 #include "chrome/browser/ui/performance_controls/test_support/memory_saver_interactive_test_mixin.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_tab_data.h"
-#include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/test/tab_strip_interactive_test_mixin.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/tabs/fade_footer_view.h"
@@ -82,7 +82,7 @@
   TabRendererData new_tab_data = TabRendererData();
   new_tab_data.title = kTabTitle;
   new_tab_data.last_committed_url = GURL(kTabUrl);
-  new_tab_data.alert_state = {TabAlertState::AUDIO_PLAYING};
+  new_tab_data.alert_state = {tabs::TabAlert::AUDIO_PLAYING};
   return new_tab_data;
 }
 
@@ -747,7 +747,7 @@
   browser()->tab_strip_model()->ActivateTabAt(0);
   Tab* const tab = tab_strip->tab_at(1);
   TabRendererData data = tab->data();
-  data.alert_state = {TabAlertState::AUDIO_PLAYING};
+  data.alert_state = {tabs::TabAlert::AUDIO_PLAYING};
   tab->SetData(data);
   tab_strip->GetFocusManager()->SetFocusedView(tab);
   WaitForHoverCardVisible(tab_strip);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 0d8bfbe..713beef 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -48,6 +48,7 @@
 #include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/layout_constants.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/features.h"
 #include "chrome/browser/ui/tabs/tab_group_theme.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -1107,7 +1108,7 @@
   return tab_at(tab_index)->data().network_state == TabNetworkState::kError;
 }
 
-std::optional<TabAlertState> TabStrip::GetTabAlertState(int tab_index) const {
+std::optional<tabs::TabAlert> TabStrip::GetTabAlertState(int tab_index) const {
   return Tab::GetAlertStateToShow(tab_at(tab_index)->data().alert_state);
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index b3249f63..eddce1f 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -16,7 +16,6 @@
 #include "base/memory/raw_ref.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_types.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/views/frame/browser_root_view.h"
@@ -58,6 +57,10 @@
 class ListSelectionModel;
 }
 
+namespace tabs {
+enum class TabAlert;
+}  // namespace tabs
+
 // A View that represents the TabStripModel. The TabStrip has the
 // following responsibilities:
 //
@@ -120,7 +123,7 @@
   // Returns information about tabs at given indices.
   bool IsTabCrashed(int tab_index) const;
   bool TabHasNetworkError(int tab_index) const;
-  std::optional<TabAlertState> GetTabAlertState(int tab_index) const;
+  std::optional<tabs::TabAlert> GetTabAlertState(int tab_index) const;
 
   // Updates the loading animations displayed by tabs in the tabstrip to the
   // next frame. The `elapsed_time` parameter is shared between tabs and used to
diff --git a/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc
index 1657940..a88558b 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_action_container_unittest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h"
 #include "chrome/browser/ui/tabs/test/mock_tab_interface.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/commerce/product_specifications_button.h"
 #include "chrome/browser/ui/views/frame/tab_strip_region_view.h"
 #include "chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h"
diff --git a/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc b/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
index 794fbc86..58dcc8a7a 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_browsertest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/browser_command_controller.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/performance_controls/tab_resource_usage_tab_helper.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_utils.h"
 #include "chrome/browser/ui/tabs/tab_group.h"
 #include "chrome/browser/ui/tabs/tab_group_model.h"
@@ -130,7 +131,7 @@
 
   tab_groups::TabGroupId group = tab_strip_model()->AddToNewGroup({0, 1});
 
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       tab_strip_model()->DetachTabGroupForInsertion(group);
 
   EXPECT_EQ(tab_strip()->GetTabCount(), 1);
@@ -1000,7 +1001,7 @@
   // AccessibleName update with alert on tab
   tab_renderer_data = tab_strip()->tab_at(new_index)->data();
   tab_renderer_data.network_state = TabNetworkState::kLoading;
-  tab_renderer_data.alert_state.push_back(TabAlertState::AUDIO_PLAYING);
+  tab_renderer_data.alert_state.push_back(tabs::TabAlert::AUDIO_PLAYING);
   tab_strip()->tab_at(new_index)->SetData(tab_renderer_data);
   data = ui::AXNodeData();
   tab_strip()->tab_at(new_index)->GetViewAccessibility().GetAccessibleNodeData(
diff --git a/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc b/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc
index 2f219a6..27fba58 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_combo_button.cc
@@ -9,10 +9,10 @@
 #include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/browser/ui/layout_constants.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/tabs/tab_search_button.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_control_button.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/vector_icons/vector_icons.h"
diff --git a/chrome/browser/ui/views/tabs/tab_strip_combo_button_browsertest.cc b/chrome/browser/ui/views/tabs/tab_strip_combo_button_browsertest.cc
index b3b4718..66329cf8 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_combo_button_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_combo_button_browsertest.cc
@@ -6,10 +6,10 @@
 
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/tab_strip_region_view.h"
 #include "chrome/browser/ui/views/tabs/tab_search_button.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/browser_test.h"
 
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc
index 3e2e0f0a..b8a53a0 100644
--- a/chrome/browser/ui/views/tabs/tab_style_views.cc
+++ b/chrome/browser/ui/views/tabs/tab_style_views.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tabs/tab_style.h"
 #include "chrome/browser/ui/tabs/tab_types.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/top_container_background.h"
@@ -27,7 +28,6 @@
 #include "chrome/browser/ui/views/tabs/tab_group_underline.h"
 #include "chrome/browser/ui/views/tabs/tab_slot_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_slot_view.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/tab_groups/tab_group_visual_data.h"
 #include "third_party/skia/include/core/SkRRect.h"
@@ -45,14 +45,6 @@
 
 namespace {
 
-Tab* GetLeftTab(const Tab* tab) {
-  return tab->controller()->GetAdjacentTab(tab, base::i18n::IsRTL() ? 1 : -1);
-}
-
-Tab* GetRightTab(const Tab* tab) {
-  return tab->controller()->GetAdjacentTab(tab, base::i18n::IsRTL() ? -1 : 1);
-}
-
 // Updates a target value, returning true if it changed.
 template <class T>
 bool UpdateValue(T* dest, const T& src) {
@@ -290,17 +282,13 @@
       const int right_separator_overlap =
           tab_style()->GetSeparatorSize().width() - left_separator_overlap;
 
-      // If there is a tab before this one, then expand into its overlap.
-      const Tab* const previous_tab = GetLeftTab(tab());
-      if (expand_into_previous_separator && previous_tab) {
+      if (expand_into_previous_separator) {
         left -= (tab_style()->GetSeparatorMargins().right() +
                  left_separator_overlap) *
                 scale;
       }
 
-      // If there is a tab after this one, then expand into its overlap.
-      const Tab* const next_tab = GetRightTab(tab());
-      if (expand_into_next_separator && next_tab) {
+      if (expand_into_next_separator) {
         right += (tab_style()->GetSeparatorMargins().left() +
                   right_separator_overlap) *
                  scale;
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
index bb8ca23a..461dc720 100644
--- a/chrome/browser/ui/views/tabs/tab_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -14,8 +14,8 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "chrome/browser/ui/layout_constants.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/saved_tab_groups/collaboration_messaging_tab_data.h"
-#include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_style.h"
 #include "chrome/browser/ui/tabs/tab_types.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
@@ -387,12 +387,12 @@
 }
 
 TEST_F(TabTest, LayoutAndVisibilityOfElements) {
-  static const std::optional<TabAlertState> kAlertStatesToTest[] = {
+  static const std::optional<tabs::TabAlert> kAlertStatesToTest[] = {
       std::nullopt,
-      TabAlertState::TAB_CAPTURING,
-      TabAlertState::AUDIO_PLAYING,
-      TabAlertState::AUDIO_MUTING,
-      TabAlertState::PIP_PLAYING,
+      tabs::TabAlert::TAB_CAPTURING,
+      tabs::TabAlert::AUDIO_PLAYING,
+      tabs::TabAlert::AUDIO_MUTING,
+      tabs::TabAlert::PIP_PLAYING,
   };
 
   auto controller = std::make_unique<FakeTabSlotController>();
@@ -410,7 +410,7 @@
   // results.
   for (bool is_pinned_tab : {false, true}) {
     for (bool is_active_tab : {false, true}) {
-      for (std::optional<TabAlertState> alert_state : kAlertStatesToTest) {
+      for (std::optional<tabs::TabAlert> alert_state : kAlertStatesToTest) {
         SCOPED_TRACE(
             ::testing::Message()
             << (is_active_tab ? "Active " : "Inactive ")
@@ -632,7 +632,7 @@
     views::View* icon = GetTabIcon(tab);
     int icon_x = icon->x();
     TabRendererData data;
-    data.alert_state = {TabAlertState::AUDIO_PLAYING};
+    data.alert_state = {tabs::TabAlert::AUDIO_PLAYING};
     tab->SetData(data);
     EXPECT_EQ(icon_x, icon->x());
   }
@@ -681,7 +681,7 @@
   Tab* tab = widget->SetContentsView(std::make_unique<Tab>(controller.get()));
   controller->set_active_tab(tab);
   TabRendererData data;
-  data.alert_state = {TabAlertState::AUDIO_PLAYING};
+  data.alert_state = {tabs::TabAlert::AUDIO_PLAYING};
   tab->SetData(data);
 
   tab->SetBounds(0, 0, 200, 50);
@@ -779,7 +779,7 @@
   EXPECT_FALSE(showing_close_button(media_tab));
 
   TabRendererData start_media;
-  start_media.alert_state = {TabAlertState::AUDIO_PLAYING};
+  start_media.alert_state = {tabs::TabAlert::AUDIO_PLAYING};
   start_media.pinned = media_tab->data().pinned;
   media_tab->SetData(std::move(start_media));
 
@@ -820,7 +820,7 @@
   EXPECT_EQ(base::Time(), get_camera_mic_indicator_start_time(media_tab));
 
   TabRendererData start_media;
-  start_media.alert_state = {TabAlertState::MEDIA_RECORDING};
+  start_media.alert_state = {tabs::TabAlert::MEDIA_RECORDING};
   start_media.pinned = media_tab->data().pinned;
   media_tab->SetData(std::move(start_media));
 
@@ -851,7 +851,7 @@
   EXPECT_EQ(base::Time(), get_camera_mic_indicator_start_time(media_tab));
 
   TabRendererData start_media;
-  start_media.alert_state = {TabAlertState::MEDIA_RECORDING};
+  start_media.alert_state = {tabs::TabAlert::MEDIA_RECORDING};
   start_media.pinned = media_tab->data().pinned;
   media_tab->SetData(std::move(start_media));
 
diff --git a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_browsertest.cc b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_browsertest.cc
index 451f932..990654a 100644
--- a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_browsertest.cc
+++ b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/actions/chrome_action_id.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_ui.h"
 #include "chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h"
 #include "chrome/browser/web_applications/test/os_integration_test_override_impl.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_unittest.cc b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_unittest.cc
index b8eed8a..4c32af79 100644
--- a/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container_unittest.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h"
 #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model_factory.h"
 #include "chrome/browser/ui/toolbar/toolbar_pref_names.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
 #include "chrome/browser/ui/views/toolbar/pinned_action_toolbar_button.h"
@@ -23,7 +24,6 @@
 #include "chrome/browser/ui/views/toolbar/pinned_toolbar_button_status_indicator.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "components/keyed_service/core/keyed_service.h"
diff --git a/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc
index 9b36dcd..980d752 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h"
 #include "chrome/browser/ui/toolbar_controller_util.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h"
@@ -26,7 +27,6 @@
 #include "chrome/browser/ui/views/toolbar/pinned_toolbar_actions_container.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
diff --git a/chrome/browser/ui/webui/connectors_internals/connectors_internals.mojom b/chrome/browser/ui/webui/connectors_internals/connectors_internals.mojom
index 07c7777..9b3878d 100644
--- a/chrome/browser/ui/webui/connectors_internals/connectors_internals.mojom
+++ b/chrome/browser/ui/webui/connectors_internals/connectors_internals.mojom
@@ -17,6 +17,7 @@
   UNSPECIFIED = 0,
   HW = 1,
   OS = 2,
+  OS_SOFTWARE = 3,
 };
 
 // Type of the signing key, equivalent to the algorithm used for its generation.
@@ -64,6 +65,9 @@
   // Result of an attempt to upload the key. May be empty if the
   // key has not yet been uploaded.
   KeyUploadStatus? key_upload_status;
+
+  // Whether the key was correctly converted into an SSL key.
+  bool has_ssl_key;
 };
 
 struct KeyInfo {
diff --git a/chrome/browser/ui/webui/connectors_internals/device_trust_utils.cc b/chrome/browser/ui/webui/connectors_internals/device_trust_utils.cc
index 4f29233..1035eecf 100644
--- a/chrome/browser/ui/webui/connectors_internals/device_trust_utils.cc
+++ b/chrome/browser/ui/webui/connectors_internals/device_trust_utils.cc
@@ -32,6 +32,7 @@
 #include "components/enterprise/client_certificates/core/private_key.h"
 #include "components/enterprise/client_certificates/core/private_key_types.h"
 #include "net/cert/x509_certificate.h"
+#include "net/ssl/ssl_private_key.h"
 #endif  // BUILDFLAG(ENTERPRISE_CLIENT_CERTIFICATES)
 
 namespace enterprise_connectors::utils {
@@ -116,6 +117,8 @@
       return connectors_internals::mojom::KeyTrustLevel::HW;
     case client_certificates::PrivateKeySource::kSoftwareKey:
       return connectors_internals::mojom::KeyTrustLevel::OS;
+    case client_certificates::PrivateKeySource::kOsSoftwareKey:
+      return connectors_internals::mojom::KeyTrustLevel::OS_SOFTWARE;
   }
 }
 
@@ -145,8 +148,8 @@
   return connectors_internals::mojom::LoadedKeyInfo::New(
       ConvertPrivateKeySource(private_key->GetSource()),
       AlgorithmToType(private_key->GetAlgorithm()),
-      HashAndEncodeString(BufferToString(spki_bytes)),
-      std::move(upload_status));
+      HashAndEncodeString(BufferToString(spki_bytes)), std::move(upload_status),
+      bool(private_key->GetSSLPrivateKey()));
 }
 
 connectors_internals::mojom::CertificateMetadataPtr ConvertCertificate(
@@ -190,7 +193,8 @@
                 HashAndEncodeString(metadata->spki_bytes),
                 connectors_internals::mojom::KeyUploadStatus::
                     NewSyncKeyResponseCode(
-                        ToMojomValue(metadata->synchronization_response_code))),
+                        ToMojomValue(metadata->synchronization_response_code)),
+                /*has_ssl_key=*/false),
             ConvertPermanentFailure(metadata->permanent_failure));
       }
 
diff --git a/chrome/browser/ui/webui/settings/appearance_handler_browsertest.cc b/chrome/browser/ui/webui/settings/appearance_handler_browsertest.cc
index 1fe8f376..a61ac10f 100644
--- a/chrome/browser/ui/webui/settings/appearance_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/appearance_handler_browsertest.cc
@@ -10,8 +10,8 @@
 #include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/side_panel/side_panel_ui.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
diff --git a/chrome/browser/ui/webui/settings/glic_handler_browsertest.cc b/chrome/browser/ui/webui/settings/glic_handler_browsertest.cc
index ea64e670..344873a 100644
--- a/chrome/browser/ui/webui/settings/glic_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/glic_handler_browsertest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/background/glic/glic_launcher_configuration.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/glic/glic_pref_names.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/test_browser_window.h"
diff --git a/chrome/browser/ui/webui/settings/safety_hub_handler.cc b/chrome/browser/ui/webui/settings/safety_hub_handler.cc
index b239180..6700ccc 100644
--- a/chrome/browser/ui/webui/settings/safety_hub_handler.cc
+++ b/chrome/browser/ui/webui/settings/safety_hub_handler.cc
@@ -68,6 +68,8 @@
 
 namespace {
 
+const char kRevocationTypeKey[] = "revocation_type";
+
 // Get values from |UnusedSitePermission| object in
 // safety_hub_browser_proxy.ts.
 PermissionsData GetUnusedSitePermissionsFromDict(
@@ -115,6 +117,9 @@
       content_settings::ContentSettingConstraints(expiration - lifetime);
   permissions_data.constraints.set_lifetime(lifetime);
 
+  permissions_data.revocation_type = static_cast<PermissionsRevocationType>(
+      unused_site_permissions.FindInt(kRevocationTypeKey).value_or(0));
+
   return permissions_data;
 }
 
@@ -239,42 +244,13 @@
       RevokedPermissionsServiceFactory::GetForProfile(profile_);
   CHECK(service);
 
+  std::vector<PermissionsData> permissions_data_list;
   for (const auto& unused_site_permissions_js : unused_site_permissions_list) {
     CHECK(unused_site_permissions_js.is_dict());
-    PermissionsData permissions_data =
-        GetUnusedSitePermissionsFromDict(unused_site_permissions_js.GetDict());
-    if (base::FeatureList::IsEnabled(
-            safe_browsing::kSafetyHubAbusiveNotificationRevocation)) {
-      HostContentSettingsMap* map =
-          HostContentSettingsMapFactory::GetForProfile(profile_);
-      // This pattern is origin-scoped, so this conversion is safe.
-      GURL permission_url =
-          permissions_data.primary_pattern.ToRepresentativeUrl();
-      DCHECK(permission_url.is_valid());
-      // If the permission_types includes `NOTIFICATIONS`, then the revocation
-      // is for a site that should have a
-      // `REVOKED_ABUSIVE_NOTIFICATION_PERMISSIONS` setting.
-      if (permissions_data.permission_types.contains(
-              ContentSettingsType::NOTIFICATIONS)) {
-        safety_hub_util::SetRevokedAbusiveNotificationPermission(
-            map, permission_url, /*is_ignored=*/false,
-            permissions_data.constraints);
-        // Remove `NOTIFICATIONS` from permission type list for handling unused
-        // permission revocation below.
-        permissions_data.permission_types.erase(
-            ContentSettingsType::NOTIFICATIONS);
-      }
-
-      // If the permission_types include any permission type that is not
-      // `NOTIFICATIONS`, then the revocation is for an unused site that should
-      // have a `REVOKED_UNUSED_SITE_PERMISSIONS` setting.
-      if (!permissions_data.permission_types.empty()) {
-        service->StorePermissionInRevokedPermissionSetting(permissions_data);
-      }
-    } else {
-      service->StorePermissionInRevokedPermissionSetting(permissions_data);
-    }
+    permissions_data_list.push_back(
+        GetUnusedSitePermissionsFromDict(unused_site_permissions_js.GetDict()));
   }
+  service->RestoreDeletedRevokedPermissionsList(permissions_data_list);
 
   SendUnusedSitePermissionsReviewList();
 }
@@ -325,6 +301,9 @@
         safety_hub::kSafetyHubChooserPermissionsData,
         base::Value(permissions_data.chooser_permissions_data.Clone()));
 
+    revoked_permission_value.Set(
+        kRevocationTypeKey, static_cast<int>(permissions_data.revocation_type));
+
     result.Append(std::move(revoked_permission_value));
   }
 
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
index bbf9fc4..b5e6efa 100644
--- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
+++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_features.h"
 #include "chrome/browser/ui/color/chrome_color_id.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/organization/tab_declutter_controller.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_request.h"
 #include "chrome/browser/ui/tabs/organization/tab_organization_service.h"
@@ -1440,18 +1441,18 @@
           ? custom_last_active_text
           : GetLastActiveElapsedText(last_active_time_ticks);
 
-  std::vector<TabAlertState> alert_states =
+  std::vector<tabs::TabAlert> alert_states =
       GetTabAlertStatesForContents(contents);
   // Currently, we only report media alert states.
   std::ranges::copy_if(alert_states.begin(), alert_states.end(),
                        std::back_inserter(tab_data->alert_states),
-                       [](TabAlertState alert) {
-                         return alert == TabAlertState::MEDIA_RECORDING ||
-                                alert == TabAlertState::AUDIO_RECORDING ||
-                                alert == TabAlertState::VIDEO_RECORDING ||
-                                alert == TabAlertState::AUDIO_PLAYING ||
-                                alert == TabAlertState::AUDIO_MUTING ||
-                                alert == TabAlertState::GLIC_ACCESSING;
+                       [](tabs::TabAlert alert) {
+                         return alert == tabs::TabAlert::MEDIA_RECORDING ||
+                                alert == tabs::TabAlert::AUDIO_RECORDING ||
+                                alert == tabs::TabAlert::VIDEO_RECORDING ||
+                                alert == tabs::TabAlert::AUDIO_PLAYING ||
+                                alert == tabs::TabAlert::AUDIO_MUTING ||
+                                alert == tabs::TabAlert::GLIC_ACCESSING;
                        });
 
   return tab_data;
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
index 2c8b260..2f37aae 100644
--- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
@@ -22,8 +22,8 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
 #include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/tabs/organization/tab_declutter_controller.h"
-#include "chrome/browser/ui/tabs/tab_enums.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/browser/ui/tabs/test_util.h"
@@ -445,7 +445,7 @@
           [&](tab_search::mojom::ProfileDataPtr profile_tabs) {
             auto* window1 = profile_tabs->windows[0].get();
             auto* tab1 = window1->tabs[0].get();
-            EXPECT_EQ(TabAlertState::AUDIO_PLAYING, tab1->alert_states[0]);
+            EXPECT_EQ(tabs::TabAlert::AUDIO_PLAYING, tab1->alert_states[0]);
           });
   handler()->GetProfileData(std::move(callback));
 
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_util.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_util.cc
index a9f1c158..3298a7a 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_util.cc
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_util.cc
@@ -82,7 +82,7 @@
     return;
   }
 
-  std::unique_ptr<DetachedTabGroup> detached_group =
+  std::unique_ptr<DetachedTabCollection> detached_group =
       source_browser->tab_strip_model()->DetachTabGroupForInsertion(group_id);
   target_browser->tab_strip_model()->InsertDetachedTabGroupAt(
       std::move(detached_group), to_index);
diff --git a/chrome/browser/ui/webui/tabs/BUILD.gn b/chrome/browser/ui/webui/tabs/BUILD.gn
index 9c92e28..8d3eb41 100644
--- a/chrome/browser/ui/webui/tabs/BUILD.gn
+++ b/chrome/browser/ui/webui/tabs/BUILD.gn
@@ -14,14 +14,14 @@
       types = [
         {
           mojom = "tabs.mojom.TabAlertState"
-          cpp = "::TabAlertState"
+          cpp = "::tabs::TabAlert"
         },
       ]
-      traits_headers = [ "tabs_mojom_traits.h" ]
-      traits_public_deps = [
-        "//base",
-        "//chrome/browser/ui/tabs:tab_enums",
+      traits_headers = [
+        "tabs_mojom_traits.h",
+        "//chrome/browser/ui/tabs/alert/tab_alert.h",
       ]
+      traits_public_deps = [ "//base" ]
     },
   ]
 }
diff --git a/chrome/browser/ui/webui/tabs/tabs_mojom_traits.h b/chrome/browser/ui/webui/tabs/tabs_mojom_traits.h
index c5e62ab9..8984bcc 100644
--- a/chrome/browser/ui/webui/tabs/tabs_mojom_traits.h
+++ b/chrome/browser/ui/webui/tabs/tabs_mojom_traits.h
@@ -6,78 +6,78 @@
 #define CHROME_BROWSER_UI_WEBUI_TABS_TABS_MOJOM_TRAITS_H_
 
 #include "base/containers/fixed_flat_map.h"
-#include "chrome/browser/ui/tabs/tab_enums.h"
+#include "chrome/browser/ui/tabs/alert/tab_alert.h"
 #include "chrome/browser/ui/webui/tabs/tabs.mojom.h"
 
 namespace mojo {
 
 template <>
-struct EnumTraits<tabs::mojom::TabAlertState, TabAlertState> {
-  static tabs::mojom::TabAlertState ToMojom(TabAlertState input) {
+struct EnumTraits<tabs::mojom::TabAlertState, tabs::TabAlert> {
+  static tabs::mojom::TabAlertState ToMojom(tabs::TabAlert input) {
     static constexpr auto alert_state_map =
-        base::MakeFixedFlatMap<TabAlertState, tabs::mojom::TabAlertState>(
-            {{TabAlertState::MEDIA_RECORDING,
+        base::MakeFixedFlatMap<tabs::TabAlert, tabs::mojom::TabAlertState>(
+            {{tabs::TabAlert::MEDIA_RECORDING,
               tabs::mojom::TabAlertState::kMediaRecording},
-             {TabAlertState::TAB_CAPTURING,
+             {tabs::TabAlert::TAB_CAPTURING,
               tabs::mojom::TabAlertState::kTabCapturing},
-             {TabAlertState::AUDIO_PLAYING,
+             {tabs::TabAlert::AUDIO_PLAYING,
               tabs::mojom::TabAlertState::kAudioPlaying},
-             {TabAlertState::AUDIO_MUTING,
+             {tabs::TabAlert::AUDIO_MUTING,
               tabs::mojom::TabAlertState::kAudioMuting},
-             {TabAlertState::BLUETOOTH_CONNECTED,
+             {tabs::TabAlert::BLUETOOTH_CONNECTED,
               tabs::mojom::TabAlertState::kBluetoothConnected},
-             {TabAlertState::BLUETOOTH_SCAN_ACTIVE,
+             {tabs::TabAlert::BLUETOOTH_SCAN_ACTIVE,
               tabs::mojom::TabAlertState::kBluetoothConnected},
-             {TabAlertState::USB_CONNECTED,
+             {tabs::TabAlert::USB_CONNECTED,
               tabs::mojom::TabAlertState::kUsbConnected},
-             {TabAlertState::HID_CONNECTED,
+             {tabs::TabAlert::HID_CONNECTED,
               tabs::mojom::TabAlertState::kHidConnected},
-             {TabAlertState::SERIAL_CONNECTED,
+             {tabs::TabAlert::SERIAL_CONNECTED,
               tabs::mojom::TabAlertState::kSerialConnected},
-             {TabAlertState::PIP_PLAYING,
+             {tabs::TabAlert::PIP_PLAYING,
               tabs::mojom::TabAlertState::kPipPlaying},
-             {TabAlertState::DESKTOP_CAPTURING,
+             {tabs::TabAlert::DESKTOP_CAPTURING,
               tabs::mojom::TabAlertState::kDesktopCapturing},
-             {TabAlertState::VR_PRESENTING_IN_HEADSET,
+             {tabs::TabAlert::VR_PRESENTING_IN_HEADSET,
               tabs::mojom::TabAlertState::kVrPresentingInHeadset},
-             {TabAlertState::AUDIO_RECORDING,
+             {tabs::TabAlert::AUDIO_RECORDING,
               tabs::mojom::TabAlertState::kAudioRecording},
-             {TabAlertState::VIDEO_RECORDING,
+             {tabs::TabAlert::VIDEO_RECORDING,
               tabs::mojom::TabAlertState::kVideoRecording},
-             {TabAlertState::GLIC_ACCESSING,
+             {tabs::TabAlert::GLIC_ACCESSING,
               tabs::mojom::TabAlertState::kGlicAccessing}});
     return alert_state_map.at(input);
   }
 
-  static bool FromMojom(tabs::mojom::TabAlertState input, TabAlertState* out) {
+  static bool FromMojom(tabs::mojom::TabAlertState input, tabs::TabAlert* out) {
     static constexpr auto alert_state_map =
-        base::MakeFixedFlatMap<tabs::mojom::TabAlertState, TabAlertState>(
+        base::MakeFixedFlatMap<tabs::mojom::TabAlertState, tabs::TabAlert>(
             {{tabs::mojom::TabAlertState::kMediaRecording,
-              TabAlertState::MEDIA_RECORDING},
+              tabs::TabAlert::MEDIA_RECORDING},
              {tabs::mojom::TabAlertState::kTabCapturing,
-              TabAlertState::TAB_CAPTURING},
+              tabs::TabAlert::TAB_CAPTURING},
              {tabs::mojom::TabAlertState::kAudioPlaying,
-              TabAlertState::AUDIO_PLAYING},
+              tabs::TabAlert::AUDIO_PLAYING},
              {tabs::mojom::TabAlertState::kAudioMuting,
-              TabAlertState::AUDIO_MUTING},
+              tabs::TabAlert::AUDIO_MUTING},
              {tabs::mojom::TabAlertState::kBluetoothConnected,
-              TabAlertState::BLUETOOTH_CONNECTED},
+              tabs::TabAlert::BLUETOOTH_CONNECTED},
              {tabs::mojom::TabAlertState::kUsbConnected,
-              TabAlertState::USB_CONNECTED},
+              tabs::TabAlert::USB_CONNECTED},
              {tabs::mojom::TabAlertState::kHidConnected,
-              TabAlertState::HID_CONNECTED},
+              tabs::TabAlert::HID_CONNECTED},
              {tabs::mojom::TabAlertState::kSerialConnected,
-              TabAlertState::SERIAL_CONNECTED},
+              tabs::TabAlert::SERIAL_CONNECTED},
              {tabs::mojom::TabAlertState::kPipPlaying,
-              TabAlertState::PIP_PLAYING},
+              tabs::TabAlert::PIP_PLAYING},
              {tabs::mojom::TabAlertState::kDesktopCapturing,
-              TabAlertState::DESKTOP_CAPTURING},
+              tabs::TabAlert::DESKTOP_CAPTURING},
              {tabs::mojom::TabAlertState::kVrPresentingInHeadset,
-              TabAlertState::VR_PRESENTING_IN_HEADSET},
+              tabs::TabAlert::VR_PRESENTING_IN_HEADSET},
              {tabs::mojom::TabAlertState::kAudioRecording,
-              TabAlertState::AUDIO_RECORDING},
+              tabs::TabAlert::AUDIO_RECORDING},
              {tabs::mojom::TabAlertState::kVideoRecording,
-              TabAlertState::VIDEO_RECORDING}});
+              tabs::TabAlert::VIDEO_RECORDING}});
     *out = alert_state_map.at(input);
     return true;
   }
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 57e6c676..142f1c1f 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -86,7 +86,7 @@
 #if BUILDFLAG(IS_MAC)
 BASE_FEATURE(kDiyAppIconsMaskedOnMacUpdate,
              "DiyAppIconsMaskedOnMacUpdate",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 #endif
 
 // static
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 05c9d8d4..e4b2544 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1747249678-e43702381cd568814955b66dcd87a7e0826fdb43-2b23ba12fc0bff23d878248a3cd6ed11f376680d.profdata
+chrome-android64-main-1747267889-3b0200515b525bd4e5909a6ab320d601f1a9ee17-5469682bc6b1ea94267ce7c44a4cac37bbffd1d7.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 6a1d25d..b657069 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1747252715-bb00393b72fe86fcfdefb11ecaf54c3b04294b53-d46c76c1dc5bcf8388ea12080d1eb072e90f6943.profdata
+chrome-mac-arm-main-1747274301-dfbe16ba589ec1e1ce9a76907777456126ecac29-ae5ec58f91555ac5fb0e12a58b6f7ef82a3a88d5.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index e32ea8d..fda23b946 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1747245510-6fcfb0d502d85532aa200db62276832dbae43a35-db287c7cb3630d08c8a452237cf6eece15867f61.profdata
+chrome-mac-main-1747266928-68763f645594aa6109e1defd80fc6b95c7859f29-4ba649be861fbbcceaa3a1dd000c6785c3b595ef.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 76f4bdc..5d3d150b 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1747245510-6b1ef9862ff7ebff7797a61e689663c752e957ce-db287c7cb3630d08c8a452237cf6eece15867f61.profdata
+chrome-win-arm64-main-1747266928-497eea47c75771870ac54f916dbf1154a8415ca4-4ba649be861fbbcceaa3a1dd000c6785c3b595ef.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index b9b48cb..06f8ac8f 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1747234746-d4ab879dc17a0e6bb741531c30f7cb9da0c43c01-54671829bfbb662a4d8a7c1b4c9f3826e618fb42.profdata
+chrome-win32-main-1747245510-9066dd76f445ed6dcaf9fd83deb5ac82f8efa48f-db287c7cb3630d08c8a452237cf6eece15867f61.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 02fd60b..e9a14605 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1747213155-31f4a89a5bfae9bc892ab93991c3b615a2b67384-57643b439871e4cf9f63b22a9cde066ef3fa9b7f.profdata
+chrome-win64-main-1747234746-beca5e55a25c645ffaee0dfd1b05f6860f5301ec-54671829bfbb662a4d8a7c1b4c9f3826e618fb42.profdata
diff --git a/chrome/common/actor.mojom b/chrome/common/actor.mojom
index d57a77f..f3b7c2a 100644
--- a/chrome/common/actor.mojom
+++ b/chrome/common/actor.mojom
@@ -207,6 +207,17 @@
   // Navigations were created but asynchronously cancelled before being started.
   kHistoryCancelledBeforeStart = 801,
 
+  // Back traversal was requested when at beginning of session history.
+  kHistoryNoBackEntries = 802,
+
+  // Forward traversal was requested when at end of session history.
+  kHistoryNoForwardEntries = 803,
+
+  // History navigation was aborted before commit.
+  kHistoryFailedBeforeCommit = 804,
+
+  // History navigation committed to an error page.
+  kHistoryErrorPage = 805,
 };
 
 // All information required to invoke a tool in the renderer.
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 6c3b7722..54693ee 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -538,39 +538,6 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(ENABLE_GLIC)
 
-BASE_FEATURE(kTabstripComboButton,
-             "TabstripComboButton",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-bool IsTabSearchMoving() {
-  return base::FeatureList::IsEnabled(features::kTabstripComboButton);
-}
-
-const base::FeatureParam<bool> kTabstripComboButtonHasBackground{
-    &kTabstripComboButton, "has_background", false};
-
-const base::FeatureParam<bool> kTabstripComboButtonHasReverseButtonOrder{
-    &kTabstripComboButton, "reverse_button_order", false};
-
-const base::FeatureParam<bool> kTabSearchToolbarButton{
-    &kTabstripComboButton, "tab_search_toolbar_button", false};
-
-bool HasTabstripComboButtonWithBackground() {
-  return IsTabSearchMoving() &&
-         features::kTabstripComboButtonHasBackground.Get() &&
-         !features::kTabSearchToolbarButton.Get();
-}
-
-bool HasTabstripComboButtonWithReverseButtonOrder() {
-  return IsTabSearchMoving() &&
-         features::kTabstripComboButtonHasReverseButtonOrder.Get() &&
-         !features::kTabSearchToolbarButton.Get();
-}
-
-bool HasTabSearchToolbarButton() {
-  return IsTabSearchMoving() && features::kTabSearchToolbarButton.Get();
-}
-
 // Force Privacy Guide to be available even if it would be unavailable
 // otherwise. This is meant for development and test purposes only.
 BASE_FEATURE(kPrivacyGuideForceAvailable,
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index a178e48..2fdf59ff 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -311,18 +311,6 @@
 BASE_DECLARE_FEATURE(kGlicUnloadOnClose);
 #endif  // BUILDFLAG(ENABLE_GLIC)
 
-COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kTabstripComboButton);
-COMPONENT_EXPORT(CHROME_FEATURES) bool IsTabSearchMoving();
-COMPONENT_EXPORT(CHROME_FEATURES)
-extern const base::FeatureParam<bool> kTabstripComboButtonHasBackground;
-COMPONENT_EXPORT(CHROME_FEATURES) bool HasTabstripComboButtonWithBackground();
-COMPONENT_EXPORT(CHROME_FEATURES)
-extern const base::FeatureParam<bool> kTabstripComboButtonHasReverseButtonOrder;
-COMPONENT_EXPORT(CHROME_FEATURES)
-bool HasTabstripComboButtonWithReverseButtonOrder();
-extern const base::FeatureParam<bool> kTabSearchToolbarButton;
-COMPONENT_EXPORT(CHROME_FEATURES) bool HasTabSearchToolbarButton();
-
 COMPONENT_EXPORT(CHROME_FEATURES)
 BASE_DECLARE_FEATURE(kPrivacyGuideForceAvailable);
 
diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc
index 43fdd0d..71c911c 100644
--- a/chrome/common/extensions/extension_unittest.cc
+++ b/chrome/common/extensions/extension_unittest.cc
@@ -176,12 +176,11 @@
   EXPECT_TRUE(extension.get());
 
   EXPECT_EQ(extension->url().spec() + "bar/baz.js",
-            Extension::GetResourceURL(extension->url(), "bar/baz.js").spec());
+            extension->GetResourceURL("bar/baz.js").spec());
   EXPECT_EQ(extension->url().spec() + "baz.js",
-            Extension::GetResourceURL(extension->url(),
-                                      "bar/../baz.js").spec());
+            extension->GetResourceURL("bar/../baz.js").spec());
   EXPECT_EQ(extension->url().spec() + "baz.js",
-            Extension::GetResourceURL(extension->url(), "../baz.js").spec());
+            extension->GetResourceURL("../baz.js").spec());
 
   // Test that absolute-looking paths ("/"-prefixed) are pasted correctly.
   EXPECT_EQ(extension->url().spec() + "test.html",
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 4712c66..2ba6f037 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2012,7 +2012,10 @@
         "${target_gen_dir}/android_browsertests_manifest/AndroidManifest.xml"
     android_manifest_dep = ":android_browsertests_manifest"
 
-    deps = android_sync_integration_tests_deps + [ "//chrome/browser/sync" ]
+    deps = android_sync_integration_tests_deps + [
+             "//chrome/browser/sync",
+             "//chrome/browser/ui:ui_features",
+           ]
     sources = sync_integration_tests_sources
     data = android_sync_integration_tests_data
   }
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 0db4f7e..71fefd6 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -323,6 +323,7 @@
 
   if (!is_android) {
     deps += [
+      "//chrome/browser/ui:ui_features",
       "//components/history_clusters/core",
       "//components/password_manager/content/common",
       "//components/power_bookmarks/core:features",
diff --git a/chrome/test/data/webui/glic/glic_browsertest.cc b/chrome/test/data/webui/glic/glic_browsertest.cc
index d0678f2b..1f3f9d2 100644
--- a/chrome/test/data/webui/glic/glic_browsertest.cc
+++ b/chrome/test/data/webui/glic/glic_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/web_ui_mocha_browser_test.h"
diff --git a/chrome/test/data/webui/settings/settings_browsertest.cc b/chrome/test/data/webui/settings/settings_browsertest.cc
index 8b0d373..e6714ee6 100644
--- a/chrome/test/data/webui/settings/settings_browsertest.cc
+++ b/chrome/test/data/webui/settings/settings_browsertest.cc
@@ -7,6 +7,7 @@
 #include "build/build_config.h"
 #include "build/config/coverage/buildflags.h"
 #include "chrome/browser/preloading/preloading_features.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/web_ui_mocha_browser_test.h"
diff --git a/chrome/test/data/webui/settings/settings_focus_test.cc b/chrome/test/data/webui/settings/settings_focus_test.cc
index 217fa09e..90cbc09 100644
--- a/chrome/test/data/webui/settings/settings_focus_test.cc
+++ b/chrome/test/data/webui/settings/settings_focus_test.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 "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/web_ui_mocha_browser_test.h"
diff --git a/chrome/test/data/webui/side_panel/read_anything/update_content_selection_with_highlights_test.ts b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_with_highlights_test.ts
index c57aa77..9758912 100644
--- a/chrome/test/data/webui/side_panel/read_anything/update_content_selection_with_highlights_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/update_content_selection_with_highlights_test.ts
@@ -4,7 +4,7 @@
 import 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
 
 import type {AppElement} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
-import {BrowserProxy, currentReadHighlightClass, previousReadHighlightClass, ReadAloudHighlighter} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
+import {BrowserProxy, currentReadHighlightClass, previousReadHighlightClass, ReadAloudHighlighter, SpeechController} from 'chrome-untrusted://read-anything-side-panel.top-chrome/read_anything.js';
 import {assertEquals} from 'chrome-untrusted://webui-test/chai_assert.js';
 import {microtasksFinished} from 'chrome-untrusted://webui-test/test_util.js';
 
@@ -43,8 +43,10 @@
     BrowserProxy.setInstance(new TestColorUpdaterBrowserProxy());
     const readingMode = new FakeReadingMode();
     chrome.readingMode = readingMode as unknown as typeof chrome.readingMode;
+    chrome.readingMode.isReadAloudEnabled = true;
     highlighter = new ReadAloudHighlighter();
     ReadAloudHighlighter.setInstance(highlighter);
+    SpeechController.setInstance(new SpeechController());
 
     // Don't use await createApp() when using a FakeTree, as it seems to cause
     // flakiness.
diff --git a/chrome/test/data/webui/webview/webui_webview_browsertest.cc b/chrome/test/data/webui/webview/webui_webview_browsertest.cc
index 909690d..595819c 100644
--- a/chrome/test/data/webui/webview/webui_webview_browsertest.cc
+++ b/chrome/test/data/webui/webview/webui_webview_browsertest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index f49ddf1..9ea32b7 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -5148,6 +5148,24 @@
   ASSERT_NO_FATAL_FAILURE(Uninstall());
 }
 
+TEST_F(IntegrationTest, OfflineOverInstall) {
+  ScopedServer test_server(test_commands_);
+  ExpectInstallEvent(test_server, kUpdaterAppId);
+  ASSERT_NO_FATAL_FAILURE(Install({kEnableCecaExperimentSwitch}));
+  ASSERT_NO_FATAL_FAILURE(ExpectInstalled());
+
+  ExpectInstallEvent(test_server, "{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");
+  ASSERT_NO_FATAL_FAILURE(RunOfflineInstall(/*is_legacy_install=*/false,
+                                            /*is_silent_install=*/false));
+
+  ExpectInstallEvent(test_server, "{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");
+  ASSERT_NO_FATAL_FAILURE(RunOfflineInstall(/*is_legacy_install=*/false,
+                                            /*is_silent_install=*/false));
+
+  ASSERT_NO_FATAL_FAILURE(ExpectUninstallPing(&test_server));
+  ASSERT_NO_FATAL_FAILURE(Uninstall());
+}
+
 TEST_F(IntegrationTest, OfflineInstallOsNotSupported) {
   ScopedServer test_server(test_commands_);
   ExpectInstallEvent(test_server, kUpdaterAppId);
diff --git a/chromeos/ash/components/boca/on_task/on_task_session_manager.cc b/chromeos/ash/components/boca/on_task/on_task_session_manager.cc
index 2aa33fa..1499ec5 100644
--- a/chromeos/ash/components/boca/on_task/on_task_session_manager.cc
+++ b/chromeos/ash/components/boca/on_task/on_task_session_manager.cc
@@ -300,6 +300,15 @@
 void OnTaskSessionManager::LockOrUnlockWindow(bool lock_window) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (lock_in_progress_ && lock_window) {
+    // Enter pause mode and remove countdown notification if pause mode is
+    // triggered while in locked mode countdown.
+    if (enter_pause_mode_) {
+      notifications_manager_->StopProcessingNotification(
+          kOnTaskEnterLockedModeNotificationId);
+      notifications_manager_->ClearNotification(
+          kOnTaskEnterLockedModeNotificationId);
+      EnterLockedMode();
+    }
     return;
   }
   lock_in_progress_ = lock_window;
diff --git a/chromeos/ui/frame/BUILD.gn b/chromeos/ui/frame/BUILD.gn
index 492345d..e40ba2e6 100644
--- a/chromeos/ui/frame/BUILD.gn
+++ b/chromeos/ui/frame/BUILD.gn
@@ -26,8 +26,6 @@
     "desks/move_to_desks_menu_delegate.h",
     "desks/move_to_desks_menu_model.cc",
     "desks/move_to_desks_menu_model.h",
-    "frame_color_metrics_helper.cc",
-    "frame_color_metrics_helper.h",
     "frame_header.cc",
     "frame_header.h",
     "frame_utils.cc",
diff --git a/chromeos/ui/frame/default_frame_header.cc b/chromeos/ui/frame/default_frame_header.cc
index 08d2f6e..2e784484 100644
--- a/chromeos/ui/frame/default_frame_header.cc
+++ b/chromeos/ui/frame/default_frame_header.cc
@@ -72,7 +72,6 @@
     : FrameHeader(target_widget, header_view) {
   DCHECK(caption_button_container);
   SetCaptionButtonContainer(caption_button_container);
-  InitializeFrameColorMetricsHelper();
 }
 
 DefaultFrameHeader::~DefaultFrameHeader() = default;
@@ -111,7 +110,6 @@
 
   if (updated) {
     StartTransitionAnimation(kDefaultFrameColorChangeAnimationDuration);
-    frame_color_metrics_helper_->UpdateFrameColorChangesCount();
   }
 
   if (ShouldApplyDynamicColor(GetTargetWindow())) {
@@ -184,11 +182,4 @@
   return mode() == MODE_ACTIVE ? active_frame_color_ : inactive_frame_color_;
 }
 
-void DefaultFrameHeader::InitializeFrameColorMetricsHelper() {
-  aura::Window* window = GetTargetWindow();
-  CHECK(window);
-  frame_color_metrics_helper_ = std::make_unique<FrameColorMetricsHelper>(
-      window->GetProperty(chromeos::kAppTypeKey));
-}
-
 }  // namespace chromeos
diff --git a/chromeos/ui/frame/default_frame_header.h b/chromeos/ui/frame/default_frame_header.h
index 8f89c4bb6..10f5ba6 100644
--- a/chromeos/ui/frame/default_frame_header.h
+++ b/chromeos/ui/frame/default_frame_header.h
@@ -5,13 +5,10 @@
 #ifndef CHROMEOS_UI_FRAME_DEFAULT_FRAME_HEADER_H_
 #define CHROMEOS_UI_FRAME_DEFAULT_FRAME_HEADER_H_
 
-#include <memory>
-
 #include "base/compiler_specific.h"  // override
 #include "base/component_export.h"
 #include "base/gtest_prod_util.h"
 #include "chromeos/ui/base/chromeos_ui_constants.h"
-#include "chromeos/ui/frame/frame_color_metrics_helper.h"
 #include "chromeos/ui/frame/frame_header.h"
 
 namespace ash {
@@ -58,17 +55,10 @@
   // Returns the window of the target widget.
   aura::Window* GetTargetWindow();
 
-  // This function should be only called once, i.e., one instance of
-  // default_frame_header should own only one `frame_color_metrics_helper_`
-  // throughout its lifetime.
-  void InitializeFrameColorMetricsHelper();
-
   SkColor active_frame_color_ = chromeos::kDefaultFrameColor;
   SkColor inactive_frame_color_ = chromeos::kDefaultFrameColor;
 
   int width_in_pixels_ = -1;
-
-  std::unique_ptr<FrameColorMetricsHelper> frame_color_metrics_helper_;
 };
 
 }  // namespace chromeos
diff --git a/chromeos/ui/frame/frame_color_metrics_helper.cc b/chromeos/ui/frame/frame_color_metrics_helper.cc
deleted file mode 100644
index 6e18f70..0000000
--- a/chromeos/ui/frame/frame_color_metrics_helper.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/ui/frame/frame_color_metrics_helper.h"
-
-#include "base/check.h"
-#include "base/functional/bind.h"
-#include "base/functional/callback_forward.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/strcat.h"
-#include "base/time/time.h"
-#include "chromeos/ui/base/app_types.h"
-
-namespace {
-
-constexpr char kArcHistogramName[] = "ArcApp";
-constexpr char kBrowserHistogramName[] = "Browser";
-constexpr char kChromeAppHistogramName[] = "ChromeApp";
-constexpr char kSystemAppHistogramName[] = "SystemApp";
-constexpr char kCrostiniAppHistogramName[] = "CrostiniApp";
-
-// The tracing duration for frame color changes.
-constexpr base::TimeDelta kFrameColorTracingTime = base::Seconds(3);
-
-}  // namespace
-
-namespace chromeos {
-
-FrameColorMetricsHelper::FrameColorMetricsHelper(chromeos::AppType app_type)
-    : app_type_(app_type) {
-  StartTracing();
-}
-
-FrameColorMetricsHelper::~FrameColorMetricsHelper() = default;
-
-void FrameColorMetricsHelper::UpdateFrameColorChangesCount() {
-  frame_color_change_count_++;
-}
-
-// static
-std::string FrameColorMetricsHelper::GetFrameColorChangeHistogramName(
-    chromeos::AppType app_type) {
-  std::string app_type_str_;
-  switch (app_type) {
-    case chromeos::AppType::ARC_APP:
-      app_type_str_ = kArcHistogramName;
-      break;
-    case chromeos::AppType::BROWSER:
-      app_type_str_ = kBrowserHistogramName;
-      break;
-    case chromeos::AppType::CHROME_APP:
-      app_type_str_ = kChromeAppHistogramName;
-      break;
-    case chromeos::AppType::SYSTEM_APP:
-      app_type_str_ = kSystemAppHistogramName;
-      break;
-    case chromeos::AppType::CROSTINI_APP:
-      app_type_str_ = kCrostiniAppHistogramName;
-      break;
-    default:
-      app_type_str_ = "Others";
-  }
-  return base::StrCat({"Ash.Frame.ColorChangeCount.", app_type_str_});
-}
-
-void FrameColorMetricsHelper::StartTracing() {
-  CHECK(!frame_start_timer_.IsRunning());
-  frame_start_timer_.Start(
-      FROM_HERE, kFrameColorTracingTime,
-      base::BindOnce(&FrameColorMetricsHelper::FinalizeFrameColorTracing,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void FrameColorMetricsHelper::FinalizeFrameColorTracing() {
-  frame_start_timer_.Stop();
-  RecordFrameColorChangeCount();
-}
-
-void FrameColorMetricsHelper::RecordFrameColorChangeCount() {
-  const auto histogram_name = GetFrameColorChangeHistogramName(app_type_);
-  base::UmaHistogramCounts100(histogram_name, frame_color_change_count_);
-}
-
-}  // namespace chromeos
diff --git a/chromeos/ui/frame/frame_color_metrics_helper.h b/chromeos/ui/frame/frame_color_metrics_helper.h
deleted file mode 100644
index da31804..0000000
--- a/chromeos/ui/frame/frame_color_metrics_helper.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_UI_FRAME_FRAME_COLOR_METRICS_HELPER_H_
-#define CHROMEOS_UI_FRAME_FRAME_COLOR_METRICS_HELPER_H_
-
-#include <string>
-
-#include "base/timer/timer.h"
-#include "chromeos/ui/base/app_types.h"
-
-namespace chromeos {
-
-class FrameColorMetricsHelper {
- public:
-  explicit FrameColorMetricsHelper(chromeos::AppType app_type);
-  FrameColorMetricsHelper(const FrameColorMetricsHelper& other) = delete;
-  FrameColorMetricsHelper& operator=(const FrameColorMetricsHelper&) = delete;
-  ~FrameColorMetricsHelper();
-
-  // When the frame color is changed, the count is incremented.
-  void UpdateFrameColorChangesCount();
-
-  static std::string GetFrameColorChangeHistogramName(
-      chromeos::AppType app_type);
-
- private:
-  // Start the timer for counting the frame color changes.
-  void StartTracing();
-
-  // When the timer expires, stop counting the frame color changes, and record
-  // the result in UMA.
-  void FinalizeFrameColorTracing();
-
-  void RecordFrameColorChangeCount();
-
-  // Timer for frame color changes counting.
-  base::OneShotTimer frame_start_timer_;
-
-  const chromeos::AppType app_type_;
-
-  uint32_t frame_color_change_count_ = 0;
-
-  base::WeakPtrFactory<FrameColorMetricsHelper> weak_ptr_factory_{this};
-};
-
-}  // namespace chromeos
-
-#endif  // CHROMEOS_UI_FRAME_FRAME_COLOR_METRICS_HELPER_H_
diff --git a/clank b/clank
index 2135957..458624d 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 2135957a97f443f1db1b70e4379f0d808684e977
+Subproject commit 458624d042c10f66119db1ede7220e141e4eda26
diff --git a/components/affiliations/core/browser/affiliation_utils.cc b/components/affiliations/core/browser/affiliation_utils.cc
index efeffcf5..08d192b2 100644
--- a/components/affiliations/core/browser/affiliation_utils.cc
+++ b/components/affiliations/core/browser/affiliation_utils.cc
@@ -142,7 +142,8 @@
 
   url::Component unused;
   bool success = url::CanonicalizeScheme(
-      input_uri.c_str(), input_parsed.scheme, &canonical_output, &unused);
+      input_parsed.scheme.as_string_view_on(input_uri.c_str()),
+      &canonical_output, &unused);
 
   canonical_output.push_back('/');
   canonical_output.push_back('/');
diff --git a/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc b/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc
index a5a8be0..243ccf6 100644
--- a/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc
+++ b/components/autofill/core/browser/data_manager/payments/payments_data_manager.cc
@@ -996,12 +996,18 @@
 
 bool PaymentsDataManager::IsCardEligibleForBenefits(
     const CreditCard& card) const {
-  return (card.issuer_id() == kAmexCardIssuerId &&
+  return (card.benefit_source() == kAmexCardBenefitSource &&
           base::FeatureList::IsEnabled(
               features::kAutofillEnableCardBenefitsForAmericanExpress)) ||
-         (card.issuer_id() == kBmoCardIssuerId &&
+         (card.benefit_source() == kBmoCardBenefitSource &&
           base::FeatureList::IsEnabled(
-              features::kAutofillEnableCardBenefitsForBmo));
+              features::kAutofillEnableCardBenefitsForBmo)) ||
+         (card.benefit_source() == kCurinosCardBenefitSource &&
+          GetFlatRateBenefitByInstrumentId(
+              CreditCardBenefitBase::LinkedCardInstrumentId(
+                  card.instrument_id())) &&
+          base::FeatureList::IsEnabled(
+              features::kAutofillEnableFlatRateCardBenefitsFromCurinos));
 }
 
 bool PaymentsDataManager::IsCardBenefitsFeatureEnabled() {
diff --git a/components/autofill/core/browser/data_model/payments/credit_card.cc b/components/autofill/core/browser/data_model/payments/credit_card.cc
index b364aa58..e9c174fe 100644
--- a/components/autofill/core/browser/data_model/payments/credit_card.cc
+++ b/components/autofill/core/browser/data_model/payments/credit_card.cc
@@ -37,7 +37,6 @@
 #include "components/autofill/core/common/autofill_clock.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/autofill_features.h"
-#include "components/autofill/core/common/autofill_payments_features.h"
 #include "components/autofill/core/common/autofill_regexes.h"
 #include "components/autofill/core/common/credit_card_network_identifiers.h"
 #include "components/autofill/core/common/credit_card_number_validation.h"
diff --git a/components/autofill/core/browser/data_model/payments/credit_card.h b/components/autofill/core/browser/data_model/payments/credit_card.h
index 769203d..6b1cd3aa 100644
--- a/components/autofill/core/browser/data_model/payments/credit_card.h
+++ b/components/autofill/core/browser/data_model/payments/credit_card.h
@@ -20,6 +20,7 @@
 #include "components/autofill/core/browser/data_model/usage_history_information.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/suggestions/suggestion.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
 #include "url/gurl.h"
 
 namespace autofill {
@@ -518,7 +519,15 @@
     product_terms_url_ = product_terms_url;
   }
 
-  const std::string& benefit_source() const { return benefit_source_; }
+  // TODO(crbug.com/416338314): Remove kAutofillEnableCardBenefitsSourceSync
+  // once this flag is enabled by default and no drawbacks occur.
+  const std::string& benefit_source() const {
+    return base::FeatureList::IsEnabled(
+               features::kAutofillEnableCardBenefitsSourceSync)
+               ? benefit_source_
+               : issuer_id_;
+  }
+
   void set_benefit_source(std::string_view benefit_source) {
     benefit_source_ = std::string(benefit_source);
   }
diff --git a/components/autofill/core/browser/metrics/payments/card_metadata_metrics.cc b/components/autofill/core/browser/metrics/payments/card_metadata_metrics.cc
index 4a497fc..148be94 100644
--- a/components/autofill/core/browser/metrics/payments/card_metadata_metrics.cc
+++ b/components/autofill/core/browser/metrics/payments/card_metadata_metrics.cc
@@ -102,6 +102,19 @@
   }
 }
 
+std::string_view GetCardBenefitSourceSuffix(
+    const std::string& card_benefit_source) {
+  if (card_benefit_source == kAmexCardBenefitSource) {
+    return kAmericanExpress;
+  } else if (card_benefit_source == kBmoCardBenefitSource) {
+    return kBmo;
+  } else if (card_benefit_source == kCurinosCardBenefitSource) {
+    return kCurinos;
+  } else {
+    return "";
+  }
+}
+
 CardMetadataLoggingContext GetMetadataLoggingContext(
     base::span<const CreditCard> cards) {
   constexpr auto kLoggedNetworks =
diff --git a/components/autofill/core/browser/metrics/payments/card_metadata_metrics.h b/components/autofill/core/browser/metrics/payments/card_metadata_metrics.h
index 1a359b2d..923b0d1b 100644
--- a/components/autofill/core/browser/metrics/payments/card_metadata_metrics.h
+++ b/components/autofill/core/browser/metrics/payments/card_metadata_metrics.h
@@ -11,15 +11,18 @@
 
 namespace autofill::autofill_metrics {
 
-// The below issuer and network names are used for logging purposes. The issuer
-// names must be consistent with the Autofill.CreditCardIssuerId in the
-// autofill/histograms.xml file.
+// The below issuer, network, and benefit source names are used for logging
+// purposes. The issuers, networks, and benefit sources must be consistent with
+// the Autofill.CreditCardIssuerId, Autofill.CreditCardNetwork, and
+// Autofill.CreditCardBenefitSource respectively, in the
+// tools/metrics/histograms/metadata/autofill/histograms.xml file.
 constexpr std::string_view kAmericanExpress = "Amex";
 constexpr std::string_view kAnz = "Anz";
 constexpr std::string_view kBmo = "Bmo";
 constexpr std::string_view kCapitalOne = "CapitalOne";
 constexpr std::string_view kChase = "Chase";
 constexpr std::string_view kCiti = "Citi";
+constexpr std::string_view kCurinos = "Curinos";
 constexpr std::string_view kDiscover = "Discover";
 constexpr std::string_view kLloyds = "Lloyds";
 constexpr std::string_view kMarqeta = "Marqeta";
@@ -117,10 +120,14 @@
   int64_t selected_card_instrument_id;
 };
 
-// Get histogram suffix based on given card issuer id or network.
+// Get histogram suffix based on a given card issuer id or network.
 std::string_view GetCardIssuerIdOrNetworkSuffix(
     const std::string& card_issuer_id_or_network);
 
+// Get histogram suffix based on a given card benefit source.
+std::string_view GetCardBenefitSourceSuffix(
+    const std::string& card_benefit_source);
+
 // Get the CardMetadataLoggingContext for the given credit cards.
 CardMetadataLoggingContext GetMetadataLoggingContext(
     base::span<const CreditCard> cards);
diff --git a/components/autofill/core/browser/payments/constants.h b/components/autofill/core/browser/payments/constants.h
index ee0e340..767ea40 100644
--- a/components/autofill/core/browser/payments/constants.h
+++ b/components/autofill/core/browser/payments/constants.h
@@ -34,6 +34,12 @@
 inline constexpr std::string_view kBnplZipIssuerId = "zip";
 inline constexpr std::string_view kBnplAfterpayIssuerId = "afterpay";
 
+// Credit card benefit sources. These are server-generated values that must be
+// consistent between server and client.
+inline constexpr std::string_view kAmexCardBenefitSource = "amex";
+inline constexpr std::string_view kBmoCardBenefitSource = "bmo";
+inline constexpr std::string_view kCurinosCardBenefitSource = "curinos";
+
 // The urls to the static card art images used by Capital One cards.
 inline constexpr std::string_view kCapitalOneCardArtUrl =
     "https://www.gstatic.com/autofill/virtualcard/icon/capitalone.png";
diff --git a/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc b/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
index a1d6e31..a96b95bf 100644
--- a/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
@@ -1034,12 +1034,16 @@
 // 1. Function reference to call which creates the appropriate credit card
 // benefit for the unittest.
 // 2. Whether the flag to render benefits is enabled.
-// 3. Issuer ID which is set for the credit card with benefits.
+// 3. Whether the flag to sync benefits source is enabled.
+// 4. Issuer ID which is set for the credit card with benefits.
+// 5. Benefit source which is set for the credit card with benefits.
 class CreditCardOtpAuthenticatorCardBenefitsTest
     : public CreditCardOtpAuthenticatorTestBase,
       public ::testing::WithParamInterface<
           std::tuple<base::FunctionRef<CreditCardBenefit()>,
                      bool,
+                     bool,
+                     std::string,
                      std::string>> {
  public:
   void SetUp() override {
@@ -1048,21 +1052,48 @@
         {{features::kAutofillEnableCardBenefitsForAmericanExpress,
           IsCreditCardBenefitsEnabled()},
          {features::kAutofillEnableCardBenefitsForBmo,
-          IsCreditCardBenefitsEnabled()}});
+          IsCreditCardBenefitsEnabled()},
+         {features::kAutofillEnableFlatRateCardBenefitsFromCurinos,
+          IsCreditCardBenefitsEnabled()},
+         {features::kAutofillEnableCardBenefitsSourceSync,
+          IsCreditCardBenefitsSourceSyncEnabled()}});
     CreateSelectedOtpChallengeOption(CardUnmaskChallengeOptionType::kSmsOtp);
     card_ = test::GetVirtualCard();
     autofill_client().set_last_committed_primary_main_frame_url(
         test::GetOriginsForMerchantBenefit().begin()->GetURL());
-    test::SetUpCreditCardAndBenefitData(
-        card_, GetBenefit(), GetIssuerId(), personal_data(),
-        autofill_client().GetAutofillOptimizationGuide());
+    if (IsCreditCardBenefitsSourceSyncEnabled()) {
+      test::SetUpCreditCardAndBenefitData(
+          card_, /*issuer_id=*/"", GetBenefit(), GetBenefitSource(),
+          personal_data(), autofill_client().GetAutofillOptimizationGuide());
+    } else {
+      test::SetUpCreditCardAndBenefitData(
+          card_, GetIssuerId(), GetBenefit(), /*benefit_source=*/"",
+          personal_data(), autofill_client().GetAutofillOptimizationGuide());
+    }
   }
 
   CreditCardBenefit GetBenefit() const { return std::get<0>(GetParam())(); }
 
   bool IsCreditCardBenefitsEnabled() const { return std::get<1>(GetParam()); }
 
-  const std::string& GetIssuerId() const { return std::get<2>(GetParam()); }
+  bool IsCreditCardBenefitsSourceSyncEnabled() const {
+    return std::get<2>(GetParam());
+  }
+
+  const std::string& GetIssuerId() const { return std::get<3>(GetParam()); }
+
+  const std::string& GetBenefitSource() const {
+    return std::get<4>(GetParam());
+  }
+
+  bool ShouldShowCardBenefits() const {
+    if (IsCreditCardBenefitsSourceSyncEnabled() &&
+        GetBenefitSource() == "curinos") {
+      return IsCreditCardBenefitsEnabled() &&
+             std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit());
+    }
+    return IsCreditCardBenefitsEnabled();
+  }
 
   const CreditCard& card() { return card_; }
 
@@ -1079,7 +1110,9 @@
                           &test::GetActiveCreditCardCategoryBenefit,
                           &test::GetActiveCreditCardMerchantBenefit),
         ::testing::Bool(),
-        ::testing::Values("amex", "bmo")));
+        ::testing::Bool(),
+        ::testing::Values("amex", "bmo"),
+        ::testing::Values("amex", "bmo", "curinos")));
 
 // Checks that ClientBehaviorConstants::kShowingCardBenefits is populated as a
 // signal if a card benefit was shown when unmasking a credit card suggestion
@@ -1091,13 +1124,12 @@
       /*context_token=*/"context_token_from_previous_unmask_response",
       /*billing_customer_number=*/kTestBillingCustomerNumber);
   authenticator_->OnUnmaskPromptAccepted(/*otp=*/u"111111");
-
   std::vector<ClientBehaviorConstants> signals =
       payments_network_interface().unmask_request()->client_behavior_signals;
   EXPECT_EQ(std::ranges::find(signals,
                               ClientBehaviorConstants::kShowingCardBenefits) !=
                 signals.end(),
-            IsCreditCardBenefitsEnabled());
+            ShouldShowCardBenefits());
 }
 
 }  // namespace
diff --git a/components/autofill/core/browser/payments/credit_card_risk_based_authenticator_unittest.cc b/components/autofill/core/browser/payments/credit_card_risk_based_authenticator_unittest.cc
index 49ae1bd..bf800c5 100644
--- a/components/autofill/core/browser/payments/credit_card_risk_based_authenticator_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_risk_based_authenticator_unittest.cc
@@ -504,12 +504,16 @@
 // 1. Function reference to call which creates the appropriate credit card
 // benefit for the unittest.
 // 2. Whether the flag to render benefits is enabled.
-// 3. Issuer ID which is set for the credit card with benefits.
+// 3. Whether the flag to sync benefits source is enabled.
+// 4. Issuer ID which is set for the credit card with benefits.
+// 5. Benefit source which is set for the credit card with benefits.
 class CreditCardRiskBasedAuthenticatorCardBenefitsTest
     : public CreditCardRiskBasedAuthenticatorTest,
       public ::testing::WithParamInterface<
           std::tuple<base::FunctionRef<CreditCardBenefit()>,
                      bool,
+                     bool,
+                     std::string,
                      std::string>> {
  public:
   void SetUp() override {
@@ -518,20 +522,47 @@
         {{features::kAutofillEnableCardBenefitsForAmericanExpress,
           IsCreditCardBenefitsEnabled()},
          {features::kAutofillEnableCardBenefitsForBmo,
-          IsCreditCardBenefitsEnabled()}});
+          IsCreditCardBenefitsEnabled()},
+         {features::kAutofillEnableFlatRateCardBenefitsFromCurinos,
+          IsCreditCardBenefitsEnabled()},
+         {features::kAutofillEnableCardBenefitsSourceSync,
+          IsCreditCardBenefitsSourceSyncEnabled()}});
     card_ = test::GetMaskedServerCard();
     autofill_client()->set_last_committed_primary_main_frame_url(
         test::GetOriginsForMerchantBenefit().begin()->GetURL());
-    test::SetUpCreditCardAndBenefitData(
-        card_, GetBenefit(), GetIssuerId(), personal_data(),
-        autofill_client()->GetAutofillOptimizationGuide());
+    if (IsCreditCardBenefitsSourceSyncEnabled()) {
+      test::SetUpCreditCardAndBenefitData(
+          card_, /*issuer_id=*/"", GetBenefit(), GetBenefitSource(),
+          personal_data(), autofill_client()->GetAutofillOptimizationGuide());
+    } else {
+      test::SetUpCreditCardAndBenefitData(
+          card_, GetIssuerId(), GetBenefit(), /*benefit_source=*/"",
+          personal_data(), autofill_client()->GetAutofillOptimizationGuide());
+    }
   }
 
   CreditCardBenefit GetBenefit() const { return std::get<0>(GetParam())(); }
 
   bool IsCreditCardBenefitsEnabled() const { return std::get<1>(GetParam()); }
 
-  const std::string& GetIssuerId() const { return std::get<2>(GetParam()); }
+  bool IsCreditCardBenefitsSourceSyncEnabled() const {
+    return std::get<2>(GetParam());
+  }
+
+  const std::string& GetIssuerId() const { return std::get<3>(GetParam()); }
+
+  const std::string& GetBenefitSource() const {
+    return std::get<4>(GetParam());
+  }
+
+  bool ShouldShowCardBenefits() const {
+    if (IsCreditCardBenefitsSourceSyncEnabled() &&
+        GetBenefitSource() == "curinos") {
+      return IsCreditCardBenefitsEnabled() &&
+             std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit());
+    }
+    return IsCreditCardBenefitsEnabled();
+  }
 
   const CreditCard& card() { return card_; }
 
@@ -548,7 +579,9 @@
                           &test::GetActiveCreditCardCategoryBenefit,
                           &test::GetActiveCreditCardMerchantBenefit),
         ::testing::Bool(),
-        ::testing::Values("amex", "bmo")));
+        ::testing::Bool(),
+        ::testing::Values("amex", "bmo"),
+        ::testing::Values("amex", "bmo", "curinos")));
 
 // Checks that ClientBehaviorConstants::kShowingCardBenefits is populated as a
 // signal if a card benefit was shown when unmasking a credit card suggestion
@@ -563,11 +596,10 @@
 
   std::vector<ClientBehaviorConstants> signals =
       payments_network_interface()->unmask_request()->client_behavior_signals;
-
   EXPECT_EQ(std::ranges::find(signals,
                               ClientBehaviorConstants::kShowingCardBenefits) !=
                 signals.end(),
-            IsCreditCardBenefitsEnabled());
+            ShouldShowCardBenefits());
 }
 
 }  // namespace
diff --git a/components/autofill/core/browser/payments/full_card_request_unittest.cc b/components/autofill/core/browser/payments/full_card_request_unittest.cc
index 7151a1c3..ec0bb90 100644
--- a/components/autofill/core/browser/payments/full_card_request_unittest.cc
+++ b/components/autofill/core/browser/payments/full_card_request_unittest.cc
@@ -794,12 +794,16 @@
 // 1. Function reference to call which creates the appropriate credit card
 // benefit for the unittest.
 // 2. Whether the flag to render benefits is enabled.
-// 3. Issuer ID which is set for the credit card with benefits.
+// 3. Whether the flag to sync benefits source is enabled.
+// 4. Issuer ID which is set for the credit card with benefits.
+// 5. Benefit source which is set for the credit card with benefits.
 class FullCardRequestCardBenefitsTest
     : public FullCardRequestTest,
       public ::testing::WithParamInterface<
           std::tuple<base::FunctionRef<CreditCardBenefit()>,
                      bool,
+                     bool,
+                     std::string,
                      std::string>> {
  public:
   void SetUp() override {
@@ -807,21 +811,47 @@
         {{features::kAutofillEnableCardBenefitsForAmericanExpress,
           IsCreditCardBenefitsEnabled()},
          {features::kAutofillEnableCardBenefitsForBmo,
-          IsCreditCardBenefitsEnabled()}});
-
+          IsCreditCardBenefitsEnabled()},
+         {features::kAutofillEnableFlatRateCardBenefitsFromCurinos,
+          IsCreditCardBenefitsEnabled()},
+         {features::kAutofillEnableCardBenefitsSourceSync,
+          IsCreditCardBenefitsSourceSyncEnabled()}});
     card_ = test::GetMaskedServerCard();
     autofill_client().set_last_committed_primary_main_frame_url(
         test::GetOriginsForMerchantBenefit().begin()->GetURL());
-    test::SetUpCreditCardAndBenefitData(
-        card_, GetBenefit(), GetIssuerId(), personal_data(),
-        autofill_client().GetAutofillOptimizationGuide());
+    if (IsCreditCardBenefitsSourceSyncEnabled()) {
+      test::SetUpCreditCardAndBenefitData(
+          card_, /*issuer_id=*/"", GetBenefit(), GetBenefitSource(),
+          personal_data(), autofill_client().GetAutofillOptimizationGuide());
+    } else {
+      test::SetUpCreditCardAndBenefitData(
+          card_, GetIssuerId(), GetBenefit(), /*benefit_source=*/"",
+          personal_data(), autofill_client().GetAutofillOptimizationGuide());
+    }
   }
 
   CreditCardBenefit GetBenefit() const { return std::get<0>(GetParam())(); }
 
   bool IsCreditCardBenefitsEnabled() const { return std::get<1>(GetParam()); }
 
-  const std::string& GetIssuerId() const { return std::get<2>(GetParam()); }
+  bool IsCreditCardBenefitsSourceSyncEnabled() const {
+    return std::get<2>(GetParam());
+  }
+
+  const std::string& GetIssuerId() const { return std::get<3>(GetParam()); }
+
+  const std::string& GetBenefitSource() const {
+    return std::get<4>(GetParam());
+  }
+
+  bool ShouldShowCardBenefits() const {
+    if (IsCreditCardBenefitsSourceSyncEnabled() &&
+        GetBenefitSource() == "curinos") {
+      return IsCreditCardBenefitsEnabled() &&
+             std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit());
+    }
+    return IsCreditCardBenefitsEnabled();
+  }
 
   const CreditCard& card() { return card_; }
 
@@ -838,7 +868,9 @@
                           &test::GetActiveCreditCardCategoryBenefit,
                           &test::GetActiveCreditCardMerchantBenefit),
         ::testing::Bool(),
-        ::testing::Values("amex", "bmo")));
+        ::testing::Bool(),
+        ::testing::Values("amex", "bmo"),
+        ::testing::Values("amex", "bmo", "curinos")));
 
 // Checks that ClientBehaviorConstants::kShowingCardBenefits is populated as a
 // signal if a card benefit was shown when unmasking a credit card suggestion
@@ -851,7 +883,7 @@
   EXPECT_EQ(std::ranges::find(signals,
                               ClientBehaviorConstants::kShowingCardBenefits) !=
                 signals.end(),
-            IsCreditCardBenefitsEnabled());
+            ShouldShowCardBenefits());
 }
 
 }  // namespace autofill::payments
diff --git a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc
index 1873271..d401551 100644
--- a/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/suggestions/payments/payments_suggestion_generator_unittest.cc
@@ -321,21 +321,28 @@
 // Params:
 // 1. Function reference to call which creates the appropriate credit card
 // benefit for the unittest.
-// 2. Issuer ID which is set for the credit card with benefits.
+// 2. Whether the flag to sync benefits source is enabled.
+// 3. Issuer ID which is set for the credit card with benefits.
+// 4. Benefit source which is set for the credit card with benefits.
 class AutofillCreditCardBenefitsLabelTest
     : public PaymentsSuggestionGeneratorTest,
       public ::testing::WithParamInterface<
-          std::tuple<base::FunctionRef<CreditCardBenefit()>, std::string>> {
+          std::tuple<base::FunctionRef<CreditCardBenefit()>,
+                     bool,
+                     std::string,
+                     std::string>> {
  public:
   void SetUp() override {
     PaymentsSuggestionGeneratorTest::SetUp();
-    scoped_feature_list_.InitWithFeatures(
-        /*enabled_features=*/
-        {features::kAutofillEnableCardBenefitsForAmericanExpress,
-         features::kAutofillEnableCardBenefitsForBmo,
-         features::kAutofillEnableCardBenefitsIph,
-         features::kAutofillEnableNewFopDisplayDesktop},
-        /*disabled_features=*/{});
+
+    scoped_feature_list_.InitWithFeatureStates(
+        {{features::kAutofillEnableCardBenefitsForAmericanExpress, true},
+         {features::kAutofillEnableCardBenefitsForBmo, true},
+         {features::kAutofillEnableFlatRateCardBenefitsFromCurinos, true},
+         {features::kAutofillEnableCardBenefitsIph, true},
+         {features::kAutofillEnableNewFopDisplayDesktop, true},
+         {features::kAutofillEnableCardBenefitsSourceSync,
+          IsCreditCardBenefitsSourceSyncEnabled()}});
 
     std::u16string benefit_description;
     int64_t instrument_id;
@@ -384,12 +391,26 @@
         /*guid=*/"00000000-0000-0000-0000-000000000001",
         /*server_id=*/"server_id1",
         /*instrument_id=*/instrument_id);
-    card_.set_issuer_id(std::get<1>(GetParam()));
+    if (IsCreditCardBenefitsSourceSyncEnabled()) {
+      card_.set_benefit_source(GetBenefitSource());
+    } else {
+      card_.set_issuer_id(GetIssuerId());
+    }
     payments_data().AddServerCreditCard(card_);
   }
 
   CreditCardBenefit GetBenefit() const { return std::get<0>(GetParam())(); }
 
+  bool IsCreditCardBenefitsSourceSyncEnabled() const {
+    return std::get<1>(GetParam());
+  }
+
+  const std::string& GetIssuerId() const { return std::get<2>(GetParam()); }
+
+  const std::string& GetBenefitSource() const {
+    return std::get<3>(GetParam());
+  }
+
   const CreditCard& card() { return card_; }
 
   const std::u16string& expected_benefit_text() {
@@ -425,30 +446,44 @@
     testing::Combine(testing::Values(&test::GetActiveCreditCardFlatRateBenefit,
                                      &test::GetActiveCreditCardCategoryBenefit,
                                      &test::GetActiveCreditCardMerchantBenefit),
-                     ::testing::Values("amex", "bmo")));
+                     ::testing::Bool(),
+                     ::testing::Values("amex", "bmo"),
+                     ::testing::Values("amex", "bmo", "curinos")));
 
 #if !BUILDFLAG(IS_ANDROID)
 // Checks that for FPAN suggestions that the benefit description is displayed.
 TEST_P(AutofillCreditCardBenefitsLabelTest, BenefitSuggestionLabel_Fpan) {
-  EXPECT_THAT(CreateCreditCardSuggestionForTest(
-                  card(), *autofill_client(), CREDIT_CARD_NUMBER,
-                  /*virtual_card_option=*/false,
-                  /*card_linked_offer_available=*/false)
-                  .labels,
-              ElementsAre(std::vector<Suggestion::Text>{
-                  Suggestion::Text(expected_benefit_text())}));
+  Suggestion suggestion = CreateCreditCardSuggestionForTest(
+      card(), *autofill_client(), CREDIT_CARD_NUMBER,
+      /*virtual_card_option=*/false,
+      /*card_linked_offer_available=*/false);
+  if (IsCreditCardBenefitsSourceSyncEnabled() &&
+      GetBenefitSource() == "curinos" &&
+      !std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit())) {
+    EXPECT_TRUE(suggestion.labels.empty());
+  } else {
+    EXPECT_THAT(suggestion.labels,
+                ElementsAre(std::vector<Suggestion::Text>{
+                    Suggestion::Text(expected_benefit_text())}));
+  }
 }
 
 // Checks that feature is set to display the credit card benefit IPH for
 // FPAN suggestions with benefits labels.
 TEST_P(AutofillCreditCardBenefitsLabelTest,
        BenefitSuggestionFeatureForIph_Fpan) {
-  EXPECT_EQ(CreateCreditCardSuggestionForTest(
-                card(), *autofill_client(), CREDIT_CARD_NUMBER,
-                /*virtual_card_option=*/false,
-                /*card_linked_offer_available=*/false)
-                .iph_metadata.feature,
-            &feature_engagement::kIPHAutofillCreditCardBenefitFeature);
+  Suggestion suggestion = CreateCreditCardSuggestionForTest(
+      card(), *autofill_client(), CREDIT_CARD_NUMBER,
+      /*virtual_card_option=*/false,
+      /*card_linked_offer_available=*/false);
+  if (IsCreditCardBenefitsSourceSyncEnabled() &&
+      GetBenefitSource() == "curinos" &&
+      !std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit())) {
+    EXPECT_EQ(suggestion.iph_metadata.feature, nullptr);
+  } else {
+    EXPECT_EQ(suggestion.iph_metadata.feature,
+              &feature_engagement::kIPHAutofillCreditCardBenefitFeature);
+  }
 }
 
 // Checks that feature is set to display the virtual card IPH for
@@ -499,13 +534,19 @@
 // as a label.
 TEST_P(AutofillCreditCardBenefitsLabelTest,
        BenefitSuggestionLabel_VirtualCard) {
-  EXPECT_THAT(CreateCreditCardSuggestionForTest(
-                  card(), *autofill_client(), CREDIT_CARD_NUMBER,
-                  /*virtual_card_option=*/true,
-                  /*card_linked_offer_available=*/false)
-                  .labels,
-              ElementsAre(std::vector<Suggestion::Text>{
-                  Suggestion::Text(expected_benefit_text())}));
+  Suggestion suggestion = CreateCreditCardSuggestionForTest(
+      card(), *autofill_client(), CREDIT_CARD_NUMBER,
+      /*virtual_card_option=*/true,
+      /*card_linked_offer_available=*/false);
+  if (IsCreditCardBenefitsSourceSyncEnabled() &&
+      GetBenefitSource() == "curinos" &&
+      !std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit())) {
+    EXPECT_TRUE(suggestion.labels.empty());
+  } else {
+    EXPECT_THAT(suggestion.labels,
+                ElementsAre(std::vector<Suggestion::Text>{
+                    Suggestion::Text(expected_benefit_text())}));
+  }
 }
 
 // Checks that for merchant opt-out virtual cards suggestion the benefit
@@ -544,7 +585,8 @@
   disable_benefits.InitWithFeatures(
       /*enabled_features=*/{}, /*disabled_features=*/{
           features::kAutofillEnableCardBenefitsForAmericanExpress,
-          features::kAutofillEnableCardBenefitsForBmo});
+          features::kAutofillEnableCardBenefitsForBmo,
+          features::kAutofillEnableFlatRateCardBenefitsFromCurinos});
   DoBenefitSuggestionLabel_MetadataLoggingContextTest();
 }
 
@@ -612,17 +654,26 @@
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
       features::kAutofillEnableNewFopDisplayDesktop);
-  EXPECT_THAT(
-      CreateCreditCardSuggestionForTest(card(), *autofill_client(),
-                                        CREDIT_CARD_NUMBER,
-                                        /*virtual_card_option=*/false,
-                                        /*card_linked_offer_available=*/false)
-          .labels,
-      ElementsAre(
-          std::vector<Suggestion::Text>{
-              Suggestion::Text(expected_benefit_text())},
-          std::vector<Suggestion::Text>{Suggestion::Text(card().GetInfo(
-              CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, /*app_locale=*/"en-US"))}));
+  Suggestion suggestion = CreateCreditCardSuggestionForTest(
+      card(), *autofill_client(), CREDIT_CARD_NUMBER,
+      /*virtual_card_option=*/false,
+      /*card_linked_offer_available=*/false);
+  if (IsCreditCardBenefitsSourceSyncEnabled() &&
+      GetBenefitSource() == "curinos" &&
+      !std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit())) {
+    EXPECT_THAT(suggestion.labels,
+                ElementsAre(std::vector<Suggestion::Text>{Suggestion::Text(
+                    card().GetInfo(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+                                   /*app_locale=*/"en-US"))}));
+  } else {
+    EXPECT_THAT(
+        suggestion.labels,
+        ElementsAre(
+            std::vector<Suggestion::Text>{
+                Suggestion::Text(expected_benefit_text())},
+            std::vector<Suggestion::Text>{Suggestion::Text(card().GetInfo(
+                CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR, /*app_locale=*/"en-US"))}));
+  }
 }
 
 // Checks that for virtual cards suggestion the benefit description is shown
@@ -632,19 +683,27 @@
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
       features::kAutofillEnableNewFopDisplayDesktop);
-
-  EXPECT_THAT(
-      CreateCreditCardSuggestionForTest(card(), *autofill_client(),
-                                        CREDIT_CARD_NUMBER,
-                                        /*virtual_card_option=*/true,
-                                        /*card_linked_offer_available=*/false)
-          .labels,
-      ElementsAre(
-          std::vector<Suggestion::Text>{
-              Suggestion::Text(expected_benefit_text())},
-          std::vector<Suggestion::Text>{
-              Suggestion::Text(l10n_util::GetStringUTF16(
-                  IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE))}));
+  Suggestion suggestion = CreateCreditCardSuggestionForTest(
+      card(), *autofill_client(), CREDIT_CARD_NUMBER,
+      /*virtual_card_option=*/true,
+      /*card_linked_offer_available=*/false);
+  if (IsCreditCardBenefitsSourceSyncEnabled() &&
+      GetBenefitSource() == "curinos" &&
+      !std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit())) {
+    EXPECT_THAT(suggestion.labels,
+                ElementsAre(std::vector<Suggestion::Text>{
+                    Suggestion::Text(l10n_util::GetStringUTF16(
+                        IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE))}));
+  } else {
+    EXPECT_THAT(
+        suggestion.labels,
+        ElementsAre(
+            std::vector<Suggestion::Text>{
+                Suggestion::Text(expected_benefit_text())},
+            std::vector<Suggestion::Text>{
+                Suggestion::Text(l10n_util::GetStringUTF16(
+                    IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE))}));
+  }
 }
 
 // Checks that for merchant opt-out virtual cards suggestion the benefit
@@ -659,18 +718,28 @@
               autofill_client()->GetAutofillOptimizationGuide()),
           ShouldBlockFormFieldSuggestion)
       .WillByDefault(testing::Return(true));
-  EXPECT_THAT(
-      CreateCreditCardSuggestionForTest(virtual_card, *autofill_client(),
-                                        CREDIT_CARD_NUMBER,
-                                        /*virtual_card_option=*/true,
-                                        /*card_linked_offer_available=*/false)
-          .labels,
-      ElementsAre(
-          std::vector<Suggestion::Text>{
-              Suggestion::Text(expected_benefit_text())},
-          std::vector<
-              Suggestion::Text>{Suggestion::Text(l10n_util::GetStringUTF16(
-              IDS_AUTOFILL_VIRTUAL_CARD_DISABLED_SUGGESTION_OPTION_VALUE))}));
+  Suggestion suggestion = CreateCreditCardSuggestionForTest(
+      virtual_card, *autofill_client(), CREDIT_CARD_NUMBER,
+      /*virtual_card_option=*/true,
+      /*card_linked_offer_available=*/false);
+  if (IsCreditCardBenefitsSourceSyncEnabled() &&
+      GetBenefitSource() == "curinos" &&
+      !std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit())) {
+    EXPECT_THAT(
+        suggestion.labels,
+        ElementsAre(std::vector<Suggestion::Text>{
+            Suggestion::Text(l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_VIRTUAL_CARD_DISABLED_SUGGESTION_OPTION_VALUE))}));
+  } else {
+    EXPECT_THAT(
+        suggestion.labels,
+        ElementsAre(
+            std::vector<Suggestion::Text>{
+                Suggestion::Text(expected_benefit_text())},
+            std::vector<
+                Suggestion::Text>{Suggestion::Text(l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_VIRTUAL_CARD_DISABLED_SUGGESTION_OPTION_VALUE))}));
+  }
 }
 
 // Checks that the merchant benefit description is not displayed for suggestions
@@ -770,13 +839,24 @@
       cards, *autofill_client(), *credit_card_form_event_logger_);
 
   EXPECT_EQ(suggestions[0].type, SuggestionType::kCreditCardEntry);
-  EXPECT_THAT(suggestions[0],
-              EqualLabels({{expected_benefit_text()},
-                           {card().GetInfo(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
-                                           app_locale())}}));
-  EXPECT_TRUE(suggestions[0]
-                  .GetPayload<Suggestion::PaymentsPayload>()
-                  .should_display_terms_available);
+  if (IsCreditCardBenefitsSourceSyncEnabled() &&
+      GetBenefitSource() == "curinos" &&
+      !std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit())) {
+    EXPECT_THAT(suggestions[0],
+                EqualLabels({{card().GetInfo(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+                                             app_locale())}}));
+    EXPECT_FALSE(suggestions[0]
+                     .GetPayload<Suggestion::PaymentsPayload>()
+                     .should_display_terms_available);
+  } else {
+    EXPECT_THAT(suggestions[0],
+                EqualLabels({{expected_benefit_text()},
+                             {card().GetInfo(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+                                             app_locale())}}));
+    EXPECT_TRUE(suggestions[0]
+                    .GetPayload<Suggestion::PaymentsPayload>()
+                    .should_display_terms_available);
+  }
 }
 
 TEST_P(AutofillCreditCardBenefitsLabelTest,
@@ -798,14 +878,25 @@
       cards, *autofill_client(), *credit_card_form_event_logger_);
 
   EXPECT_EQ(suggestions[0].type, SuggestionType::kVirtualCreditCardEntry);
-  EXPECT_THAT(
-      suggestions[0],
-      EqualLabels({{expected_benefit_text()},
-                   {l10n_util::GetStringUTF16(
-                       IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE)}}));
-  EXPECT_TRUE(suggestions[0]
-                  .GetPayload<Suggestion::PaymentsPayload>()
-                  .should_display_terms_available);
+  if (IsCreditCardBenefitsSourceSyncEnabled() &&
+      GetBenefitSource() == "curinos" &&
+      !std::holds_alternative<CreditCardFlatRateBenefit>(GetBenefit())) {
+    EXPECT_THAT(suggestions[0],
+                EqualLabels({{l10n_util::GetStringUTF16(
+                    IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE)}}));
+    EXPECT_FALSE(suggestions[0]
+                     .GetPayload<Suggestion::PaymentsPayload>()
+                     .should_display_terms_available);
+  } else {
+    EXPECT_THAT(
+        suggestions[0],
+        EqualLabels({{expected_benefit_text()},
+                     {l10n_util::GetStringUTF16(
+                         IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE)}}));
+    EXPECT_TRUE(suggestions[0]
+                    .GetPayload<Suggestion::PaymentsPayload>()
+                    .should_display_terms_available);
+  }
 }
 
 // Checks that the merchant benefit description is not displayed for suggestions
diff --git a/components/autofill/core/browser/test_utils/autofill_test_utils.cc b/components/autofill/core/browser/test_utils/autofill_test_utils.cc
index 03db465..bec4287 100644
--- a/components/autofill/core/browser/test_utils/autofill_test_utils.cc
+++ b/components/autofill/core/browser/test_utils/autofill_test_utils.cc
@@ -689,8 +689,9 @@
 
 void SetUpCreditCardAndBenefitData(
     CreditCard& card,
-    const CreditCardBenefit& benefit,
     const std::string& issuer_id,
+    const CreditCardBenefit& benefit,
+    const std::string& benefit_source,
     TestPersonalDataManager& personal_data,
     AutofillOptimizationGuide* optimization_guide) {
   std::visit(
@@ -716,6 +717,7 @@
       benefit);
   personal_data.payments_data_manager().AddCreditCardBenefitForTest(benefit);
   card.set_issuer_id(issuer_id);
+  card.set_benefit_source(benefit_source);
   personal_data.test_payments_data_manager().AddServerCreditCard(card);
 }
 
diff --git a/components/autofill/core/browser/test_utils/autofill_test_utils.h b/components/autofill/core/browser/test_utils/autofill_test_utils.h
index c3e01c6..ca3e11a 100644
--- a/components/autofill/core/browser/test_utils/autofill_test_utils.h
+++ b/components/autofill/core/browser/test_utils/autofill_test_utils.h
@@ -231,12 +231,14 @@
 // benefit.
 base::flat_set<url::Origin> GetOriginsForMerchantBenefit();
 
-// Adds `card` with a set `benefit` and `issuer_id` to `personal_data`. Also
-// configures a category benefit with the `optimization_guide`.
+// Adds `card` with a set `issuer_id`, `benefit` and `benefit_source` to
+// `personal_data`. Also configures a category benefit with the
+// `optimization_guide`.
 void SetUpCreditCardAndBenefitData(
     CreditCard& card,
-    const CreditCardBenefit& benefit,
     const std::string& issuer_id,
+    const CreditCardBenefit& benefit,
+    const std::string& benefit_source,
     TestPersonalDataManager& personal_data,
     AutofillOptimizationGuide* optimization_guide);
 
diff --git a/components/collaboration/internal/collaboration_controller.cc b/components/collaboration/internal/collaboration_controller.cc
index 86e2701..65f540ec 100644
--- a/components/collaboration/internal/collaboration_controller.cc
+++ b/components/collaboration/internal/collaboration_controller.cc
@@ -457,9 +457,10 @@
  private:
   void FinishAndTransition() {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    RecordLatency(GetLogger(),
-                  metrics::CollaborationServiceStep::kAuthenticationSuccess,
-                  base::Time::Now() - start_time_);
+    RecordLatency(
+        GetLogger(),
+        metrics::CollaborationServiceStep::kAuthenticationInitToSuccess,
+        base::Time::Now() - start_time_);
     controller_->delegate()->NotifySignInAndSyncStatusChange();
     controller_->TransitionTo(StateId::kWaitingForServicesToInitialize);
   }
@@ -513,9 +514,10 @@
 
   void OnProcessingFinishedWithSuccess() override {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    RecordLatency(GetLogger(),
-                  metrics::CollaborationServiceStep::kServicesInitialized,
-                  base::Time::Now() - start_time_);
+    RecordLatency(
+        GetLogger(),
+        metrics::CollaborationServiceStep::kWaitingForServicesInitialization,
+        base::Time::Now() - start_time_);
     controller_->TransitionTo(StateId::kCheckingFlowRequirements);
   }
 
diff --git a/components/collaboration/internal/collaboration_controller_unittest.cc b/components/collaboration/internal/collaboration_controller_unittest.cc
index 7f59111..1b9c44c 100644
--- a/components/collaboration/internal/collaboration_controller_unittest.cc
+++ b/components/collaboration/internal/collaboration_controller_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
+#include "base/time/time.h"
 #include "components/collaboration/internal/metrics.h"
 #include "components/collaboration/public/collaboration_controller_delegate.h"
 #include "components/collaboration/public/collaboration_flow_type.h"
@@ -133,6 +134,9 @@
 
 TEST_F(CollaborationControllerTest, FullJoinFlowAllStates) {
   base::HistogramTester histogram_tester;
+  base::TimeDelta authentication_time = base::Milliseconds(10);
+  base::TimeDelta service_initialization_time = base::Milliseconds(11);
+  base::TimeDelta tab_group_fetch_time = base::Milliseconds(12);
 
   RunLoop run_loop;
 
@@ -176,6 +180,7 @@
       .WillOnce(SaveArg<0>(&sync_observer));
 
   // 3. Authenticating -> WaitingForServicesToInitialize state.
+  task_environment_.FastForwardBy(authentication_time);
   std::move(authentication_ui_calback).Run(Outcome::kSuccess);
   EXPECT_EQ(controller_->GetStateForTesting(),
             StateId::kWaitingForServicesToInitialize);
@@ -189,6 +194,7 @@
 
   // 4. WaitingForServicesToInitialize -> CheckingFlowRequirementsState ->
   // AddingUserToGroup state.
+  task_environment_.FastForwardBy(service_initialization_time);
   sync_observer->OnInitialized();
   EXPECT_EQ(controller_->GetStateForTesting(), StateId::kAddingUserToGroup);
 
@@ -234,6 +240,7 @@
             StateId::kWaitingForSyncAndDataSharingGroup);
 
   // Simulate added in both tab group and data_sharing group.
+  task_environment_.FastForwardBy(tab_group_fetch_time);
   base::OnceCallback<void(Outcome)> promote_ui_callback;
   EXPECT_CALL(*collaboration_service_, GetCurrentUserRoleForGroup(kGroupId))
       .WillOnce(Return(data_sharing::MemberRole::kMember));
@@ -262,6 +269,15 @@
   histogram_tester.ExpectBucketCount(
       "CollaborationService.JoinFlow",
       metrics::CollaborationServiceJoinEvent::kOpenedNewGroup, 1);
+  histogram_tester.ExpectTimeBucketCount(
+      "CollaborationService.Latency.AuthenticationInitToSuccess",
+      authentication_time, 1);
+  histogram_tester.ExpectTimeBucketCount(
+      "CollaborationService.Latency.WaitingForServicesInitialization",
+      service_initialization_time, 1);
+  histogram_tester.ExpectTimeBucketCount(
+      "CollaborationService.Latency.TabGroupFetchedAfterPeopleGroupJoined",
+      tab_group_fetch_time, 1);
 }
 
 TEST_F(CollaborationControllerTest, JoinFlowManagedDevice) {
@@ -677,6 +693,7 @@
 
 TEST_F(CollaborationControllerTest, FullShareFlowAllStates) {
   base::HistogramTester histogram_tester;
+  base::TimeDelta url_ready_time = base::Milliseconds(10);
 
   // Start Share flow.
   tab_groups::LocalTabGroupID local_id =
@@ -730,6 +747,7 @@
       GroupData(kGroupId, /*display_name=*/"",
                 /*members=*/{}, /*former_members=*/{}, kAccessToken);
   std::move(group_data_callback).Run(group_data);
+  task_environment_.FastForwardBy(url_ready_time);
   std::move(tab_group_sharing_callback)
       .Run(tab_groups::TabGroupSyncService::TabGroupSharingResult::kSuccess);
   EXPECT_EQ(controller_->GetStateForTesting(), StateId::kSharingTabGroupUrl);
@@ -752,6 +770,9 @@
   histogram_tester.ExpectBucketCount(
       "CollaborationService.ShareOrManageFlow",
       metrics::CollaborationServiceShareOrManageEvent::kUrlReadyToShare, 1);
+  histogram_tester.ExpectTimeBucketCount(
+      "CollaborationService.Latency.LinkReadyAfterGroupCreation",
+      url_ready_time, 1);
 }
 
 TEST_F(CollaborationControllerTest, CheckingFlowRequirementsManageFlow) {
diff --git a/components/collaboration/internal/metrics.cc b/components/collaboration/internal/metrics.cc
index 2204b64..5a8c354 100644
--- a/components/collaboration/internal/metrics.cc
+++ b/components/collaboration/internal/metrics.cc
@@ -7,6 +7,7 @@
 #include <string_view>
 
 #include "base/metrics/histogram_functions.h"
+#include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "components/collaboration/public/collaboration_flow_entry_point.h"
 #include "components/data_sharing/public/logger.h"
@@ -269,10 +270,10 @@
   switch (step) {
     case CollaborationServiceStep::kUnknown:
       return "Unknown";
-    case CollaborationServiceStep::kAuthenticationSuccess:
-      return "AuthenticationSuccess";
-    case CollaborationServiceStep::kServicesInitialized:
-      return "ServicesInitialized";
+    case CollaborationServiceStep::kAuthenticationInitToSuccess:
+      return "AuthenticationInitToSuccess";
+    case CollaborationServiceStep::kWaitingForServicesInitialization:
+      return "WaitingForServicesInitialization";
     case CollaborationServiceStep::kLinkReadyAfterGroupCreation:
       return "LinkReadyAfterGroupCreation";
     case CollaborationServiceStep::kTabGroupFetchedAfterPeopleGroupJoined:
@@ -379,7 +380,11 @@
 void RecordLatency(data_sharing::Logger* logger,
                    CollaborationServiceStep step,
                    base::TimeDelta duration) {
-  base::UmaHistogramMediumTimes("CollaborationService.Latency", duration);
+  std::string histogram_name =
+      base::StrCat({"CollaborationService.Latency.",
+                    CollaborationServiceStepToString(step)});
+
+  base::UmaHistogramMediumTimes(histogram_name, duration);
   DATA_SHARING_LOG(logger_common::mojom::LogSource::CollaborationService,
                    logger, CreateLatencyLogToString(step, duration));
 }
diff --git a/components/collaboration/internal/metrics.h b/components/collaboration/internal/metrics.h
index 1ef7823..9ee32aa8 100644
--- a/components/collaboration/internal/metrics.h
+++ b/components/collaboration/internal/metrics.h
@@ -96,19 +96,14 @@
 };
 // LINT.ThenChange(//tools/metrics/histograms/metadata/collaboration_service/enums.xml:CollaborationServiceShareOrManageEvent)
 
-// Steps in a collaboration flow that has user wait time.
-// These values are persisted to logs. Entries should not be renumbered and
-// number values should never be reused.
-// LINT.IfChange(CollaborationServiceStep)
 enum class CollaborationServiceStep {
   kUnknown = 0,
-  kAuthenticationSuccess = 1,
-  kServicesInitialized = 2,
+  kAuthenticationInitToSuccess = 1,
+  kWaitingForServicesInitialization = 2,
   kLinkReadyAfterGroupCreation = 3,
   kTabGroupFetchedAfterPeopleGroupJoined = 4,
   kMaxValue = kTabGroupFetchedAfterPeopleGroupJoined,
 };
-// LINT.ThenChange(//tools/metrics/histograms/metadata/collaboration_service/enums.xml:CollaborationServiceStep)
 
 void RecordJoinEvent(data_sharing::Logger* logger,
                      CollaborationServiceJoinEvent event);
diff --git a/components/enterprise/client_certificates/core/BUILD.gn b/components/enterprise/client_certificates/core/BUILD.gn
index 97fc7fd..56ef7430 100644
--- a/components/enterprise/client_certificates/core/BUILD.gn
+++ b/components/enterprise/client_certificates/core/BUILD.gn
@@ -108,6 +108,12 @@
     "upload_client_error.cc",
   ]
 
+  if (is_win) {
+    public += [ "win/windows_software_private_key_factory.h" ]
+
+    sources += [ "win/windows_software_private_key_factory.cc" ]
+  }
+
   public_deps = [
     "//base",
     "//components/enterprise/client_certificates/proto:db_client_certs",
@@ -190,6 +196,10 @@
     "unexportable_private_key_unittest.cc",
   ]
 
+  if (is_win) {
+    sources += [ "win/windows_software_private_key_factory_unittest.cc" ]
+  }
+
   deps = [
     ":cloud_management_delegate",
     ":core",
diff --git a/components/enterprise/client_certificates/core/features.cc b/components/enterprise/client_certificates/core/features.cc
index c1e64cf5..9262a96 100644
--- a/components/enterprise/client_certificates/core/features.cc
+++ b/components/enterprise/client_certificates/core/features.cc
@@ -4,6 +4,10 @@
 
 #include "components/enterprise/client_certificates/core/features.h"
 
+#if BUILDFLAG(IS_WIN)
+#include "crypto/features.h"
+#endif  // BUILDFLAG(IS_WIN)
+
 namespace client_certificates::features {
 
 BASE_FEATURE(kManagedClientCertificateForUserEnabled,
@@ -30,4 +34,17 @@
   return base::FeatureList::IsEnabled(kManagedUserClientCertificateInPrefs);
 }
 
+#if BUILDFLAG(IS_WIN)
+BASE_FEATURE(kWindowsSoftwareKeysEnabled,
+             "WindowsSoftwareKeysEnabled",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
+bool AreWindowsSoftwareKeysEnabled() {
+  // Windows Software keys depend on a fix in the //crypto layer.
+  return base::FeatureList::IsEnabled(
+             crypto::features::kIsHardwareBackedFixEnabled) &&
+         base::FeatureList::IsEnabled(kWindowsSoftwareKeysEnabled);
+}
+#endif  // BUILDFLAG(IS_WIN)
+
 }  // namespace client_certificates::features
diff --git a/components/enterprise/client_certificates/core/features.h b/components/enterprise/client_certificates/core/features.h
index 5a63a68..8ae7dfd 100644
--- a/components/enterprise/client_certificates/core/features.h
+++ b/components/enterprise/client_certificates/core/features.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_ENTERPRISE_CLIENT_CERTIFICATES_CORE_FEATURES_H_
 
 #include "base/feature_list.h"
+#include "build/build_config.h"
 
 namespace client_certificates::features {
 
@@ -29,6 +30,14 @@
 // Return true if the managed user certificate should be stored in prefs.
 bool IsManagedUserClientCertificateInPrefsEnabled();
 
+#if BUILDFLAG(IS_WIN)
+// Controls whether Windows software keys are enabled or not.
+BASE_DECLARE_FEATURE(kWindowsSoftwareKeysEnabled);
+
+// Return true if Windows software keys are enabled.
+bool AreWindowsSoftwareKeysEnabled();
+#endif  // BUILDFLAG(IS_WIN)
+
 }  // namespace client_certificates::features
 
 #endif  // COMPONENTS_ENTERPRISE_CLIENT_CERTIFICATES_CORE_FEATURES_H_
diff --git a/components/enterprise/client_certificates/core/key_upload_client.cc b/components/enterprise/client_certificates/core/key_upload_client.cc
index d407025..9a373be 100644
--- a/components/enterprise/client_certificates/core/key_upload_client.cc
+++ b/components/enterprise/client_certificates/core/key_upload_client.cc
@@ -37,6 +37,7 @@
     case PrivateKeySource::kUnexportableKey:
       return BPKUR::CHROME_BROWSER_HW_KEY;
     case PrivateKeySource::kSoftwareKey:
+    case PrivateKeySource::kOsSoftwareKey:
       return BPKUR::CHROME_BROWSER_OS_KEY;
   }
 }
diff --git a/components/enterprise/client_certificates/core/private_key_factory.cc b/components/enterprise/client_certificates/core/private_key_factory.cc
index 1c3d09a..8b578364 100644
--- a/components/enterprise/client_certificates/core/private_key_factory.cc
+++ b/components/enterprise/client_certificates/core/private_key_factory.cc
@@ -15,6 +15,18 @@
 
 namespace client_certificates {
 
+namespace {
+
+// List of all the key sources ordered by security (i.e. first entry yields most
+// secure key source).
+constexpr std::array<PrivateKeySource, 3> kKeySourcesOrderedBySecurity = {
+    PrivateKeySource::kUnexportableKey,
+    PrivateKeySource::kOsSoftwareKey,
+    PrivateKeySource::kSoftwareKey,
+};
+
+}  // namespace
+
 PrivateKeyFactory::PrivateKeyFactory() = default;
 PrivateKeyFactory::~PrivateKeyFactory() = default;
 
@@ -52,21 +64,14 @@
     PrivateKeyFactory::PrivateKeyCallback callback) {
   // Go through the supported key sources in order of most secure to least, and
   // delegate the key creation to that sub factory.
-  if (sub_factories_.contains(PrivateKeySource::kUnexportableKey)) {
-    sub_factories_[PrivateKeySource::kUnexportableKey]->CreatePrivateKey(
-        base::BindOnce(&PrivateKeyFactoryImpl::OnPrivateKeyCreated,
-                       weak_factory_.GetWeakPtr(),
-                       PrivateKeySource::kUnexportableKey,
-                       std::move(callback)));
-    return;
-  }
-
-  if (sub_factories_.contains(PrivateKeySource::kSoftwareKey)) {
-    sub_factories_[PrivateKeySource::kSoftwareKey]->CreatePrivateKey(
-        base::BindOnce(&PrivateKeyFactoryImpl::OnPrivateKeyCreated,
-                       weak_factory_.GetWeakPtr(),
-                       PrivateKeySource::kSoftwareKey, std::move(callback)));
-    return;
+  for (size_t i = 0U; i < kKeySourcesOrderedBySecurity.size(); i++) {
+    PrivateKeySource source = kKeySourcesOrderedBySecurity[i];
+    if (sub_factories_.contains(source)) {
+      sub_factories_[source]->CreatePrivateKey(base::BindOnce(
+          &PrivateKeyFactoryImpl::OnPrivateKeyCreated,
+          weak_factory_.GetWeakPtr(), source, std::move(callback)));
+      return;
+    }
   }
 
   std::move(callback).Run(nullptr);
diff --git a/components/enterprise/client_certificates/core/private_key_factory_unittest.cc b/components/enterprise/client_certificates/core/private_key_factory_unittest.cc
index 4e16028..9dd2ae1 100644
--- a/components/enterprise/client_certificates/core/private_key_factory_unittest.cc
+++ b/components/enterprise/client_certificates/core/private_key_factory_unittest.cc
@@ -113,8 +113,31 @@
   EXPECT_FALSE(test_future.Get());
 }
 
+TEST(PrivateKeyFactoryTest, CreatePrivateKey_OsSoftwareAndSoftware) {
+  auto os_software_factory = CreateMockedFactory();
+  auto software_factory = CreateMockedFactory();
+
+  EXPECT_CALL(*os_software_factory, CreatePrivateKey(_))
+      .WillOnce(Invoke([](PrivateKeyFactory::PrivateKeyCallback callback) {
+        std::move(callback).Run(base::MakeRefCounted<MockPrivateKey>());
+      }));
+
+  PrivateKeyFactory::PrivateKeyFactoriesMap map;
+  map.insert_or_assign(PrivateKeySource::kOsSoftwareKey,
+                       std::move(os_software_factory));
+  map.insert_or_assign(PrivateKeySource::kSoftwareKey,
+                       std::move(software_factory));
+  auto factory = PrivateKeyFactory::Create(std::move(map));
+
+  base::test::TestFuture<scoped_refptr<PrivateKey>> test_future;
+  factory->CreatePrivateKey(test_future.GetCallback());
+
+  EXPECT_TRUE(test_future.Get());
+}
+
 TEST(PrivateKeyFactoryTest, CreatePrivateKey_AllSources) {
   auto unexportable_factory = CreateMockedFactory();
+  auto os_software_factory = CreateMockedFactory();
   auto software_factory = CreateMockedFactory();
 
   EXPECT_CALL(*unexportable_factory, CreatePrivateKey(_))
@@ -123,6 +146,8 @@
       }));
 
   PrivateKeyFactory::PrivateKeyFactoriesMap map;
+  map.insert_or_assign(PrivateKeySource::kOsSoftwareKey,
+                       std::move(os_software_factory));
   map.insert_or_assign(PrivateKeySource::kSoftwareKey,
                        std::move(software_factory));
   map.insert_or_assign(PrivateKeySource::kUnexportableKey,
@@ -137,6 +162,7 @@
 
 TEST(PrivateKeyFactoryTest, CreatePrivateKey_AllSources_UnexportableFail) {
   auto unexportable_factory = CreateMockedFactory();
+  auto os_software_factory = CreateMockedFactory();
   auto software_factory = CreateMockedFactory();
 
   EXPECT_CALL(*unexportable_factory, CreatePrivateKey(_))
@@ -150,6 +176,8 @@
       }));
 
   PrivateKeyFactory::PrivateKeyFactoriesMap map;
+  map.insert_or_assign(PrivateKeySource::kOsSoftwareKey,
+                       std::move(os_software_factory));
   map.insert_or_assign(PrivateKeySource::kSoftwareKey,
                        std::move(software_factory));
   map.insert_or_assign(PrivateKeySource::kUnexportableKey,
@@ -164,6 +192,7 @@
 
 TEST(PrivateKeyFactoryTest, CreatePrivateKey_AllSources_AllFail) {
   auto unexportable_factory = CreateMockedFactory();
+  auto os_software_factory = CreateMockedFactory();
   auto software_factory = CreateMockedFactory();
 
   EXPECT_CALL(*unexportable_factory, CreatePrivateKey(_))
@@ -177,6 +206,8 @@
       }));
 
   PrivateKeyFactory::PrivateKeyFactoriesMap map;
+  map.insert_or_assign(PrivateKeySource::kOsSoftwareKey,
+                       std::move(os_software_factory));
   map.insert_or_assign(PrivateKeySource::kSoftwareKey,
                        std::move(software_factory));
   map.insert_or_assign(PrivateKeySource::kUnexportableKey,
@@ -191,6 +222,7 @@
 
 TEST(PrivateKeyFactoryTest, LoadPrivateKey_AllSources_Unexportable) {
   auto unexportable_factory = CreateMockedFactory();
+  auto os_software_factory = CreateMockedFactory();
   auto software_factory = CreateMockedFactory();
 
   client_certificates_pb::PrivateKey serialized_private_key;
@@ -208,6 +240,8 @@
           }));
 
   PrivateKeyFactory::PrivateKeyFactoriesMap map;
+  map.insert_or_assign(PrivateKeySource::kOsSoftwareKey,
+                       std::move(os_software_factory));
   map.insert_or_assign(PrivateKeySource::kSoftwareKey,
                        std::move(software_factory));
   map.insert_or_assign(PrivateKeySource::kUnexportableKey,
@@ -222,6 +256,7 @@
 
 TEST(PrivateKeyFactoryTest, LoadPrivateKeyFromDict_AllSources_Unexportable) {
   auto unexportable_factory = CreateMockedFactory();
+  auto os_software_factory = CreateMockedFactory();
   auto software_factory = CreateMockedFactory();
 
   base::Value::Dict serialized_private_key;
@@ -234,12 +269,49 @@
           Invoke([&unexportable_source](
                      const base::Value::Dict& serialized_private_key_param,
                      PrivateKeyFactory::PrivateKeyCallback callback) {
-            EXPECT_EQ(unexportable_source,
-                      *serialized_private_key_param.FindInt(kKeySource));
+            EXPECT_EQ(*serialized_private_key_param.FindInt(kKeySource),
+                      unexportable_source);
             std::move(callback).Run(base::MakeRefCounted<MockPrivateKey>());
           }));
 
   PrivateKeyFactory::PrivateKeyFactoriesMap map;
+  map.insert_or_assign(PrivateKeySource::kOsSoftwareKey,
+                       std::move(os_software_factory));
+  map.insert_or_assign(PrivateKeySource::kSoftwareKey,
+                       std::move(software_factory));
+  map.insert_or_assign(PrivateKeySource::kUnexportableKey,
+                       std::move(unexportable_factory));
+  auto factory = PrivateKeyFactory::Create(std::move(map));
+
+  base::test::TestFuture<scoped_refptr<PrivateKey>> test_future;
+  factory->LoadPrivateKeyFromDict(serialized_private_key,
+                                  test_future.GetCallback());
+
+  EXPECT_TRUE(test_future.Get());
+}
+
+TEST(PrivateKeyFactoryTest, LoadPrivateKeyFromDict_AllSources_OsSoftware) {
+  auto unexportable_factory = CreateMockedFactory();
+  auto os_software_factory = CreateMockedFactory();
+  auto software_factory = CreateMockedFactory();
+
+  base::Value::Dict serialized_private_key;
+  int expected_source = static_cast<int>(PrivateKeySource::kOsSoftwareKey);
+  serialized_private_key.Set(kKeySource, expected_source);
+
+  EXPECT_CALL(*os_software_factory, LoadPrivateKeyFromDict(_, _))
+      .WillOnce(
+          Invoke([&expected_source](
+                     const base::Value::Dict& serialized_private_key_param,
+                     PrivateKeyFactory::PrivateKeyCallback callback) {
+            EXPECT_EQ(*serialized_private_key_param.FindInt(kKeySource),
+                      expected_source);
+            std::move(callback).Run(base::MakeRefCounted<MockPrivateKey>());
+          }));
+
+  PrivateKeyFactory::PrivateKeyFactoriesMap map;
+  map.insert_or_assign(PrivateKeySource::kOsSoftwareKey,
+                       std::move(os_software_factory));
   map.insert_or_assign(PrivateKeySource::kSoftwareKey,
                        std::move(software_factory));
   map.insert_or_assign(PrivateKeySource::kUnexportableKey,
diff --git a/components/enterprise/client_certificates/core/private_key_types.cc b/components/enterprise/client_certificates/core/private_key_types.cc
index 616dd69..05786c38b 100644
--- a/components/enterprise/client_certificates/core/private_key_types.cc
+++ b/components/enterprise/client_certificates/core/private_key_types.cc
@@ -13,6 +13,8 @@
       return PrivateKeySource::kUnexportableKey;
     case client_certificates_pb::PrivateKey::PRIVATE_SOFTWARE_KEY:
       return PrivateKeySource::kSoftwareKey;
+    case client_certificates_pb::PrivateKey::PRIVATE_OS_SOFTWARE_KEY:
+      return PrivateKeySource::kOsSoftwareKey;
     default:
       return std::nullopt;
   }
@@ -25,6 +27,8 @@
       return client_certificates_pb::PrivateKey::PRIVATE_UNEXPORTABLE_KEY;
     case PrivateKeySource::kSoftwareKey:
       return client_certificates_pb::PrivateKey::PRIVATE_SOFTWARE_KEY;
+    case PrivateKeySource::kOsSoftwareKey:
+      return client_certificates_pb::PrivateKey::PRIVATE_OS_SOFTWARE_KEY;
   }
 }
 
@@ -34,6 +38,8 @@
       return PrivateKeySource::kUnexportableKey;
     case 1:
       return PrivateKeySource::kSoftwareKey;
+    case 2:
+      return PrivateKeySource::kOsSoftwareKey;
     default:
       return std::nullopt;
   }
diff --git a/components/enterprise/client_certificates/core/private_key_types.h b/components/enterprise/client_certificates/core/private_key_types.h
index aebfaae..c9cae715 100644
--- a/components/enterprise/client_certificates/core/private_key_types.h
+++ b/components/enterprise/client_certificates/core/private_key_types.h
@@ -23,7 +23,10 @@
   // mechanism.
   kSoftwareKey = 1,
 
-  kMaxValue = kSoftwareKey
+  // Key created by the operating system that is not hardware-backed.
+  kOsSoftwareKey = 2,
+
+  kMaxValue = kOsSoftwareKey
 };
 
 // Converts a `proto_key_source` from the proto values to the C++ enum values.
diff --git a/components/enterprise/client_certificates/core/unexportable_private_key.cc b/components/enterprise/client_certificates/core/unexportable_private_key.cc
index 0bf4d8a9..4a62044 100644
--- a/components/enterprise/client_certificates/core/unexportable_private_key.cc
+++ b/components/enterprise/client_certificates/core/unexportable_private_key.cc
@@ -14,7 +14,13 @@
 
 UnexportablePrivateKey::UnexportablePrivateKey(
     std::unique_ptr<crypto::UnexportableSigningKey> key)
-    : PrivateKey(PrivateKeySource::kUnexportableKey,
+    : UnexportablePrivateKey(std::move(key),
+                             PrivateKeySource::kUnexportableKey) {}
+
+UnexportablePrivateKey::UnexportablePrivateKey(
+    std::unique_ptr<crypto::UnexportableSigningKey> key,
+    PrivateKeySource key_source)
+    : PrivateKey(key_source,
                  SSLKeyConverter::Get()->ConvertUnexportableKeySlowly(*key)),
       key_(std::move(key)) {
   CHECK(key_);
diff --git a/components/enterprise/client_certificates/core/unexportable_private_key.h b/components/enterprise/client_certificates/core/unexportable_private_key.h
index d5dc4700..5205d0b 100644
--- a/components/enterprise/client_certificates/core/unexportable_private_key.h
+++ b/components/enterprise/client_certificates/core/unexportable_private_key.h
@@ -19,9 +19,16 @@
 
 class UnexportablePrivateKey : public PrivateKey {
  public:
+  // Wraps `key` and associates it with PrivateKeySource::kUnexportableKey.
   explicit UnexportablePrivateKey(
       std::unique_ptr<crypto::UnexportableSigningKey> key);
 
+  // Not all crypto::UnexportableSigningKey are TPM-backed, so allow
+  // reusing this class by enabling the association of `key` with parameterized
+  // `key_source`.
+  UnexportablePrivateKey(std::unique_ptr<crypto::UnexportableSigningKey> key,
+                         PrivateKeySource key_source);
+
   // PrivateKey:
   std::optional<std::vector<uint8_t>> SignSlowly(
       base::span<const uint8_t> data) const override;
diff --git a/components/enterprise/client_certificates/core/unexportable_private_key_factory_unittest.cc b/components/enterprise/client_certificates/core/unexportable_private_key_factory_unittest.cc
index c7248e6..f565fbc 100644
--- a/components/enterprise/client_certificates/core/unexportable_private_key_factory_unittest.cc
+++ b/components/enterprise/client_certificates/core/unexportable_private_key_factory_unittest.cc
@@ -24,6 +24,8 @@
   ASSERT_TRUE(loaded_key);
   EXPECT_NE(key, loaded_key);
   EXPECT_EQ(key->GetAlgorithm(), loaded_key->GetAlgorithm());
+  EXPECT_EQ(key->GetSource(), loaded_key->GetSource());
+  EXPECT_EQ(key->GetSource(), PrivateKeySource::kUnexportableKey);
   ASSERT_THAT(key->GetSubjectPublicKeyInfo(),
               testing::ElementsAreArray(loaded_key->GetSubjectPublicKeyInfo()));
   ASSERT_TRUE(key->GetSSLPrivateKey());
diff --git a/components/enterprise/client_certificates/core/unexportable_private_key_unittest.cc b/components/enterprise/client_certificates/core/unexportable_private_key_unittest.cc
index a88faeb6..db300dfb 100644
--- a/components/enterprise/client_certificates/core/unexportable_private_key_unittest.cc
+++ b/components/enterprise/client_certificates/core/unexportable_private_key_unittest.cc
@@ -50,4 +50,36 @@
   EXPECT_GT(dict_key.FindString(kKey)->size(), 0U);
 }
 
+TEST(UnexportablePrivateKeyTest, SupportedCreateKeySoftware) {
+  ScopedSSLKeyConverter scoped_converter;
+  auto provider = crypto::GetUnexportableKeyProvider(/*config=*/{});
+  ASSERT_TRUE(provider);
+
+  // The mock only works with the ECDSA_SHA256 algorithm.
+  std::array<crypto::SignatureVerifier::SignatureAlgorithm, 1>
+      kAcceptableAlgorithms = {crypto::SignatureVerifier::ECDSA_SHA256};
+  auto unexportable_key =
+      provider->GenerateSigningKeySlowly(kAcceptableAlgorithms);
+  ASSERT_TRUE(unexportable_key);
+
+  auto private_key = base::MakeRefCounted<UnexportablePrivateKey>(
+      std::move(unexportable_key), PrivateKeySource::kOsSoftwareKey);
+
+  auto spki_bytes = private_key->GetSubjectPublicKeyInfo();
+  EXPECT_GT(spki_bytes.size(), 0U);
+  EXPECT_EQ(private_key->GetAlgorithm(),
+            crypto::SignatureVerifier::ECDSA_SHA256);
+  EXPECT_TRUE(private_key->SignSlowly(spki_bytes).has_value());
+
+  auto proto_key = private_key->ToProto();
+  EXPECT_EQ(proto_key.source(),
+            client_certificates_pb::PrivateKey::PRIVATE_OS_SOFTWARE_KEY);
+  EXPECT_GT(proto_key.wrapped_key().size(), 0U);
+
+  auto dict_key = private_key->ToDict();
+  EXPECT_EQ(*dict_key.FindInt(kKeySource),
+            static_cast<int>(PrivateKeySource::kOsSoftwareKey));
+  EXPECT_GT(dict_key.FindString(kKey)->size(), 0U);
+}
+
 }  // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/win/windows_software_private_key_factory.cc b/components/enterprise/client_certificates/core/win/windows_software_private_key_factory.cc
new file mode 100644
index 0000000..8f197fd
--- /dev/null
+++ b/components/enterprise/client_certificates/core/win/windows_software_private_key_factory.cc
@@ -0,0 +1,133 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/enterprise/client_certificates/core/win/windows_software_private_key_factory.h"
+
+#include <array>
+#include <optional>
+#include <utility>
+#include <vector>
+
+#include "base/base64.h"
+#include "base/check.h"
+#include "base/functional/bind.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "components/enterprise/client_certificates/core/constants.h"
+#include "components/enterprise/client_certificates/core/private_key.h"
+#include "components/enterprise/client_certificates/core/private_key_types.h"
+#include "components/enterprise/client_certificates/core/unexportable_private_key.h"
+#include "crypto/unexportable_key.h"
+#include "net/ssl/ssl_private_key.h"
+
+namespace client_certificates {
+
+namespace {
+
+scoped_refptr<UnexportablePrivateKey> CreateKey() {
+  auto provider = crypto::GetMicrosoftSoftwareUnexportableKeyProvider();
+  if (!provider) {
+    return nullptr;
+  }
+
+  static constexpr std::array<crypto::SignatureVerifier::SignatureAlgorithm, 2>
+      kAcceptableAlgorithms = {crypto::SignatureVerifier::ECDSA_SHA256,
+                               crypto::SignatureVerifier::RSA_PKCS1_SHA256};
+  auto key = provider->GenerateSigningKeySlowly(kAcceptableAlgorithms);
+
+  if (!key) {
+    return nullptr;
+  }
+
+  return base::MakeRefCounted<UnexportablePrivateKey>(
+      std::move(key), PrivateKeySource::kOsSoftwareKey);
+}
+
+scoped_refptr<UnexportablePrivateKey> LoadKeyFromWrapped(
+    const std::vector<uint8_t>& wrapped_key) {
+  auto provider = crypto::GetMicrosoftSoftwareUnexportableKeyProvider();
+  if (!provider) {
+    return nullptr;
+  }
+
+  auto key = provider->FromWrappedSigningKeySlowly(wrapped_key);
+  if (!key) {
+    return nullptr;
+  }
+
+  return base::MakeRefCounted<UnexportablePrivateKey>(
+      std::move(key), PrivateKeySource::kOsSoftwareKey);
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<WindowsSoftwarePrivateKeyFactory>
+WindowsSoftwarePrivateKeyFactory::TryCreate() {
+  auto provider = crypto::GetMicrosoftSoftwareUnexportableKeyProvider();
+
+  if (!provider) {
+    // OS software keys are not supported.
+    return nullptr;
+  }
+
+  return base::WrapUnique<WindowsSoftwarePrivateKeyFactory>(
+      new WindowsSoftwarePrivateKeyFactory());
+}
+
+WindowsSoftwarePrivateKeyFactory::WindowsSoftwarePrivateKeyFactory() = default;
+
+WindowsSoftwarePrivateKeyFactory::~WindowsSoftwarePrivateKeyFactory() = default;
+
+void WindowsSoftwarePrivateKeyFactory::CreatePrivateKey(
+    PrivateKeyCallback callback) {
+  base::ThreadPool::PostTaskAndReplyWithResult(FROM_HERE, {base::MayBlock()},
+                                               base::BindOnce(CreateKey),
+                                               std::move(callback));
+}
+
+void WindowsSoftwarePrivateKeyFactory::LoadPrivateKey(
+    const client_certificates_pb::PrivateKey& serialized_private_key,
+    PrivateKeyCallback callback) {
+  auto private_key_source = ToPrivateKeySource(serialized_private_key.source());
+  CHECK(private_key_source.has_value());
+  CHECK(private_key_source.value() == PrivateKeySource::kOsSoftwareKey);
+
+  const auto& wrapped_key_str = serialized_private_key.wrapped_key();
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()},
+      base::BindOnce(
+          LoadKeyFromWrapped,
+          std::vector<uint8_t>(wrapped_key_str.begin(), wrapped_key_str.end())),
+      std::move(callback));
+}
+
+void WindowsSoftwarePrivateKeyFactory::LoadPrivateKeyFromDict(
+    const base::Value::Dict& serialized_private_key,
+    PrivateKeyCallback callback) {
+  std::optional<int> source = serialized_private_key.FindInt(kKeySource);
+  auto* encoded_wrapped_private_key = serialized_private_key.FindString(kKey);
+
+  // Supposed to have been already checked by the parent factory.
+  CHECK(source);
+  auto source_enum = ToPrivateKeySource(source.value());
+  CHECK(source_enum);
+
+  CHECK(encoded_wrapped_private_key);
+  std::string decoded_wrapped_private_key;
+  if (!base::Base64Decode(*encoded_wrapped_private_key,
+                          &decoded_wrapped_private_key)) {
+    std::move(callback).Run(nullptr);
+    return;
+  }
+
+  client_certificates_pb::PrivateKey private_key_proto;
+  private_key_proto.set_source(ToProtoKeySource(source_enum.value()));
+  private_key_proto.set_wrapped_key(std::move(decoded_wrapped_private_key));
+  LoadPrivateKey(private_key_proto, std::move(callback));
+}
+
+}  // namespace client_certificates
diff --git a/components/enterprise/client_certificates/core/win/windows_software_private_key_factory.h b/components/enterprise/client_certificates/core/win/windows_software_private_key_factory.h
new file mode 100644
index 0000000..1447960
--- /dev/null
+++ b/components/enterprise/client_certificates/core/win/windows_software_private_key_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_ENTERPRISE_CLIENT_CERTIFICATES_CORE_WIN_WINDOWS_SOFTWARE_PRIVATE_KEY_FACTORY_H_
+#define COMPONENTS_ENTERPRISE_CLIENT_CERTIFICATES_CORE_WIN_WINDOWS_SOFTWARE_PRIVATE_KEY_FACTORY_H_
+
+#include <memory>
+
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "components/enterprise/client_certificates/core/private_key_factory.h"
+
+namespace client_certificates {
+
+class WindowsSoftwarePrivateKeyFactory : public PrivateKeyFactory {
+ public:
+  // Will return a factory instance only if the creation of
+  // software keys via the OS is supported on the current device.
+  // Otherwise, will return nullptr.
+  static std::unique_ptr<WindowsSoftwarePrivateKeyFactory> TryCreate();
+
+  ~WindowsSoftwarePrivateKeyFactory() override;
+
+  // PrivateKeyFactory:
+  void CreatePrivateKey(PrivateKeyCallback callback) override;
+  void LoadPrivateKey(
+      const client_certificates_pb::PrivateKey& serialized_private_key,
+      PrivateKeyCallback callback) override;
+  void LoadPrivateKeyFromDict(const base::Value::Dict& serialized_private_key,
+                              PrivateKeyCallback callback) override;
+
+ private:
+  WindowsSoftwarePrivateKeyFactory();
+
+  base::WeakPtrFactory<WindowsSoftwarePrivateKeyFactory> weak_factory_{this};
+};
+
+}  // namespace client_certificates
+
+#endif  // COMPONENTS_ENTERPRISE_CLIENT_CERTIFICATES_CORE_WIN_WINDOWS_SOFTWARE_PRIVATE_KEY_FACTORY_H_
diff --git a/components/enterprise/client_certificates/core/win/windows_software_private_key_factory_unittest.cc b/components/enterprise/client_certificates/core/win/windows_software_private_key_factory_unittest.cc
new file mode 100644
index 0000000..3f1c5da
--- /dev/null
+++ b/components/enterprise/client_certificates/core/win/windows_software_private_key_factory_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/enterprise/client_certificates/core/win/windows_software_private_key_factory.h"
+
+#include "base/memory/scoped_refptr.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "components/enterprise/client_certificates/core/constants.h"
+#include "components/enterprise/client_certificates/core/private_key.h"
+#include "components/enterprise/client_certificates/core/private_key_types.h"
+#include "components/enterprise/client_certificates/core/scoped_ssl_key_converter.h"
+#include "net/ssl/ssl_private_key.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace client_certificates {
+
+namespace {
+
+void ValidatePrivateKey(scoped_refptr<PrivateKey> key,
+                        scoped_refptr<PrivateKey> loaded_key) {
+  ASSERT_TRUE(loaded_key);
+  EXPECT_NE(key, loaded_key);
+  EXPECT_EQ(key->GetAlgorithm(), loaded_key->GetAlgorithm());
+  EXPECT_EQ(key->GetSource(), loaded_key->GetSource());
+  EXPECT_EQ(key->GetSource(), PrivateKeySource::kOsSoftwareKey);
+  ASSERT_THAT(key->GetSubjectPublicKeyInfo(),
+              testing::ElementsAreArray(loaded_key->GetSubjectPublicKeyInfo()));
+  ASSERT_TRUE(key->GetSSLPrivateKey());
+}
+
+}  // namespace
+
+TEST(WindowsSoftwarePrivateKeyFactoryTest, SupportedCreateKey_LoadKey) {
+  base::test::TaskEnvironment task_environment;
+  ScopedSSLKeyConverter scoped_converter;
+
+  auto factory = WindowsSoftwarePrivateKeyFactory::TryCreate();
+
+  ASSERT_TRUE(factory);
+
+  base::test::TestFuture<scoped_refptr<PrivateKey>> create_key_future;
+  factory->CreatePrivateKey(create_key_future.GetCallback());
+
+  auto private_key = create_key_future.Get();
+  ASSERT_TRUE(private_key);
+
+  base::test::TestFuture<scoped_refptr<PrivateKey>> load_key_future;
+  auto proto_key = private_key->ToProto();
+  factory->LoadPrivateKey(std::move(proto_key), load_key_future.GetCallback());
+  ValidatePrivateKey(private_key, load_key_future.Get());
+}
+
+TEST(WindowsSoftwarePrivateKeyFactoryTest, SupportedCreateKey_LoadKeyFromDict) {
+  base::test::TaskEnvironment task_environment;
+  ScopedSSLKeyConverter scoped_converter;
+
+  auto factory = WindowsSoftwarePrivateKeyFactory::TryCreate();
+
+  ASSERT_TRUE(factory);
+
+  base::test::TestFuture<scoped_refptr<PrivateKey>> create_key_future;
+  factory->CreatePrivateKey(create_key_future.GetCallback());
+
+  auto private_key = create_key_future.Get();
+  ASSERT_TRUE(private_key);
+
+  base::test::TestFuture<scoped_refptr<PrivateKey>> load_key_future;
+  auto dict_key = private_key->ToDict();
+  factory->LoadPrivateKeyFromDict(dict_key, load_key_future.GetCallback());
+  ValidatePrivateKey(private_key, load_key_future.Get());
+
+  base::test::TestFuture<scoped_refptr<PrivateKey>>
+      load_key_fails_future_invalid_key;
+  dict_key.Set(kKey, "");
+  dict_key.Set(kKeySource, static_cast<int>(PrivateKeySource::kOsSoftwareKey));
+  factory->LoadPrivateKeyFromDict(
+      dict_key, load_key_fails_future_invalid_key.GetCallback());
+  EXPECT_FALSE(load_key_fails_future_invalid_key.Get());
+}
+
+TEST(WindowsSoftwarePrivateKeyFactoryTest, UnsupportedCreateKey) {
+  ScopedSSLKeyConverter scoped_converter(/*supports_unexportable=*/false);
+
+  auto factory = WindowsSoftwarePrivateKeyFactory::TryCreate();
+
+  EXPECT_FALSE(factory);
+}
+
+}  // namespace client_certificates
diff --git a/components/enterprise/client_certificates/proto/client_certificates_database.proto b/components/enterprise/client_certificates/proto/client_certificates_database.proto
index de8c64e9..c7da767 100644
--- a/components/enterprise/client_certificates/proto/client_certificates_database.proto
+++ b/components/enterprise/client_certificates/proto/client_certificates_database.proto
@@ -16,6 +16,8 @@
     PRIVATE_UNEXPORTABLE_KEY = 1;
     // Chrome Browser with the key stored at OS level.
     PRIVATE_SOFTWARE_KEY = 2;
+    // Chrome Browser with the key stored in OS key storage.
+    PRIVATE_OS_SOFTWARE_KEY = 3;
   }
 
   // Represents the source of the private key, which will dictate how
diff --git a/components/neterror/resources/BUILD.gn b/components/neterror/resources/BUILD.gn
index c3c4cf66..b265794 100644
--- a/components/neterror/resources/BUILD.gn
+++ b/components/neterror/resources/BUILD.gn
@@ -15,7 +15,7 @@
   "dino_game/cloud.ts",
   "dino_game/constants.ts",
   "dino_game/dimensions.ts",
-  "dino_game/distance_meter.js",
+  "dino_game/distance_meter.ts",
   "dino_game/generated_sound_fx.ts",
   "dino_game/game_over_panel.js",
   "dino_game/horizon_line.ts",
diff --git a/components/neterror/resources/dino_game/distance_meter.js b/components/neterror/resources/dino_game/distance_meter.js
deleted file mode 100644
index 10046a7ca..0000000
--- a/components/neterror/resources/dino_game/distance_meter.js
+++ /dev/null
@@ -1,418 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {IS_HIDPI, IS_RTL} from './constants.js';
-import {Runner} from './offline.js';
-import {getTimeStamp} from './utils.js';
-
-export class DistanceMeter {
-  /**
-   * Handles displaying the distance meter.
-   * @param {!HTMLCanvasElement} canvas
-   * @param {Object} spritePos Image position in sprite.
-   * @param {number} canvasWidth
-   */
-  constructor(canvas, spritePos, canvasWidth) {
-    this.canvas = canvas;
-    this.canvasCtx =
-        /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d'));
-    this.image = Runner.imageSprite;
-    this.spritePos = spritePos;
-    this.x = 0;
-    this.y = 5;
-
-    this.currentDistance = 0;
-    this.maxScore = 0;
-    this.highScore = '0';
-    this.container = null;
-
-    this.digits = [];
-    this.achievement = false;
-    this.defaultString = '';
-    this.flashTimer = 0;
-    this.flashIterations = 0;
-    this.invertTrigger = false;
-    this.flashingRafId = null;
-    this.highScoreBounds = {};
-    this.highScoreFlashing = false;
-
-    this.config = DistanceMeter.config;
-    this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS;
-    this.canvasWidth = canvasWidth;
-    this.init(canvasWidth);
-  }
-
-
-  /**
-   * Initialise the distance meter to '00000'.
-   * @param {number} width Canvas width in px.
-   */
-  init(width) {
-    let maxDistanceStr = '';
-
-    this.calcXPos(width);
-    this.maxScore = this.maxScoreUnits;
-    for (let i = 0; i < this.maxScoreUnits; i++) {
-      this.draw(i, 0);
-      this.defaultString += '0';
-      maxDistanceStr += '9';
-    }
-
-    this.maxScore = parseInt(maxDistanceStr, 10);
-  }
-
-  /**
-   * Calculate the xPos in the canvas.
-   * @param {number} canvasWidth
-   */
-  calcXPos(canvasWidth) {
-    this.x = canvasWidth -
-        (DistanceMeter.dimensions.DEST_WIDTH * (this.maxScoreUnits + 1));
-  }
-
-  /**
-   * Draw a digit to canvas.
-   * @param {number} digitPos Position of the digit.
-   * @param {number} value Digit value 0-9.
-   * @param {boolean=} opt_highScore Whether drawing the high score.
-   */
-  draw(digitPos, value, opt_highScore) {
-    let sourceWidth = DistanceMeter.dimensions.WIDTH;
-    let sourceHeight = DistanceMeter.dimensions.HEIGHT;
-    let sourceX = DistanceMeter.dimensions.WIDTH * value;
-    let sourceY = 0;
-
-    const targetX = digitPos * DistanceMeter.dimensions.DEST_WIDTH;
-    const targetY = this.y;
-    const targetWidth = DistanceMeter.dimensions.WIDTH;
-    const targetHeight = DistanceMeter.dimensions.HEIGHT;
-
-    // For high DPI we 2x source values.
-    if (IS_HIDPI) {
-      sourceWidth *= 2;
-      sourceHeight *= 2;
-      sourceX *= 2;
-    }
-
-    sourceX += this.spritePos.x;
-    sourceY += this.spritePos.y;
-
-    this.canvasCtx.save();
-
-    if (IS_RTL) {
-      if (opt_highScore) {
-        this.canvasCtx.translate(
-            this.canvasWidth -
-                (DistanceMeter.dimensions.WIDTH * (this.maxScoreUnits + 3)),
-            this.y);
-      } else {
-        this.canvasCtx.translate(
-            this.canvasWidth - DistanceMeter.dimensions.WIDTH, this.y);
-      }
-      this.canvasCtx.scale(-1, 1);
-    } else {
-      const highScoreX =
-          this.x - (this.maxScoreUnits * 2) * DistanceMeter.dimensions.WIDTH;
-      if (opt_highScore) {
-        this.canvasCtx.translate(highScoreX, this.y);
-      } else {
-        this.canvasCtx.translate(this.x, this.y);
-      }
-    }
-
-    this.canvasCtx.drawImage(
-        this.image,
-        sourceX,
-        sourceY,
-        sourceWidth,
-        sourceHeight,
-        targetX,
-        targetY,
-        targetWidth,
-        targetHeight,
-    );
-
-    this.canvasCtx.restore();
-  }
-
-  /**
-   * Covert pixel distance to a 'real' distance.
-   * @param {number} distance Pixel distance ran.
-   * @return {number} The 'real' distance ran.
-   */
-  getActualDistance(distance) {
-    return distance ? Math.round(distance * this.config.COEFFICIENT) : 0;
-  }
-
-  /**
-   * Update the distance meter.
-   * @param {number} distance
-   * @param {number} deltaTime
-   * @return {boolean} Whether the achievement sound fx should be played.
-   */
-  update(deltaTime, distance) {
-    let paint = true;
-    let playSound = false;
-
-    if (!this.achievement) {
-      distance = this.getActualDistance(distance);
-      // Score has gone beyond the initial digit count.
-      if (distance > this.maxScore &&
-          this.maxScoreUnits === this.config.MAX_DISTANCE_UNITS) {
-        this.maxScoreUnits++;
-        this.maxScore = parseInt(this.maxScore + '9', 10);
-      } else {
-        this.distance = 0;
-      }
-
-      if (distance > 0) {
-        // Achievement unlocked.
-        if (distance % this.config.ACHIEVEMENT_DISTANCE === 0) {
-          // Flash score and play sound.
-          this.achievement = true;
-          this.flashTimer = 0;
-          playSound = true;
-        }
-
-        // Create a string representation of the distance with leading 0.
-        const distanceStr =
-            (this.defaultString + distance).substr(-this.maxScoreUnits);
-        this.digits = distanceStr.split('');
-      } else {
-        this.digits = this.defaultString.split('');
-      }
-    } else {
-      // Control flashing of the score on reaching achievement.
-      if (this.flashIterations <= this.config.FLASH_ITERATIONS) {
-        this.flashTimer += deltaTime;
-
-        if (this.flashTimer < this.config.FLASH_DURATION) {
-          paint = false;
-        } else if (this.flashTimer > this.config.FLASH_DURATION * 2) {
-          this.flashTimer = 0;
-          this.flashIterations++;
-        }
-      } else {
-        this.achievement = false;
-        this.flashIterations = 0;
-        this.flashTimer = 0;
-      }
-    }
-
-    // Draw the digits if not flashing.
-    if (paint) {
-      for (let i = this.digits.length - 1; i >= 0; i--) {
-        this.draw(i, parseInt(this.digits[i], 10));
-      }
-    }
-
-    this.drawHighScore();
-    return playSound;
-  }
-
-  /**
-   * Draw the high score.
-   */
-  drawHighScore() {
-    if (parseInt(this.highScore, 10) > 0) {
-      this.canvasCtx.save();
-      this.canvasCtx.globalAlpha = .8;
-      for (let i = this.highScore.length - 1; i >= 0; i--) {
-        this.draw(i, parseInt(this.highScore[i], 10), true);
-      }
-      this.canvasCtx.restore();
-    }
-  }
-
-  /**
-   * Set the highscore as a array string.
-   * Position of char in the sprite: H - 10, I - 11.
-   * @param {number} distance Distance ran in pixels.
-   */
-  setHighScore(distance) {
-    distance = this.getActualDistance(distance);
-    const highScoreStr =
-        (this.defaultString + distance).substr(-this.maxScoreUnits);
-
-    this.highScore = ['10', '11', ''].concat(highScoreStr.split(''));
-  }
-
-
-  /**
-   * Whether a clicked is in the high score area.
-   * @param {Event} e Event object.
-   * @return {boolean} Whether the click was in the high score bounds.
-   */
-  hasClickedOnHighScore(e) {
-    let x = 0;
-    let y = 0;
-
-    if (e.touches) {
-      // Bounds for touch differ from pointer.
-      const canvasBounds = this.canvas.getBoundingClientRect();
-      x = e.touches[0].clientX - canvasBounds.left;
-      y = e.touches[0].clientY - canvasBounds.top;
-    } else {
-      x = e.offsetX;
-      y = e.offsetY;
-    }
-
-    this.highScoreBounds = this.getHighScoreBounds();
-    return x >= this.highScoreBounds.x &&
-        x <= this.highScoreBounds.x + this.highScoreBounds.width &&
-        y >= this.highScoreBounds.y &&
-        y <= this.highScoreBounds.y + this.highScoreBounds.height;
-  }
-
-  /**
-   * Get the bounding box for the high score.
-   * @return {Object} Object with x, y, width and height properties.
-   */
-  getHighScoreBounds() {
-    return {
-      x: (this.x - (this.maxScoreUnits * 2) * DistanceMeter.dimensions.WIDTH) -
-          DistanceMeter.config.HIGH_SCORE_HIT_AREA_PADDING,
-      y: this.y,
-      width: DistanceMeter.dimensions.WIDTH * (this.highScore.length + 1) +
-          DistanceMeter.config.HIGH_SCORE_HIT_AREA_PADDING,
-      height: DistanceMeter.dimensions.HEIGHT +
-          (DistanceMeter.config.HIGH_SCORE_HIT_AREA_PADDING * 2),
-    };
-  }
-
-  /**
-   * Animate flashing the high score to indicate ready for resetting.
-   * The flashing stops following this.config.FLASH_ITERATIONS x 2 flashes.
-   */
-  flashHighScore() {
-    const now = getTimeStamp();
-    const deltaTime = now - (this.frameTimeStamp || now);
-    let paint = true;
-    this.frameTimeStamp = now;
-
-    // Reached the max number of flashes.
-    if (this.flashIterations > this.config.FLASH_ITERATIONS * 2) {
-      this.cancelHighScoreFlashing();
-      return;
-    }
-
-    this.flashTimer += deltaTime;
-
-    if (this.flashTimer < this.config.FLASH_DURATION) {
-      paint = false;
-    } else if (this.flashTimer > this.config.FLASH_DURATION * 2) {
-      this.flashTimer = 0;
-      this.flashIterations++;
-    }
-
-    if (paint) {
-      this.drawHighScore();
-    } else {
-      this.clearHighScoreBounds();
-    }
-    // Frame update.
-    this.flashingRafId = requestAnimationFrame(this.flashHighScore.bind(this));
-  }
-
-  /**
-   * Draw empty rectangle over high score.
-   */
-  clearHighScoreBounds() {
-    this.canvasCtx.save();
-    this.canvasCtx.fillStyle = '#fff';
-    this.canvasCtx.rect(
-        this.highScoreBounds.x, this.highScoreBounds.y,
-        this.highScoreBounds.width, this.highScoreBounds.height);
-    this.canvasCtx.fill();
-    this.canvasCtx.restore();
-  }
-
-  /**
-   * Starts the flashing of the high score.
-   */
-  startHighScoreFlashing() {
-    this.highScoreFlashing = true;
-    this.flashHighScore();
-  }
-
-  /**
-   * Whether high score is flashing.
-   * @return {boolean}
-   */
-  isHighScoreFlashing() {
-    return this.highScoreFlashing;
-  }
-
-  /**
-   * Stop flashing the high score.
-   */
-  cancelHighScoreFlashing() {
-    if (this.flashingRafId) {
-      cancelAnimationFrame(this.flashingRafId);
-    }
-    this.flashIterations = 0;
-    this.flashTimer = 0;
-    this.highScoreFlashing = false;
-    this.clearHighScoreBounds();
-    this.drawHighScore();
-  }
-
-  /**
-   * Clear the high score.
-   */
-  resetHighScore() {
-    this.setHighScore(0);
-    this.cancelHighScoreFlashing();
-  }
-
-  /**
-   * Reset the distance meter back to '00000'.
-   */
-  reset() {
-    this.update(0, 0);
-    this.achievement = false;
-  }
-}
-
-/**
- * @enum {number}
- */
-DistanceMeter.dimensions = {
-  WIDTH: 10,
-  HEIGHT: 13,
-  DEST_WIDTH: 11,
-};
-
-
-/**
- * Y positioning of the digits in the sprite sheet.
- * X position is always 0.
- * @type {Array<number>}
- */
-DistanceMeter.yPos = [0, 13, 27, 40, 53, 67, 80, 93, 107, 120];
-
-
-/**
- * Distance meter config.
- * @enum {number}
- */
-DistanceMeter.config = {
-  // Number of digits.
-  MAX_DISTANCE_UNITS: 5,
-
-  // Distance that causes achievement animation.
-  ACHIEVEMENT_DISTANCE: 100,
-
-  // Used for conversion from pixel distance to a scaled unit.
-  COEFFICIENT: 0.025,
-
-  // Flash duration in milliseconds.
-  FLASH_DURATION: 1000 / 4,
-
-  // Flash iterations for achievement animation.
-  FLASH_ITERATIONS: 3,
-
-  // Padding around the high score hit area.
-  HIGH_SCORE_HIT_AREA_PADDING: 4,
-};
\ No newline at end of file
diff --git a/components/neterror/resources/dino_game/distance_meter.ts b/components/neterror/resources/dino_game/distance_meter.ts
new file mode 100644
index 0000000..41d6f7b
--- /dev/null
+++ b/components/neterror/resources/dino_game/distance_meter.ts
@@ -0,0 +1,416 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {assert} from 'chrome://resources/js/assert.js';
+
+import {IS_HIDPI, IS_RTL} from './constants.js';
+import type {CollisionBox} from './offline_sprite_definitions.js';
+import type {SpritePosition} from './sprite_position.js';
+import {getRunnerImageSprite, getTimeStamp} from './utils.js';
+
+/**
+ * Dimensions of each individual character in pixels.
+ */
+enum Dimensions {
+  WIDTH = 10,
+  HEIGHT = 13,
+  DEST_WIDTH = 11,
+}
+
+/**
+ * Distance meter config.
+ */
+enum Config {
+  // Number of digits.
+  MAX_DISTANCE_UNITS = 5,
+
+  // Distance that causes achievement animation.
+  ACHIEVEMENT_DISTANCE = 100,
+
+  // Used for conversion from pixel distance to a scaled unit.
+  COEFFICIENT = 0.025,
+
+  // Flash duration in milliseconds.
+  FLASH_DURATION = 1000 / 4,
+
+  // Flash iterations for achievement animation.
+  FLASH_ITERATIONS = 3,
+
+  // Padding around the high score hit area.
+  HIGH_SCORE_HIT_AREA_PADDING = 4,
+}
+
+export class DistanceMeter {
+  achievement: boolean = false;
+
+  private canvas: HTMLCanvasElement;
+  private canvasCtx: CanvasRenderingContext2D;
+  private image: CanvasImageSource;
+  private spritePos: SpritePosition;
+  private x: number = 0;
+  private y: number = 5;
+  private maxScore: number = 0;
+  private highScore: string = '0';
+  private digits: string[] = [];
+  private defaultString: string = '';
+  private flashTimer: number = 0;
+  private flashIterations: number = 0;
+  private flashingRafId: number|null = null;
+  private highScoreBounds: CollisionBox|null = null;
+  private highScoreFlashing: boolean = false;
+  private maxScoreUnits: number = Config.MAX_DISTANCE_UNITS;
+  private canvasWidth: number;
+  private frameTimeStamp?: number;
+
+  /**
+   * Handles displaying the distance meter.
+   */
+  constructor(
+      canvas: HTMLCanvasElement, spritePos: SpritePosition,
+      canvasWidth: number) {
+    this.canvas = canvas;
+    const canvasContext = canvas.getContext('2d');
+    assert(canvasContext);
+    this.canvasCtx = canvasContext;
+    const runnerImageSprite = getRunnerImageSprite();
+    assert(runnerImageSprite);
+    this.image = runnerImageSprite;
+    this.spritePos = spritePos;
+
+    this.canvasWidth = canvasWidth;
+    this.init(canvasWidth);
+  }
+
+
+  /**
+   * Initialise the distance meter to '00000'.
+   * @param width Canvas width in px.
+   */
+  private init(width: number) {
+    let maxDistanceStr = '';
+
+    this.calcXpos(width);
+    this.maxScore = this.maxScoreUnits;
+    for (let i = 0; i < this.maxScoreUnits; i++) {
+      this.draw(i, 0);
+      this.defaultString += '0';
+      maxDistanceStr += '9';
+    }
+
+    this.maxScore = parseInt(maxDistanceStr, 10);
+  }
+
+  /**
+   * Calculate the xPos in the canvas.
+   */
+  calcXpos(canvasWidth: number) {
+    this.x = canvasWidth - (Dimensions.DEST_WIDTH * (this.maxScoreUnits + 1));
+  }
+
+  /**
+   * Draw a digit to canvas.
+   * @param digitPos Position of the digit.
+   * @param value Digit value 0-9.
+   * @param highScore Whether drawing the high score.
+   */
+  private draw(digitPos: number, value: number, highScore?: boolean) {
+    let sourceWidth = Dimensions.WIDTH;
+    let sourceHeight = Dimensions.HEIGHT;
+    let sourceX = Dimensions.WIDTH * value;
+    let sourceY = 0;
+
+    const targetX = digitPos * Dimensions.DEST_WIDTH;
+    const targetY = this.y;
+    const targetWidth = Dimensions.WIDTH;
+    const targetHeight = Dimensions.HEIGHT;
+
+    // For high DPI we 2x source values.
+    if (IS_HIDPI) {
+      sourceWidth *= 2;
+      sourceHeight *= 2;
+      sourceX *= 2;
+    }
+
+    sourceX += this.spritePos.x;
+    sourceY += this.spritePos.y;
+
+    this.canvasCtx.save();
+
+    if (IS_RTL) {
+      const translateX = highScore ?
+          this.canvasWidth - (Dimensions.WIDTH * (this.maxScoreUnits + 3)) :
+          this.canvasWidth - Dimensions.WIDTH;
+      this.canvasCtx.translate(translateX, this.y);
+      this.canvasCtx.scale(-1, 1);
+    } else {
+      const highScoreX = this.x - (this.maxScoreUnits * 2) * Dimensions.WIDTH;
+      this.canvasCtx.translate(highScore ? highScoreX : this.x, this.y);
+    }
+
+    this.canvasCtx.drawImage(
+        this.image,
+        sourceX,
+        sourceY,
+        sourceWidth,
+        sourceHeight,
+        targetX,
+        targetY,
+        targetWidth,
+        targetHeight,
+    );
+
+    this.canvasCtx.restore();
+  }
+
+  /**
+   * Covert pixel distance to a 'real' distance.
+   * @param distance Pixel distance ran.
+   * @return The 'real' distance ran.
+   */
+  getActualDistance(distance: number): number {
+    return distance ? Math.round(distance * Config.COEFFICIENT) : 0;
+  }
+
+  /**
+   * Update the distance meter.
+   * @return Whether the achievement sound fx should be played.
+   */
+  update(deltaTime: number, distance: number): boolean {
+    let paint = true;
+    let playSound = false;
+
+    if (!this.achievement) {
+      distance = this.getActualDistance(distance);
+      // Score has gone beyond the initial digit count.
+      if (distance > this.maxScore &&
+          this.maxScoreUnits === Config.MAX_DISTANCE_UNITS) {
+        this.maxScoreUnits++;
+        this.maxScore = parseInt(this.maxScore + '9', 10);
+      }
+
+      if (distance > 0) {
+        // Achievement unlocked.
+        if (distance % Config.ACHIEVEMENT_DISTANCE === 0) {
+          // Flash score and play sound.
+          this.achievement = true;
+          this.flashTimer = 0;
+          playSound = true;
+        }
+
+        // Create a string representation of the distance with leading 0.
+        const distanceStr =
+            (this.defaultString + distance).substr(-this.maxScoreUnits);
+        this.digits = distanceStr.split('');
+      } else {
+        this.digits = this.defaultString.split('');
+      }
+    } else {
+      // Control flashing of the score on reaching achievement.
+      if (this.flashIterations <= Config.FLASH_ITERATIONS) {
+        this.flashTimer += deltaTime;
+
+        if (this.flashTimer < Config.FLASH_DURATION) {
+          paint = false;
+        } else if (this.flashTimer > Config.FLASH_DURATION * 2) {
+          this.flashTimer = 0;
+          this.flashIterations++;
+        }
+      } else {
+        this.achievement = false;
+        this.flashIterations = 0;
+        this.flashTimer = 0;
+      }
+    }
+
+    // Draw the digits if not flashing.
+    if (paint) {
+      for (let i = this.digits.length - 1; i >= 0; i--) {
+        this.draw(i, parseInt(this.digits[i]!, 10));
+      }
+    }
+
+    this.drawHighScore();
+    return playSound;
+  }
+
+  /**
+   * Draw the high score.
+   */
+  private drawHighScore() {
+    if (this.highScore.length > 0) {
+      this.canvasCtx.save();
+      this.canvasCtx.globalAlpha = .8;
+      for (let i = this.highScore.length - 1; i >= 0; i--) {
+        const characterToDraw = this.highScore[i]!;
+        // Position of characterToDraw in sprite sheet, digits 0-9 are mapped
+        // directly.
+        let characterSpritePosition = parseInt(characterToDraw, 10);
+        // If characterToDraw is not a digit then they must be part of the label
+        // "HI". The position of these characters in the sheet is: H - 10, I
+        // - 11.
+        if (isNaN(characterSpritePosition)) {
+          switch (characterToDraw) {
+            case 'H':
+              characterSpritePosition = 10;
+              break;
+            case 'I':
+              characterSpritePosition = 11;
+              break;
+            // Any other character is ignored.
+            default:
+              continue;
+          }
+        }
+        this.draw(i, characterSpritePosition, true);
+      }
+      this.canvasCtx.restore();
+    }
+  }
+
+  /**
+   * Set the highscore as a string.
+   * @param distance Distance ran in pixels.
+   */
+  setHighScore(distance: number) {
+    distance = this.getActualDistance(distance);
+    const highScoreStr =
+        (this.defaultString + distance).substr(-this.maxScoreUnits);
+
+    this.highScore = 'HI ' + highScoreStr;
+  }
+
+
+  /**
+   * Whether a clicked is in the high score area.
+   * @return Whether the click was in the high score bounds.
+   */
+  hasClickedOnHighScore(e: TouchEvent|MouseEvent): boolean {
+    let x = 0;
+    let y = 0;
+
+    if (e instanceof TouchEvent) {
+      // Bounds for touch differ from pointer.
+      const canvasBounds = this.canvas.getBoundingClientRect();
+      x = e.touches[0]!.clientX - canvasBounds.left;
+      y = e.touches[0]!.clientY - canvasBounds.top;
+    } else {
+      x = e.offsetX;
+      y = e.offsetY;
+    }
+
+    this.highScoreBounds = this.getHighScoreBounds();
+    return x >= this.highScoreBounds.x &&
+        x <= this.highScoreBounds.x + this.highScoreBounds.width &&
+        y >= this.highScoreBounds.y &&
+        y <= this.highScoreBounds.y + this.highScoreBounds.height;
+  }
+
+  /**
+   * Get the bounding box for the high score.
+   */
+  private getHighScoreBounds(): CollisionBox {
+    return {
+      x: (this.x - (this.maxScoreUnits * 2) * Dimensions.WIDTH) -
+          Config.HIGH_SCORE_HIT_AREA_PADDING,
+      y: this.y,
+      width: Dimensions.WIDTH * (this.highScore.length + 1) +
+          Config.HIGH_SCORE_HIT_AREA_PADDING,
+      height: Dimensions.HEIGHT + (Config.HIGH_SCORE_HIT_AREA_PADDING * 2),
+    };
+  }
+
+  /**
+   * Animate flashing the high score to indicate ready for resetting.
+   * The flashing stops following distanceMeterConfig.FLASH_ITERATIONS x 2
+   * flashes.
+   */
+  private flashHighScore() {
+    const now = getTimeStamp();
+    const deltaTime = now - (this.frameTimeStamp || now);
+    let paint = true;
+    this.frameTimeStamp = now;
+
+    // Reached the max number of flashes.
+    if (this.flashIterations > Config.FLASH_ITERATIONS * 2) {
+      this.cancelHighScoreFlashing();
+      return;
+    }
+
+    this.flashTimer += deltaTime;
+
+    if (this.flashTimer < Config.FLASH_DURATION) {
+      paint = false;
+    } else if (this.flashTimer > Config.FLASH_DURATION * 2) {
+      this.flashTimer = 0;
+      this.flashIterations++;
+    }
+
+    if (paint) {
+      this.drawHighScore();
+    } else {
+      this.clearHighScoreBounds();
+    }
+    // Frame update.
+    this.flashingRafId = requestAnimationFrame(this.flashHighScore.bind(this));
+  }
+
+  /**
+   * Draw empty rectangle over high score.
+   */
+  private clearHighScoreBounds() {
+    assert(this.highScoreBounds);
+    this.canvasCtx.save();
+    this.canvasCtx.fillStyle = '#fff';
+    this.canvasCtx.rect(
+        this.highScoreBounds.x, this.highScoreBounds.y,
+        this.highScoreBounds.width, this.highScoreBounds.height);
+    this.canvasCtx.fill();
+    this.canvasCtx.restore();
+  }
+
+  /**
+   * Starts the flashing of the high score.
+   */
+  startHighScoreFlashing() {
+    this.highScoreFlashing = true;
+    this.flashHighScore();
+  }
+
+  /**
+   * Whether high score is flashing.
+   */
+  isHighScoreFlashing(): boolean {
+    return this.highScoreFlashing;
+  }
+
+  /**
+   * Stop flashing the high score.
+   */
+  cancelHighScoreFlashing() {
+    if (this.flashingRafId) {
+      cancelAnimationFrame(this.flashingRafId);
+    }
+    this.flashIterations = 0;
+    this.flashTimer = 0;
+    this.highScoreFlashing = false;
+    this.clearHighScoreBounds();
+    this.drawHighScore();
+  }
+
+  /**
+   * Clear the high score.
+   */
+  resetHighScore() {
+    this.setHighScore(0);
+    this.cancelHighScoreFlashing();
+  }
+
+  /**
+   * Reset the distance meter back to '00000'.
+   */
+  reset() {
+    this.update(0, 0);
+    this.achievement = false;
+  }
+}
diff --git a/components/omnibox/browser/autocomplete_provider_client.cc b/components/omnibox/browser/autocomplete_provider_client.cc
index 55928b4..a0c5423 100644
--- a/components/omnibox/browser/autocomplete_provider_client.cc
+++ b/components/omnibox/browser/autocomplete_provider_client.cc
@@ -45,6 +45,10 @@
   return false;
 }
 
+bool AutocompleteProviderClient::IsLensEnabled() const {
+  return false;
+}
+
 bool AutocompleteProviderClient::in_background_state() const {
   return false;
 }
diff --git a/components/omnibox/browser/autocomplete_provider_client.h b/components/omnibox/browser/autocomplete_provider_client.h
index ce250bfe..c0f3785 100644
--- a/components/omnibox/browser/autocomplete_provider_client.h
+++ b/components/omnibox/browser/autocomplete_provider_client.h
@@ -217,6 +217,9 @@
   // Returns true if history embeddings is enabled and user can opt in/out.
   virtual bool IsHistoryEmbeddingsSettingVisible() const;
 
+  // Returns true if the current profile is eligible for Lens.
+  virtual bool IsLensEnabled() const;
+
   // Returns whether the app is currently in the background state (Mobile only).
   virtual bool in_background_state() const;
 
diff --git a/components/omnibox/browser/contextual_search_provider.cc b/components/omnibox/browser/contextual_search_provider.cc
index bcad740..8dbf6636 100644
--- a/components/omnibox/browser/contextual_search_provider.cc
+++ b/components/omnibox/browser/contextual_search_provider.cc
@@ -105,7 +105,8 @@
     if (omnibox::IsOtherWebPage(input.current_page_classification()) &&
         input.current_url().SchemeIsHTTPOrHTTPS() &&
         (input.IsZeroSuggest() ||
-         input.type() == metrics::OmniboxInputType::EMPTY)) {
+         input.type() == metrics::OmniboxInputType::EMPTY) &&
+       client()->IsLensEnabled()) {
       AddPageSearchActionMatches(input);
     }
     return;
diff --git a/components/omnibox/browser/contextual_search_provider_unittest.cc b/components/omnibox/browser/contextual_search_provider_unittest.cc
index 384797e..f815bab 100644
--- a/components/omnibox/browser/contextual_search_provider_unittest.cc
+++ b/components/omnibox/browser/contextual_search_provider_unittest.cc
@@ -46,6 +46,8 @@
       return !!match.takeover_action;
     });
   };
+  EXPECT_CALL(*client_, IsLensEnabled()).WillRepeatedly(testing::Return(true));
+
   {
     AutocompleteInput input(u"nonempty input text",
                             metrics::OmniboxEventProto::OTHER,
@@ -74,4 +76,15 @@
     EXPECT_TRUE(provider_->done());
     EXPECT_FALSE(has_actions());
   }
+    // Lens action missing if Lens is disabled.
+  {
+    EXPECT_CALL(*client_, IsLensEnabled()).WillOnce(testing::Return(false));
+    AutocompleteInput input(u"", metrics::OmniboxEventProto::OTHER,
+                            TestSchemeClassifier());
+    input.set_current_url(GURL("https://example.com"));
+    input.set_focus_type(metrics::OmniboxFocusType::INTERACTION_FOCUS);
+    provider_->Start(input, false);
+    EXPECT_TRUE(provider_->done());
+    EXPECT_FALSE(has_actions());
+  }
 }
diff --git a/components/omnibox/browser/mock_autocomplete_provider_client.h b/components/omnibox/browser/mock_autocomplete_provider_client.h
index 19c6d8e..d2ebc3b1a9 100644
--- a/components/omnibox/browser/mock_autocomplete_provider_client.h
+++ b/components/omnibox/browser/mock_autocomplete_provider_client.h
@@ -151,6 +151,7 @@
   MOCK_CONST_METHOD0(IsSyncActive, bool());
   MOCK_CONST_METHOD0(IsHistoryEmbeddingsEnabled, bool());
   MOCK_CONST_METHOD0(IsHistoryEmbeddingsSettingVisible, bool());
+  MOCK_CONST_METHOD0(IsLensEnabled, bool());
   MOCK_CONST_METHOD1(GetLensSuggestInputsWhenReady,
                      base::CallbackListSubscription(
                          LensOverlaySuggestInputsCallback callback));
diff --git a/components/omnibox/browser/zero_suggest_provider.cc b/components/omnibox/browser/zero_suggest_provider.cc
index 2284d21..937060b 100644
--- a/components/omnibox/browser/zero_suggest_provider.cc
+++ b/components/omnibox/browser/zero_suggest_provider.cc
@@ -287,7 +287,13 @@
 }
 
 void MaybeAddContextualUrlSuggestParam(
+    const AutocompleteProviderClient* client,
     TemplateURLRef::SearchTermsArgs& search_terms_args) {
+  // Do not add the contextual URL suggest param if Lens is not enabled to
+  // fulfill the suggestion.
+  if (!client->IsLensEnabled()) {
+    return;
+  }
   if (!search_terms_args.current_page_url.empty() &&
       omnibox::IsOtherWebPage(search_terms_args.page_classification)) {
     std::string_view contextual_url_suggest_param =
@@ -427,7 +433,7 @@
                                            : std::string();
   search_terms_args.lens_overlay_suggest_inputs =
       input.lens_overlay_suggest_inputs();
-  MaybeAddContextualUrlSuggestParam(search_terms_args);
+  MaybeAddContextualUrlSuggestParam(client(), search_terms_args);
 
   std::unique_ptr<network::SimpleURLLoader>* prefetch_loader = nullptr;
   if (result_type == ResultType::kRemoteNoURL) {
@@ -513,7 +519,7 @@
           : std::string();
   search_terms_args.lens_overlay_suggest_inputs =
       input.lens_overlay_suggest_inputs();
-  MaybeAddContextualUrlSuggestParam(search_terms_args);
+  MaybeAddContextualUrlSuggestParam(client(), search_terms_args);
 
   const auto* template_url_service = client()->GetTemplateURLService();
   // Create a loader for the request and take ownership of it.
diff --git a/components/omnibox/browser/zero_suggest_provider_unittest.cc b/components/omnibox/browser/zero_suggest_provider_unittest.cc
index 8bf55b8..bfbc030 100644
--- a/components/omnibox/browser/zero_suggest_provider_unittest.cc
+++ b/components/omnibox/browser/zero_suggest_provider_unittest.cc
@@ -3014,20 +3014,30 @@
       config;
   config.Get().contextual_url_suggest_param = "1";
 
-  // Web gets the param.
+  // Web gets the param when Lens is enabled.
   {
+    EXPECT_CALL(*client_, IsLensEnabled()).WillOnce(testing::Return(true));
     GURL url =
         get_provider_request_url(ZeroPrefixInputForWeb(/*is_prefetch=*/false));
     EXPECT_NE(url.spec().find("ctxus=1"), std::string::npos);
   }
+  // Web does not get the param when Lens is disabled.
+  {
+    EXPECT_CALL(*client_, IsLensEnabled()).WillOnce(testing::Return(false));
+    GURL url =
+        get_provider_request_url(ZeroPrefixInputForWeb(/*is_prefetch=*/false));
+    EXPECT_EQ(url.spec().find("ctxus=1"), std::string::npos);
+  }
   // NTP does not, even when enabled.
   {
+    EXPECT_CALL(*client_, IsLensEnabled()).WillOnce(testing::Return(true));
     GURL url =
         get_provider_request_url(ZeroPrefixInputForNTP(/*is_prefetch=*/false));
     EXPECT_EQ(url.spec().find("ctxus=1"), std::string::npos);
   }
   // SRP does not, even when enabled.
   {
+    EXPECT_CALL(*client_, IsLensEnabled()).WillOnce(testing::Return(true));
     GURL url =
         get_provider_request_url(ZeroPrefixInputForSRP(/*is_prefetch=*/false));
     EXPECT_EQ(url.spec().find("ctxus=1"), std::string::npos);
diff --git a/components/omnibox/common/omnibox_feature_configs.cc b/components/omnibox/common/omnibox_feature_configs.cc
index 1bbf5a76..11cdf7f8 100644
--- a/components/omnibox/common/omnibox_feature_configs.cc
+++ b/components/omnibox/common/omnibox_feature_configs.cc
@@ -216,6 +216,11 @@
                                       "relevance_scoring_mode", "mixed")
           .Get();
 
+  realbox_unscoped_suggestions =
+      base::FeatureParam<bool>(&kSearchAggregatorProvider,
+                               "realbox_unscoped_suggestions", false)
+          .Get();
+
   scoring_max_matches_created_per_type =
       base::FeatureParam<size_t>(&kSearchAggregatorProvider,
                                  "scoring_max_matches_created_per_type", 40)
diff --git a/components/omnibox/common/omnibox_feature_configs.h b/components/omnibox/common/omnibox_feature_configs.h
index c4dcf1b..9f49653 100644
--- a/components/omnibox/common/omnibox_feature_configs.h
+++ b/components/omnibox/common/omnibox_feature_configs.h
@@ -265,6 +265,9 @@
   //   "server": Use server-provided scores in both scoped and unscoped mode.
   //   "client": Use client-calculated scores in both scoped and unscoped mode.
   std::string relevance_scoring_mode;
+  // If true, show unscoped `EnterpriseSearchAggregatorProvider` suggestions in
+  // the NTP realbox.
+  bool realbox_unscoped_suggestions;
 
   // See comments in enterprise_search_aggregator_provider.cc
   size_t scoring_max_matches_created_per_type;
diff --git a/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc b/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
index aeadd81..355e260 100644
--- a/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
+++ b/components/optimization_guide/core/model_execution/on_device_model_service_controller.cc
@@ -673,7 +673,8 @@
 
 bool OnDeviceModelServiceController::Solution::IsValid() {
   return model_controller_ &&
-         (adapter_->CanSkipTextSafety() || safety_checker_->client());
+         (!features::ShouldUseTextSafetyClassifierModel() ||
+          adapter_->CanSkipTextSafety() || safety_checker_->client());
 }
 
 // Creates a config describing this solution;
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn
index 0ded25c..ac60dfa 100644
--- a/components/performance_manager/BUILD.gn
+++ b/components/performance_manager/BUILD.gn
@@ -221,6 +221,7 @@
     "public/resource_attribution/resource_types.h",
     "public/resource_attribution/type_helpers.h",
     "public/resource_attribution/worker_context.h",
+    "public/scenarios/process_performance_scenarios.h",
     "public/tracing_support.h",
     "public/user_tuning/prefs.h",
     "public/user_tuning/tab_revisit_tracker.h",
@@ -273,6 +274,7 @@
     "scenarios/loading_scenario_observer.h",
     "scenarios/performance_scenario_data.cc",
     "scenarios/performance_scenario_data.h",
+    "scenarios/process_performance_scenarios.cc",
     "scenarios/scoped_global_scenario_memory.cc",
     "service_worker_context_adapter.cc",
     "service_worker_context_adapter.h",
@@ -417,6 +419,7 @@
     "scenarios/browser_performance_scenarios_unittest.cc",
     "scenarios/input_scenario_observer_unittest.cc",
     "scenarios/loading_scenario_observer_unittest.cc",
+    "scenarios/process_performance_scenarios_unittest.cc",
     "test_support/mock_graphs_unittest.cc",
     "user_tuning/prefs_unittest.cc",
     "user_tuning/tab_revisit_tracker_unittest.cc",
diff --git a/components/performance_manager/public/DEPS b/components/performance_manager/public/DEPS
index f1973c8..c4d58e4 100644
--- a/components/performance_manager/public/DEPS
+++ b/components/performance_manager/public/DEPS
@@ -2,4 +2,5 @@
 include_rules = [
   "-components/performance_manager",
   "+components/performance_manager/public",
+  "+components/performance_manager/scenario_api",
 ]
diff --git a/components/performance_manager/public/scenarios/process_performance_scenarios.h b/components/performance_manager/public/scenarios/process_performance_scenarios.h
new file mode 100644
index 0000000..e4072b7
--- /dev/null
+++ b/components/performance_manager/public/scenarios/process_performance_scenarios.h
@@ -0,0 +1,103 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_SCENARIOS_PROCESS_PERFORMANCE_SCENARIOS_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_SCENARIOS_PROCESS_PERFORMANCE_SCENARIOS_H_
+
+#include "base/observer_list.h"
+#include "base/scoped_observation_traits.h"
+#include "components/performance_manager/scenario_api/performance_scenarios.h"
+
+namespace performance_scenarios {
+class MatchingScenarioObserver;
+class PerformanceScenarioObserver;
+}  // namespace performance_scenarios
+
+namespace performance_manager {
+
+class ProcessNode;
+
+// Functions to let the browser process query the performance scenarios for a
+// child process. These are similar to functions in
+// components/performance_manager/scenario_api/performance_scenarios.h, but have
+// extra performance_manager dependencies.
+//
+// These functions all take a ProcessNode, and read the scenario values that are
+// visible for ScenarioScope::kCurrentProcess in that process. Scenario values
+// that are visible for ScenarioScope::kGlobal are the same in all processes, so
+// can be read in the browser process using the API in performance_scenarios.h.
+//
+// All functions must be called on the UI thread. They return scenario values
+// directly instead of `scenario_api::SharedAtomicRef` because the browser
+// process updates scenario memory on the UI thread, so it won't change
+// unexpectedly.
+
+// Returns the current LoadingScenario for `process`.
+performance_scenarios::LoadingScenario GetProcessLoadingScenario(
+    const ProcessNode* process);
+
+// Returns the current InputScenario for `process`.
+performance_scenarios::InputScenario GetProcessInputScenario(
+    const ProcessNode* process);
+
+// Returns true if the current scenarios for `process` match `pattern`.
+bool CurrentProcessScenariosMatch(
+    const ProcessNode* process,
+    performance_scenarios::ScenarioPattern pattern);
+
+// Returns a list of PerformanceScenarioObservers for `process` that will be
+// notified when the scenarios for that process change. The list is only valid
+// as long as the ProcessNode exists.
+base::ObserverList<performance_scenarios::PerformanceScenarioObserver>&
+GetScenarioObserversForProcess(const ProcessNode* process);
+
+// Returns a list of MatchingScenarioObservers for `process` that will be
+// notified when the scenarios for that process change to start or stop
+// matching a scenario pattern. The list is only valid as long as the
+// ProcessNode exists.
+base::ObserverList<performance_scenarios::MatchingScenarioObserver>&
+GetMatchingScenarioObserversForProcess(const ProcessNode* process);
+
+}  // namespace performance_manager
+
+namespace base {
+
+// Specialize ScopedObservation to look up the observer lists for a ProcessNode.
+// These must be in the same namespace as base::ScopedObservationTraits.
+
+template <>
+struct ScopedObservationTraits<
+    performance_manager::ProcessNode,
+    performance_scenarios::PerformanceScenarioObserver> {
+  static void AddObserver(
+      const performance_manager::ProcessNode* source,
+      performance_scenarios::PerformanceScenarioObserver* observer) {
+    GetScenarioObserversForProcess(source).AddObserver(observer);
+  }
+  static void RemoveObserver(
+      const performance_manager::ProcessNode* source,
+      performance_scenarios::PerformanceScenarioObserver* observer) {
+    GetScenarioObserversForProcess(source).RemoveObserver(observer);
+  }
+};
+
+template <>
+struct ScopedObservationTraits<
+    performance_manager::ProcessNode,
+    performance_scenarios::MatchingScenarioObserver> {
+  static void AddObserver(
+      const performance_manager::ProcessNode* source,
+      performance_scenarios::MatchingScenarioObserver* observer) {
+    GetMatchingScenarioObserversForProcess(source).AddObserver(observer);
+  }
+  static void RemoveObserver(
+      const performance_manager::ProcessNode* source,
+      performance_scenarios::MatchingScenarioObserver* observer) {
+    GetMatchingScenarioObserversForProcess(source).RemoveObserver(observer);
+  }
+};
+
+}  // namespace base
+
+#endif  // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_SCENARIOS_PROCESS_PERFORMANCE_SCENARIOS_H_
diff --git a/components/performance_manager/scenario_api/performance_scenario_observer.cc b/components/performance_manager/scenario_api/performance_scenario_observer.cc
index 9171d49..93543c0 100644
--- a/components/performance_manager/scenario_api/performance_scenario_observer.cc
+++ b/components/performance_manager/scenario_api/performance_scenario_observer.cc
@@ -82,7 +82,6 @@
 MatchingScenarioObserver::~MatchingScenarioObserver() = default;
 
 void MatchingScenarioObserver::NotifyIfScenarioMatchChanged(
-    base::PassKey<PerformanceScenarioObserverList>,
     ScenarioScope scope,
     LoadingScenario loading_scenario,
     InputScenario input_scenario) {
@@ -149,8 +148,8 @@
     last_input_scenario_ = input_scenario;
   }
   matching_observers_->Notify(
-      location, &MatchingScenarioObserver::NotifyIfScenarioMatchChanged,
-      PassKey(), scope_, loading_scenario, input_scenario);
+      location, &MatchingScenarioObserver::NotifyIfScenarioMatchChanged, scope_,
+      loading_scenario, input_scenario);
 }
 
 // static
diff --git a/components/performance_manager/scenario_api/performance_scenario_observer.h b/components/performance_manager/scenario_api/performance_scenario_observer.h
index 8241849..fd7a1d0 100644
--- a/components/performance_manager/scenario_api/performance_scenario_observer.h
+++ b/components/performance_manager/scenario_api/performance_scenario_observer.h
@@ -61,11 +61,9 @@
 
   // Allows PerformanceScenarioObserverList to notify of scenario changes. Will
   // invoke OnScenarioMatchChanged if necessary.
-  void NotifyIfScenarioMatchChanged(
-      base::PassKey<PerformanceScenarioObserverList>,
-      ScenarioScope scope,
-      LoadingScenario loading_scenario,
-      InputScenario input_scenario);
+  void NotifyIfScenarioMatchChanged(ScenarioScope scope,
+                                    LoadingScenario loading_scenario,
+                                    InputScenario input_scenario);
 
  private:
   // Returns a reference into `last_match_notifications_` for `scope`.
@@ -137,8 +135,6 @@
  private:
   friend class base::RefCountedThreadSafe<PerformanceScenarioObserverList>;
 
-  using PassKey = base::PassKey<PerformanceScenarioObserverList>;
-
   explicit PerformanceScenarioObserverList(ScenarioScope scope);
   ~PerformanceScenarioObserverList();
 
diff --git a/components/performance_manager/scenario_api/performance_scenarios.h b/components/performance_manager/scenario_api/performance_scenarios.h
index 4a2a1a8..7950758 100644
--- a/components/performance_manager/scenario_api/performance_scenarios.h
+++ b/components/performance_manager/scenario_api/performance_scenarios.h
@@ -26,6 +26,10 @@
 // child processes over shared memory. Each process can view a global scenario
 // list over the entire browser (eg. some page is loading) or a scenario list
 // targeted only to that process (eg. a page hosted in this process is loading).
+//
+// Additional functions to let the browser process query the performance
+// scenarios for a child process are in
+// components/performance_manager/public/scenarios/process_performance_scenarios.h.
 
 // Scenarios indicating a page is loading, ordered from least-specific to
 // most-specific.
diff --git a/components/performance_manager/scenarios/browser_performance_scenarios.cc b/components/performance_manager/scenarios/browser_performance_scenarios.cc
index 113169b..271b913 100644
--- a/components/performance_manager/scenarios/browser_performance_scenarios.cc
+++ b/components/performance_manager/scenarios/browser_performance_scenarios.cc
@@ -31,6 +31,9 @@
 
 namespace performance_manager {
 
+using performance_scenarios::MatchingScenarioObserver;
+using performance_scenarios::PerformanceScenarioObserver;
+using performance_scenarios::PerformanceScenarioObserverList;
 using performance_scenarios::ScenarioScope;
 
 namespace {
@@ -62,6 +65,11 @@
   // a tracing track is registered.
   void MaybeRecordTraceEvent(Scenario old_scenario,
                              Scenario new_scenario) const;
+
+  // Notifies a ProcessNode's PerformanceScenarioObserver list of a switch from
+  // `old_scenario` to `new_scenario`.
+  void NotifyProcessObservers(Scenario old_scenario,
+                              Scenario new_scenario) const;
 };
 
 template <>
@@ -81,6 +89,19 @@
         {"AnyPageLoading", "VisiblePageLoading", "FocusedPageLoading"});
   }
 
+  void NotifyProcessObservers(LoadingScenario old_scenario,
+                              LoadingScenario new_scenario) const {
+    state_ptr->observers().Notify(
+        &PerformanceScenarioObserver::OnLoadingScenarioChanged,
+        ScenarioScope::kCurrentProcess, old_scenario, new_scenario);
+    InputScenario input_scenario =
+        state_ptr->shared_state().ReadOnlyRef().input.load(
+            std::memory_order_relaxed);
+    state_ptr->matching_observers().Notify(
+        &MatchingScenarioObserver::NotifyIfScenarioMatchChanged,
+        ScenarioScope::kCurrentProcess, new_scenario, input_scenario);
+  }
+
   raw_ptr<PerformanceScenarioData> state_ptr;
 };
 
@@ -101,6 +122,19 @@
                                 {"TypingTapOrScroll", "TapOrScroll", "Scroll"});
   }
 
+  void NotifyProcessObservers(InputScenario old_scenario,
+                              InputScenario new_scenario) const {
+    state_ptr->observers().Notify(
+        &PerformanceScenarioObserver::OnInputScenarioChanged,
+        ScenarioScope::kCurrentProcess, old_scenario, new_scenario);
+    LoadingScenario loading_scenario =
+        state_ptr->shared_state().ReadOnlyRef().loading.load(
+            std::memory_order_relaxed);
+    state_ptr->matching_observers().Notify(
+        &MatchingScenarioObserver::NotifyIfScenarioMatchChanged,
+        ScenarioScope::kCurrentProcess, loading_scenario, new_scenario);
+  }
+
   raw_ptr<PerformanceScenarioData> state_ptr;
 };
 
@@ -132,7 +166,8 @@
 // Sets the value for Scenario in the memory region held in `state_ptr` to
 // `new_scenario`.
 template <typename Scenario>
-void SetScenarioValue(Scenario new_scenario,
+void SetScenarioValue(ScenarioScope scope,
+                      Scenario new_scenario,
                       PerformanceScenarioData* state_ptr) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (state_ptr) {
@@ -143,6 +178,19 @@
         traits.ScenarioRef().exchange(new_scenario, std::memory_order_relaxed);
     if (old_scenario != new_scenario) {
       traits.MaybeRecordTraceEvent(old_scenario, new_scenario);
+      switch (scope) {
+        case ScenarioScope::kCurrentProcess:
+          // Notify observers for the ProcessNode holding `state_ptr`.
+          traits.NotifyProcessObservers(old_scenario, new_scenario);
+          break;
+        case ScenarioScope::kGlobal:
+          // Notify all global observers registered in the browser process.
+          if (auto observers = PerformanceScenarioObserverList::GetForScope(
+                  ScenarioScope::kGlobal)) {
+            observers->NotifyIfScenarioChanged();
+          }
+          break;
+      }
     }
   }
 }
@@ -154,19 +202,8 @@
   base::WeakPtr<ProcessNode> process_node =
       PerformanceManager::GetProcessNodeForRenderProcessHost(host);
   CHECK(process_node);
-  SetScenarioValue(scenario, GetSharedStateForProcessNode(process_node.get()));
-}
-
-template <typename Scenario>
-void SetGlobalScenarioValue(Scenario scenario) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  SetScenarioValue(scenario, GetGlobalSharedState());
-  // Notify kGlobal observers in the browser process.
-  if (auto observers =
-          performance_scenarios::PerformanceScenarioObserverList::GetForScope(
-              ScenarioScope::kGlobal)) {
-    observers->NotifyIfScenarioChanged();
-  }
+  SetScenarioValue(ScenarioScope::kCurrentProcess, scenario,
+                   GetSharedStateForProcessNode(process_node.get()));
 }
 
 }  // namespace
@@ -209,12 +246,13 @@
 void SetLoadingScenarioForProcessNode(LoadingScenario scenario,
                                       const ProcessNode* process_node) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  SetScenarioValue(scenario, GetSharedStateForProcessNode(process_node));
+  SetScenarioValue(ScenarioScope::kCurrentProcess, scenario,
+                   GetSharedStateForProcessNode(process_node));
 }
 
 void SetGlobalLoadingScenario(LoadingScenario scenario) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  SetGlobalScenarioValue(scenario);
+  SetScenarioValue(ScenarioScope::kGlobal, scenario, GetGlobalSharedState());
 }
 
 void SetInputScenarioForProcess(InputScenario scenario,
@@ -226,12 +264,13 @@
 void SetInputScenarioForProcessNode(InputScenario scenario,
                                     const ProcessNode* process_node) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  SetScenarioValue(scenario, GetSharedStateForProcessNode(process_node));
+  SetScenarioValue(ScenarioScope::kCurrentProcess, scenario,
+                   GetSharedStateForProcessNode(process_node));
 }
 
 void SetGlobalInputScenario(InputScenario scenario) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  SetGlobalScenarioValue(scenario);
+  SetScenarioValue(ScenarioScope::kGlobal, scenario, GetGlobalSharedState());
 }
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/scenarios/performance_scenario_data.h b/components/performance_manager/scenarios/performance_scenario_data.h
index df9e723..9e448d3 100644
--- a/components/performance_manager/scenarios/performance_scenario_data.h
+++ b/components/performance_manager/scenarios/performance_scenario_data.h
@@ -9,9 +9,11 @@
 #include <optional>
 
 #include "base/memory/structured_shared_memory.h"
+#include "base/observer_list.h"
 #include "base/types/optional_util.h"
 #include "components/performance_manager/graph/node_inline_data.h"
 #include "components/performance_manager/scenario_api/performance_scenario_memory_forward.h"
+#include "components/performance_manager/scenario_api/performance_scenario_observer.h"
 #include "third_party/perfetto/include/perfetto/tracing/track.h"
 
 namespace base {
@@ -31,6 +33,10 @@
  public:
   using SharedScenarioState =
       base::StructuredSharedMemory<performance_scenarios::ScenarioState>;
+  using MatchingScenarioObserver =
+      performance_scenarios::MatchingScenarioObserver;
+  using PerformanceScenarioObserver =
+      performance_scenarios::PerformanceScenarioObserver;
 
   // Returns the data for `process_node`, creating it if it doesn't already
   // exist. If the data is newly created and `mapper` is non-null, it will be
@@ -61,6 +67,22 @@
     return shared_state_.value();
   }
 
+  // Returns observer lists for changes to the scenario state of the
+  // ProcessNode.
+  base::ObserverList<PerformanceScenarioObserver>& observers() {
+    return *observers_;
+  }
+  const base::ObserverList<PerformanceScenarioObserver>& observers() const {
+    return *observers_;
+  }
+  base::ObserverList<MatchingScenarioObserver>& matching_observers() {
+    return *matching_observers_;
+  }
+  const base::ObserverList<MatchingScenarioObserver>& matching_observers()
+      const {
+    return *matching_observers_;
+  }
+
   // Returns tracing tracks to log trace events when updating scenarios in the
   // shared memory region, or nullptr if EnsureTracingTracks() wasn't called.
   const perfetto::NamedTrack* loading_tracing_track() const {
@@ -86,10 +108,19 @@
   std::optional<SharedScenarioState> shared_state_;
 
   // Additional data associated with the region.
+
   // Tracing tracks must be stored in a heap-allocated struct because NamedTrack
   // is non-copyable and non-movable.
   std::unique_ptr<TracingTracks> tracing_tracks_ =
       std::make_unique<TracingTracks>();
+
+  // Observers for changes to the scenario state of a specific ProcessNode. Held
+  // in unique_ptr because ObserverList isn't movable.
+  std::unique_ptr<base::ObserverList<PerformanceScenarioObserver>> observers_ =
+      std::make_unique<base::ObserverList<PerformanceScenarioObserver>>();
+  std::unique_ptr<base::ObserverList<MatchingScenarioObserver>>
+      matching_observers_ =
+          std::make_unique<base::ObserverList<MatchingScenarioObserver>>();
 };
 
 }  // namespace performance_manager
diff --git a/components/performance_manager/scenarios/process_performance_scenarios.cc b/components/performance_manager/scenarios/process_performance_scenarios.cc
new file mode 100644
index 0000000..573e6281
--- /dev/null
+++ b/components/performance_manager/scenarios/process_performance_scenarios.cc
@@ -0,0 +1,60 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/performance_manager/public/scenarios/process_performance_scenarios.h"
+
+#include <atomic>
+
+#include "components/performance_manager/public/graph/process_node.h"
+#include "components/performance_manager/scenario_api/performance_scenario_memory.h"
+#include "components/performance_manager/scenarios/performance_scenario_data.h"
+
+namespace performance_manager {
+
+namespace {
+
+using performance_scenarios::InputScenario;
+using performance_scenarios::LoadingScenario;
+using performance_scenarios::MatchingScenarioObserver;
+using performance_scenarios::PerformanceScenarioObserver;
+using performance_scenarios::ScenarioState;
+
+const ScenarioState& GetScenarioStateForProcess(const ProcessNode* process) {
+  static constinit ScenarioState kDummyScenarioState;
+  const auto& data = PerformanceScenarioData::GetOrCreate(process);
+  return data.HasSharedState() ? data.shared_state().ReadOnlyRef()
+                               : kDummyScenarioState;
+}
+
+}  // namespace
+
+LoadingScenario GetProcessLoadingScenario(const ProcessNode* process) {
+  return GetScenarioStateForProcess(process).loading.load(
+      std::memory_order_relaxed);
+}
+
+InputScenario GetProcessInputScenario(const ProcessNode* process) {
+  return GetScenarioStateForProcess(process).input.load(
+      std::memory_order_relaxed);
+}
+
+bool CurrentProcessScenariosMatch(
+    const ProcessNode* process,
+    performance_scenarios::ScenarioPattern pattern) {
+  return performance_scenarios::ScenariosMatch(
+      GetProcessLoadingScenario(process), GetProcessInputScenario(process),
+      pattern);
+}
+
+base::ObserverList<performance_scenarios::PerformanceScenarioObserver>&
+GetScenarioObserversForProcess(const ProcessNode* process) {
+  return PerformanceScenarioData::GetOrCreate(process).observers();
+}
+
+base::ObserverList<performance_scenarios::MatchingScenarioObserver>&
+GetMatchingScenarioObserversForProcess(const ProcessNode* process) {
+  return PerformanceScenarioData::GetOrCreate(process).matching_observers();
+}
+
+}  // namespace performance_manager
diff --git a/components/performance_manager/scenarios/process_performance_scenarios_unittest.cc b/components/performance_manager/scenarios/process_performance_scenarios_unittest.cc
new file mode 100644
index 0000000..ceff87d
--- /dev/null
+++ b/components/performance_manager/scenarios/process_performance_scenarios_unittest.cc
@@ -0,0 +1,272 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/performance_manager/public/scenarios/process_performance_scenarios.h"
+
+#include <optional>
+
+#include "base/containers/span.h"
+#include "base/memory/platform_shared_memory_handle.h"
+#include "base/memory/shared_memory_mapper.h"
+#include "base/scoped_observation.h"
+#include "components/performance_manager/embedder/scoped_global_scenario_memory.h"
+#include "components/performance_manager/graph/process_node_impl.h"
+#include "components/performance_manager/public/graph/graph.h"
+#include "components/performance_manager/scenario_api/performance_scenario_observer.h"
+#include "components/performance_manager/scenario_api/performance_scenarios.h"
+#include "components/performance_manager/scenarios/browser_performance_scenarios.h"
+#include "components/performance_manager/scenarios/performance_scenario_data.h"
+#include "components/performance_manager/test_support/graph_test_harness.h"
+#include "components/performance_manager/test_support/mock_graphs.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace performance_manager {
+
+namespace {
+
+using performance_scenarios::InputScenario;
+using performance_scenarios::LoadingScenario;
+using performance_scenarios::MatchingScenarioObserver;
+using performance_scenarios::PerformanceScenarioObserver;
+using performance_scenarios::ScenarioScope;
+
+class LenientMockPerformanceScenarioObserver
+    : public PerformanceScenarioObserver {
+ public:
+  MOCK_METHOD(void,
+              OnLoadingScenarioChanged,
+              (ScenarioScope scope,
+               LoadingScenario old_scenario,
+               LoadingScenario new_scenario),
+              (override));
+  MOCK_METHOD(void,
+              OnInputScenarioChanged,
+              (ScenarioScope scope,
+               InputScenario old_scenario,
+               InputScenario new_scenario),
+              (override));
+};
+
+using MockPerformanceScenarioObserver =
+    ::testing::StrictMock<LenientMockPerformanceScenarioObserver>;
+
+class LenientMockMatchingScenarioObserver : public MatchingScenarioObserver {
+ public:
+  explicit LenientMockMatchingScenarioObserver(
+      performance_scenarios::ScenarioPattern pattern)
+      : MatchingScenarioObserver(pattern) {}
+
+  MOCK_METHOD(void,
+              OnScenarioMatchChanged,
+              (ScenarioScope scope, bool matches_pattern),
+              (override));
+};
+
+using MockMatchingScenarioObserver =
+    ::testing::StrictMock<LenientMockMatchingScenarioObserver>;
+
+// A fake SharedMemoryMapper that fails to map in memory.
+class FailingSharedMemoryMapper final : public base::SharedMemoryMapper {
+ public:
+  FailingSharedMemoryMapper() = default;
+  ~FailingSharedMemoryMapper() = default;
+
+  std::optional<base::span<uint8_t>> Map(
+      base::subtle::PlatformSharedMemoryHandle handle,
+      bool write_allowed,
+      uint64_t offset,
+      size_t size) final {
+    return std::nullopt;
+  }
+
+  void Unmap(base::span<uint8_t> mapping) final {}
+};
+
+class ProcessPerformanceScenariosTest : public GraphTestHarness {
+ private:
+  // Always map global memory. Per-process memory will be mapped automatically
+  // as process nodes are created.
+  ScopedGlobalScenarioMemory scoped_global_scenario_memory_;
+};
+
+}  // namespace
+
+TEST_F(ProcessPerformanceScenariosTest, LoadingScenario) {
+  MockSinglePageWithMultipleProcessesGraph mock_graph(graph());
+
+  EXPECT_EQ(GetProcessLoadingScenario(mock_graph.process.get()),
+            LoadingScenario::kNoPageLoading);
+  EXPECT_EQ(GetProcessLoadingScenario(mock_graph.other_process.get()),
+            LoadingScenario::kNoPageLoading);
+
+  MockPerformanceScenarioObserver mock_observer;
+  base::ScopedObservation<ProcessNode, PerformanceScenarioObserver> observation(
+      &mock_observer);
+  observation.Observe(mock_graph.process.get());
+
+  MockMatchingScenarioObserver mock_matching_observer(
+      performance_scenarios::kDefaultIdleScenarios);
+  base::ScopedObservation<ProcessNode, MatchingScenarioObserver>
+      matching_observation(&mock_matching_observer);
+  matching_observation.Observe(mock_graph.process.get());
+
+  // Changing to kBackgroundPageLoading should invoke the
+  // PerformanceScenarioObserver but not the MatchingScenarioObserver, since it
+  // still matches kDefaultIdleScenarios.
+  EXPECT_CALL(mock_observer, OnLoadingScenarioChanged(
+                                 ScenarioScope::kCurrentProcess,
+                                 LoadingScenario::kNoPageLoading,
+                                 LoadingScenario::kBackgroundPageLoading));
+
+  SetLoadingScenarioForProcessNode(LoadingScenario::kBackgroundPageLoading,
+                                   mock_graph.process.get());
+  EXPECT_EQ(GetProcessLoadingScenario(mock_graph.process.get()),
+            LoadingScenario::kBackgroundPageLoading);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_matching_observer);
+
+  // Observers shouldn't be notified if the scenario doesn't change.
+  SetLoadingScenarioForProcessNode(LoadingScenario::kBackgroundPageLoading,
+                                   mock_graph.process.get());
+  EXPECT_EQ(GetProcessLoadingScenario(mock_graph.process.get()),
+            LoadingScenario::kBackgroundPageLoading);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_matching_observer);
+
+  // Observer shouldn't be notified for changes to a different process, or for
+  // global changes.
+  SetLoadingScenarioForProcessNode(LoadingScenario::kVisiblePageLoading,
+                                   mock_graph.other_process.get());
+  SetGlobalLoadingScenario(LoadingScenario::kFocusedPageLoading);
+  EXPECT_EQ(GetProcessLoadingScenario(mock_graph.other_process.get()),
+            LoadingScenario::kVisiblePageLoading);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_matching_observer);
+
+  // Changing to kVisiblePageLoading should notify both observers since the
+  // scenario no longer matches kDefaultIdleScenarios.
+  EXPECT_CALL(mock_observer,
+              OnLoadingScenarioChanged(ScenarioScope::kCurrentProcess,
+                                       LoadingScenario::kBackgroundPageLoading,
+                                       LoadingScenario::kVisiblePageLoading));
+  EXPECT_CALL(mock_matching_observer,
+              OnScenarioMatchChanged(ScenarioScope::kCurrentProcess, false));
+
+  SetLoadingScenarioForProcessNode(LoadingScenario::kVisiblePageLoading,
+                                   mock_graph.process.get());
+  EXPECT_EQ(GetProcessLoadingScenario(mock_graph.process.get()),
+            LoadingScenario::kVisiblePageLoading);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_matching_observer);
+}
+
+TEST_F(ProcessPerformanceScenariosTest, InputScenario) {
+  MockSinglePageWithMultipleProcessesGraph mock_graph(graph());
+
+  EXPECT_EQ(GetProcessInputScenario(mock_graph.process.get()),
+            InputScenario::kNoInput);
+  EXPECT_EQ(GetProcessInputScenario(mock_graph.other_process.get()),
+            InputScenario::kNoInput);
+
+  MockPerformanceScenarioObserver mock_observer;
+  base::ScopedObservation<ProcessNode, PerformanceScenarioObserver> observation(
+      &mock_observer);
+  observation.Observe(mock_graph.process.get());
+
+  MockMatchingScenarioObserver mock_matching_observer(
+      performance_scenarios::kDefaultIdleScenarios);
+  base::ScopedObservation<ProcessNode, MatchingScenarioObserver>
+      matching_observation(&mock_matching_observer);
+  matching_observation.Observe(mock_graph.process.get());
+
+  // Changing to kTyping should notify both observers since the scenario no
+  // longer matches kDefaultIdleScenarios.
+  EXPECT_CALL(
+      mock_observer,
+      OnInputScenarioChanged(ScenarioScope::kCurrentProcess,
+                             InputScenario::kNoInput, InputScenario::kTyping));
+  EXPECT_CALL(mock_matching_observer,
+              OnScenarioMatchChanged(ScenarioScope::kCurrentProcess, false));
+
+  SetInputScenarioForProcessNode(InputScenario::kTyping,
+                                 mock_graph.process.get());
+  EXPECT_EQ(GetProcessInputScenario(mock_graph.process.get()),
+            InputScenario::kTyping);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_matching_observer);
+
+  // Observers shouldn't be notified if the scenario doesn't change.
+  SetInputScenarioForProcessNode(InputScenario::kTyping,
+                                 mock_graph.process.get());
+  EXPECT_EQ(GetProcessInputScenario(mock_graph.process.get()),
+            InputScenario::kTyping);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_matching_observer);
+
+  // Observer shouldn't be notified for changes to a different process, or for
+  // global changes.
+  SetInputScenarioForProcessNode(InputScenario::kTap,
+                                 mock_graph.other_process.get());
+  SetGlobalInputScenario(InputScenario::kScroll);
+  EXPECT_EQ(GetProcessInputScenario(mock_graph.other_process.get()),
+            InputScenario::kTap);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_matching_observer);
+
+  // Changing to kTap should invoke the PerformanceScenarioObserver but not the
+  // MatchingScenarioObserver, since it still doesn't match
+  // kDefaultIdleScenarios.
+  EXPECT_CALL(mock_observer, OnInputScenarioChanged(
+                                 ScenarioScope::kCurrentProcess,
+                                 InputScenario::kTyping, InputScenario::kTap));
+
+  SetInputScenarioForProcessNode(InputScenario::kTap, mock_graph.process.get());
+  EXPECT_EQ(GetProcessInputScenario(mock_graph.process.get()),
+            InputScenario::kTap);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_observer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_matching_observer);
+}
+
+TEST_F(ProcessPerformanceScenariosTest, NoMemory) {
+  MockSinglePageInSingleProcessGraph mock_graph(graph());
+
+  // First access to the PerformanceScenarioData uses a failing mapper.
+  FailingSharedMemoryMapper failing_mapper;
+  EXPECT_FALSE(PerformanceScenarioData::Exists(mock_graph.process.get()));
+  auto& data = PerformanceScenarioData::GetOrCreate(mock_graph.process.get(),
+                                                    &failing_mapper);
+  EXPECT_FALSE(data.HasSharedState());
+
+  // Reading the process scenario should return default values when memory
+  // mapping failed.
+  EXPECT_EQ(GetProcessLoadingScenario(mock_graph.process.get()),
+            LoadingScenario::kNoPageLoading);
+  EXPECT_EQ(GetProcessInputScenario(mock_graph.process.get()),
+            InputScenario::kNoInput);
+
+  // Writing to process state should do nothing. Observers should not be
+  // notified.
+  MockPerformanceScenarioObserver mock_observer;
+  base::ScopedObservation<ProcessNode, PerformanceScenarioObserver> observation(
+      &mock_observer);
+  observation.Observe(mock_graph.process.get());
+
+  MockMatchingScenarioObserver mock_matching_observer(
+      performance_scenarios::kDefaultIdleScenarios);
+  base::ScopedObservation<ProcessNode, MatchingScenarioObserver>
+      matching_observation(&mock_matching_observer);
+  matching_observation.Observe(mock_graph.process.get());
+
+  SetLoadingScenarioForProcessNode(LoadingScenario::kVisiblePageLoading,
+                                   mock_graph.process.get());
+  SetInputScenarioForProcessNode(InputScenario::kTyping,
+                                 mock_graph.process.get());
+  EXPECT_EQ(GetProcessLoadingScenario(mock_graph.process.get()),
+            LoadingScenario::kNoPageLoading);
+  EXPECT_EQ(GetProcessInputScenario(mock_graph.process.get()),
+            InputScenario::kNoInput);
+}
+
+}  // namespace performance_manager
diff --git a/components/permissions/notifications_engagement_service.h b/components/permissions/notifications_engagement_service.h
index 19b0e83..fcdadca 100644
--- a/components/permissions/notifications_engagement_service.h
+++ b/components/permissions/notifications_engagement_service.h
@@ -46,6 +46,8 @@
   static std::map<std::pair<ContentSettingsPattern, ContentSettingsPattern>,
                   int>
   GetNotificationCountMapPerPatternPair(const HostContentSettingsMap* hcsm);
+  static int GetDailyAverageNotificationCount(
+      const base::Value::Dict& engagement);
 
   static std::string GetBucketLabel(base::Time time);
   static std::optional<base::Time> ParsePeriodBeginFromBucketLabel(
@@ -58,8 +60,6 @@
 
   static int GetDailyAverageNotificationCount(
       const ContentSettingPatternSource& setting);
-  static int GetDailyAverageNotificationCount(
-      const base::Value::Dict& engagement);
 
   raw_ptr<PrefService> pref_service_;
   raw_ptr<content::BrowserContext> browser_context_;
diff --git a/components/signin/core/browser/signin_metrics_service.cc b/components/signin/core/browser/signin_metrics_service.cc
index ff3e6ce5..6fc2827 100644
--- a/components/signin/core/browser/signin_metrics_service.cc
+++ b/components/signin/core/browser/signin_metrics_service.cc
@@ -189,6 +189,8 @@
         kHistorySyncOptinExpansionPillOnInactivity:
     case signin_metrics::AccessPoint::kHistorySyncEducationalTip:
     case signin_metrics::AccessPoint::kManagedProfileAutoSigninIos:
+    case signin_metrics::AccessPoint::kNonModalSigninPasswordPromo:
+    case signin_metrics::AccessPoint::kNonModalSigninBookmarkPromo:
       return;
   }
 
diff --git a/components/signin/public/base/signin_metrics.cc b/components/signin/public/base/signin_metrics.cc
index 8f64c95..11672776 100644
--- a/components/signin/public/base/signin_metrics.cc
+++ b/components/signin/public/base/signin_metrics.cc
@@ -592,6 +592,14 @@
       base::RecordAction(base::UserMetricsAction(
           "Signin_Signin_FromHistorySyncOptinExpansionPillOnInactivity"));
       break;
+    case AccessPoint::kNonModalSigninPasswordPromo:
+      base::RecordAction(base::UserMetricsAction(
+          "Signin_Signin_FromNonModalSigninPasswordPromo"));
+      break;
+    case AccessPoint::kNonModalSigninBookmarkPromo:
+      base::RecordAction(base::UserMetricsAction(
+          "Signin_Signin_FromNonModalSigninBookmarkPromo"));
+      break;
   }
 }
 
@@ -766,6 +774,8 @@
     case AccessPoint::kHistorySyncOptinExpansionPillOnInactivity:
     case AccessPoint::kHistorySyncEducationalTip:
     case AccessPoint::kManagedProfileAutoSigninIos:
+    case AccessPoint::kNonModalSigninPasswordPromo:
+    case AccessPoint::kNonModalSigninBookmarkPromo:
       NOTREACHED() << "Signin_Impression_From* user actions are not recorded "
                       "for access point "
                    << static_cast<int>(access_point);
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index ec8b288..31eaaee 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -284,10 +284,14 @@
   // iOS only: The user switched to a managed account for the first time, and
   // the corresponding profile was automatically signed in.
   kManagedProfileAutoSigninIos = 82,
+  // iOS only: Access point for the contextual non modal sign-in password promo.
+  kNonModalSigninPasswordPromo = 83,
+  // iOS only: Access point for the contextual non modal sign-in bookmark promo.
+  kNonModalSigninBookmarkPromo = 84,
   // Add values above this line with a corresponding label to the
   // "SigninAccessPoint" enum in
   // tools/metrics/histograms/metadata/signin/enums.xml.
-  kMaxValue = kManagedProfileAutoSigninIos,  // This must be last.
+  kMaxValue = kNonModalSigninBookmarkPromo,  // This must be last.
 };
 // LINT.ThenChange(/tools/metrics/histograms/metadata/signin/enums.xml)
 
diff --git a/components/signin/public/base/signin_metrics_unittest.cc b/components/signin/public/base/signin_metrics_unittest.cc
index 48f9e9a..788db859 100644
--- a/components/signin/public/base/signin_metrics_unittest.cc
+++ b/components/signin/public/base/signin_metrics_unittest.cc
@@ -50,6 +50,8 @@
     AccessPoint::kProductSpecifications,
     AccessPoint::kAddressBubble,
     AccessPoint::kGlicLaunchButton,
+    AccessPoint::kNonModalSigninPasswordPromo,
+    AccessPoint::kNonModalSigninBookmarkPromo,
 };
 
 const AccessPoint kAccessPointsThatSupportImpression[] = {
@@ -234,6 +236,10 @@
         return "HistorySyncEducationalTip";
       case AccessPoint::kManagedProfileAutoSigninIos:
         return "ManagedProfileAutoSigninIos";
+      case AccessPoint::kNonModalSigninPasswordPromo:
+        return "NonModalSigninPasswordPromo";
+      case AccessPoint::kNonModalSigninBookmarkPromo:
+        return "NonModalSigninBookmarkPromo";
     }
   }
 };
diff --git a/components/url_formatter/url_fixer.cc b/components/url_formatter/url_fixer.cc
index 38f97710..2bd6afe 100644
--- a/components/url_formatter/url_fixer.cc
+++ b/components/url_formatter/url_fixer.cc
@@ -414,7 +414,7 @@
   // brackets are not in the whitelist.
   url::StdStringCanonOutput canon_scheme_output(canon_scheme);
   url::Component canon_scheme_component;
-  if (!url::CanonicalizeScheme(text.data(), *scheme_component,
+  if (!url::CanonicalizeScheme(scheme_component->as_string_view_on(text.data()),
                                &canon_scheme_output, &canon_scheme_component)) {
     return false;
   }
diff --git a/components/url_pattern/url_pattern_util.cc b/components/url_pattern/url_pattern_util.cc
index 6e56c10..cad3fcf 100644
--- a/components/url_pattern/url_pattern_util.cc
+++ b/components/url_pattern/url_pattern_util.cc
@@ -49,9 +49,7 @@
   url::RawCanonOutputT<char> canon_output;
   url::Component component;
 
-  bool result = url::CanonicalizeScheme(
-      input.data(), url::Component(0, base::checked_cast<int>(input.size())),
-      &canon_output, &component);
+  bool result = url::CanonicalizeScheme(input, &canon_output, &component);
 
   if (!result) {
     return base::unexpected(absl::InvalidArgumentError(
diff --git a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
index e2b524c9..d1426068 100644
--- a/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
+++ b/content/app_shim_remote_cocoa/render_widget_host_view_cocoa.mm
@@ -481,7 +481,7 @@
   NSRect textRectInViewCoordinates =
       [self convertRect:textRectInWindowCoordinates fromView:nil];
 
-  NSUInteger capturedChangeCounter = _availableTextChangeCounter;
+  ui::TextInputType capturedTextInputType = _textInputType;
 
   [self.spellChecker
       showCorrectionIndicatorOfType:NSCorrectionIndicatorTypeDefault
@@ -492,13 +492,13 @@
                   completionHandler:^(NSString* acceptedString) {
                     [self didAcceptReplacementString:acceptedString
                                forTextCheckingResult:candidateResult
-                                    withChangeNumber:capturedChangeCounter];
+                                   withTextInputType:capturedTextInputType];
                   }];
 }
 
 - (void)didAcceptReplacementString:(NSString*)acceptedString
              forTextCheckingResult:(NSTextCheckingResult*)correction
-                  withChangeNumber:(NSUInteger)changeNumber {
+                 withTextInputType:(ui::TextInputType)textInputType {
   // TODO: Keep NSSpellChecker up to date on the user's response via
   // -recordResponse:toCorrection:forWord:language:inSpellDocumentWithTag:.
   // Call it to report whether they initially accepted or rejected the
@@ -507,6 +507,12 @@
   if (acceptedString == nil)
     return;
 
+  // If the text input type is different now than when we set up the callback,
+  // the text replacement operation is stale and can be ignored.
+  if (textInputType != _textInputType) {
+    return;
+  }
+
   NSRange availableTextRange =
       NSMakeRange(_availableTextOffset, _availableText.length());
 
@@ -529,18 +535,6 @@
                                                      language:nil])
       return;
 
-    // Gather some info in case -doubleClickAtIndex: throws an exception.
-    // This change will eventually be reverted.
-    NSString* info = [NSString
-        stringWithFormat:@"%lu == %lu %lu %@ %@ %@ %@", changeNumber,
-                         _availableTextChangeCounter, attString.string.length,
-                         NSStringFromRange(availableTextRange),
-                         NSStringFromRange(correction.range),
-                         NSStringFromRange(trailingRange),
-                         NSStringFromRange(trailingRangeInAvailableText)];
-    SCOPED_CRASH_KEY_STRING256("RenderWidgetHostViewCocoa", "didAcceptTR",
-                               base::SysNSStringToUTF8(info));
-
     if ([attString doubleClickAtIndex:trailingRangeInAvailableText.location]
             .location < trailingRangeInAvailableText.location)
       return;
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.h b/content/browser/accessibility/dump_accessibility_tree_browsertest.h
index 3e010e4..b6fa1d75 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.h
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.h
@@ -27,6 +27,9 @@
 
 // See content/test/data/accessibility/readme.md for an overview.
 //
+// Use tools/accessibility/rebase_dump_accessibility_tree_tests.py to
+// update test expectations.
+//
 // This test takes a snapshot of the platform BrowserAccessibility tree and
 // tests it against an expected baseline.
 //
diff --git a/content/browser/preloading/prefetch/prefetch_service.h b/content/browser/preloading/prefetch/prefetch_service.h
index de3d3dc..7779198 100644
--- a/content/browser/preloading/prefetch/prefetch_service.h
+++ b/content/browser/preloading/prefetch/prefetch_service.h
@@ -107,15 +107,6 @@
   virtual PrefetchOriginProber* GetPrefetchOriginProber() const;
   virtual void PrefetchUrl(base::WeakPtr<PrefetchContainer> prefetch_container);
 
-  // Finds the prefetch (if any) that can be used to serve a navigation to
-  // |url|, and then calls |on_prefetch_to_serve_ready| with that prefetch.
-  using OnPrefetchToServeReady =
-      base::OnceCallback<void(PrefetchContainer::Reader prefetch_to_serve)>;
-  void GetPrefetchToServe(const PrefetchContainer::Key& key,
-                          base::WeakPtr<PrefetchServingPageMetricsContainer>
-                              serving_page_metrics_container,
-                          PrefetchMatchResolver& prefetch_match_resolver);
-
   // Copies any cookies in the isolated network context associated with
   // |prefetch_container| to the default network context.
   virtual void CopyIsolatedCookies(const PrefetchContainer::Reader& reader);
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index e2bc8ad0b..06dfcf6 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -123,6 +123,12 @@
 namespace content {
 namespace {
 
+// Feature to skip a redundant NavigationRequest creation for bfcache
+// activations, per https://crbug.com/417251428.
+BASE_FEATURE(kSkipExtraBfcacheNavigationRequest,
+             "SkipExtraBfcacheNavigationRequest",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Invoked when entries have been pruned, or removed. For example, if the
 // current entries are [google, digg, yahoo], with the current entry google,
 // and the user types in cnet, then digg and yahoo are pruned.
@@ -3317,29 +3323,49 @@
   // Navigate immediately if the document is in the BackForwardCache.
   if (back_forward_cache_.GetOrEvictEntry(nav_entry_id).has_value()) {
     TRACE_EVENT0("navigation", "BackForwardCache_CreateNavigationRequest");
-    DCHECK_EQ(reload_type, ReloadType::NONE);
-    auto navigation_request = CreateNavigationRequestFromEntry(
-        root, pending_entry_, pending_entry_->GetFrameEntry(root),
-        ReloadType::NONE, false /* is_same_document_history_load */,
-        false /* is_history_navigation_in_new_child */, initiator_frame_token,
-        initiator_process_id);
-    base::WeakPtr<NavigationRequest> request = navigation_request->GetWeakPtr();
-    root->navigator().Navigate(std::move(navigation_request), ReloadType::NONE);
+    CHECK_EQ(reload_type, ReloadType::NONE);
+    base::WeakPtr<NavigationRequest> request;
 
-    for (auto& unused_request : same_document_loads) {
-      unused_request->set_navigation_discard_reason(
-          NavigationDiscardReason::kNeverStarted);
-    }
-    for (auto& unused_request : different_document_loads) {
-      unused_request->set_navigation_discard_reason(
-          NavigationDiscardReason::kNeverStarted);
+    // Skip a redundant NavigationRequest creation, per
+    // https://crbug.com/417251428.
+    if (base::FeatureList::IsEnabled(kSkipExtraBfcacheNavigationRequest)) {
+      // If the BackForwardCache can handle this request, it must be for a main
+      // frame, cross-document, non-reload request. This means there is only one
+      // item in `different_document_loads` and no `same_document_loads`.
+      CHECK_EQ(different_document_loads.size(), 1u);
+      CHECK(same_document_loads.empty());
+      request = different_document_loads.at(0)->GetWeakPtr();
+      root->navigator().Navigate(std::move(different_document_loads.at(0)),
+                                 ReloadType::NONE);
+    } else {
+      // The legacy approach creates a new NavigationRequest for the entry and
+      // discards any previously created NavigationRequests, even though the new
+      // request is identical to the sole existing request.
+      // TODO(crbug.com/417251428): Remove this path once we measure the impact.
+      auto navigation_request = CreateNavigationRequestFromEntry(
+          root, pending_entry_, pending_entry_->GetFrameEntry(root),
+          ReloadType::NONE, false /* is_same_document_history_load */,
+          false /* is_history_navigation_in_new_child */, initiator_frame_token,
+          initiator_process_id);
+      request = navigation_request->GetWeakPtr();
+      root->navigator().Navigate(std::move(navigation_request),
+                                 ReloadType::NONE);
+
+      for (auto& unused_request : same_document_loads) {
+        unused_request->set_navigation_discard_reason(
+            NavigationDiscardReason::kNeverStarted);
+      }
+      for (auto& unused_request : different_document_loads) {
+        unused_request->set_navigation_discard_reason(
+            NavigationDiscardReason::kNeverStarted);
+      }
     }
 
-    std::vector<base::WeakPtr<NavigationRequest>> bf_cache_request;
+    std::vector<base::WeakPtr<NavigationRequest>> bf_cache_requests;
     if (request) {
-      bf_cache_request.push_back(std::move(request));
+      bf_cache_requests.push_back(std::move(request));
     }
-    return bf_cache_request;
+    return bf_cache_requests;
   }
 
   // History navigation might try to reuse a specific BrowsingInstance, already
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 36a213d..a5f8882 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -15891,7 +15891,7 @@
   base::Value::Dict body;
   if (base::FeatureList::IsEnabled(
           blink::features::kCrashReportingAPIMoreContextData)) {
-    body.Set("is_top_level", IsOutermostMainFrame() ? "true" : "false");
+    body.Set("is_top_level", IsOutermostMainFrame() ? true : false);
     body.Set("visibility_state",
              GetVisibilityState() == PageVisibilityState::kVisible ? "visible"
                                                                    : "hidden");
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
index d71195a..569bc28 100644
--- a/content/browser/webid/federated_auth_request_impl.cc
+++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -68,7 +68,6 @@
 using blink::mojom::FederatedAuthRequestResult;
 using blink::mojom::IdentityProviderConfig;
 using blink::mojom::IdentityProviderConfigPtr;
-using blink::mojom::IdentityProviderGetParametersPtr;
 using blink::mojom::IdentityProviderRequestOptions;
 using blink::mojom::IdentityProviderRequestOptionsPtr;
 using blink::mojom::RegisterIdpStatus;
@@ -319,48 +318,7 @@
     std::vector<IdentityProviderGetParametersPtr> idp_get_params_ptrs,
     MediationRequirement requirement,
     RequestTokenCallback callback) {
-  // idp_get_params_ptrs sent from the renderer should be of size 1.
-  if (idp_get_params_ptrs.size() != 1u) {
-    ReportBadMessageAndDeleteThis("idp_get_params_ptrs should be of size 1.");
-    return;
-  }
-  // This could only happen with a compromised renderer process. We ensure that
-  // the provider list size is > 0 on the renderer side at the beginning of
-  // parsing |IdentityCredentialRequestOptions|.
-  for (auto& idp_get_params_ptr : idp_get_params_ptrs) {
-    if (idp_get_params_ptr->providers.size() == 0) {
-      ReportBadMessageAndDeleteThis("The provider list should not be empty.");
-      return;
-    }
-    if (idp_get_params_ptr->providers.size() > 10u) {
-      ReportBadMessageAndDeleteThis(
-          "The provider list should not be greater than 10.");
-      return;
-    }
-    if (idp_get_params_ptr->mode == RpMode::kActive &&
-        requirement == MediationRequirement::kSilent) {
-      ReportBadMessageAndDeleteThis(
-          "mediation: silent is not supported in active mode.");
-      return;
-    }
-  }
-
-  if (requirement == MediationRequirement::kConditional &&
-      !IsFedCmAutofillEnabled()) {
-    // The conditional mediation parameter can only be used when delegation
-    // is enabled while it is under development.
-    //
-    // TODO(crbug.com/380367784): handle all of the many cases in which a
-    // conditional mediation may interact with other features.
-    ReportBadMessageAndDeleteThis(
-        "Conditional mediation is not supported when both autofill and "
-        "delegation are disabled.");
-    return;
-  }
-
-  if (render_frame_host().IsNestedWithinFencedFrame()) {
-    ReportBadMessageAndDeleteThis(
-        "FedCM should not be allowed in fenced frame trees.");
+  if (ShouldTerminateRequest(idp_get_params_ptrs, requirement)) {
     return;
   }
 
@@ -409,12 +367,7 @@
     std::move(callback).Run(RequestTokenStatus::kError, std::nullopt, "",
                             /*error=*/nullptr,
                             /*is_auto_selected=*/false);
-    fedcm_metrics_.reset();
-    // If there's an existing auth request token callback, we will need to
-    // record metrics for it once it is resolved.
-    if (auth_request_token_callback_) {
-      MaybeCreateFedCmMetrics();
-    }
+    HandleMetricsForPotentialConcurrentRequests();
     return;
   }
 
@@ -427,19 +380,14 @@
     std::move(callback).Run(RequestTokenStatus::kError, std::nullopt, "",
                             /*error=*/nullptr,
                             /*is_auto_selected=*/false);
-    fedcm_metrics_.reset();
-    // If there's an existing auth request token callback, we will need to
-    // record metrics for it once it is resolved.
-    if (auth_request_token_callback_) {
-      MaybeCreateFedCmMetrics();
-    }
+    HandleMetricsForPotentialConcurrentRequests();
     return;
   }
 
   had_transient_user_activation_ =
       render_frame_host().HasTransientUserActivation();
-
   MaybeCreateFedCmMetrics();
+
   // Store the previous `idp_order_` value from this class. Note that this is {}
   // unless there is a pending request from the same RFH. In particular, this is
   // still {} if there is a pending request but from a different RFH.
@@ -450,84 +398,13 @@
       idp_order_.push_back(idp_ptr->config->config_url);
     }
   }
-
-  if (HasPendingRequest()) {
-    FederatedAuthRequestImpl* pending_request =
-        webid::GetPageData(render_frame_host().GetPage())
-            ->PendingWebIdentityRequest();
-
-    RpMode pending_request_rp_mode = pending_request->GetRpMode();
-    RpMode new_request_rp_mode = idp_get_params_ptrs[0]->mode;
-    fedcm_metrics_->RecordMultipleRequestsRpMode(
-        pending_request_rp_mode, new_request_rp_mode, idp_order_);
-
-    bool can_replace_pending_request =
-        had_transient_user_activation_ &&
-        new_request_rp_mode == RpMode::kActive &&
-        pending_request_rp_mode != RpMode::kActive;
-    if (!can_replace_pending_request) {
-      // Cancel this new request.
-      fedcm_metrics_->RecordRequestTokenStatus(
-          TokenStatus::kTooManyRequests, requirement, idp_order_,
-          /*num_idps_mismatch=*/0,
-          /*selected_idp_config_url=*/std::nullopt,
-          (idp_get_params_ptrs[0]->mode == blink::mojom::RpMode::kActive)
-              ? RpMode::kActive
-              : RpMode::kPassive,
-          /*use_other_account_result=*/std::nullopt,
-          /*verifying_dialog_result=*/std::nullopt,
-          api_permission_delegate_->AreThirdPartyCookiesEnabledInSettings()
-              ? FedCmThirdPartyCookiesStatus::kEnabledInSettings
-              : FedCmThirdPartyCookiesStatus::kDisabledInSettings,
-          webid::ComputeRequesterFrameType(render_frame_host(), origin(),
-                                           GetEmbeddingOrigin()),
-          /*has_signin_account=*/std::nullopt);
-
-      AddDevToolsIssue(
-          blink::mojom::FederatedAuthRequestResult::kTooManyRequests);
-      AddConsoleErrorMessage(
-          blink::mojom::FederatedAuthRequestResult::kTooManyRequests);
-
-      std::move(callback).Run(RequestTokenStatus::kErrorTooManyRequests,
-                              std::nullopt, "", /*error=*/nullptr,
-                              /*is_auto_selected=*/false);
-
-      // Since multiple `get` calls is not yet supported, if one IdP invokes the
-      // API while another request from different IdPs is in-flight, the new API
-      // call will be rejected. The two requests may be from different RFHs so
-      // we should calculate properly.
-      if (old_idp_order.empty()) {
-        fedcm_metrics_->RecordMultipleRequestsFromDifferentIdPs(
-            idp_order_ != pending_request->idp_order_);
-      } else {
-        fedcm_metrics_->RecordMultipleRequestsFromDifferentIdPs(idp_order_ !=
-                                                                old_idp_order);
-      }
-
-      // Reset to record kErrorTooManyRequests but recreate to continue
-      // recording for the pending request.
-      fedcm_metrics_.reset();
-      MaybeCreateFedCmMetrics();
-      idp_order_ = std::move(old_idp_order);
-      return;
-    }
-
-    // Cancel the pending request before starting the new active flow request.
-    // Set the old values before completing in case the pending request
-    // corresponds to one in this object.
-    std::vector<GURL> new_idp_order = std::move(idp_order_);
-    idp_order_ = std::move(old_idp_order);
-    pending_request->CompleteRequestWithError(
-        FederatedAuthRequestResult::kReplacedByActiveMode,
-        TokenStatus::kReplacedByActiveMode,
-        /*should_delay_callback=*/false);
-    CHECK(!auth_request_token_callback_);
-
-    // Some members were reset to false during CleanUp when replacing a passive
-    // flow from the same frame so we need to set them again.
-    had_transient_user_activation_ = true;
-    MaybeCreateFedCmMetrics();
-    idp_order_ = std::move(new_idp_order);
+  if (HasPendingRequest() &&
+      HandlePendingRequestAndCancelNewRequest(
+          old_idp_order, idp_get_params_ptrs, requirement)) {
+    std::move(callback).Run(RequestTokenStatus::kErrorTooManyRequests,
+                            std::nullopt, "", /*error=*/nullptr,
+                            /*is_auto_selected=*/false);
+    return;
   }
 
   should_complete_request_immediately_ = should_complete_request_immediately;
@@ -667,6 +544,7 @@
                                                   rp_context, rp_mode, format));
     }
   }
+
   if (any_idp_has_parameters || any_idp_has_custom_scopes) {
     FedCmRpParameters parameters;
     if (any_idp_has_custom_scopes && any_idp_has_parameters) {
@@ -1045,12 +923,7 @@
   }
   std::move(callback).Run(status);
   disconnect_request_.reset();
-  fedcm_metrics_.reset();
-  // If there's an existing auth request token callback, we will need to record
-  // metrics for it once it is resolved.
-  if (auth_request_token_callback_) {
-    MaybeCreateFedCmMetrics();
-  }
+  HandleMetricsForPotentialConcurrentRequests();
 }
 
 void FederatedAuthRequestImpl::OnClientMetadataResponseReceived(
@@ -3335,6 +3208,145 @@
   return IsFedCmShowFilteredAccountsEnabled() || accounts_remaining > 0u;
 }
 
+void FederatedAuthRequestImpl::HandleMetricsForPotentialConcurrentRequests() {
+  // Record UKM for the request that's completed, either successfully or with
+  // errors.
+  // TODO(crbug.com/417784830): fedcm_metrics_ should be bound to each request.
+  // Otherwise UKMs in a single flow may be recorded in different events.
+  fedcm_metrics_.reset();
+  // If there's an existing auth request token callback, we will need to
+  // record metrics for it once it is resolved.
+  if (auth_request_token_callback_) {
+    MaybeCreateFedCmMetrics();
+  }
+}
+
+bool FederatedAuthRequestImpl::ShouldTerminateRequest(
+    const std::vector<IdentityProviderGetParametersPtr>& idp_get_params_ptrs,
+    const MediationRequirement& requirement) {
+  // idp_get_params_ptrs sent from the renderer should be of size 1.
+  if (idp_get_params_ptrs.size() != 1u) {
+    ReportBadMessageAndDeleteThis("idp_get_params_ptrs should be of size 1.");
+    return true;
+  }
+  // This could only happen with a compromised renderer process. We ensure that
+  // the provider list size is > 0 on the renderer side at the beginning of
+  // parsing |IdentityCredentialRequestOptions|.
+  for (const auto& idp_get_params_ptr : idp_get_params_ptrs) {
+    if (idp_get_params_ptr->providers.size() == 0) {
+      ReportBadMessageAndDeleteThis("The provider list should not be empty.");
+      return true;
+    }
+    if (idp_get_params_ptr->providers.size() > 10u) {
+      ReportBadMessageAndDeleteThis(
+          "The provider list should not be greater than 10.");
+      return true;
+    }
+    if (idp_get_params_ptr->mode == RpMode::kActive &&
+        requirement == MediationRequirement::kSilent) {
+      ReportBadMessageAndDeleteThis(
+          "mediation: silent is not supported in active mode.");
+      return true;
+    }
+  }
+
+  if (requirement == MediationRequirement::kConditional &&
+      !IsFedCmAutofillEnabled()) {
+    // The conditional mediation parameter can only be used when delegation
+    // is enabled while it is under development.
+    //
+    // TODO(crbug.com/380367784): handle all of the many cases in which a
+    // conditional mediation may interact with other features.
+    ReportBadMessageAndDeleteThis(
+        "Conditional mediation is not supported when both autofill and "
+        "delegation are disabled.");
+    return true;
+  }
+
+  if (render_frame_host().IsNestedWithinFencedFrame()) {
+    ReportBadMessageAndDeleteThis(
+        "FedCM should not be allowed in fenced frame trees.");
+    return true;
+  }
+
+  return false;
+}
+
+bool FederatedAuthRequestImpl::HandlePendingRequestAndCancelNewRequest(
+    const std::vector<GURL>& old_idp_order,
+    const std::vector<IdentityProviderGetParametersPtr>& idp_get_params_ptrs,
+    const MediationRequirement& requirement) {
+  FederatedAuthRequestImpl* pending_request =
+      webid::GetPageData(render_frame_host().GetPage())
+          ->PendingWebIdentityRequest();
+
+  RpMode pending_request_rp_mode = pending_request->GetRpMode();
+  RpMode new_request_rp_mode = idp_get_params_ptrs[0]->mode;
+  fedcm_metrics_->RecordMultipleRequestsRpMode(pending_request_rp_mode,
+                                               new_request_rp_mode, idp_order_);
+
+  bool can_replace_pending_request = had_transient_user_activation_ &&
+                                     new_request_rp_mode == RpMode::kActive &&
+                                     pending_request_rp_mode != RpMode::kActive;
+  if (!can_replace_pending_request) {
+    // Cancel this new request.
+    fedcm_metrics_->RecordRequestTokenStatus(
+        TokenStatus::kTooManyRequests, requirement, idp_order_,
+        /*num_idps_mismatch=*/0,
+        /*selected_idp_config_url=*/std::nullopt,
+        (idp_get_params_ptrs[0]->mode == blink::mojom::RpMode::kActive)
+            ? RpMode::kActive
+            : RpMode::kPassive,
+        /*use_other_account_result=*/std::nullopt,
+        /*verifying_dialog_result=*/std::nullopt,
+        api_permission_delegate_->AreThirdPartyCookiesEnabledInSettings()
+            ? FedCmThirdPartyCookiesStatus::kEnabledInSettings
+            : FedCmThirdPartyCookiesStatus::kDisabledInSettings,
+        webid::ComputeRequesterFrameType(render_frame_host(), origin(),
+                                         GetEmbeddingOrigin()),
+        /*has_signin_account=*/std::nullopt);
+
+    AddDevToolsIssue(
+        blink::mojom::FederatedAuthRequestResult::kTooManyRequests);
+    AddConsoleErrorMessage(
+        blink::mojom::FederatedAuthRequestResult::kTooManyRequests);
+
+    // Since multiple `get` calls is not yet supported, if one IdP invokes the
+    // API while another request from different IdPs is in-flight, the new API
+    // call will be rejected. The two requests may be from different RFHs so
+    // we should calculate properly.
+    if (old_idp_order.empty()) {
+      fedcm_metrics_->RecordMultipleRequestsFromDifferentIdPs(
+          idp_order_ != pending_request->idp_order_);
+    } else {
+      fedcm_metrics_->RecordMultipleRequestsFromDifferentIdPs(idp_order_ !=
+                                                              old_idp_order);
+    }
+    idp_order_ = std::move(old_idp_order);
+    HandleMetricsForPotentialConcurrentRequests();
+    return true;
+  }
+
+  // Cancel the pending request before starting the new active flow request.
+  // Set the old values before completing in case the pending request
+  // corresponds to one in this object.
+  std::vector<GURL> new_idp_order = std::move(idp_order_);
+  idp_order_ = std::move(old_idp_order);
+  pending_request->CompleteRequestWithError(
+      FederatedAuthRequestResult::kReplacedByActiveMode,
+      TokenStatus::kReplacedByActiveMode,
+      /*should_delay_callback=*/false);
+  CHECK(!auth_request_token_callback_);
+
+  // Some members were reset to false during CleanUp when replacing a passive
+  // flow from the same frame so we need to set them again.
+  had_transient_user_activation_ = true;
+  MaybeCreateFedCmMetrics();
+  idp_order_ = std::move(new_idp_order);
+
+  return false;
+}
+
 RelyingPartyData FederatedAuthRequestImpl::CreateRpData() const {
   // We want to show the iframe origin if any IDP requests it.
   bool show_iframe_origin = false;
diff --git a/content/browser/webid/federated_auth_request_impl.h b/content/browser/webid/federated_auth_request_impl.h
index 00a3a3c..e17bd57 100644
--- a/content/browser/webid/federated_auth_request_impl.h
+++ b/content/browser/webid/federated_auth_request_impl.h
@@ -52,6 +52,7 @@
 class FederatedIdentityPermissionContextDelegate;
 class RenderFrameHost;
 
+using blink::mojom::IdentityProviderGetParametersPtr;
 using IdentityProviderDataPtr = scoped_refptr<content::IdentityProviderData>;
 using IdentityRequestAccountPtr =
     scoped_refptr<content::IdentityRequestAccount>;
@@ -389,6 +390,27 @@
       blink::mojom::FederatedAuthRequestResult result);
   void SendSuccessfulTokenRequestMetrics(const GURL& idp_config_url);
 
+  // When two APIs that are associated with the same frame, hence
+  // fedcm_metrics_, are triggered concurrently, we need to reset
+  // `fedcm_metrics` to record UKM for the first request when it's completed and
+  // recreate one for the second if needed.
+  void HandleMetricsForPotentialConcurrentRequests();
+
+  // Validates the input from the renderer and signals to terminate the request
+  // if needed.
+  bool ShouldTerminateRequest(
+      const std::vector<IdentityProviderGetParametersPtr>& idp_get_params_ptrs,
+      const MediationRequirement& requirement);
+
+  // If a new request is associated with active mode, it can replace the pending
+  // request with passive mode. Otherwise a new request will be cancelled when
+  // there's a pending request. Returns `true` if the new request needs to be
+  // cancelled.
+  bool HandlePendingRequestAndCancelNewRequest(
+      const std::vector<GURL>& old_idp_order,
+      const std::vector<IdentityProviderGetParametersPtr>& idps,
+      const MediationRequirement& requirement);
+
   void CleanUp();
 
   std::unique_ptr<IdpNetworkRequestManager> CreateNetworkManager();
diff --git a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
index f016086..a31c4136 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webcodecs_expectations.txt
@@ -148,37 +148,6 @@
 # Same with prefer-hardware
 crbug.com/371802469 [ amd-0x7340 angle-opengl asan graphite-disabled mac ] WebCodecs_Encode_camera_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
 
-# Flaky crashes that started when upgrading to Mac 15.4
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_ContentHint_hvc1.1.6.L123.00_detail [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_ContentHint_hvc1.1.6.L123.00_motion [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodeColorSpace_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodeDecode_arraybuffer_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodeDecode_camera_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodeDecode_capture_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodeDecode_hw_decoder_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodeDecode_offscreen_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodeDecode_sw_decoder_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_Encode_arraybuffer_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_Encode_camera_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_Encode_capture_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_Encode_hw_decoder_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_Encode_offscreen_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_Encode_sw_decoder_hvc1.1.6.L123.00_prefer-hardware [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodingFramerateResolutions_1920x1080_120_hvc1.1.6.L186.B0_prefer-hardware_quality [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodingFramerateResolutions_1920x1080_30_hvc1.1.6.L186.B0_prefer-hardware_quality [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodingFramerateResolutions_1920x1080_60_hvc1.1.6.L186.B0_prefer-hardware_quality [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodingFramerateResolutions_3840x2160_120_hvc1.1.6.L186.B0_prefer-hardware_quality [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodingFramerateResolutions_3840x2160_30_hvc1.1.6.L186.B0_prefer-hardware_quality [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodingFramerateResolutions_3840x2160_60_hvc1.1.6.L186.B0_prefer-hardware_quality [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodingModes_offscreen_hvc1.1.6.L123.00_prefer-hardware_constant_quality [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodingRateControl_hvc1.1.6.L123.00_prefer-hardware_constant_1500000 [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodingRateControl_hvc1.1.6.L123.00_prefer-hardware_variable_1500000 [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_EncodingRateControl_hvc1.1.6.L123.00_prefer-hardware_variable_2000000 [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_arraybuffer [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_capture [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_hw_decoder [ Failure ]
-crbug.com/416294710 [ sequoia intel-0x3e9b ] WebCodecs_FrameSizeChange_hvc1.1.6.L123.00_offscreen [ Failure ]
-
 crbug.com/389978730 [ win11 nvidia-0x2783 ] WebCodecs_EncodeColorSpace_av01.0.04M.08_prefer-hardware [ Failure ]
 
 # Win/AMD RX 7600 Failures
diff --git a/extensions/common/api/extension_action/action_info.cc b/extensions/common/api/extension_action/action_info.cc
index be3b3ee..6f71f1ef 100644
--- a/extensions/common/api/extension_action/action_info.cc
+++ b/extensions/common/api/extension_action/action_info.cc
@@ -163,22 +163,13 @@
     }
 
     if (!url_str->empty()) {
-      GURL popup_url = Extension::GetResourceURL(extension->url(), *url_str);
-
+      GURL popup_url = extension->GetResourceURL(*url_str);
       if (!popup_url.is_valid()) {
         *error = errors::kInvalidActionDefaultPopup;
         return nullptr;
       }
 
-      // Check popup is only for this extension.
-      if (extension->origin().IsSameOriginWith(popup_url)) {
-        result->default_popup_url = popup_url;
-      } else {
-        install_warnings->emplace_back(
-            extensions::manifest_errors::kInvalidExtensionOriginPopup,
-            GetManifestKeyForActionType(type),
-            extensions::manifest_keys::kActionDefaultPopup);
-      }
+      result->default_popup_url = popup_url;
     } else {
       // An empty string is treated as having no popup.
       DCHECK(result->default_popup_url.is_empty());
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc
index 6563b56..f82aaf92 100644
--- a/extensions/common/extension.cc
+++ b/extensions/common/extension.cc
@@ -308,9 +308,14 @@
 
 // static
 GURL Extension::GetResourceURL(const GURL& extension_url,
-                               std::string_view relative_path) {
+                               std::string_view relative_url) {
   DCHECK(extension_url.SchemeIs(kExtensionScheme));
-  return extension_url.Resolve(relative_path);
+  GURL resolved = extension_url.Resolve(relative_url);
+  if (!url::IsSameOriginWith(resolved, extension_url)) {
+    return GURL();
+  }
+
+  return resolved;
 }
 
 bool Extension::ResourceMatches(const URLPatternSet& pattern_set,
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index 0235f821..ec776e62 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -160,13 +160,21 @@
   // See Type definition in Manifest.
   Manifest::Type GetType() const;
 
-  // Returns an absolute url to a resource inside of an extension. The
+  // Returns an absolute URL to a resource inside of an extension. The
   // `extension_url` argument should be the url() from an Extension object. The
-  // `relative_path` can be untrusted user input. The returned URL will either
-  // be invalid() or a child of `extension_url`.
+  // `relative_url` can be untrusted user input. The returned URL will either be
+  // invalid() or a child of `extension_url`.
+  //
+  // Note that `relative_url` is treated as a URL-encoded string, e.g. "%21.txt"
+  // will refer to the "!.txt" file. Any query or fragment components in
+  // `relative_url` are included in the returned URL.
+  //
+  // `relative_url` may be an absolute URL as long as it is a child of
+  // `extension_url`.
+  //
   // NOTE: Static so that it can be used from multiple threads.
   static GURL GetResourceURL(const GURL& extension_url,
-                             std::string_view relative_path);
+                             std::string_view relative_url);
   GURL GetResourceURL(std::string_view relative_path) const {
     return GetResourceURL(url(), relative_path);
   }
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
index 4869978..8dc058a0 100644
--- a/extensions/common/manifest_constants.h
+++ b/extensions/common/manifest_constants.h
@@ -368,9 +368,9 @@
     "Empty 'export.allowlist' implies any extension can import this module.";
 inline constexpr char kInvalidExportAllowlistString[] =
     "Invalid value for 'export.allowlist[*]'.";
-inline constexpr char kInvalidExtensionOriginPopup[] =
-    "The default_popup path specified in the manifest is invalid. Ensure it is "
-    "a path to a file in this extension.";
+inline constexpr char kInvalidExtensionPopupPath[] =
+    "The specified popup path is invalid. Ensure it is a path to a file in "
+    "this extension.";
 inline constexpr char16_t kInvalidFileAccessList[] =
     u"Invalid value for 'file_access'.";
 inline constexpr char kInvalidFileAccessValue[] =
@@ -426,7 +426,7 @@
 inline constexpr char kInvalidImportVersion[] =
     "Invalid value for 'import[*].minimum_version'.";
 inline constexpr char kInvalidImportRepeatedImport[] =
-    "There are multiple occurences of the same extension ID in 'import'. Only "
+    "There are multiple occurrences of the same extension ID in 'import'. Only "
     "one version will be installed.";
 inline constexpr char kInvalidInputComponents[] =
     "Invalid value for 'input_components'";
@@ -436,7 +436,8 @@
     "Invalid value for 'input_components[*].layouts[*]";
 inline constexpr char kInvalidInputComponentName[] =
     "Invalid value for 'input_components[*].name";
-inline constexpr char kInvalidInputView[] = "Invalid value for 'input_view'.";
+inline constexpr char kInvalidInputView[] =
+    "Invalid value for 'input_components[*].input_view'.";
 inline constexpr char16_t kInvalidIsolation[] =
     u"Invalid value for 'app.isolation'.";
 inline constexpr char kInvalidIsolationValue[] =
@@ -532,7 +533,8 @@
     u"Invalid value for 'oauth2.client_id'.";
 inline constexpr char16_t kInvalidOfflineEnabled[] =
     u"Invalid value for 'offline_enabled'.";
-inline constexpr char kInvalidOptionsPage[] = "Invalid value for '*'.";
+inline constexpr char kInvalidOptionsPage[] =
+    "Invalid value for 'input_components[*].options_page'.";
 inline constexpr char16_t kInvalidOptionsPageExpectUrlInPackage[] =
     u"Invalid value for 'options_page'.  Value must be a relative path.";
 inline constexpr char16_t kInvalidOptionsPageInHostedApp[] =
diff --git a/extensions/common/manifest_handlers/extension_action_handler_unittest.cc b/extensions/common/manifest_handlers/extension_action_handler_unittest.cc
index 134db6ee..84556f9 100644
--- a/extensions/common/manifest_handlers/extension_action_handler_unittest.cc
+++ b/extensions/common/manifest_handlers/extension_action_handler_unittest.cc
@@ -197,7 +197,8 @@
   scoped_refptr<Extension> LoadExtensionWithDefaultPopup(
       const char* popup_file_name,
       int manifest_version,
-      TestExtensionDir* test_extension_dir) {
+      TestExtensionDir* test_extension_dir,
+      std::string* error) {
     const char* action_key =
         ActionInfo::GetManifestKeyForActionType(GetParam());
 
@@ -211,11 +212,9 @@
         manifest_version, action_key, popup_file_name));
     test_extension_dir->WriteFile(FILE_PATH_LITERAL("popup.html"), "");
 
-    std::string error;
     scoped_refptr<Extension> extension(file_util::LoadExtension(
         test_extension_dir->UnpackedPath(), mojom::ManifestLocation::kUnpacked,
-        Extension::NO_FLAGS, &error));
-    EXPECT_EQ(error, "");
+        Extension::NO_FLAGS, error));
     return extension;
   }
 };
@@ -334,11 +333,25 @@
   constexpr char valid_popup_file_name[] = "popup.html";
   TestExtensionDir test_extension_dir = TestExtensionDir();
   int manifest_version = GetManifestVersionForActionType(GetParam());
+  std::string error;
   scoped_refptr<Extension> test_extension = LoadExtensionWithDefaultPopup(
-      valid_popup_file_name, manifest_version, &test_extension_dir);
-  ASSERT_TRUE(test_extension);
-  EXPECT_FALSE(warnings_test_util::HasInstallWarning(
-      test_extension, manifest_errors::kInvalidExtensionOriginPopup));
+      valid_popup_file_name, manifest_version, &test_extension_dir, &error);
+  ASSERT_TRUE(test_extension) << error;
+
+  std::vector<InstallWarning> warnings;
+  if (GetParam() == ActionInfo::Type::kBrowser) {
+    warnings.emplace_back("Unrecognized manifest key 'browser_action'.");
+  }
+  if (manifest_version == 2) {
+    warnings.emplace_back(manifest_errors::kManifestV2IsDeprecatedWarning);
+  }
+  EXPECT_EQ(warnings, test_extension->install_warnings());
+
+  const ActionInfo* action_info =
+      GetActionInfoOfType(*test_extension, GetParam());
+  ASSERT_TRUE(action_info);
+  EXPECT_EQ(test_extension->GetResourceURL("popup.html"),
+            action_info->default_popup_url);
 }
 
 // Tests success when default_popup is empty.
@@ -346,11 +359,24 @@
   constexpr char empty_popup_file_name[] = "";
   TestExtensionDir test_extension_dir = TestExtensionDir();
   int manifest_version = GetManifestVersionForActionType(GetParam());
+  std::string error;
   scoped_refptr<Extension> test_extension = LoadExtensionWithDefaultPopup(
-      empty_popup_file_name, manifest_version, &test_extension_dir);
-  ASSERT_TRUE(test_extension);
-  EXPECT_FALSE(warnings_test_util::HasInstallWarning(
-      test_extension, manifest_errors::kInvalidExtensionOriginPopup));
+      empty_popup_file_name, manifest_version, &test_extension_dir, &error);
+  ASSERT_TRUE(test_extension) << error;
+
+  std::vector<InstallWarning> warnings;
+  if (GetParam() == ActionInfo::Type::kBrowser) {
+    warnings.emplace_back("Unrecognized manifest key 'browser_action'.");
+  }
+  if (manifest_version == 2) {
+    warnings.emplace_back(manifest_errors::kManifestV2IsDeprecatedWarning);
+  }
+  EXPECT_EQ(warnings, test_extension->install_warnings());
+
+  const ActionInfo* action_info =
+      GetActionInfoOfType(*test_extension, GetParam());
+  ASSERT_TRUE(action_info);
+  EXPECT_TRUE(action_info->default_popup_url.is_empty());
 }
 
 // Tests warning when the default_popup seems to be for another extension.
@@ -359,12 +385,13 @@
       "chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef/popup.html";
   TestExtensionDir test_extension_dir = TestExtensionDir();
   int manifest_version = GetManifestVersionForActionType(GetParam());
-  scoped_refptr<Extension> test_extension =
-      LoadExtensionWithDefaultPopup(other_extension_specified_popup_file_name,
-                                    manifest_version, &test_extension_dir);
-  ASSERT_TRUE(test_extension);
-  EXPECT_TRUE(warnings_test_util::HasInstallWarning(
-      test_extension, manifest_errors::kInvalidExtensionOriginPopup));
+  std::string error;
+  scoped_refptr<Extension> test_extension = LoadExtensionWithDefaultPopup(
+      other_extension_specified_popup_file_name, manifest_version,
+      &test_extension_dir, &error);
+  ASSERT_FALSE(test_extension);
+  ASSERT_EQ(base::UTF16ToUTF8(manifest_errors::kInvalidActionDefaultPopup),
+            error);
 }
 
 // Tests warning when the default_popup doesn't exist on file system.
@@ -372,11 +399,27 @@
   constexpr char nonexistent_popup_file_name[] = "nonexistent_popup.html";
   TestExtensionDir test_extension_dir = TestExtensionDir();
   int manifest_version = GetManifestVersionForActionType(GetParam());
+  std::string error;
   scoped_refptr<Extension> test_extension = LoadExtensionWithDefaultPopup(
-      nonexistent_popup_file_name, manifest_version, &test_extension_dir);
-  ASSERT_TRUE(test_extension);
-  EXPECT_TRUE(warnings_test_util::HasInstallWarning(
-      test_extension, manifest_errors::kNonexistentDefaultPopup));
+      nonexistent_popup_file_name, manifest_version, &test_extension_dir,
+      &error);
+  ASSERT_TRUE(test_extension) << error;
+
+  std::vector<InstallWarning> warnings;
+  if (GetParam() == ActionInfo::Type::kBrowser) {
+    warnings.emplace_back("Unrecognized manifest key 'browser_action'.");
+  }
+  if (manifest_version == 2) {
+    warnings.emplace_back(manifest_errors::kManifestV2IsDeprecatedWarning);
+  }
+  warnings.emplace_back(manifest_errors::kNonexistentDefaultPopup);
+  EXPECT_EQ(warnings, test_extension->install_warnings());
+
+  const ActionInfo* action_info =
+      GetActionInfoOfType(*test_extension, GetParam());
+  ASSERT_TRUE(action_info);
+  EXPECT_EQ(test_extension->GetResourceURL("nonexistent_popup.html"),
+            action_info->default_popup_url);
 }
 
 // Test the handling of the default_state key.
diff --git a/extensions/common/manifest_handlers/webview_info.cc b/extensions/common/manifest_handlers/webview_info.cc
index 2e1318ba..0aede66 100644
--- a/extensions/common/manifest_handlers/webview_info.cc
+++ b/extensions/common/manifest_handlers/webview_info.cc
@@ -169,13 +169,10 @@
         return false;
       }
 
-      GURL pattern_url =
-          Extension::GetResourceURL(extension->url(), item.GetString());
+      GURL pattern_url = extension->GetResourceURL(item.GetString());
       // If passed a non-relative URL (like http://example.com),
-      // Extension::GetResourceURL() will return that URL directly. (See
-      // https://crbug.com/1135236). Check if this happened by comparing the
-      // host.
-      if (pattern_url.host_piece() != extension->id()) {
+      // Extension::GetResourceURL() will return an invalid URL.
+      if (!pattern_url.is_valid()) {
         // NOTE: Warning instead of error because there are existing apps that
         // have this bug, and we don't want to hard-error on them.
         // https://crbug.com/856948.
diff --git a/extensions/renderer/api/core_extensions_renderer_api_provider.cc b/extensions/renderer/api/core_extensions_renderer_api_provider.cc
index 3ed51366..75b5db9f4 100644
--- a/extensions/renderer/api/core_extensions_renderer_api_provider.cc
+++ b/extensions/renderer/api/core_extensions_renderer_api_provider.cc
@@ -164,7 +164,6 @@
   } js_resources[] = {
       {"appView", IDR_APP_VIEW_JS},
       {"appViewElement", IDR_APP_VIEW_ELEMENT_JS},
-      {"appViewDeny", IDR_APP_VIEW_DENY_JS},
       {"entryIdManager", IDR_ENTRY_ID_MANAGER},
       {"extensionOptions", IDR_EXTENSION_OPTIONS_JS},
       {"extensionOptionsElement", IDR_EXTENSION_OPTIONS_ELEMENT_JS},
@@ -175,6 +174,10 @@
       {"fileEntryBindingUtil", IDR_FILE_ENTRY_BINDING_UTIL_JS},
       {"fileSystem", IDR_FILE_SYSTEM_CUSTOM_BINDINGS_JS},
 
+#if BUILDFLAG(ENABLE_PLATFORM_APPS)
+      {"appViewDeny", IDR_APP_VIEW_DENY_JS},
+#endif
+
 #if BUILDFLAG(ENABLE_GUEST_VIEW)
       {"guestView", IDR_GUEST_VIEW_JS},
       {"guestViewAttributes", IDR_GUEST_VIEW_ATTRIBUTES_JS},
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
index e0e171bb..4d84506 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_mediator.mm
@@ -156,6 +156,8 @@
         kHistorySyncOptinExpansionPillOnInactivity:
     case signin_metrics::AccessPoint::kHistorySyncEducationalTip:
     case signin_metrics::AccessPoint::kManagedProfileAutoSigninIos:
+    case signin_metrics::AccessPoint::kNonModalSigninPasswordPromo:
+    case signin_metrics::AccessPoint::kNonModalSigninBookmarkPromo:
       // Nothing prevents instantiating ConsistencyDefaultAccountViewController
       // with an arbitrary entry point, API-wise. In doubt, no label is a good,
       // generic default that fits all entry points.
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin_promo/coordinator/non_modal_signin_promo_coordinator.mm b/ios/chrome/browser/authentication/ui_bundled/signin_promo/coordinator/non_modal_signin_promo_coordinator.mm
index df11d06..149dd42 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin_promo/coordinator/non_modal_signin_promo_coordinator.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin_promo/coordinator/non_modal_signin_promo_coordinator.mm
@@ -238,12 +238,23 @@
 
   [self hideBannerUI];
 
+  // Select the appropriate access point based on promo type
+  signin_metrics::AccessPoint accessPoint;
+  switch (_promoType) {
+    case SignInPromoType::kPassword:
+      accessPoint = signin_metrics::AccessPoint::kNonModalSigninPasswordPromo;
+      break;
+    case SignInPromoType::kBookmark:
+      accessPoint = signin_metrics::AccessPoint::kNonModalSigninBookmarkPromo;
+      break;
+  }
+
   id<ApplicationCommands> handler = HandlerForProtocol(
       self.browser->GetCommandDispatcher(), ApplicationCommands);
   ShowSigninCommand* const showSigninCommand = [[ShowSigninCommand alloc]
       initWithOperation:AuthenticationOperation::kSheetSigninAndHistorySync
                identity:nil
-            accessPoint:signin_metrics::AccessPoint::kNtpSignedOutIcon
+            accessPoint:accessPoint
             promoAction:signin_metrics::PromoAction::
                             PROMO_ACTION_NO_SIGNIN_PROMO
              completion:nil];
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin_promo_view_mediator.mm b/ios/chrome/browser/authentication/ui_bundled/signin_promo_view_mediator.mm
index a1e7759..736495a8 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin_promo_view_mediator.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin_promo_view_mediator.mm
@@ -138,6 +138,8 @@
         kHistorySyncOptinExpansionPillOnInactivity:
     case signin_metrics::AccessPoint::kHistorySyncEducationalTip:
     case signin_metrics::AccessPoint::kManagedProfileAutoSigninIos:
+    case signin_metrics::AccessPoint::kNonModalSigninPasswordPromo:
+    case signin_metrics::AccessPoint::kNonModalSigninBookmarkPromo:
       return false;
   }
 }
@@ -236,6 +238,8 @@
         kHistorySyncOptinExpansionPillOnInactivity:
     case signin_metrics::AccessPoint::kHistorySyncEducationalTip:
     case signin_metrics::AccessPoint::kManagedProfileAutoSigninIos:
+    case signin_metrics::AccessPoint::kNonModalSigninPasswordPromo:
+    case signin_metrics::AccessPoint::kNonModalSigninBookmarkPromo:
       NOTREACHED() << "Unexpected value for access point "
                    << static_cast<int>(access_point);
   }
@@ -335,6 +339,8 @@
         kHistorySyncOptinExpansionPillOnInactivity:
     case signin_metrics::AccessPoint::kHistorySyncEducationalTip:
     case signin_metrics::AccessPoint::kManagedProfileAutoSigninIos:
+    case signin_metrics::AccessPoint::kNonModalSigninPasswordPromo:
+    case signin_metrics::AccessPoint::kNonModalSigninBookmarkPromo:
       NOTREACHED() << "Unexpected value for access point "
                    << static_cast<int>(access_point);
   }
@@ -423,6 +429,8 @@
         kHistorySyncOptinExpansionPillOnInactivity:
     case signin_metrics::AccessPoint::kHistorySyncEducationalTip:
     case signin_metrics::AccessPoint::kManagedProfileAutoSigninIos:
+    case signin_metrics::AccessPoint::kNonModalSigninPasswordPromo:
+    case signin_metrics::AccessPoint::kNonModalSigninBookmarkPromo:
       return nullptr;
   }
 }
@@ -510,6 +518,8 @@
         kHistorySyncOptinExpansionPillOnInactivity:
     case signin_metrics::AccessPoint::kHistorySyncEducationalTip:
     case signin_metrics::AccessPoint::kManagedProfileAutoSigninIos:
+    case signin_metrics::AccessPoint::kNonModalSigninPasswordPromo:
+    case signin_metrics::AccessPoint::kNonModalSigninBookmarkPromo:
       return nullptr;
   }
 }
diff --git a/ios/chrome/browser/settings/ui_bundled/downloads/BUILD.gn b/ios/chrome/browser/settings/ui_bundled/downloads/BUILD.gn
index f1c0e87..e29f0ce 100644
--- a/ios/chrome/browser/settings/ui_bundled/downloads/BUILD.gn
+++ b/ios/chrome/browser/settings/ui_bundled/downloads/BUILD.gn
@@ -72,6 +72,7 @@
     "//ios/chrome/browser/authentication/ui_bundled/signin:constants",
     "//ios/chrome/browser/authentication/ui_bundled/signin:constants",
     "//ios/chrome/browser/authentication/ui_bundled/signin:signin_headers",
+    "//ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin",
     "//ios/chrome/browser/authentication/ui_bundled/views",
     "//ios/chrome/browser/photos/model:photos_service_factory",
     "//ios/chrome/browser/settings/ui_bundled/downloads:identity_button_cell",
diff --git a/ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_coordinator.mm b/ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_coordinator.mm
index 8229cd6..25f7194 100644
--- a/ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_coordinator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_coordinator.mm
@@ -5,7 +5,9 @@
 #import "ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_coordinator.h"
 
 #import "components/prefs/pref_service.h"
+#import "ios/chrome/browser/authentication/ui_bundled/continuation.h"
 #import "ios/chrome/browser/authentication/ui_bundled/signin/signin_constants.h"
+#import "ios/chrome/browser/authentication/ui_bundled/signin/signin_coordinator.h"
 #import "ios/chrome/browser/download/coordinator/auto_deletion/auto_deletion_settings_mediator.h"
 #import "ios/chrome/browser/photos/model/photos_service.h"
 #import "ios/chrome/browser/photos/model/photos_service_factory.h"
@@ -47,6 +49,8 @@
 
   // Auto deletion settings mediator.
   AutoDeletionSettingsMediator* _autoDeletionSettingsMediator;
+  // The signin coordinator, if it is opened.
+  SigninCoordinator* _signinCoordinator;
 }
 
 @synthesize baseNavigationController = _baseNavigationController;
@@ -103,6 +107,7 @@
 }
 
 - (void)stop {
+  [self stopSigninCoordinator];
   [_saveToPhotosSettingsMediator disconnect];
   _saveToPhotosSettingsMediator = nil;
 
@@ -159,26 +164,39 @@
 #pragma mark - SaveToPhotosSettingsAccountSelectionViewControllerActionDelegate
 
 - (void)saveToPhotosSettingsAccountSelectionViewControllerAddAccount {
-  id<ApplicationCommands> applicationCommandsHandler = HandlerForProtocol(
-      self.browser->GetCommandDispatcher(), ApplicationCommands);
+  SigninContextStyle contextStyle = SigninContextStyle::kDefault;
+  signin_metrics::AccessPoint accessPoint =
+      signin_metrics::AccessPoint::kSaveToPhotosIos;
+
   __weak __typeof(self) weakSelf = self;
-  ShowSigninCommand* addAccountCommand = [[ShowSigninCommand alloc]
-      initWithOperation:AuthenticationOperation::kAddAccount
-               identity:nil
-            accessPoint:signin_metrics::AccessPoint::kSaveToPhotosIos
-            promoAction:signin_metrics::PromoAction::
-                            PROMO_ACTION_NO_SIGNIN_PROMO
-             completion:^(SigninCoordinatorResult result,
-                          id<SystemIdentity> signinIdentity) {
-               __strong __typeof(weakSelf) strongSelf = weakSelf;
-               if (strongSelf && result == SigninCoordinatorResultSuccess &&
-                   signinIdentity) {
-                 [strongSelf->_saveToPhotosSettingsMediator
-                     setSelectedIdentityGaiaID:signinIdentity.gaiaID];
-               }
-             }];
-  [applicationCommandsHandler showSignin:addAccountCommand
-                      baseViewController:self.baseViewController];
+  _signinCoordinator = [SigninCoordinator
+      addAccountCoordinatorWithBaseViewController:self.baseViewController
+                                          browser:self.browser
+                                     contextStyle:contextStyle
+                                      accessPoint:accessPoint
+                             continuationProvider:
+                                 DoNothingContinuationProvider()];
+  _signinCoordinator.signinCompletion = ^(SigninCoordinatorResult result,
+                                          id<SystemIdentity> signinIdentity) {
+    [weakSelf signinCoordinatorCompletion:result signinIdentity:signinIdentity];
+  };
+  [_signinCoordinator start];
+}
+
+#pragma mark - Private
+
+- (void)stopSigninCoordinator {
+  [_signinCoordinator stop];
+  _signinCoordinator = nil;
+}
+
+- (void)signinCoordinatorCompletion:(SigninCoordinatorResult)result
+                     signinIdentity:(id<SystemIdentity>)signinIdentity {
+  [self stopSigninCoordinator];
+  if (result == SigninCoordinatorResultSuccess && signinIdentity) {
+    [_saveToPhotosSettingsMediator
+        setSelectedIdentityGaiaID:signinIdentity.gaiaID];
+  }
 }
 
 @end
diff --git a/ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_coordinator_unittest.mm b/ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_coordinator_unittest.mm
index 0203084..6feb192 100644
--- a/ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_coordinator_unittest.mm
+++ b/ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_coordinator_unittest.mm
@@ -6,7 +6,10 @@
 
 #import "base/apple/foundation_util.h"
 #import "components/signin/public/identity_manager/identity_test_environment.h"
+#import "ios/chrome/browser/authentication/ui_bundled/continuation.h"
+#import "ios/chrome/browser/authentication/ui_bundled/signin/add_account_signin/add_account_signin_coordinator.h"
 #import "ios/chrome/browser/authentication/ui_bundled/signin/signin_constants.h"
+#import "ios/chrome/browser/authentication/ui_bundled/signin/signin_coordinator.h"
 #import "ios/chrome/browser/photos/model/photos_service_factory.h"
 #import "ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_table_view_controller.h"
 #import "ios/chrome/browser/settings/ui_bundled/downloads/downloads_settings_table_view_controller_action_delegate.h"
@@ -52,11 +55,6 @@
 
     base_navigation_controller_ = [[FakeUINavigationController alloc] init];
 
-    mock_application_commands_handler_ =
-        OCMStrictProtocolMock(@protocol(ApplicationCommands));
-    [browser_->GetCommandDispatcher()
-        startDispatchingToTarget:mock_application_commands_handler_
-                     forProtocol:@protocol(ApplicationCommands)];
     mock_settings_commands_handler_ =
         OCMStrictProtocolMock(@protocol(SettingsCommands));
     [browser_->GetCommandDispatcher()
@@ -143,7 +141,6 @@
   id mock_save_to_photos_settings_mediator_;
   id mock_downloads_settings_table_view_controller_;
   id mock_save_to_photos_settings_account_selection_view_controller_;
-  id mock_application_commands_handler_;
   id mock_settings_commands_handler_;
 };
 
@@ -311,27 +308,33 @@
   CreateMockDownloadsSettingsTableViewControllerStubbed(true);
   CreateMockSaveToPhotosSettingsAccountSelectionViewControllerStubbed(true);
   [coordinator start];
+  AddAccountSigninCoordinator* signin_coordinator_mock =
+      OCMClassMock([AddAccountSigninCoordinator class]);
+  OCMExpect([(id)signin_coordinator_mock alloc])
+      .andReturn(signin_coordinator_mock);
+  OCMExpect([signin_coordinator_mock
+                initWithBaseViewController:[OCMArg any]
+                                   browser:browser_.get()
+                              contextStyle:SigninContextStyle::kDefault
+                               accessPoint:signin_metrics::AccessPoint::
+                                               kSaveToPhotosIos
+                               promoAction:signin_metrics::PromoAction::
+                                               PROMO_ACTION_NO_SIGNIN_PROMO
+                              signinIntent:AddAccountSigninIntent::kAddAccount
+                      continuationProvider:DoNothingContinuationProvider()])
+      .ignoringNonObjectArgs()
+      .andReturn(signin_coordinator_mock);
 
   // Expect that a ShowSigninCommand is dispatched to show the Add account view
   // when -saveToPhotosSettingsAccountSelectionViewControllerAddAccount is
   // called.
   __block SigninCoordinatorCompletionCallback show_signin_callback = nil;
-  OCMExpect([mock_application_commands_handler_
-              showSignin:[OCMArg checkWithBlock:^BOOL(
-                                     ShowSigninCommand* command) {
-                EXPECT_TRUE(command.completion);
-                show_signin_callback = command.completion;
-                EXPECT_EQ(AuthenticationOperation::kAddAccount,
-                          command.operation);
-                EXPECT_FALSE(command.identity);
-                EXPECT_EQ(signin_metrics::AccessPoint::kSaveToPhotosIos,
-                          command.accessPoint);
-                EXPECT_EQ(
-                    signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO,
-                    command.promoAction);
-                return YES;
-              }]
-      baseViewController:base_navigation_controller_]);
+
+  OCMExpect([signin_coordinator_mock
+      setSigninCompletion:[OCMArg checkWithBlock:^BOOL(id value) {
+        show_signin_callback = value;
+        return YES;
+      }]]);
 
   // Call the coordinator through the action delegate protocol and verify the
   // ShowSigninCommand was dispatched.
@@ -343,7 +346,6 @@
       id<SaveToPhotosSettingsAccountSelectionViewControllerActionDelegate>>(
       coordinator)
       saveToPhotosSettingsAccountSelectionViewControllerAddAccount];
-  EXPECT_OCMOCK_VERIFY(mock_application_commands_handler_);
 
   // Expect that the selected identity Gaia ID is set to the Gaia ID of the
   // identity that was just added.
diff --git a/media/gpu/mac/vt_video_encode_accelerator_mac.mm b/media/gpu/mac/vt_video_encode_accelerator_mac.mm
index d861be61..215c4bb 100644
--- a/media/gpu/mac/vt_video_encode_accelerator_mac.mm
+++ b/media/gpu/mac/vt_video_encode_accelerator_mac.mm
@@ -720,12 +720,17 @@
       std::move(frame), encoder_color_space_.value_or(gfx::ColorSpace()),
       frame_qp);
 
-  // We can pass the ownership of |request| to the encode callback if
-  // successful. Otherwise let it fall out of scope.
+  // Pass the ownership of `request` to the encode callback, then release the
+  // smart pointer.
+  //
+  // NOTE: When encoding fails, VT still holds the `sourceFrameRefcon`, and
+  // either the `CompressionCallback` or VT itself may still use this resource
+  // afterwards. Therefore, we always release the smart pointer here.
   OSStatus status = VTCompressionSessionEncodeFrame(
       compression_session_.get(), pixel_buffer.get(), timestamp_cm, duration_cm,
-      NSToCFPtrCast(frame_props), reinterpret_cast<void*>(request.get()),
+      NSToCFPtrCast(frame_props), reinterpret_cast<void*>(request.release()),
       nullptr);
+  ++pending_encodes_;
   if (status == kVTVideoEncoderNotAvailableNowErr ||
       status == kVTCouldNotCreateInstanceErr) {
     NotifyErrorStatus({EncoderStatus::Codes::kOutOfPlatformEncoders,
@@ -739,10 +744,6 @@
                            logging::DescriptionFromOSStatus(status)});
     return;
   }
-  ++pending_encodes_;
-  // We successfully passed ownership to `sourceFrameRefcon` parameter
-  // of `VTCompressionSessionEncodeFrame`, release the smart pointer.
-  request.release();
 }
 
 void VTVideoEncodeAccelerator::UseOutputBitstreamBuffer(
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 846e9c60..9391062 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -611,6 +611,8 @@
     "http/http_cache.h",
     "http/http_cache_transaction.cc",
     "http/http_cache_transaction.h",
+    "http/http_cache_util.cc",
+    "http/http_cache_util.h",
     "http/http_cache_writers.cc",
     "http/http_cache_writers.h",
     "http/http_chunked_decoder.cc",
diff --git a/net/device_bound_sessions/session_usage.h b/net/device_bound_sessions/session_usage.h
index 45fc9793..972d7b59 100644
--- a/net/device_bound_sessions/session_usage.h
+++ b/net/device_bound_sessions/session_usage.h
@@ -10,6 +10,9 @@
 // Represents per-request usage of a session for populating use
 // counters. This currently has the invariant that requests only move
 // from lower-valued usage enums to higher-valued ones.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+// LINT.IfChange(DeviceBoundSessionUsage)
 enum class SessionUsage {
   // Usage is unknown
   kUnknown = 0,
@@ -19,7 +22,9 @@
   kInScopeNotDeferred = 2,
   // Request was deferred by a session
   kDeferred = 3,
+  kMaxValue = kDeferred
 };
+// LINT.ThenChange(//tools/metrics/histograms/metadata/net/enums.xml:DeviceBoundSessionUsage)
 
 }  // namespace net::device_bound_sessions
 
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index e64a3398..fdc71064 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -55,6 +55,7 @@
 #include "net/disk_cache/disk_cache.h"
 #include "net/disk_cache/memory_entry_data_hints.h"
 #include "net/http/http_cache.h"
+#include "net/http/http_cache_util.h"
 #include "net/http/http_cache_writers.h"
 #include "net/http/http_log_util.h"
 #include "net/http/http_network_session.h"
@@ -101,63 +102,6 @@
           written_at_run_id.value() < clear_at_run_id.value());
 }
 
-// If the request includes one of these request headers, then avoid caching
-// to avoid getting confused.
-struct HeaderNameAndValue {
-  std::string_view name;
-  std::optional<std::string_view> value;
-};
-
-// If the request includes one of these request headers, then avoid caching
-// to avoid getting confused.
-constexpr auto kPassThroughHeaders = std::to_array(
-    {HeaderNameAndValue{"if-unmodified-since",
-                        std::nullopt},              // causes unexpected 412s
-     HeaderNameAndValue{"if-match", std::nullopt},  // causes unexpected 412s
-     HeaderNameAndValue{"if-range", std::nullopt}});
-
-struct ValidationHeaderInfo {
-  std::string_view request_header_name;
-  std::string_view related_response_header_name;
-};
-
-constexpr auto kValidationHeaders = std::to_array<ValidationHeaderInfo>(
-    {{"if-modified-since", "last-modified"}, {"if-none-match", "etag"}});
-
-// If the request includes one of these request headers, then avoid reusing
-// our cached copy if any.
-constexpr auto kForceFetchHeaders =
-    std::to_array({HeaderNameAndValue{"cache-control", "no-cache"},
-                   HeaderNameAndValue{"pragma", "no-cache"}});
-
-// If the request includes one of these request headers, then force our
-// cached copy (if any) to be revalidated before reusing it.
-constexpr auto kForceValidateHeaders =
-    std::to_array({HeaderNameAndValue{"cache-control", "max-age=0"}});
-
-bool HeaderMatches(const HttpRequestHeaders& headers,
-                   base::span<const HeaderNameAndValue> search_headers) {
-  for (const auto& search_header : search_headers) {
-    std::optional<std::string> header_value =
-        headers.GetHeader(search_header.name);
-    if (!header_value) {
-      continue;
-    }
-
-    if (!search_header.value) {
-      return true;
-    }
-
-    HttpUtil::ValuesIterator v(*header_value, ',');
-    while (v.GetNext()) {
-      if (base::EqualsCaseInsensitiveASCII(v.value(), *search_header.value)) {
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
 // Methods other than "GET" or "HEAD" can have request bodies, which causes
 // problems for the request matching.
 // TODO(https://crbug.com/390459312): Consider supporting additional methods.
@@ -181,10 +125,6 @@
       priority_(priority),
       cache_(cache->GetWeakPtr()),
       read_no_vary_search_cache_(cache->no_vary_search_cache_) {
-  static_assert(HttpCache::Transaction::kNumValidationHeaders ==
-                    std::size(kValidationHeaders),
-                "invalid number of validation headers");
-
   io_callback_ = base::BindRepeating(&Transaction::OnIOComplete,
                                      weak_factory_.GetWeakPtr());
   cache_io_callback_ = base::BindRepeating(&Transaction::OnCacheIOComplete,
@@ -1107,7 +1047,7 @@
     }
 
     // Downgrade to UPDATE if the request has been externally conditionalized.
-    if (external_validation_.initialized) {
+    if (external_validation_) {
       if (mode_ & WRITE) {
         // Strip off the READ_DATA bit (and maybe add back a READ_META bit
         // in case READ was off).
@@ -2603,7 +2543,7 @@
   // Reset the variables that might get set in this function. This is done
   // because this function can be invoked multiple times for a transaction.
   cache_entry_status_ = CacheEntryStatus::ENTRY_UNDEFINED;
-  external_validation_.Reset();
+  external_validation_.reset();
   range_requested_ = false;
   partial_.reset();
 
@@ -2622,58 +2562,26 @@
     effective_load_flags_ |= LOAD_DISABLE_CACHE;
   }
 
-  // Some headers imply load flags.  The order here is significant.
-  //
-  //   LOAD_DISABLE_CACHE   : no cache read or write
-  //   LOAD_BYPASS_CACHE    : no cache read
-  //   LOAD_VALIDATE_CACHE  : no cache read unless validation
-  //
-  // The former modes trump latter modes, so if we find a matching header we
-  // can stop iterating kSpecialHeaders.
-  static const struct {
-    // RAW_PTR_EXCLUSION: Never allocated by PartitionAlloc (always points to
-    // constexpr tables), so there is no benefit to using a raw_ptr, only cost.
-    RAW_PTR_EXCLUSION const base::span<const HeaderNameAndValue> search;
-    int load_flag;
-  } kSpecialHeaders[] = {
-      {kPassThroughHeaders, LOAD_DISABLE_CACHE},
-      {kForceFetchHeaders, LOAD_BYPASS_CACHE},
-      {kForceValidateHeaders, LOAD_VALIDATE_CACHE},
-  };
+  bool range_found =
+      request_->extra_headers.HasHeader(HttpRequestHeaders::kRange);
+  int load_flags_for_extra_headers =
+      http_cache_util::GetLoadFlagsForExtraHeaders(request_->extra_headers);
+  effective_load_flags_ |= load_flags_for_extra_headers;
 
-  bool range_found = false;
-  bool external_validation_error = false;
-  bool special_headers = false;
-
-  if (request_->extra_headers.HasHeader(HttpRequestHeaders::kRange)) {
-    range_found = true;
+  base::expected<std::optional<http_cache_util::ValidationHeaders>,
+                 std::string_view>
+      maybe_validation_headers =
+          http_cache_util::ValidationHeaders::MaybeCreate(
+              request_->extra_headers);
+  std::optional<std::string_view> external_validation_error;
+  if (maybe_validation_headers.has_value()) {
+    external_validation_ = std::move(maybe_validation_headers.value());
+  } else {
+    external_validation_error = maybe_validation_headers.error();
   }
 
-  for (const auto& special_header : kSpecialHeaders) {
-    if (HeaderMatches(request_->extra_headers, special_header.search)) {
-      effective_load_flags_ |= special_header.load_flag;
-      special_headers = true;
-      break;
-    }
-  }
-
-  // Check for conditionalization headers which may correspond with a
-  // cache validation request.
-  for (size_t i = 0; i < std::size(kValidationHeaders); ++i) {
-    const ValidationHeaderInfo& info = kValidationHeaders[i];
-    if (std::optional<std::string> validation_value =
-            request_->extra_headers.GetHeader(info.request_header_name);
-        validation_value) {
-      if (!external_validation_.values[i].empty() ||
-          validation_value->empty()) {
-        external_validation_error = true;
-      }
-      external_validation_.values[i] = std::move(validation_value).value();
-      external_validation_.initialized = true;
-    }
-  }
-
-  if (range_found || special_headers || external_validation_.initialized) {
+  if (range_found || load_flags_for_extra_headers || external_validation_ ||
+      external_validation_error) {
     // Log the headers before request_ is modified.
     std::string empty;
     NetLogRequestHeaders(net_log_,
@@ -2682,16 +2590,15 @@
   }
 
   // We don't support ranges and validation headers.
-  if (range_found && external_validation_.initialized) {
+  if (range_found && external_validation_) {
     LOG(WARNING) << "Byte ranges AND validation headers found.";
     effective_load_flags_ |= LOAD_DISABLE_CACHE;
   }
 
-  // If there is more than one validation header, we can't treat this request as
-  // a cache validation, since we don't know for sure which header the server
-  // will give us a response for (and they could be contradictory).
+  // If there is an invalid validation header, we can't treat this request as
+  // a cache validation.
   if (external_validation_error) {
-    LOG(WARNING) << "Multiple or malformed validation headers found.";
+    LOG(WARNING) << *external_validation_error;
     effective_load_flags_ |= LOAD_DISABLE_CACHE;
   }
 
@@ -2716,27 +2623,36 @@
 }
 
 bool HttpCache::Transaction::ShouldPassThrough() {
-  bool cacheable = true;
-
   // We may have a null disk_cache if there is an error we cannot recover from,
   // like not enough disk space, or sharing violations.
   if (!cache_->disk_cache_.get()) {
-    cacheable = false;
-  } else if (effective_load_flags_ & LOAD_DISABLE_CACHE) {
-    cacheable = false;
-  } else if (method_ == "GET" || method_ == "HEAD") {
-  } else if (method_ == "POST" && request_->upload_data_stream &&
-             request_->upload_data_stream->identifier()) {
-  } else if (method_ == "PUT" && request_->upload_data_stream) {
-  }
-  // DELETE and PATCH requests may result in invalidating the cache, so cannot
-  // just pass through.
-  else if (method_ == "DELETE" || method_ == "PATCH") {
-  } else {
-    cacheable = false;
+    return true;
   }
 
-  return !cacheable;
+  if (effective_load_flags_ & LOAD_DISABLE_CACHE) {
+    return true;
+  }
+
+  if (method_ == "GET" || method_ == "HEAD") {
+    return false;
+  }
+
+  if (method_ == "POST" && request_->upload_data_stream &&
+      request_->upload_data_stream->identifier()) {
+    return false;
+  }
+
+  if (method_ == "PUT" && request_->upload_data_stream) {
+    return false;
+  }
+
+  // DELETE and PATCH requests may result in invalidating the cache, so cannot
+  // just pass through.
+  if (method_ == "DELETE" || method_ == "PATCH") {
+    return false;
+  }
+
+  return true;
 }
 
 int HttpCache::Transaction::BeginCacheRead() {
@@ -2934,33 +2850,12 @@
   return OK;
 }
 
-bool HttpCache::Transaction::
-    ExternallyConditionalizedValidationHeadersMatchEntry() const {
-  DCHECK(external_validation_.initialized);
-
-  for (size_t i = 0; i < std::size(kValidationHeaders); i++) {
-    if (external_validation_.values[i].empty()) {
-      continue;
-    }
-
-    // Retrieve either the cached response's "etag" or "last-modified" header.
-    std::optional<std::string_view> validator =
-        response_.headers->EnumerateHeader(
-            nullptr, kValidationHeaders[i].related_response_header_name);
-
-    if (validator && *validator != external_validation_.values[i]) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
 int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {
   DCHECK_EQ(UPDATE, mode_);
+  CHECK(external_validation_);
 
   if (response_.headers->response_code() != HTTP_OK || truncated_ ||
-      !ExternallyConditionalizedValidationHeadersMatchEntry()) {
+      !external_validation_->Match(*response_.headers)) {
     // The externally conditionalized request is not a validation request
     // for our existing cache entry. Proceed with caching disabled.
     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
@@ -4029,9 +3924,6 @@
          entry_->writers()->HasTransaction(this);
 }
 
-HttpCache::Transaction::ValidationHeaders::ValidationHeaders() = default;
-HttpCache::Transaction::ValidationHeaders::~ValidationHeaders() = default;
-
 HttpCache::Transaction::NetworkTransactionInfo::NetworkTransactionInfo() =
     default;
 HttpCache::Transaction::NetworkTransactionInfo::~NetworkTransactionInfo() =
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 8623d95d..c6a60783 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -13,6 +13,7 @@
 
 #include <array>
 #include <memory>
+#include <optional>
 #include <string>
 
 #include "base/functional/callback.h"
@@ -31,6 +32,7 @@
 #include "net/base/request_priority.h"
 #include "net/base/tracing.h"
 #include "net/http/http_cache.h"
+#include "net/http/http_cache_util.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_response_info.h"
@@ -195,27 +197,6 @@
   void AddDiskCacheWriteTime(base::TimeDelta elapsed);
 
  private:
-  static const size_t kNumValidationHeaders = 2;
-  // Helper struct to pair a header name with its value, for
-  // headers used to validate cache entries.
-  struct ValidationHeaders {
-    ValidationHeaders();
-
-    ValidationHeaders(const ValidationHeaders&) = delete;
-    ValidationHeaders& operator=(const ValidationHeaders&) = delete;
-
-    ~ValidationHeaders();
-
-    std::array<std::string, kNumValidationHeaders> values;
-    void Reset() {
-      initialized = false;
-      for (auto& value : values) {
-        value.clear();
-      }
-    }
-    bool initialized = false;
-  };
-
   struct NetworkTransactionInfo {
     NetworkTransactionInfo();
 
@@ -413,10 +394,6 @@
   // the validation of the rest of the entry.  Returns a network error code.
   int ValidateEntryHeadersAndContinue();
 
-  // Returns whether the current externally conditionalized request's validation
-  // headers match the current cache entry's headers.
-  bool ExternallyConditionalizedValidationHeadersMatchEntry() const;
-
   // Called to start requests which were given an "if-modified-since" or
   // "if-none-match" validation header by the caller (NOT when the request was
   // conditionalized internally in response to LOAD_VALIDATE_CACHE).
@@ -678,8 +655,8 @@
   NetLogWithSource net_log_;
   HttpRequestHeaders request_headers_copy_;
   // If extra_headers specified a "if-modified-since" or "if-none-match",
-  // |external_validation_| contains the value of those headers.
-  ValidationHeaders external_validation_;
+  // `external_validation_` contains the value of those headers.
+  std::optional<http_cache_util::ValidationHeaders> external_validation_;
   base::WeakPtr<HttpCache> cache_;
   scoped_refptr<HttpCache::ActiveEntry> entry_;
   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 0d6fcb2..599e8ec 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -7045,6 +7045,54 @@
                                            kNetResponse1, kExtraRequestHeaders);
 }
 
+// Tests that a conditional request with an empty "If-Modified-Since" header
+// value bypasses the cache for that request due to the malformed header,
+// and does not update the existing cache entry. The original cache entry
+// (kNetResponse1) should still be served from cache subsequently.
+TEST_F(HttpCacheTest, ConditionalizedRequestEmptyIfModifiedSince) {
+  static const Response kNetResponse1 = {
+      "HTTP/1.1 200 OK",
+      "Date: Fri, 12 Jun 2009 21:46:42 GMT\n"
+      "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n",
+      "body1"};
+
+  static const Response kNetResponse2 = {
+      "HTTP/1.1 200 OK",
+      "Date: Wed, 22 Jul 2009 03:15:26 GMT\n"
+      "Last-Modified: Fri, 03 Jul 2009 02:14:27 GMT\n",
+      "body2"};
+
+  const char kExtraRequestHeaders[] = "If-Modified-Since:\r\n";
+
+  ConditionalizedRequestUpdatesCacheHelper(kNetResponse1, kNetResponse2,
+                                           kNetResponse1, kExtraRequestHeaders);
+}
+
+// Tests that a conditional request with an empty "If-None-Match" header
+// value bypasses the cache for that request due to the malformed header,
+// and does not update the existing cache entry. The original cache entry
+// (kNetResponse1) should still be served from cache subsequently.
+TEST_F(HttpCacheTest, ConditionalizedRequestEmptyIfNoneMatch) {
+  static const Response kNetResponse1 = {
+      "HTTP/1.1 200 OK",
+      "Date: Fri, 12 Jun 2009 21:46:42 GMT\n"
+      "Etag: \"Foo1\"\n"
+      "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n",
+      "body1"};
+
+  static const Response kNetResponse2 = {
+      "HTTP/1.1 200 OK",
+      "Date: Wed, 22 Jul 2009 03:15:26 GMT\n"
+      "Etag: \"Foo2\"\n"
+      "Last-Modified: Fri, 03 Jul 2009 02:14:27 GMT\n",
+      "body2"};
+
+  const char kExtraRequestHeaders[] = "If-None-Match:\r\n";
+
+  ConditionalizedRequestUpdatesCacheHelper(kNetResponse1, kNetResponse2,
+                                           kNetResponse1, kExtraRequestHeaders);
+}
+
 TEST_F(HttpCacheTest, UrlContainingHash) {
   MockHttpCache cache;
 
diff --git a/net/http/http_cache_util.cc b/net/http/http_cache_util.cc
new file mode 100644
index 0000000..5ceea4d
--- /dev/null
+++ b/net/http/http_cache_util.cc
@@ -0,0 +1,163 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/http/http_cache_util.h"
+
+#include <array>
+#include <optional>
+#include <string_view>
+
+#include "base/containers/span.h"
+#include "base/memory/raw_ptr_exclusion.h"
+#include "base/strings/string_util.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+
+namespace net::http_cache_util {
+
+namespace {
+
+// If the request includes one of these request headers, then avoid caching
+// to avoid getting confused.
+struct HeaderNameAndValue {
+  std::string_view name;
+  std::optional<std::string_view> value;
+};
+
+// If the request includes one of these request headers, then avoid caching
+// to avoid getting confused.
+constexpr auto kPassThroughHeaders = std::to_array(
+    {HeaderNameAndValue{"if-unmodified-since",
+                        std::nullopt},              // causes unexpected 412s
+     HeaderNameAndValue{"if-match", std::nullopt},  // causes unexpected 412s
+     HeaderNameAndValue{"if-range", std::nullopt}});
+
+// If the request includes one of these request headers, then avoid reusing
+// our cached copy if any.
+constexpr auto kForceFetchHeaders =
+    std::to_array({HeaderNameAndValue{"cache-control", "no-cache"},
+                   HeaderNameAndValue{"pragma", "no-cache"}});
+
+// If the request includes one of these request headers, then force our
+// cached copy (if any) to be revalidated before reusing it.
+constexpr auto kForceValidateHeaders =
+    std::to_array({HeaderNameAndValue{"cache-control", "max-age=0"}});
+
+bool HeaderMatches(const HttpRequestHeaders& headers,
+                   base::span<const HeaderNameAndValue> search_headers) {
+  for (const auto& search_header : search_headers) {
+    std::optional<std::string> header_value =
+        headers.GetHeader(search_header.name);
+    if (!header_value) {
+      continue;
+    }
+
+    if (!search_header.value) {
+      return true;
+    }
+
+    HttpUtil::ValuesIterator v(*header_value, ',');
+    while (v.GetNext()) {
+      if (base::EqualsCaseInsensitiveASCII(v.value(), *search_header.value)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+struct ValidationHeaderInfo {
+  std::string_view request_header_name;
+  std::string_view related_response_header_name;
+};
+
+constexpr auto kValidationHeaders = std::to_array<ValidationHeaderInfo>(
+    {{"if-modified-since", "last-modified"}, {"if-none-match", "etag"}});
+
+}  // namespace
+
+int GetLoadFlagsForExtraHeaders(const HttpRequestHeaders& extra_headers) {
+  // Some headers imply load flags.  The order here is significant.
+  //
+  //   LOAD_DISABLE_CACHE   : no cache read or write
+  //   LOAD_BYPASS_CACHE    : no cache read
+  //   LOAD_VALIDATE_CACHE  : no cache read unless validation
+  //
+  // The former modes trump latter modes, so if we find a matching header we
+  // can stop iterating kSpecialHeaders.
+  static const struct {
+    // RAW_PTR_EXCLUSION: Never allocated by PartitionAlloc (always points to
+    // constexpr tables), so there is no benefit to using a raw_ptr, only cost.
+    RAW_PTR_EXCLUSION const base::span<const HeaderNameAndValue> search;
+    int load_flag;
+  } kSpecialHeaders[] = {
+      {kPassThroughHeaders, LOAD_DISABLE_CACHE},
+      {kForceFetchHeaders, LOAD_BYPASS_CACHE},
+      {kForceValidateHeaders, LOAD_VALIDATE_CACHE},
+  };
+  for (const auto& special_header : kSpecialHeaders) {
+    if (HeaderMatches(extra_headers, special_header.search)) {
+      return special_header.load_flag;
+    }
+  }
+  static_assert(LOAD_NORMAL == 0);
+  return LOAD_NORMAL;
+}
+
+// static
+base::expected<std::optional<ValidationHeaders>, std::string_view>
+ValidationHeaders::MaybeCreate(const HttpRequestHeaders& extra_headers) {
+  static_assert(kNumValidationHeaders == std::size(kValidationHeaders),
+                "invalid number of validation headers");
+  ValidationHeaderValues values;
+  bool validation_header_found = false;
+  // Check for conditionalization headers which may correspond with a
+  // cache validation request.
+  for (size_t i = 0; i < std::size(kValidationHeaders); ++i) {
+    const ValidationHeaderInfo& info = kValidationHeaders[i];
+    if (std::optional<std::string> validation_value =
+            extra_headers.GetHeader(info.request_header_name)) {
+      if (validation_value->empty()) {
+        return base::unexpected("Empty validation header value found");
+      }
+      values[i] = std::move(*validation_value);
+      validation_header_found = true;
+    }
+  }
+  if (validation_header_found) {
+    return ValidationHeaders(std::move(values));
+  }
+  return std::nullopt;
+}
+
+ValidationHeaders::ValidationHeaders(ValidationHeaderValues values)
+    : values_(std::move(values)) {}
+
+ValidationHeaders::~ValidationHeaders() = default;
+
+ValidationHeaders::ValidationHeaders(ValidationHeaders&&) = default;
+ValidationHeaders& ValidationHeaders::operator=(ValidationHeaders&&) = default;
+
+bool ValidationHeaders::Match(
+    const HttpResponseHeaders& response_headers) const {
+  for (size_t i = 0; i < std::size(kValidationHeaders); i++) {
+    if (values_[i].empty()) {
+      continue;
+    }
+
+    // Retrieve either the cached response's "etag" or "last-modified" header.
+    std::optional<std::string_view> validator =
+        response_headers.EnumerateHeader(
+            nullptr, kValidationHeaders[i].related_response_header_name);
+
+    if (validator && *validator != values_[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace net::http_cache_util
diff --git a/net/http/http_cache_util.h b/net/http/http_cache_util.h
new file mode 100644
index 0000000..6641209
--- /dev/null
+++ b/net/http/http_cache_util.h
@@ -0,0 +1,70 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_HTTP_HTTP_CACHE_UTIL_H_
+#define NET_HTTP_HTTP_CACHE_UTIL_H_
+
+#include <optional>
+#include <string_view>
+
+#include "base/types/expected.h"
+
+namespace net {
+
+class HttpRequestHeaders;
+class HttpResponseHeaders;
+
+namespace http_cache_util {
+
+// Determines cache-related load flags based on the provided HTTP request
+// headers.
+//
+// This function inspects `extra_headers` for patterns implying specific cache
+// behaviors (e.g., "Cache-Control: no-cache", "If-Match"). It can return
+// flags like LOAD_DISABLE_CACHE, LOAD_BYPASS_CACHE, or LOAD_VALIDATE_CACHE.
+//
+// Returns an int representing the determined load flags , or 0 (LOAD_NORMAL) if
+// no special cache-related headers are found.
+int GetLoadFlagsForExtraHeaders(const HttpRequestHeaders& extra_headers);
+
+// Manages HTTP validation headers (e.g., If-Modified-Since, If-None-Match)
+// provided in a request. It can parse them from HttpRequestHeaders and
+// match them against HttpResponseHeaders.
+class ValidationHeaders {
+ public:
+  // Attempts to create a ValidationHeaders object by parsing
+  // "If-Modified-Since" and "If-None-Match" headers from the provided
+  // `extra_headers`. Returns an ValidationHeaders if one or more valid
+  // validation headers are found. Returns std::nullopt if no relevant headers
+  // are present. Returns base::unexpected on error (e.g., an empty header
+  // value).
+  static base::expected<std::optional<ValidationHeaders>, std::string_view>
+  MaybeCreate(const HttpRequestHeaders& extra_headers);
+
+  ~ValidationHeaders();
+
+  ValidationHeaders(const ValidationHeaders&) = delete;
+  ValidationHeaders& operator=(const ValidationHeaders&) = delete;
+
+  ValidationHeaders(ValidationHeaders&&);
+  ValidationHeaders& operator=(ValidationHeaders&&);
+
+  // Checks if the provided `response_headers` satisfy the validation
+  // conditions. This compares stored "If-Modified-Since" with "Last-Modified"
+  // and "If-None-Match" with "ETag" from the `response_headers`.
+  bool Match(const HttpResponseHeaders& response_headers) const;
+
+ private:
+  static const size_t kNumValidationHeaders = 2;
+  using ValidationHeaderValues = std::array<std::string, kNumValidationHeaders>;
+
+  explicit ValidationHeaders(ValidationHeaderValues values);
+
+  ValidationHeaderValues values_;
+};
+
+}  // namespace http_cache_util
+}  // namespace net
+
+#endif  // NET_HTTP_HTTP_CACHE_UTIL_H_
diff --git a/net/http/http_stream_pool_attempt_manager.cc b/net/http/http_stream_pool_attempt_manager.cc
index a2b6aafb..393d4e2 100644
--- a/net/http/http_stream_pool_attempt_manager.cc
+++ b/net/http/http_stream_pool_attempt_manager.cc
@@ -1624,14 +1624,16 @@
                                             dns_aliases);
   });
 
+  // This WeakPtr is to ensure `this` is not destroyed while notifying.
+  // TODO(crbug.com/417339803): Remove once we stabilize the implementation.
   base::WeakPtr<AttemptManager> weak_this = weak_ptr_factory_.GetWeakPtr();
-  while (weak_this && !streams.empty()) {
+  while (!streams.empty()) {
     std::unique_ptr<SpdyHttpStream> stream = std::move(streams.back());
     streams.pop_back();
     NotifyStreamReady(std::move(stream), NextProto::kProtoHTTP2);
-    // `this` may be deleted.
+    CHECK(weak_this);
   }
-  CHECK(!weak_this || jobs_.empty());
+  CHECK(jobs_.empty());
 }
 
 void HttpStreamPool::AttemptManager::MaybeCreateQuicStreamAndNotify(
@@ -1653,14 +1655,16 @@
         quic_session->CreateHandle(stream_key().destination()), dns_aliases);
   });
 
+  // This WeakPtr is to ensure `this` is not destroyed while notifying.
+  // TODO(crbug.com/417339803): Remove once we stabilize the implementation.
   base::WeakPtr<AttemptManager> weak_this = weak_ptr_factory_.GetWeakPtr();
-  while (weak_this && !streams.empty()) {
+  while (!streams.empty()) {
     std::unique_ptr<QuicHttpStream> stream = std::move(streams.back());
     streams.pop_back();
     NotifyStreamReady(std::move(stream), NextProto::kProtoQUIC);
-    // `this` may be deleted.
+    CHECK(weak_this);
   }
-  CHECK(!weak_this || jobs_.empty());
+  CHECK(jobs_.empty());
 }
 
 void HttpStreamPool::AttemptManager::NotifyStreamReady(
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index 625353f..3672a5f1 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -66,33 +66,10 @@
   // once https://crbug.com/458365 is resolved.
   static void SetSSLKeyLogger(std::unique_ptr<SSLKeyLogger> logger);
 
- protected:
-  void set_signed_cert_timestamps_received(
-      bool signed_cert_timestamps_received) {
-    signed_cert_timestamps_received_ = signed_cert_timestamps_received;
-  }
-
-  void set_stapled_ocsp_response_received(bool stapled_ocsp_response_received) {
-    stapled_ocsp_response_received_ = stapled_ocsp_response_received;
-  }
-
   // Serialize |next_protos| in the wire format for ALPN: protocols are listed
   // in order, each prefixed by a one-byte length.
   static std::vector<uint8_t> SerializeNextProtos(
       const NextProtoVector& next_protos);
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(SSLClientSocket, SerializeNextProtos);
-  // For signed_cert_timestamps_received_ and stapled_ocsp_response_received_.
-  FRIEND_TEST_ALL_PREFIXES(SSLClientSocketVersionTest,
-                           ConnectSignedCertTimestampsTLSExtension);
-  FRIEND_TEST_ALL_PREFIXES(SSLClientSocketVersionTest,
-                           ConnectSignedCertTimestampsEnablesOCSP);
-
-  // True if SCTs were received via a TLS extension.
-  bool signed_cert_timestamps_received_ = false;
-  // True if a stapled OCSP response was received.
-  bool stapled_ocsp_response_received_ = false;
 };
 
 // Shared state and configuration across multiple SSLClientSockets.
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 7e27804..b285bfe 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -906,16 +906,6 @@
 
   RecordNegotiatedProtocol();
 
-  const uint8_t* ocsp_response_raw;
-  size_t ocsp_response_len;
-  SSL_get0_ocsp_response(ssl_.get(), &ocsp_response_raw, &ocsp_response_len);
-  set_stapled_ocsp_response_received(ocsp_response_len != 0);
-
-  const uint8_t* sct_list;
-  size_t sct_list_len;
-  SSL_get0_signed_cert_timestamp_list(ssl_.get(), &sct_list, &sct_list_len);
-  set_signed_cert_timestamps_received(sct_list_len != 0);
-
   if (!IsRenegotiationAllowed())
     SSL_set_renegotiate_mode(ssl_.get(), ssl_renegotiate_never);
 
@@ -1070,21 +1060,20 @@
   const uint8_t* ocsp_response_raw;
   size_t ocsp_response_len;
   SSL_get0_ocsp_response(ssl_.get(), &ocsp_response_raw, &ocsp_response_len);
-  std::string_view ocsp_response(
-      reinterpret_cast<const char*>(ocsp_response_raw), ocsp_response_len);
+  base::span ocsp_response(ocsp_response_raw, ocsp_response_len);
 
   const uint8_t* sct_list_raw;
   size_t sct_list_len;
   SSL_get0_signed_cert_timestamp_list(ssl_.get(), &sct_list_raw, &sct_list_len);
-  std::string_view sct_list(reinterpret_cast<const char*>(sct_list_raw),
-                            sct_list_len);
+  base::span sct_list(sct_list_raw, sct_list_len);
 
   cert_verification_result_ = context_->cert_verifier()->Verify(
       CertVerifier::RequestParams(
           server_cert_,
           ech_name_override.empty() ? host_and_port_.host() : ech_name_override,
-          ssl_config_.GetCertVerifyFlags(), std::string(ocsp_response),
-          std::string(sct_list)),
+          ssl_config_.GetCertVerifyFlags(),
+          std::string(base::as_string_view(ocsp_response)),
+          std::string(base::as_string_view(sct_list))),
       &server_cert_verify_result_,
       base::BindOnce(&SSLClientSocketImpl::OnVerifyComplete,
                      base::Unretained(this)),
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index d811651..db63eb5 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -2724,8 +2724,6 @@
   ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
   EXPECT_THAT(rv, IsOk());
 
-  EXPECT_TRUE(sock_->signed_cert_timestamps_received_);
-
   ASSERT_EQ(cert_verifier_->GetVerifyParams().size(), 1u);
   const auto& params = cert_verifier_->GetVerifyParams().front();
   EXPECT_TRUE(params.certificate()->EqualsIncludingChain(
@@ -2756,7 +2754,12 @@
   ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
   EXPECT_THAT(rv, IsOk());
 
-  EXPECT_TRUE(sock_->stapled_ocsp_response_received_);
+  ASSERT_EQ(cert_verifier_->GetVerifyParams().size(), 1u);
+  const auto& params = cert_verifier_->GetVerifyParams().front();
+  EXPECT_TRUE(params.certificate()->EqualsIncludingChain(
+      embedded_test_server()->GetCertificate().get()));
+  EXPECT_EQ(params.hostname(), embedded_test_server()->host_port_pair().host());
+  EXPECT_FALSE(params.ocsp_response().empty());
 }
 
 // Tests that IsConnectedAndIdle and WasEverUsed behave as expected.
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 8781f09..d7ffce2 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -974,6 +974,9 @@
 
     base::UmaHistogramCounts100("Net.DeviceBoundSessions.RequestDeferralCount",
                                 device_bound_session_deferral_count_);
+    base::UmaHistogramEnumeration(
+        "Net.DeviceBoundSessions.RequestDeferralDecision",
+        request_->device_bound_session_usage());
     if (device_bound_session_deferral_count_ > 0) {
       base::UmaHistogramTimes(
           "Net.DeviceBoundSessions.TotalRequestDeferredDuration",
diff --git a/net/url_request/url_request_http_job_unittest.cc b/net/url_request/url_request_http_job_unittest.cc
index a4609b6..2fd8b1d 100644
--- a/net/url_request/url_request_http_job_unittest.cc
+++ b/net/url_request/url_request_http_job_unittest.cc
@@ -1603,6 +1603,7 @@
 
 TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
        DeferRequestIfNeeded) {
+  base::HistogramTester histogram_tester;
   const MockWrite writes[] = {
       MockWrite("GET / HTTP/1.1\r\n"
                 "Host: www.example.com\r\n"
@@ -1629,16 +1630,34 @@
               device_bound_sessions::Session::Id("test"));
         }));
     EXPECT_CALL(GetMockService(), DeferRequestForRefresh)
-        .WillOnce(base::test::RunOnceClosure<3>());
+        .WillOnce(Invoke([](URLRequest* request, Unused,
+                            device_bound_sessions::SessionServiceMock::
+                                RefreshCompleteCallback restart_callback,
+                            device_bound_sessions::SessionServiceMock::
+                                RefreshCompleteCallback continue_callback) {
+          request->set_device_bound_session_usage(
+              net::device_bound_sessions::SessionUsage::kDeferred);
+          std::move(restart_callback).Run();
+        }));
+    EXPECT_CALL(GetMockService(), ShouldDefer).WillOnce(Return(std::nullopt));
   }
 
   request_->Start();
   delegate_.RunUntilComplete();
   EXPECT_THAT(delegate_.request_status(), IsOk());
+  histogram_tester.ExpectUniqueSample(
+      "Net.DeviceBoundSessions.RequestDeferralCount",
+      /*sample=*/1,
+      /*expected_bucket_count=*/1);
+  histogram_tester.ExpectUniqueSample(
+      "Net.DeviceBoundSessions.RequestDeferralDecision",
+      /*sample=*/device_bound_sessions::SessionUsage::kDeferred,
+      /*expected_bucket_count=*/1);
 }
 
 TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
        DontDeferRequestIfNotNeeded) {
+  base::HistogramTester histogram_tester;
   const MockWrite writes[] = {
       MockWrite("GET / HTTP/1.1\r\n"
                 "Host: www.example.com\r\n"
@@ -1662,6 +1681,10 @@
   request_->Start();
   delegate_.RunUntilComplete();
   EXPECT_THAT(delegate_.request_status(), IsOk());
+  histogram_tester.ExpectUniqueSample(
+      "Net.DeviceBoundSessions.RequestDeferralCount",
+      /*sample=*/0,
+      /*expected_bucket_count=*/1);
 }
 
 TEST_F(URLRequestHttpJobWithMockSocketsDeviceBoundSessionServiceTest,
diff --git a/services/webnn/tflite/graph_builder_tflite.cc b/services/webnn/tflite/graph_builder_tflite.cc
index f096b4f..c9af27f 100644
--- a/services/webnn/tflite/graph_builder_tflite.cc
+++ b/services/webnn/tflite/graph_builder_tflite.cc
@@ -1790,6 +1790,53 @@
   return SerializeQuantizedOutput(*next_op);
 }
 
+std::optional<base::FixedArray<GraphBuilderTflite::TensorInfo>>
+GraphBuilderTflite::CanFuseQuantizeAndGetOutput(const mojom::Split& split) {
+  if (!IsDequantizeOutput(split.input_operand_id)) {
+    return std::nullopt;
+  }
+
+  // TODO(crbug.com/413083273): Consider the restriction in GPU delegate.
+  // For XNNPack delegate, the scale and zero point of input and output have to
+  // be scaler, and the number of outputs should be in the range of [2, 4]. But
+  // there is no limitation on the number of outputs for TFLite kernel, so relax
+  // the output number restriction here.
+  // https://source.chromium.org/chromium/chromium/src/+/main:third_party/tflite/src/tensorflow/lite/delegates/xnnpack/xnnpack_delegate.cc;l=5558;drc=1379ddb0f0535ff846ce0fbad8ee49af303140c4
+  const mojom::DequantizeLinear& input_dequantize =
+      GetDequantizeOp(split.input_operand_id);
+  if (!IsInts8AndScalarScale(input_dequantize)) {
+    return std::nullopt;
+  }
+
+  const size_t outputs_size = split.output_operand_ids.size();
+  const OperandDataType quantized_type =
+      GetOperand(input_dequantize.input_operand_id).descriptor.data_type();
+  base::FixedArray<std::pair<OperationId, QuantizateParametersOffset>>
+      quantize_ops(outputs_size);
+  for (size_t i = 0; i < outputs_size; ++i) {
+    std::optional<std::pair<OperationId, QuantizateParametersOffset>> next_op =
+        IsNextOpQuantize(split.output_operand_ids[i], {quantized_type});
+    if (!next_op) {
+      return std::nullopt;
+    }
+
+    OperationId quantize_op_id = next_op->first;
+    const mojom::QuantizeLinear& output_quantize =
+        GetQuantizeOp(quantize_op_id);
+    if (!IsInts8AndScalarScale(output_quantize)) {
+      return std::nullopt;
+    }
+    quantize_ops[i] = std::move(*next_op);
+  }
+
+  base::FixedArray<TensorInfo> output_tensor_infos(outputs_size);
+  for (size_t i = 0; i < outputs_size; ++i) {
+    output_tensor_infos[i] = SerializeQuantizedOutput(quantize_ops[i]);
+  }
+
+  return output_tensor_infos;
+}
+
 std::optional<GraphBuilderTflite::TensorInfo>
 GraphBuilderTflite::CanFuseQuantizeAndGetOutput(
     const mojom::Transpose& transpose) {
@@ -6657,17 +6704,31 @@
       /*buffer=*/std::array<int32_t, 1>{checked_axis.ValueOrDie()},
       /*dimensions=*/{});
 
+  std::optional<base::FixedArray<TensorInfo>> quantized_outputs =
+      CanFuseQuantizeAndGetOutput(split);
+  const bool fuse_dequantize = quantized_outputs.has_value();
+  ASSIGN_OR_RETURN(const TensorInfo& input_tensor_info,
+                   SerializeInputTensorInfo(
+                       split.input_operand_id, /*quantize_params=*/0,
+                       /*operation_supports_float16=*/false, fuse_dequantize));
+
   // Serialize the split sizes tensor that specifies the sizes of each output
   // tensor along the axis.
   const size_t outputs_size = split.output_operand_ids.size();
   base::FixedArray<int32_t> split_sizes(outputs_size);
   base::FixedArray<int32_t> op_outputs(outputs_size);
   for (size_t i = 0; i < outputs_size; ++i) {
-    const TensorInfo output_tensor_info =
-        SerializeOutputTensorInfo(split.output_operand_ids[i]);
-    CHECK_LT(split.axis, output_tensor_info.dimensions.size());
-    split_sizes[i] = output_tensor_info.dimensions[split.axis];
-    op_outputs[i] = output_tensor_info.index;
+    if (fuse_dequantize) {
+      CHECK_LT(split.axis, quantized_outputs->at(i).dimensions.size());
+      split_sizes[i] = quantized_outputs->at(i).dimensions[split.axis];
+      op_outputs[i] = quantized_outputs->at(i).index;
+    } else {
+      const TensorInfo output_tensor_info =
+          SerializeOutputTensorInfo(split.output_operand_ids[i]);
+      CHECK_LT(split.axis, output_tensor_info.dimensions.size());
+      split_sizes[i] = output_tensor_info.dimensions[split.axis];
+      op_outputs[i] = output_tensor_info.index;
+    }
   }
   const auto checked_split_size =
       base::MakeCheckedNum<int32_t>(split_sizes.size());
@@ -6683,8 +6744,6 @@
   const auto split_options = ::tflite::CreateSplitOptions(
       builder_, /*num_splits=*/checked_split_size.ValueOrDie());
 
-  ASSIGN_OR_RETURN(const TensorInfo& input_tensor_info,
-                   SerializeInputTensorInfo(split.input_operand_id));
   const OperatorCodeIndex operator_code_index =
       GetOperatorCodeIndex(::tflite::BuiltinOperator_SPLIT_V);
   // The order of inputs is input, split sizes tensor and then axis tensor as
diff --git a/services/webnn/tflite/graph_builder_tflite.h b/services/webnn/tflite/graph_builder_tflite.h
index d3aa8789d..d124929ff 100644
--- a/services/webnn/tflite/graph_builder_tflite.h
+++ b/services/webnn/tflite/graph_builder_tflite.h
@@ -726,6 +726,8 @@
       const mojom::Pool2d& pool2d);
   std::optional<TensorInfo> CanFuseQuantizeAndGetOutput(
       const mojom::Reshape& reshape);
+  std::optional<base::FixedArray<TensorInfo>> CanFuseQuantizeAndGetOutput(
+      const mojom::Split& split);
   std::optional<TensorInfo> CanFuseQuantizeAndGetOutput(
       const mojom::Transpose& transpose);
   std::optional<TensorInfo> CanFuseQuantizeAndGetOutput(
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c516bd5..d3d57c1 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -4956,35 +4956,6 @@
             ]
         }
     ],
-    "ChromnientIPH": [
-        {
-            "platforms": [
-                "chromeos",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "params": {
-                        "availability": "any",
-                        "event_trigger": "name:lens_overlay_iph_triggered;comparator:any;window:90;storage:365",
-                        "event_used": "name:lens_overlay_used;comparator:==0;window:90;storage:365",
-                        "session_rate": "==0",
-                        "x_url_allow_filters": "[\"*\"]",
-                        "x_url_block_filters": "[\"chegg.com\",\"brainly.com\",\"coursehero.com\",\"quizlet.com\",\"study.com\",\"tutor.com\",\"wyzant.com\",\"tutoring.k12.com\",\"varsitytutors.com\",\"studypool.com\",\"sylvanlearning.com\",\"skooli.com\",\"socratic.org\",\"schoolhouse.world\",\"google.com\",\"ai\",\"indeedassessments.com\",\"nytimes.com\",\"cnn.com\",\"foxnews.com\",\"people.com\",\"usatoday.com\",\"msn.com\",\"nypost.com\",\"apnews.com\",\"dailymail.co.uk\",\"news.google.com\",\"cnbc.com\",\"newsweek.com\",\"washingtonpost.com\",\"yahoo.com\",\"theguardian.com\",\"bbc.com\",\"wsj.com\",\"reuters.com\",\"breitbart.com\",\"bloomberg.com\",\"huffpost.com\",\"nbcnews.com\",\"businessinsider.com\",\"cbsnews.com\",\"usnews.com\",\"thegatewaypundit.com\",\"axios.com\",\"drudgereport.com\",\"theatlantic.com\",\"forbes.com\",\"npr.org\",\"espn.com\",\"latimes.com\",\"thecooldown.com\",\"zerohedge.com\",\"politico.com\",\"thehill.com\",\"weather.com\",\"marketwatch.com\",\"buzzfeed.com\",\"cbssports.com\",\"tmz.com\",\"slate.com\",\"vice.com\",\"salon.com\",\"theintercept.com\",\"inquirer.com\",\"chicagotribune.com\",\"bostonglobe.com\",\"upworthy.com\",\"geediting.com\",\"popularmechanics.com \",\"hindustantimes.com\",\"independent.co.uk\",\"uniladtech.com\",\"paypal.com\",\"capitalone.com\",\"chase.com\",\"finance.yahoo.com\",\"bankofamerica.com\",\"wellsfargo.com\",\"fidelity.com\",\"citi.com\",\"americanexpress.com\",\"schwab.com\",\"creditkarma.com\",\"experian.com\",\"discover.com\",\"usbank.com\",\"navyfederal.org\",\"pnc.com\",\"truist.com\",\"ally.com\",\"vanguard.com\",\"forbes.com\",\"intuit.com\",\"investopedia.com\",\"cnbc.com\",\"nerdwallet.com\",\"wsj.com\",\"marketwatch.com\",\"bloomberg.com\",\"reuters.com\",\"businessinsider.com\",\"cash.app\",\"venmo.com\",\"equifax.com\",\"transunion.com\",\"etrade.com\",\"robinhood.com\",\"morganstanley.com\",\"ml.com\",\"sofi.com\",\"chime.com\",\"huntington.com\",\"key.com\",\"citizensbank.com\",\"fifththird.com\",\"mtb.com\",\"regions.com\",\"santanderbank.com\",\"td.com\",\"usaa.com\",\"bankrate.com\",\"youtube.com\",\"facebook.com\",\"instagram.com\",\"tiktok.com\",\"x.com\",\"reddit.com\",\"pinterest.com\",\"linkedin.com\",\"whatsapp.com\",\"messenger.com\",\"snapchat.com\",\"twitch.tv\",\"discord.com\",\"telegram.org\",\"quora.com\",\"nextdoor.com\",\"tumblr.com\",\"threads.net\",\"blueskyweb.xyz\",\"mastodon.social\",\"medium.com\",\"vimeo.com\",\"flickr.com\",\"yelp.com\",\"bere.al\",\"kick.com\",\"behance.net\",\"deviantart.com\",\"goodreads.com\",\"clubhouse.com\",\"ello.co\",\"mewe.com\",\"signal.org\",\"glassdoor.com\",\"meetup.com\",\"houzz.com\",\"imgur.com\",\"letterboxd.com\",\"care2.com\",\"ravelry.com\",\"bandcamp.com\",\"soundcloud.com\",\"gaia.com\",\"caringbridge.org\",\"myspace.com\",\"livejournal.com\",\"classmates.com\",\"weheartit.com\",\"unofficialnetworks.com\",\"internalfb.com\",\"allrecipes.com\"]",
-                        "x_url_path_match_allow_patterns": "[\"(?i)assignments\",\"(?i)assignment\",\"(?i)assign\",\"(?i)assessment\",\"(?i)assessments\",\"(?i)homework\",\"(?i)quiz\",\"(?i)quizzes\",\"(?i)question\",\"(?i)questions\",\"(?i)exam\",\"(?i)exams\",\"(?i)task\",\"(?i)tasks\",\"(?i)attempt\",\"(?i)test\",\"(?i)tests\",\"(?i)worksheet\",\"(?i)worksheets\",\"(?i)science\",\"(?i)biology\",\"(?i)chemistry\",\"(?i)physics\",\"(?i)geology\",\"(?i)astronomy\",\"(?i)programming\",\"(?i)robotics\",\"(?i)engineering\",\"(?i)mechanics\",\"(?i)mathematics\",\"(?i)math\",\"(?i)algebra\",\"(?i)calculus\",\"(?i)geometry\",\"(?i)statistics\",\"(?i)sociology\",\"(?i)geography\",\"(?i)psychology\",\"(?i)literature\",\"(?i)archaeology\",\"(?i)economics\",\"(?i)accounting\",\"(?i)course\",\"(?i)courses\"]",
-                        "x_url_path_match_block_patterns": "[\"(?i)tutor\",\"(?i)protest\",\"(?i)latest\",\"(?i)account\",\"(?i)management\",\"(?i)login\",\"(?i)assessment\",\"(?i)apply\",\"(?i)questionnaire\",\"(?i)calendar\",\"(?i)news\",\"(?i)certification\",\"(?i)article\",\"(?i)download\",\"(?i)profile\",\"(?i)policy\",\"(?i)auth\",\"(?i)secure\"]",
-                        "x_wait_time": "60s"
-                    },
-                    "enable_features": [
-                        "IPH_LensOverlay"
-                    ]
-                }
-            ]
-        }
-    ],
     "ChromnientLatencyOptimizations": [
         {
             "platforms": [
@@ -5027,6 +4998,24 @@
             ]
         }
     ],
+    "ChromnientNewFeedback": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "NewFeedbackEnabled",
+                    "enable_features": [
+                        "LensSearchSidePanelNewFeedback"
+                    ]
+                }
+            ]
+        }
+    ],
     "ChromnientPostLaunchTranslate": [
         {
             "platforms": [
diff --git a/third_party/angle b/third_party/angle
index f5f6704..8d75490 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit f5f6704c1cf00faa87a8b55eec0988600a8128e6
+Subproject commit 8d75490aa47bc2be90e8b1bbeaae495bdf0a37e9
diff --git a/third_party/blink/public/mojom/indexeddb/indexeddb.mojom b/third_party/blink/public/mojom/indexeddb/indexeddb.mojom
index 9b0d0f41..264b5583 100644
--- a/third_party/blink/public/mojom/indexeddb/indexeddb.mojom
+++ b/third_party/blink/public/mojom/indexeddb/indexeddb.mojom
@@ -163,7 +163,7 @@
   kVersionError = 33,
   kAbortError = 20,
   kIgnorableAbortError = 11,
-  kQuotaError = 22,
+  kQuotaError = 37,
   kTimeoutError = 23,
 };
 
diff --git a/third_party/blink/renderer/bindings/generated_in_core.gni b/third_party/blink/renderer/bindings/generated_in_core.gni
index e0b3fe84..32b5721 100644
--- a/third_party/blink/renderer/bindings/generated_in_core.gni
+++ b/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -378,6 +378,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_property_definition.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_queuing_strategy_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_queuing_strategy_init.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_quota_exceeded_error_options.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_quota_exceeded_error_options.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_get_reader_options.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_get_reader_options.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_readable_stream_iterator_options.cc",
@@ -1352,6 +1354,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_progress_event.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_promise_rejection_event.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_promise_rejection_event.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_quota_exceeded_error.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_quota_exceeded_error.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_radio_node_list.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_radio_node_list.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_range.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_core.gni b/third_party/blink/renderer/bindings/idl_in_core.gni
index be1c11899..a8ade17f 100644
--- a/third_party/blink/renderer/bindings/idl_in_core.gni
+++ b/third_party/blink/renderer/bindings/idl_in_core.gni
@@ -188,6 +188,7 @@
   "//third_party/blink/renderer/core/dom/pointer_lock_options.idl",
   "//third_party/blink/renderer/core/dom/popover_invoker_element.idl",
   "//third_party/blink/renderer/core/dom/processing_instruction.idl",
+  "//third_party/blink/renderer/core/dom/quota_exceeded_error.idl",
   "//third_party/blink/renderer/core/dom/range.idl",
   "//third_party/blink/renderer/core/dom/shadow_root.idl",
   "//third_party/blink/renderer/core/dom/shadow_root_init.idl",
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
index 4f1e3faa8..0f5253c 100644
--- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -695,7 +695,7 @@
 
 // g-issues.chromium.org/issues/349835587
 // https://github.com/WICG/canvas-place-element
-static bool IsCanvasPlaceOrDrawElement(const Element* element) {
+static bool IsCanvasDrawElement(const Element* element) {
   if (RuntimeEnabledFeatures::CanvasDrawElementEnabled() && element &&
       element->IsInCanvasSubtree()) {
     // Placed elements are always immediate children of the canvas.
@@ -708,7 +708,7 @@
   return false;
 }
 
-static bool IsCanvasWithPlaceOrDrawElements(const Element* element) {
+static bool IsCanvasWithDrawElements(const Element* element) {
   if (!RuntimeEnabledFeatures::CanvasDrawElementEnabled() || !element) {
     return false;
   }
@@ -725,10 +725,10 @@
     const ComputedStyle& layout_parent_style,
     const Element* element,
     Document* document) {
-  bool is_canvas_place_or_draw_element = IsCanvasPlaceOrDrawElement(element);
+  bool is_canvas_draw_element = IsCanvasDrawElement(element);
 
   if ((layout_parent_style.BlockifiesChildren() && !HostIsInputFile(element)) ||
-      is_canvas_place_or_draw_element) {
+      is_canvas_draw_element) {
     builder.SetIsInBlockifyingDisplay();
     if (builder.Display() != EDisplay::kContents) {
       builder.SetDisplay(EquivalentBlockDisplay(builder.Display()));
@@ -737,13 +737,13 @@
       }
     }
     if (layout_parent_style.IsDisplayFlexibleOrGridBox() ||
-        layout_parent_style.IsDisplayMathType() ||
-        is_canvas_place_or_draw_element) {
+        layout_parent_style.IsDisplayMathType() || is_canvas_draw_element) {
       builder.SetIsInsideDisplayIgnoringFloatingChildren();
     }
 
-    if (is_canvas_place_or_draw_element) {
+    if (is_canvas_draw_element) {
       builder.SetPosition(EPosition::kStatic);
+      builder.SetContain(builder.Contain() | kContainsPaint);
     }
   }
 
@@ -1165,8 +1165,7 @@
       builder.Overlay() == EOverlay::kAuto ||
       builder.StyleType() == kPseudoIdBackdrop ||
       builder.StyleType() == kPseudoIdViewTransition ||
-      IsCanvasPlaceOrDrawElement(element) ||
-      IsCanvasWithPlaceOrDrawElements(element)) {
+      IsCanvasWithDrawElements(element)) {
     builder.SetForcesStackingContext(true);
   }
 
diff --git a/third_party/blink/renderer/core/dom/build.gni b/third_party/blink/renderer/core/dom/build.gni
index 9e799323..464901b 100644
--- a/third_party/blink/renderer/core/dom/build.gni
+++ b/third_party/blink/renderer/core/dom/build.gni
@@ -231,6 +231,8 @@
   "pseudo_element.cc",
   "pseudo_element.h",
   "pseudo_element_data.h",
+  "quota_exceeded_error.cc",
+  "quota_exceeded_error.h",
   "range.cc",
   "range.h",
   "range_boundary_point.h",
diff --git a/third_party/blink/renderer/core/dom/dom_exception.cc b/third_party/blink/renderer/core/dom/dom_exception.cc
index cea8135..8bcdbc3 100644
--- a/third_party/blink/renderer/core/dom/dom_exception.cc
+++ b/third_party/blink/renderer/core/dom/dom_exception.cc
@@ -30,6 +30,7 @@
 
 #include "base/notreached.h"
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/text/strcat.h"
 
 namespace blink {
@@ -189,6 +190,11 @@
       exception_code <= DOMExceptionCode::kLegacyErrorCodeMax) {
     return static_cast<uint16_t>(exception_code);
   }
+  if (!RuntimeEnabledFeatures::QuotaExceededErrorUpdateEnabled() &&
+      exception_code == DOMExceptionCode::kQuotaExceededError) {
+    // Return legacy error code.
+    return 22;
+  }
   return 0;
 }
 
diff --git a/third_party/blink/renderer/core/dom/quota_exceeded_error.cc b/third_party/blink/renderer/core/dom/quota_exceeded_error.cc
new file mode 100644
index 0000000..25a8169
--- /dev/null
+++ b/third_party/blink/renderer/core/dom/quota_exceeded_error.cc
@@ -0,0 +1,58 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/dom/quota_exceeded_error.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_quota_exceeded_error_options.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+
+namespace blink {
+
+// static
+QuotaExceededError* QuotaExceededError::Create(
+    const String& message,
+    const QuotaExceededErrorOptions* options) {
+  // Not doing AttachStackProperty is consistent with `new DOMException()`
+  // but should be updated to do so to match spec (crbug.com/40815519).
+  return MakeGarbageCollected<QuotaExceededError>(message, options);
+}
+
+// static
+v8::Local<v8::Value> QuotaExceededError::Create(
+    v8::Isolate* isolate,
+    const String& message,
+    std::optional<double> quota,
+    std::optional<double> requested) {
+  auto* options = QuotaExceededErrorOptions::Create(isolate);
+  if (quota) {
+    options->setQuota(quota.value());
+  }
+  if (requested) {
+    options->setRequested(requested.value());
+  }
+  auto* exception = MakeGarbageCollected<QuotaExceededError>(message, options);
+  return V8ThrowDOMException::AttachStackProperty(isolate, exception);
+}
+
+QuotaExceededError::QuotaExceededError(const String& message,
+                                       const QuotaExceededErrorOptions* options)
+    : DOMException(DOMExceptionCode::kQuotaExceededError, message),
+      quota_(options->hasQuota() ? std::make_optional(options->quota())
+                                 : std::nullopt),
+      requested_(options->hasRequested()
+                     ? std::make_optional(options->requested())
+                     : std::nullopt) {}
+
+QuotaExceededError::QuotaExceededError(const String& message,
+                                       std::optional<double> quota,
+                                       std::optional<double> requested)
+    : DOMException(DOMExceptionCode::kQuotaExceededError, message),
+      quota_(quota),
+      requested_(requested) {}
+
+QuotaExceededError::QuotaExceededError(const String& message)
+    : DOMException(DOMExceptionCode::kQuotaExceededError, message) {}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/quota_exceeded_error.h b/third_party/blink/renderer/core/dom/quota_exceeded_error.h
new file mode 100644
index 0000000..bf90283
--- /dev/null
+++ b/third_party/blink/renderer/core/dom/quota_exceeded_error.h
@@ -0,0 +1,50 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_QUOTA_EXCEEDED_ERROR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_QUOTA_EXCEEDED_ERROR_H_
+
+#include <optional>
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+
+namespace blink {
+
+class QuotaExceededErrorOptions;
+
+class CORE_EXPORT QuotaExceededError : public DOMException {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  // Constructor exposed to script. Called by the V8 bindings.
+  static QuotaExceededError* Create(const String& message,
+                                    const QuotaExceededErrorOptions* options);
+
+  // For creating a QuotaExceededError from C++ to be immediately passed to
+  // ScriptPromiseResolverBase::Reject.
+  static v8::Local<v8::Value> Create(v8::Isolate*,
+                                     const String& message,
+                                     std::optional<double> quota,
+                                     std::optional<double> requested);
+
+  QuotaExceededError(const String& message,
+                     const QuotaExceededErrorOptions* options);
+  QuotaExceededError(const String& message,
+                     std::optional<double> quota,
+                     std::optional<double> requested);
+  explicit QuotaExceededError(const String& message);
+
+  std::optional<double> quota() const { return quota_; }
+  std::optional<double> requested() const { return requested_; }
+
+ private:
+  std::optional<double> quota_;
+  std::optional<double> requested_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_DOM_QUOTA_EXCEEDED_ERROR_H_
diff --git a/third_party/blink/renderer/core/dom/quota_exceeded_error.idl b/third_party/blink/renderer/core/dom/quota_exceeded_error.idl
new file mode 100644
index 0000000..96bfb5e4
--- /dev/null
+++ b/third_party/blink/renderer/core/dom/quota_exceeded_error.idl
@@ -0,0 +1,18 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+dictionary QuotaExceededErrorOptions {
+    double quota;
+    double requested;
+};
+
+[
+    Exposed=*,
+    Serializable,
+    RuntimeEnabled=QuotaExceededErrorUpdate
+] interface QuotaExceededError : DOMException {
+    constructor(optional DOMString message = "", optional QuotaExceededErrorOptions options = {});
+    readonly attribute double? quota;
+    readonly attribute double? requested;
+};
diff --git a/third_party/blink/renderer/core/html/resources/html.css b/third_party/blink/renderer/core/html/resources/html.css
index e82b003..484370e 100644
--- a/third_party/blink/renderer/core/html/resources/html.css
+++ b/third_party/blink/renderer/core/html/resources/html.css
@@ -2112,5 +2112,4 @@
   select:-internal-list-box::picker-icon {
     display: none !important;
   }
-
 }
diff --git a/third_party/blink/renderer/core/scroll/scroll_into_view_util.cc b/third_party/blink/renderer/core/scroll/scroll_into_view_util.cc
index 20974abc..47a265a 100644
--- a/third_party/blink/renderer/core/scroll/scroll_into_view_util.cc
+++ b/third_party/blink/renderer/core/scroll/scroll_into_view_util.cc
@@ -593,15 +593,13 @@
       Intersection(non_zero_visible_rect, expose_rect_x).Width();
   if (intersect_width == expose_rect_no_margin.Width()) {
     // If the rectangle is fully visible, use the specified visible behavior.
-    // If the rectangle is partially visible, but over a certain threshold,
-    // then treat it as fully visible to avoid unnecessary horizontal scrolling
     scroll_x = align_x.rect_visible;
   } else if (intersect_width == non_zero_visible_rect.Width()) {
     // The rect is bigger than the visible area.
     scroll_x = align_x.rect_visible;
   } else if (intersect_width > 0) {
-    // If the rectangle is partially visible, but not above the minimum
-    // threshold, use the specified partial behavior
+    // If the rectangle is partially visible, use the specified partial
+    // behavior.
     scroll_x = align_x.rect_partial;
   } else {
     scroll_x = align_x.rect_hidden;
@@ -635,7 +633,8 @@
     // The rect is bigger than the visible area.
     scroll_y = align_y.rect_visible;
   } else if (intersect_height > 0) {
-    // If the rectangle is partially visible, use the specified partial behavior
+    // If the rectangle is partially visible, use the specified partial
+    // behavior.
     scroll_y = align_y.rect_partial;
   } else {
     scroll_y = align_y.rect_hidden;
diff --git a/third_party/blink/renderer/core/url_pattern/url_pattern_canon.cc b/third_party/blink/renderer/core/url_pattern/url_pattern_canon.cc
index 610c787..d95e5962 100644
--- a/third_party/blink/renderer/core/url_pattern/url_pattern_canon.cc
+++ b/third_party/blink/renderer/core/url_pattern/url_pattern_canon.cc
@@ -59,12 +59,11 @@
   url::Component component;
   if (stripped.Is8Bit()) {
     StringUTF8Adaptor utf8(stripped);
-    result = url::CanonicalizeScheme(
-        utf8.data(), url::Component(0, utf8.size()), &canon_output, &component);
+    result =
+        url::CanonicalizeScheme(utf8.AsStringView(), &canon_output, &component);
   } else {
-    result = url::CanonicalizeScheme(stripped.Characters16(),
-                                     url::Component(0, stripped.length()),
-                                     &canon_output, &component);
+    result =
+        url::CanonicalizeScheme(stripped.View16(), &canon_output, &component);
   }
 
   if (!result) {
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
index 9f0165c9..161f454 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -191,29 +191,29 @@
   if (element->parentElement() != canvas_element) {
     exception_state.ThrowTypeError(
         "Only immediate children of the <canvas> element can be passed to "
-        "placeElement().");
-    return false;
-  }
-
-  if (!element->GetLayoutObject()) {
-    exception_state.ThrowTypeError(
-        "An element used with drawElement() must have been laid out. "
-        "Add layoutsubtree=`true` to the canvas element and be sure the "
-        "element is not `display: none`.");
-    return false;
-  }
-
-  // TODO(crbug.com/413728246): Maybe we can support canvas element.
-  if (IsA<HTMLCanvasElement>(element)) {
-    exception_state.ThrowTypeError(
-        "<canvas> children of a <canvas> cannot be passed to placeElement().");
+        "drawElement().");
     return false;
   }
 
   if (!canvas_element->layoutSubtree()) {
     exception_state.ThrowTypeError(
         "<canvas> elements without layoutsubtree do not support "
-        "placeElement().");
+        "drawElement().");
+    return false;
+  }
+
+  if (!element->GetLayoutObject()) {
+    exception_state.ThrowTypeError(
+        "The canvas and element used with drawElement() must have been laid "
+        "out. Detached canvases are not supported, nor canvas or children that "
+        "are `display: none`.");
+    return false;
+  }
+
+  // TODO(crbug.com/413728246): Maybe we can support canvas element.
+  if (IsA<HTMLCanvasElement>(element)) {
+    exception_state.ThrowTypeError(
+        "<canvas> children of a <canvas> cannot be passed to drawElement().");
     return false;
   }
 
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_database.cc b/third_party/blink/renderer/modules/indexeddb/idb_database.cc
index 629e9a930..21c5f01 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_database.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_database.cc
@@ -40,6 +40,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_union_string_stringsequence.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/dom/quota_exceeded_error.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
 #include "third_party/blink/renderer/modules/indexed_db_names.h"
@@ -55,6 +56,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -211,9 +213,15 @@
                         mojom::blink::IDBException code,
                         const WTF::String& message) {
   DCHECK(transactions_.Contains(transaction_id));
-  transactions_.at(transaction_id)
-      ->OnAbort(MakeGarbageCollected<DOMException>(
-          static_cast<DOMExceptionCode>(code), message));
+  DOMException* dom_exception;
+  if (code == mojom::blink::IDBException::kQuotaError &&
+      RuntimeEnabledFeatures::QuotaExceededErrorUpdateEnabled()) {
+    dom_exception = MakeGarbageCollected<QuotaExceededError>(message);
+  } else {
+    dom_exception = MakeGarbageCollected<DOMException>(
+        static_cast<DOMExceptionCode>(code), message);
+  }
+  transactions_.at(transaction_id)->OnAbort(dom_exception);
 }
 
 void IDBDatabase::Complete(int64_t transaction_id) {
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_factory_client.cc b/third_party/blink/renderer/modules/indexeddb/idb_factory_client.cc
index cdab81a..be3d484 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_factory_client.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_factory_client.cc
@@ -35,11 +35,13 @@
 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
 #include "third_party/blink/public/platform/web_blob_info.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/dom/quota_exceeded_error.h"
 #include "third_party/blink/renderer/modules/indexed_db_names.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_metadata.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_open_db_request.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
 namespace blink {
@@ -86,8 +88,15 @@
 
   IDBOpenDBRequest* request = request_.Get();
   Detach();
-  request->OnDBFactoryError(MakeGarbageCollected<DOMException>(
-      static_cast<DOMExceptionCode>(code), message));
+  DOMException* dom_exception;
+  if (code == mojom::blink::IDBException::kQuotaError &&
+      RuntimeEnabledFeatures::QuotaExceededErrorUpdateEnabled()) {
+    dom_exception = MakeGarbageCollected<QuotaExceededError>(message);
+  } else {
+    dom_exception = MakeGarbageCollected<DOMException>(
+        static_cast<DOMExceptionCode>(code), message);
+  }
+  request->OnDBFactoryError(dom_exception);
 }
 
 void IDBFactoryClient::OpenSuccess(
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_request.cc b/third_party/blink/renderer/modules/indexeddb/idb_request.cc
index b59870f..38231a4b 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_request.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_request.cc
@@ -43,6 +43,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_union_idbcursor_idbindex_idbobjectstore.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_union_idbindex_idbobjectstore.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/dom/quota_exceeded_error.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/modules/indexed_db_names.h"
@@ -56,6 +57,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
@@ -662,12 +664,19 @@
   }
   probe::AsyncTask async_task(GetExecutionContext(), &async_task_context_,
                               "error");
-  auto* exception = MakeGarbageCollected<DOMException>(
-      static_cast<DOMExceptionCode>(code),
-      error ? error->error_message : "Invalid response");
+
+  DOMException* dom_exception;
+  auto message = error ? error->error_message : "Invalid response";
+  if (code == mojom::blink::IDBException::kQuotaError &&
+      RuntimeEnabledFeatures::QuotaExceededErrorUpdateEnabled()) {
+    dom_exception = MakeGarbageCollected<QuotaExceededError>(message);
+  } else {
+    dom_exception = MakeGarbageCollected<DOMException>(
+        static_cast<DOMExceptionCode>(code), message);
+  }
 
   transaction_->EnqueueResult(std::make_unique<IDBRequestQueueItem>(
-      this, exception,
+      this, dom_exception,
       WTF::BindOnce(&IDBTransaction::OnResultReady,
                     WrapPersistent(transaction_.Get()))));
 }
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.cc b/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.cc
index 38e57c84..7ebe03c 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.cc
@@ -12,11 +12,13 @@
 #include "base/memory/scoped_refptr.h"
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/dom/quota_exceeded_error.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_request.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_request_loader.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
 #include "third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 namespace blink {
@@ -88,9 +90,18 @@
 
   void OnError(mojom::blink::IDBErrorPtr error) override {
     DCHECK(active_);
+    DOMException* dom_exception;
+    if (error->error_code == mojom::blink::IDBException::kQuotaError &&
+        RuntimeEnabledFeatures::QuotaExceededErrorUpdateEnabled()) {
+      dom_exception =
+          MakeGarbageCollected<QuotaExceededError>(error->error_message);
+    } else {
+      dom_exception = MakeGarbageCollected<DOMException>(
+          static_cast<DOMExceptionCode>(error->error_code),
+          error->error_message);
+    }
     owner_->response_type_ = IDBRequestQueueItem::kError;
-    owner_->error_ = MakeGarbageCollected<DOMException>(
-        static_cast<DOMExceptionCode>(error->error_code), error->error_message);
+    owner_->error_ = dom_exception;
     active_ = false;
     owner_->OnResultReady();
   }
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition.cc b/third_party/blink/renderer/modules/speech/speech_recognition.cc
index 7751523..f65fad9 100644
--- a/third_party/blink/renderer/modules/speech/speech_recognition.cc
+++ b/third_party/blink/renderer/modules/speech/speech_recognition.cc
@@ -499,9 +499,8 @@
       ExecutionContextLifecycleObserver(window),
       PageVisibilityObserver(window->GetFrame() ? window->GetFrame()->GetPage()
                                                 : nullptr),
-      grammars_(SpeechGrammarList::Create()),  // FIXME: The spec is not clear
-                                               // on the default value for the
-                                               // grammars attribute.
+      grammars_(SpeechGrammarList::Create()),
+      phrases_(SpeechRecognitionPhraseList::Create({})),
       controller_(SpeechRecognitionController::From(*window)),
       receiver_(this, window),
       session_(window) {}
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 04c10fcd..3126c81 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -755,7 +755,7 @@
     "fonts/shaping/glyph_data_range.cc",
     "fonts/shaping/glyph_data_range.h",
     "fonts/shaping/glyph_index_result.h",
-    "fonts/shaping/glyph_offset_array.h",
+    "fonts/shaping/glyph_offset_iterator.h",
     "fonts/shaping/han_kerning.cc",
     "fonts/shaping/han_kerning.h",
     "fonts/shaping/harfbuzz_face.cc",
diff --git a/third_party/blink/renderer/platform/bindings/exception_code.h b/third_party/blink/renderer/platform/bindings/exception_code.h
index b41391a..c277546 100644
--- a/third_party/blink/renderer/platform/bindings/exception_code.h
+++ b/third_party/blink/renderer/platform/bindings/exception_code.h
@@ -68,7 +68,6 @@
   kNetworkError = 19,
   kAbortError = 20,
   kURLMismatchError = 21,
-  kQuotaExceededError = 22,
   kTimeoutError = 23,
   kInvalidNodeTypeError = 24,
   kDataCloneError = 25,
@@ -90,6 +89,7 @@
   kOperationError,
   kNotAllowedError,
   kOptOutError,
+  kQuotaExceededError,
 
   // The rest of entries are defined out of scope of Web IDL.
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/glyph_offset_array.h b/third_party/blink/renderer/platform/fonts/shaping/glyph_offset_array.h
deleted file mode 100644
index 43936e1..0000000
--- a/third_party/blink/renderer/platform/fonts/shaping/glyph_offset_array.h
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_GLYPH_OFFSET_ARRAY_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_GLYPH_OFFSET_ARRAY_H_
-
-#include "third_party/blink/renderer/platform/fonts/shaping/glyph_data.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/glyph_data_range.h"
-#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
-
-namespace blink {
-
-// A array of glyph offsets. If all offsets are zero, we don't allocate
-// storage for reducing memory usage.
-class PLATFORM_EXPORT GlyphOffsetArray final {
-  DISALLOW_NEW();
-
- public:
-  GlyphOffsetArray() = default;
-  GlyphOffsetArray(const GlyphOffsetArray& other) : storage_(other.storage_) {}
-
-  // The `span` of `GlyphOffset` if `HasStorage()`, or an empty span.
-  explicit operator base::span<const GlyphOffset>() const {
-    return base::span{storage_};
-  }
-
-  // A return value of |GetOffsets()| to represent optional |GlyphOffset|
-  // array.
-  template <bool has_non_zero_glyph_offsets>
-  struct iterator final {};
-
-  template <bool has_non_zero_glyph_offsets>
-  iterator<has_non_zero_glyph_offsets> GetIterator() const {
-    return iterator<has_non_zero_glyph_offsets>(*this);
-  }
-
-  size_t ByteSize() const {
-    return HasStorage() ? AllocatedSize() * sizeof(GlyphOffset) : 0;
-  }
-
-  void CopyFrom(const GlyphOffsetArray& other1,
-                wtf_size_t size1,
-                const GlyphOffsetArray& other2,
-                wtf_size_t size2) {
-    other1.CheckSize(size1);
-    other2.CheckSize(size2);
-    DCHECK(size1);
-    DCHECK(size2);
-    const wtf_size_t size = size1 + size2;
-    if (other1.HasStorage()) {
-      AllocateStorageIfNeeded(size);
-      std::ranges::copy(other1.storage_, GetStorage());
-    }
-    if (other2.HasStorage()) {
-      AllocateStorageIfNeeded(size);
-      std::ranges::copy(other2.storage_, UNSAFE_TODO(GetStorage() + size1));
-    }
-  }
-
-  void CopyFromRange(const GlyphDataRange& range) {
-    if (!range.HasOffsets() || range.IsEmpty()) {
-      storage_.clear();
-      return;
-    }
-    AllocateStorage(range.size());
-    std::ranges::copy(range.Offsets(), GetStorage());
-  }
-
-  GlyphOffset* GetStorage() { return storage_.data(); }
-  const GlyphOffset* GetStorage() const { return storage_.data(); }
-  bool HasStorage() const { return !storage_.empty(); }
-  wtf_size_t AllocatedSize() const { return storage_.size(); }
-
-  void Reverse() { storage_.Reverse(); }
-
-  void Shrink(unsigned new_size) {
-    DCHECK_GE(new_size, 1u);
-    if (!HasStorage()) {
-      return;
-    }
-    storage_.Shrink(new_size);
-  }
-
-  // Functions to change one element.
-  void AddHeightAt(unsigned index, float delta, wtf_size_t size) {
-    DCHECK_NE(delta, 0.0f);
-    AllocateStorageIfNeeded(size);
-    storage_[index].set_y(storage_[index].y() + delta);
-  }
-
-  void AddWidthAt(unsigned index, float delta, wtf_size_t size) {
-    DCHECK_NE(delta, 0.0f);
-    AllocateStorageIfNeeded(size);
-    storage_[index].set_x(storage_[index].x() + delta);
-  }
-
-  void SetAt(unsigned index, GlyphOffset offset, wtf_size_t size) {
-    if (!HasStorage()) {
-      if (offset.IsZero()) {
-        return;
-      }
-      AllocateStorage(size);
-    }
-    storage_[index] = offset;
-  }
-
-  void Trace(Visitor* visitor) const { visitor->Trace(storage_); }
-
- private:
-  void CheckSize(wtf_size_t size) const {
-    CHECK(!HasStorage() || size == AllocatedSize());
-  }
-
-  // Note: HarfBuzzShaperTest.ShapeVerticalUpright uses non-zero glyph offset.
-  void AllocateStorage(wtf_size_t size) {
-    DCHECK_GE(size, 1u);
-    DCHECK(!HasStorage());
-    storage_.resize(size);
-  }
-
-  void AllocateStorageIfNeeded(wtf_size_t size) {
-    CheckSize(size);
-    if (!HasStorage()) {
-      AllocateStorage(size);
-    }
-  }
-
-  HeapVector<GlyphOffset> storage_;
-};
-
-// For non-zero glyph offset array
-template <>
-struct GlyphOffsetArray::iterator<true> final {
-  STACK_ALLOCATED();
-
- public:
-  explicit iterator(base::span<const GlyphOffset> offsets)
-      : iterator_(offsets.begin()) {
-    // An empty span should use `has_non_zero_glyph_offsets = false`.
-    DCHECK(!offsets.empty());
-  }
-
-  // The constructor for ShapeResult
-  explicit iterator(const GlyphOffsetArray& array)
-      : iterator(static_cast<base::span<const GlyphOffset>>(array)) {}
-
-  // The constructor for ShapeResultView
-  explicit iterator(const GlyphDataRange& range) : iterator(range.Offsets()) {}
-
-  GlyphOffset operator*() const { return *iterator_; }
-  void operator++() { ++iterator_; }
-  void operator+=(ptrdiff_t s) { iterator_ += s; }
-
-  GlyphOffset operator[](size_t i) const { return *(iterator_ + i); }
-
- private:
-  base::span<const GlyphOffset>::iterator iterator_;
-};
-
-// For zero glyph offset array
-template <>
-struct GlyphOffsetArray::iterator<false> final {
-  explicit iterator(const GlyphOffsetArray& array) {
-    DCHECK(!array.HasStorage());
-  }
-  explicit iterator(const GlyphDataRange& range) {
-    DCHECK(!range.HasOffsets());
-  }
-
-  GlyphOffset operator*() const { return GlyphOffset(); }
-  void operator++() {}
-  void operator+=(ptrdiff_t) {}
-  GlyphOffset operator[](size_t) const { return GlyphOffset(); }
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_GLYPH_OFFSET_ARRAY_H_
diff --git a/third_party/blink/renderer/platform/fonts/shaping/glyph_offset_iterator.h b/third_party/blink/renderer/platform/fonts/shaping/glyph_offset_iterator.h
new file mode 100644
index 0000000..a515608
--- /dev/null
+++ b/third_party/blink/renderer/platform/fonts/shaping/glyph_offset_iterator.h
@@ -0,0 +1,67 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_GLYPH_OFFSET_ITERATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_GLYPH_OFFSET_ITERATOR_H_
+
+#include "third_party/blink/renderer/platform/fonts/shaping/glyph_data.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/glyph_data_range.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
+
+namespace blink {
+
+// An iterator for `ShapeResultRun::offsets_`.
+//
+// Since it could be empty if there are no glyph offsets in the run, this
+// iterator makes iterating offsets to be no-operations in such case.
+template <bool has_non_zero_glyph_offsets>
+struct PLATFORM_EXPORT GlyphOffsetIterator final {};
+
+// For non-zero glyph offset array
+template <>
+struct GlyphOffsetIterator<true> final {
+  STACK_ALLOCATED();
+
+ public:
+  explicit GlyphOffsetIterator(base::span<const GlyphOffset> offsets)
+      : iterator_(offsets.begin()) {
+    // An empty span should use `has_non_zero_glyph_offsets = false`.
+    DCHECK(!offsets.empty());
+  }
+
+  // The constructor for ShapeResultView
+  explicit GlyphOffsetIterator(const GlyphDataRange& range)
+      : GlyphOffsetIterator(range.Offsets()) {}
+
+  GlyphOffset operator*() const { return *iterator_; }
+  void operator++() { ++iterator_; }
+  void operator+=(ptrdiff_t s) { iterator_ += s; }
+
+  GlyphOffset operator[](size_t i) const { return *(iterator_ + i); }
+
+ private:
+  base::span<const GlyphOffset>::iterator iterator_;
+};
+
+// For zero glyph offset array
+template <>
+struct GlyphOffsetIterator<false> final {
+  explicit GlyphOffsetIterator(base::span<const GlyphOffset> offsets) {
+    // An empty span should use `has_non_zero_glyph_offsets = false`.
+    DCHECK(offsets.empty());
+  }
+
+  explicit GlyphOffsetIterator(const GlyphDataRange& range) {
+    DCHECK(!range.HasOffsets());
+  }
+
+  GlyphOffset operator*() const { return GlyphOffset(); }
+  void operator++() {}
+  void operator+=(ptrdiff_t) {}
+  GlyphOffset operator[](size_t) const { return GlyphOffset(); }
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_GLYPH_OFFSET_ITERATOR_H_
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h
index 5aa0fc3..1171ef7e 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h
@@ -42,7 +42,7 @@
 #include "third_party/blink/renderer/platform/fonts/shaping/glyph_data.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/glyph_data_range.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/glyph_index_result.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/glyph_offset_array.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/glyph_offset_iterator.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -274,11 +274,11 @@
     HarfBuzzRunGlyphData& back() { return data_.back(); }
     const HarfBuzzRunGlyphData& back() const { return data_.back(); }
 
-    bool HasNonZeroOffsets() const { return offsets_.HasStorage(); }
+    bool HasNonZeroOffsets() const { return !offsets_.empty(); }
 
     size_t ByteSize() const {
       return sizeof(*this) + size() * sizeof(HarfBuzzRunGlyphData) +
-             offsets_.ByteSize();
+             sizeof(GlyphOffset) * offsets_.size();
     }
 
     // The `span` of `GlyphOffset` if `HasNonZeroOffsets()`, or an empty span.
@@ -287,8 +287,8 @@
     }
 
     template <bool has_non_zero_glyph_offsets>
-    GlyphOffsetArray::iterator<has_non_zero_glyph_offsets> GetOffsets() const {
-      return offsets_.GetIterator<has_non_zero_glyph_offsets>();
+    GlyphOffsetIterator<has_non_zero_glyph_offsets> GetOffsets() const {
+      return GlyphOffsetIterator<has_non_zero_glyph_offsets>(offsets_);
     }
 
     // Note: Caller should be adjust |HarfBuzzRunGlyphData.character_index|.
@@ -301,8 +301,16 @@
       std::ranges::copy(other1.data_, data_.data());
       std::ranges::copy(other2.data_,
                         UNSAFE_TODO(data_.data() + other1.size()));
-      offsets_.CopyFrom(other1.offsets_, other1.size(), other2.offsets_,
-                        other2.size());
+
+      if (other1.HasNonZeroOffsets()) {
+        AllocateOffsetsIfNeeded();
+        std::ranges::copy(other1.offsets_, offsets_.begin());
+      }
+      if (other2.HasNonZeroOffsets()) {
+        AllocateOffsetsIfNeeded();
+        std::ranges::copy(other2.offsets_,
+                          UNSAFE_TODO(offsets_.begin() + other1.size()));
+      }
     }
 
     // Note: Caller should be adjust |HarfBuzzRunGlyphData.character_index|.
@@ -310,19 +318,35 @@
       CHECK_EQ(range.size(), size());
       static_assert(std::is_trivially_copyable_v<HarfBuzzRunGlyphData>);
       std::ranges::copy(range, data_.data());
-      offsets_.CopyFromRange(range);
+
+      if (!range.HasOffsets() || range.IsEmpty()) {
+        offsets_.clear();
+      } else {
+        AllocateOffsets();
+        std::ranges::copy(range.Offsets(), offsets_.begin());
+      }
     }
 
     void AddOffsetHeightAt(unsigned index, float delta) {
-      offsets_.AddHeightAt(index, delta, size());
+      DCHECK_NE(delta, 0.0f);
+      AllocateOffsetsIfNeeded();
+      offsets_[index].set_y(offsets_[index].y() + delta);
     }
 
     void AddOffsetWidthAt(unsigned index, float delta) {
-      offsets_.AddWidthAt(index, delta, size());
+      DCHECK_NE(delta, 0.0f);
+      AllocateOffsetsIfNeeded();
+      offsets_[index].set_x(offsets_[index].x() + delta);
     }
 
     void SetOffsetAt(unsigned index, GlyphOffset offset) {
-      offsets_.SetAt(index, offset, size());
+      if (!HasNonZeroOffsets()) {
+        if (offset.IsZero()) {
+          return;
+        }
+        AllocateOffsets();
+      }
+      offsets_[index] = offset;
     }
 
     // Vector<HarfBuzzRunGlyphData> like functions
@@ -357,7 +381,9 @@
       }
       DCHECK_LT(new_size, size());
       data_.Shrink(new_size);
-      offsets_.Shrink(new_size);
+      if (HasNonZeroOffsets()) {
+        offsets_.Shrink(new_size);
+      }
     }
 
     void Trace(Visitor* visitor) const {
@@ -366,12 +392,24 @@
     }
 
    private:
+    void AllocateOffsets() {
+      DCHECK_GE(size(), 1u);
+      DCHECK(!HasNonZeroOffsets());
+      offsets_.resize(size());
+    }
+
+    void AllocateOffsetsIfNeeded() {
+      if (!HasNonZeroOffsets()) {
+        AllocateOffsets();
+      }
+    }
+
     // Note: |offsets_| holds number of elements instead o here to reduce
     // memory usage.
     HeapVector<HarfBuzzRunGlyphData> data_;
     // |offsets_| holds collection of offset for |data_[i]|.
     // When all offsets are zero, we don't allocate for reducing memory usage.
-    GlyphOffsetArray offsets_;
+    HeapVector<GlyphOffset> offsets_;
   };
 
   void CheckConsistency() const {
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_run_test.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_run_test.cc
index f2a4b07..c22dfe7 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_run_test.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_run_test.cc
@@ -4,101 +4,152 @@
 
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_run.h"
 
+#include <hb.h>
+
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
 
-class ShapeResultRunTest : public testing::Test {};
+namespace {
 
-TEST_F(ShapeResultRunTest, CopyConstructor) {
-  GlyphOffsetArray offsets;
-
-  GlyphOffsetArray offsets2(offsets);
-  EXPECT_FALSE(offsets2.HasStorage());
-
-  offsets.SetAt(0, GlyphOffset(1, 1), 2);
-  GlyphOffsetArray offsets3(offsets);
-  ASSERT_TRUE(offsets3.HasStorage());
-  EXPECT_EQ(GlyphOffset(1, 1), offsets3.GetStorage()[0]);
+ShapeResultRun* CreateTestShapeResultRun(unsigned num_glyphs,
+                                         unsigned num_characters) {
+  return MakeGarbageCollected<ShapeResultRun>(
+      /*font*/ nullptr, hb_direction_t::HB_DIRECTION_LTR,
+      CanvasRotationInVertical::kRegular, hb_script_t::HB_SCRIPT_LATIN,
+      /*start_index*/ 0, num_glyphs, num_characters);
 }
 
-TEST_F(ShapeResultRunTest, CopyFromRange) {
-  ShapeResultRun* run = MakeGarbageCollected<ShapeResultRun>(
-      nullptr, HB_DIRECTION_LTR, CanvasRotationInVertical::kRegular,
-      HB_SCRIPT_COMMON, 0, 2, 2);
+}  // namespace
 
-  GlyphOffsetArray offsets2;
-  offsets2.CopyFromRange(GlyphDataRange{*run});
-  EXPECT_FALSE(offsets2.HasStorage());
+class ShapeResultRunTest : public testing::Test {};
+
+TEST_F(ShapeResultRunTest, GlyphDataCopyConstructor) {
+  ShapeResultRun* run = CreateTestShapeResultRun(2, 2);
+
+  ShapeResultRun* run2 = MakeGarbageCollected<ShapeResultRun>(*run);
+  EXPECT_FALSE(run2->glyph_data_.HasNonZeroOffsets());
+
+  run->glyph_data_.SetOffsetAt(0, GlyphOffset(1, 1));
+  ShapeResultRun* run3 = MakeGarbageCollected<ShapeResultRun>(*run);
+  ASSERT_TRUE(run3->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(GlyphOffset(1, 1), run3->glyph_data_.Offsets()[0]);
+}
+
+TEST_F(ShapeResultRunTest, GlyphDataCopyFromRange) {
+  ShapeResultRun* run = CreateTestShapeResultRun(2, 2);
+
+  ShapeResultRun* run2 = CreateTestShapeResultRun(2, 2);
+  run2->glyph_data_.CopyFromRange(GlyphDataRange{*run});
+  EXPECT_FALSE(run2->glyph_data_.HasNonZeroOffsets());
 
   run->glyph_data_.SetOffsetAt(0, GlyphOffset(1, 1));
   ASSERT_TRUE(run->glyph_data_.HasNonZeroOffsets());
 
-  GlyphOffsetArray offsets3;
-  offsets3.CopyFromRange(GlyphDataRange{*run});
-  ASSERT_TRUE(offsets3.HasStorage());
-  EXPECT_EQ(GlyphOffset(1, 1), offsets3.GetStorage()[0]);
+  ShapeResultRun* run3 = CreateTestShapeResultRun(2, 2);
+  run3->glyph_data_.CopyFromRange(GlyphDataRange{*run});
+  ASSERT_TRUE(run3->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(GlyphOffset(1, 1), run3->glyph_data_.Offsets()[0]);
 }
 
-TEST_F(ShapeResultRunTest, GlyphOffsetArrayReverse) {
-  GlyphOffsetArray offsets;
+TEST_F(ShapeResultRunTest, GlyphDataReverse) {
+  ShapeResultRun* run = CreateTestShapeResultRun(2, 2);
 
-  offsets.Reverse();
-  EXPECT_FALSE(offsets.HasStorage());
+  run->glyph_data_.Reverse();
+  EXPECT_FALSE(run->glyph_data_.HasNonZeroOffsets());
 
-  offsets.SetAt(0, GlyphOffset(1, 1), 2);
-  ASSERT_TRUE(offsets.HasStorage());
-  offsets.Reverse();
-  EXPECT_EQ(GlyphOffset(), offsets.GetStorage()[0]);
-  EXPECT_EQ(GlyphOffset(1, 1), UNSAFE_TODO(offsets.GetStorage()[1]));
+  run->glyph_data_.SetOffsetAt(0, GlyphOffset(1, 1));
+  ASSERT_TRUE(run->glyph_data_.HasNonZeroOffsets());
+  run->glyph_data_.Reverse();
+  EXPECT_EQ(GlyphOffset(), run->glyph_data_.Offsets()[0]);
+  EXPECT_EQ(GlyphOffset(1, 1), run->glyph_data_.Offsets()[1]);
 }
 
-TEST_F(ShapeResultRunTest, GlyphOffsetArraySetAddOffsetHeightAt) {
-  GlyphOffsetArray offsets;
+TEST_F(ShapeResultRunTest, GlyphDataAddOffsetHeightAt) {
+  ShapeResultRun* run = CreateTestShapeResultRun(2, 2);
 
-  offsets.AddHeightAt(1, 1.5f, 2);
-  ASSERT_TRUE(offsets.HasStorage());
-  EXPECT_EQ(GlyphOffset(0, 1.5f), UNSAFE_TODO(offsets.GetStorage()[1]));
+  run->glyph_data_.AddOffsetHeightAt(1, 1.5f);
+  ASSERT_TRUE(run->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(GlyphOffset(0, 1.5f), run->glyph_data_.Offsets()[1]);
 
-  offsets.AddHeightAt(1, 2.0f, 2);
-  ASSERT_TRUE(offsets.HasStorage());
-  EXPECT_EQ(GlyphOffset(0, 3.5f), UNSAFE_TODO(offsets.GetStorage()[1]));
+  run->glyph_data_.AddOffsetHeightAt(1, 2.0f);
+  ASSERT_TRUE(run->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(GlyphOffset(0, 3.5f), run->glyph_data_.Offsets()[1]);
 }
 
-TEST_F(ShapeResultRunTest, GlyphOffsetArraySetAddOffsetWidthAt) {
-  GlyphOffsetArray offsets;
+TEST_F(ShapeResultRunTest, GlyphDataAddOffsetWidthAt) {
+  ShapeResultRun* run = CreateTestShapeResultRun(2, 2);
 
-  offsets.AddWidthAt(1, 1.5f, 2);
-  ASSERT_TRUE(offsets.HasStorage());
-  EXPECT_EQ(GlyphOffset(1.5f, 0), UNSAFE_TODO(offsets.GetStorage()[1]));
+  run->glyph_data_.AddOffsetWidthAt(1, 1.5f);
+  ASSERT_TRUE(run->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(GlyphOffset(1.5f, 0), run->glyph_data_.Offsets()[1]);
 
-  offsets.AddWidthAt(1, 2.0f, 2);
-  ASSERT_TRUE(offsets.HasStorage());
-  EXPECT_EQ(GlyphOffset(3.5f, 0), UNSAFE_TODO(offsets.GetStorage()[1]));
+  run->glyph_data_.AddOffsetWidthAt(1, 2.0f);
+  ASSERT_TRUE(run->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(GlyphOffset(3.5f, 0), run->glyph_data_.Offsets()[1]);
 }
 
-TEST_F(ShapeResultRunTest, GlyphOffsetArraySetAt) {
-  GlyphOffsetArray offsets;
+TEST_F(ShapeResultRunTest, GlyphDataSetAt) {
+  ShapeResultRun* run = CreateTestShapeResultRun(2, 2);
 
-  offsets.SetAt(0, GlyphOffset(), 2);
-  EXPECT_FALSE(offsets.HasStorage());
+  run->glyph_data_.SetOffsetAt(0, GlyphOffset());
+  // Setting a zero offset should not allocate storage if it wasn't already
+  // allocated.
+  EXPECT_FALSE(run->glyph_data_.HasNonZeroOffsets());
 
-  offsets.SetAt(1, GlyphOffset(1, 1), 2);
-  EXPECT_TRUE(offsets.HasStorage());
+  run->glyph_data_.SetOffsetAt(1, GlyphOffset(1, 1));
+  ASSERT_TRUE(run->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(GlyphOffset(1, 1), run->glyph_data_.Offsets()[1]);
 }
 
-TEST_F(ShapeResultRunTest, GlyphOffsetArrayShrink) {
-  GlyphOffsetArray offsets;
+TEST_F(ShapeResultRunTest, GlyphDataShrink) {
+  // Case 1: Shrink when no offsets are allocated.
+  ShapeResultRun* run_no_offsets = CreateTestShapeResultRun(3, 3);
+  EXPECT_FALSE(run_no_offsets->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(3u, run_no_offsets->glyph_data_.size());
 
-  offsets.Shrink(2);
-  EXPECT_FALSE(offsets.HasStorage());
+  run_no_offsets->glyph_data_.Shrink(2);  // Shrink from 3 to 2
+  // Offsets should remain unallocated.
+  EXPECT_FALSE(run_no_offsets->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(2u, run_no_offsets->glyph_data_.size());  // Data should shrink.
 
-  offsets.SetAt(0, GlyphOffset(1, 1), 2);
-  ASSERT_TRUE(offsets.HasStorage());
+  run_no_offsets->glyph_data_.Shrink(1);  // Shrink from 2 to 1
+  EXPECT_FALSE(run_no_offsets->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(1u, run_no_offsets->glyph_data_.size());
 
-  offsets.Shrink(1);
-  ASSERT_TRUE(offsets.HasStorage());
-  EXPECT_EQ(GlyphOffset(1, 1), offsets.GetStorage()[0]);
+  // Case 2: Shrink when offsets are allocated.
+  ShapeResultRun* run_with_offsets = CreateTestShapeResultRun(3, 3);
+  run_with_offsets->glyph_data_.SetOffsetAt(0, GlyphOffset(1, 0));
+  run_with_offsets->glyph_data_.SetOffsetAt(1, GlyphOffset(2, 0));
+  run_with_offsets->glyph_data_.SetOffsetAt(2, GlyphOffset(3, 0));
+  ASSERT_TRUE(run_with_offsets->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(3u, run_with_offsets->glyph_data_.size());
+  ASSERT_EQ(3u, run_with_offsets->glyph_data_.Offsets().size());
+
+  // Shrink to a smaller size.
+  run_with_offsets->glyph_data_.Shrink(2);
+  ASSERT_TRUE(run_with_offsets->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(2u, run_with_offsets->glyph_data_.size());
+  ASSERT_EQ(2u, run_with_offsets->glyph_data_.Offsets().size());
+  EXPECT_EQ(GlyphOffset(1, 0), run_with_offsets->glyph_data_.Offsets()[0]);
+  EXPECT_EQ(GlyphOffset(2, 0), run_with_offsets->glyph_data_.Offsets()[1]);
+
+  // Shrink further.
+  run_with_offsets->glyph_data_.Shrink(1);
+  ASSERT_TRUE(run_with_offsets->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(1u, run_with_offsets->glyph_data_.size());
+  ASSERT_EQ(1u, run_with_offsets->glyph_data_.Offsets().size());
+  EXPECT_EQ(GlyphOffset(1, 0), run_with_offsets->glyph_data_.Offsets()[0]);
+
+  // Case 3: Shrink to the same size (no-op for vector sizes).
+  ShapeResultRun* run_shrink_same_size = CreateTestShapeResultRun(2, 2);
+  run_shrink_same_size->glyph_data_.SetOffsetAt(0, GlyphOffset(5, 0));
+  ASSERT_TRUE(run_shrink_same_size->glyph_data_.HasNonZeroOffsets());
+  run_shrink_same_size->glyph_data_.Shrink(2);  // Shrink to current size.
+  ASSERT_TRUE(run_shrink_same_size->glyph_data_.HasNonZeroOffsets());
+  EXPECT_EQ(2u, run_shrink_same_size->glyph_data_.size());
+  ASSERT_EQ(2u, run_shrink_same_size->glyph_data_.Offsets().size());
+  EXPECT_EQ(GlyphOffset(5, 0), run_shrink_same_size->glyph_data_.Offsets()[0]);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
index f87afcd..c62a856f 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
@@ -8,7 +8,7 @@
 #include "base/containers/span.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/glyph_data.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/glyph_data_range.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/glyph_offset_array.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/glyph_offset_iterator.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
@@ -186,9 +186,8 @@
       return *(UNSAFE_TODO(range_.begin() + index));
     }
     template <bool has_non_zero_glyph_offsets>
-    GlyphOffsetArray::iterator<has_non_zero_glyph_offsets> GetGlyphOffsets()
-        const {
-      return GlyphOffsetArray::iterator<has_non_zero_glyph_offsets>(range_);
+    GlyphOffsetIterator<has_non_zero_glyph_offsets> GetGlyphOffsets() const {
+      return GlyphOffsetIterator<has_non_zero_glyph_offsets>(range_);
     }
     bool HasGlyphOffsets() const { return range_.HasOffsets(); }
     // The end character index of |this| without considering offsets in
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 3a01973..db2d458 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -2722,7 +2722,7 @@
     },
     {
       name: "LanguageDetectionAPI",
-      status: "experimental",
+      status: "stable",
       origin_trial_feature_name: "LanguageDetectionAPI",
       origin_trial_allows_third_party: true,
       base_feature_status: "enabled",
@@ -3711,6 +3711,11 @@
       base_feature: "none",
     },
     {
+      // ChromeStatus: https://chromestatus.com/feature/6194847180128256
+      name: "QuotaExceededErrorUpdate",
+      status: "experimental",
+    },
+    {
      // crbug.com/323953913
      // Fix looking for next radio button in the form's scope. This was added
      // in M135 and can be removed after M138.
diff --git a/third_party/blink/renderer/platform/weborigin/kurl.cc b/third_party/blink/renderer/platform/weborigin/kurl.cc
index 3cfab81..f834f8c 100644
--- a/third_party/blink/renderer/platform/weborigin/kurl.cc
+++ b/third_party/blink/renderer/platform/weborigin/kurl.cc
@@ -483,11 +483,11 @@
   // the URL and set "m_isValid."
   url::RawCanonOutputT<char> canon_protocol;
   url::Component protocol_component;
-  if (!url::CanonicalizeScheme(new_protocol_utf8.data(),
-                               url::Component(0, new_protocol_utf8.size()),
+  if (!url::CanonicalizeScheme(new_protocol_utf8.AsStringView(),
                                &canon_protocol, &protocol_component) ||
-      protocol_component.is_empty())
+      protocol_component.is_empty()) {
     return false;
+  }
 
   DCHECK_EQ(protocol_component.begin, 0);
   const wtf_size_t protocol_length =
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index da019e44..debe802 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -5413,6 +5413,13 @@
         {}
        ]
       ],
+      "text-decoration-first-line-layer-crash.html": [
+       "5f5b7e7b9e4774d74224000271e2115ef9792540",
+       [
+        null,
+        {}
+       ]
+      ],
       "text-decoration-first-line-multi-crash.html": [
        "f6176334ad6e6ef2662a8f89785f601f48a762cf",
        [
@@ -9503,6 +9510,13 @@
        {}
       ]
      ],
+     "scroll-timeline-completion-crash.html": [
+      "fb7ecd1ed1bff87cb45bfdbcbb9ad7504a9fda9c",
+      [
+       null,
+       {}
+      ]
+     ],
      "viewport-100vh.html": [
       "cc862bd29955ec0c6730614a4eb72e3565c46cd4",
       [
@@ -20601,8 +20615,8 @@
       {}
      ]
     ],
-    "SpeechRecognition-recognitionContext-manual.https.html": [
-     "1039baa2825baed883e1c95c80247ee96a2ee33d",
+    "SpeechRecognition-phrases-manual.https.html": [
+     "2d0b19ab46ce3c41610b298750cbb0ca85832513",
      [
       null,
       {}
@@ -73956,7 +73970,7 @@
        ]
       ],
       "align-self-stretch-auto-margins-aspect-ratio.html": [
-       "4eaa9d2f3a6dbab63d3d931d4c58a427bc11976f",
+       "347005204e333eeb813bd531ec1aa12e734e37d4",
        [
         null,
         [
@@ -73969,7 +73983,7 @@
        ]
       ],
       "align-self-stretch-auto-margins.html": [
-       "9d1b6454c848c02b7fef360fb447d4d6b46ee8c0",
+       "9d6eb2306534d5d2a30c5724abf11e994470b92c",
        [
         null,
         [
@@ -74008,7 +74022,7 @@
        ]
       ],
       "justify-self-stretch-auto-margins-aspect-ratio.html": [
-       "c50b32f089b1b0043ac5d9dbd0f79906d82827f3",
+       "bc6120584c248659646cad0a3f6349a23f4b8744",
        [
         null,
         [
@@ -74021,7 +74035,7 @@
        ]
       ],
       "justify-self-stretch-auto-margins.html": [
-       "7d7b4bfc8570d3dde59fc903de7cb173b0b5baf8",
+       "675321fc2b12b16816e5355d420e51e3b0195aac",
        [
         null,
         [
@@ -74253,7 +74267,7 @@
         {}
        ]
       ],
-      "justify-items-anonymous.tentative.html": [
+      "justify-items-anonymous.html": [
        "641dea1f54b2f0cea29bc4c4c82e023a479e3d3c",
        [
         null,
@@ -74280,7 +74294,7 @@
        ]
       ],
       "justify-self-auto-margins-2.html": [
-       "33c98d6c1dfb43ff29f5c63472f041add65faff1",
+       "e81c4bba6f4fb98f79a3abfced011d896bd734d3",
        [
         null,
         [
@@ -74538,7 +74552,7 @@
       ]
      ],
      "anchor-center-visibility-change.html": [
-      "0f7d805844f010d9854301c094b5ce6fd03d13fa",
+      "e5559433206741222198471088ddd165cf6786bf",
       [
        null,
        [
@@ -75216,6 +75230,19 @@
        {}
       ]
      ],
+     "position-area-visibility-change.html": [
+      "61d8ab50284aed3f7e2c3abc13180af7967e1463",
+      [
+       null,
+       [
+        [
+         "/css/css-anchor-position/reference/position-area-visibility-change-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "position-try-fallbacks-001.html": [
       "b41e326800cf26a85b762ae34213e20aa47905b2",
       [
@@ -134265,6 +134292,32 @@
         {}
        ]
       ],
+      "flex-gap-decorations-020.html": [
+       "6c07493d14d576026e7693b4391fd8baeadbba14",
+       [
+        null,
+        [
+         [
+          "/css/css-gaps/flex/flex-gap-decorations-020-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "flex-gap-decorations-021.html": [
+       "c59db4f635b361c4f8f5d77c94129264f560d79b",
+       [
+        null,
+        [
+         [
+          "/css/css-gaps/flex/flex-gap-decorations-021-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "flex-gap-decorations-022.html": [
        "5f3b512ef76214b3645c329c92bd06ebf23efd9d",
        [
@@ -134696,6 +134749,58 @@
         {}
        ]
       ],
+      "grid-gap-decorations-034.html": [
+       "afe20ef5117b5bc7b628fee1ce86960a9b927adc",
+       [
+        null,
+        [
+         [
+          "/css/css-gaps/grid/grid-gap-decorations-034-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "grid-gap-decorations-035.html": [
+       "d2fa76094a96e8b7f786ca903288b1a057c999e3",
+       [
+        null,
+        [
+         [
+          "/css/css-gaps/grid/grid-gap-decorations-035-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "grid-gap-decorations-036.html": [
+       "8b1e1e2e1c2d37e9a3367e3d2224b15ded9ebf57",
+       [
+        null,
+        [
+         [
+          "/css/css-gaps/grid/grid-gap-decorations-036-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "grid-gap-decorations-037.html": [
+       "656bfee7dfcdd7f568a3ff9bf088c0ece08a57df",
+       [
+        null,
+        [
+         [
+          "/css/css-gaps/grid/grid-gap-decorations-037-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "grid-gap-decorations-38.html": [
        "8b87bcd4860ac50a1c2f3de98cec9599bebb77a3",
        [
@@ -168146,6 +168251,19 @@
        {}
       ]
      ],
+     "multicol-fill-balance-030.html": [
+      "9fc1f4e859afb74d151d3a4c2d56fd96aacfdc40",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square.xht",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "multicol-fill-balance-nested-000.html": [
       "5e466df8077545b4d6474389d296bc26c5b28b86",
       [
@@ -282578,6 +282696,19 @@
         {}
        ]
       ],
+      "negated-last-of-type-invalidation.html": [
+       "40bf8a8f0f4727ffa6b61633e8c2e35dbb812d82",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "negated-negated-first-of-type-when-ancestor-changes.html": [
        "7e5376fc31f15febe5db2202e915427ea2e4cc5d",
        [
@@ -320144,10 +320275,18 @@
       []
      ],
      "util.js": [
-      "3e95a936304f3190066f3774e9483394d31a501f",
+      "7eba1467f925a3871bcb9bf445accbf2678fd8f2",
       []
      ]
     },
+    "rewriter": {
+     "resources": {
+      "iframe-helper.html": [
+       "222c192f04f84f78f6785a7bc274445da5cf864c",
+       []
+      ]
+     }
+    },
     "summarizer": {
      "resources": {
       "iframe-helper.html": [
@@ -320171,6 +320310,14 @@
        []
       ]
      }
+    },
+    "writer": {
+     "resources": {
+      "iframe-helper.html": [
+       "e85e8a5fb408b7029596d86fcd65e2ffd3a57959",
+       []
+      ]
+     }
     }
    },
    "ambient-light": {
@@ -332726,7 +332873,7 @@
       []
      ],
      "anchor-center-visibility-change-ref.html": [
-      "66bf9083c3a24e6adad0ad724a1e54ccbe6f568b",
+      "bc9872a9093680d8584df0e923c658ce589ef271",
       []
      ],
      "anchor-center-vrl-htb-expected.txt": [
@@ -332956,6 +333103,10 @@
        "a4feab487c5c9262e6c71d2f16f4bb83384cdcbe",
        []
       ],
+      "position-area-visibility-change-ref.html": [
+       "87e1804940900132e8b8a062e096924585a5b227",
+       []
+      ],
       "sticky-anchor-position-invalid-ref.html": [
        "c4a5dd37354f61c66b0e2e53847b8fcc16112fc3",
        []
@@ -350201,6 +350352,14 @@
       "flex-gap-decorations-018-ref.html": [
        "644a409bd977acb91812666ac2f9a6e1c1b66830",
        []
+      ],
+      "flex-gap-decorations-020-ref.html": [
+       "b708a78a3472f1a903febe26cbec09da22db1f19",
+       []
+      ],
+      "flex-gap-decorations-021-ref.html": [
+       "1e28d73b4e2ce48d62880be1aa66e26f511ab7b1",
+       []
       ]
      },
      "grid": {
@@ -350319,6 +350478,22 @@
       "grid-gap-decorations-033-ref.html": [
        "e26143a6b93e9fdd53d4055234d89e40d98dc2af",
        []
+      ],
+      "grid-gap-decorations-034-ref.html": [
+       "4e964879e795ec6877b6564c04575d296aa4d94b",
+       []
+      ],
+      "grid-gap-decorations-035-ref.html": [
+       "851360a99a4bb9262e24368fed9a81d34f066a45",
+       []
+      ],
+      "grid-gap-decorations-036-ref.html": [
+       "29ed684d85f72c24fcf6e67187c834f5624eeda3",
+       []
+      ],
+      "grid-gap-decorations-037-ref.html": [
+       "4a2ee5bd5c6fbdb25e5a70eac56a9b0bbac5d56f",
+       []
       ]
      },
      "multicol": {
@@ -361629,7 +361804,7 @@
        []
       ],
       "scroll-initial-target-with-text-fragment-navigation-target.html": [
-       "aea8e120c15af61717f79b52ddd2f5c957393725",
+       "8b3c168af8a101a2421563babcf24c476201a534",
        []
       ],
       "stash.py": [
@@ -371362,7 +371537,7 @@
       []
      ],
      "WEB_FEATURES.yml": [
-      "a10f70297916abe13376013b18ae4b2f7cd4dec5",
+      "e699a40acddb78a7ef04314918aa839519eaa3f2",
       []
      ],
      "accent-color-checkbox-checked-001-notref.html": [
@@ -371575,7 +371750,7 @@
      ],
      "parsing": {
       "WEB_FEATURES.yml": [
-       "b4ae339c2f3301bc1845c39923c05095d9e48499",
+       "3be770b3a51dcebaca35d4a92e1f0b4a2e8004b9",
        []
       ],
       "canonical-order-outline-sub-properties-001-expected.txt": [
@@ -380804,7 +380979,7 @@
       []
      ],
      "iframe.html": [
-      "3ec761e08a6266ab24fcea357d866f76d8c9ed2f",
+      "d737dcfc091b7873863e46ba5bdb5e2bef07e2f4",
       []
      ]
     },
@@ -380813,7 +380988,7 @@
      []
     ],
     "user-activation.https-expected.txt": [
-     "5b258016a6775998fc2ae6163cd1915d9ea4a494",
+     "fed8949f2d27e344d58df8bf136e0d486d43511c",
      []
     ]
    },
@@ -397027,7 +397202,7 @@
        []
       ],
       "noopener-helper.js": [
-       "6dd2c9bc1c9ac2625be861246160e1a4dd7c4088",
+       "ead0ef3b34370bc4fc805ab72595beb3dea3deee",
        []
       ],
       "popup-test.js": [
@@ -397768,7 +397943,7 @@
       []
      ],
      "idlharness.https_include=(Document_Window)-expected.txt": [
-      "a59b20d054bd2e80a3751d8e005a9ad1a183b7f4",
+      "e975efd5af5f2240eb4efe84f575100c6a05a740",
       []
      ],
      "idlharness.https_include=HTML.+-expected.txt": [
@@ -403774,7 +403949,7 @@
         []
        ],
        "iframe-loading-lazy-reload-navigation-reload-expected.txt": [
-        "3ad8c48808bc4661334beb6a80564c43f6773ab4",
+        "8d930e94fc176d9f49af0d93f9e1250bf873990e",
         []
        ],
        "iframe-modify-scrolling-attr-to-yes-ref.html": [
@@ -404535,6 +404710,10 @@
         "6a81fd2c5e28412b1316c23a17ab6d5cac48873e",
         []
        ],
+       "WEB_FEATURES.yml": [
+        "c5f2a8811dda16b13199adde7b81e4659f69d57d",
+        []
+       ],
        "input-text-focused-ref.html": [
         "f78a937f17815a6a063a7465bf53fe402cdb671f",
         []
@@ -404723,6 +404902,10 @@
         "ca0f27e1264c80a86a50081786c047cdcb03840d",
         []
        ],
+       "WEB_FEATURES.yml": [
+        "944746a8eece9a2f3ecfd172ff37b98b0a785bb9",
+        []
+       ],
        "meter-min-rendering-ref.html": [
         "f253945968e49902d1f2c2d60d9d8cd230166c6b",
         []
@@ -404780,6 +404963,10 @@
        "DIR_METADATA": [
         "fc4f695cfcf8d1113152f89b4e363e756b4668a4",
         []
+       ],
+       "WEB_FEATURES.yml": [
+        "95c7b887c3770a821d37849b7cce77daf81ebf44",
+        []
        ]
       },
       "the-select-element": {
@@ -411157,7 +411344,7 @@
      []
     ],
     "crash-reporting.idl": [
-     "a6737ca8482e1d67c40d6d3618424969fa680f96",
+     "6eaee138a828f7749026458265e7db598822330f",
      []
     ],
     "credential-management.idl": [
@@ -411337,7 +411524,7 @@
      []
     ],
     "digital-credentials.idl": [
-     "e4ebb3b3e8621b668a18dcdeed7974e6446234e0",
+     "60b63975640c5a131c802ac459d08eb938446df8",
      []
     ],
     "digital-goods.idl": [
@@ -411861,7 +412048,7 @@
      []
     ],
     "speech-api.idl": [
-     "0e07b4619a5b80e901f0b8c17a208f9077f9187f",
+     "94a416f262b361e326c5b3c89fa8d160c1118b48",
      []
     ],
     "storage-access.idl": [
@@ -411900,6 +412087,10 @@
      "19f55156a6e3a40c8a6c78a303754c1c8ace58de",
      []
     ],
+    "translation-api.idl": [
+     "6cbad38938a15f373936cf760a9b30b8506bd5e0",
+     []
+    ],
     "trust-token-api.idl": [
      "9b74290da724b62fb91b3f5532b689cf70a10045",
      []
@@ -412073,7 +412264,7 @@
      []
     ],
     "webnn.idl": [
-     "37fcc32501efbeb38c9686a8fc96e1ce062eb30a",
+     "8d0e485bc76e49a616847f305d0b81cc5cce0589",
      []
     ],
     "webrtc-encoded-transform.idl": [
@@ -420154,6 +420345,10 @@
      "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
      []
     ],
+    "WEB_FEATURES.yml": [
+     "989f1fc7e45c3c1d04746a4cf627981a8652d4d2",
+     []
+    ],
     "resources": {
      "child.html": [
       "4d6895125a2acaad00cc2bc849e026a2632dd88e",
@@ -420877,7 +421072,7 @@
      ]
     },
     "idlharness.js": [
-     "d52ba9fd3c417955f5cb6eb68f96113057128318",
+     "2eb710c1827cda28b7bf75acd5b3a3d6c67d66fc",
      []
     ],
     "idlharness.js.headers": [
@@ -420945,7 +421140,7 @@
      []
     ],
     "testharness.js": [
-     "6ccede34483b227cc41fcb15235e56aa60d4022e",
+     "32f033a569b166b238fa9b02fbf99639f1f2f90c",
      []
     ],
     "testharness.js.headers": [
@@ -435030,11 +435225,11 @@
     },
     "resources": {
      "utils.js": [
-      "9d5cfc70c10187743807096421975a099f22afc9",
+      "c562b3028bdecd3cd9cb9afacd658132ca3b1420",
       []
      ],
      "utils_validation.js": [
-      "77a6d79205b5365d9a92af7d1a2d39df144a0f3f",
+      "3f8687b88f17a00eb29cd28d0cc4a81c75466b7c",
       []
      ]
     },
@@ -435428,8 +435623,12 @@
      "d4cec39ffce0f58b76da653c78dc384f22ffa43d",
      []
     ],
-    "idlharness.https.window-expected.txt": [
-     "655d49107e28d78dc284c4475f384527ea118af3",
+    "idlharness.https.window_exclude=SFrameTransform._-expected.txt": [
+     "5bd2fe419921843598c49bc16ffa70ed01c026bd",
+     []
+    ],
+    "idlharness.https.window_include=SFrameTransform._-expected.txt": [
+     "e0e394e24cf86578fe3cd367a9b4129258e39319",
      []
     ],
     "routines.js": [
@@ -467210,9 +467409,87 @@
       ]
      ]
     },
+    "rewriter": {
+     "rewriter-abort.tentative.https.window.js": [
+      "eaf33e62b758d37cb8668c031569c0bda6bb37f7",
+      [
+       "ai/rewriter/rewriter-abort.tentative.https.window.html",
+       {
+        "script_metadata": [
+         [
+          "title",
+          "Rewriter Abort"
+         ],
+         [
+          "script",
+          "../resources/util.js"
+         ],
+         [
+          "timeout",
+          "long"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ]
+     ],
+     "rewriter-from-detached-iframe.tentative.https.window.js": [
+      "ecc24c77be7b9e05cd20a1a307432e25d4972d87",
+      [
+       "ai/rewriter/rewriter-from-detached-iframe.tentative.https.window.html",
+       {
+        "script_metadata": [
+         [
+          "title",
+          "Rewriter Detached Iframe"
+         ],
+         [
+          "script",
+          "../resources/util.js"
+         ],
+         [
+          "timeout",
+          "long"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ]
+     ],
+     "rewriter-iframe.tentative.https.html": [
+      "979a39b86973bfd02e96fc81f489f3db4928efdd",
+      [
+       null,
+       {}
+      ]
+     ],
+     "rewriter.tentative.https.window.js": [
+      "86b9a2fbccdd2b0ee4ebb11ff34d4385d7a025ab",
+      [
+       "ai/rewriter/rewriter.tentative.https.window.html",
+       {
+        "script_metadata": [
+         [
+          "title",
+          "Rewriter"
+         ],
+         [
+          "script",
+          "../resources/util.js"
+         ],
+         [
+          "timeout",
+          "long"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ]
+     ]
+    },
     "summarizer": {
      "summarizer-abort.tentative.https.window.js": [
-      "64595ea930c9e21b8044a281c2f9f4d467478772",
+      "c96c561e6faedc457a8b81d2f2ff7fb2d1546981",
       [
        "ai/summarizer/summarizer-abort.tentative.https.window.html",
        {
@@ -467222,10 +467499,6 @@
           "Summarizer Abort"
          ],
          [
-          "global",
-          "window,worker"
-         ],
-         [
           "script",
           "../resources/util.js"
          ]
@@ -467465,6 +467738,84 @@
        }
       ]
      ]
+    },
+    "writer": {
+     "writer-abort.tentative.https.window.js": [
+      "f1796d22fb98f10e17b3309367eed3de093a82a5",
+      [
+       "ai/writer/writer-abort.tentative.https.window.html",
+       {
+        "script_metadata": [
+         [
+          "title",
+          "Writer Abort"
+         ],
+         [
+          "script",
+          "../resources/util.js"
+         ],
+         [
+          "timeout",
+          "long"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ]
+     ],
+     "writer-from-detached-iframe.tentative.https.window.js": [
+      "6143bc4276fbe6ea2f9f16270b293174cda496f5",
+      [
+       "ai/writer/writer-from-detached-iframe.tentative.https.window.html",
+       {
+        "script_metadata": [
+         [
+          "title",
+          "Writer Detached Iframe"
+         ],
+         [
+          "script",
+          "../resources/util.js"
+         ],
+         [
+          "timeout",
+          "long"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ]
+     ],
+     "writer-iframe.tentative.https.html": [
+      "10819399324f8204ba0a03f7d255ab51f7b07bb3",
+      [
+       null,
+       {}
+      ]
+     ],
+     "writer.tentative.https.window.js": [
+      "38b1254e3459446e619c6baf9b308d3b4d92f243",
+      [
+       "ai/writer/writer.tentative.https.window.html",
+       {
+        "script_metadata": [
+         [
+          "title",
+          "Writer Detached Iframe"
+         ],
+         [
+          "script",
+          "../resources/util.js"
+         ],
+         [
+          "timeout",
+          "long"
+         ]
+        ],
+        "timeout": "long"
+       }
+      ]
+     ]
     }
    },
    "ambient-light": {
@@ -476712,7 +477063,7 @@
      ]
     ],
     "async-navigator-clipboard-basics.https.html": [
-     "f7aed80b17ebd0af8f4c255ef83dfc85a7eb71ce",
+     "b71d6665bcba982b9d686f3b1d6115269feb60e3",
      [
       null,
       {
@@ -476738,6 +477089,15 @@
       }
      ]
     ],
+    "async-navigator-clipboard-write-domstring.https.html": [
+     "a16f358f46d4d555ade6a96eb5f14f73c732e1c5",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "async-navigator-clipboard-write-multiple.tentative.https.sub.html": [
      "c310203503f3530b881b866b7fc2f8b8ade5b371",
      [
@@ -496275,6 +496635,20 @@
          null,
          {}
         ]
+       ],
+       "corner-shape-outside-left.html": [
+        "b38b7f3f27872e5bf8ad402aa6dabe981a9d5530",
+        [
+         null,
+         {}
+        ]
+       ],
+       "corner-shape-outside-right.html": [
+        "96a297230bb52863ac149c7a8da1ec1e9d20bcac",
+        [
+         null,
+         {}
+        ]
        ]
       },
       "parsing": {
@@ -538253,7 +538627,7 @@
      ]
     ],
     "allow-attribute-with-get.https.html": [
-     "15601d891f25c4c2d75dad2260d1b45a26a9344d",
+     "a13a188c9da1554df1cd38ca07e3fcb87837063f",
      [
       null,
       {
@@ -538334,7 +538708,7 @@
      ]
     ],
     "non-fully-active.https.html": [
-     "3c09b132daf76ec719cadf2fc741d60a2a8d0df2",
+     "8d8f889f6ac627d584e27e59e001e2b5e7e7d90a",
      [
       null,
       {
@@ -538343,7 +538717,7 @@
      ]
     ],
     "user-activation.https.html": [
-     "facaf7bddbbd419801a9ffa470f4bb5bbc1ab07c",
+     "1189c32252ae1a1c52fa2d75d11f4ec00b45d57a",
      [
       null,
       {
@@ -645050,7 +645424,7 @@
         ]
        ],
        "iframe-loading-lazy-nav-navigation-navigate.html": [
-        "1010c540b7fd59521278ece38b34f9e572e4e4a6",
+        "47435f4c48d4e2fb1c5382c27c0325dfc1a7e8bf",
         [
          null,
          {}
@@ -645078,7 +645452,7 @@
         ]
        ],
        "iframe-loading-lazy-reload-navigation-reload.html": [
-        "aefd6c472b5ae888e0786de8e26e8d9ad5111adb",
+        "6633b710828d8f15e8f7edf0834c6260bd270bb3",
         [
          null,
          {}
@@ -712367,15 +712741,6 @@
       }
      ]
     ],
-    "replacestate.tentative.html": [
-     "d47b9b653881f57e085fef94360c9245e23c022f",
-     [
-      null,
-      {
-       "testdriver": true
-      }
-     ]
-    ],
     "second-interaction-not-softnav.tentative.html": [
      "a9bb337060d00a5e21075f2c2cb53570e500afaf",
      [
@@ -712388,7 +712753,7 @@
     "smoke": {
      "tentative": {
       "almost-soft-navigation.html": [
-       "bbd09e1625d2a10694e3af94ed6fe4d246be921e",
+       "aa5732f9fb7e735d72c732a8299f5832db410ce0",
        [
         null,
         {
@@ -712452,15 +712817,6 @@
       }
      ]
     ],
-    "soft-navigation-no-url.tentative.html": [
-     "a0055c654c2049c9df444510c892489e363d0bb3",
-     [
-      null,
-      {
-       "testdriver": true
-      }
-     ]
-    ],
     "softnav-after-lcp-paint-larger-than-viewport.tentative.html": [
      "3c930d8be4cd459d9167404be13ad9ac219ec422",
      [
@@ -715440,7 +715796,7 @@
      ]
     ],
     "SpeechRecognition-basics.https.html": [
-     "827844096f6e58a7b64f1192958c8a2475a1410f",
+     "91cf8e6d3e54a64a6cac0cf776fa618b99966cbc",
      [
       null,
       {}
@@ -715581,7 +715937,7 @@
    "storage": {
     "buckets": {
      "bucket-quota-indexeddb.tentative.https.any.js": [
-      "ee9202777e7ec55faee0b89f4c656f7a76c05e83",
+      "49cd7077b7908e75ee626d307fffbba8310630fe",
       [
        "storage/buckets/bucket-quota-indexeddb.tentative.https.any.html",
        {
@@ -763705,7 +764061,7 @@
        ]
       ],
       "DOMException-constructor-behavior.any.js": [
-       "c4ddabdafd4597aac6f13ad5182b78566045c09a",
+       "5bb6da77a7d1ca7d68a74538b36e609bb3f0c417",
        [
         "webidl/ecmascript-binding/es-exceptions/DOMException-constructor-behavior.any.html",
         {
@@ -796827,12 +797183,55 @@
      ]
     ],
     "idlharness.https.window.js": [
-     "2c6ef19ca82a56c799b97b5eb9af3edb900a40b5",
+     "d3eea3bc138cad7676690e274006a5c521ec038d",
      [
-      "webrtc-encoded-transform/idlharness.https.window.html",
+      "webrtc-encoded-transform/idlharness.https.window.html?exclude=SFrameTransform.*",
       {
        "script_metadata": [
         [
+         "variant",
+         "?exclude=SFrameTransform.*"
+        ],
+        [
+         "variant",
+         "?include=SFrameTransform.*"
+        ],
+        [
+         "script",
+         "/common/subset-tests-by-key.js"
+        ],
+        [
+         "script",
+         "/resources/WebIDLParser.js"
+        ],
+        [
+         "script",
+         "/resources/idlharness.js"
+        ],
+        [
+         "script",
+         "./RTCPeerConnection-helper.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "webrtc-encoded-transform/idlharness.https.window.html?include=SFrameTransform.*",
+      {
+       "script_metadata": [
+        [
+         "variant",
+         "?exclude=SFrameTransform.*"
+        ],
+        [
+         "variant",
+         "?include=SFrameTransform.*"
+        ],
+        [
+         "script",
+         "/common/subset-tests-by-key.js"
+        ],
+        [
          "script",
          "/resources/WebIDLParser.js"
         ],
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-center-visibility-change-ref.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-center-visibility-change-ref.html
index 66bf9083..bc9872a9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-center-visibility-change-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-center-visibility-change-ref.html
@@ -17,16 +17,43 @@
   background: lime;
 }
 
-.target {
-  position: fixed;
-  background: cyan;
-  left: 111px;
+.target-inner {
+  width: 30px;
+  height: 20px;
 }
+
+.target {
+  position: absolute;
+}
+
+#target-1 {
+  background: cyan;
+  left: 50px;
+}
+
+#target-2 {
+  top: 20px;
+  left: 0;
+  background: blue;
+}
+
+#target-3 {
+  top: 20px;
+  left: 50px;
+  background: magenta;
+}
+
 </style>
 
 <div class="container">
   <div class="anchor"></div>
-  <div class="target">
-    <div style="width:30px;height:20px;"></div>
+  <div id="target-1" class="target">
+    <div class="target-inner"></div>
+  </div>
+  <div id="target-2" class="target">
+    <div class="target-inner"></div>
+  </div>
+  <div id="target-3" class="target">
+    <div class="target-inner"></div>
   </div>
 </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-center-visibility-change.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-center-visibility-change.html
index 0f7d8058..e555943 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-center-visibility-change.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-center-visibility-change.html
@@ -1,8 +1,9 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
-<title>Tests 'anchor-center' value when target visibility changes</title>
+<title>Tests 'anchor-center' value when target visibility changes (by changing 'display', 'visibility', or popover trigger)</title>
 <link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#valdef-justify-self-anchor-center">
 <link rel="author" href="mailto:plampe@igalia.com">
+<link rel="author" href="mailto:kiet.ho@apple.com">
 <link rel="match" href="anchor-center-visibility-change-ref.html">
 <script src="/common/reftest-wait.js"></script>
 <script src="/common/rendering-utils.js"></script>
@@ -27,27 +28,61 @@
 
 .target {
   position-anchor: --anchor;
-  position: fixed;
-  background: cyan;
+  position: absolute;
+}
+
+.target-inner {
+  width: 30px;
+  height: 20px;
+}
+
+#target-1 {
   justify-self: anchor-center;
+  background: cyan;
   display: none;
 }
+
+#target-2 {
+  align-self: anchor-center;
+  background: blue;
+  visibility: hidden;
+}
+
+#target-3 {
+  align-self: anchor-center;
+  justify-self: anchor-center;
+  background: magenta;
+
+  /* Override default popover style */
+  margin: 0;
+  padding: 0;
+  border: none;
+}
 </style>
 
 <div class="container">
   <div class="anchor"></div>
-  <div id="target" class="target">
-    <div style="width:30px;height:20px;"></div>
+  <div id="target-1" class="target">
+    <div class="target-inner"></div>
+  </div>
+  <div id="target-2" class="target">
+    <div class="target-inner"></div>
+  </div>
+  <div id="target-3" class="target" popover>
+    <div class="target-inner"></div>
   </div>
 </div>
 
 <script>
-  // #target should be invisible initially.
+  // Targets should be invisible initially.
   waitForAtLeastOneFrame().then(() => {
-    // Change #target to be visible.
-    document.getElementById('target').style.display = 'flow';
+    // Change targets to be visible.
+    document.getElementById('target-1').style.display = 'flow';
+    document.getElementById('target-2').style.visibility = 'visible';
+    document.getElementById('target-3').showPopover();
+
     waitForAtLeastOneFrame().then(() => {
-      // #target should be visible and anchor-centered now.
+      // Targets should be visible now.
       takeScreenshot();
     });
   });
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-visibility-change.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-visibility-change.html
new file mode 100644
index 0000000..61d8ab5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-visibility-change.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+
+<html class="reftest-wait">
+
+<head>
+  <title>Tests that an element positioned using position-area renders when it's initially hidden, then shown</title>
+
+  <link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#position-area">
+  <link rel="author" href="mailto:kiet.ho@apple.com">
+  <link rel="match" href="reference/position-area-visibility-change-ref.html">
+
+  <script src="/common/reftest-wait.js"></script>
+  <script src="/common/rendering-utils.js"></script>
+
+  <style>
+    .containing-block {
+      position: relative;
+      width: 150px;
+      height: 150px;
+      outline: 2px black solid;
+    }
+
+    .cell {
+      width: 50px;
+      height: 50px;
+    }
+
+    #anchor-cell {
+      position: absolute;
+      top: 50px;
+      left: 50px;
+
+      anchor-name: --anchor;
+
+      background: green;
+    }
+
+    .anchor-positioned-cell {
+      position: absolute;
+      position-anchor: --anchor;
+    }
+
+    #target-1 {
+      position-area: top right;
+
+      /* Will be changed to 'block' */
+      display: none;
+    }
+
+    #target-2 {
+      position-area: bottom left;
+
+      /* Will be changed to 'visible' */
+      visibility: hidden;
+    }
+
+    #target-3 {
+      position-area: bottom right;
+
+      /* Override default popover style */
+      margin: 0;
+      padding: 0;
+      border: none;
+    }
+
+    .blue-background {
+      background: blue;
+    }
+
+    .magenta-background {
+      background: magenta;
+    }
+
+    .cyan-background {
+      background: cyan;
+    }
+  </style>
+</head>
+
+<body>
+  <div class="containing-block">
+    <div class="cell" id="anchor-cell"></div>
+
+    <div class="cell anchor-positioned-cell" id="target-1">
+      <div class="cell blue-background"></div>
+    </div>
+
+    <div class="cell anchor-positioned-cell" id="target-2">
+      <div class="cell magenta-background"></div>
+    </div>
+
+    <div class="cell anchor-positioned-cell" id="target-3" popover>
+      <div class="cell cyan-background"></div>
+    </div>
+  </div>
+
+  <script>
+    // All targets should initially be hidden.
+    waitForAtLeastOneFrame().then(() => {
+      // Change targets to be visible.
+      document.getElementById('target-1').style.display = 'block';
+      document.getElementById('target-2').style.visibility = 'visible';
+      document.getElementById('target-3').showPopover();
+
+      waitForAtLeastOneFrame().then(() => {
+        // All targets should be visible now.
+        takeScreenshot();
+      });
+    });
+  </script>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/reference/position-area-visibility-change-ref.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/reference/position-area-visibility-change-ref.html
new file mode 100644
index 0000000..87e1804
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/reference/position-area-visibility-change-ref.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+
+<style>
+  .containing-block {
+    position: relative;
+    width: 150px;
+    height: 150px;
+    outline: 2px black solid;
+  }
+
+  .cell {
+    width: 50px;
+    height: 50px;
+  }
+
+  #anchor-cell {
+    position: absolute;
+    top: 50px;
+    left: 50px;
+
+    background: green;
+  }
+
+  .anchor-positioned-cell {
+    position: absolute;
+  }
+
+  #target-1 {
+    top: 0;
+    right: 0;
+  }
+
+  #target-2 {
+    bottom: 0;
+    left: 0;
+  }
+
+  #target-3 {
+    bottom: 0;
+    right: 0;
+  }
+
+  .blue-background {
+    background: blue;
+  }
+
+  .magenta-background {
+    background: magenta;
+  }
+
+  .cyan-background {
+    background: cyan;
+  }
+</style>
+
+<body>
+  <div class="containing-block">
+    <div class="cell" id="anchor-cell"></div>
+
+    <div class="cell anchor-positioned-cell" id="target-1">
+      <div class="cell blue-background"></div>
+    </div>
+
+    <div class="cell anchor-positioned-cell" id="target-2">
+      <div class="cell magenta-background"></div>
+    </div>
+
+    <div class="cell anchor-positioned-cell" id="target-3">
+      <div class="cell cyan-background"></div>
+    </div>
+  </div>
+</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-initial-target/scroll-initial-target-with-text-fragment-navigation-target.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-initial-target/scroll-initial-target-with-text-fragment-navigation-target.html
index aea8e120..8b3c168 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-initial-target/scroll-initial-target-with-text-fragment-navigation-target.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-initial-target/scroll-initial-target-with-text-fragment-navigation-target.html
@@ -57,11 +57,12 @@
       const expected_scroll_top = document.scrollingElement.scrollHeight -
         document.scrollingElement.clientHeight;
 
-      const scroll_start_target_top = top_box.getBoundingClientRect().height;
+      const scroll_start_target_top = Math.round(top_box.getBoundingClientRect().height);
 
-      if (document.scrollingElement.scrollTop == scroll_start_target_top) {
+      const actual_scroll_top = Math.round(document.scrollingElement.scrollTop);
+      if (actual_scroll_top == scroll_start_target_top) {
         scroll_position = "AT_SCROLL_START_TARGET";
-      } else if (document.scrollingElement.scrollTop == expected_scroll_top) {
+      } else if (actual_scroll_top == expected_scroll_top) {
         scroll_position = "AT_TEXT_FRAGMENT";
       }
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-ui/WEB_FEATURES.yml
index a10f702..e699a40 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/WEB_FEATURES.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/WEB_FEATURES.yml
@@ -8,3 +8,6 @@
 - name: outline
   files:
   - outline-*
+- name: user-select
+  files:
+  - user-select-*
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/WEB_FEATURES.yml
index b4ae339..3be770b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/WEB_FEATURES.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/parsing/WEB_FEATURES.yml
@@ -2,3 +2,6 @@
 - name: field-sizing
   files:
   - field-sizing-*
+- name: user-select
+  files:
+  - user-select-*
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/negated-last-of-type-invalidation.html b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/negated-last-of-type-invalidation.html
new file mode 100644
index 0000000..40bf8a8f0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/invalidation/negated-last-of-type-invalidation.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset="utf-8">
+<html class="reftest-wait">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1964575">
+<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-last-of-type-pseudo">
+<style>
+#dut {
+  width: 100px;
+  height: 100px;
+  background: red;
+}
+.foo:not(:last-of-type ~ .bar) > #dut.baz {
+  background-color: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div>
+  <span></span>
+  <div class="foo bar">
+    <div id=dut></div>
+  </div>
+  <span></span>
+</div>
+<script>
+window.onload = () => {
+  dut.classList.add("baz");
+  document.documentElement.classList.remove('reftest-wait');
+};
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/allow-attribute-with-get.https.html b/third_party/blink/web_tests/external/wpt/digital-credentials/allow-attribute-with-get.https.html
index 15601d8..a13a188c 100644
--- a/third_party/blink/web_tests/external/wpt/digital-credentials/allow-attribute-with-get.https.html
+++ b/third_party/blink/web_tests/external/wpt/digital-credentials/allow-attribute-with-get.https.html
@@ -105,10 +105,11 @@
                         const options = {
                             digital: {
                                 // Results in TypeError when allowed, NotAllowedError when disallowed
-                                requests: [],
+                                requests: [{ data: {}, protocol: "openid4vp" }],
                             },
                             mediation: "required",
                         };
+                        await test_driver.bless("User activation");
                         const { data } = await new Promise((resolve) => {
                             window.addEventListener("message", resolve, {
                                 once: true,
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/non-fully-active.https.html b/third_party/blink/web_tests/external/wpt/digital-credentials/non-fully-active.https.html
index 3c09b13..8d8f889 100644
--- a/third_party/blink/web_tests/external/wpt/digital-credentials/non-fully-active.https.html
+++ b/third_party/blink/web_tests/external/wpt/digital-credentials/non-fully-active.https.html
@@ -33,7 +33,7 @@
     controller.abort();
 
     // Steal all the needed references.
-    const navigator = iframe.contentWindow.navigator;
+    const { credentials } = iframe.contentWindow.navigator;
     const DOMExceptionCtor = iframe.contentWindow.DOMException;
 
     // No longer fully active.
@@ -44,7 +44,7 @@
       t,
       "InvalidStateError",
       DOMExceptionCtor,
-      navigator.credentials.get({ signal }),
+      credentials.get({ signal }),
       "Expected InvalidStateError for get() on non-fully-active document"
     );
 
@@ -53,7 +53,7 @@
       t,
       "InvalidStateError",
       DOMExceptionCtor,
-      navigator.credentials.create({ signal }),
+      credentials.create({ signal }),
       "Expected InvalidStateError for create() on non-fully-active document"
     );
 
@@ -62,7 +62,7 @@
       t,
       "InvalidStateError",
       DOMExceptionCtor,
-      navigator.credentials.preventSilentAccess(),
+      credentials.preventSilentAccess(),
       "Expected InvalidStateError for preventSilentAccess() on non-fully-active document"
     );
   }, "non-fully active document behavior for CredentialsContainer");
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/support/iframe.html b/third_party/blink/web_tests/external/wpt/digital-credentials/support/iframe.html
index 3ec761e..d737dcf 100644
--- a/third_party/blink/web_tests/external/wpt/digital-credentials/support/iframe.html
+++ b/third_party/blink/web_tests/external/wpt/digital-credentials/support/iframe.html
@@ -27,8 +27,8 @@
       }
       data.options.signal = abortController.signal;
     }
-    if (data.needsActivation) {
-      await test_driver.bless("user activation", null, window);
+    if (data.needsActivation && !navigator.userActivation.isActive) {
+      await test_driver.bless("user activation");
     }
     let result;
     try {
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/user-activation.https-expected.txt b/third_party/blink/web_tests/external/wpt/digital-credentials/user-activation.https-expected.txt
index 5b258016..fed8949 100644
--- a/third_party/blink/web_tests/external/wpt/digital-credentials/user-activation.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/digital-credentials/user-activation.https-expected.txt
@@ -1,6 +1,4 @@
 This is a testharness.js-based test.
-[FAIL] navigator.credentials.get() calling the API without user activation should reject with NotAllowedError.
-  promise_rejects_dom: function "function() { throw e; }" threw object "TypeError: Failed to execute 'get' on 'CredentialsContainer': Digital identity API needs at least one well-formed request." that is not a DOMException NotAllowedError: property "code" is equal to undefined, expected 0
 [FAIL] navigator.credentials.get() consumes user activation.
   assert_false: User activation should be consumed after navigator.credentials.get(). expected false got true
 [FAIL] navigator.credentials.create() calling the API without user activation should reject with NotAllowedError.
diff --git a/third_party/blink/web_tests/external/wpt/digital-credentials/user-activation.https.html b/third_party/blink/web_tests/external/wpt/digital-credentials/user-activation.https.html
index facaf7bd..1189c32 100644
--- a/third_party/blink/web_tests/external/wpt/digital-credentials/user-activation.https.html
+++ b/third_party/blink/web_tests/external/wpt/digital-credentials/user-activation.https.html
@@ -14,7 +14,7 @@
       navigator.userActivation.isActive,
       "User activation should not be active"
     );
-    const options = makeGetOptions([]);
+    const options = makeGetOptions("openid4vp");
     await promise_rejects_dom(
       t,
       "NotAllowedError",
@@ -24,12 +24,17 @@
 
   promise_test(async (t) => {
     await test_driver.bless();
+    const abort = new AbortController();
+    const options = makeGetOptions("openid4vp");
+    options.signal = abort.signal;
     assert_true(
       navigator.userActivation.isActive,
       "User activation should be active after test_driver.bless()."
     );
-    const options = makeGetOptions([]);
-    await promise_rejects_js(t, TypeError, navigator.credentials.get(options));
+
+    const getPromise = navigator.credentials.get(options);
+    abort.abort();
+    await promise_rejects_dom(t, "AbortError", getPromise);
     assert_false(
       navigator.userActivation.isActive,
       "User activation should be consumed after navigator.credentials.get()."
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/noopener-helper.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/noopener-helper.js
index 6dd2c9b..ead0ef3 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/noopener-helper.js
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/noopener-helper.js
@@ -121,8 +121,9 @@
     assert_equals(await receive(reply_token), 'Popup loaded');
     t.add_cleanup(() => send(popup_token, 'window.close()'));
 
-    // Assert that we can script the popup.
-    assert_not_equals(popup.window, null, 'can script the popup');
+    // There's an open question if we should check that popup.window is null here.
+    // See https://github.com/whatwg/html/issues/10457
+    // Assert that we cannot script the popup.
     assert_false(popup.closed, 'popup closed');
 
     // Ensure that the popup has no access to its opener.
diff --git "a/third_party/blink/web_tests/external/wpt/html/dom/idlharness.https_include=\050Document_Window\051-expected.txt" "b/third_party/blink/web_tests/external/wpt/html/dom/idlharness.https_include=\050Document_Window\051-expected.txt"
index a59b20d..e975efd 100644
--- "a/third_party/blink/web_tests/external/wpt/html/dom/idlharness.https_include=\050Document_Window\051-expected.txt"
+++ "b/third_party/blink/web_tests/external/wpt/html/dom/idlharness.https_include=\050Document_Window\051-expected.txt"
@@ -1,19 +1,7 @@
 This is a testharness.js-based test.
-Found 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] Window interface: attribute navigation
   assert_equals: setter must be undefined for readonly attributes expected (undefined) undefined but got (function) function "function set navigation() { [native code] }"
-[FAIL] Window interface: attribute oncopy
-  assert_own_property: The global object must have a property "oncopy" expected property "oncopy" missing
-[FAIL] Window interface: attribute oncut
-  assert_own_property: The global object must have a property "oncut" expected property "oncut" missing
-[FAIL] Window interface: attribute onpaste
-  assert_own_property: The global object must have a property "onpaste" expected property "onpaste" missing
-[FAIL] Window interface: window must inherit property "oncopy" with the proper type
-  assert_own_property: expected property "oncopy" missing
-[FAIL] Window interface: window must inherit property "oncut" with the proper type
-  assert_own_property: expected property "oncut" missing
-[FAIL] Window interface: window must inherit property "onpaste" with the proper type
-  assert_own_property: expected property "onpaste" missing
 [FAIL] Document interface: calling parseHTMLUnsafe((TrustedHTML or DOMString)) on iframe.contentDocument with too few arguments must throw TypeError
   assert_own_property: interface object must have static operation as own property expected property "parseHTMLUnsafe" missing
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-navigation-navigate.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-navigation-navigate.html
index 1010c540..47435f4 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-navigation-navigate.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-nav-navigation-navigate.html
@@ -14,8 +14,8 @@
 <script src="/resources/testharnessreport.js"></script>
 <script>
 setup({single_test: true});
+assert_true("navigation" in window, "Navigation API is supported");
 iframeLoaded.then(() => {
-  assert_true("navigation" in window, "Navigation API is supported");
   // Need a timeout to detect failure when there are two navigations.
   step_timeout(() => {
     assert_equals(iframe.contentWindow.location.href, new URL("support/blank.htm?nav", location.href).href);
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload-expected.txt
index 3ad8c48..8d930e9 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-[FAIL] Reloading iframe loading='lazy' before it is loaded: location.reload
+[FAIL] Reloading iframe loading='lazy' before it is loaded: navigation.reload
   Uncaught Error: assert_equals: expected "http://web-platform.test:8001/html/semantics/embedded-content/the-iframe-element/support/blank.htm?src" but got "about:blank"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html
index aefd6c4..6633b710 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<title>Reloading iframe loading='lazy' before it is loaded: location.reload</title>
+<title>Reloading iframe loading='lazy' before it is loaded: navigation.reload</title>
 <iframe src="support/blank.htm?src" loading="lazy" hidden></iframe>
 <script>
 const iframe = document.querySelector('iframe');
@@ -15,10 +15,10 @@
 <script src="/resources/testharnessreport.js"></script>
 <script>
 setup({single_test: true});
+assert_true("navigation" in window, "Navigation API is supported");
 iframeLoaded.then(() => {
   // Need a timeout to detect failure when there are two navigations.
   step_timeout(() => {
-    assert_true("navigation" in window, "Navigation API is supported");
     assert_equals(iframe.contentWindow.location.href, new URL("support/blank.htm?src", location.href).href);
     done();
   }, 1000);
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-datalist-element/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-datalist-element/WEB_FEATURES.yml
new file mode 100644
index 0000000..c5f2a881
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-datalist-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: datalist
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-meter-element/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-meter-element/WEB_FEATURES.yml
new file mode 100644
index 0000000..944746a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-meter-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: meter
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-progress-element/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-progress-element/WEB_FEATURES.yml
new file mode 100644
index 0000000..95c7b88
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-progress-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: progress
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/crash-reporting.idl b/third_party/blink/web_tests/external/wpt/interfaces/crash-reporting.idl
index a6737ca8..6eaee13 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/crash-reporting.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/crash-reporting.idl
@@ -8,4 +8,6 @@
   [Default] object toJSON();
   readonly attribute DOMString? reason;
   readonly attribute DOMString? stack;
+  readonly attribute DOMString? is_top_level;
+  readonly attribute DocumentVisibilityState? page_visibility;
 };
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/digital-credentials.idl b/third_party/blink/web_tests/external/wpt/interfaces/digital-credentials.idl
index e4ebb3b..60b6397 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/digital-credentials.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/digital-credentials.idl
@@ -1,17 +1,30 @@
 // GENERATED CONTENT - DO NOT EDIT
 // Content was automatically extracted by Reffy into webref
 // (https://github.com/w3c/webref)
-// Source: Digital Credentials (https://wicg.github.io/digital-credentials/)
+// Source: Digital Credentials (https://w3c-fedid.github.io/digital-credentials/)
 
 partial dictionary CredentialRequestOptions {
   DigitalCredentialRequestOptions digital;
 };
 
 dictionary DigitalCredentialRequestOptions {
-  sequence<DigitalCredentialRequest> requests;
+  sequence<DigitalCredentialGetRequest> requests;
 };
 
-dictionary DigitalCredentialRequest {
+dictionary DigitalCredentialGetRequest {
+  required DOMString protocol;
+  required object data;
+};
+
+partial dictionary CredentialCreationOptions {
+  DigitalCredentialCreationOptions digital;
+};
+
+dictionary DigitalCredentialCreationOptions {
+  sequence<DigitalCredentialCreateRequest> requests;
+};
+
+dictionary DigitalCredentialCreateRequest {
   required DOMString protocol;
   required object data;
 };
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/speech-api.idl b/third_party/blink/web_tests/external/wpt/interfaces/speech-api.idl
index 0e07b46..94a416f 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/speech-api.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/speech-api.idl
@@ -3,7 +3,7 @@
 // (https://github.com/w3c/webref)
 // Source: Web Speech API (https://webaudio.github.io/web-speech-api/)
 
-[Exposed=Window]
+[SecureContext, Exposed=Window]
 interface SpeechRecognition : EventTarget {
     constructor();
 
@@ -61,7 +61,7 @@
     "available"
 };
 
-[Exposed=Window]
+[SecureContext, Exposed=Window]
 interface SpeechRecognitionErrorEvent : Event {
     constructor(DOMString type, SpeechRecognitionErrorEventInit eventInitDict);
     readonly attribute SpeechRecognitionErrorCode error;
@@ -74,14 +74,14 @@
 };
 
 // Item in N-best list
-[Exposed=Window]
+[SecureContext, Exposed=Window]
 interface SpeechRecognitionAlternative {
     readonly attribute DOMString transcript;
     readonly attribute float confidence;
 };
 
 // A complete one-shot simple response
-[Exposed=Window]
+[SecureContext, Exposed=Window]
 interface SpeechRecognitionResult {
     readonly attribute unsigned long length;
     getter SpeechRecognitionAlternative item(unsigned long index);
@@ -89,14 +89,14 @@
 };
 
 // A collection of responses (used in continuous mode)
-[Exposed=Window]
+[SecureContext, Exposed=Window]
 interface SpeechRecognitionResultList {
     readonly attribute unsigned long length;
     getter SpeechRecognitionResult item(unsigned long index);
 };
 
 // A full response, which could be interim or final, part of a continuous response or not
-[Exposed=Window]
+[SecureContext, Exposed=Window]
 interface SpeechRecognitionEvent : Event {
     constructor(DOMString type, SpeechRecognitionEventInit eventInitDict);
     readonly attribute unsigned long resultIndex;
@@ -109,7 +109,7 @@
 };
 
 // The object representing a phrase for contextual biasing.
-[Exposed=Window]
+[SecureContext, Exposed=Window]
 interface SpeechRecognitionPhrase {
     constructor(DOMString phrase, optional float boost = 1.0);
     readonly attribute DOMString phrase;
@@ -117,7 +117,7 @@
 };
 
 // The object representing a list of phrases for contextual biasing.
-[Exposed=Window]
+[SecureContext, Exposed=Window]
 interface SpeechRecognitionPhraseList {
     constructor(sequence<SpeechRecognitionPhrase> phrases);
     readonly attribute unsigned long length;
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/translation-api.idl b/third_party/blink/web_tests/external/wpt/interfaces/translation-api.idl
new file mode 100644
index 0000000..6cbad38
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/interfaces/translation-api.idl
@@ -0,0 +1,85 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content was automatically extracted by Reffy into webref
+// (https://github.com/w3c/webref)
+// Source: Translator and Language Detector APIs (https://webmachinelearning.github.io/translation-api/)
+
+[Exposed=Window, SecureContext]
+interface Translator {
+  static Promise<Translator> create(TranslatorCreateOptions options);
+  static Promise<Availability> availability(TranslatorCreateCoreOptions options);
+
+  Promise<DOMString> translate(
+    DOMString input,
+    optional TranslatorTranslateOptions options = {}
+  );
+  ReadableStream translateStreaming(
+    DOMString input,
+    optional TranslatorTranslateOptions options = {}
+  );
+
+  readonly attribute DOMString sourceLanguage;
+  readonly attribute DOMString targetLanguage;
+
+  Promise<double> measureInputUsage(
+    DOMString input,
+    optional TranslatorTranslateOptions options = {}
+  );
+  readonly attribute unrestricted double inputQuota;
+};
+Translator includes DestroyableModel;
+
+dictionary TranslatorCreateCoreOptions {
+  required DOMString sourceLanguage;
+  required DOMString targetLanguage;
+};
+
+dictionary TranslatorCreateOptions : TranslatorCreateCoreOptions {
+  AbortSignal signal;
+  CreateMonitorCallback monitor;
+};
+
+dictionary TranslatorTranslateOptions {
+  AbortSignal signal;
+};
+
+[Exposed=Window, SecureContext]
+interface LanguageDetector {
+  static Promise<LanguageDetector> create(
+    optional LanguageDetectorCreateOptions options = {}
+  );
+  static Promise<Availability> availability(
+    optional LanguageDetectorCreateCoreOptions options = {}
+  );
+
+  Promise<sequence<LanguageDetectionResult>> detect(
+    DOMString input,
+    optional LanguageDetectorDetectOptions options = {}
+  );
+
+  readonly attribute FrozenArray<DOMString>? expectedInputLanguages;
+
+  Promise<double> measureInputUsage(
+    DOMString input,
+    optional LanguageDetectorDetectOptions options = {}
+  );
+  readonly attribute unrestricted double inputQuota;
+};
+LanguageDetector includes DestroyableModel;
+
+dictionary LanguageDetectorCreateCoreOptions {
+  sequence<DOMString> expectedInputLanguages;
+};
+
+dictionary LanguageDetectorCreateOptions : LanguageDetectorCreateCoreOptions {
+  AbortSignal signal;
+  CreateMonitorCallback monitor;
+};
+
+dictionary LanguageDetectorDetectOptions {
+  AbortSignal signal;
+};
+
+dictionary LanguageDetectionResult {
+  DOMString detectedLanguage;
+  double confidence;
+};
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/webnn.idl b/third_party/blink/web_tests/external/wpt/interfaces/webnn.idl
index 37fcc32..8d0e485b 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/webnn.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/webnn.idl
@@ -799,8 +799,7 @@
 enum MLPaddingMode {
   "constant",
   "edge",
-  "reflection",
-  "symmetric"
+  "reflection"
 };
 
 dictionary MLPadOptions : MLOperatorOptions {
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/requestidlecallback/WEB_FEATURES.yml
new file mode 100644
index 0000000..989f1fc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/requestidlecallback/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: requestidlecallback
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/resources/idlharness.js b/third_party/blink/web_tests/external/wpt/resources/idlharness.js
index d52ba9f..2eb710c1 100644
--- a/third_party/blink/web_tests/external/wpt/resources/idlharness.js
+++ b/third_party/blink/web_tests/external/wpt/resources/idlharness.js
@@ -783,6 +783,10 @@
         }
         testedPartials.set(parsed_idl.name, partialTestCount);
 
+        if (!self.shouldRunSubTest(partialTestName)) {
+            return;
+        }
+
         if (!parsed_idl.untested) {
             test(function () {
                 assert_true(originalExists, `Original ${parsed_idl.type} should be defined`);
@@ -871,6 +875,7 @@
     {
         const lhs = parsed_idl.target;
         const rhs = parsed_idl.includes;
+        const testName = lhs + " includes " + rhs + ": member names are unique";
 
         var errStr = lhs + " includes " + rhs + ", but ";
         if (!(lhs in this.members)) throw errStr + lhs + " is undefined.";
@@ -878,7 +883,7 @@
         if (!(rhs in this.members)) throw errStr + rhs + " is undefined.";
         if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface.";
 
-        if (this.members[rhs].members.length) {
+        if (this.members[rhs].members.length && self.shouldRunSubTest(testName)) {
             test(function () {
                 var clash = this.members[rhs].members.find(function(member) {
                     return this.members[lhs].members.find(function(m) {
@@ -892,7 +897,7 @@
                     this.members[lhs].members.push(new IdlInterfaceMember(member));
                 }.bind(this));
                 assert_true(!clash, "member " + (clash && clash.name) + " is unique");
-            }.bind(this), lhs + " includes " + rhs + ": member names are unique");
+            }.bind(this), testName);
         }
     }
     this.includes = [];
diff --git a/third_party/blink/web_tests/external/wpt/resources/testharness.js b/third_party/blink/web_tests/external/wpt/resources/testharness.js
index 6ccede34..32f033a 100644
--- a/third_party/blink/web_tests/external/wpt/resources/testharness.js
+++ b/third_party/blink/web_tests/external/wpt/resources/testharness.js
@@ -2321,7 +2321,6 @@
                 NetworkError: 19,
                 AbortError: 20,
                 URLMismatchError: 21,
-                QuotaExceededError: 22,
                 TimeoutError: 23,
                 InvalidNodeTypeError: 24,
                 DataCloneError: 25,
@@ -2336,7 +2335,8 @@
                 VersionError: 0,
                 OperationError: 0,
                 NotAllowedError: 0,
-                OptOutError: 0
+                OptOutError: 0,
+                QuotaExceededError: 0
             };
 
             var code_name_map = {};
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/crashtests/scroll-timeline-completion-crash.html b/third_party/blink/web_tests/external/wpt/scroll-animations/crashtests/scroll-timeline-completion-crash.html
new file mode 100644
index 0000000..fb7ecd1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/crashtests/scroll-timeline-completion-crash.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>This test passes if it does not crash</title>
+<link rel="help" src="https://drafts.csswg.org/scroll-animations-1/">
+<script src="/web-animations/testcommon.js"></script>
+
+<style>
+    @keyframes grow-progress {
+        from { background-color: green; }
+        to { background-color: red; }
+    }
+
+    #container {
+        overflow: scroll;
+        width: 100px;
+        height: 100px;
+        animation: grow-progress linear forwards;
+        animation-timeline: scroll(self);
+    }
+
+    #content {
+        width: 200px;
+        height: 200px;
+    }
+</style>
+<body onload="runTest()">
+<div id="container">
+    <div id="content"></div>
+</div>
+<script>
+
+async function runTest() {
+    const container = document.getElementById("container");
+    container.scrollTo(0, container.scrollHeight - container.clientHeight);
+    await waitForNextFrame();
+
+    const elem = document.getElementById("content");
+    elem.style.width = "0px";
+    elem.style.height = "0px";
+
+    await waitForNextFrame();
+  }
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-basics.https.html b/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-basics.https.html
index 8278440..91cf8e6 100644
--- a/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-basics.https.html
+++ b/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-basics.https.html
@@ -12,6 +12,6 @@
   assert_false(reco.interimResults, 'SpeechRecognition.interimResults');
   assert_equals(reco.maxAlternatives, 1, 'SpeechRecognition.maxAlternatives');
   assert_equals(reco.mode, 'ondevice-preferred', 'SpeechRecognition.mode');
-  assert_equals(reco.phrases, null, 'SpeechRecognition.phrases');
+  assert_equals(reco.phrases.length, 0, 'SpeechRecognition.phrases.length');
 });
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-recognitionContext-manual.https.html b/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-phrases-manual.https.html
similarity index 74%
rename from third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-recognitionContext-manual.https.html
rename to third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-phrases-manual.https.html
index 1039baa..2d0b19a 100644
--- a/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-recognitionContext-manual.https.html
+++ b/third_party/blink/web_tests/external/wpt/speech-api/SpeechRecognition-phrases-manual.https.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <html lang="en">
-<title>SpeechRecognition RecognitionContext</title>
+<title>SpeechRecognition Phrases</title>
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
@@ -29,42 +29,41 @@
         "Audio track should be a valid MediaStreamTrack"
     );
 
-    // Create the recognition context.
-    var list = new SpeechRecognitionPhraseList();
-    list.addItem(new SpeechRecognitionPhrase("ASIC", 1.0));
-    list.addItem(new SpeechRecognitionPhrase("FPGA", 1.0));
-    var context = new SpeechRecognitionContext(list);
-
-    // Create the first speech recognition with a mode that does not support
-    // recognition context. Note that this may vary between browsers in the future.
+    // Create the first speech recognition with a mode that does not support contextual biasing.
+    // Note that this may vary between browsers in the future.
     window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
     const recognition1 = new SpeechRecognition();
     recognition1.mode = "cloud-only";
     recognition1.lang = "en-US";
-    recognition1.context = context;
 
     recognition1.onerror = function(event) {
         assert_equals(
             event.error,
-            "recognition-context-not-supported",
-            "First speech recognition should throw a recognition-context-not-supported error"
+            "phrases-not-supported",
+            "First speech recognition should throw a phrases-not-supported error"
         );
     };
 
-    recognition1.start(audioTrack);
+    recognition1.phrases = new SpeechRecognitionPhraseList([
+        new SpeechRecognitionPhrase("test", 1.0)
+    ]);
 
-    // Create the second speech recognition with a mode that supports recognition context.
+    // Create the second speech recognition with a mode that supports contextual biasing.
     const recognition2 = new SpeechRecognition();
     recognition2.mode = "ondevice-only";
     recognition2.lang = "en-US";
-    recognition2.context = context;
 
     recognition2.onerror = function(event) {
         // Currently WPT may not be able to detect that SODA is available and
         // will throw a "language-not-supported" error here.
-        assert_unreached();
+        assert_unreached("Caught an error: " + event.error);
     };
 
+    recognition2.phrases = new SpeechRecognitionPhraseList([
+        new SpeechRecognitionPhrase("ASIC", 1.0),
+        new SpeechRecognitionPhrase("FPGA", 1.0)
+    ]);
+
     const recognitionPromise = new Promise((resolve) => {
         recognition2.onresult = (event) => {
             const transcript = event.results[0][0].transcript;
@@ -80,6 +79,6 @@
         "the fpga's latency were both below expectations",
         "Second speech recognition should correctly recognize the phrases"
     );
-}, "SpeechRecognition should recognize speech with the given recognition context.");
+}, "SpeechRecognition should recognize speech with the given contextual information.");
 </script>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js b/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js
index ee920277..49cd707 100644
--- a/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/storage/buckets/bucket-quota-indexeddb.tentative.https.any.js
@@ -34,8 +34,11 @@
     type: 'binary/random'
   }), 2);
 
-  await promise_rejects_dom(
-      t, 'QuotaExceededError', transactionPromise(txn));
+  try {
+    await transactionPromise(txn);
+  } catch (e) {
+    assert_equals(e.name, 'QuotaExceededError');
+  }
 
   db.close();
 }, 'IDB respects bucket quota');
diff --git a/third_party/blink/web_tests/external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-constructor-behavior.any.js b/third_party/blink/web_tests/external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-constructor-behavior.any.js
index c4ddabd..5bb6da7 100644
--- a/third_party/blink/web_tests/external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-constructor-behavior.any.js
+++ b/third_party/blink/web_tests/external/wpt/webidl/ecmascript-binding/es-exceptions/DOMException-constructor-behavior.any.js
@@ -107,7 +107,6 @@
   {name: "NetworkError", code: 19},
   {name: "AbortError", code: 20},
   {name: "URLMismatchError", code: 21},
-  {name: "QuotaExceededError", code: 22},
   {name: "TimeoutError", code: 23},
   {name: "InvalidNodeTypeError", code: 24},
   {name: "DataCloneError", code: 25},
@@ -128,7 +127,9 @@
   {name: "ReadOnlyError", code: 0},
   {name: "VersionError", code: 0},
   {name: "OperationError", code: 0},
-  {name: "NotAllowedError", code: 0}
+  {name: "NotAllowedError", code: 0},
+  // See https://github.com/whatwg/webidl/pull/1465.
+  {name: "QuotaExceededError", code: 0}
 ].forEach(function(test_case) {
   test(function() {
     var ex = new DOMException("msg", test_case.name);
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js
index 80a53ed..9369fce 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js
@@ -1471,6 +1471,132 @@
       }
     }
   },
+  {
+    'name': 'quantized split',
+    'graph': {
+      'inputs': {
+        'input': {
+          'data': [
+            1.6811466217041016, 0.0479511022567749, 0.33355462551116943,
+            -0.1988269537687301, -0.0041167140007019, -0.0634240251779556,
+          ],
+          'descriptor': {shape: [2, 3], dataType: 'float32'},
+          'constant': false
+        },
+        'inputScale': {
+          'data': [0.003921568859368563],
+          'descriptor': {shape: [1], dataType: 'float32'},
+          'constant': true
+        },
+        'inputZeroPoint': {
+          'data': [16],
+          'descriptor': {shape: [1], dataType: 'int8'},
+          'constant': true
+        },
+        'outputScale': {
+          'data': [0.003921568859368563],
+          'descriptor': {shape: [1], dataType: 'float32'},
+          'constant': true
+        },
+        'outputZeroPoint': {
+          'data': [16],
+          'descriptor': {shape: [1], dataType: 'int8'},
+          'constant': true
+        },
+      },
+      'operators': [
+        {
+          'name': 'quantizeLinear',
+          'arguments': [
+            {'input': 'input'},
+            {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'}
+          ],
+          'outputs': 'quantizedInput'
+        },
+        {
+          'name': 'dequantizeLinear',
+          'arguments': [
+            {'input': 'quantizedInput'},
+            {'scale': 'inputScale', 'zeroPoint': 'inputZeroPoint'}
+          ],
+          'outputs': 'dequantizedInput'
+        },
+        {
+          'name': 'split',
+          'arguments': [{'input': 'dequantizedInput'}, {'splits': 3}, {'options': {'axis': 1}}],
+          'outputs': ['splitOutput 1', 'splitOutput 2', 'splitOutput 3'],
+        },
+        {
+          'name': 'quantizeLinear',
+          'arguments': [
+            {'input': 'splitOutput 1'},
+            {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+          ],
+          'outputs': 'quantizedSplitOutput 1'
+        },
+        {
+          'name': 'dequantizeLinear',
+          'arguments': [
+            {'input': 'quantizedSplitOutput 1'},
+            {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+          ],
+          'outputs': 'output 1'
+        },
+        {
+          'name': 'quantizeLinear',
+          'arguments': [
+            {'input': 'splitOutput 2'},
+            {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+          ],
+          'outputs': 'quantizedSplitOutput 2'
+        },
+        {
+          'name': 'dequantizeLinear',
+          'arguments': [
+            {'input': 'quantizedSplitOutput 2'},
+            {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+          ],
+          'outputs': 'output 2'
+        },
+                {
+          'name': 'quantizeLinear',
+          'arguments': [
+            {'input': 'splitOutput 3'},
+            {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+          ],
+          'outputs': 'quantizedSplitOutput 3'
+        },
+        {
+          'name': 'dequantizeLinear',
+          'arguments': [
+            {'input': 'quantizedSplitOutput 3'},
+            {'scale': 'outputScale', 'zeroPoint': 'outputZeroPoint'}
+          ],
+          'outputs': 'output 3'
+        }
+      ],
+      'expectedOutputs': {
+        'output 1': {
+          'data': [
+            0.43529415130615234, -0.20000001788139343,
+          ],
+          'descriptor': {shape: [2, 1], dataType: 'float32'}
+        },
+        'output 2': {
+          'data': [
+            0.0470588281750679, -0.003921568859368563,
+          ],
+          'descriptor': {shape: [2, 1], dataType: 'float32'}
+        },
+        'output 3': {
+          'data': [
+            0.3333333432674408, -0.062745101749897,
+          ],
+          'descriptor': {shape: [2, 1], dataType: 'float32'}
+        }
+      }
+    }
+  },
 ];
 
 if (navigator.ml) {
diff --git a/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js b/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
index 9d5cfc7..c562b30 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/resources/utils.js
@@ -143,8 +143,8 @@
 const assertDescriptorsEquals = (outputOperand, expected) => {
   const dataType =
       expected.castedType ? expected.castedType : expected.dataType;
-  assert_true(
-      outputOperand.dataType === dataType,
+  assert_equals(
+      outputOperand.dataType, dataType,
       'actual output dataType should be equal to expected output dataType');
   assert_array_equals(
       outputOperand.shape, expected.shape,
@@ -282,7 +282,7 @@
  * @param {Array} actual - Array of test values.
  * @param {Array} expected - Array of values expected to be close to the values
  *     in ``actual``.
- * @param {Number} nulp - A BigInt value indicates acceptable ULP distance.
+ * @param {(Number|BigInt)} nulp - A value indicates acceptable ULP distance.
  * @param {String} dataType - A data type string, value: "float32",
  *     more types, please see:
  *     https://www.w3.org/TR/webnn/#enumdef-mloperanddatatype
@@ -292,33 +292,25 @@
   /*
     * Test if two primitive arrays are equal within acceptable ULP distance
     */
-  assert(
-      typeof nulp === 'number', `unexpected type for nulp: ${typeof nulp}`);
-  assert_true(
-      actual.length === expected.length,
-      `assert_array_approx_equals_ulp: ${description} lengths differ, ` +
-          `expected ${expected.length} but got ${actual.length}`);
-  let distance;
+  assert_equals(
+      actual.length, expected.length,
+      `assert_array_approx_equals_ulp: ${description} lengths differ`);
   for (let i = 0; i < actual.length; i++) {
     if (actual[i] === expected[i]) {
       continue;
     } else {
-      distance = ulpDistance(actual[i], expected[i], dataType);
+      let distance = ulpDistance(actual[i], expected[i], dataType);
 
-      // if true, invoke assert_true() in failure case
-      // if false, it's expected, not invoke assert_true() in success case to
-      // prevent spammy output
-      if (distance > nulp) {
-        assert_true(
-            false,
+      // TODO: See if callers can be updated to pass matching type.
+      nulp = typeof distance === 'bigint' ? BigInt(nulp) : Number(nulp);
+
+      assert_less_than_equal(distance, nulp,
             `assert_array_approx_equals_ulp: ${description} actual ` +
                 `${
                     dataType === 'float16' ?
                         float16AsUint16ToNumber(actual[i]) :
                         actual[i]} should be close enough to expected ` +
-                `${expected[i]} by the acceptable ${nulp} ULP distance, ` +
-                `but they have ${distance} ULP distance`);
-      }
+                `${expected[i]} by ULP distance:`);
     }
   }
 };
diff --git a/third_party/blink/web_tests/external/wpt/webnn/resources/utils_validation.js b/third_party/blink/web_tests/external/wpt/webnn/resources/utils_validation.js
index 77a6d79..3f8687b 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/resources/utils_validation.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/resources/utils_validation.js
@@ -205,7 +205,7 @@
 function assert_throws_with_label(func, regrexp) {
   try {
     func.call(this);
-    assert_true(false, 'Graph builder method unexpectedly succeeded');
+    assert_unreached('Graph builder method unexpectedly succeeded');
   } catch (e) {
     assert_equals(e.name, 'TypeError');
     const error_message = e.message;
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window.js
index 2c6ef19ca..d3eea3bc 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window.js
@@ -1,3 +1,6 @@
+// META: variant=?exclude=SFrameTransform.*
+// META: variant=?include=SFrameTransform.*
+// META: script=/common/subset-tests-by-key.js
 // META: script=/resources/WebIDLParser.js
 // META: script=/resources/idlharness.js
 // META: script=./RTCPeerConnection-helper.js
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window_exclude=SFrameTransform._-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window_exclude=SFrameTransform._-expected.txt
new file mode 100644
index 0000000..5bd2fe4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window_exclude=SFrameTransform._-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+[FAIL] RTCRtpSender interface: operation generateKeyFrame(optional sequence<DOMString>)
+  assert_own_property: interface prototype object missing non-static operation expected property "generateKeyFrame" missing
+[FAIL] RTCRtpSender interface: new RTCPeerConnection().addTransceiver('audio').sender must inherit property "generateKeyFrame(optional sequence<DOMString>)" with the proper type
+  assert_inherits: property "generateKeyFrame" not found in prototype chain
+[FAIL] RTCRtpSender interface: calling generateKeyFrame(optional sequence<DOMString>) on new RTCPeerConnection().addTransceiver('audio').sender with too few arguments must throw TypeError
+  assert_inherits: property "generateKeyFrame" not found in prototype chain
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window_include=SFrameTransform._-expected.txt
similarity index 82%
rename from third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window-expected.txt
rename to third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window_include=SFrameTransform._-expected.txt
index 655d491..e0e394e2 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc-encoded-transform/idlharness.https.window_include=SFrameTransform._-expected.txt
@@ -1,5 +1,4 @@
 This is a testharness.js-based test.
-Found 20 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] SFrameTransform interface: existence and properties of interface object
   assert_own_property: self does not have own property "SFrameTransform" expected property "SFrameTransform" missing
 [FAIL] SFrameTransform interface object length
@@ -34,11 +33,5 @@
   assert_own_property: self does not have own property "SFrameTransformErrorEvent" expected property "SFrameTransformErrorEvent" missing
 [FAIL] SFrameTransformErrorEvent interface: attribute frame
   assert_own_property: self does not have own property "SFrameTransformErrorEvent" expected property "SFrameTransformErrorEvent" missing
-[FAIL] RTCRtpSender interface: operation generateKeyFrame(optional sequence<DOMString>)
-  assert_own_property: interface prototype object missing non-static operation expected property "generateKeyFrame" missing
-[FAIL] RTCRtpSender interface: new RTCPeerConnection().addTransceiver('audio').sender must inherit property "generateKeyFrame(optional sequence<DOMString>)" with the proper type
-  assert_inherits: property "generateKeyFrame" not found in prototype chain
-[FAIL] RTCRtpSender interface: calling generateKeyFrame(optional sequence<DOMString>) on new RTCPeerConnection().addTransceiver('audio').sender with too few arguments must throw TypeError
-  assert_inherits: property "generateKeyFrame" not found in prototype chain
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/fast/dom/DOMException/constructor.html b/third_party/blink/web_tests/fast/dom/DOMException/constructor.html
index 19c6501..2f4986a7 100644
--- a/third_party/blink/web_tests/fast/dom/DOMException/constructor.html
+++ b/third_party/blink/web_tests/fast/dom/DOMException/constructor.html
@@ -75,7 +75,6 @@
     {name: "NetworkError", code: 19},
     {name: "AbortError", code: 20},
     {name: "URLMismatchError", code: 21},
-    {name: "QuotaExceededError", code: 22},
     {name: "TimeoutError", code: 23},
     {name: "InvalidNodeTypeError", code: 24},
     {name: "DataCloneError", code: 25}
diff --git a/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload-expected.txt b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload-expected.txt
new file mode 100644
index 0000000..3ad8c48
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-navigation-reload-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Reloading iframe loading='lazy' before it is loaded: location.reload
+  Uncaught Error: assert_equals: expected "http://web-platform.test:8001/html/semantics/embedded-content/the-iframe-element/support/blank.htm?src" but got "about:blank"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-skia-graphite/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reciprocal.https.any_cpu-expected.txt b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reciprocal.https.any_cpu-expected.txt
new file mode 100644
index 0000000..6df8957
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reciprocal.https.any_cpu-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+[FAIL] reciprocal float16 1D tensor
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by ULP distance: expected a number less than or equal to 2n but got 3n
+[FAIL] reciprocal float16 2D tensor
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by ULP distance: expected a number less than or equal to 2n but got 3n
+[FAIL] reciprocal float16 3D tensor
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by ULP distance: expected a number less than or equal to 2n but got 3n
+[FAIL] reciprocal float16 4D tensor
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by ULP distance: expected a number less than or equal to 2n but got 3n
+[FAIL] reciprocal float16 5D tensor
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by ULP distance: expected a number less than or equal to 2n but got 3n
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-skia-graphite/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/neg.https.any_npu-expected.txt b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/neg.https.any_npu-expected.txt
new file mode 100644
index 0000000..cca069b2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/neg.https.any_npu-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+[FAIL] neg int8 4D tensor
+  promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type int8 must be one of [float32,float16,int32]."
+[FAIL] neg int32 4D tensor
+  assert_less_than_equal: assert_array_approx_equals_ulp: test neg int32 actual -2147483648 should be close enough to expected -2147483646 by ULP distance: expected a number less than or equal to 0n but got 2n
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 994d24d2..88a1538 100644
--- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -1668,6 +1668,11 @@
     getter applicationServerKey
     getter userVisibleOnly
     method constructor
+interface QuotaExceededError : DOMException
+    attribute @@toStringTag
+    getter quota
+    getter requested
+    method constructor
 interface RTCRtpAcks
     attribute @@toStringTag
     getter explicitCongestionNotification
diff --git a/third_party/blink/web_tests/http/tests/shadowrealm/webexposed/global-interface-listing-shadow-realm-expected.txt b/third_party/blink/web_tests/http/tests/shadowrealm/webexposed/global-interface-listing-shadow-realm-expected.txt
index 9a2a85e2..16cddb1 100644
--- a/third_party/blink/web_tests/http/tests/shadowrealm/webexposed/global-interface-listing-shadow-realm-expected.txt
+++ b/third_party/blink/web_tests/http/tests/shadowrealm/webexposed/global-interface-listing-shadow-realm-expected.txt
@@ -163,6 +163,11 @@
 CONSOLE MESSAGE:     getter promise
 CONSOLE MESSAGE:     getter reason
 CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface QuotaExceededError : DOMException
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter quota
+CONSOLE MESSAGE:     getter requested
+CONSOLE MESSAGE:     method constructor
 CONSOLE MESSAGE: interface ReadableByteStreamController
 CONSOLE MESSAGE:     attribute @@toStringTag
 CONSOLE MESSAGE:     getter byobRequest
diff --git a/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-audio-worklet-expected.txt b/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-audio-worklet-expected.txt
index d5b6acb..85fc3a0 100644
--- a/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-audio-worklet-expected.txt
+++ b/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-audio-worklet-expected.txt
@@ -95,6 +95,11 @@
 CONSOLE MESSAGE:     setter onclose
 CONSOLE MESSAGE:     setter onmessage
 CONSOLE MESSAGE:     setter onmessageerror
+CONSOLE MESSAGE: interface QuotaExceededError : DOMException
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter quota
+CONSOLE MESSAGE:     getter requested
+CONSOLE MESSAGE:     method constructor
 CONSOLE MESSAGE: interface ReadableByteStreamController
 CONSOLE MESSAGE:     attribute @@toStringTag
 CONSOLE MESSAGE:     getter byobRequest
diff --git a/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-layout-worklet-expected.txt b/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-layout-worklet-expected.txt
index e8af938..f4db7a8 100644
--- a/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-layout-worklet-expected.txt
+++ b/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-layout-worklet-expected.txt
@@ -282,6 +282,11 @@
 CONSOLE MESSAGE: interface LayoutWorkletGlobalScope : WorkletGlobalScope
 CONSOLE MESSAGE:     attribute @@toStringTag
 CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface QuotaExceededError : DOMException
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter quota
+CONSOLE MESSAGE:     getter requested
+CONSOLE MESSAGE:     method constructor
 CONSOLE MESSAGE: interface ReadableByteStreamController
 CONSOLE MESSAGE:     attribute @@toStringTag
 CONSOLE MESSAGE:     getter byobRequest
@@ -695,6 +700,11 @@
 CONSOLE MESSAGE: interface LayoutWorkletGlobalScope : WorkletGlobalScope
 CONSOLE MESSAGE:     attribute @@toStringTag
 CONSOLE MESSAGE:     method constructor
+CONSOLE MESSAGE: interface QuotaExceededError : DOMException
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter quota
+CONSOLE MESSAGE:     getter requested
+CONSOLE MESSAGE:     method constructor
 CONSOLE MESSAGE: interface ReadableByteStreamController
 CONSOLE MESSAGE:     attribute @@toStringTag
 CONSOLE MESSAGE:     getter byobRequest
diff --git a/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt b/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
index 0b18e9ec..b68dc268 100644
--- a/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
+++ b/third_party/blink/web_tests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
@@ -353,6 +353,11 @@
 CONSOLE MESSAGE:     method quadraticCurveTo
 CONSOLE MESSAGE:     method rect
 CONSOLE MESSAGE:     method roundRect
+CONSOLE MESSAGE: interface QuotaExceededError : DOMException
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter quota
+CONSOLE MESSAGE:     getter requested
+CONSOLE MESSAGE:     method constructor
 CONSOLE MESSAGE: interface ReadableByteStreamController
 CONSOLE MESSAGE:     attribute @@toStringTag
 CONSOLE MESSAGE:     getter byobRequest
@@ -838,6 +843,11 @@
 CONSOLE MESSAGE:     method quadraticCurveTo
 CONSOLE MESSAGE:     method rect
 CONSOLE MESSAGE:     method roundRect
+CONSOLE MESSAGE: interface QuotaExceededError : DOMException
+CONSOLE MESSAGE:     attribute @@toStringTag
+CONSOLE MESSAGE:     getter quota
+CONSOLE MESSAGE:     getter requested
+CONSOLE MESSAGE:     method constructor
 CONSOLE MESSAGE: interface ReadableByteStreamController
 CONSOLE MESSAGE:     attribute @@toStringTag
 CONSOLE MESSAGE:     getter byobRequest
diff --git a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reciprocal.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reciprocal.https.any_cpu-expected.txt
index 7e2f6a7..221eeec 100644
--- a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reciprocal.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reciprocal.https.any_cpu-expected.txt
@@ -1,13 +1,13 @@
 This is a testharness.js-based test.
 [FAIL] reciprocal float16 1D tensor
-  assert_true: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by the acceptable 2 ULP distance, but they have 3 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by ULP distance: expected a number less than or equal to 2 but got 3
 [FAIL] reciprocal float16 2D tensor
-  assert_true: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by the acceptable 2 ULP distance, but they have 3 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by ULP distance: expected a number less than or equal to 2 but got 3
 [FAIL] reciprocal float16 3D tensor
-  assert_true: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by the acceptable 2 ULP distance, but they have 3 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by ULP distance: expected a number less than or equal to 2 but got 3
 [FAIL] reciprocal float16 4D tensor
-  assert_true: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by the acceptable 2 ULP distance, but they have 3 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by ULP distance: expected a number less than or equal to 2 but got 3
 [FAIL] reciprocal float16 5D tensor
-  assert_true: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by the acceptable 2 ULP distance, but they have 3 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reciprocal float16 actual 0.216796875 should be close enough to expected 0.2164306640625 by ULP distance: expected a number less than or equal to 2 but got 3
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_npu-expected.txt
index 3e7bfde..1dc322e 100644
--- a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_npu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] convTranspose2d same output size different padding (padding=2, outputPadding=2))
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 1 should be close enough to expected 2 by the acceptable 18 ULP distance, but they have 8388608 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 1 should be close enough to expected 2 by ULP distance: expected a number less than or equal to 18n but got 8388608n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/neg.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/neg.https.any_npu-expected.txt
index 2b8e54db..02ae569c 100644
--- a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/neg.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/neg.https.any_npu-expected.txt
@@ -2,6 +2,6 @@
 [FAIL] neg int8 4D tensor
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type int8 must be one of [float32,float16,int32]."
 [FAIL] neg int32 4D tensor
-  assert_true: assert_array_approx_equals_ulp: test neg int32 actual -2147483648 should be close enough to expected -2147483646 by the acceptable 0 ULP distance, but they have 2 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test neg int32 actual -2147483648 should be close enough to expected -2147483646 by ULP distance: expected a number less than or equal to 0 but got 2
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_gpu-expected.txt
index 3e7bfde..1dc322e 100644
--- a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_gpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] convTranspose2d same output size different padding (padding=2, outputPadding=2))
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 1 should be close enough to expected 2 by the acceptable 18 ULP distance, but they have 8388608 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 1 should be close enough to expected 2 by ULP distance: expected a number less than or equal to 18n but got 8388608n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/neg.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/neg.https.any_gpu-expected.txt
index 2b8e54db..cca069b2 100644
--- a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/neg.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/neg.https.any_gpu-expected.txt
@@ -2,6 +2,6 @@
 [FAIL] neg int8 4D tensor
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type int8 must be one of [float32,float16,int32]."
 [FAIL] neg int32 4D tensor
-  assert_true: assert_array_approx_equals_ulp: test neg int32 actual -2147483648 should be close enough to expected -2147483646 by the acceptable 0 ULP distance, but they have 2 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test neg int32 actual -2147483648 should be close enough to expected -2147483646 by ULP distance: expected a number less than or equal to 0n but got 2n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/abs.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/abs.https.any_cpu-expected.txt
index cb5fabb..364ab1b 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/abs.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/abs.https.any_cpu-expected.txt
@@ -2,6 +2,6 @@
 [FAIL] abs int8 4D tensor
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type int8 must be one of [float32,float16,int32]."
 [FAIL] abs int32 4D tensor
-  assert_true: assert_array_approx_equals_ulp: test abs int32 actual 2147483647 should be close enough to expected 2147483646 by the acceptable 0 ULP distance, but they have 1 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test abs int32 actual 2147483647 should be close enough to expected 2147483646 by ULP distance: expected a number less than or equal to 0 but got 1
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gather.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gather.https.any_cpu-expected.txt
index a753779..28d4d598 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gather.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gather.https.any_cpu-expected.txt
@@ -4,6 +4,6 @@
 [FAIL] gather float32 1D tensor and int64 0D scalar indices default options
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, constant 'indices' data type int64 must be one of [float32,float16,int32,uint32,int8,uint8,int4,uint4]."
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound positive indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual -66.05901336669922 should be close enough to expected 90.2870101928711 by the acceptable 0 ULP distance, but they have 2235085098 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual -66.05901336669922 should be close enough to expected 90.2870101928711 by ULP distance: expected a number less than or equal to 0n but got 2235085098n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherElements.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherElements.https.any_cpu-expected.txt
index 1a387fc..c3c893f 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherElements.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherElements.https.any_cpu-expected.txt
@@ -2,8 +2,8 @@
 [FAIL] gatherElements float32 2D input and uint32 indices options.axis=1
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'indices' data type uint32 must be one of [int32]."
 [FAIL] gatherElements float32 3D input and int32 negative indices
-  assert_true: assert_array_approx_equals_ulp: test gatherElements float32 actual -66.05901336669922 should be close enough to expected 89.0337142944336 by the acceptable 0 ULP distance, but they have 2234920826 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherElements float32 actual -66.05901336669922 should be close enough to expected 89.0337142944336 by ULP distance: expected a number less than or equal to 0n but got 2234920826n
 [FAIL] gatherElements float32 1D input and int32 out-of-bounds indices
-  assert_true: assert_array_approx_equals_ulp: test gatherElements float32 actual -26.158037185668945 should be close enough to expected 51.79948425292969 by the acceptable 0 ULP distance, but they have 2216719957 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherElements float32 actual -26.158037185668945 should be close enough to expected 51.79948425292969 by ULP distance: expected a number less than or equal to 0n but got 2216719957n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherND.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherND.https.any_cpu-expected.txt
index 43ba1600..95341fc 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherND.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherND.https.any_cpu-expected.txt
@@ -4,10 +4,10 @@
 [FAIL] gatherND float32 4D input and 1D int64 indices
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, constant 'indices' data type int64 must be one of [float32,float16,int32,uint32,int8,uint8,int4,uint4]."
 [FAIL] gatherND float32 2D input and 2D negative indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 44.92119598388672 by the acceptable 0 ULP distance, but they have 2226638213 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 44.92119598388672 by ULP distance: expected a number less than or equal to 0n but got 2226638213n
 [FAIL] gatherND float32 1D input and 2D out-of-bounds indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by the acceptable 0 ULP distance, but they have 2229759677 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by ULP distance: expected a number less than or equal to 0n but got 2229759677n
 [FAIL] gatherND float32 2D input and 2D out-of-bounds indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by the acceptable 0 ULP distance, but they have 2229759677 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by ULP distance: expected a number less than or equal to 0n but got 2229759677n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
index 4f2fe75..0857e24 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by ULP distance: expected a number less than or equal to 3n but got 27754759n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_cpu-expected.txt
index bc3cdc4..0a0f2072 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_cpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] reduceL1 float32 1D constant tensor empty axes
-  assert_true: assert_array_approx_equals_ulp: test reduceL1 float32 actual -5.50882625579834 should be close enough to expected 5.50882625579834 by the acceptable 1 ULP distance, but they have 2170589340 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reduceL1 float32 actual -5.50882625579834 should be close enough to expected 5.50882625579834 by ULP distance: expected a number less than or equal to 1n but got 2170589340n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_cpu-expected.txt
index e4f6147..f308670 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_cpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] reduceL2 float32 1D constant tensor empty axes
-  assert_true: assert_array_approx_equals_ulp: test reduceL2 float32 actual -4.860228061676025 should be close enough to expected 4.860228061676025 by the acceptable 3 ULP distance, but they have 2167868922 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reduceL2 float32 actual -4.860228061676025 should be close enough to expected 4.860228061676025 by ULP distance: expected a number less than or equal to 3n but got 2167868922n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/abs.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/abs.https.any_npu-expected.txt
index cb5fabb..364ab1b 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/abs.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/abs.https.any_npu-expected.txt
@@ -2,6 +2,6 @@
 [FAIL] abs int8 4D tensor
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type int8 must be one of [float32,float16,int32]."
 [FAIL] abs int32 4D tensor
-  assert_true: assert_array_approx_equals_ulp: test abs int32 actual 2147483647 should be close enough to expected 2147483646 by the acceptable 0 ULP distance, but they have 1 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test abs int32 actual 2147483647 should be close enough to expected 2147483646 by ULP distance: expected a number less than or equal to 0 but got 1
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gather.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gather.https.any_npu-expected.txt
index a753779..28d4d598 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gather.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gather.https.any_npu-expected.txt
@@ -4,6 +4,6 @@
 [FAIL] gather float32 1D tensor and int64 0D scalar indices default options
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, constant 'indices' data type int64 must be one of [float32,float16,int32,uint32,int8,uint8,int4,uint4]."
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound positive indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual -66.05901336669922 should be close enough to expected 90.2870101928711 by the acceptable 0 ULP distance, but they have 2235085098 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual -66.05901336669922 should be close enough to expected 90.2870101928711 by ULP distance: expected a number less than or equal to 0n but got 2235085098n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherElements.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherElements.https.any_npu-expected.txt
index 1a387fc..c3c893f 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherElements.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherElements.https.any_npu-expected.txt
@@ -2,8 +2,8 @@
 [FAIL] gatherElements float32 2D input and uint32 indices options.axis=1
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'indices' data type uint32 must be one of [int32]."
 [FAIL] gatherElements float32 3D input and int32 negative indices
-  assert_true: assert_array_approx_equals_ulp: test gatherElements float32 actual -66.05901336669922 should be close enough to expected 89.0337142944336 by the acceptable 0 ULP distance, but they have 2234920826 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherElements float32 actual -66.05901336669922 should be close enough to expected 89.0337142944336 by ULP distance: expected a number less than or equal to 0n but got 2234920826n
 [FAIL] gatherElements float32 1D input and int32 out-of-bounds indices
-  assert_true: assert_array_approx_equals_ulp: test gatherElements float32 actual -26.158037185668945 should be close enough to expected 51.79948425292969 by the acceptable 0 ULP distance, but they have 2216719957 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherElements float32 actual -26.158037185668945 should be close enough to expected 51.79948425292969 by ULP distance: expected a number less than or equal to 0n but got 2216719957n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherND.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherND.https.any_npu-expected.txt
index 43ba1600..95341fc 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherND.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherND.https.any_npu-expected.txt
@@ -4,10 +4,10 @@
 [FAIL] gatherND float32 4D input and 1D int64 indices
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, constant 'indices' data type int64 must be one of [float32,float16,int32,uint32,int8,uint8,int4,uint4]."
 [FAIL] gatherND float32 2D input and 2D negative indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 44.92119598388672 by the acceptable 0 ULP distance, but they have 2226638213 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 44.92119598388672 by ULP distance: expected a number less than or equal to 0n but got 2226638213n
 [FAIL] gatherND float32 1D input and 2D out-of-bounds indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by the acceptable 0 ULP distance, but they have 2229759677 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by ULP distance: expected a number less than or equal to 0n but got 2229759677n
 [FAIL] gatherND float32 2D input and 2D out-of-bounds indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by the acceptable 0 ULP distance, but they have 2229759677 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by ULP distance: expected a number less than or equal to 0n but got 2229759677n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt
index 4f2fe75..0857e24 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by ULP distance: expected a number less than or equal to 3n but got 27754759n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_npu-expected.txt
index bc3cdc4..0a0f2072 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_npu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] reduceL1 float32 1D constant tensor empty axes
-  assert_true: assert_array_approx_equals_ulp: test reduceL1 float32 actual -5.50882625579834 should be close enough to expected 5.50882625579834 by the acceptable 1 ULP distance, but they have 2170589340 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reduceL1 float32 actual -5.50882625579834 should be close enough to expected 5.50882625579834 by ULP distance: expected a number less than or equal to 1n but got 2170589340n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_npu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_npu-expected.txt
index e4f6147..f308670 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_npu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] reduceL2 float32 1D constant tensor empty axes
-  assert_true: assert_array_approx_equals_ulp: test reduceL2 float32 actual -4.860228061676025 should be close enough to expected 4.860228061676025 by the acceptable 3 ULP distance, but they have 2167868922 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reduceL2 float32 actual -4.860228061676025 should be close enough to expected 4.860228061676025 by ULP distance: expected a number less than or equal to 3n but got 2167868922n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/abs.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/abs.https.any_gpu-expected.txt
index cb5fabb..364ab1b 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/abs.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/abs.https.any_gpu-expected.txt
@@ -2,6 +2,6 @@
 [FAIL] abs int8 4D tensor
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type int8 must be one of [float32,float16,int32]."
 [FAIL] abs int32 4D tensor
-  assert_true: assert_array_approx_equals_ulp: test abs int32 actual 2147483647 should be close enough to expected 2147483646 by the acceptable 0 ULP distance, but they have 1 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test abs int32 actual 2147483647 should be close enough to expected 2147483646 by ULP distance: expected a number less than or equal to 0 but got 1
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt
index a753779..28d4d598 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt
@@ -4,6 +4,6 @@
 [FAIL] gather float32 1D tensor and int64 0D scalar indices default options
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, constant 'indices' data type int64 must be one of [float32,float16,int32,uint32,int8,uint8,int4,uint4]."
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound positive indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual -66.05901336669922 should be close enough to expected 90.2870101928711 by the acceptable 0 ULP distance, but they have 2235085098 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual -66.05901336669922 should be close enough to expected 90.2870101928711 by ULP distance: expected a number less than or equal to 0n but got 2235085098n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherElements.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherElements.https.any_gpu-expected.txt
index 1a387fc..c3c893f 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherElements.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherElements.https.any_gpu-expected.txt
@@ -2,8 +2,8 @@
 [FAIL] gatherElements float32 2D input and uint32 indices options.axis=1
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'indices' data type uint32 must be one of [int32]."
 [FAIL] gatherElements float32 3D input and int32 negative indices
-  assert_true: assert_array_approx_equals_ulp: test gatherElements float32 actual -66.05901336669922 should be close enough to expected 89.0337142944336 by the acceptable 0 ULP distance, but they have 2234920826 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherElements float32 actual -66.05901336669922 should be close enough to expected 89.0337142944336 by ULP distance: expected a number less than or equal to 0n but got 2234920826n
 [FAIL] gatherElements float32 1D input and int32 out-of-bounds indices
-  assert_true: assert_array_approx_equals_ulp: test gatherElements float32 actual -26.158037185668945 should be close enough to expected 51.79948425292969 by the acceptable 0 ULP distance, but they have 2216719957 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherElements float32 actual -26.158037185668945 should be close enough to expected 51.79948425292969 by ULP distance: expected a number less than or equal to 0n but got 2216719957n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherND.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherND.https.any_gpu-expected.txt
index 43ba1600..95341fc 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherND.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherND.https.any_gpu-expected.txt
@@ -4,10 +4,10 @@
 [FAIL] gatherND float32 4D input and 1D int64 indices
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, constant 'indices' data type int64 must be one of [float32,float16,int32,uint32,int8,uint8,int4,uint4]."
 [FAIL] gatherND float32 2D input and 2D negative indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 44.92119598388672 by the acceptable 0 ULP distance, but they have 2226638213 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 44.92119598388672 by ULP distance: expected a number less than or equal to 0n but got 2226638213n
 [FAIL] gatherND float32 1D input and 2D out-of-bounds indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by the acceptable 0 ULP distance, but they have 2229759677 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by ULP distance: expected a number less than or equal to 0n but got 2229759677n
 [FAIL] gatherND float32 2D input and 2D out-of-bounds indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by the acceptable 0 ULP distance, but they have 2229759677 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual -66.05901336669922 should be close enough to expected 56.828636169433594 by ULP distance: expected a number less than or equal to 0n but got 2229759677n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt
index 4f2fe75..0857e24 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by ULP distance: expected a number less than or equal to 3n but got 27754759n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_gpu-expected.txt
index bc3cdc4..0a0f2072 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l1.https.any_gpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] reduceL1 float32 1D constant tensor empty axes
-  assert_true: assert_array_approx_equals_ulp: test reduceL1 float32 actual -5.50882625579834 should be close enough to expected 5.50882625579834 by the acceptable 1 ULP distance, but they have 2170589340 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reduceL1 float32 actual -5.50882625579834 should be close enough to expected 5.50882625579834 by ULP distance: expected a number less than or equal to 1n but got 2170589340n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_gpu-expected.txt
index e4f6147..f308670 100644
--- a/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac15-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/reduce_l2.https.any_gpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] reduceL2 float32 1D constant tensor empty axes
-  assert_true: assert_array_approx_equals_ulp: test reduceL2 float32 actual -4.860228061676025 should be close enough to expected 4.860228061676025 by the acceptable 3 ULP distance, but they have 2167868922 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test reduceL2 float32 actual -4.860228061676025 should be close enough to expected 4.860228061676025 by ULP distance: expected a number less than or equal to 3n but got 2167868922n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/README.md b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/README.md
index e78086e..b3e8af05 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/README.md
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/README.md
@@ -1,6 +1,6 @@
 Currently on the mac x86 macmini bots(mac_rel, mac*-blink-rel), some of the tests have floating point precision issue and are failing with error message like:
 ```
-actual 47.25 should be close enough to expected 47.26926803588867 by the acceptable 27 ULP distance, but they have 5051 ULP distance expected true got false
+actual 47.25 should be close enough to expected 47.26926803588867 by ULP distance: expected a number less than or equal to 27n but got 5051n
 ```
 
-This is not reproducible on intel macbooks. It's suspected to be an intel driver bug or a coreml bug on the particular hardware. Since it's only lossing some precision on a particular macmini configuration, we decide to leave the behavior as is. See more detail in crbug.com/331631226.
\ No newline at end of file
+This is not reproducible on intel macbooks. It's suspected to be an intel driver bug or a coreml bug on the particular hardware. Since it's only lossing some precision on a particular macmini configuration, we decide to leave the behavior as is. See more detail in crbug.com/331631226.
diff --git a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_gpu-expected.txt
index 73e3a66..9c1a7c9d 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_gpu-expected.txt
@@ -4,15 +4,15 @@
 [FAIL] convTranspose2d float32 4D input and filter tensors options.groups=2 options.strides=[2, 2]
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': convTranspose2d doesn't support dilations and groups."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.padding
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 0.2787136137485504 by the acceptable 8 ULP distance, but they have 1049539469 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 0.2787136137485504 by ULP distance: expected a number less than or equal to 8n but got 1049539469n
 [FAIL] convTranspose2d float32 4D input and filter tensors options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': convTranspose2d doesn't support dilations and groups."
 [FAIL] convTranspose2d same output size different padding (padding=1, outputPadding=0))
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by the acceptable 18 ULP distance, but they have 1065353216 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by ULP distance: expected a number less than or equal to 18n but got 1065353216n
 [FAIL] convTranspose2d same output size different padding (padding=2, outputPadding=2))
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by the acceptable 18 ULP distance, but they have 1065353216 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by ULP distance: expected a number less than or equal to 18n but got 1065353216n
 [FAIL] convTranspose2d float16 4D input and filter tensors options.padding
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float16 actual 0 should be close enough to expected 0.27880859375 by the acceptable 8 ULP distance, but they have 13430 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float16 actual 0 should be close enough to expected 0.27880859375 by ULP distance: expected a number less than or equal to 8 but got 13430
 [FAIL] convTranspose2d float16 4D input and filter tensors options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': convTranspose2d doesn't support dilations and groups."
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt
index f90e7b98..cc19ef40 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 [FAIL] gather float32 2D tensor and int32 0D negative indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by the acceptable 0 ULP distance, but they have 1115954743 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by ULP distance: expected a number less than or equal to 0n but got 1115954743n
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound positive indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected 90.2870101928711 by the acceptable 0 ULP distance, but they have 1119130355 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected 90.2870101928711 by ULP distance: expected a number less than or equal to 0n but got 1119130355n
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound negative indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by the acceptable 0 ULP distance, but they have 1115954743 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by ULP distance: expected a number less than or equal to 0n but got 1115954743n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherND.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherND.https.any_gpu-expected.txt
index 7b6da10..0a12d07e 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherND.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gatherND.https.any_gpu-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 [FAIL] gatherND float32 4D input and 1D minimum indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual 0 should be close enough to expected -66.05901336669922 by the acceptable 0 ULP distance, but they have 1115954743 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual 0 should be close enough to expected -66.05901336669922 by ULP distance: expected a number less than or equal to 0n but got 1115954743n
 [FAIL] gatherND float32 2D input and 2D negative indices
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': TFLite doesn't support to gather input into one dimension."
 [FAIL] gatherND float32 1D input and 2D out-of-bounds indices
diff --git a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gru.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gru.https.any_gpu-expected.txt
index cb2b3a1..70254f1 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gru.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gru.https.any_gpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 [FAIL] gru float32 tensors steps=2 with options.bias, options.recurrentBias, options.direction='backward', options.activations=['relu', 'relu'] and options.returnSequence=true
-  assert_true: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by the acceptable 6 ULP distance, but they have 16778 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by ULP distance: expected a number less than or equal to 6n but got 16778n
 [FAIL] gru float32 tensors steps=2 with options.bias, options.recurrentBias, options.direction='both' and options.returnSequence=true
-  assert_true: assert_array_approx_equals_ulp: test gru float32 actual -0.375 should be close enough to expected -0.28068751096725464 by the acceptable 6 ULP distance, but they have 3164602 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gru float32 actual -0.375 should be close enough to expected -0.28068751096725464 by ULP distance: expected a number less than or equal to 6n but got 3164602n
 [FAIL] gru float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by the acceptable 6 ULP distance, but they have 16778 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by ULP distance: expected a number less than or equal to 6n but got 16778n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt
index e53dd3b2..1cd8dc3 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/lstm.https.any_gpu-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by ULP distance: expected a number less than or equal to 3n but got 27754759n
 [FAIL] lstm float32 tensors steps=2 with bidirections
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063756942749 should be close enough to expected 0.5764073133468628 by the acceptable 3 ULP distance, but they have 5657186 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063756942749 should be close enough to expected 0.5764073133468628 by ULP distance: expected a number less than or equal to 3n but got 5657186n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/pooling.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/pooling.https.any_gpu-expected.txt
index 727d407..7d6c7d69 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/pooling.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/pooling.https.any_gpu-expected.txt
@@ -1,24 +1,24 @@
 This is a testharness.js-based test.
 [FAIL] averagePool2d float32 4D tensor options.padding
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 41.9493293762207 should be close enough to expected 52.43666076660156 by the acceptable 27 ULP distance, but they have 2749191 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 41.9493293762207 should be close enough to expected 52.43666076660156 by ULP distance: expected a number less than or equal to 27n but got 2749191n
 [FAIL] averagePool2d float32 4D tensor options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Pool2d in tflite doesn't support dilations."
 [FAIL] averagePool2d float32 4D tensor options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.roundingType=ceil and no padding
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 50.63130569458008 should be close enough to expected 40.29140853881836 by the acceptable 11 ULP distance, but they have 2710542 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 50.63130569458008 should be close enough to expected 40.29140853881836 by ULP distance: expected a number less than or equal to 11n but got 2710542n
 [FAIL] averagePool2d float32 4D tensor options.layout=nhwc and options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.layout=nhwc and options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.outputSizes ignores options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.outputSizes ignores options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.dilations with options.strides
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 28.626827239990234 should be close enough to expected 42.940242767333984 by the acceptable 11 ULP distance, but they have 4636433 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 28.626827239990234 should be close enough to expected 42.940242767333984 by ULP distance: expected a number less than or equal to 11n but got 4636433n
 [FAIL] l2Pool2d float32 4D constant tensor all positive default options
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type float32 must be one of []."
 [FAIL] l2Pool2d float32 4D tensor default all positive options
@@ -50,8 +50,8 @@
 [FAIL] maxPool2d float32 4D tensor options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Pool2d in tflite doesn't support dilations."
 [FAIL] maxPool2d float32 4D tensor options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by the acceptable 0 ULP distance, but they have 2229449938 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by ULP distance: expected a number less than or equal to 0n but got 2229449938n
 [FAIL] maxPool2d float32 4D tensor options.outputSizes ignores options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by the acceptable 0 ULP distance, but they have 2229449938 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by ULP distance: expected a number less than or equal to 0n but got 2229449938n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/batch_normalization.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/batch_normalization.https.any_gpu-expected.txt
index 5269be09..13cf7ab 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/batch_normalization.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/batch_normalization.https.any_gpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] batchNormalization float16 4D NHWC tensor all options
-  assert_true: assert_array_approx_equals_ulp: test batchNormalization float16 actual 199.5 should be close enough to expected 200.375 by the acceptable 6 ULP distance, but they have 7 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test batchNormalization float16 actual 199.5 should be close enough to expected 200.375 by ULP distance: expected a number less than or equal to 6 but got 7
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/cast.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/cast.https.any_gpu-expected.txt
index af82d3ea..7a8f382 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/cast.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/cast.https.any_gpu-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] cast float16 4D tensor to int64
-  assert_true: assert_array_approx_equals_ulp: test cast int64 actual 137438953475 should be close enough to expected 3 by the acceptable 0 ULP distance, but they have 137438953472 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test cast int64 actual 137438953475 should be close enough to expected 3 by ULP distance: expected a number less than or equal to 0n but got 137438953472n
 [FAIL] cast int64 4D tensor to float16
-  assert_true: assert_array_approx_equals_ulp: test cast float16 actual 0 should be close enough to expected 1 by the acceptable 1 ULP distance, but they have 15360 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test cast float16 actual 0 should be close enough to expected 1 by ULP distance: expected a number less than or equal to 1 but got 15360
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/clamp.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/clamp.https.any_gpu-expected.txt
index 2a3d0f7..aaddfe5 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/clamp.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/clamp.https.any_gpu-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 [FAIL] clamp int32 1D tensor
-  assert_true: assert_array_approx_equals_ulp: test clamp int32 actual 2147483647 should be close enough to expected 2147483645 by the acceptable 0 ULP distance, but they have 2 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test clamp int32 actual 2147483647 should be close enough to expected 2147483645 by ULP distance: expected a number less than or equal to 0 but got 2
 [FAIL] clamp uint32 1D tensor
-  assert_true: assert_array_approx_equals_ulp: test clamp uint32 actual 4294967295 should be close enough to expected 4294967290 by the acceptable 0 ULP distance, but they have 5 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test clamp uint32 actual 4294967295 should be close enough to expected 4294967290 by ULP distance: expected a number less than or equal to 0 but got 5
 [FAIL] clamp int64 1D tensor
-  assert_true: assert_array_approx_equals_ulp: test clamp int64 actual -4147483648 should be close enough to expected -2 by the acceptable 0 ULP distance, but they have 4147483646 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test clamp int64 actual -4147483648 should be close enough to expected -2 by ULP distance: expected a number less than or equal to 0n but got 4147483646n
 [FAIL] clamp uint64 1D tensor
-  assert_true: assert_array_approx_equals_ulp: test clamp uint64 actual 5294967295 should be close enough to expected 5294967290 by the acceptable 0 ULP distance, but they have 5 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test clamp uint64 actual 5294967295 should be close enough to expected 5294967290 by ULP distance: expected a number less than or equal to 0n but got 5n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv2d.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv2d.https.any_gpu-expected.txt
index 9693870..8fd2230 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv2d.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/conv2d.https.any_gpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] depthwise conv2d float32 4D input and filter tensors options.groups= input_channels
-  assert_true: assert_array_approx_equals_ulp: test conv2d float32 actual 0 should be close enough to expected 1.165167212486267 by the acceptable 8 ULP distance, but they have 1066738739 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test conv2d float32 actual 0 should be close enough to expected 1.165167212486267 by ULP distance: expected a number less than or equal to 8n but got 1066738739n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt
index fd965e6..ec70e249 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/gather.https.any_gpu-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound positive indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 73.60064697265625 should be close enough to expected 90.2870101928711 by the acceptable 0 ULP distance, but they have 2187115 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 73.60064697265625 should be close enough to expected 90.2870101928711 by ULP distance: expected a number less than or equal to 0n but got 2187115n
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound negative indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 73.60064697265625 should be close enough to expected -66.05901336669922 by the acceptable 0 ULP distance, but they have 2232897983 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 73.60064697265625 should be close enough to expected -66.05901336669922 by ULP distance: expected a number less than or equal to 0n but got 2232897983n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/layer_normalization.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/layer_normalization.https.any_gpu-expected.txt
index 759937bc..9374093 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/layer_normalization.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/layer_normalization.https.any_gpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 [FAIL] layerNormalization float32 0D tensor default options
-  assert_true: assert_array_approx_equals_ulp: test layerNormalization float32 actual NaN should be close enough to expected 0 by the acceptable 14 ULP distance, but they have 2143289344 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test layerNormalization float32 actual NaN should be close enough to expected 0 by ULP distance: expected a number less than or equal to 14n but got 2143289344n
 [FAIL] layerNormalization float32 2D tensor axes=[] and options.bias
-  assert_true: assert_array_approx_equals_ulp: test layerNormalization float32 actual NaN should be close enough to expected 7.862982749938965 by the acceptable 14 ULP distance, but they have 1053057650 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test layerNormalization float32 actual NaN should be close enough to expected 7.862982749938965 by ULP distance: expected a number less than or equal to 14n but got 1053057650n
 [FAIL] layerNormalization float32 2D tensor axes=[]
-  assert_true: assert_array_approx_equals_ulp: test layerNormalization float32 actual NaN should be close enough to expected 0 by the acceptable 14 ULP distance, but they have 2143289344 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test layerNormalization float32 actual NaN should be close enough to expected 0 by ULP distance: expected a number less than or equal to 14n but got 2143289344n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/neg.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/neg.https.any_gpu-expected.txt
index 93084ba..11e58aa 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/neg.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/neg.https.any_gpu-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
 [FAIL] neg int32 4D tensor
-  assert_true: assert_array_approx_equals_ulp: test neg int32 actual -2147483648 should be close enough to expected -2147483646 by the acceptable 0 ULP distance, but they have 2 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test neg int32 actual -2147483648 should be close enough to expected -2147483646 by ULP distance: expected a number less than or equal to 0 but got 2
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/pooling.https.any_gpu-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/pooling.https.any_gpu-expected.txt
index 6004f7b..4a090ab1 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/pooling.https.any_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/pooling.https.any_gpu-expected.txt
@@ -2,6 +2,6 @@
 [FAIL] averagePool2d float32 4D tensor options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': DirectML: Dilations are not supported for average pooling operator."
 [FAIL] l2Pool2d float32 4D tensor options.dilations
-  assert_true: assert_array_approx_equals_ulp: test l2Pool2d float32 actual 194.45481872558594 should be close enough to expected 189.47933959960938 by the acceptable 11 ULP distance, but they have 326073 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test l2Pool2d float32 actual 194.45481872558594 should be close enough to expected 189.47933959960938 by ULP distance: expected a number less than or equal to 11n but got 326073n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
index 11c2c3b..f81fb80 100644
--- a/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/platform/win11-arm64/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by ULP distance: expected a number less than or equal to 3n but got 27754759n
 [FAIL] lstm float32 tensors steps=2 with bidirections
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063458919525 should be close enough to expected 0.5764073133468628 by the acceptable 3 ULP distance, but they have 5657187 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063458919525 should be close enough to expected 0.5764073133468628 by ULP distance: expected a number less than or equal to 3n but got 5657187n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/resources/testharness.js b/third_party/blink/web_tests/resources/testharness.js
index 8ef0574..cf380bc 100644
--- a/third_party/blink/web_tests/resources/testharness.js
+++ b/third_party/blink/web_tests/resources/testharness.js
@@ -2279,7 +2279,6 @@
                 NetworkError: 19,
                 AbortError: 20,
                 URLMismatchError: 21,
-                QuotaExceededError: 22,
                 TimeoutError: 23,
                 InvalidNodeTypeError: 24,
                 DataCloneError: 25,
@@ -2294,7 +2293,8 @@
                 VersionError: 0,
                 OperationError: 0,
                 NotAllowedError: 0,
-                OptOutError: 0
+                OptOutError: 0,
+                QuotaExceededError: 0
             };
 
             var code_name_map = {};
diff --git a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 8882c47..791460a0 100644
--- a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -172,6 +172,11 @@
     getter highWaterMark
     getter size
     method constructor
+interface CreateMonitor : EventTarget
+    attribute @@toStringTag
+    getter ondownloadprogress
+    method constructor
+    setter ondownloadprogress
 interface CropTarget
     attribute @@toStringTag
     method constructor
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt
index 0c495711..157be07 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/feature-policy-features-expected.txt
@@ -48,6 +48,7 @@
 interest-cohort
 join-ad-interest-group
 keyboard-map
+language-detector
 local-fonts
 magnetometer
 microphone
@@ -60,15 +61,19 @@
 private-state-token-redemption
 publickey-credentials-create
 publickey-credentials-get
+rewriter
 run-ad-auction
 screen-wake-lock
 serial
 shared-storage
 shared-storage-select-url
 storage-access
+summarizer
 sync-xhr
+translator
 unload
 usb
 window-management
+writer
 xr-spatial-tracking
 
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index e1084b90..8f5c13d 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -172,6 +172,11 @@
 [Worker]     getter highWaterMark
 [Worker]     getter size
 [Worker]     method constructor
+[Worker] interface CreateMonitor : EventTarget
+[Worker]     attribute @@toStringTag
+[Worker]     getter ondownloadprogress
+[Worker]     method constructor
+[Worker]     setter ondownloadprogress
 [Worker] interface CropTarget
 [Worker]     attribute @@toStringTag
 [Worker]     method constructor
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index e9cccf5..89f5441 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1292,6 +1292,11 @@
     getter highWaterMark
     getter size
     method constructor
+interface CreateMonitor : EventTarget
+    attribute @@toStringTag
+    getter ondownloadprogress
+    method constructor
+    setter ondownloadprogress
 interface Credential
     attribute @@toStringTag
     getter id
@@ -5309,6 +5314,16 @@
     setter composite
     setter pseudoElement
     setter target
+interface LanguageDetector
+    static method availability
+    static method create
+    attribute @@toStringTag
+    getter expectedInputLanguages
+    getter inputQuota
+    method constructor
+    method destroy
+    method detect
+    method measureInputUsage
 interface LargestContentfulPaint : PerformanceEntry
     attribute @@toStringTag
     getter element
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
index 4d1b520..e2724240 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -133,6 +133,11 @@
 [Worker]     getter highWaterMark
 [Worker]     getter size
 [Worker]     method constructor
+[Worker] interface CreateMonitor : EventTarget
+[Worker]     attribute @@toStringTag
+[Worker]     getter ondownloadprogress
+[Worker]     method constructor
+[Worker]     setter ondownloadprogress
 [Worker] interface CropTarget
 [Worker]     attribute @@toStringTag
 [Worker]     method constructor
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_cpu-expected.txt
index 73e3a66..9c1a7c9d 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_cpu-expected.txt
@@ -4,15 +4,15 @@
 [FAIL] convTranspose2d float32 4D input and filter tensors options.groups=2 options.strides=[2, 2]
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': convTranspose2d doesn't support dilations and groups."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.padding
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 0.2787136137485504 by the acceptable 8 ULP distance, but they have 1049539469 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 0.2787136137485504 by ULP distance: expected a number less than or equal to 8n but got 1049539469n
 [FAIL] convTranspose2d float32 4D input and filter tensors options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': convTranspose2d doesn't support dilations and groups."
 [FAIL] convTranspose2d same output size different padding (padding=1, outputPadding=0))
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by the acceptable 18 ULP distance, but they have 1065353216 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by ULP distance: expected a number less than or equal to 18n but got 1065353216n
 [FAIL] convTranspose2d same output size different padding (padding=2, outputPadding=2))
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by the acceptable 18 ULP distance, but they have 1065353216 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by ULP distance: expected a number less than or equal to 18n but got 1065353216n
 [FAIL] convTranspose2d float16 4D input and filter tensors options.padding
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float16 actual 0 should be close enough to expected 0.27880859375 by the acceptable 8 ULP distance, but they have 13430 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float16 actual 0 should be close enough to expected 0.27880859375 by ULP distance: expected a number less than or equal to 8 but got 13430
 [FAIL] convTranspose2d float16 4D input and filter tensors options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': convTranspose2d doesn't support dilations and groups."
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gather.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gather.https.any_cpu-expected.txt
index f90e7b98..cc19ef40 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gather.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gather.https.any_cpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 [FAIL] gather float32 2D tensor and int32 0D negative indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by the acceptable 0 ULP distance, but they have 1115954743 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by ULP distance: expected a number less than or equal to 0n but got 1115954743n
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound positive indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected 90.2870101928711 by the acceptable 0 ULP distance, but they have 1119130355 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected 90.2870101928711 by ULP distance: expected a number less than or equal to 0n but got 1119130355n
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound negative indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by the acceptable 0 ULP distance, but they have 1115954743 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by ULP distance: expected a number less than or equal to 0n but got 1115954743n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherND.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherND.https.any_cpu-expected.txt
index 7b6da10..0a12d07e 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherND.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gatherND.https.any_cpu-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 [FAIL] gatherND float32 4D input and 1D minimum indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual 0 should be close enough to expected -66.05901336669922 by the acceptable 0 ULP distance, but they have 1115954743 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual 0 should be close enough to expected -66.05901336669922 by ULP distance: expected a number less than or equal to 0n but got 1115954743n
 [FAIL] gatherND float32 2D input and 2D negative indices
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': TFLite doesn't support to gather input into one dimension."
 [FAIL] gatherND float32 1D input and 2D out-of-bounds indices
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gru.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gru.https.any_cpu-expected.txt
index cb2b3a1..70254f1 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gru.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/gru.https.any_cpu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 [FAIL] gru float32 tensors steps=2 with options.bias, options.recurrentBias, options.direction='backward', options.activations=['relu', 'relu'] and options.returnSequence=true
-  assert_true: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by the acceptable 6 ULP distance, but they have 16778 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by ULP distance: expected a number less than or equal to 6n but got 16778n
 [FAIL] gru float32 tensors steps=2 with options.bias, options.recurrentBias, options.direction='both' and options.returnSequence=true
-  assert_true: assert_array_approx_equals_ulp: test gru float32 actual -0.375 should be close enough to expected -0.28068751096725464 by the acceptable 6 ULP distance, but they have 3164602 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gru float32 actual -0.375 should be close enough to expected -0.28068751096725464 by ULP distance: expected a number less than or equal to 6n but got 3164602n
 [FAIL] gru float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by the acceptable 6 ULP distance, but they have 16778 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by ULP distance: expected a number less than or equal to 6n but got 16778n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
index e53dd3b2..1cd8dc3 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/lstm.https.any_cpu-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by ULP distance: expected a number less than or equal to 3n but got 27754759n
 [FAIL] lstm float32 tensors steps=2 with bidirections
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063756942749 should be close enough to expected 0.5764073133468628 by the acceptable 3 ULP distance, but they have 5657186 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063756942749 should be close enough to expected 0.5764073133468628 by ULP distance: expected a number less than or equal to 3n but got 5657186n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/pooling.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/pooling.https.any_cpu-expected.txt
index 727d407..7d6c7d69 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/pooling.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/pooling.https.any_cpu-expected.txt
@@ -1,24 +1,24 @@
 This is a testharness.js-based test.
 [FAIL] averagePool2d float32 4D tensor options.padding
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 41.9493293762207 should be close enough to expected 52.43666076660156 by the acceptable 27 ULP distance, but they have 2749191 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 41.9493293762207 should be close enough to expected 52.43666076660156 by ULP distance: expected a number less than or equal to 27n but got 2749191n
 [FAIL] averagePool2d float32 4D tensor options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Pool2d in tflite doesn't support dilations."
 [FAIL] averagePool2d float32 4D tensor options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.roundingType=ceil and no padding
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 50.63130569458008 should be close enough to expected 40.29140853881836 by the acceptable 11 ULP distance, but they have 2710542 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 50.63130569458008 should be close enough to expected 40.29140853881836 by ULP distance: expected a number less than or equal to 11n but got 2710542n
 [FAIL] averagePool2d float32 4D tensor options.layout=nhwc and options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.layout=nhwc and options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.outputSizes ignores options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.outputSizes ignores options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.dilations with options.strides
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 28.626827239990234 should be close enough to expected 42.940242767333984 by the acceptable 11 ULP distance, but they have 4636433 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 28.626827239990234 should be close enough to expected 42.940242767333984 by ULP distance: expected a number less than or equal to 11n but got 4636433n
 [FAIL] l2Pool2d float32 4D constant tensor all positive default options
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type float32 must be one of []."
 [FAIL] l2Pool2d float32 4D tensor default all positive options
@@ -50,8 +50,8 @@
 [FAIL] maxPool2d float32 4D tensor options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Pool2d in tflite doesn't support dilations."
 [FAIL] maxPool2d float32 4D tensor options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by the acceptable 0 ULP distance, but they have 2229449938 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by ULP distance: expected a number less than or equal to 0n but got 2229449938n
 [FAIL] maxPool2d float32 4D tensor options.outputSizes ignores options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by the acceptable 0 ULP distance, but they have 2229449938 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by ULP distance: expected a number less than or equal to 0n but got 2229449938n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_npu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_npu-expected.txt
index 73e3a66..9c1a7c9d 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/conv_transpose2d.https.any_npu-expected.txt
@@ -4,15 +4,15 @@
 [FAIL] convTranspose2d float32 4D input and filter tensors options.groups=2 options.strides=[2, 2]
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': convTranspose2d doesn't support dilations and groups."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.padding
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 0.2787136137485504 by the acceptable 8 ULP distance, but they have 1049539469 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 0.2787136137485504 by ULP distance: expected a number less than or equal to 8n but got 1049539469n
 [FAIL] convTranspose2d float32 4D input and filter tensors options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': convTranspose2d doesn't support dilations and groups."
 [FAIL] convTranspose2d same output size different padding (padding=1, outputPadding=0))
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by the acceptable 18 ULP distance, but they have 1065353216 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by ULP distance: expected a number less than or equal to 18n but got 1065353216n
 [FAIL] convTranspose2d same output size different padding (padding=2, outputPadding=2))
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by the acceptable 18 ULP distance, but they have 1065353216 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float32 actual 0 should be close enough to expected 1 by ULP distance: expected a number less than or equal to 18n but got 1065353216n
 [FAIL] convTranspose2d float16 4D input and filter tensors options.padding
-  assert_true: assert_array_approx_equals_ulp: test convTranspose2d float16 actual 0 should be close enough to expected 0.27880859375 by the acceptable 8 ULP distance, but they have 13430 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test convTranspose2d float16 actual 0 should be close enough to expected 0.27880859375 by ULP distance: expected a number less than or equal to 8 but got 13430
 [FAIL] convTranspose2d float16 4D input and filter tensors options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': convTranspose2d doesn't support dilations and groups."
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gather.https.any_npu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gather.https.any_npu-expected.txt
index f90e7b98..cc19ef40 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gather.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gather.https.any_npu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 [FAIL] gather float32 2D tensor and int32 0D negative indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by the acceptable 0 ULP distance, but they have 1115954743 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by ULP distance: expected a number less than or equal to 0n but got 1115954743n
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound positive indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected 90.2870101928711 by the acceptable 0 ULP distance, but they have 1119130355 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected 90.2870101928711 by ULP distance: expected a number less than or equal to 0n but got 1119130355n
 [FAIL] gather float32 2D tensor and int32 0D out-of-bound negative indices default options
-  assert_true: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by the acceptable 0 ULP distance, but they have 1115954743 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gather float32 actual 0 should be close enough to expected -66.05901336669922 by ULP distance: expected a number less than or equal to 0n but got 1115954743n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherND.https.any_npu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherND.https.any_npu-expected.txt
index 7b6da10..0a12d07e 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherND.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gatherND.https.any_npu-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 [FAIL] gatherND float32 4D input and 1D minimum indices
-  assert_true: assert_array_approx_equals_ulp: test gatherND float32 actual 0 should be close enough to expected -66.05901336669922 by the acceptable 0 ULP distance, but they have 1115954743 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gatherND float32 actual 0 should be close enough to expected -66.05901336669922 by ULP distance: expected a number less than or equal to 0n but got 1115954743n
 [FAIL] gatherND float32 2D input and 2D negative indices
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': TFLite doesn't support to gather input into one dimension."
 [FAIL] gatherND float32 1D input and 2D out-of-bounds indices
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gru.https.any_npu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gru.https.any_npu-expected.txt
index cb2b3a1..70254f1 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gru.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/gru.https.any_npu-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 [FAIL] gru float32 tensors steps=2 with options.bias, options.recurrentBias, options.direction='backward', options.activations=['relu', 'relu'] and options.returnSequence=true
-  assert_true: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by the acceptable 6 ULP distance, but they have 16778 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by ULP distance: expected a number less than or equal to 6n but got 16778n
 [FAIL] gru float32 tensors steps=2 with options.bias, options.recurrentBias, options.direction='both' and options.returnSequence=true
-  assert_true: assert_array_approx_equals_ulp: test gru float32 actual -0.375 should be close enough to expected -0.28068751096725464 by the acceptable 6 ULP distance, but they have 3164602 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gru float32 actual -0.375 should be close enough to expected -0.28068751096725464 by ULP distance: expected a number less than or equal to 6n but got 3164602n
 [FAIL] gru float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by the acceptable 6 ULP distance, but they have 16778 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test gru float32 actual -0.25 should be close enough to expected -0.24974998831748962 by ULP distance: expected a number less than or equal to 6n but got 16778n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt
index e53dd3b2..1cd8dc3 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/lstm.https.any_npu-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] lstm float32 tensors steps=2 with all options
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by the acceptable 3 ULP distance, but they have 27754759 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 1 should be close enough to expected 10.469000816345215 by ULP distance: expected a number less than or equal to 3n but got 27754759n
 [FAIL] lstm float32 tensors steps=2 with bidirections
-  assert_true: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063756942749 should be close enough to expected 0.5764073133468628 by the acceptable 3 ULP distance, but they have 5657186 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test lstm float32 actual 0.3696063756942749 should be close enough to expected 0.5764073133468628 by ULP distance: expected a number less than or equal to 3n but got 5657186n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/pooling.https.any_npu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/pooling.https.any_npu-expected.txt
index 727d407..7d6c7d69 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/pooling.https.any_npu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-npu/external/wpt/webnn/conformance_tests/pooling.https.any_npu-expected.txt
@@ -1,24 +1,24 @@
 This is a testharness.js-based test.
 [FAIL] averagePool2d float32 4D tensor options.padding
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 41.9493293762207 should be close enough to expected 52.43666076660156 by the acceptable 27 ULP distance, but they have 2749191 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 41.9493293762207 should be close enough to expected 52.43666076660156 by ULP distance: expected a number less than or equal to 27n but got 2749191n
 [FAIL] averagePool2d float32 4D tensor options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Pool2d in tflite doesn't support dilations."
 [FAIL] averagePool2d float32 4D tensor options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.roundingType=ceil and no padding
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 50.63130569458008 should be close enough to expected 40.29140853881836 by the acceptable 11 ULP distance, but they have 2710542 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 50.63130569458008 should be close enough to expected 40.29140853881836 by ULP distance: expected a number less than or equal to 11n but got 2710542n
 [FAIL] averagePool2d float32 4D tensor options.layout=nhwc and options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.layout=nhwc and options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.outputSizes ignores options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.outputSizes ignores options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by the acceptable 11 ULP distance, but they have 4736288 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 36.13502502441406 should be close enough to expected 54.20252990722656 by ULP distance: expected a number less than or equal to 11n but got 4736288n
 [FAIL] averagePool2d float32 4D tensor options.dilations with options.strides
-  assert_true: assert_array_approx_equals_ulp: test averagePool2d float32 actual 28.626827239990234 should be close enough to expected 42.940242767333984 by the acceptable 11 ULP distance, but they have 4636433 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test averagePool2d float32 actual 28.626827239990234 should be close enough to expected 42.940242767333984 by ULP distance: expected a number less than or equal to 11n but got 4636433n
 [FAIL] l2Pool2d float32 4D constant tensor all positive default options
   promise_test: Unhandled rejection with value: object "TypeError: Unsupported data type, input 'input' data type float32 must be one of []."
 [FAIL] l2Pool2d float32 4D tensor default all positive options
@@ -50,8 +50,8 @@
 [FAIL] maxPool2d float32 4D tensor options.dilations
   promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Pool2d in tflite doesn't support dilations."
 [FAIL] maxPool2d float32 4D tensor options.roundingType=ceil
-  assert_true: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by the acceptable 0 ULP distance, but they have 2229449938 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by ULP distance: expected a number less than or equal to 0n but got 2229449938n
 [FAIL] maxPool2d float32 4D tensor options.outputSizes ignores options.roundingType=floor
-  assert_true: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by the acceptable 0 ULP distance, but they have 2229449938 ULP distance expected true got false
+  assert_less_than_equal: assert_array_approx_equals_ulp: test maxPool2d float32 actual 99.28312683105469 should be close enough to expected -39.03501892089844 by ULP distance: expected a number less than or equal to 0n but got 2229449938n
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 8904cdb..4517dc6 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1748,6 +1748,11 @@
 [Worker]     getter applicationServerKey
 [Worker]     getter userVisibleOnly
 [Worker]     method constructor
+[Worker] interface QuotaExceededError : DOMException
+[Worker]     attribute @@toStringTag
+[Worker]     getter quota
+[Worker]     getter requested
+[Worker]     method constructor
 [Worker] interface RTCDataChannel : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter binaryType
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index b68f2cde..8c083a2 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -7696,6 +7696,11 @@
     getter applicationServerKey
     getter userVisibleOnly
     method constructor
+interface QuotaExceededError : DOMException
+    attribute @@toStringTag
+    getter quota
+    getter requested
+    method constructor
 interface RTCCertificate
     attribute @@toStringTag
     getter expires
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
index bc445b7..ec6acef 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -1583,6 +1583,11 @@
 [Worker]     getter applicationServerKey
 [Worker]     getter userVisibleOnly
 [Worker]     method constructor
+[Worker] interface QuotaExceededError : DOMException
+[Worker]     attribute @@toStringTag
+[Worker]     getter quota
+[Worker]     getter requested
+[Worker]     method constructor
 [Worker] interface RTCRtpAcks
 [Worker]     attribute @@toStringTag
 [Worker]     getter explicitCongestionNotification
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/containment.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/containment.html
new file mode 100644
index 0000000..b168c22
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/containment.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>Canvas.drawElement: styles for children of canvas</title>
+<link rel="help" href="https://github.com/WICG/html-in-canvas">
+<link rel="author" href="mailto:chrishtr@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  * {
+    contain: none !important;
+    position: absolute !important;
+  }
+</style>
+<canvas id=canvas width="200" height="200" layoutsubtree=true>
+  <div id=child1>
+    <div id=grandchild1></div>
+  </div>
+  <div id=child2>
+    <div id=grandchild2></div>
+  </div>
+</canvas>
+<script>
+promise_test(async () => {
+  child_asserts = {
+    contain: 'paint',
+    position: 'static'};
+  grandchild_asserts = {
+    contain: 'none',
+    position: 'absolute'};
+
+  for (a in child_asserts) {
+    assert_equals(getComputedStyle(child1)[a], child_asserts[a]);
+    assert_equals(getComputedStyle(child2)[a], child_asserts[a]);
+  }
+  for (a in grandchild_asserts) {
+    assert_equals(getComputedStyle(grandchild1)[a], grandchild_asserts[a]);
+    assert_equals(getComputedStyle(grandchild2)[a], grandchild_asserts[a]);
+  }
+ }, 'canvas child containment');
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/draw-element-detached.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/draw-element-detached.html
new file mode 100644
index 0000000..53c01dd89
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/draw-element-detached.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>Canvas.drawElement: Throw on lack of layout</title>
+<link rel="help" href="https://github.com/WICG/html-in-canvas">
+<link rel="author" href="mailto:schenney@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+#child {
+  width: 100px;
+  height: 100px;
+  background: #01ff02;
+}
+</style>
+
+<script>
+  promise_test(async t => {
+    let canvas = window.document.createElement("canvas");
+    canvas.setAttribute("layoutsubtree", "true");
+    let child = window.document.createElement("div");
+    child.setAttribute("id", "child");
+    canvas.appendChild(child);
+    let ctx = canvas.getContext('2d');
+    ctx.fillStyle = 'rgb(3, 4, 5)';
+    ctx.fillRect(0, 0, 200, 200);
+    assert_throws_js(TypeError,
+      () => ctx.drawElement(child, 20, 30),
+      "Can't draw into a detached canvas.");
+
+  }, 'canvas drawElement throws for a detached canvas due to lack of layout');
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/draw-element-display-none.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/draw-element-display-none.html
new file mode 100644
index 0000000..e549746
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/draw-element-display-none.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>Canvas.drawElement: Throw on display: none</title>
+<link rel="help" href="https://github.com/WICG/html-in-canvas">
+<link rel="author" href="mailto:schenney@chromium.org">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+div {
+  width: 100px;
+  height: 100px;
+  background: green;
+}
+canvas {
+  background: grey;
+}
+.display-none {
+  display: none;
+}
+</style>
+
+<canvas id="canvas1" width="200" height="200" layoutsubtree=true>
+  <div id="child1" class="display-none">
+  </div>
+</canvas>
+<canvas id="canvas2" class="display-none" width="200" height="200" layoutsubtree=true>
+  <div id="child2">
+  </div>
+</canvas>
+
+
+<script>
+promise_test(async () => {
+  assert_throws_js(TypeError,
+    () => canvas1.getContext("2d").drawElement(child1, 20, 30),
+    "Can't draw a display: none child.");
+
+  assert_throws_js(TypeError,
+    () => canvas2.getContext("2d").drawElement(child2, 20, 30),
+    "Can't draw into a display-none <canvas>.");
+}, "Canvas drawElement() should throw when not laid out.");
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/draw-element-missing-layout.html b/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/draw-element-missing-layout.html
deleted file mode 100644
index 18a00be1..0000000
--- a/third_party/blink/web_tests/wpt_internal/html/canvas/drawElement/draw-element-missing-layout.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<title>Canvas.drawElement: Throw on lack of layout</title>
-<link rel="help" href="https://github.com/WICG/html-in-canvas">
-<link rel="author" href="mailto:schenney@chromium.org">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<style>
-#child {
-  width: 100px;
-  height: 100px;
-  background: #01ff02;
-}
-</style>
-
-<canvas id=canvas width="200" height="200">
-  <div id=child></div>
-</canvas>
-
-<script>
-  promise_test(async t => {
-    let ctx = canvas.getContext('2d');
-    ctx.fillStyle = 'rgb(3, 4, 5)';
-    ctx.fillRect(0, 0, 200, 200);
-    try {
-      ctx.drawElement(child, 20, 30);
-      assert_unreached('Should throw TypeError exception');
-    } catch (e) {
-      assert_true(e instanceof TypeError, 'Exception should be a TypeError');
-    }
-  }, 'canvas drawElement throws when the element is not laid out');
-</script>
diff --git a/third_party/blink/web_tests/wpt_internal/isolated-permissions-policy-stable/permissions_policy.https.html b/third_party/blink/web_tests/wpt_internal/isolated-permissions-policy-stable/permissions_policy.https.html
index 052ccec..82e3f33 100644
--- a/third_party/blink/web_tests/wpt_internal/isolated-permissions-policy-stable/permissions_policy.https.html
+++ b/third_party/blink/web_tests/wpt_internal/isolated-permissions-policy-stable/permissions_policy.https.html
@@ -59,6 +59,7 @@
   'interest-cohort',
   'join-ad-interest-group',
   'keyboard-map',
+  'language-detector',
   'local-fonts',
   'magnetometer',
   'microphone',
@@ -71,16 +72,20 @@
   'private-state-token-redemption',
   'publickey-credentials-create',
   'publickey-credentials-get',
+  'rewriter',
   'run-ad-auction',
   'screen-wake-lock',
   'serial',
   'shared-storage',
   'shared-storage-select-url',
   'storage-access',
+  'summarizer',
   'sync-xhr',
+  'translator',
   'unload',
   'usb',
   'window-management',
+  'writer',
   'xr-spatial-tracking',
 ]
 
diff --git a/third_party/boringssl/src b/third_party/boringssl/src
index 6295694..02bc094 160000
--- a/third_party/boringssl/src
+++ b/third_party/boringssl/src
@@ -1 +1 @@
-Subproject commit 62956948e445c5bc67d3f299e0003c34a3030523
+Subproject commit 02bc0949e5cac0e1ee82c6f365f5a6c3cfd0cfa9
diff --git a/third_party/catapult b/third_party/catapult
index bbb14e4..2fa93b23 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit bbb14e46563c14a055b394f18b117e504e98d4ab
+Subproject commit 2fa93b2332b7a27c3066bef8d7ba9de2a5e1ab2e
diff --git a/third_party/crabbyavif/BUILD.gn b/third_party/crabbyavif/BUILD.gn
index d7fdceb..09d2dbc 100644
--- a/third_party/crabbyavif/BUILD.gn
+++ b/third_party/crabbyavif/BUILD.gn
@@ -42,10 +42,22 @@
   bindgen_flags = [
     "no-doc-comments",
     "generate=functions,types,vars,methods,constructors,destructors",
+    "allowlist-item=ABGRToI420",
+    "allowlist-item=ABGRToJ400",
+    "allowlist-item=ABGRToJ420",
+    "allowlist-item=ABGRToJ422",
     "allowlist-item=AR30ToAB30",
-    "allowlist-item=ARGBToABGR",
     "allowlist-item=ARGBAttenuate",
+    "allowlist-item=ARGBToABGR",
+    "allowlist-item=ARGBToI400",
+    "allowlist-item=ARGBToI420",
+    "allowlist-item=ARGBToI422",
+    "allowlist-item=ARGBToI444",
+    "allowlist-item=ARGBToJ400",
+    "allowlist-item=ARGBToJ420",
+    "allowlist-item=ARGBToJ422",
     "allowlist-item=ARGBUnattenuate",
+    "allowlist-item=BGRAToI420",
     "allowlist-item=Convert16To8Plane",
     "allowlist-item=FilterMode",
     "allowlist-item=FilterMode_kFilterBilinear",
@@ -54,6 +66,7 @@
     "allowlist-item=HalfFloatPlane",
     "allowlist-item=I010AlphaToARGBMatrix",
     "allowlist-item=I010AlphaToARGBMatrixFilter",
+    "allowlist-item=I010ToAR30Matrix",
     "allowlist-item=I010ToARGBMatrix",
     "allowlist-item=I010ToARGBMatrixFilter",
     "allowlist-item=I012ToARGBMatrix",
@@ -82,10 +95,21 @@
     "allowlist-item=I444AlphaToARGBMatrix",
     "allowlist-item=I444ToARGBMatrix",
     "allowlist-item=I444ToRGB24Matrix",
+    "allowlist-item=NV12Scale",
     "allowlist-item=NV12ToARGBMatrix",
+    "allowlist-item=NV12ToRGB565Matrix",
     "allowlist-item=NV21ToARGBMatrix",
     "allowlist-item=P010ToAR30Matrix",
     "allowlist-item=P010ToARGBMatrix",
+    "allowlist-item=P010ToI010",
+    "allowlist-item=RAWToI420",
+    "allowlist-item=RAWToJ400",
+    "allowlist-item=RAWToJ420",
+    "allowlist-item=RGB24ToI420",
+    "allowlist-item=RGB24ToJ400",
+    "allowlist-item=RGB24ToJ420",
+    "allowlist-item=RGBAToI420",
+    "allowlist-item=RGBAToJ400",
     "allowlist-item=ScalePlane",
     "allowlist-item=ScalePlane_12",
     "allowlist-item=YuvConstants",
@@ -132,15 +156,14 @@
     "src/src/capi/types.rs",
     "src/src/codecs/dav1d.rs",
     "src/src/codecs/mod.rs",
-    "src/src/decoder/gainmap.rs",
     "src/src/decoder/item.rs",
     "src/src/decoder/mod.rs",
     "src/src/decoder/tile.rs",
     "src/src/decoder/track.rs",
+    "src/src/gainmap.rs",
     "src/src/image.rs",
     "src/src/internal_utils/io.rs",
     "src/src/internal_utils/mod.rs",
-    "src/src/internal_utils/pixels.rs",
     "src/src/internal_utils/stream.rs",
     "src/src/lib.rs",
     "src/src/parser/exif.rs",
@@ -156,6 +179,11 @@
     "src/src/reformat/scale.rs",
     "src/src/utils/clap.rs",
     "src/src/utils/mod.rs",
+    "src/src/utils/pixels.rs",
+    "src/src/utils/reader/mod.rs",
+    "src/src/utils/reader/y4m.rs",
+    "src/src/utils/writer/mod.rs",
+    "src/src/utils/writer/y4m.rs",
   ]
 
   features = [
diff --git a/third_party/crabbyavif/README.chromium b/third_party/crabbyavif/README.chromium
index 3ef4cd2..99b29a08 100644
--- a/third_party/crabbyavif/README.chromium
+++ b/third_party/crabbyavif/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crabbyavif
 URL: https://github.com/webmproject/CrabbyAvif
 Version: N/A
-Revision: DEPS
+Revision: b097e11df62db2a6b8561f60aeae0718901122cb
 License: Apache-2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/crabbyavif/src b/third_party/crabbyavif/src
index 02d0fad..b097e11 160000
--- a/third_party/crabbyavif/src
+++ b/third_party/crabbyavif/src
@@ -1 +1 @@
-Subproject commit 02d0fad2c512380b7270d6e704c86521075d7d54
+Subproject commit b097e11df62db2a6b8561f60aeae0718901122cb
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index ec446c5..9f30607 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: N/A
-Revision: 3bc11fdb21b301d328dc0c063c5a30774adba098
+Revision: aed4e5d82c7082635a09bcc999760489e573b406
 License: Apache-2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS
index 0268f149..9c4aa15c 100644
--- a/third_party/crashpad/crashpad/DEPS
+++ b/third_party/crashpad/crashpad/DEPS
@@ -36,7 +36,7 @@
       'c912837e0d82b5ca4b6e790b573b3956d3744c1c',
   'crashpad/third_party/edo/edo': {
       'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' +
-      '727e556705278598fce683522beedbb9946bfda0',
+      '38e71ff183d76f702db6966fa7236c98831acd80',
       'condition': 'checkout_ios',
   },
   'crashpad/third_party/googletest/googletest':
@@ -47,7 +47,7 @@
       '9719c1e1e676814c456b55f5f070eabad6709d31',
   'crashpad/third_party/mini_chromium/mini_chromium':
       Var('chromium_git') + '/chromium/mini_chromium@' +
-      '15d1cace45803c0efb2a43630bf48bcdc15ad9e8',
+      '361ef33dcdfb1f2495fe6e44b9887fb9ab1d46af',
   'crashpad/third_party/libfuzzer/src':
       Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' +
       'fda403cf93ecb8792cb1d061564d89a6553ca020',
diff --git a/third_party/crashpad/crashpad/build/fuchsia_envs.py b/third_party/crashpad/crashpad/build/fuchsia_envs.py
index 8d95b78..753c322 100755
--- a/third_party/crashpad/crashpad/build/fuchsia_envs.py
+++ b/third_party/crashpad/crashpad/build/fuchsia_envs.py
@@ -37,6 +37,8 @@
         os.environ['SRC_ROOT'], 'third_party/fuchsia/sdk/linux-amd64/')
     os.environ['FUCHSIA_GN_SDK_ROOT'] = os.path.join(
         os.environ['SRC_ROOT'], 'third_party/fuchsia-gn-sdk/src')
+    os.environ['FUCHSIA_READELF'] = os.path.join(os.environ['SRC_ROOT'],
+        'third_party/fuchsia/clang/linux-amd64/bin/llvm-readelf')
 
     return subprocess.run(args).returncode
 
diff --git a/third_party/crashpad/crashpad/client/BUILD.gn b/third_party/crashpad/crashpad/client/BUILD.gn
index 78c3ded..a3ccc71 100644
--- a/third_party/crashpad/crashpad/client/BUILD.gn
+++ b/third_party/crashpad/crashpad/client/BUILD.gn
@@ -32,6 +32,8 @@
 
   if (crashpad_is_ios) {
     sources += [
+      "crash_handler_base_ios.cc",
+      "crash_handler_base_ios.h",
       "crashpad_client_ios.cc",
       "ios_handler/exception_processor.h",
       "ios_handler/exception_processor.mm",
@@ -44,6 +46,18 @@
       "simulate_crash_ios.h",
       "upload_behavior_ios.h",
     ]
+
+    if (!crashpad_is_tvos) {
+      sources += [
+        "crash_handler_ios.cc",
+        "crash_handler_ios.h",
+      ]
+    } else {
+      sources += [
+        "crash_handler_tvos.cc",
+        "crash_handler_tvos.h",
+      ]
+    }
   }
 
   if (crashpad_is_linux || crashpad_is_android) {
diff --git a/third_party/crashpad/crashpad/client/crash_handler_base_ios.cc b/third_party/crashpad/crashpad/client/crash_handler_base_ios.cc
new file mode 100644
index 0000000..6b349ca
--- /dev/null
+++ b/third_party/crashpad/crashpad/client/crash_handler_base_ios.cc
@@ -0,0 +1,127 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "client/crash_handler_base_ios.h"
+
+#include "base/logging.h"
+#include "util/posix/signals.h"
+
+namespace crashpad {
+
+CrashHandlerBase::CrashHandlerBase() = default;
+CrashHandlerBase::~CrashHandlerBase() = default;
+
+bool CrashHandlerBase::Initialize(
+    const base::FilePath& database,
+    const std::string& url,
+    const std::map<std::string, std::string>& annotations,
+    internal::InProcessHandler::ProcessPendingReportsObservationCallback
+        callback) {
+  INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
+  if (!in_process_handler().Initialize(database, url, annotations, callback)) {
+    LOG(ERROR) << "Unable to initialize Crashpad.";
+    return false;
+  }
+  if (!DoInitialize()) {
+    return false;
+  }
+  INITIALIZATION_STATE_SET_VALID(initialized_);
+  return true;
+}
+
+void CrashHandlerBase::ProcessIntermediateDumps(
+    const std::map<std::string, std::string>& annotations,
+    const UserStreamDataSources* user_stream_sources) {
+  in_process_handler_.ProcessIntermediateDumps(annotations,
+                                               user_stream_sources);
+}
+
+void CrashHandlerBase::ProcessIntermediateDump(
+    const base::FilePath& file,
+    const std::map<std::string, std::string>& annotations) {
+  in_process_handler_.ProcessIntermediateDump(file, annotations);
+}
+
+void CrashHandlerBase::DumpWithoutCrash(NativeCPUContext* context,
+                                        bool process_dump) {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  base::FilePath path;
+  if (!in_process_handler_.DumpExceptionFromSimulatedMachException(
+          context, kMachExceptionSimulated, &path)) {
+    return;
+  }
+
+  if (process_dump) {
+    in_process_handler_.ProcessIntermediateDump(path);
+  }
+}
+
+void CrashHandlerBase::DumpWithoutCrashAtPath(NativeCPUContext* context,
+                                              const base::FilePath& path) {
+  in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath(
+      context, kMachExceptionSimulated, path);
+}
+
+void CrashHandlerBase::StartProcessingPendingReports(
+    UploadBehavior upload_behavior) {
+  INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+  in_process_handler_.StartProcessingPendingReports(upload_behavior);
+}
+
+void CrashHandlerBase::SetExceptionCallbackForTesting(void (*callback)()) {
+  in_process_handler_.SetExceptionCallbackForTesting(callback);
+}
+
+void CrashHandlerBase::HandleAndReraiseSignal(int signo,
+                                              siginfo_t* siginfo,
+                                              ucontext_t* context,
+                                              struct sigaction* old_action) {
+  in_process_handler_.DumpExceptionFromSignal(siginfo, context);
+
+  // Always call system handler.
+  Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, old_action);
+}
+
+void CrashHandlerBase::HandleUncaughtNSException(const uint64_t* frames,
+                                                 const size_t num_frames) {
+  in_process_handler_.DumpExceptionFromNSExceptionWithFrames(frames,
+                                                             num_frames);
+  // After uncaught exceptions are reported, the system immediately triggers a
+  // call to std::terminate()/abort(). Remove the abort handler so a second
+  // dump isn't generated.
+  CHECK(Signals::InstallDefaultHandler(SIGABRT));
+}
+
+void CrashHandlerBase::HandleUncaughtNSExceptionWithContext(
+    NativeCPUContext* context) {
+  base::FilePath path;
+  in_process_handler_.DumpExceptionFromSimulatedMachException(
+      context, kMachExceptionFromNSException, &path);
+
+  // After uncaught exceptions are reported, the system immediately triggers a
+  // call to std::terminate()/abort(). Remove the abort handler so a second
+  // dump isn't generated.
+  CHECK(Signals::InstallDefaultHandler(SIGABRT));
+}
+
+void CrashHandlerBase::HandleUncaughtNSExceptionWithContextAtPath(
+    NativeCPUContext* context,
+    const base::FilePath& path) {
+  in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath(
+      context, kMachExceptionFromNSException, path);
+}
+
+bool CrashHandlerBase::MoveIntermediateDumpAtPathToPending(
+    const base::FilePath& path) {
+  if (in_process_handler_.MoveIntermediateDumpAtPathToPending(path)) {
+    // After uncaught exceptions are reported, the system immediately triggers
+    // a call to std::terminate()/abort(). Remove the abort handler so a
+    // second dump isn't generated.
+    CHECK(Signals::InstallDefaultHandler(SIGABRT));
+    return true;
+  }
+  return false;
+}
+
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/client/crash_handler_base_ios.h b/third_party/crashpad/crashpad/client/crash_handler_base_ios.h
new file mode 100644
index 0000000..0aea1925
--- /dev/null
+++ b/third_party/crashpad/crashpad/client/crash_handler_base_ios.h
@@ -0,0 +1,89 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRASHPAD_CLIENT_CRASH_HANDLER_BASE_IOS_H_
+#define CRASHPAD_CLIENT_CRASH_HANDLER_BASE_IOS_H_
+
+#include <stdint.h>
+#include <sys/signal.h>
+
+#include <map>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "client/ios_handler/exception_processor.h"
+#include "client/ios_handler/in_process_handler.h"
+#include "client/upload_behavior_ios.h"
+#include "util/misc/capture_context.h"
+#include "util/misc/initialization_state_dcheck.h"
+
+namespace crashpad {
+
+// Base class shared by the iOS and tvOS CrashHandler implementations.
+class CrashHandlerBase : public ObjcExceptionDelegate {
+ public:
+  CrashHandlerBase(const CrashHandlerBase&) = delete;
+  CrashHandlerBase& operator=(const CrashHandlerBase&) = delete;
+
+  bool Initialize(
+      const base::FilePath& database,
+      const std::string& url,
+      const std::map<std::string, std::string>& annotations,
+      internal::InProcessHandler::ProcessPendingReportsObservationCallback
+          callback);
+
+  void ProcessIntermediateDumps(
+      const std::map<std::string, std::string>& annotations,
+      const UserStreamDataSources* user_stream_sources);
+
+  void ProcessIntermediateDump(
+      const base::FilePath& file,
+      const std::map<std::string, std::string>& annotations);
+
+  void DumpWithoutCrash(NativeCPUContext* context, bool process_dump);
+
+  void DumpWithoutCrashAtPath(NativeCPUContext* context,
+                              const base::FilePath& path);
+
+  void StartProcessingPendingReports(UploadBehavior upload_behavior);
+
+  void SetExceptionCallbackForTesting(void (*callback)());
+
+ protected:
+  CrashHandlerBase();
+  virtual ~CrashHandlerBase();
+
+  // Subclasses are expected to install signal handlers and set up Mach ports in
+  // this function.
+  virtual bool DoInitialize() = 0;
+
+  void HandleAndReraiseSignal(int signo,
+                              siginfo_t* siginfo,
+                              ucontext_t* context,
+                              struct sigaction* old_action);
+
+  internal::InProcessHandler& in_process_handler() {
+    return in_process_handler_;
+  }
+
+ private:
+  // ObjcExceptionDelegate overrides:
+  void HandleUncaughtNSException(const uint64_t* frames,
+                                 const size_t num_frames) override;
+
+  void HandleUncaughtNSExceptionWithContext(NativeCPUContext* context) override;
+
+  void HandleUncaughtNSExceptionWithContextAtPath(
+      NativeCPUContext* context,
+      const base::FilePath& path) override;
+
+  bool MoveIntermediateDumpAtPathToPending(const base::FilePath& path) override;
+
+  internal::InProcessHandler in_process_handler_;
+  InitializationStateDcheck initialized_;
+};
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_CLIENT_CRASH_HANDLER_BASE_IOS_H_
diff --git a/third_party/crashpad/crashpad/client/crash_handler_ios.cc b/third_party/crashpad/crashpad/client/crash_handler_ios.cc
new file mode 100644
index 0000000..f149ae7
--- /dev/null
+++ b/third_party/crashpad/crashpad/client/crash_handler_ios.cc
@@ -0,0 +1,307 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "client/crash_handler_ios.h"
+
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+#include <iterator>
+
+#include "base/apple/mach_logging.h"
+#include "util/ios/raw_logging.h"
+#include "util/mach/mach_extensions.h"
+#include "util/mach/mach_message.h"
+#include "util/mach/mach_message_server.h"
+#include "util/posix/signals.h"
+
+namespace {
+
+bool IsBeingDebugged() {
+  int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
+  size_t len = sizeof(kinfo_proc);
+  kinfo_proc kern_proc_info;
+  if (sysctl(mib, std::size(mib), &kern_proc_info, &len, nullptr, 0) == 0) {
+    return kern_proc_info.kp_proc.p_flag & P_TRACED;
+  }
+  return false;
+}
+
+}  // namespace
+
+namespace crashpad {
+
+CrashHandler::ThreadSafeScopedMachPortWithReceiveRight::
+    ThreadSafeScopedMachPortWithReceiveRight()
+    : port_(NewMachPort(MACH_PORT_RIGHT_RECEIVE)) {}
+
+CrashHandler::ThreadSafeScopedMachPortWithReceiveRight::
+    ~ThreadSafeScopedMachPortWithReceiveRight() {
+  reset();
+}
+
+mach_port_t CrashHandler::ThreadSafeScopedMachPortWithReceiveRight::get() {
+  return port_.load();
+}
+void CrashHandler::ThreadSafeScopedMachPortWithReceiveRight::reset() {
+  mach_port_t old_port = port_.exchange(MACH_PORT_NULL);
+  if (old_port == MACH_PORT_NULL) {
+    // Already reset, nothing to do.
+    return;
+  }
+  kern_return_t kr = mach_port_mod_refs(
+      mach_task_self(), old_port, MACH_PORT_RIGHT_RECEIVE, -1);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+      << "ThreadSafeScopedMachPortWithReceiveRight mach_port_mod_refs";
+  kr = mach_port_deallocate(mach_task_self(), old_port);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+      << "ThreadSafeScopedMachPortWithReceiveRight mach_port_deallocate";
+}
+
+CrashHandler* CrashHandler::instance_ = nullptr;
+
+CrashHandler::CrashHandler() = default;
+
+CrashHandler::~CrashHandler() {
+  UninstallObjcExceptionPreprocessor();
+  // Reset the SIGPIPE handler only if the current handler is the
+  // one installed by DoInitialize(). In other words, if an
+  // application has set its own SIGPIPE handler after initializing
+  // Crashpad, there is no need to change the signal handler here.
+  struct sigaction sa;
+  if (sigaction(SIGPIPE, nullptr, &sa) == 0 &&
+      sa.sa_sigaction == CatchAndReraiseSignalDefaultAction) {
+    Signals::InstallDefaultHandler(SIGPIPE);
+  }
+  Signals::InstallDefaultHandler(SIGABRT);
+  UninstallMachExceptionHandler();
+}
+
+// static
+CrashHandler* CrashHandler::Get() {
+  if (!instance_)
+    instance_ = new CrashHandler();
+  return instance_;
+}
+
+// static
+void CrashHandler::ResetForTesting() {
+  delete instance_;
+  instance_ = nullptr;
+}
+
+bool CrashHandler::DoInitialize() {
+  if (!InstallMachExceptionHandler() ||
+      // xnu turns hardware faults into Mach exceptions, so the only signal
+      // left to register is SIGABRT, which never starts off as a hardware
+      // fault. Installing a handler for other signals would lead to
+      // recording exceptions twice. As a consequence, Crashpad will not
+      // generate intermediate dumps for anything manually calling
+      // raise(SIG*). In practice, this doesn’t actually happen for crash
+      // signals that originate as hardware faults.
+      !Signals::InstallHandler(
+          SIGABRT, CatchAndReraiseSignal, 0, &old_action_)) {
+    return false;
+  }
+
+  // For applications that haven't ignored or set a handler for SIGPIPE:
+  // It’s OK for an application to set its own SIGPIPE handler (including
+  // SIG_IGN) before initializing Crashpad, because Crashpad will discover the
+  // existing handler and not install its own.
+  // It’s OK for Crashpad to install its own SIGPIPE handler and for the
+  // application to subsequently install its own (including SIG_IGN)
+  // afterwards, because its handler will replace Crashpad’s.
+  // This is useful to cover the default situation where nobody installs a
+  // SIGPIPE handler and the disposition is at SIG_DFL, because SIGPIPE is a
+  // “kill” signal (bsd/sys/signalvar.h sigprop). In that case, without
+  // Crashpad, SIGPIPE results in a silent and unreported kill (and not even
+  // ReportCrash will record it), but developers probably want to be alerted to
+  // the condition.
+  struct sigaction sa;
+  if (sigaction(SIGPIPE, nullptr, &sa) == 0 && sa.sa_handler == SIG_DFL) {
+    Signals::InstallHandler(
+        SIGPIPE, CatchAndReraiseSignalDefaultAction, 0, nullptr);
+  }
+
+  InstallObjcExceptionPreprocessor(this);
+  return true;
+}
+
+bool CrashHandler::InstallMachExceptionHandler() {
+  mach_port_t exception_port = exception_port_.get();
+  if (exception_port == MACH_PORT_NULL) {
+    return false;
+  }
+
+  kern_return_t kr = mach_port_insert_right(mach_task_self(),
+                                            exception_port,
+                                            exception_port,
+                                            MACH_MSG_TYPE_MAKE_SEND);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "mach_port_insert_right";
+    return false;
+  }
+
+  // TODO: Use SwapExceptionPort instead and put back EXC_MASK_BREAKPOINT.
+  // Until then, remove |EXC_MASK_BREAKPOINT| while attached to a debugger.
+  exception_mask_t mask =
+      ExcMaskAll() &
+      ~(EXC_MASK_EMULATION | EXC_MASK_SOFTWARE | EXC_MASK_RPC_ALERT |
+        EXC_MASK_GUARD | (IsBeingDebugged() ? EXC_MASK_BREAKPOINT : 0));
+
+  ExceptionPorts exception_ports(ExceptionPorts::kTargetTypeTask, TASK_NULL);
+  if (!exception_ports.GetExceptionPorts(mask, &original_handlers_) ||
+      !exception_ports.SetExceptionPort(
+          mask,
+          exception_port,
+          EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
+          MACHINE_THREAD_STATE)) {
+    return false;
+  }
+
+  mach_handler_running_ = true;
+  Start();
+  return true;
+}
+
+void CrashHandler::UninstallMachExceptionHandler() {
+  mach_handler_running_ = false;
+  exception_port_.reset();
+  Join();
+}
+
+// Thread:
+
+void CrashHandler::ThreadMain() {
+  UniversalMachExcServer universal_mach_exc_server(this);
+  while (mach_handler_running_) {
+    mach_msg_return_t mr =
+        MachMessageServer::Run(&universal_mach_exc_server,
+                               exception_port_.get(),
+                               MACH_MSG_OPTION_NONE,
+                               MachMessageServer::kPersistent,
+                               MachMessageServer::kReceiveLargeIgnore,
+                               kMachMessageTimeoutWaitIndefinitely);
+    MACH_CHECK(
+        mach_handler_running_
+            ? mr == MACH_SEND_INVALID_DEST  // This shouldn't happen for
+                                            // exception messages that come
+                                            // from the kernel itself, but if
+                                            // something else in-process sends
+                                            // exception messages and breaks,
+                                            // handle that case.
+            : (mr == MACH_RCV_PORT_CHANGED ||  // Port was closed while the
+                                               // thread was listening.
+               mr == MACH_RCV_INVALID_NAME),  // Port was closed before the
+                                              // thread started listening.
+        mr)
+        << "MachMessageServer::Run";
+  }
+}
+
+// UniversalMachExcServer::Interface:
+
+kern_return_t CrashHandler::CatchMachException(
+    exception_behavior_t behavior,
+    exception_handler_t exception_port,
+    thread_t thread,
+    task_t task,
+    exception_type_t exception,
+    const mach_exception_data_type_t* code,
+    mach_msg_type_number_t code_count,
+    thread_state_flavor_t* flavor,
+    ConstThreadState old_state,
+    mach_msg_type_number_t old_state_count,
+    thread_state_t new_state,
+    mach_msg_type_number_t* new_state_count,
+    const mach_msg_trailer_t* trailer,
+    bool* destroy_complex_request) {
+  *destroy_complex_request = true;
+
+  // TODO(justincohen): Forward exceptions to original_handlers_ with
+  // UniversalExceptionRaise.
+
+  // iOS shouldn't have any child processes, but just in case, those will
+  // inherit the task exception ports, and this process isn’t prepared to
+  // handle them
+  if (task != mach_task_self()) {
+    CRASHPAD_RAW_LOG("MachException task != mach_task_self()");
+    return KERN_FAILURE;
+  }
+
+  HandleMachException(behavior,
+                      thread,
+                      exception,
+                      code,
+                      code_count,
+                      *flavor,
+                      old_state,
+                      old_state_count);
+
+  // Respond with KERN_FAILURE so the system will continue to handle this
+  // exception. xnu will turn this Mach exception into a signal and take the
+  // default action to terminate the process. However, if sigprocmask is
+  // called before this Mach exception returns (such as by another thread
+  // calling abort, see: Libc-1506.40.4/stdlib/FreeBSD/abort.c), the Mach
+  // exception will be converted into a signal but delivery will be blocked.
+  // Since concurrent exceptions lead to the losing thread sleeping
+  // indefinitely, if the abort thread never returns, the thread that
+  // triggered this Mach exception will repeatedly trap and the process will
+  // never terminate. If the abort thread didn’t have a user-space signal
+  // handler that slept forever, the abort would terminate the process even if
+  // all other signals had been blocked. Instead, unblock all signals
+  // corresponding to all Mach exceptions Crashpad is registered for before
+  // returning KERN_FAILURE. There is still racy behavior possible with this
+  // call to sigprocmask, but the repeated calls to CatchMachException here
+  // will eventually lead to termination.
+  sigset_t unblock_set;
+  sigemptyset(&unblock_set);
+  sigaddset(&unblock_set, SIGILL);  // EXC_BAD_INSTRUCTION
+  sigaddset(&unblock_set, SIGTRAP);  // EXC_BREAKPOINT
+  sigaddset(&unblock_set, SIGFPE);  // EXC_ARITHMETIC
+  sigaddset(&unblock_set, SIGBUS);  // EXC_BAD_ACCESS
+  sigaddset(&unblock_set, SIGSEGV);  // EXC_BAD_ACCESS
+  if (sigprocmask(SIG_UNBLOCK, &unblock_set, nullptr) != 0) {
+    CRASHPAD_RAW_LOG("sigprocmask");
+  }
+  return KERN_FAILURE;
+}
+
+void CrashHandler::HandleMachException(exception_behavior_t behavior,
+                                       thread_t thread,
+                                       exception_type_t exception,
+                                       const mach_exception_data_type_t* code,
+                                       mach_msg_type_number_t code_count,
+                                       thread_state_flavor_t flavor,
+                                       ConstThreadState old_state,
+                                       mach_msg_type_number_t old_state_count) {
+  in_process_handler().DumpExceptionFromMachException(behavior,
+                                                      thread,
+                                                      exception,
+                                                      code,
+                                                      code_count,
+                                                      flavor,
+                                                      old_state,
+                                                      old_state_count);
+}
+
+// static
+void CrashHandler::CatchAndReraiseSignal(int signo,
+                                         siginfo_t* siginfo,
+                                         void* context) {
+  Get()->HandleAndReraiseSignal(signo,
+                                siginfo,
+                                reinterpret_cast<ucontext_t*>(context),
+                                &(Get()->old_action_));
+}
+
+// static
+void CrashHandler::CatchAndReraiseSignalDefaultAction(int signo,
+                                                      siginfo_t* siginfo,
+                                                      void* context) {
+  Get()->HandleAndReraiseSignal(
+      signo, siginfo, reinterpret_cast<ucontext_t*>(context), nullptr);
+}
+
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/client/crash_handler_ios.h b/third_party/crashpad/crashpad/client/crash_handler_ios.h
new file mode 100644
index 0000000..35e1753d
--- /dev/null
+++ b/third_party/crashpad/crashpad/client/crash_handler_ios.h
@@ -0,0 +1,109 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRASHPAD_CLIENT_CRASH_HANDLER_IOS_H_
+#define CRASHPAD_CLIENT_CRASH_HANDLER_IOS_H_
+
+#include <atomic>
+
+#include "client/crash_handler_base_ios.h"
+#include "util/mach/exc_server_variants.h"
+#include "util/mach/exception_ports.h"
+#include "util/thread/thread.h"
+
+namespace crashpad {
+
+// A base class for signal handler and Mach exception server.
+class CrashHandler : public Thread,
+                     public UniversalMachExcServer::Interface,
+                     public CrashHandlerBase {
+ public:
+  CrashHandler(const CrashHandler&) = delete;
+  CrashHandler& operator=(const CrashHandler&) = delete;
+
+  static CrashHandler* Get();
+
+  static void ResetForTesting();
+
+ private:
+  // Thread-safe version of `base::apple::ScopedMachReceiveRight` which
+  // allocates the Mach port upon construction and deallocates it upon
+  // destruction.
+  class ThreadSafeScopedMachPortWithReceiveRight {
+   public:
+    ThreadSafeScopedMachPortWithReceiveRight();
+
+    ThreadSafeScopedMachPortWithReceiveRight(
+        const ThreadSafeScopedMachPortWithReceiveRight&) = delete;
+    ThreadSafeScopedMachPortWithReceiveRight& operator=(
+        const ThreadSafeScopedMachPortWithReceiveRight&) = delete;
+
+    ~ThreadSafeScopedMachPortWithReceiveRight();
+
+    mach_port_t get();
+    void reset();
+
+   private:
+    std::atomic<mach_port_t> port_;
+  };
+
+  CrashHandler();
+
+  ~CrashHandler() override;
+
+  bool DoInitialize() override;
+
+  bool InstallMachExceptionHandler();
+
+  void UninstallMachExceptionHandler();
+
+  // Thread:
+
+  void ThreadMain() override;
+
+  // UniversalMachExcServer::Interface:
+
+  kern_return_t CatchMachException(exception_behavior_t behavior,
+                                   exception_handler_t exception_port,
+                                   thread_t thread,
+                                   task_t task,
+                                   exception_type_t exception,
+                                   const mach_exception_data_type_t* code,
+                                   mach_msg_type_number_t code_count,
+                                   thread_state_flavor_t* flavor,
+                                   ConstThreadState old_state,
+                                   mach_msg_type_number_t old_state_count,
+                                   thread_state_t new_state,
+                                   mach_msg_type_number_t* new_state_count,
+                                   const mach_msg_trailer_t* trailer,
+                                   bool* destroy_complex_request) override;
+
+  void HandleMachException(exception_behavior_t behavior,
+                           thread_t thread,
+                           exception_type_t exception,
+                           const mach_exception_data_type_t* code,
+                           mach_msg_type_number_t code_count,
+                           thread_state_flavor_t flavor,
+                           ConstThreadState old_state,
+                           mach_msg_type_number_t old_state_count);
+
+  // The signal handler installed at OS-level.
+  static void CatchAndReraiseSignal(int signo,
+                                    siginfo_t* siginfo,
+                                    void* context);
+
+  static void CatchAndReraiseSignalDefaultAction(int signo,
+                                                 siginfo_t* siginfo,
+                                                 void* context);
+
+  ThreadSafeScopedMachPortWithReceiveRight exception_port_;
+  ExceptionPorts::ExceptionHandlerVector original_handlers_;
+  struct sigaction old_action_ = {};
+  static CrashHandler* instance_;
+  std::atomic<bool> mach_handler_running_ = false;
+};
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_CLIENT_CRASH_HANDLER_IOS_H_
diff --git a/third_party/crashpad/crashpad/client/crash_handler_tvos.cc b/third_party/crashpad/crashpad/client/crash_handler_tvos.cc
new file mode 100644
index 0000000..3b92fab
--- /dev/null
+++ b/third_party/crashpad/crashpad/client/crash_handler_tvos.cc
@@ -0,0 +1,97 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "client/crash_handler_tvos.h"
+
+#include <sys/signal.h>
+
+#include "util/posix/signals.h"
+#include "util/thread/thread.h"
+
+namespace crashpad {
+
+CrashHandler* CrashHandler::instance_ = nullptr;
+
+CrashHandler::CrashHandler() = default;
+
+CrashHandler::~CrashHandler() {
+  UninstallObjcExceptionPreprocessor();
+  for (int signo = 1; signo < NSIG; ++signo) {
+    if (!Signals::IsCrashSignal(signo)) {
+      Signals::RestoreOrResetHandler(signo,
+                                     old_actions_.ActionForSignal(signo));
+    } else if (signo == SIGPIPE) {
+      // Reset the SIGPIPE handler only if the current handler is the one
+      // installed by DoInitialize(). In other words, if an application has set
+      // its own SIGPIPE handler after initializing Crashpad, there is no need
+      // to change the signal handler here.
+      struct sigaction sa;
+      if (sigaction(SIGPIPE, nullptr, &sa) == 0 &&
+          sa.sa_sigaction == CatchAndReraiseSignal) {
+        Signals::InstallDefaultHandler(SIGPIPE);
+      }
+    }
+  }
+}
+
+// static
+CrashHandler* CrashHandler::Get() {
+  if (!instance_) {
+    instance_ = new CrashHandler;
+  }
+  return instance_;
+}
+
+// static
+void CrashHandler::ResetForTesting() {
+  delete instance_;
+  instance_ = nullptr;
+}
+
+uint64_t CrashHandler::GetThreadIdForTesting() {
+  return Thread::GetThreadIdForTesting();
+}
+
+bool CrashHandler::DoInitialize() {
+  if (!Signals::InstallCrashHandlers(CatchAndReraiseSignal,
+                                     /*flags=*/0,
+                                     &old_actions_)) {
+    LOG(ERROR) << "Unable to install crash handlers";
+    return false;
+  }
+
+  // For applications that haven't ignored or set a handler for SIGPIPE:
+  // It’s OK for an application to set its own SIGPIPE handler (including
+  // SIG_IGN) before initializing Crashpad, because Crashpad will discover the
+  // existing handler and not install its own.
+  // It’s OK for Crashpad to install its own SIGPIPE handler and for the
+  // application to subsequently install its own (including SIG_IGN)
+  // afterwards, because its handler will replace Crashpad’s.
+  // This is useful to cover the default situation where nobody installs a
+  // SIGPIPE handler and the disposition is at SIG_DFL, because SIGPIPE is a
+  // “kill” signal (bsd/sys/signalvar.h sigprop). In that case, without
+  // Crashpad, SIGPIPE results in a silent and unreported kill (and not even
+  // ReportCrash will record it), but developers probably want to be alerted to
+  // the condition.
+  struct sigaction sa;
+  if (sigaction(SIGPIPE, nullptr, &sa) == 0 && sa.sa_handler == SIG_DFL) {
+    Signals::InstallHandler(SIGPIPE, CatchAndReraiseSignal, 0, nullptr);
+  }
+
+  InstallObjcExceptionPreprocessor(this);
+  return true;
+}
+
+// static
+void CrashHandler::CatchAndReraiseSignal(int signo,
+                                         siginfo_t* siginfo,
+                                         void* context) {
+  CrashHandler* self = Get();
+  self->HandleAndReraiseSignal(signo,
+                               siginfo,
+                               reinterpret_cast<ucontext_t*>(context),
+                               self->old_actions_.ActionForSignal(signo));
+}
+
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/client/crash_handler_tvos.h b/third_party/crashpad/crashpad/client/crash_handler_tvos.h
new file mode 100644
index 0000000..61e2718
--- /dev/null
+++ b/third_party/crashpad/crashpad/client/crash_handler_tvos.h
@@ -0,0 +1,44 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRASHPAD_CLIENT_CRASH_HANDLER_TVOS_H_
+#define CRASHPAD_CLIENT_CRASH_HANDLER_TVOS_H_
+
+#include "client/crash_handler_base_ios.h"
+#include "util/posix/signals.h"
+
+namespace crashpad {
+
+// A crash handler based on POSIX signals.
+// The APIs to handle Mach exceptions are not available to third-party
+// applications on tvOS.
+class CrashHandler final : public CrashHandlerBase {
+ public:
+  CrashHandler(const CrashHandler&) = delete;
+  CrashHandler& operator=(const CrashHandler&) = delete;
+
+  static CrashHandler* Get();
+
+  static void ResetForTesting();
+
+  uint64_t GetThreadIdForTesting();
+
+ private:
+  CrashHandler();
+  ~CrashHandler() override;
+
+  bool DoInitialize() override;
+
+  // The signal handler installed at OS-level.
+  static void CatchAndReraiseSignal(int signo,
+                                    siginfo_t* siginfo,
+                                    void* context);
+
+  Signals::OldActions old_actions_ = {};
+  static CrashHandler* instance_;
+};
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_CLIENT_CRASH_HANDLER_TVOS_H_
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_ios.cc b/third_party/crashpad/crashpad/client/crashpad_client_ios.cc
index c9a0226..fbff1a3 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_ios.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_ios.cc
@@ -14,432 +14,17 @@
 
 #include "client/crashpad_client.h"
 
-#include <signal.h>
-#include <unistd.h>
-
-#include <atomic>
-#include <iterator>
-
-#include "base/apple/mach_logging.h"
-#include "base/logging.h"
-#include "client/ios_handler/exception_processor.h"
+#include "build/buildflag.h"
 #include "client/ios_handler/in_process_handler.h"
-#include "util/ios/raw_logging.h"
-#include "util/mach/exc_server_variants.h"
-#include "util/mach/exception_ports.h"
-#include "util/mach/mach_extensions.h"
-#include "util/mach/mach_message.h"
-#include "util/mach/mach_message_server.h"
-#include "util/misc/initialization_state_dcheck.h"
-#include "util/posix/signals.h"
-#include "util/thread/thread.h"
 
-namespace {
-
-bool IsBeingDebugged() {
-  kinfo_proc kern_proc_info;
-  int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
-  size_t len = sizeof(kern_proc_info);
-  if (sysctl(mib, std::size(mib), &kern_proc_info, &len, nullptr, 0) == 0)
-    return kern_proc_info.kp_proc.p_flag & P_TRACED;
-  return false;
-}
-
-}  // namespace
+#if !BUILDFLAG(IS_IOS_TVOS)
+#include "client/crash_handler_ios.h"
+#else
+#include "client/crash_handler_tvos.h"
+#endif
 
 namespace crashpad {
 
-namespace {
-
-// Thread-safe version of `base::apple::ScopedMachReceiveRight` which allocates
-// the Mach port upon construction and deallocates it upon destruction.
-class ThreadSafeScopedMachPortWithReceiveRight {
- public:
-  ThreadSafeScopedMachPortWithReceiveRight()
-      : port_(NewMachPort(MACH_PORT_RIGHT_RECEIVE)) {}
-
-  ThreadSafeScopedMachPortWithReceiveRight(
-      const ThreadSafeScopedMachPortWithReceiveRight&) = delete;
-  ThreadSafeScopedMachPortWithReceiveRight& operator=(
-      const ThreadSafeScopedMachPortWithReceiveRight&) = delete;
-
-  ~ThreadSafeScopedMachPortWithReceiveRight() { reset(); }
-
-  mach_port_t get() { return port_.load(); }
-  void reset() {
-    mach_port_t old_port = port_.exchange(MACH_PORT_NULL);
-    if (old_port == MACH_PORT_NULL) {
-      // Already reset, nothing to do.
-      return;
-    }
-    kern_return_t kr = mach_port_mod_refs(
-        mach_task_self(), old_port, MACH_PORT_RIGHT_RECEIVE, -1);
-    MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
-        << "ThreadSafeScopedMachPortWithReceiveRight mach_port_mod_refs";
-    kr = mach_port_deallocate(mach_task_self(), old_port);
-    MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
-        << "ThreadSafeScopedMachPortWithReceiveRight mach_port_deallocate";
-  }
-
- private:
-  std::atomic<mach_port_t> port_;
-};
-
-// A base class for signal handler and Mach exception server.
-class CrashHandler : public Thread,
-                     public UniversalMachExcServer::Interface,
-                     public ObjcExceptionDelegate {
- public:
-  CrashHandler(const CrashHandler&) = delete;
-  CrashHandler& operator=(const CrashHandler&) = delete;
-
-  static CrashHandler* Get() {
-    if (!instance_)
-      instance_ = new CrashHandler();
-    return instance_;
-  }
-
-  static void ResetForTesting() {
-    delete instance_;
-    instance_ = nullptr;
-  }
-
-  bool Initialize(
-      const base::FilePath& database,
-      const std::string& url,
-      const std::map<std::string, std::string>& annotations,
-      internal::InProcessHandler::ProcessPendingReportsObservationCallback
-          callback) {
-    INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
-    if (!in_process_handler_.Initialize(database, url, annotations, callback) ||
-        !InstallMachExceptionHandler() ||
-        // xnu turns hardware faults into Mach exceptions, so the only signal
-        // left to register is SIGABRT, which never starts off as a hardware
-        // fault. Installing a handler for other signals would lead to
-        // recording exceptions twice. As a consequence, Crashpad will not
-        // generate intermediate dumps for anything manually calling
-        // raise(SIG*). In practice, this doesn’t actually happen for crash
-        // signals that originate as hardware faults.
-        !Signals::InstallHandler(
-            SIGABRT, CatchAndReraiseSignal, 0, &old_action_)) {
-      LOG(ERROR) << "Unable to initialize Crashpad.";
-      return false;
-    }
-
-    // For applications that haven't ignored or set a handler for SIGPIPE:
-    // It’s OK for an application to set its own SIGPIPE handler (including
-    // SIG_IGN) before initializing Crashpad, because Crashpad will discover the
-    // existing handler and not install its own.
-    // It’s OK for Crashpad to install its own  SIGPIPE handler and for the
-    // application to subsequently install its own (including SIG_IGN)
-    // afterwards, because its handler will replace Crashpad’s.
-    // This is useful to cover the default situation where nobody installs a
-    // SIGPIPE  handler and the disposition is at SIG_DFL, because SIGPIPE is a
-    // “kill” signal (bsd/sys/signalvar.h  sigprop). In that case, without
-    // Crashpad, SIGPIPE results in a silent and unreported kill (and not even
-    // ReportCrash will record it), but developers probably want to be alerted
-    // to the conditon.
-    struct sigaction sa;
-    if (sigaction(SIGPIPE, nullptr, &sa) == 0 && sa.sa_handler == SIG_DFL) {
-      Signals::InstallHandler(
-          SIGPIPE, CatchAndReraiseSignalDefaultAction, 0, nullptr);
-    }
-
-    InstallObjcExceptionPreprocessor(this);
-    INITIALIZATION_STATE_SET_VALID(initialized_);
-    return true;
-  }
-
-  void ProcessIntermediateDumps(
-      const std::map<std::string, std::string>& annotations,
-      const UserStreamDataSources* user_stream_sources) {
-    in_process_handler_.ProcessIntermediateDumps(annotations,
-                                                 user_stream_sources);
-  }
-
-  void ProcessIntermediateDump(
-      const base::FilePath& file,
-      const std::map<std::string, std::string>& annotations) {
-    in_process_handler_.ProcessIntermediateDump(file, annotations);
-  }
-
-  void DumpWithoutCrash(NativeCPUContext* context, bool process_dump) {
-    INITIALIZATION_STATE_DCHECK_VALID(initialized_);
-    base::FilePath path;
-    if (!in_process_handler_.DumpExceptionFromSimulatedMachException(
-            context, kMachExceptionSimulated, &path)) {
-      return;
-    }
-
-    if (process_dump) {
-      in_process_handler_.ProcessIntermediateDump(path);
-    }
-  }
-
-  void DumpWithoutCrashAtPath(NativeCPUContext* context,
-                              const base::FilePath& path) {
-    in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath(
-        context, kMachExceptionSimulated, path);
-  }
-
-  void StartProcessingPendingReports(UploadBehavior upload_behavior) {
-    INITIALIZATION_STATE_DCHECK_VALID(initialized_);
-    in_process_handler_.StartProcessingPendingReports(upload_behavior);
-  }
-
-  void SetExceptionCallbackForTesting(void (*callback)()) {
-    in_process_handler_.SetExceptionCallbackForTesting(callback);
-  }
-
-  uint64_t GetThreadIdForTesting() { return Thread::GetThreadIdForTesting(); }
-
- private:
-  CrashHandler() = default;
-
-  ~CrashHandler() {
-    UninstallObjcExceptionPreprocessor();
-    Signals::InstallDefaultHandler(SIGABRT);
-    UninstallMachExceptionHandler();
-  }
-
-  bool InstallMachExceptionHandler() {
-    mach_port_t exception_port = exception_port_.get();
-    if (exception_port == MACH_PORT_NULL) {
-      return false;
-    }
-
-    kern_return_t kr = mach_port_insert_right(mach_task_self(),
-                                              exception_port,
-                                              exception_port,
-                                              MACH_MSG_TYPE_MAKE_SEND);
-    if (kr != KERN_SUCCESS) {
-      MACH_LOG(ERROR, kr) << "mach_port_insert_right";
-      return false;
-    }
-
-    // TODO: Use SwapExceptionPort instead and put back EXC_MASK_BREAKPOINT.
-    // Until then, remove |EXC_MASK_BREAKPOINT| while attached to a debugger.
-    exception_mask_t mask =
-        ExcMaskAll() &
-        ~(EXC_MASK_EMULATION | EXC_MASK_SOFTWARE | EXC_MASK_RPC_ALERT |
-          EXC_MASK_GUARD | (IsBeingDebugged() ? EXC_MASK_BREAKPOINT : 0));
-
-    ExceptionPorts exception_ports(ExceptionPorts::kTargetTypeTask, TASK_NULL);
-    if (!exception_ports.GetExceptionPorts(mask, &original_handlers_) ||
-        !exception_ports.SetExceptionPort(
-            mask,
-            exception_port,
-            EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
-            MACHINE_THREAD_STATE)) {
-      return false;
-    }
-
-    mach_handler_running_ = true;
-    Start();
-    return true;
-  }
-
-  void UninstallMachExceptionHandler() {
-    mach_handler_running_ = false;
-    exception_port_.reset();
-    Join();
-  }
-
-  // Thread:
-
-  void ThreadMain() override {
-    UniversalMachExcServer universal_mach_exc_server(this);
-    while (mach_handler_running_) {
-      mach_msg_return_t mr =
-          MachMessageServer::Run(&universal_mach_exc_server,
-                                 exception_port_.get(),
-                                 MACH_MSG_OPTION_NONE,
-                                 MachMessageServer::kPersistent,
-                                 MachMessageServer::kReceiveLargeIgnore,
-                                 kMachMessageTimeoutWaitIndefinitely);
-      MACH_CHECK(
-          mach_handler_running_
-              ? mr == MACH_SEND_INVALID_DEST  // This shouldn't happen for
-                                              // exception messages that come
-                                              // from the kernel itself, but if
-                                              // something else in-process sends
-                                              // exception messages and breaks,
-                                              // handle that case.
-              : (mr == MACH_RCV_PORT_CHANGED ||  // Port was closed while the
-                                                 // thread was listening.
-                 mr == MACH_RCV_INVALID_NAME),  // Port was closed before the
-                                                // thread started listening.
-          mr)
-          << "MachMessageServer::Run";
-    }
-  }
-
-  // UniversalMachExcServer::Interface:
-
-  kern_return_t CatchMachException(exception_behavior_t behavior,
-                                   exception_handler_t exception_port,
-                                   thread_t thread,
-                                   task_t task,
-                                   exception_type_t exception,
-                                   const mach_exception_data_type_t* code,
-                                   mach_msg_type_number_t code_count,
-                                   thread_state_flavor_t* flavor,
-                                   ConstThreadState old_state,
-                                   mach_msg_type_number_t old_state_count,
-                                   thread_state_t new_state,
-                                   mach_msg_type_number_t* new_state_count,
-                                   const mach_msg_trailer_t* trailer,
-                                   bool* destroy_complex_request) override {
-    *destroy_complex_request = true;
-
-    // TODO(justincohen): Forward exceptions to original_handlers_ with
-    // UniversalExceptionRaise.
-
-    // iOS shouldn't have any child processes, but just in case, those will
-    // inherit the task exception ports, and this process isn’t prepared to
-    // handle them
-    if (task != mach_task_self()) {
-      CRASHPAD_RAW_LOG("MachException task != mach_task_self()");
-      return KERN_FAILURE;
-    }
-
-    HandleMachException(behavior,
-                        thread,
-                        exception,
-                        code,
-                        code_count,
-                        *flavor,
-                        old_state,
-                        old_state_count);
-
-    // Respond with KERN_FAILURE so the system will continue to handle this
-    // exception. xnu will turn this Mach exception into a signal and take the
-    // default action to terminate the process. However, if sigprocmask is
-    // called before this Mach exception returns (such as by another thread
-    // calling abort, see: Libc-1506.40.4/stdlib/FreeBSD/abort.c), the Mach
-    // exception will be converted into a signal but delivery will be blocked.
-    // Since concurrent exceptions lead to the losing thread sleeping
-    // indefinitely, if the abort thread never returns, the thread that
-    // triggered this Mach exception will repeatedly trap and the process will
-    // never terminate. If the abort thread didn’t have a user-space signal
-    // handler that slept forever, the abort would terminate the process even if
-    // all other signals had been blocked. Instead, unblock all signals
-    // corresponding to all Mach exceptions Crashpad is registered for before
-    // returning KERN_FAILURE. There is still racy behavior possible with this
-    // call to sigprocmask, but the repeated calls to CatchMachException here
-    // will eventually lead to termination.
-    sigset_t unblock_set;
-    sigemptyset(&unblock_set);
-    sigaddset(&unblock_set, SIGILL);  // EXC_BAD_INSTRUCTION
-    sigaddset(&unblock_set, SIGTRAP);  // EXC_BREAKPOINT
-    sigaddset(&unblock_set, SIGFPE);  // EXC_ARITHMETIC
-    sigaddset(&unblock_set, SIGBUS);  // EXC_BAD_ACCESS
-    sigaddset(&unblock_set, SIGSEGV);  // EXC_BAD_ACCESS
-    if (sigprocmask(SIG_UNBLOCK, &unblock_set, nullptr) != 0) {
-      CRASHPAD_RAW_LOG("sigprocmask");
-    }
-    return KERN_FAILURE;
-  }
-
-  void HandleMachException(exception_behavior_t behavior,
-                           thread_t thread,
-                           exception_type_t exception,
-                           const mach_exception_data_type_t* code,
-                           mach_msg_type_number_t code_count,
-                           thread_state_flavor_t flavor,
-                           ConstThreadState old_state,
-                           mach_msg_type_number_t old_state_count) {
-    in_process_handler_.DumpExceptionFromMachException(behavior,
-                                                       thread,
-                                                       exception,
-                                                       code,
-                                                       code_count,
-                                                       flavor,
-                                                       old_state,
-                                                       old_state_count);
-  }
-
-  void HandleUncaughtNSException(const uint64_t* frames,
-                                 const size_t num_frames) override {
-    in_process_handler_.DumpExceptionFromNSExceptionWithFrames(frames,
-                                                               num_frames);
-    // After uncaught exceptions are reported, the system immediately triggers a
-    // call to std::terminate()/abort(). Remove the abort handler so a second
-    // dump isn't generated.
-    CHECK(Signals::InstallDefaultHandler(SIGABRT));
-  }
-
-  void HandleUncaughtNSExceptionWithContext(
-      NativeCPUContext* context) override {
-    base::FilePath path;
-    in_process_handler_.DumpExceptionFromSimulatedMachException(
-        context, kMachExceptionFromNSException, &path);
-
-    // After uncaught exceptions are reported, the system immediately triggers a
-    // call to std::terminate()/abort(). Remove the abort handler so a second
-    // dump isn't generated.
-    CHECK(Signals::InstallDefaultHandler(SIGABRT));
-  }
-
-  void HandleUncaughtNSExceptionWithContextAtPath(
-      NativeCPUContext* context,
-      const base::FilePath& path) override {
-    in_process_handler_.DumpExceptionFromSimulatedMachExceptionAtPath(
-        context, kMachExceptionFromNSException, path);
-  }
-
-  bool MoveIntermediateDumpAtPathToPending(
-      const base::FilePath& path) override {
-    if (in_process_handler_.MoveIntermediateDumpAtPathToPending(path)) {
-      // After uncaught exceptions are reported, the system immediately triggers
-      // a call to std::terminate()/abort(). Remove the abort handler so a
-      // second dump isn't generated.
-      CHECK(Signals::InstallDefaultHandler(SIGABRT));
-      return true;
-    }
-    return false;
-  }
-
-  // The signal handler installed at OS-level.
-  static void CatchAndReraiseSignal(int signo,
-                                    siginfo_t* siginfo,
-                                    void* context) {
-    Get()->HandleAndReraiseSignal(signo,
-                                  siginfo,
-                                  reinterpret_cast<ucontext_t*>(context),
-                                  &(Get()->old_action_));
-  }
-
-  static void CatchAndReraiseSignalDefaultAction(int signo,
-                                                 siginfo_t* siginfo,
-                                                 void* context) {
-    Get()->HandleAndReraiseSignal(
-        signo, siginfo, reinterpret_cast<ucontext_t*>(context), nullptr);
-  }
-
-  void HandleAndReraiseSignal(int signo,
-                              siginfo_t* siginfo,
-                              ucontext_t* context,
-                              struct sigaction* old_action) {
-    in_process_handler_.DumpExceptionFromSignal(siginfo, context);
-
-    // Always call system handler.
-    Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, old_action);
-  }
-
-  ThreadSafeScopedMachPortWithReceiveRight exception_port_;
-  ExceptionPorts::ExceptionHandlerVector original_handlers_;
-  struct sigaction old_action_ = {};
-  internal::InProcessHandler in_process_handler_;
-  static CrashHandler* instance_;
-  std::atomic<bool> mach_handler_running_ = false;
-  InitializationStateDcheck initialized_;
-};
-
-CrashHandler* CrashHandler::instance_ = nullptr;
-
-}  // namespace
-
 CrashpadClient::CrashpadClient() {}
 
 CrashpadClient::~CrashpadClient() {}
diff --git a/third_party/crashpad/crashpad/test/fuchsia_crashpad_tests.cml b/third_party/crashpad/crashpad/test/fuchsia_crashpad_tests.cml
index d231f8f..bfcedb3 100644
--- a/third_party/crashpad/crashpad/test/fuchsia_crashpad_tests.cml
+++ b/third_party/crashpad/crashpad/test/fuchsia_crashpad_tests.cml
@@ -1,6 +1,17 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+// Copyright 2022 The Crashpad Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 {
     include: [
         "//src/sys/test_runners/elf/ambient_exec.shard.cml",
diff --git a/third_party/crashpad/crashpad/test/ios/crash_type_xctest.mm b/third_party/crashpad/crashpad/test/ios/crash_type_xctest.mm
index b6d1bff..330b9f6 100644
--- a/third_party/crashpad/crashpad/test/ios/crash_type_xctest.mm
+++ b/third_party/crashpad/crashpad/test/ios/crash_type_xctest.mm
@@ -159,6 +159,7 @@
 
 - (void)testTrap {
   [rootObject_ crashTrap];
+#if !BUILDFLAG(IS_IOS_TVOS)
 #if defined(ARCH_CPU_X86_64)
   [self verifyCrashReportException:EXC_BAD_INSTRUCTION];
 #elif defined(ARCH_CPU_ARM64)
@@ -166,6 +167,12 @@
 #else
 #error Port to your CPU architecture
 #endif
+#else  // !BUILDFLAG(IS_IOS_TVOS)
+  [self verifyCrashReportException:EXC_SOFT_SIGNAL];
+  NSNumber* report_exception;
+  XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]);
+  XCTAssertEqual(report_exception.intValue, SIGTRAP);
+#endif
 }
 
 - (void)testAbort {
@@ -178,7 +185,14 @@
 
 - (void)testBadAccess {
   [rootObject_ crashBadAccess];
+#if !BUILDFLAG(IS_IOS_TVOS)
   [self verifyCrashReportException:EXC_BAD_ACCESS];
+#else
+  [self verifyCrashReportException:EXC_SOFT_SIGNAL];
+  NSNumber* report_exception;
+  XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]);
+  XCTAssertEqual(report_exception.intValue, SIGSEGV);
+#endif
 }
 
 - (void)testException {
@@ -250,7 +264,14 @@
 
 - (void)testCatchUIGestureEnvironmentNSException {
   // Tap the button with the string UIGestureEnvironmentException.
+#if !BUILDFLAG(IS_IOS_TVOS)
   [app_.buttons[@"UIGestureEnvironmentException"] tap];
+#else
+  // tvOS does not have [XCUIElement tap]. This version assumes there is just
+  // one big button with "UIGestureEnvironmentException" as title, so we can
+  // just press Select on the remote to activate it.
+  [XCUIRemote.sharedRemote pressButton:XCUIRemoteButtonSelect];
+#endif
   [self verifyCrashReportException:crashpad::kMachExceptionFromNSException];
   NSDictionary* dict = [rootObject_ getAnnotations];
   XCTAssertTrue([[dict[@"objects"][0] valueForKeyPath:@"exceptionReason"]
@@ -280,10 +301,21 @@
       isEqualToString:@"NSGenericException"]);
 }
 
+// This test cannot run correctly on tvOS: it is impossible to catch this stack
+// overflow as a Mach exception (like we do on iOS), and sigaltstack() is also
+// forbidden so we cannot detect it with POSIX signals either.
+// Per xnu-11215.81.4/bsd/uxkern/ux_exception.c's handle_ux_exception(), when a
+// stack overflow is detected but no alternate stack is specified, the kernel
+// will reset SIGSEGV to SIG_DFL before delivering the signal, so we are never
+// able to capture this crash. Even if we do pass SA_ONSTACK to sigaction(), we
+// will just crash a bit later, as we are still using the same stack that has
+// already overflown.
+#if !BUILDFLAG(IS_IOS_TVOS)
 - (void)testRecursion {
   [rootObject_ crashRecursion];
   [self verifyCrashReportException:EXC_BAD_ACCESS];
 }
+#endif
 
 - (void)testClientAnnotations {
   [rootObject_ crashKillAbort];
diff --git a/third_party/crashpad/crashpad/third_party/edo/BUILD.gn b/third_party/crashpad/crashpad/third_party/edo/BUILD.gn
index aac3e87..9744cbc98 100644
--- a/third_party/crashpad/crashpad/third_party/edo/BUILD.gn
+++ b/third_party/crashpad/crashpad/third_party/edo/BUILD.gn
@@ -1,6 +1,16 @@
-# Copyright 2018 The Chromium Authors
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+# Copyright 2025 The Crashpad Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
 
 import("../../build/crashpad_buildconfig.gni")
 
diff --git a/third_party/crashpad/crashpad/third_party/ninja/ninja b/third_party/crashpad/crashpad/third_party/ninja/ninja
index 402ab2a1..ca087460 100755
--- a/third_party/crashpad/crashpad/third_party/ninja/ninja
+++ b/third_party/crashpad/crashpad/third_party/ninja/ninja
@@ -1,8 +1,18 @@
 #!/bin/sh
 
-# Copyright 2022 Google Inc. All rights reserved
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+# Copyright 2022 The Crashpad Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
 
 set -eu
 
diff --git a/third_party/crashpad/crashpad/util/BUILD.gn b/third_party/crashpad/crashpad/util/BUILD.gn
index 1bb36a4..31eb3d7 100644
--- a/third_party/crashpad/crashpad/util/BUILD.gn
+++ b/third_party/crashpad/crashpad/util/BUILD.gn
@@ -19,7 +19,7 @@
   import("//build/config/sanitizers/sanitizers.gni")
 }
 
-if (crashpad_is_apple) {
+if (crashpad_is_apple && !crashpad_is_tvos) {
   if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
     import("//build/config/sysroot.gni")
   } else {
@@ -334,29 +334,37 @@
       "mac/sysctl.h",
       "mac/xattr.cc",
       "mac/xattr.h",
-      "mach/composite_mach_message_server.cc",
-      "mach/composite_mach_message_server.h",
-      "mach/exc_client_variants.cc",
-      "mach/exc_client_variants.h",
-      "mach/exc_server_variants.cc",
-      "mach/exc_server_variants.h",
-      "mach/exception_behaviors.cc",
-      "mach/exception_behaviors.h",
-      "mach/exception_ports.cc",
-      "mach/exception_ports.h",
       "mach/mach_extensions.cc",
       "mach/mach_extensions.h",
-      "mach/mach_message.cc",
-      "mach/mach_message.h",
-      "mach/mach_message_server.cc",
-      "mach/mach_message_server.h",
-      "mach/symbolic_constants_mach.cc",
-      "mach/symbolic_constants_mach.h",
       "misc/capture_context_mac.S",
       "misc/clock_mac.cc",
       "misc/paths_mac.cc",
       "synchronization/semaphore_mac.cc",
     ]
+
+    # Exclude files related to Mach exceptions when building for tvOS. Mach
+    # messaging APIs are not available to third-party applications on tvOS so
+    # crashes are handled via POSIX signals.
+    if (!crashpad_is_tvos) {
+      sources += [
+        "mach/composite_mach_message_server.cc",
+        "mach/composite_mach_message_server.h",
+        "mach/exc_client_variants.cc",
+        "mach/exc_client_variants.h",
+        "mach/exc_server_variants.cc",
+        "mach/exc_server_variants.h",
+        "mach/exception_behaviors.cc",
+        "mach/exception_behaviors.h",
+        "mach/exception_ports.cc",
+        "mach/exception_ports.h",
+        "mach/mach_message.cc",
+        "mach/mach_message.h",
+        "mach/mach_message_server.cc",
+        "mach/mach_message_server.h",
+        "mach/symbolic_constants_mach.cc",
+        "mach/symbolic_constants_mach.h",
+      ]
+    }
   }
 
   if (crashpad_is_mac && !crashpad_is_in_fuchsia) {
@@ -593,10 +601,11 @@
 
   if (crashpad_is_apple) {
     include_dirs += [ "$root_gen_dir" ]
-    deps += [
-      ":mig_output",
-      "../build:apple_enable_arc",
-    ]
+    deps += [ "../build:apple_enable_arc" ]
+
+    if (!crashpad_is_tvos) {
+      deps += [ ":mig_output" ]
+    }
   }
 
   if (crashpad_is_mac && !crashpad_is_in_fuchsia) {
@@ -823,14 +832,19 @@
   if (crashpad_is_apple) {
     sources += [
       "mac/xattr_test.cc",
-      "mach/composite_mach_message_server_test.cc",
-      "mach/exc_server_variants_test.cc",
-      "mach/exception_behaviors_test.cc",
-      "mach/mach_extensions_test.cc",
-      "mach/mach_message_test.cc",
-      "mach/symbolic_constants_mach_test.cc",
       "misc/capture_context_test_util_mac.cc",
     ]
+
+    if (!crashpad_is_tvos) {
+      sources += [
+        "mach/composite_mach_message_server_test.cc",
+        "mach/exc_server_variants_test.cc",
+        "mach/exception_behaviors_test.cc",
+        "mach/mach_extensions_test.cc",
+        "mach/mach_message_test.cc",
+        "mach/symbolic_constants_mach_test.cc",
+      ]
+    }
   }
 
   if (crashpad_is_mac) {
diff --git a/third_party/crashpad/crashpad/util/posix/signals.cc b/third_party/crashpad/crashpad/util/posix/signals.cc
index e24bb60..58f957c 100644
--- a/third_party/crashpad/crashpad/util/posix/signals.cc
+++ b/third_party/crashpad/crashpad/util/posix/signals.cc
@@ -278,14 +278,8 @@
 }
 
 // static
-void Signals::RestoreHandlerAndReraiseSignalOnReturn(
-    const siginfo_t* siginfo,
-    const struct sigaction* old_action) {
-  // Failures in this function should _exit(kFailureExitCode). This is a quick
-  // and quiet failure. This function runs in signal handler context, and it’s
-  // difficult to safely be loud from a signal handler.
-  constexpr int kFailureExitCode = 191;
-
+bool Signals::RestoreOrResetHandler(int sig,
+                                    const struct sigaction* old_action) {
   struct sigaction default_action;
   sigemptyset(&default_action.sa_mask);
   default_action.sa_flags = 0;
@@ -297,9 +291,25 @@
   // Try to restore restore_action. If that fails and restore_action was
   // old_action, the problem may have been that old_action was bogus, so try to
   // set the default action.
-  const int sig = siginfo->si_signo;
   if (sigaction(sig, restore_action, nullptr) != 0 && old_action &&
       sigaction(sig, &default_action, nullptr) != 0) {
+    return false;
+  }
+  return true;
+}
+
+// static
+void Signals::RestoreHandlerAndReraiseSignalOnReturn(
+    const siginfo_t* siginfo,
+    const struct sigaction* old_action) {
+  // Failures in this function should _exit(kFailureExitCode). This is a quick
+  // and quiet failure. This function runs in signal handler context, and it’s
+  // difficult to safely be loud from a signal handler.
+  constexpr int kFailureExitCode = 191;
+
+  const int sig = siginfo->si_signo;
+
+  if (!RestoreOrResetHandler(sig, old_action)) {
     _exit(kFailureExitCode);
   }
 
diff --git a/third_party/crashpad/crashpad/util/posix/signals.h b/third_party/crashpad/crashpad/util/posix/signals.h
index e12ad72b..934b312 100644
--- a/third_party/crashpad/crashpad/util/posix/signals.h
+++ b/third_party/crashpad/crashpad/util/posix/signals.h
@@ -196,6 +196,24 @@
   //! \note This function is safe to call from a signal handler.
   static bool WillSignalReraiseAutonomously(const siginfo_t* siginfo);
 
+  //! \brief Restores a previous signal action or reinstalls the default signal
+  //!     handler for a given signal.
+  //!
+  //! Attempts to reinstate the action given by \a old_action and, in case of
+  //! failure or if \a old_actiono is `nullptr`, resets the handler for \a sig
+  //! to the default action.
+  //!
+  //! \param[in] sig The signal to manage.
+  //! \param[in] old_action The previous action for the signal, which will be
+  //!     re-established as the signal’s action. May be `nullptr`, which directs
+  //!     the default action for the signal to be used.
+  //!
+  //! \return `true` on success, `false` if `sigaction()` fails.
+  //!
+  //! \note This function is safe to call from a signal handler.
+  static bool RestoreOrResetHandler(int sig,
+                                    const struct sigaction* old_action);
+
   //! \brief Restores a previous signal action and arranges to re-raise a signal
   //!     on return from a signal handler.
   //!
diff --git a/third_party/dawn b/third_party/dawn
index 3ae10bb..e9424a0 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 3ae10bb874bd495b9334b42a1c1bddec00ec53cb
+Subproject commit e9424a009a62bacb7ba8e027bf7c8c3de4fb19d9
diff --git a/third_party/depot_tools b/third_party/depot_tools
index a9cc320..c273e3e 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit a9cc320bf761323906c614f7040cb1dc22fcc858
+Subproject commit c273e3eb6202ef710a9cbf48fc99437a56a13631
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src
index 27ee073..9aefa1c 160000
--- a/third_party/llvm-libc/src
+++ b/third_party/llvm-libc/src
@@ -1 +1 @@
-Subproject commit 27ee0730164e6f101985f057c6ad23a9ba7710f6
+Subproject commit 9aefa1cede964571c0b0ef41460cc5c3bbc6b4b8
diff --git a/third_party/ml_dtypes/BUILD.gn b/third_party/ml_dtypes/BUILD.gn
new file mode 100644
index 0000000..de8771f
--- /dev/null
+++ b/third_party/ml_dtypes/BUILD.gn
@@ -0,0 +1,29 @@
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/sanitizers/sanitizers.gni")
+
+config("ml_dtypes-includes") {
+  include_dirs = [
+    "src",
+    "src/ml_dtypes",
+  ]
+}
+
+static_library("ml_dtypes") {
+  sources = [
+    "src/ml_dtypes/include/float8.h",
+    "src/ml_dtypes/include/intn.h",
+    "src/ml_dtypes/include/mxfloat.h",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    ":ml_dtypes-includes",
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/eigen3:eigen_includes",
+  ]
+
+  public_configs = [ ":ml_dtypes-includes" ]
+}
diff --git a/third_party/ml_dtypes/DEPS b/third_party/ml_dtypes/DEPS
new file mode 100644
index 0000000..2fdad449
--- /dev/null
+++ b/third_party/ml_dtypes/DEPS
@@ -0,0 +1,4 @@
+# checkdeps.py shouldn't check include paths for files in these dirs:
+skip_child_includes = [
+  'src',
+]
diff --git a/third_party/ml_dtypes/DIR_METADATA b/third_party/ml_dtypes/DIR_METADATA
new file mode 100644
index 0000000..c23828c
--- /dev/null
+++ b/third_party/ml_dtypes/DIR_METADATA
@@ -0,0 +1,6 @@
+monorail: {
+  component: "Internals>OptimizationGuide"
+}
+buganizer_public: {
+  component_id: 1456757
+}
diff --git a/third_party/ml_dtypes/OWNERS b/third_party/ml_dtypes/OWNERS
new file mode 100644
index 0000000..a3ecffc6f
--- /dev/null
+++ b/third_party/ml_dtypes/OWNERS
@@ -0,0 +1 @@
+file://third_party/tflite/OWNERS
diff --git a/third_party/ml_dtypes/README.chromium b/third_party/ml_dtypes/README.chromium
new file mode 100644
index 0000000..eaf45581
--- /dev/null
+++ b/third_party/ml_dtypes/README.chromium
@@ -0,0 +1,19 @@
+Name: ml_dtypes
+Short Name: ml_dtypes
+URL: https://github.com/jax-ml/ml_dtypes
+Version: 57e857e85df34d463f2c778810dc4b876750c5e0
+Date: 2025-05-07
+License: Apache-2.0
+License File: src/LICENSE
+Security Critical: Yes
+Shipped: yes
+CPEPrefix: unknown
+
+Description:
+ml_dtypes is a stand-alone implementation of several NumPy dtype extensions used
+in machine learning libraries.
+
+Local Modifications:
+Only a portion of the upstream library is copied here, namely the include
+headers which serve as glue code between TFLite and Eigen. See also update.sh
+in this directory.
diff --git a/third_party/ml_dtypes/src/LICENSE b/third_party/ml_dtypes/src/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/ml_dtypes/src/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/third_party/ml_dtypes/src/ml_dtypes/include/float8.h b/third_party/ml_dtypes/src/ml_dtypes/include/float8.h
new file mode 100644
index 0000000..7696c05
--- /dev/null
+++ b/third_party/ml_dtypes/src/ml_dtypes/include/float8.h
@@ -0,0 +1,1843 @@
+/* Copyright 2022 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#ifndef ML_DTYPES_FLOAT8_H_
+#define ML_DTYPES_FLOAT8_H_
+
+// 8-bit Floating Point Interchange Format, as described by
+//   https://arxiv.org/abs/2209.05433
+//   https://www.opencompute.org/documents/ocp-8-bit-floating-point-specification-ofp8-revision-1-0-2023-12-01-pdf-1
+//   https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
+
+#include <algorithm>
+#include <climits>
+#include <cmath>
+#include <cstdint>
+#include <limits>
+#include <ostream>
+#include <type_traits>
+#include <utility>
+
+#ifdef __has_include
+#if __has_include(<version>)
+#include <version>
+#endif
+#endif
+
+#if (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L)
+#include <bit>
+#endif
+
+#include "Eigen/Core"
+
+namespace ml_dtypes {
+namespace float8_internal {
+
+// Forward-declarations of classes.
+class float8_e3m4;
+class float8_e4m3;
+class float8_e4m3fn;
+class float8_e4m3fnuz;
+class float8_e4m3b11fnuz;
+class float8_e5m2;
+class float8_e5m2fnuz;
+class float8_e8m0fnu;
+
+template <typename Derived>
+class float8_base {
+ protected:
+  // Constructor tag to allow constexpr construction from bit representation.
+  struct ConstructFromRepTag {};
+  constexpr float8_base(uint8_t rep, ConstructFromRepTag) : rep_{rep} {}
+
+ public:
+  static constexpr int kBits = 8;
+  constexpr float8_base() : rep_(0) {}
+
+  template <typename T>
+  explicit EIGEN_DEVICE_FUNC float8_base(
+      T i, std::enable_if_t<std::is_integral_v<T>, int> = 0)
+      : float8_base(ConvertFrom(static_cast<float>(i)).rep(),
+                    ConstructFromRepTag{}) {}
+  template <typename T>
+  explicit EIGEN_DEVICE_FUNC float8_base(
+      T f, std::enable_if_t<std::is_floating_point_v<T>, int> = 0)
+      : float8_base(ConvertFrom(f).rep(), ConstructFromRepTag{}) {}
+  explicit EIGEN_DEVICE_FUNC float8_base(Eigen::bfloat16 bf16)
+      : float8_base(ConvertFrom(bf16).rep(), ConstructFromRepTag{}) {}
+  explicit EIGEN_DEVICE_FUNC float8_base(Eigen::half f16)
+      : float8_base(ConvertFrom(f16).rep(), ConstructFromRepTag{}) {}
+
+  constexpr uint8_t rep() const { return rep_; }
+
+  template <typename T,
+            typename EnableIf = std::enable_if<std::is_arithmetic_v<T>>>
+  explicit EIGEN_DEVICE_FUNC operator T() const {
+    return static_cast<T>(static_cast<float>(derived()));
+  }
+  explicit EIGEN_DEVICE_FUNC operator double() const {
+    return ConvertTo<double>(derived());
+  }
+  EIGEN_DEVICE_FUNC operator float() const {
+    return ConvertTo<float>(derived());
+  }
+  EIGEN_DEVICE_FUNC operator Eigen::bfloat16() const {
+    return ConvertTo<Eigen::bfloat16>(derived());
+  }
+  EIGEN_DEVICE_FUNC operator Eigen::half() const {
+    return ConvertTo<Eigen::half>(derived());
+  }
+  explicit EIGEN_DEVICE_FUNC operator bool() const {
+    return (rep() & 0x7F) != 0;
+  }
+
+  constexpr Derived operator-() const {
+    return Derived(static_cast<uint8_t>(rep() ^ 0x80), ConstructFromRepTag{});
+  }
+
+  constexpr const Derived& derived() const {
+    return *static_cast<const Derived*>(this);
+  }
+
+  constexpr Derived& derived() { return *static_cast<Derived*>(this); }
+
+  static constexpr Derived FromRep(uint8_t rep) {
+    return Derived(rep, ConstructFromRepTag{});
+  }
+
+  // Conversions allowing saturation and truncation.
+  template <bool kSaturate = false, bool kTruncate = false, typename From>
+  static inline EIGEN_DEVICE_FUNC Derived ConvertFrom(From from);
+
+  template <typename To, bool kSaturate = false, bool kTruncate = false>
+  static inline EIGEN_DEVICE_FUNC To ConvertTo(Derived from);
+
+  // Operators via float32.
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Derived
+  operator+(const Derived& other) const {
+    return Derived{float{derived()} + float{other}};
+  }
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Derived
+  operator-(const Derived& other) const {
+    return Derived{float{derived()} - float{other}};
+  }
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Derived
+  operator*(const Derived& other) const {
+    return Derived{float{derived()} * float{other}};
+  }
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Derived
+  operator/(const Derived& other) const {
+    return Derived{float{derived()} / float{other}};
+  }
+
+  constexpr bool operator==(const Derived& other) const {
+    return Compare(derived(), other) == Ordering::kEquivalent;
+  }
+
+  constexpr bool operator!=(const Derived& other) const {
+    return Compare(derived(), other) != Ordering::kEquivalent;
+  }
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator<(
+      const Derived& other) const {
+    return Compare(derived(), other) == Ordering::kLess;
+  }
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator<=(
+      const Derived& other) const {
+    return Compare(derived(), other) <= Ordering::kEquivalent;
+  }
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator>(
+      const Derived& other) const {
+    return Compare(derived(), other) == Ordering::kGreater;
+  }
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator>=(
+      const Derived& other) const {
+    Ordering ordering = Compare(derived(), other);
+    return ordering == Ordering::kGreater || ordering == Ordering::kEquivalent;
+  }
+
+  // Compound assignment.
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Derived& operator+=(
+      const Derived& other) {
+    derived() = derived() + other;
+    return derived();
+  }
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Derived& operator-=(
+      const Derived& other) {
+    derived() = derived() - other;
+    return derived();
+  }
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Derived& operator*=(
+      const Derived& other) {
+    derived() = derived() * other;
+    return derived();
+  }
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Derived& operator/=(
+      const Derived& other) {
+    derived() = derived() / other;
+    return derived();
+  }
+
+ private:
+  static EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC std::pair<uint8_t, uint8_t>
+  SignAndMagnitude(Derived x) {
+    const uint8_t x_abs_bits =
+        Eigen::numext::bit_cast<uint8_t>(Eigen::numext::abs(x));
+    const uint8_t x_bits = Eigen::numext::bit_cast<uint8_t>(x);
+    const uint8_t x_sign = (x_bits ^ x_abs_bits) << (CHAR_BIT - Derived::kBits);
+    return {x_sign, x_abs_bits};
+  }
+  static EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC int8_t
+  SignAndMagnitudeToTwosComplement(uint8_t sign, uint8_t magnitude) {
+    return magnitude ^ (static_cast<int8_t>(sign) < 0 ? -1 : 0);
+  }
+
+  enum Ordering : int8_t {
+    kLess = -1,
+    kEquivalent = 0,
+    kGreater = 1,
+    kUnordered = 2,
+  };
+
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC friend Ordering Compare(
+      const Derived& lhs, const Derived& rhs) {
+    if (Eigen::numext::isnan(lhs) || Eigen::numext::isnan(rhs)) {
+      return Ordering::kUnordered;
+    }
+    auto [lhs_sign, lhs_mag] = SignAndMagnitude(lhs);
+    auto [rhs_sign, rhs_mag] = SignAndMagnitude(rhs);
+    if (lhs_mag == 0 && rhs_mag == 0) {
+      return Ordering::kEquivalent;
+    }
+    int8_t lhs_twos_complement =
+        SignAndMagnitudeToTwosComplement(lhs_sign, lhs_mag);
+    int8_t rhs_twos_complement =
+        SignAndMagnitudeToTwosComplement(rhs_sign, rhs_mag);
+    if (lhs_twos_complement < rhs_twos_complement) {
+      return Ordering::kLess;
+    }
+    if (lhs_twos_complement > rhs_twos_complement) {
+      return Ordering::kGreater;
+    }
+    return Ordering::kEquivalent;
+  }
+
+  uint8_t rep_;
+};
+
+template <typename T>
+using RequiresIsDerivedFromFloat8Base =
+    std::enable_if_t<std::is_base_of_v<float8_base<T>, T>, int>;
+
+class float8_e3m4 : public float8_base<float8_e3m4> {
+  // Exponent: 3, Mantissa: 4, bias: 3.
+  // IEEE 754.
+ private:
+  using Base = float8_base<float8_e3m4>;
+  friend class float8_base<float8_e3m4>;
+  using Base::Base;
+
+ public:
+  template <typename T, RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float8_e3m4(T f8) : float8_e3m4(ConvertFrom(f8)) {}
+};
+
+class float8_e4m3 : public float8_base<float8_e4m3> {
+  // Exponent: 4, Mantissa: 3, bias: 7.
+  // IEEE 754.
+ private:
+  using Base = float8_base<float8_e4m3>;
+  friend class float8_base<float8_e4m3>;
+  using Base::Base;
+
+ public:
+  template <typename T, RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float8_e4m3(T f8) : float8_e4m3(ConvertFrom(f8)) {}
+};
+
+class float8_e4m3fn : public float8_base<float8_e4m3fn> {
+  // Exponent: 4, Mantissa: 3, bias: 7.
+  // Extended range: no inf, NaN represented by 0bS111'1111.
+  // The "fn" suffix is for consistency with the corresponding LLVM/MLIR type,
+  // signaling this type is not consistent with IEEE-754.  The "f" indicates
+  // it is finite values only. The "n" indicates it includes NaNs, but only
+  // at the outer range.
+ private:
+  using Base = float8_base<float8_e4m3fn>;
+  friend class float8_base<float8_e4m3fn>;
+  using Base::Base;
+
+ public:
+  template <typename T, RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float8_e4m3fn(T f8)
+      : float8_e4m3fn(ConvertFrom(f8)) {}
+};
+
+class float8_e4m3b11fnuz : public float8_base<float8_e4m3b11fnuz> {
+  // Exponent: 4, Mantissa: 3, bias: 11.
+  // Extended range: no inf, NaN represented by 0b1000'0000.
+ private:
+  using Base = float8_base<float8_e4m3b11fnuz>;
+  friend class float8_base<float8_e4m3b11fnuz>;
+  using Base::Base;
+
+ public:
+  template <typename T, RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float8_e4m3b11fnuz(T f8)
+      : float8_e4m3b11fnuz(ConvertFrom(f8)) {}
+
+  constexpr float8_e4m3b11fnuz operator-() const {
+    if ((rep() & 0x7f) == 0x00) {
+      return *this;
+    }
+    return Base::operator-();
+  }
+
+  float8_e4m3b11fnuz operator-(const float8_e4m3b11fnuz& other) const {
+    return Base::operator-(other);
+  }
+
+  explicit EIGEN_DEVICE_FUNC operator bool() const { return rep() != 0; }
+};
+
+// Legacy name used in XLA (TODO(jewillco): remove).
+using float8_e4m3b11 = float8_e4m3b11fnuz;
+
+class float8_e4m3fnuz : public float8_base<float8_e4m3fnuz> {
+  // 8-bit floating point with 3 bit mantissa.
+  //
+  // An 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits
+  // mantissa. The suffix "fnuz" is consistent with LLVM/MLIR naming and is
+  // derived from the differences to IEEE floating point conventions. `F` is
+  // for "finite" (no infinities), `N` for with special NaN encoding, `UZ` for
+  // unsigned zero.
+  //
+  // This type has the following characteristics:
+  // * bit encoding: S1E4M3 - `0bSEEEEMMM`
+  // * exponent bias: 8
+  // * infinities: Not supported
+  // * NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits
+  // set to all 0s - `0b10000000`
+  // * denormals when exponent is 0
+ private:
+  using Base = float8_base<float8_e4m3fnuz>;
+  friend class float8_base<float8_e4m3fnuz>;
+  using Base::Base;
+
+ public:
+  template <typename T, RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float8_e4m3fnuz(T f8)
+      : float8_e4m3fnuz(ConvertFrom(f8)) {}
+
+  constexpr float8_e4m3fnuz operator-() const {
+    if ((rep() & 0x7f) == 0x00) {
+      return *this;
+    }
+    return Base::operator-();
+  }
+
+  float8_e4m3fnuz operator-(const float8_e4m3fnuz& other) const {
+    return Base::operator-(other);
+  }
+
+  explicit EIGEN_DEVICE_FUNC operator bool() const { return rep() != 0; }
+};
+
+class float8_e5m2 : public float8_base<float8_e5m2> {
+  // Exponent: 5, Mantissa: 2, bias: 15.
+  // IEEE 754.
+ private:
+  using Base = float8_base<float8_e5m2>;
+  friend class float8_base<float8_e5m2>;
+  using Base::Base;
+
+ public:
+  template <typename T, RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float8_e5m2(T f8) : float8_e5m2(ConvertFrom(f8)) {}
+};
+
+class float8_e5m2fnuz : public float8_base<float8_e5m2fnuz> {
+  // 8-bit floating point with 2 bit mantissa.
+  //
+  // An 8-bit floating point type with 1 sign bit, 5 bits exponent and 2 bits
+  // mantissa. The suffix "fnuz" is consistent with LLVM/MLIR naming and is
+  // derived from the differences to IEEE floating point conventions. `F` is
+  // for "finite" (no infinities), `N` for with special NaN encoding, `UZ` for
+  // unsigned zero.
+  //
+  // This type has the following characteristics:
+  // * bit encoding: S1E5M2 - `0bSEEEEEMM`
+  // * exponent bias: 16
+  // * infinities: Not supported
+  // * NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits
+  // set to all 0s - `0b10000000`
+  // * denormals when exponent is 0
+ private:
+  using Base = float8_base<float8_e5m2fnuz>;
+  friend class float8_base<float8_e5m2fnuz>;
+  using Base::Base;
+
+ public:
+  template <typename T, RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float8_e5m2fnuz(T f8)
+      : float8_e5m2fnuz(ConvertFrom(f8)) {}
+
+  constexpr float8_e5m2fnuz operator-() const {
+    if ((rep() & 0x7f) == 0x00) {
+      return *this;
+    }
+    return Base::operator-();
+  }
+
+  float8_e5m2fnuz operator-(const float8_e5m2fnuz& other) const {
+    return Base::operator-(other);
+  }
+
+  explicit EIGEN_DEVICE_FUNC operator bool() const { return rep() != 0; }
+};
+
+class float8_e8m0fnu : public float8_base<float8_e8m0fnu> {
+  // 8-bit floating point with 8 bit exponent, no sign and zero mantissa.
+  //
+  // See:
+  // https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
+  //
+  // An 8-bit floating point type with no sign bit, 8 bits exponent and 0 bits
+  // mantissa. The suffix "fnuz" is consistent with LLVM/MLIR naming and is
+  // derived from the differences to IEEE floating point conventions. `F` is
+  // for "finite" (no infinities), `N` for with special NaN encoding, `U` for
+  // unsigned.
+  //
+  // This type has the following characteristics:
+  // * bit encoding: S0E8M0 - `0bEEEEEEEE`
+  // * exponent bias: 127
+  // * infinities: Not supported
+  // * NaNs: Supported with exponent bits set to 1s - `0b11111111`
+ private:
+  using Base = float8_base<float8_e8m0fnu>;
+  friend class float8_base<float8_e8m0fnu>;
+  using Base::Base;
+
+ public:
+  template <typename T, RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float8_e8m0fnu(T f8)
+      : float8_e8m0fnu(ConvertFrom(f8)) {}
+
+  constexpr float8_e8m0fnu operator-() const {
+    // No negative numbers supported in E8M0 => NaN
+    return float8_e8m0fnu::FromRep(0xFF);
+  }
+
+  float8_e8m0fnu operator-(const float8_e8m0fnu& other) const {
+    return Base::operator-(other);
+  }
+
+  explicit EIGEN_DEVICE_FUNC operator bool() const {
+    // No zero supported in E8M0 format.
+    return true;
+  }
+
+  // Comparison simplified to uint8_t compare.
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator<(
+      const float8_e8m0fnu& other) const {
+    if (Eigen::numext::isnan(*this) || Eigen::numext::isnan(other)) {
+      return false;
+    }
+    return rep() < other.rep();
+  }
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator<=(
+      const float8_e8m0fnu& other) const {
+    if (Eigen::numext::isnan(*this) || Eigen::numext::isnan(other)) {
+      return false;
+    }
+    return rep() <= other.rep();
+  }
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator>(
+      const float8_e8m0fnu& other) const {
+    if (Eigen::numext::isnan(*this) || Eigen::numext::isnan(other)) {
+      return false;
+    }
+    return rep() > other.rep();
+  }
+  EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator>=(
+      const float8_e8m0fnu& other) const {
+    if (Eigen::numext::isnan(*this) || Eigen::numext::isnan(other)) {
+      return false;
+    }
+    return rep() >= other.rep();
+  }
+};
+
+constexpr double ConstexprAbs(double x) { return x < 0.0 ? -x : x; }
+
+constexpr double ConstexprCeil(double x) {
+  constexpr double kIntegerThreshold =
+      uint64_t{1} << (std::numeric_limits<double>::digits - 1);
+  // Too big or NaN inputs get returned unchanged.
+  if (!(ConstexprAbs(x) < kIntegerThreshold)) {
+    return x;
+  }
+  const double x_trunc = static_cast<double>(static_cast<int64_t>(x));
+  return x_trunc < x ? x_trunc + 1.0 : x_trunc;
+}
+
+constexpr double ConstexprFloor(double x) { return -ConstexprCeil(-x); }
+
+constexpr double kLog10Of2 = 0.3010299956639812;
+// C17 5.2.4.2.2p11:
+// "number of decimal digits, q, such that any floating-point number with q
+// decimal digits can be rounded into a floating-point number with p radix b
+// digits and back again without change to the q decimal digits"
+// floor((p - 1) * log10(2));
+constexpr int Digits10FromDigits(int digits) {
+  return static_cast<int>(ConstexprFloor((digits - 1) * kLog10Of2));
+}
+
+// C17 5.2.4.2.2p11:
+// "number of decimal digits, n, such that any floating-point number with p
+// radix b digits can be rounded to a floating-point number with n decimal
+// digits and back again without change to the value"
+// ceil(1 + p * log10(2));
+constexpr int MaxDigits10FromDigits(int digits) {
+  return static_cast<int>(ConstexprCeil(1.0 + (digits * kLog10Of2)));
+}
+
+// C17 5.2.4.2.2p11:
+// "minimum negative integer such that 10 raised to that power is in the range
+// of normalized floating-point numbers"
+// ceil(log10(2**(emin - 1))) == ceil((emin - 1) * log10(2));
+constexpr int MinExponent10FromMinExponent(int min_exponent) {
+  return static_cast<int>(ConstexprCeil((min_exponent - 1) * kLog10Of2));
+}
+
+// C17 5.2.4.2.2p11:
+// "maximum integer such that 10 raised to that power is in the range of
+// representable finite floating-point numbers"
+// floor(log10((1 - 2**-p) * 2**emax)) == floor(log10(1 - 2**-p) +
+// emax * log10(2))
+constexpr int MaxExponent10FromMaxExponentAndDigits(int max_exponent,
+                                                    int digits) {
+  // We only support digits in {1,2,3,4,5}. This table would grow if we wanted
+  // to handle more values.
+  constexpr double kLog10OfOnePredecessor[] = {
+      // log10(1 - 2**-1)
+      -0.3010299956639812,
+      // log10(1 - 2**-2)
+      -0.12493873660829993,
+      // log10(1 - 2**-3)
+      -0.057991946977686754,
+      // log10(1 - 2**-4)
+      -0.028028723600243537,
+      // log10(1 - 2**-5)
+      -0.013788284485633295,
+  };
+  return static_cast<int>(ConstexprFloor(kLog10OfOnePredecessor[digits - 1] +
+                                         max_exponent * kLog10Of2));
+}
+
+// Structures for use in specializing std::numeric_limits.
+struct numeric_limits_float8_base {
+  // NOLINTBEGIN: these names must match std::numeric_limits.
+  static inline constexpr const bool is_specialized = true;
+  static inline constexpr const bool is_signed = true;
+  static inline constexpr const bool is_integer = false;
+  static inline constexpr const bool is_exact = false;
+  static inline constexpr const bool has_quiet_NaN = true;
+  static inline constexpr const std::float_denorm_style has_denorm =
+      std::denorm_present;
+  static inline constexpr const bool has_denorm_loss = false;
+  static inline constexpr const std::float_round_style round_style =
+      std::round_to_nearest;
+  static inline constexpr const bool is_bounded = true;
+  static inline constexpr const bool is_modulo = false;
+  static inline constexpr const int radix = std::numeric_limits<float>::radix;
+  static inline constexpr const bool traps = std::numeric_limits<float>::traps;
+  static inline constexpr const bool tinyness_before =
+      std::numeric_limits<float>::tinyness_before;
+  // NOLINTEND
+};
+
+struct numeric_limits_float8_e3m4 : public numeric_limits_float8_base {
+ private:
+  static inline constexpr const int kExponentBias = 3;
+  static inline constexpr const int kMantissaBits = 4;
+
+ public:
+  // NOLINTBEGIN: these names must match std::numeric_limits.
+  static inline constexpr const int digits = kMantissaBits + 1;
+  static inline constexpr const int digits10 = Digits10FromDigits(digits);
+  static inline constexpr const int max_digits10 =
+      MaxDigits10FromDigits(digits);
+  static inline constexpr const int min_exponent = (1 - kExponentBias) + 1;
+  static inline constexpr const int min_exponent10 =
+      MinExponent10FromMinExponent(min_exponent);
+  static inline constexpr const int max_exponent = 0b111 - kExponentBias;
+  static inline constexpr const int max_exponent10 =
+      MaxExponent10FromMaxExponentAndDigits(max_exponent, digits);
+  static inline constexpr const bool is_iec559 = true;
+  static inline constexpr const bool has_infinity = true;
+  static inline constexpr const bool has_signaling_NaN = true;
+  // NOLINTEND
+
+  // 1.0 * 2^(0b001 - 3) = 1.0 * 2^-2 = 1/4 (min normal)
+  static constexpr float8_e3m4 min() {
+    return float8_e3m4::FromRep(1 << kMantissaBits);
+  }
+  // -(1 + 0b1111 * 2^-2) * 2^(0b110 - 3) = -(1 + 15/16) * 2^3 = -15.5
+  static constexpr float8_e3m4 lowest() {
+    return float8_e3m4::FromRep(0b1'110'1111);
+  }
+  // (1 + 0b1111 * 2^-2) * 2^(0b110 - 3) = (1 + 15/16) * 2^3 = 15.5
+  static constexpr float8_e3m4 max() {
+    return float8_e3m4::FromRep(0b0'110'1111);
+  }
+  // (1 + 1/16) * 2^0 - 1.0 = 1.0 + 1/16 - 1.0 = 1/16
+  // Encoded as denormal number 2^-2 * 1/4
+  static constexpr float8_e3m4 epsilon() {
+    return float8_e3m4::FromRep(0b0'000'0100);
+  }
+  // 1.0 * 2^-1 = 0.5
+  static constexpr float8_e3m4 round_error() {
+    return float8_e3m4::FromRep((-1 + kExponentBias) << kMantissaBits);
+  }
+  static constexpr float8_e3m4 infinity() {
+    return float8_e3m4::FromRep(0b0'111'0000);
+  }
+  static constexpr float8_e3m4 quiet_NaN() {
+    // IEEE 754-2019 6.2.1: "All binary NaN bit strings have the sign bit S set
+    // to 0 or 1 and all the bits of the biased exponent field E set to 1
+    // (see 3.4). A quiet NaN bit string should be encoded with the first bit
+    // (d1) of the trailing significand field T being 1."
+    return float8_e3m4::FromRep(0b0'111'1000);
+  }
+  static constexpr float8_e3m4 signaling_NaN() {
+    // IEEE 754-2019 6.2.1: "A signaling NaN bit string should be encoded with
+    // the first bit of the trailing significand field being 0."
+    return float8_e3m4::FromRep(0b0'111'0100);
+  }
+  // 2^(-2) * 2^(-4) = 2^-6 = 1/64 (min denormal)
+  static constexpr float8_e3m4 denorm_min() {
+    return float8_e3m4::FromRep(0b0'000'0001);
+  }
+};
+
+struct numeric_limits_float8_e4m3 : public numeric_limits_float8_base {
+ private:
+  static inline constexpr const int kExponentBias = 7;
+  static inline constexpr const int kMantissaBits = 3;
+
+ public:
+  // NOLINTBEGIN: these names must match std::numeric_limits.
+  static inline constexpr const int digits = kMantissaBits + 1;
+  static inline constexpr const int digits10 = Digits10FromDigits(digits);
+  static inline constexpr const int max_digits10 =
+      MaxDigits10FromDigits(digits);
+  static inline constexpr const int min_exponent = (1 - kExponentBias) + 1;
+  static inline constexpr const int min_exponent10 =
+      MinExponent10FromMinExponent(min_exponent);
+  static inline constexpr const int max_exponent = 0b1111 - kExponentBias;
+  static inline constexpr const int max_exponent10 =
+      MaxExponent10FromMaxExponentAndDigits(max_exponent, digits);
+  static inline constexpr const bool is_iec559 = true;
+  static inline constexpr const bool has_infinity = true;
+  static inline constexpr const bool has_signaling_NaN = true;
+  // NOLINTEND
+
+  // 1.0 * 2^(0b0001 - 7) = 1.0 * 2^-6 = 1/64 (min normal)
+  static constexpr float8_e4m3 min() {
+    return float8_e4m3::FromRep(1 << kMantissaBits);
+  }
+  // -(1 + 0b111 * 2^-2) * 2^(0b1110 - 7) = -(1 + 7/8) * 2^7 = -240
+  static constexpr float8_e4m3 lowest() {
+    return float8_e4m3::FromRep(0b1'1110'111);
+  }
+  // (1 + 0b111 * 2^-2) * 2^(0b1110 - 7) = (1 + 7/8) * 2^7 = 240
+  static constexpr float8_e4m3 max() {
+    return float8_e4m3::FromRep(0b0'1110'111);
+  }
+  // 1.0 * 2^-3 = 0.125
+  static constexpr float8_e4m3 epsilon() {
+    return float8_e4m3::FromRep((-kMantissaBits + kExponentBias)
+                                << kMantissaBits);
+  }
+  // 1.0 * 2^-1 = 0.5
+  static constexpr float8_e4m3 round_error() {
+    return float8_e4m3::FromRep((-1 + kExponentBias) << kMantissaBits);
+  }
+  static constexpr float8_e4m3 infinity() {
+    return float8_e4m3::FromRep(0b0'1111'000);
+  }
+  static constexpr float8_e4m3 quiet_NaN() {
+    // IEEE 754-2019 6.2.1: "All binary NaN bit strings have the sign bit S set
+    // to 0 or 1 and all the bits of the biased exponent field E set to 1
+    // (see 3.4). A quiet NaN bit string should be encoded with the first bit
+    // (d1) of the trailing significand field T being 1."
+    return float8_e4m3::FromRep(0b0'1111'100);
+  }
+  static constexpr float8_e4m3 signaling_NaN() {
+    // IEEE 754-2019 6.2.1: "A signaling NaN bit string should be encoded with
+    // the first bit of the trailing significand field being 0."
+    return float8_e4m3::FromRep(0b0'1111'001);
+  }
+  // 2^(-6) * 2^(-3) = 2^-9 = 1/512 (min denormal)
+  static constexpr float8_e4m3 denorm_min() {
+    return float8_e4m3::FromRep(0b0'0000'001);
+  }
+};
+
+struct numeric_limits_float8_e4m3fn : public numeric_limits_float8_base {
+ private:
+  static inline constexpr const int kExponentBias = 7;
+  static inline constexpr const int kMantissaBits = 3;
+
+ public:
+  // NOLINTBEGIN: these names must match std::numeric_limits.
+  static inline constexpr const int digits = kMantissaBits + 1;
+  static inline constexpr const int digits10 = Digits10FromDigits(digits);
+  static inline constexpr const int max_digits10 =
+      MaxDigits10FromDigits(digits);
+  static inline constexpr const int min_exponent = (1 - kExponentBias) + 1;
+  static inline constexpr const int min_exponent10 =
+      MinExponent10FromMinExponent(min_exponent);
+  static inline constexpr const int max_exponent =
+      (0b1111 - kExponentBias) + 1;  // Extended format.
+  static inline constexpr const int max_exponent10 =
+      MaxExponent10FromMaxExponentAndDigits(max_exponent, digits);
+  static inline constexpr const bool is_iec559 = false;
+  static inline constexpr const bool has_infinity = false;
+  static inline constexpr const bool has_signaling_NaN = false;
+  // NOLINTEND
+
+  // 1.0 * 2^(0b0001 - 7) = 1.0 * 2^-6 = 0.015625
+  static constexpr float8_e4m3fn min() {
+    return float8_e4m3fn::FromRep(0b0'0001 << kMantissaBits);
+  }
+  // -(1 + 0b110 * 2^-3) * 2^(0b1111 - 7) = -1.75 * 2^8 = 448
+  static constexpr float8_e4m3fn lowest() {
+    return float8_e4m3fn::FromRep(0b1'1111'110);
+  }
+  // (1 + 0b110 * 2^-3) * 2**(0b1111 - 7) = 1.75 * 2^8 = 448
+  static constexpr float8_e4m3fn max() {
+    return float8_e4m3fn::FromRep(0b0'1111'110);
+  }
+  // 1.0 * 2^-3 = 0.125
+  static constexpr float8_e4m3fn epsilon() {
+    return float8_e4m3fn::FromRep((-kMantissaBits + kExponentBias)
+                                  << kMantissaBits);
+  }
+  // 1.0 * 2^-1 = 0.5
+  static constexpr float8_e4m3fn round_error() {
+    return float8_e4m3fn::FromRep((-1 + kExponentBias) << kMantissaBits);
+  }
+  static constexpr float8_e4m3fn infinity() {
+    return float8_e4m3fn::FromRep(0b0'1111'111);
+  }
+  // NaN.
+  static constexpr float8_e4m3fn quiet_NaN() {
+    return float8_e4m3fn::FromRep(0b0'1111'111);
+  }
+  static constexpr float8_e4m3fn signaling_NaN() {
+    return float8_e4m3fn::FromRep(0b0'1111'111);
+  }
+  // 1.0 * 2^(-7 - 3 + 1) = 1.0 * 2^-9 = 0.001953125
+  static constexpr float8_e4m3fn denorm_min() {
+    return float8_e4m3fn::FromRep(0b0'0000'001);
+  }
+};
+
+struct numeric_limits_float8_e4m3b11fnuz : public numeric_limits_float8_base {
+ private:
+  static inline constexpr const int kExponentBias = 11;
+  static inline constexpr const int kMantissaBits = 3;
+
+ public:
+  // NOLINTBEGIN: these names must match std::numeric_limits.
+  static inline constexpr const int digits = kMantissaBits + 1;
+  static inline constexpr const int digits10 = Digits10FromDigits(digits);
+  static inline constexpr const int max_digits10 =
+      MaxDigits10FromDigits(digits);
+  static inline constexpr const int min_exponent = (1 - kExponentBias) + 1;
+  static inline constexpr const int min_exponent10 =
+      MinExponent10FromMinExponent(min_exponent);
+  static inline constexpr const int max_exponent =
+      (0b1111 - kExponentBias) + 1;  // Extended format.
+  static inline constexpr const int max_exponent10 =
+      MaxExponent10FromMaxExponentAndDigits(max_exponent, digits);
+  static inline constexpr const bool is_iec559 = false;
+  static inline constexpr const bool has_infinity = false;
+  static inline constexpr const bool has_signaling_NaN = false;
+  // NOLINTEND
+
+  // 1.0 * 2^(0b0001 - 11) = 1.0 * 2^-10 = 0.0009765625
+  static constexpr float8_e4m3b11fnuz min() {
+    return float8_e4m3b11fnuz::FromRep(1 << kMantissaBits);
+  }
+  // -(1 + 0b111 * 2^-3) * 2^(0b1111 - 11) = -1.875 * 2^4 = -30
+  static constexpr float8_e4m3b11fnuz lowest() {
+    return float8_e4m3b11fnuz::FromRep(0b1'1111'111);
+  }
+  // (1 + 0b111 * 2^-3) * 2^(0b1111 - 11) = 1.875 * 2^4 = 30
+  static constexpr float8_e4m3b11fnuz max() {
+    return float8_e4m3b11fnuz::FromRep(0b0'1111'111);
+  }
+  // 1.0 * 2^-3 = 0.125
+  static constexpr float8_e4m3b11fnuz epsilon() {
+    return float8_e4m3b11fnuz::FromRep((-kMantissaBits + kExponentBias)
+                                       << kMantissaBits);
+  }
+  // 1.0 * 2^-1 = 0.5
+  static constexpr float8_e4m3b11fnuz round_error() {
+    return float8_e4m3b11fnuz::FromRep((-1 + kExponentBias) << kMantissaBits);
+  }
+  static constexpr float8_e4m3b11fnuz infinity() {
+    return float8_e4m3b11fnuz::FromRep(0b1'0000'000);
+  }
+  // NaN.
+  static constexpr float8_e4m3b11fnuz quiet_NaN() {
+    return float8_e4m3b11fnuz::FromRep(0b1'0000'000);
+  }
+  static constexpr float8_e4m3b11fnuz signaling_NaN() {
+    return float8_e4m3b11fnuz::FromRep(0b1'0000'000);
+  }
+  // 1.0 * 2^(-11 - 3 + 1) = 1.0 * 2^-13 = 0.0001220703125
+  static constexpr float8_e4m3b11fnuz denorm_min() {
+    return float8_e4m3b11fnuz::FromRep(0b0'0000'001);
+  }
+};
+
+struct numeric_limits_float8_e4m3fnuz : public numeric_limits_float8_base {
+ private:
+  static inline constexpr const int kExponentBias = 8;
+  static inline constexpr const int kMantissaBits = 3;
+
+ public:
+  // NOLINTBEGIN: these names must match std::numeric_limits.
+  static inline constexpr const int digits = kMantissaBits + 1;
+  static inline constexpr const int digits10 = Digits10FromDigits(digits);
+  static inline constexpr const int max_digits10 =
+      MaxDigits10FromDigits(digits);
+  static inline constexpr const int min_exponent = (1 - kExponentBias) + 1;
+  static inline constexpr const int min_exponent10 =
+      MinExponent10FromMinExponent(min_exponent);
+  static inline constexpr const int max_exponent =
+      (0b1111 - kExponentBias) + 1;  // Extended format.
+  static inline constexpr const int max_exponent10 =
+      MaxExponent10FromMaxExponentAndDigits(max_exponent, digits);
+  static inline constexpr const bool is_iec559 = false;
+  static inline constexpr const bool has_infinity = false;
+  static inline constexpr const bool has_signaling_NaN = false;
+  // NOLINTEND
+
+  static constexpr float8_e4m3fnuz min() {
+    return float8_e4m3fnuz::FromRep(0x08);
+  }
+  static constexpr float8_e4m3fnuz lowest() {
+    return float8_e4m3fnuz::FromRep(0xFF);
+  }
+  static constexpr float8_e4m3fnuz max() {
+    return float8_e4m3fnuz::FromRep(0x7F);
+  }
+  static constexpr float8_e4m3fnuz epsilon() {
+    return float8_e4m3fnuz::FromRep((-kMantissaBits + kExponentBias)
+                                    << kMantissaBits);
+  }
+  static constexpr float8_e4m3fnuz round_error() {
+    return float8_e4m3fnuz::FromRep((-1 + kExponentBias) << kMantissaBits);
+  }
+  static constexpr float8_e4m3fnuz infinity() {
+    return float8_e4m3fnuz::FromRep(0x80);
+  }
+  // NaN.
+  static constexpr float8_e4m3fnuz quiet_NaN() {
+    return float8_e4m3fnuz::FromRep(0x80);
+  }
+  static constexpr float8_e4m3fnuz signaling_NaN() {
+    return float8_e4m3fnuz::FromRep(0x80);
+  }
+  static constexpr float8_e4m3fnuz denorm_min() {
+    return float8_e4m3fnuz::FromRep(0x01);
+  }
+};
+
+struct numeric_limits_float8_e5m2 : public numeric_limits_float8_base {
+ private:
+  static inline constexpr const int kExponentBias = 15;
+  static inline constexpr const int kMantissaBits = 2;
+
+ public:
+  // NOLINTBEGIN: these names must match std::numeric_limits.
+  static inline constexpr const int digits = kMantissaBits + 1;
+  static inline constexpr const int digits10 = Digits10FromDigits(digits);
+  static inline constexpr const int max_digits10 =
+      MaxDigits10FromDigits(digits);
+  static inline constexpr const int min_exponent = (1 - kExponentBias) + 1;
+  static inline constexpr const int min_exponent10 =
+      MinExponent10FromMinExponent(min_exponent);
+  static inline constexpr const int max_exponent = 0b11111 - kExponentBias;
+  static inline constexpr const int max_exponent10 =
+      MaxExponent10FromMaxExponentAndDigits(max_exponent, digits);
+  static inline constexpr const bool is_iec559 = true;
+  static inline constexpr const bool has_infinity = true;
+  static inline constexpr const bool has_signaling_NaN = true;
+  // NOLINTEND
+
+  // 1.0 * 2^(0b00001 - 15) = 1.0 * 2^-14 = 0.00006103515625
+  static constexpr float8_e5m2 min() {
+    return float8_e5m2::FromRep(1 << kMantissaBits);
+  }
+  // -(1 + 0b11 * 2^-2) * 2^(0b11110 - 15) = -1.75 * 2^15 = -57344
+  static constexpr float8_e5m2 lowest() {
+    return float8_e5m2::FromRep(0b1'11110'11);
+  }
+  // (1 + 0b11 * 2^-2) * 2^(0b11110 - 15) = 1.75 * 2^15 = 57344
+  static constexpr float8_e5m2 max() {
+    return float8_e5m2::FromRep(0b0'11110'11);
+  }
+  // 1.0 * 2^-2 = 0.25
+  static constexpr float8_e5m2 epsilon() {
+    return float8_e5m2::FromRep((-kMantissaBits + kExponentBias)
+                                << kMantissaBits);
+  }
+  // 1.0 * 2^-1 = 0.5
+  static constexpr float8_e5m2 round_error() {
+    return float8_e5m2::FromRep((-1 + kExponentBias) << kMantissaBits);
+  }
+  static constexpr float8_e5m2 infinity() {
+    return float8_e5m2::FromRep(0b0'11111'00);
+  }
+  static constexpr float8_e5m2 quiet_NaN() {
+    // IEEE 754-2019 6.2.1: "All binary NaN bit strings have the sign bit S set
+    // to 0 or 1 and all the bits of the biased exponent field E set to 1
+    // (see 3.4). A quiet NaN bit string should be encoded with the first bit
+    // (d1) of the trailing significand field T being 1."
+    return float8_e5m2::FromRep(0b0'11111'10);
+  }
+  static constexpr float8_e5m2 signaling_NaN() {
+    // IEEE 754-2019 6.2.1: "A signaling NaN bit string should be encoded with
+    // the first bit of the trailing significand field being 0."
+    return float8_e5m2::FromRep(0b0'11111'01);
+  }
+  // 1.0 * 2^(-15 - 2 + 1) = 1.0 * 2^-16 = 0.0000152587890625
+  static constexpr float8_e5m2 denorm_min() {
+    return float8_e5m2::FromRep(0b0'00000'01);
+  }
+};
+
+struct numeric_limits_float8_e5m2fnuz : public numeric_limits_float8_base {
+ private:
+  static inline constexpr const int kExponentBias = 16;
+  static inline constexpr const int kMantissaBits = 2;
+
+ public:
+  // NOLINTBEGIN: these names must match std::numeric_limits.
+  static inline constexpr const int digits = kMantissaBits + 1;
+  static inline constexpr const int digits10 = Digits10FromDigits(digits);
+  static inline constexpr const int max_digits10 =
+      MaxDigits10FromDigits(digits);
+  static inline constexpr const int min_exponent = (1 - kExponentBias) + 1;
+  static inline constexpr const int min_exponent10 =
+      MinExponent10FromMinExponent(min_exponent);
+  static inline constexpr const int max_exponent =
+      (0b11111 - kExponentBias) + 1;
+  static inline constexpr const int max_exponent10 =
+      MaxExponent10FromMaxExponentAndDigits(max_exponent, digits);
+  static inline constexpr const bool is_iec559 = false;
+  static inline constexpr const bool has_infinity = false;
+  static inline constexpr const bool has_signaling_NaN = false;
+  // NOLINTEND
+
+  static constexpr float8_e5m2fnuz min() {
+    return float8_e5m2fnuz::FromRep(0x04);
+  }
+  static constexpr float8_e5m2fnuz lowest() {
+    return float8_e5m2fnuz::FromRep(0xFF);
+  }
+  static constexpr float8_e5m2fnuz max() {
+    return float8_e5m2fnuz::FromRep(0x7F);
+  }
+  static constexpr float8_e5m2fnuz epsilon() {
+    return float8_e5m2fnuz::FromRep((-kMantissaBits + kExponentBias)
+                                    << kMantissaBits);
+  }
+  static constexpr float8_e5m2fnuz round_error() {
+    return float8_e5m2fnuz::FromRep((-1 + kExponentBias) << kMantissaBits);
+  }
+  static constexpr float8_e5m2fnuz infinity() {
+    return float8_e5m2fnuz::FromRep(0x80);
+  }  // NaN.
+  static constexpr float8_e5m2fnuz quiet_NaN() {
+    return float8_e5m2fnuz::FromRep(0x80);
+  }
+  static constexpr float8_e5m2fnuz signaling_NaN() {
+    return float8_e5m2fnuz::FromRep(0x80);
+  }
+  static constexpr float8_e5m2fnuz denorm_min() {
+    return float8_e5m2fnuz::FromRep(0x01);
+  }
+};
+
+struct numeric_limits_float8_e8m0fnu : public numeric_limits_float8_base {
+ private:
+  static inline constexpr const int kExponentBias = 127;
+  static inline constexpr const int kMantissaBits = 0;
+
+ public:
+  // NOLINTBEGIN: these names must match std::numeric_limits.
+  static inline constexpr const bool is_signed = false;
+  static inline constexpr const std::float_denorm_style has_denorm =
+      std::denorm_absent;
+  static inline constexpr const int digits = kMantissaBits + 1;
+  static inline constexpr const int digits10 = Digits10FromDigits(digits);
+  static inline constexpr const int max_digits10 =
+      MaxDigits10FromDigits(digits);
+  // 2**-127 smallest valid normalized value..
+  static inline constexpr const int min_exponent = -kExponentBias + 1;
+  static inline constexpr const int min_exponent10 =
+      MinExponent10FromMinExponent(min_exponent);
+  // 128 encoding using for NaN
+  static inline constexpr const int max_exponent = kExponentBias + 1;
+  static inline constexpr const int max_exponent10 =
+      MaxExponent10FromMaxExponentAndDigits(max_exponent, digits);
+  static inline constexpr const bool is_iec559 = false;
+  static inline constexpr const bool has_infinity = false;
+  static inline constexpr const bool has_signaling_NaN = false;
+  // NOLINTEND
+
+  static constexpr float8_e8m0fnu min() {
+    return float8_e8m0fnu::FromRep(0x00);
+  }
+  static constexpr float8_e8m0fnu lowest() {
+    return float8_e8m0fnu::FromRep(0x00);
+  }
+  static constexpr float8_e8m0fnu max() {
+    return float8_e8m0fnu::FromRep(0xfe);
+  }
+  static constexpr float8_e8m0fnu epsilon() {
+    return float8_e8m0fnu::FromRep((-kMantissaBits + kExponentBias)
+                                   << kMantissaBits);
+  }
+  static constexpr float8_e8m0fnu round_error() {
+    return float8_e8m0fnu::FromRep((-1 + kExponentBias) << kMantissaBits);
+  }
+  static constexpr float8_e8m0fnu infinity() {
+    return float8_e8m0fnu::FromRep(0xFF);
+  }  // NaN.
+  static constexpr float8_e8m0fnu quiet_NaN() {
+    return float8_e8m0fnu::FromRep(0xFF);
+  }
+  static constexpr float8_e8m0fnu signaling_NaN() {
+    return float8_e8m0fnu::FromRep(0xFF);
+  }
+  static constexpr float8_e8m0fnu denorm_min() {
+    // No denorm => smallest value.
+    return float8_e8m0fnu::FromRep(0x00);
+  }
+};
+
+}  // namespace float8_internal
+}  // namespace ml_dtypes
+
+namespace std {
+// Standard-library overrides.  Note that these are picked up by Eigen as well.
+template <>
+struct numeric_limits<ml_dtypes::float8_internal::float8_e3m4>
+    : public ml_dtypes::float8_internal::numeric_limits_float8_e3m4 {};
+
+template <>
+struct numeric_limits<ml_dtypes::float8_internal::float8_e4m3>
+    : public ml_dtypes::float8_internal::numeric_limits_float8_e4m3 {};
+
+template <>
+struct numeric_limits<ml_dtypes::float8_internal::float8_e4m3fn>
+    : public ml_dtypes::float8_internal::numeric_limits_float8_e4m3fn {};
+
+template <>
+struct numeric_limits<ml_dtypes::float8_internal::float8_e4m3b11fnuz>
+    : public ml_dtypes::float8_internal::numeric_limits_float8_e4m3b11fnuz {};
+
+template <>
+struct numeric_limits<ml_dtypes::float8_internal::float8_e4m3fnuz>
+    : public ml_dtypes::float8_internal::numeric_limits_float8_e4m3fnuz {};
+
+template <>
+struct numeric_limits<ml_dtypes::float8_internal::float8_e5m2>
+    : public ml_dtypes::float8_internal::numeric_limits_float8_e5m2 {};
+
+template <>
+struct numeric_limits<ml_dtypes::float8_internal::float8_e5m2fnuz>
+    : public ml_dtypes::float8_internal::numeric_limits_float8_e5m2fnuz {};
+
+template <>
+struct numeric_limits<ml_dtypes::float8_internal::float8_e8m0fnu>
+    : public ml_dtypes::float8_internal::numeric_limits_float8_e8m0fnu {};
+}  // namespace std
+
+namespace ml_dtypes {
+namespace float8_internal {
+
+constexpr inline float8_e3m4 abs(const float8_e3m4& a) {
+  return float8_e3m4::FromRep(a.rep() & 0b0'111'1111);
+}
+
+constexpr inline bool(isnan)(const float8_e3m4& a) {
+  return abs(a).rep() > std::numeric_limits<float8_e3m4>::infinity().rep();
+}
+
+constexpr inline float8_e4m3 abs(const float8_e4m3& a) {
+  return float8_e4m3::FromRep(a.rep() & 0b0'1111'111);
+}
+
+constexpr inline bool(isnan)(const float8_e4m3& a) {
+  return abs(a).rep() > std::numeric_limits<float8_e4m3>::infinity().rep();
+}
+
+// Free-functions for use with ADL and in Eigen.
+constexpr inline float8_e4m3fn abs(const float8_e4m3fn& a) {
+  return float8_e4m3fn::FromRep(a.rep() & 0b0'1111'111);
+}
+
+constexpr inline bool(isnan)(const float8_e4m3fn& a) {
+  return abs(a).rep() == std::numeric_limits<float8_e4m3fn>::quiet_NaN().rep();
+}
+
+constexpr inline float8_e4m3b11fnuz abs(const float8_e4m3b11fnuz& a) {
+  return (a.rep() & 0b0'1111'111) == 0
+             ? float8_e4m3b11fnuz::FromRep(a.rep())
+             : float8_e4m3b11fnuz::FromRep(a.rep() & 0b0'1111'111);
+}
+
+constexpr inline bool(isnan)(const float8_e4m3b11fnuz& a) {
+  return a.rep() == std::numeric_limits<float8_e4m3b11fnuz>::quiet_NaN().rep();
+}
+
+constexpr inline float8_e4m3fnuz abs(const float8_e4m3fnuz& a) {
+  return (a.rep() & 0x7F) == 0 ? float8_e4m3fnuz::FromRep(a.rep())
+                               : float8_e4m3fnuz::FromRep(a.rep() & 0x7F);
+}
+
+constexpr inline bool(isnan)(const float8_e4m3fnuz& a) {
+  return abs(a).rep() ==
+         std::numeric_limits<float8_e4m3fnuz>::quiet_NaN().rep();
+}
+
+constexpr inline float8_e5m2 abs(const float8_e5m2& a) {
+  return float8_e5m2::FromRep(a.rep() & 0b0'11111'11);
+}
+
+constexpr inline bool(isnan)(const float8_e5m2& a) {
+  return abs(a).rep() > std::numeric_limits<float8_e5m2>::infinity().rep();
+}
+
+constexpr inline float8_e5m2fnuz abs(const float8_e5m2fnuz& a) {
+  return (a.rep() & 0x7F) == 0 ? float8_e5m2fnuz::FromRep(a.rep())
+                               : float8_e5m2fnuz::FromRep(a.rep() & 0x7F);
+}
+
+constexpr inline bool(isnan)(const float8_e5m2fnuz& a) {
+  return a.rep() == 0x80;
+}
+
+constexpr inline float8_e8m0fnu abs(const float8_e8m0fnu& a) { return a; }
+
+constexpr inline bool(isnan)(const float8_e8m0fnu& a) {
+  return a.rep() == 0xff;
+}
+
+template <typename Float8>
+constexpr inline bool(isinf)(const float8_base<Float8>& a) {
+  if constexpr (std::numeric_limits<Float8>::has_infinity) {
+    return abs(a.derived()).rep() ==
+           std::numeric_limits<Float8>::infinity().rep();
+  } else {
+    // No inf representation.
+    return false;
+  }
+}
+
+template <typename Float8>
+constexpr inline bool(isfinite)(const float8_base<Float8>& a) {
+  return !isnan(a.derived()) && !isinf(a.derived());
+}
+
+template <typename Float8>
+std::ostream& operator<<(std::ostream& os, const float8_base<Float8>& f8) {
+  os << static_cast<float>(f8.derived());
+  return os;
+}
+
+//==============================================================================
+// Inline conversion routines between float8 and other types.
+//==============================================================================
+
+template <typename T>
+bool constexpr IsPowerOfTwo(T x) {
+  return (x != 0) && ((x & (x - 1)) == 0);
+}
+// Helper for getting a bytes size which is a power of two.
+template <int Size>
+struct NextPowerOfTwo {
+  static constexpr int value = Size;
+};
+template <>
+struct NextPowerOfTwo<3> {
+  static constexpr int value = 4;
+};
+template <>
+struct NextPowerOfTwo<5> {
+  static constexpr int value = 8;
+};
+template <>
+struct NextPowerOfTwo<6> {
+  static constexpr int value = 8;
+};
+template <>
+struct NextPowerOfTwo<7> {
+  static constexpr int value = 8;
+};
+
+// Helper for getting a bit representation provided a byte size.
+template <int kNumBytes>
+using GetUnsignedInteger =
+    typename Eigen::numext::get_integer_by_size<kNumBytes>::unsigned_type;
+
+// Converts between two floating-point types.
+template <typename From, typename To, bool kSaturate, bool kTruncate,
+          typename EnableIf = void>
+struct ConvertImpl;
+
+// Convert to same type.  We need explicit specializations for all combinations
+// of template parameters to avoid ambiguities.
+template <typename Scalar>
+struct IdentityConversion {
+  static EIGEN_DEVICE_FUNC inline Scalar run(Scalar from) { return from; }
+};
+
+template <typename Scalar, bool kSaturate, bool kTruncate>
+struct ConvertImpl<Scalar, Scalar, /*kSaturate=*/kSaturate,
+                   /*kTruncate=*/kTruncate>
+    : public IdentityConversion<Scalar> {};
+
+template <typename Float>
+struct TraitsBase {
+  using BitsType = GetUnsignedInteger<sizeof(Float)>;
+  static constexpr bool kIsSigned = std::numeric_limits<Float>::is_signed;
+  static constexpr bool kHasZero = true;
+
+  static constexpr int kBits = sizeof(Float) * CHAR_BIT;
+  static constexpr int kMantissaBits = Eigen::NumTraits<Float>::digits() - 1;
+  // Extra bit used in exponent for unsigned float.
+  static constexpr int kExponentBits =
+      kBits - kMantissaBits - static_cast<int>(kIsSigned);
+  static constexpr BitsType kExponentMask = ((BitsType{1} << kExponentBits) - 1)
+                                            << kMantissaBits;
+  static constexpr BitsType kMantissaMask = (BitsType{1} << kMantissaBits) - 1;
+  static constexpr int kExponentBias = (1 << (kExponentBits - 1)) - 1;
+};
+
+template <typename Float>
+struct Traits : public TraitsBase<Float> {};
+
+template <>
+struct Traits<float8_e4m3b11fnuz> : public TraitsBase<float8_e4m3b11fnuz> {
+  static constexpr int kExponentBias = 11;
+};
+
+template <>
+struct Traits<float8_e4m3fnuz> : public TraitsBase<float8_e4m3fnuz> {
+  using Base = TraitsBase<float8_e4m3fnuz>;
+  static constexpr int kExponentBias = Base::kExponentBias + 1;
+};
+
+template <>
+struct Traits<float8_e5m2fnuz> : public TraitsBase<float8_e5m2fnuz> {
+  using Base = TraitsBase<float8_e5m2fnuz>;
+  static constexpr int kExponentBias = Base::kExponentBias + 1;
+};
+
+template <>
+struct Traits<float8_e8m0fnu> : public TraitsBase<float8_e8m0fnu> {
+  using Base = TraitsBase<float8_e8m0fnu>;
+  // No zero in E8MO OCP MX format description.
+  static constexpr bool kHasZero = false;
+};
+
+template <typename Bits>
+constexpr inline Bits RoundBitsToNearestEven(Bits bits, int roundoff,
+                                             bool use_implicit_bit) {
+  // Round to nearest even by adding a bias term.
+  // Consider a bit pattern
+  //   FFF...FLRTT...T,
+  // where bits RTT...T need to be rounded-off.  We add a bias term to the
+  // bit pattern s.t. a carry is introduced to round up only if
+  // - L is 1, R is 1, OR
+  // - L is 0, R is 1, any T is one.
+  // We do this by adding L to a bit pattern consisting of all T = 1.
+  //
+  // When rounding to zero mantissa (E8M0 type), the L bit is implicitly 1 (do
+  // not use the exponent bits for rounding). Add only the R bit in this case.
+  Bits bias = !use_implicit_bit
+                  ? ((bits >> roundoff) & 1) + (Bits{1} << (roundoff - 1)) - 1
+                  : Bits{1} << (roundoff - 1);
+  return bits + bias;
+}
+
+#if (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L)
+using std::countl_zero;
+#else
+static constexpr inline int countl_zero(uint64_t x) {
+  int zeroes = 60;
+  if (x >> 32) {
+    zeroes -= 32;
+    x >>= 32;
+  }
+  if (x >> 16) {
+    zeroes -= 16;
+    x >>= 16;
+  }
+  if (x >> 8) {
+    zeroes -= 8;
+    x >>= 8;
+  }
+  if (x >> 4) {
+    zeroes -= 4;
+    x >>= 4;
+  }
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+}
+static constexpr inline int countl_zero(uint32_t x) {
+  int zeroes = 28;
+  if (x >> 16) {
+    zeroes -= 16;
+    x >>= 16;
+  }
+  if (x >> 8) {
+    zeroes -= 8;
+    x >>= 8;
+  }
+  if (x >> 4) {
+    zeroes -= 4;
+    x >>= 4;
+  }
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+}
+static constexpr inline int countl_zero(uint16_t x) {
+  int zeroes = 12;
+  if (x >> 8) {
+    zeroes -= 8;
+    x >>= 8;
+  }
+  if (x >> 4) {
+    zeroes -= 4;
+    x >>= 4;
+  }
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+}
+static constexpr inline int countl_zero(uint8_t x) {
+  int zeroes = 4;
+  if (x >> 4) {
+    zeroes -= 4;
+    x >>= 4;
+  }
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+}
+#endif
+
+template <typename From, typename To, bool kSaturate, bool kTruncate>
+struct ConvertImpl<From, To, kSaturate, kTruncate,
+                   std::enable_if_t<!std::is_same_v<From, To>>> {
+  using FromTraits = Traits<From>;
+  using FromBits = typename FromTraits::BitsType;
+  static constexpr bool kFromIsSigned = FromTraits::kIsSigned;
+  static constexpr bool kFromHasZero = FromTraits::kHasZero;
+  static constexpr int kFromBits = FromTraits::kBits;
+  static constexpr int kFromMantissaBits = FromTraits::kMantissaBits;
+  static constexpr int kFromExponentBits = FromTraits::kExponentBits;
+  static constexpr int kFromExponentBias = FromTraits::kExponentBias;
+  static constexpr FromBits kFromExponentMask = FromTraits::kExponentMask;
+
+  using ToTraits = Traits<To>;
+  using ToBits = typename ToTraits::BitsType;
+  static constexpr bool kToIsSigned = ToTraits::kIsSigned;
+  static constexpr bool kToHasZero = ToTraits::kHasZero;
+  static constexpr int kToBits = ToTraits::kBits;
+  static constexpr int kToMantissaBits = ToTraits::kMantissaBits;
+  static constexpr int kToExponentBits = ToTraits::kExponentBits;
+  static constexpr int kToExponentBias = ToTraits::kExponentBias;
+  static constexpr ToBits kToExponentMask = ToTraits::kExponentMask;
+
+  // `WideBits` is wide enough to accommodate the largest exponent and mantissa
+  // in either `From` or `To`.
+  static constexpr int kWideBits =
+      (std::max(kToMantissaBits, kFromMantissaBits)) +  // Max significand.
+      (std::max(kToExponentBits, kFromExponentBits));   // Max exponent.
+  static constexpr int kWideBytesRaw = (kWideBits + (CHAR_BIT - 1)) / CHAR_BIT;
+  // Need a power of two (i.e. not 3 bytes).
+  static constexpr int kWideBytes = NextPowerOfTwo<kWideBytesRaw>::value;
+
+  using WideBits = GetUnsignedInteger<kWideBytes>;
+  static_assert(!std::is_void_v<WideBits>,
+                "`WideBits` type can not be void type.");
+
+  static constexpr int kExponentOffset = kToExponentBias - kFromExponentBias;
+  static constexpr int kDigitShift = kToMantissaBits - kFromMantissaBits;
+
+  static EIGEN_DEVICE_FUNC inline To run(From from) {
+    // Shift bits to destination type, without sign bit.
+    const bool from_sign_bit =
+        Eigen::numext::bit_cast<FromBits>(from) >> (kFromBits - 1) &&
+        kFromIsSigned;
+    const FromBits from_bits =
+        Eigen::numext::bit_cast<FromBits>(Eigen::numext::abs(from));
+
+    // Special values, preserving sign.
+    if (Eigen::numext::isinf(from)) {
+      return from_sign_bit ? -Eigen::NumTraits<To>::infinity()
+                           : Eigen::NumTraits<To>::infinity();
+    }
+    if (Eigen::numext::isnan(from)) {
+      return from_sign_bit ? -Eigen::NumTraits<To>::quiet_NaN()
+                           : Eigen::NumTraits<To>::quiet_NaN();
+    }
+    // Dealing with zero, when `From` has one.
+    if (from_bits == 0 && kFromHasZero) {
+      if constexpr (kToHasZero) {
+        // Keep the sign, if `To` supports it.
+        return from_sign_bit && kToIsSigned ? -To{} : To{};
+      } else {
+        return kSaturate ? std::numeric_limits<To>::denorm_min()
+                         : Eigen::NumTraits<To>::quiet_NaN();
+      }
+    }
+    // `To` unsigned floating format: NaN or saturate.
+    if constexpr (!kToIsSigned && kFromIsSigned) {
+      if (from_sign_bit) {
+        return kSaturate ? std::numeric_limits<To>::lowest()
+                         : Eigen::NumTraits<To>::quiet_NaN();
+      }
+    }
+
+    const int biased_from_exponent = from_bits >> kFromMantissaBits;
+    const bool to_zero_mantissa = kToMantissaBits == 0;
+
+    // `To` supports more exponents near zero which means that some subnormal
+    // values in `From` may become normal.
+    if constexpr (std::numeric_limits<To>::min_exponent <
+                  std::numeric_limits<From>::min_exponent) {
+      if (biased_from_exponent == 0) {
+        // Subnormals.
+        WideBits bits = from_bits;
+
+        // Determine exponent in target type.
+        const int msb =
+            sizeof(from_bits) * CHAR_BIT - countl_zero(from_bits) - 1;
+        const int normalization_factor = kFromMantissaBits - msb;
+        const int biased_exponent = kExponentOffset - normalization_factor + 1;
+        if (biased_exponent <= 0) {
+          // Result is subnormal.  Adjust the subnormal bits to account for
+          // the difference in exponent bias.
+          if constexpr (kExponentOffset < sizeof(WideBits) * CHAR_BIT) {
+            bits <<= kExponentOffset;
+          }
+        } else {
+          // Result is normal. Shift the mantissa to account for the number of
+          // leading zero digits, and clear the hidden bit.
+          bits <<= normalization_factor;
+          bits &= ~(WideBits{1} << kFromMantissaBits);
+          // Insert the exponent bits.
+          bits |= static_cast<WideBits>(biased_exponent) << kFromMantissaBits;
+        }
+
+        // Truncate/round mantissa if necessary.
+        if constexpr (kDigitShift >= 0) {
+          bits <<= kDigitShift;
+        } else {
+          if constexpr (!kTruncate) {
+            // When converting float to e8m0, the bits represent a denormal,
+            // so don't use the implicit mantissa bit for rounding.
+            bits = RoundBitsToNearestEven(
+                bits, -kDigitShift, to_zero_mantissa && kExponentOffset != 0);
+          }
+          bits >>= -kDigitShift;
+        }
+        To to = Eigen::numext::bit_cast<To>(static_cast<ToBits>(bits));
+        return from_sign_bit ? -to : to;
+      }
+    }
+    // `To` supports fewer exponents near zero which means that some values in
+    // `From` may become subnormal.
+    if constexpr (std::numeric_limits<To>::min_exponent >
+                  std::numeric_limits<From>::min_exponent) {
+      const int unbiased_exponent = biased_from_exponent - kFromExponentBias;
+      const int biased_to_exponent = unbiased_exponent + kToExponentBias;
+      // Subnormals and zero.
+      if (biased_to_exponent <= 0) {
+        // Round and shift mantissa down.
+        // Zero exponent valid if From has no zero representation.
+        FromBits from_has_leading_one =
+            (biased_from_exponent > 0 || !kFromHasZero ? 1 : 0);
+        int exponent_shift =
+            -kDigitShift - biased_to_exponent + from_has_leading_one;
+        // Insert the implicit leading 1 bit on the mantissa for normalized
+        // inputs.
+        FromBits rounded_from_bits =
+            (from_bits & FromTraits::kMantissaMask) |
+            (from_has_leading_one << kFromMantissaBits);
+        ToBits bits = 0;
+        if (exponent_shift > 0) {
+          // To avoid UB, limit rounding and shifting to the full mantissa plus
+          // leading 1.
+          if (exponent_shift <= kFromMantissaBits + 1) {
+            if constexpr (!kTruncate) {
+              // NOTE: we need to round again from the original from_bits,
+              // otherwise the lower precision bits may already be lost.  There
+              // is an edge-case where rounding to a normalized value would
+              // normally round down, but for a subnormal, we need to round up.
+              rounded_from_bits = RoundBitsToNearestEven(rounded_from_bits,
+                                                         exponent_shift, false);
+            }
+            bits = rounded_from_bits >> exponent_shift;
+          }
+        } else {
+          bits = rounded_from_bits << -exponent_shift;
+        }
+        // Insert sign and return.
+        To to = Eigen::numext::bit_cast<To>(bits);
+        return from_sign_bit ? -to : to;
+      }
+    }
+
+    // Round the mantissa if it is shrinking.
+    WideBits rounded_from_bits = from_bits;
+    if constexpr (kDigitShift < 0) {
+      if constexpr (!kTruncate) {
+        rounded_from_bits =
+            RoundBitsToNearestEven(from_bits, -kDigitShift, to_zero_mantissa);
+      }
+      // Zero-out tail bits.
+      rounded_from_bits &= ~((WideBits{1} << (-kDigitShift)) - 1);
+    }
+
+    // Re-bias the exponent.
+    rounded_from_bits += static_cast<WideBits>(kExponentOffset)
+                         << kFromMantissaBits;
+
+    ToBits bits;
+    // Check for overflows by aligning the significands. We always align the
+    // narrower significand to the wider significand.
+    const WideBits kToHighestRep =
+        Eigen::numext::bit_cast<ToBits>(Eigen::NumTraits<To>::highest());
+    WideBits aligned_highest{kToHighestRep};
+    if constexpr (kDigitShift < 0) {
+      aligned_highest <<= -kDigitShift;
+      // Shift down, all dropped bits should already be zero.
+      bits = static_cast<ToBits>(rounded_from_bits >> -kDigitShift);
+    } else if constexpr (kDigitShift >= 0) {
+      // Shift up, inserting zeros in the newly created digits.
+      rounded_from_bits <<= kDigitShift;
+      bits = static_cast<ToBits>(rounded_from_bits);
+    }
+
+    To to = Eigen::numext::bit_cast<To>(bits);
+    // `From` supports larger values than `To`, we may overflow.
+    if constexpr (std::make_pair(std::numeric_limits<To>::max_exponent,
+                                 std::numeric_limits<To>::digits) <
+                  std::make_pair(std::numeric_limits<From>::max_exponent,
+                                 std::numeric_limits<From>::digits)) {
+      if (rounded_from_bits > aligned_highest) {
+        // Overflowed values map to highest or infinity depending on kSaturate.
+        to = kSaturate ? Eigen::NumTraits<To>::highest()
+                       : Eigen::NumTraits<To>::infinity();
+      }
+    }
+    // Insert sign bit.
+    return from_sign_bit ? -to : to;
+  }
+};
+
+// Saturation has no impact when casting e4m3fn to e5m2.
+template <bool kTruncate>
+struct ConvertImpl<float8_e4m3fn, float8_e5m2, true, kTruncate> {
+  static EIGEN_DEVICE_FUNC inline float8_e5m2 run(float8_e4m3fn from) {
+    return ConvertImpl<float8_e4m3fn, float8_e5m2, false, kTruncate>::run(from);
+  }
+};
+
+template <bool kSaturate, bool kTruncate>
+struct ConvertImpl<Eigen::half, float8_e5m2, kSaturate, kTruncate> {
+  static EIGEN_DEVICE_FUNC inline float8_e5m2 run(Eigen::half from) {
+    uint16_t from_bits = Eigen::numext::bit_cast<uint16_t>(from);
+
+    // Special values (Inf or NaN).
+    uint16_t abs_bits = from_bits & 0x7FFF;
+    if (abs_bits == 0x7C00) {
+      return float8_e5m2::FromRep(from_bits >> 8);
+    } else if (abs_bits > 0x7C00) {
+      // IEEE 754-2019 6.2.1: "A quiet NaN bit string should be encoded with the
+      // first bit (d1) of the trailing significand field T being 1."
+      // IEEE 754-2019 6.2.3: "Conversion of a quiet NaN to a floating-point
+      // format of the same or a different radix that does not allow the payload
+      // to be preserved, shall return a quiet NaN [...]"
+      return float8_e5m2::FromRep((from_bits >> 8) | 0b0'00000'10);
+    }
+
+    if constexpr (!kTruncate) {
+      from_bits = RoundBitsToNearestEven(from_bits, 8, false);
+      // Rounding can cause an overflow to infinity. Clamp to the largest finite
+      // value if saturation is requested.
+      if constexpr (kSaturate) {
+        const float8_e5m2 kHighest = Eigen::NumTraits<float8_e5m2>::highest();
+        if ((from_bits & 0x7F00) > static_cast<uint16_t>(kHighest.rep()) << 8) {
+          const bool from_sign_bit = from_bits >> 15;
+          return from_sign_bit ? -kHighest : kHighest;
+        }
+      }
+    }
+    return float8_e5m2::FromRep(from_bits >> 8);
+  }
+};
+
+// Direct casts of e5m2 to Eigen::half simply shifts bits over.
+template <bool kSaturate, bool kTruncate>
+struct ConvertImpl<float8_e5m2, Eigen::half, kSaturate, kTruncate> {
+  static EIGEN_DEVICE_FUNC inline Eigen::half run(float8_e5m2 from) {
+    return Eigen::numext::bit_cast<Eigen::half>(
+        static_cast<uint16_t>(static_cast<uint16_t>(from.rep()) << 8));
+  }
+};
+
+template <typename Derived>
+template <bool kSaturate, bool kTruncate, typename From>
+EIGEN_DEVICE_FUNC Derived float8_base<Derived>::ConvertFrom(const From from) {
+  // We are rounding long double -> float -> float8. This can induce
+  // double-rounding which may alter the results. We can correct for this using
+  // a trick explained in: Boldo, Sylvie, and Guillaume Melquiond. "When double
+  // rounding is odd." 17th IMACS World Congress. 2005.
+  if constexpr (std::is_floating_point_v<From> &&
+                sizeof(From) > sizeof(double)) {
+    // binary64, float80, binary128, etc. end up here.
+    static_assert(std::numeric_limits<From>::digits >=
+                  std::numeric_limits<float>::digits + 2);
+    static_assert(std::numeric_limits<float>::min_exponent >=
+                  std::numeric_limits<From>::min_exponent + 2);
+    static_assert(std::numeric_limits<float>::is_iec559);
+    static_assert(std::numeric_limits<float>::radix == 2);
+    const bool is_negative = std::signbit(from);
+    const From abs_wide = std::fabs(from);
+    float abs_narrow = static_cast<float>(abs_wide);
+    const From abs_narrow_as_wide = static_cast<From>(abs_narrow);
+
+    uint32_t narrow_bits = Eigen::numext::bit_cast<uint32_t>(abs_narrow);
+    // We can keep the narrow value as-is if narrowing was exact (no rounding
+    // error), the wide value was NaN (the narrow value is also NaN and should
+    // be preserved) or if we rounded to the odd value.
+    const bool keep_narrow = (abs_wide == abs_narrow_as_wide) ||
+                             std::isnan(abs_narrow) || (narrow_bits & 1);
+    // We morally performed a round-down if `abs_narrow` is smaller than
+    // `abs_wide`.
+    const bool narrow_is_rd = abs_wide > abs_narrow_as_wide;
+    // If the narrow value is odd or exact, pick it.
+    // Otherwise, narrow is even and corresponds to either the rounded-up or
+    // rounded-down value. If narrow is the rounded-down value, we want the
+    // rounded-up value as it will be odd.
+    narrow_bits += keep_narrow ? 0 : narrow_is_rd ? 1 : -1;
+    abs_narrow = Eigen::numext::bit_cast<float>(narrow_bits);
+    return ConvertImpl<float, Derived, kSaturate, kTruncate>::run(
+        is_negative ? -abs_narrow : abs_narrow);
+  } else {
+    return ConvertImpl<From, Derived, kSaturate, kTruncate>::run(from);
+  }
+}
+
+template <typename Derived>
+template <typename To, bool kSaturate, bool kTruncate>
+EIGEN_DEVICE_FUNC To float8_base<Derived>::ConvertTo(Derived from) {
+  return ConvertImpl<Derived, To, kSaturate, kTruncate>::run(from);
+}
+
+}  // namespace float8_internal
+
+// Exported types.
+using float8_e3m4 = float8_internal::float8_e3m4;
+using float8_e4m3 = float8_internal::float8_e4m3;
+using float8_e4m3fn = float8_internal::float8_e4m3fn;
+using float8_e4m3fnuz = float8_internal::float8_e4m3fnuz;
+using float8_e4m3b11fnuz = float8_internal::float8_e4m3b11fnuz;
+using float8_e5m2 = float8_internal::float8_e5m2;
+using float8_e5m2fnuz = float8_internal::float8_e5m2fnuz;
+using float8_e8m0fnu = float8_internal::float8_e8m0fnu;
+
+}  // namespace ml_dtypes
+
+// Work-around for isinf/isnan/isfinite issue on aarch64.
+namespace Eigen {
+namespace internal {
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isinf_impl<ml_dtypes::float8_e3m4>(
+    const ml_dtypes::float8_e3m4& x) {
+  return ml_dtypes::float8_internal::isinf(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isinf_impl<ml_dtypes::float8_e4m3>(
+    const ml_dtypes::float8_e4m3& x) {
+  return ml_dtypes::float8_internal::isinf(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isinf_impl<ml_dtypes::float8_e4m3fn>(
+    const ml_dtypes::float8_e4m3fn& x) {
+  return ml_dtypes::float8_internal::isinf(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isinf_impl<ml_dtypes::float8_e4m3b11fnuz>(
+    const ml_dtypes::float8_e4m3b11fnuz& x) {
+  return ml_dtypes::float8_internal::isinf(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isinf_impl<ml_dtypes::float8_e4m3fnuz>(
+    const ml_dtypes::float8_e4m3fnuz& x) {
+  return ml_dtypes::float8_internal::isinf(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isinf_impl<ml_dtypes::float8_e5m2>(
+    const ml_dtypes::float8_e5m2& x) {
+  return ml_dtypes::float8_internal::isinf(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isinf_impl<ml_dtypes::float8_e5m2fnuz>(
+    const ml_dtypes::float8_e5m2fnuz& x) {
+  return ml_dtypes::float8_internal::isinf(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isinf_impl<ml_dtypes::float8_e8m0fnu>(
+    const ml_dtypes::float8_e8m0fnu& x) {
+  return ml_dtypes::float8_internal::isinf(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isnan_impl<ml_dtypes::float8_e3m4>(
+    const ml_dtypes::float8_e3m4& x) {
+  return ml_dtypes::float8_internal::isnan(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isnan_impl<ml_dtypes::float8_e4m3>(
+    const ml_dtypes::float8_e4m3& x) {
+  return ml_dtypes::float8_internal::isnan(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isnan_impl<ml_dtypes::float8_e4m3fn>(
+    const ml_dtypes::float8_e4m3fn& x) {
+  return ml_dtypes::float8_internal::isnan(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isnan_impl<ml_dtypes::float8_e4m3b11fnuz>(
+    const ml_dtypes::float8_e4m3b11fnuz& x) {
+  return ml_dtypes::float8_internal::isnan(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isnan_impl<ml_dtypes::float8_e4m3fnuz>(
+    const ml_dtypes::float8_e4m3fnuz& x) {
+  return ml_dtypes::float8_internal::isnan(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isnan_impl<ml_dtypes::float8_e5m2>(
+    const ml_dtypes::float8_e5m2& x) {
+  return ml_dtypes::float8_internal::isnan(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isnan_impl<ml_dtypes::float8_e5m2fnuz>(
+    const ml_dtypes::float8_e5m2fnuz& x) {
+  return ml_dtypes::float8_internal::isnan(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isnan_impl<ml_dtypes::float8_e8m0fnu>(
+    const ml_dtypes::float8_e8m0fnu& x) {
+  return ml_dtypes::float8_internal::isnan(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isfinite_impl<ml_dtypes::float8_e3m4>(
+    const ml_dtypes::float8_e3m4& x) {
+  return ml_dtypes::float8_internal::isfinite(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isfinite_impl<ml_dtypes::float8_e4m3>(
+    const ml_dtypes::float8_e4m3& x) {
+  return ml_dtypes::float8_internal::isfinite(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isfinite_impl<ml_dtypes::float8_e4m3fn>(
+    const ml_dtypes::float8_e4m3fn& x) {
+  return ml_dtypes::float8_internal::isfinite(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isfinite_impl<ml_dtypes::float8_e4m3b11fnuz>(
+    const ml_dtypes::float8_e4m3b11fnuz& x) {
+  return ml_dtypes::float8_internal::isfinite(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isfinite_impl<ml_dtypes::float8_e4m3fnuz>(
+    const ml_dtypes::float8_e4m3fnuz& x) {
+  return ml_dtypes::float8_internal::isfinite(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isfinite_impl<ml_dtypes::float8_e5m2>(
+    const ml_dtypes::float8_e5m2& x) {
+  return ml_dtypes::float8_internal::isfinite(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isfinite_impl<ml_dtypes::float8_e5m2fnuz>(
+    const ml_dtypes::float8_e5m2fnuz& x) {
+  return ml_dtypes::float8_internal::isfinite(x);
+}
+
+template <>
+EIGEN_DEVICE_FUNC inline bool isfinite_impl<ml_dtypes::float8_e8m0fnu>(
+    const ml_dtypes::float8_e8m0fnu& x) {
+  return ml_dtypes::float8_internal::isfinite(x);
+}
+
+}  // namespace internal
+}  // namespace Eigen
+
+#endif  // ML_DTYPES_FLOAT8_H_
diff --git a/third_party/ml_dtypes/src/ml_dtypes/include/intn.h b/third_party/ml_dtypes/src/ml_dtypes/include/intn.h
new file mode 100644
index 0000000..e201fd97
--- /dev/null
+++ b/third_party/ml_dtypes/src/ml_dtypes/include/intn.h
@@ -0,0 +1,321 @@
+/* Copyright 2023 The ml_dtypes Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#ifndef ML_DTYPES_INTN_H_
+#define ML_DTYPES_INTN_H_
+
+#include <cstdint>
+#include <limits>
+#include <optional>
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+namespace ml_dtypes {
+
+// Stores the n-bit integer value in the low n bits of a byte.  The upper
+// bits are left unspecified and ignored.
+template <int N, typename UnderlyingTy>
+struct intN {
+ private:
+  UnderlyingTy v_;
+  using SignedUnderlyingTy = std::make_signed_t<UnderlyingTy>;
+  using UnsignedUnderlyingTy = std::make_unsigned_t<UnderlyingTy>;
+  static constexpr int kUnderlyingBits =
+      std::numeric_limits<UnsignedUnderlyingTy>::digits;
+
+  static_assert(
+      std::is_same_v<UnderlyingTy, uint8_t> ||
+          std::is_same_v<UnderlyingTy, int8_t>,
+      "The underyling type must be a signed or unsigned 8-bit integer.");
+
+  // Mask the upper bits.
+  static inline constexpr UnderlyingTy Mask(UnderlyingTy v) {
+    return static_cast<UnsignedUnderlyingTy>(
+               static_cast<UnsignedUnderlyingTy>(v) << (kUnderlyingBits - N)) >>
+           (kUnderlyingBits - N);
+  }
+
+  // Mask the upper bits and sign-extend for signed types.
+  static inline constexpr UnderlyingTy ExtendToFullWidth(UnderlyingTy v) {
+    return static_cast<UnderlyingTy>(static_cast<UnderlyingTy>(v)
+                                     << (kUnderlyingBits - N)) >>
+           (kUnderlyingBits - N);
+  }
+
+  // Casts to the corresponding UnderlyingTy value.
+  inline constexpr UnderlyingTy IntValue() const {
+    return ExtendToFullWidth(v_);
+  }
+
+ public:
+  constexpr intN() noexcept : v_(0) {}
+  constexpr intN(const intN& other) noexcept = default;
+  constexpr intN(intN&& other) noexcept = default;
+  constexpr intN& operator=(const intN& other) = default;
+  constexpr intN& operator=(intN&&) = default;
+
+  explicit constexpr intN(UnderlyingTy val) : v_(Mask(val)) {}
+  template <typename T>
+  explicit constexpr intN(T t) : intN(static_cast<UnderlyingTy>(t)) {}
+
+  using underlying_type = UnderlyingTy;
+  static constexpr int bits = N;
+  static constexpr int digits = std::is_signed_v<UnderlyingTy> ? N - 1 : N;
+  static constexpr intN highest() { return intN((1 << digits) - 1); }
+  static constexpr intN lowest() {
+    return std::is_signed_v<UnderlyingTy> ? intN(1) << digits : intN(0);
+  }
+
+  template <typename T>
+  explicit constexpr operator T() const {
+    return static_cast<T>(IntValue());
+  }
+  // NOLINTNEXTLINE(google-explicit-constructor)
+  constexpr operator std::optional<int64_t>() const {
+    return static_cast<int64_t>(IntValue());
+  }
+
+  constexpr intN operator-() const { return intN(-v_); }
+  constexpr intN operator+(const intN& other) const {
+    return intN(v_ + other.v_);
+  }
+  constexpr intN operator-(const intN& other) const {
+    return intN(v_ - other.v_);
+  }
+  constexpr intN operator*(const intN& other) const {
+    return intN(v_ * other.v_);
+  }
+  constexpr intN operator/(const intN& other) const {
+    return intN(IntValue() / other.IntValue());
+  }
+  constexpr intN operator%(const intN& other) const {
+    return intN((IntValue() % other.IntValue()));
+  }
+
+  constexpr intN operator&(const intN& other) const {
+    return intN(v_ & other.v_);
+  }
+  constexpr intN operator|(const intN& other) const {
+    return intN(v_ | other.v_);
+  }
+  constexpr intN operator^(const intN& other) const {
+    return intN(v_ ^ other.v_);
+  }
+  constexpr intN operator~() const { return intN(~v_); }
+  constexpr intN operator>>(int amount) const {
+    return intN(IntValue() >> amount);
+  }
+  constexpr intN operator<<(int amount) const { return intN(v_ << amount); }
+
+  constexpr bool operator==(const intN& other) const {
+    return Mask(v_) == Mask(other.v_);
+  }
+  constexpr bool operator!=(const intN& other) const {
+    return Mask(v_) != Mask(other.v_);
+  }
+  constexpr bool operator<(const intN& other) const {
+    return IntValue() < other.IntValue();
+  }
+  constexpr bool operator>(const intN& other) const {
+    return IntValue() > other.IntValue();
+  }
+  constexpr bool operator<=(const intN& other) const {
+    return IntValue() <= other.IntValue();
+  }
+  constexpr bool operator>=(const intN& other) const {
+    return IntValue() >= other.IntValue();
+  }
+
+  constexpr bool operator==(int64_t other) const { return IntValue() == other; }
+  constexpr bool operator!=(int64_t other) const { return IntValue() != other; }
+  constexpr bool operator<(int64_t other) const { return IntValue() < other; }
+  constexpr bool operator>(int64_t other) const { return IntValue() > other; }
+  constexpr bool operator<=(int64_t other) const { return IntValue() <= other; }
+  constexpr bool operator>=(int64_t other) const { return IntValue() >= other; }
+
+  friend constexpr bool operator==(int64_t a, const intN& b) {
+    return a == b.IntValue();
+  }
+  friend constexpr bool operator!=(int64_t a, const intN& b) {
+    return a != b.IntValue();
+  }
+  friend constexpr bool operator<(int64_t a, const intN& b) {
+    return a < b.IntValue();
+  }
+  friend constexpr bool operator>(int64_t a, const intN& b) {
+    return a > b.IntValue();
+  }
+  friend constexpr bool operator<=(int64_t a, const intN& b) {
+    return a <= b.IntValue();
+  }
+  friend constexpr bool operator>=(int64_t a, const intN& b) {
+    return a >= b.IntValue();
+  }
+
+  constexpr intN& operator++() {
+    v_ = Mask(v_ + 1);
+    return *this;
+  }
+
+  constexpr intN operator++(int) {
+    intN orig = *this;
+    this->operator++();
+    return orig;
+  }
+
+  constexpr intN& operator--() {
+    v_ = Mask(v_ - 1);
+    return *this;
+  }
+
+  constexpr intN operator--(int) {
+    intN orig = *this;
+    this->operator--();
+    return orig;
+  }
+
+  constexpr intN& operator+=(const intN& other) {
+    *this = *this + other;
+    return *this;
+  }
+  constexpr intN& operator-=(const intN& other) {
+    *this = *this - other;
+    return *this;
+  }
+  constexpr intN& operator*=(const intN& other) {
+    *this = *this * other;
+    return *this;
+  }
+  constexpr intN& operator/=(const intN& other) {
+    *this = *this / other;
+    return *this;
+  }
+  constexpr intN& operator%=(const intN& other) {
+    *this = *this % other;
+    return *this;
+  }
+  constexpr intN& operator&=(const intN& other) {
+    *this = *this & other;
+    return *this;
+  }
+  constexpr intN& operator|=(const intN& other) {
+    *this = *this | other;
+    return *this;
+  }
+  constexpr intN& operator^=(const intN& other) {
+    *this = *this ^ other;
+    return *this;
+  }
+  constexpr intN& operator>>=(int amount) {
+    *this = *this >> amount;
+    return *this;
+  }
+  constexpr intN& operator<<=(int amount) {
+    *this = *this << amount;
+    return *this;
+  }
+
+  friend ::std::ostream& operator<<(::std::ostream& os, const intN& num) {
+    os << static_cast<int16_t>(num);
+    return os;
+  }
+
+  std::string ToString() const {
+    std::ostringstream os;
+    os << static_cast<int16_t>(*this);
+    return os.str();
+  }
+};
+
+using int1 = intN<1, int8_t>;
+using int2 = intN<2, int8_t>;
+using uint1 = intN<1, uint8_t>;
+using uint2 = intN<2, uint8_t>;
+using int4 = intN<4, int8_t>;
+using uint4 = intN<4, uint8_t>;
+
+namespace internal {
+
+template <typename intN>
+struct intN_numeric_limits_base {
+  static inline constexpr const bool is_specialized = true;
+  static inline constexpr const bool is_integer = true;
+  static inline constexpr const bool is_exact = true;
+  static inline constexpr const bool has_infinity = false;
+  static inline constexpr const bool has_quiet_NaN = false;
+  static inline constexpr const bool has_signaling_NaN = false;
+  static inline constexpr const std::float_denorm_style has_denorm =
+      std::denorm_absent;
+  static inline constexpr const bool has_denorm_loss = false;
+  static inline constexpr const std::float_round_style round_style =
+      std::round_toward_zero;
+  static inline constexpr const bool is_iec559 = false;
+  static inline constexpr const bool is_bounded = true;
+  static inline constexpr const int max_digits10 = 0;  // Not used for integers.
+  static inline constexpr const int radix = 2;
+  static inline constexpr const int min_exponent = 0;
+  static inline constexpr const int min_exponent10 = 0;
+  static inline constexpr const int max_exponent = 0;
+  static inline constexpr const int max_exponent10 = 0;
+  static inline constexpr const bool traps = true;
+  static inline constexpr const bool tinyness_before = false;
+  static inline constexpr const bool is_signed =
+      std::is_signed_v<typename intN::underlying_type>;
+  static inline constexpr const bool is_modulo = !is_signed;
+  static inline constexpr const int digits = intN::digits;
+  // floor(digits * log10(2))
+  static inline constexpr const int digits10 = (digits * 3) / 10;
+
+  static constexpr intN epsilon() noexcept { return intN(0); }
+  static constexpr intN round_error() noexcept { return intN(0); }
+  static constexpr intN infinity() noexcept { return intN(0); }
+  static constexpr intN quiet_NaN() noexcept { return intN(0); }
+  static constexpr intN signaling_NaN() noexcept { return intN(0); }
+  static constexpr intN denorm_min() noexcept { return intN(0); }
+  static constexpr intN min() noexcept { return intN::lowest(); }
+  static constexpr intN lowest() noexcept { return intN::lowest(); }
+  static constexpr intN max() noexcept { return intN::highest(); }
+};
+
+}  // namespace internal
+
+}  // namespace ml_dtypes
+
+namespace std {
+
+template <>
+struct numeric_limits<ml_dtypes::int1>
+    : public ml_dtypes::internal::intN_numeric_limits_base<ml_dtypes::int1> {};
+template <>
+struct numeric_limits<ml_dtypes::uint1>
+    : public ml_dtypes::internal::intN_numeric_limits_base<ml_dtypes::uint1> {};
+template <>
+struct numeric_limits<ml_dtypes::int2>
+    : public ml_dtypes::internal::intN_numeric_limits_base<ml_dtypes::int2> {};
+template <>
+struct numeric_limits<ml_dtypes::uint2>
+    : public ml_dtypes::internal::intN_numeric_limits_base<ml_dtypes::uint2> {};
+template <>
+struct numeric_limits<ml_dtypes::int4>
+    : public ml_dtypes::internal::intN_numeric_limits_base<ml_dtypes::int4> {};
+template <>
+struct numeric_limits<ml_dtypes::uint4>
+    : public ml_dtypes::internal::intN_numeric_limits_base<ml_dtypes::uint4> {};
+
+}  // namespace std
+
+#endif  // ML_DTYPES_INTN_H_
diff --git a/third_party/ml_dtypes/src/ml_dtypes/include/mxfloat.h b/third_party/ml_dtypes/src/ml_dtypes/include/mxfloat.h
new file mode 100644
index 0000000..01636b5
--- /dev/null
+++ b/third_party/ml_dtypes/src/ml_dtypes/include/mxfloat.h
@@ -0,0 +1,386 @@
+/* Copyright 2024 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#ifndef ML_DTYPES_MXFLOAT_H_
+#define ML_DTYPES_MXFLOAT_H_
+
+// Microscaling (MX) floating point formats, as described in
+//   https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
+//
+// Note: this implements the underlying raw data types (e.g. E2M1FN), not the
+// composite types (e.g. MXFP4).
+
+#include <cstdint>
+#include <limits>
+
+#include "ml_dtypes/include/float8.h"
+#include "Eigen/Core"
+
+namespace ml_dtypes {
+namespace mxfloat_internal {
+
+// Use 8-bit storage for 6-bit and 4-bit types.
+template <typename Derived>
+class mxfloat6_base : public float8_internal::float8_base<Derived> {
+  using Base = float8_internal::float8_base<Derived>;
+  friend class float8_internal::float8_base<Derived>;
+  using Base::Base;
+
+ public:
+  static constexpr int kBits = 6;
+
+  explicit EIGEN_DEVICE_FUNC operator bool() const {
+    return (Base::rep() & 0x1F) != 0;
+  }
+  constexpr Derived operator-() const {
+    return Derived::FromRep(Base::rep() ^ 0x20);
+  }
+  Derived operator-(const Derived& other) const {
+    return Base::operator-(other);
+  }
+};
+
+template <typename Derived>
+class mxfloat4_base : public float8_internal::float8_base<Derived> {
+  using Base = float8_internal::float8_base<Derived>;
+  friend class float8_internal::float8_base<Derived>;
+  using Base::Base;
+
+ public:
+  static constexpr int kBits = 4;
+
+  explicit EIGEN_DEVICE_FUNC operator bool() const {
+    return (Base::rep() & 0x07) != 0;
+  }
+  constexpr Derived operator-() const {
+    return Derived::FromRep(Base::rep() ^ 0x08);
+  }
+  Derived operator-(const Derived& other) const {
+    return Base::operator-(other);
+  }
+};
+
+class float6_e2m3fn : public mxfloat6_base<float6_e2m3fn> {
+  // Exponent: 2, Mantissa: 3, bias: 1.
+  // Extended range: no inf, no NaN.
+  using Base = mxfloat6_base<float6_e2m3fn>;
+  friend class float8_internal::float8_base<float6_e2m3fn>;
+  using Base::Base;
+
+ public:
+  template <typename T, float8_internal::RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float6_e2m3fn(T f8)
+      : float6_e2m3fn(ConvertFrom(f8)) {}
+};
+
+class float6_e3m2fn : public mxfloat6_base<float6_e3m2fn> {
+  // Exponent: 3, Mantissa: 2, bias: 3.
+  // Extended range: no inf, no NaN.
+  using Base = mxfloat6_base<float6_e3m2fn>;
+  friend class float8_internal::float8_base<float6_e3m2fn>;
+  using Base::Base;
+
+ public:
+  template <typename T, float8_internal::RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float6_e3m2fn(T f8)
+      : float6_e3m2fn(ConvertFrom(f8)) {}
+};
+
+class float4_e2m1fn : public mxfloat4_base<float4_e2m1fn> {
+  // Exponent: 2, Mantissa: 1, bias: 1.
+  // Extended range: no inf, no NaN.
+  using Base = mxfloat4_base<float4_e2m1fn>;
+  friend class float8_internal::float8_base<float4_e2m1fn>;
+  using Base::Base;
+
+ public:
+  template <typename T, float8_internal::RequiresIsDerivedFromFloat8Base<T> = 0>
+  explicit EIGEN_DEVICE_FUNC float4_e2m1fn(T f8)
+      : float4_e2m1fn(ConvertFrom(f8)) {}
+};
+
+// Common properties for specializing std::numeric_limits.
+template <int E, int M>
+struct numeric_limits_mxfloat_tpl {
+ protected:
+  static constexpr int kExponentBias = (1 << (E - 1)) - 1;
+  static constexpr int kMantissaBits = M;
+
+ public:
+  // NOLINTBEGIN: these names must match std::numeric_limits.
+  static constexpr bool is_specialized = true;
+  static constexpr bool is_signed = true;
+  static constexpr bool is_integer = false;
+  static constexpr bool is_exact = false;
+  static constexpr bool has_infinity = false;
+  static constexpr bool has_quiet_NaN = false;
+  static constexpr bool has_signaling_NaN = false;
+  static constexpr std::float_denorm_style has_denorm = std::denorm_present;
+  static constexpr bool has_denorm_loss = false;
+  static constexpr std::float_round_style round_style = std::round_to_nearest;
+  static constexpr bool is_iec559 = false;
+  static constexpr bool is_bounded = true;
+  static constexpr bool is_modulo = false;
+  static constexpr int digits = kMantissaBits + 1;
+  static constexpr int digits10 = float8_internal::Digits10FromDigits(digits);
+  static constexpr int max_digits10 =
+      float8_internal::MaxDigits10FromDigits(digits);
+  static constexpr int radix = std::numeric_limits<float>::radix;
+  static constexpr int min_exponent = (1 - kExponentBias) + 1;
+  static constexpr int min_exponent10 =
+      float8_internal::MinExponent10FromMinExponent(min_exponent);
+  static constexpr int max_exponent = kExponentBias + 2;
+  static constexpr int max_exponent10 =
+      float8_internal::MaxExponent10FromMaxExponentAndDigits(max_exponent,
+                                                             digits);
+  static constexpr bool traps = std::numeric_limits<float>::traps;
+  static constexpr bool tinyness_before =
+      std::numeric_limits<float>::tinyness_before;
+  // NOLINTEND
+};
+
+struct numeric_limits_float6_e2m3fn : public numeric_limits_mxfloat_tpl<2, 3> {
+  // 1.0 * 2^(0) = 1
+  static constexpr float6_e2m3fn min() {
+    return float6_e2m3fn::FromRep(0b0'01'000);
+  }
+  // -1.875 * 2^(2) = -7.5
+  static constexpr float6_e2m3fn lowest() {
+    return float6_e2m3fn::FromRep(0b1'11'111);
+  }
+  // 1.875 * 2^(2) = 7.5
+  static constexpr float6_e2m3fn max() {
+    return float6_e2m3fn::FromRep(0b0'11'111);
+  }
+  // 0.125 * 2^(0) = 0.125
+  static constexpr float6_e2m3fn epsilon() {
+    return float6_e2m3fn::FromRep(0b0'00'001);
+  }
+  // 0.25 * 2^(0) = 0.25
+  static constexpr float6_e2m3fn round_error() {
+    return float6_e2m3fn::FromRep(0b0'00'010);
+  }
+  // 0.25 * 2^(0) = 0.125
+  static constexpr float6_e2m3fn denorm_min() {
+    return float6_e2m3fn::FromRep(0b0'00'001);
+  }
+
+  // Conversion from NaNs is implementation-defined (by MX specification).
+  static constexpr float6_e2m3fn quiet_NaN() {
+    return float6_e2m3fn::FromRep(0b1'00'000);
+  }
+  static constexpr float6_e2m3fn signaling_NaN() {
+    return float6_e2m3fn::FromRep(0b1'00'000);
+  }
+  static constexpr float6_e2m3fn infinity() {
+    return float6_e2m3fn::FromRep(0b0'11'111);
+  }
+};
+
+struct numeric_limits_float6_e3m2fn : public numeric_limits_mxfloat_tpl<3, 2> {
+  // 1.0 * 2^(-2) = 0.25
+  static constexpr float6_e3m2fn min() {
+    return float6_e3m2fn::FromRep(0b0'001'00);
+  }
+  // -1.75 * 2^(4) = -28
+  static constexpr float6_e3m2fn lowest() {
+    return float6_e3m2fn::FromRep(0b1'111'11);
+  }
+  // 1.75 * 2^(4) = 28
+  static constexpr float6_e3m2fn max() {
+    return float6_e3m2fn::FromRep(0b0'111'11);
+  }
+  // 1.0 * 2^(-2) = 0.25
+  static constexpr float6_e3m2fn epsilon() {
+    return float6_e3m2fn::FromRep(0b0'001'00);
+  }
+  // 1.0 * 2^(0) = 1
+  static constexpr float6_e3m2fn round_error() {
+    return float6_e3m2fn::FromRep(0b0'011'00);
+  }
+  // 0.25 * 2^(-2) = 0.0625
+  static constexpr float6_e3m2fn denorm_min() {
+    return float6_e3m2fn::FromRep(0b0'000'01);
+  }
+
+  // Conversion from NaNs is implementation-defined (by MX specification).
+  static constexpr float6_e3m2fn quiet_NaN() {
+    return float6_e3m2fn::FromRep(0b1'000'00);
+  }
+  static constexpr float6_e3m2fn signaling_NaN() {
+    return float6_e3m2fn::FromRep(0b1'000'00);
+  }
+  static constexpr float6_e3m2fn infinity() {
+    return float6_e3m2fn::FromRep(0b0'111'11);
+  }
+};
+
+struct numeric_limits_float4_e2m1fn : public numeric_limits_mxfloat_tpl<2, 1> {
+  // 1.0 * 2^(0) = 1
+  static constexpr float4_e2m1fn min() {
+    return float4_e2m1fn::FromRep(0b0'01'0);
+  }
+  // -1.5 * 2^(2) = -6
+  static constexpr float4_e2m1fn lowest() {
+    return float4_e2m1fn::FromRep(0b1'11'1);
+  }
+  // 1.5 * 2^(2) = 6
+  static constexpr float4_e2m1fn max() {
+    return float4_e2m1fn::FromRep(0b0'11'1);
+  }
+  // 0.5 * 2^(0) = 0.5
+  static constexpr float4_e2m1fn epsilon() {
+    return float4_e2m1fn::FromRep(0b0'00'1);
+  }
+  // 1.0 * 2^(0) = 1
+  static constexpr float4_e2m1fn round_error() {
+    return float4_e2m1fn::FromRep(0b0'01'0);
+  }
+  // 0.5 * 2^(0) = 0.5
+  static constexpr float4_e2m1fn denorm_min() {
+    return float4_e2m1fn::FromRep(0b0'00'1);
+  }
+
+  // Conversion from NaNs is implementation-defined (by MX specification).
+  static constexpr float4_e2m1fn quiet_NaN() {
+    return float4_e2m1fn::FromRep(0b1'00'0);
+  }
+  static constexpr float4_e2m1fn signaling_NaN() {
+    return float4_e2m1fn::FromRep(0b1'00'0);
+  }
+  static constexpr float4_e2m1fn infinity() {
+    return float4_e2m1fn::FromRep(0b0'11'1);
+  }
+};
+
+// Free-functions for use with ADL and in Eigen.
+constexpr inline float6_e2m3fn abs(const float6_e2m3fn& a) {
+  return float6_e2m3fn::FromRep(a.rep() & 0b0'11'111);
+}
+
+constexpr inline bool(isnan)(const float6_e2m3fn& a) { return false; }
+
+constexpr inline float6_e3m2fn abs(const float6_e3m2fn& a) {
+  return float6_e3m2fn::FromRep(a.rep() & 0b0'111'11);
+}
+
+constexpr inline bool(isnan)(const float6_e3m2fn& a) { return false; }
+
+constexpr inline float4_e2m1fn abs(const float4_e2m1fn& a) {
+  return float4_e2m1fn::FromRep(a.rep() & 0b0'11'1);
+}
+
+constexpr inline bool(isnan)(const float4_e2m1fn& a) { return false; }
+
+// Define traits required for floating point conversion.
+template <typename T, int E, int M>
+struct TraitsBase : public float8_internal::TraitsBase<T> {
+  static constexpr int kBits = E + M + 1;
+  static constexpr int kMantissaBits = M;
+  static constexpr int kExponentBits = E;
+  static constexpr int kExponentBias = (1 << (E - 1)) - 1;
+  static constexpr uint8_t kExponentMask = ((1 << E) - 1) << M;
+};
+
+}  // namespace mxfloat_internal
+
+// Exported types.
+using float6_e2m3fn = mxfloat_internal::float6_e2m3fn;
+using float6_e3m2fn = mxfloat_internal::float6_e3m2fn;
+using float4_e2m1fn = mxfloat_internal::float4_e2m1fn;
+
+}  // namespace ml_dtypes
+
+// Standard library overrides.
+namespace std {
+
+template <>
+struct numeric_limits<ml_dtypes::mxfloat_internal::float6_e2m3fn>
+    : public ml_dtypes::mxfloat_internal::numeric_limits_float6_e2m3fn {};
+
+template <>
+struct numeric_limits<ml_dtypes::mxfloat_internal::float6_e3m2fn>
+    : public ml_dtypes::mxfloat_internal::numeric_limits_float6_e3m2fn {};
+
+template <>
+struct numeric_limits<ml_dtypes::mxfloat_internal::float4_e2m1fn>
+    : public ml_dtypes::mxfloat_internal::numeric_limits_float4_e2m1fn {};
+
+}  // namespace std
+
+// Conversion traits.
+namespace ml_dtypes {
+namespace float8_internal {
+
+template <>
+struct Traits<float6_e2m3fn>
+    : public mxfloat_internal::TraitsBase<float6_e2m3fn, 2, 3> {};
+
+template <>
+struct Traits<float6_e3m2fn>
+    : public mxfloat_internal::TraitsBase<float6_e3m2fn, 3, 2> {};
+
+template <>
+struct Traits<float4_e2m1fn>
+    : public mxfloat_internal::TraitsBase<float4_e2m1fn, 2, 1> {};
+
+}  // namespace float8_internal
+}  // namespace ml_dtypes
+
+// Eigen library overrides.
+namespace Eigen {
+namespace numext {
+
+#define MXFLOAT_EIGEN_SIGNBIT_IMPL(Type)                              \
+  EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Type signbit(const Type& x) { \
+    int8_t t = bit_cast<int8_t, Type>(x) << (8 - Type::kBits);        \
+    return bit_cast<Type, int8_t>(t >> 7);                            \
+  }
+
+MXFLOAT_EIGEN_SIGNBIT_IMPL(ml_dtypes::float6_e2m3fn)
+MXFLOAT_EIGEN_SIGNBIT_IMPL(ml_dtypes::float6_e3m2fn)
+MXFLOAT_EIGEN_SIGNBIT_IMPL(ml_dtypes::float4_e2m1fn)
+
+#undef MXFLOAT_EIGEN_SIGNBIT_IMPL
+
+}  // namespace numext
+
+// Work-around for isinf/isnan/isfinite issue on aarch64.
+namespace internal {
+
+#define MXFLOAT_EIGEN_ISFINITE_IMPL(Type)                          \
+  template <>                                                      \
+  EIGEN_DEVICE_FUNC inline bool isinf_impl<Type>(const Type&) {    \
+    return false;                                                  \
+  }                                                                \
+  template <>                                                      \
+  EIGEN_DEVICE_FUNC inline bool isnan_impl<Type>(const Type&) {    \
+    return false;                                                  \
+  }                                                                \
+  template <>                                                      \
+  EIGEN_DEVICE_FUNC inline bool isfinite_impl<Type>(const Type&) { \
+    return true;                                                   \
+  }
+
+MXFLOAT_EIGEN_ISFINITE_IMPL(ml_dtypes::float6_e2m3fn)
+MXFLOAT_EIGEN_ISFINITE_IMPL(ml_dtypes::float6_e3m2fn)
+MXFLOAT_EIGEN_ISFINITE_IMPL(ml_dtypes::float4_e2m1fn)
+
+#undef MXFLOAT_EIGEN_ISFINITE_IMPL
+
+}  // namespace internal
+}  // namespace Eigen
+
+#endif  // ML_DTYPES_MXFLOAT_H_
diff --git a/third_party/ml_dtypes/update.sh b/third_party/ml_dtypes/update.sh
new file mode 100755
index 0000000..37714d8
--- /dev/null
+++ b/third_party/ml_dtypes/update.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+if [ $(basename ${PWD}) != "src" ]; then
+  echo "Please set the current working directory to chromium/src first!"
+  exit 1
+fi
+
+files=(
+  "LICENSE"
+  "ml_dtypes/include/float8.h"
+  "ml_dtypes/include/intn.h"
+  "ml_dtypes/include/mxfloat.h"
+)
+
+git clone --depth 1 https://github.com/jax-ml/ml_dtypes /tmp/ml_dtypes
+rm -rf third_party/ml_dtypes/src/*
+pushd third_party/ml_dtypes/src/ > /dev/null
+
+for file in ${files[@]} ; do
+  if [ ! -d "$(dirname ${file})" ] ; then
+    mkdir -p "$(dirname ${file})"
+  fi
+  cp "/tmp/ml_dtypes/${file}" "${file}"
+done
+
+popd > /dev/null
+rm -rf /tmp/ml_dtypes
diff --git a/third_party/rust/PRESUBMIT.py b/third_party/rust/PRESUBMIT.py
index 46ce15bc..ca1de795 100644
--- a/third_party/rust/PRESUBMIT.py
+++ b/third_party/rust/PRESUBMIT.py
@@ -12,6 +12,7 @@
 
 import re
 
+
 def CheckForManualEditsOfGnrtAutogeneratedFiles(input_api, output_api):
     GNRT_INPUTS = [
         "tools/crates/gnrt/.*",
diff --git a/third_party/rust/chromium_crates_io/.style.yapf b/third_party/rust/chromium_crates_io/.style.yapf
new file mode 100644
index 0000000..4741fb4
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/.style.yapf
@@ -0,0 +1,3 @@
+[style]
+based_on_style = pep8
+column_limit = 80
diff --git a/third_party/rust/chromium_crates_io/PRESUBMIT.py b/third_party/rust/chromium_crates_io/PRESUBMIT.py
new file mode 100644
index 0000000..96f50a86
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/PRESUBMIT.py
@@ -0,0 +1,53 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Presubmit for //third_party/rust/chromium_crates_io
+
+See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+PRESUBMIT_VERSION = '2.0.0'
+
+
+def CheckGnrtConfig(input_api, output_api):
+    # `input_files` lists files that are used as input by
+    # `third_party/rust/chromium_crates_io/check_gnrt_config.py`.
+    CARGO_LOCK_PATH = "third_party/rust/chromium_crates_io/Cargo.lock"
+    GNRT_CONFIG_PATH = "third_party/rust/chromium_crates_io/gnrt_config.toml"
+    input_files = set([CARGO_LOCK_PATH, GNRT_CONFIG_PATH])
+
+    # Exit early if no `input_files` are affected by the current CL.
+    affected_paths = set(
+        map(lambda f: f.UnixLocalPath(), input_api.change.AffectedFiles()))
+    if not input_files.intersection(affected_paths):
+        return []
+
+    # Delegate actual checks to `check_gnrt_config.py` (one reason is that we
+    # can't apparently `import toml` in `PRESUBMIT.py`).
+    test_script_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
+                                              "check_gnrt_config.py")
+    cmd_name = '//third_party/rust/chromium_crates_io/check_gnrt_config.py'
+    test_cmd = input_api.Command(
+        name=cmd_name,
+        cmd=[input_api.python_executable, test_script_path],
+        kwargs={},
+        message=output_api.PresubmitError)
+    if input_api.verbose:
+        print('Running ' + cmd_name)
+    return input_api.RunTests([test_cmd])
+
+
+def CheckPythonUnittestsPass(input_api, output_api):
+    results = []
+    this_dir = input_api.PresubmitLocalPath()
+
+    results += input_api.RunTests(
+        input_api.canned_checks.GetUnitTestsInDirectory(
+            input_api,
+            output_api,
+            this_dir,
+            files_to_check=['.*unittest.*\.py$'],
+            env=None))
+
+    return results
diff --git a/third_party/rust/chromium_crates_io/check_gnrt_config.py b/third_party/rust/chromium_crates_io/check_gnrt_config.py
new file mode 100755
index 0000000..5f4cf51
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/check_gnrt_config.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env vpython3
+
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This script checks for issues in:
+# * `//third_party/rust/chromium_crates_io/Cargo.lock` and
+# * `//third_party/rust/chromium_crates_io/gnrt_config.toml`.
+#
+# We don't surface these issues earlier (by reporting a fatal error from `gnrt
+# vendor`, `gnrt gen`, `gn gen`, or failing the builds), because we want to
+# avoid friction when new teams experiment with using Rust.  Some of these
+# issues may also happen during the crate update rotation and in this case we
+# want to allow the `tools/crate/create_update_cl.py` to continue creating CLs
+# (that other script uses `git cl upload ... --bypass-hooks`).
+#
+# This script is typically not invoked directly, but instead is invoked as part
+# of `//third_party/rust/PRESUBMIT.py`
+
+import os
+import sys
+import toml
+
+import crate_utils
+
+CRATES_DIR = os.path.normpath(os.path.dirname(__file__))
+GNRT_CONFIG_PATH = os.path.join(CRATES_DIR, 'gnrt_config.toml')
+
+
+def _GetCrateConfigForCrateName(crate_name, gnrt_config):
+    if gnrt_config and isinstance(gnrt_config, dict):
+        crates = gnrt_config.get("crate")
+        if crates and isinstance(crates, dict):
+            crate_cfg = crates.get(crate_name)
+            if crate_cfg and isinstance(crate_cfg, dict):
+                return crate_cfg
+    return dict()
+
+
+def _GetExtraKvForCrateName(crate_name, gnrt_config):
+    crate_cfg = _GetCrateConfigForCrateName(crate_name, gnrt_config)
+    extra_kv = crate_cfg.get("extra_kv")
+    if extra_kv and isinstance(extra_kv, dict):
+        return extra_kv
+    return dict()
+
+
+def CheckMultiversionCrates(crate_ids, gnrt_config):
+    """Checks that a bug tracks each crate with multiple versions.
+
+       This check has been discussed in https://crbug.com/404867240.  Having 2
+       or more different versions of a crate in Chromium's dependency tree is
+       undesirable in general.  So we want to detect when a 2nd version is
+       imported, and require opening a bug + recording the bug in
+       `gnrt_config.toml` for the given crate.
+
+       Returns an error message if a problem is detected.
+       Returns an empty string if there are no problems.
+    """
+
+    # Group `crate_id`s by their `crate_name`.
+    crate_name_to_list_of_crate_ids = dict()
+    for crate_id in crate_ids:
+        crate_name = crate_utils.ConvertCrateIdToCrateName(crate_id)
+        if crate_name not in crate_name_to_list_of_crate_ids:
+            crate_name_to_list_of_crate_ids[crate_name] = []
+        crate_name_to_list_of_crate_ids[crate_name] += [crate_id]
+
+    result = []
+    for (crate_name, crate_ids) in crate_name_to_list_of_crate_ids.items():
+        # Ignore crates where we depend only on a single version.
+        if len(crate_ids) == 1:
+            continue
+
+        # Ignore crates that already have a bug to track cleaning up a
+        # multiversion situation.
+        extra_kv = _GetExtraKvForCrateName(crate_name, gnrt_config)
+        if "multiversion_cleanup_bug" in extra_kv:
+            continue
+
+        # Report a problem for other multiversion crates.
+        if not result:  # Is is the **first** problematic `crate_name`?
+            result.append("ERROR: Transitive dependency graph includes " + \
+                          "multiple versions of the same crate.  Please " + \
+                          "open a bug to track removing one of the " + \
+                          "versions and put a link to the bug into " + \
+                          "`gnrt_config.toml` like this:")
+            result.append("")
+
+        result += [
+            f"    # TODO: Remove multiple versions of the `{crate_name}` crate:",
+            f"    # {', '.join(sorted(crate_ids))}",
+            f"    [crate.{crate_name}.extra_kv]",
+            f'    multiversion_cleanup_bug = "https://crbug.com/<bug number>"\n',
+        ]
+
+    return "\n".join(result)
+
+
+def main():
+    crate_ids = crate_utils.GetCurrentCrateIds()
+    gnrt_config = toml.load(open(GNRT_CONFIG_PATH))
+
+    success = True
+
+    def RunChecks(check_impl):
+        result = check_impl(crate_ids, gnrt_config)
+        if result:
+            if not success:
+                # Add a separator if this is a 2nd, 3rd, or later problem.
+                print()
+                print("-" * 72)
+                print()
+            success = False
+            print(result)
+
+    RunChecks(CheckMultiversionCrates)
+
+    # TODO(https://crbug.com/399931417): RunChecks(CheckExplicitAllowUnsafeForAllCrates).
+
+    # TODO(https://crbug.com/399935219): RunChecks(CheckNonapplicableGnrtConfigEntries).
+    # Move the useless-entry-in-gnrt_config check from `gnrt` into this script.
+    # Consider also adding CheckNonapplicablePatches.
+
+    if success:
+        return 0
+    else:
+        return -1
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/third_party/rust/chromium_crates_io/check_gnrt_config_unittests.py b/third_party/rust/chromium_crates_io/check_gnrt_config_unittests.py
new file mode 100755
index 0000000..c01ab16
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/check_gnrt_config_unittests.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env vpython3
+
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import unittest
+
+from check_gnrt_config import (
+    _GetExtraKvForCrateName,
+    CheckMultiversionCrates,
+)
+
+
+class CheckMultiversionCratesTests(unittest.TestCase):
+
+    def testNoMultiversionCrates(self):
+        crate_ids = set(["foo@1.2.3", "bar@4.5.6"])
+        gnrt_config = {}
+        self.assertEqual("", CheckMultiversionCrates(crate_ids, gnrt_config))
+
+    def testBugLinkPresent(self):
+        crate_ids = set(["foo@1.2.3", "foo@4.5.6"])
+        gnrt_config = {
+            "crate": {
+                "foo": {
+                    "extra_kv": {
+                        "multiversion_cleanup_bug": "blah"
+                    }
+                }
+            }
+        }
+        self.assertEqual("", CheckMultiversionCrates(crate_ids, gnrt_config))
+
+    def testProblemDetection(self):
+        crate_ids = set(["foo@1.2.3", "foo@4.5.6"])
+        gnrt_config = {}
+        msg = CheckMultiversionCrates(crate_ids, gnrt_config)
+        self.assertTrue("multiple versions of the same crate" in msg)
+        self.assertTrue("foo@1.2.3, foo@4.5.6" in msg)
+        self.assertTrue("[crate.foo.extra_kv]" in msg)
+        self.assertTrue("multiversion_cleanup_bug = " in msg)
+
+
+class GetExtraKvForCrateNameTests(unittest.TestCase):
+
+    def testHappyPath(self):
+        gnrt_config = {"crate": {"foo": {"extra_kv": {"entry": 123}}}}
+        extra_kv = _GetExtraKvForCrateName("foo", gnrt_config)
+        self.assertEqual({"entry": 123}, extra_kv)
+
+    def testMissingExtraKv(self):
+        """ Verify an empty dictionary is a fallback when no `extra_kv`. """
+        gnrt_config = {"crate": {"foo": {"bar": 123}}}
+        extra_kv = _GetExtraKvForCrateName("foo", gnrt_config)
+        self.assertEqual({}, extra_kv)
+
+    def testMissingCrateEntry(self):
+        gnrt_config = {"crate": {"other_crate": {"extra_kv": {"entry": 123}}}}
+        extra_kv = _GetExtraKvForCrateName("foo", gnrt_config)
+        self.assertEqual({}, extra_kv)
+
+    def testMistypedExtraKv(self):
+        """ Test fallback behavior when `extra_kv` is not a dictionary. """
+        gnrt_config = {"crate": {"foo": {"extra_kv": 123}}}
+        extra_kv = _GetExtraKvForCrateName("foo", gnrt_config)
+        self.assertEqual({}, extra_kv)
+
+    def testEmptyConfigSuchAsUsedInSomeTestsHere(self):
+        gnrt_config = {}
+        extra_kv = _GetExtraKvForCrateName("foo", gnrt_config)
+        self.assertEqual({}, extra_kv)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/third_party/rust/chromium_crates_io/crate_utils.py b/third_party/rust/chromium_crates_io/crate_utils.py
new file mode 100755
index 0000000..f8841fe9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/crate_utils.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env vpython3
+
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This module contains utilities for working with information from
+# `//third_party/rust/chromium_crates_io/Cargo.lock`.
+#
+# Throughout the module, the following naming conventions are used (illustrated
+# with a crate named `syn` and published as version `2.0.50`):
+#
+# * `crate_name`   : "syn" string
+# * `crate_version`: "2.0.50" string
+# * `crate_id`     : "syn@2.0.50" string (syntax used by `cargo`)
+# * `crate_epoch`  : "v2" string (syntax used in dir names under
+#                    //third_party/rust/<crate name>/<crate epoch>)
+#
+# Note that `crate_name` may not be unique (e.g. if there is both `syn@1.0.109`
+# and `syn@2.0.50`).  Also note that f`{crate_name}@{crate_epoch}` doesn't
+# change during a minor version update (such as the one that this script
+
+import os
+import sys
+import toml
+from typing import Set
+
+THIS_DIR = os.path.dirname(__file__)
+CHROMIUM_DIR = os.path.normpath(os.path.join(THIS_DIR, '..', '..', '..'))
+THIRD_PARTY_RUST_DIR = os.path.join(CHROMIUM_DIR, "third_party", "rust")
+CRATES_DIR = os.path.join(THIRD_PARTY_RUST_DIR, "chromium_crates_io")
+CARGO_LOCK_FILEPATH = os.path.join(CRATES_DIR, 'Cargo.lock')
+VENDOR_DIR = os.path.join(CRATES_DIR, "vendor")
+
+
+def GetCurrentCrateIds() -> Set[str]:
+    """Parses Cargo.lock and returns a set of crate ids.
+
+    Example return value: `set(["serde@1.0.197", "syn@2.0.50", ...])`.
+    """
+    with open(CARGO_LOCK_FILEPATH) as f:
+        t = toml.load(f)
+        result = set()
+        for p in t["package"]:
+            name = p["name"]
+            version = p["version"]
+            crate_id = f"{name}@{version}"
+            assert crate_id not in result
+            result.add(crate_id)
+        return result
+
+
+def ConvertCrateIdToCrateEpoch(crate_id: str) -> str:
+    crate_version = ConvertCrateIdToCrateVersion(crate_id)
+    v = crate_version.split('.')
+    if v[0] == '0':
+        return f'v0_{v[1]}'
+    return f'v{v[0]}'
+
+
+def ConvertCrateIdToCrateName(crate_id: str) -> str:
+    """ Converts a `crate_id` into a `crate_name`."""
+    return crate_id[:crate_id.find("@")]
+
+
+def ConvertCrateIdToCrateVersion(crate_id: str) -> str:
+    """ Converts a `crate_id` into a `crate_version`."""
+    crate_version = crate_id[crate_id.find("@") + 1:]
+    return crate_version
+
+
+def ConvertCrateIdToBuildDir(crate_id: str) -> str:
+    """ Converts a `crate_id` (e.g. "foo@1.2.3") into a path to an epoch dir.
+
+    Example return value:
+    `"<path to chromium root>\\third_party\\rust\\foo\\v1"`
+    """
+    return os.path.join(
+        CHROMIUM_DIR, _ConvertCrateIdToBuildDirRelativeToChromiumRoot(crate_id))
+
+
+def ConvertCrateIdToVendorDir(crate_id: str) -> str:
+    """ Converts a `crate_id` (e.g. "foo@1.2.3") into a path to a target dir.
+
+    Example return value:
+    `"<path to chromium root>\\third_party\\rust\\chromium_crates_io\\vendor\\foo-v1"`
+    """
+    crate_name = ConvertCrateIdToCrateName(crate_id)
+    crate_epoch = ConvertCrateIdToCrateEpoch(crate_id)
+    crate_vendor_dir = os.path.join(VENDOR_DIR, f"{crate_name}-{crate_epoch}")
+    return crate_vendor_dir
+
+
+def ConvertCrateIdToGnLabel(crate_id: str) -> str:
+    """ Converts a `crate_id` (e.g. "foo@1.2.3") into a GN label.
+
+    See also
+    https://gn.googlesource.com/gn/+/main/docs/reference.md#labels
+
+    Example return value: `"//third_party/rust/foo/v1:lib"`
+    """
+    dir_name = _ConvertCrateIdToBuildDirRelativeToChromiumRoot(crate_id)
+    dir_name = dir_name.replace(os.sep, "/")  # GN uses `/` as a path separator.
+    return f"//{dir_name}:lib"
+
+
+def _ConvertCrateIdToBuildDirRelativeToChromiumRoot(crate_id: str) -> str:
+    """ Converts a `crate_id` (e.g. "foo@1.2.3") into an epoch dir.
+
+    The returned dir is relative to Chromium root.
+    Example return value: `"//third_party/rust/foo/v1"`
+    """
+    crate_name = ConvertCrateIdToCrateName(crate_id)
+    crate_name = crate_name.replace("-", "_")
+    epoch = ConvertCrateIdToCrateEpoch(crate_id)
+    target = os.path.join("third_party", "rust", crate_name, epoch)
+    return target
+
+
+assert __name__ != '__main__'
diff --git a/third_party/rust/chromium_crates_io/crate_utils_unittests.py b/third_party/rust/chromium_crates_io/crate_utils_unittests.py
new file mode 100755
index 0000000..b453995
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/crate_utils_unittests.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env vpython3
+
+# Copyright 2025 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import unittest
+
+from crate_utils import (
+    CHROMIUM_DIR,
+    ConvertCrateIdToCrateEpoch,
+    ConvertCrateIdToCrateName,
+    ConvertCrateIdToCrateVersion,
+    ConvertCrateIdToBuildDir,
+    ConvertCrateIdToGnLabel,
+    ConvertCrateIdToVendorDir,
+    GetCurrentCrateIds,
+)
+
+
+class CrateUtilsTests(unittest.TestCase):
+
+    def testGetCurrentCrateIds(self):
+        crate_ids = GetCurrentCrateIds()
+        self.assertTrue(crate_ids)
+
+    def testConvertCrateIdToCrateEpoch(self):
+        self.assertEqual(ConvertCrateIdToCrateEpoch("foo@0.1.2"), "v0_1")
+        self.assertEqual(ConvertCrateIdToCrateEpoch("foo@1.2.3"), "v1")
+
+    def testConvertCrateIdToBuildDir(self):
+        actual_dir = ConvertCrateIdToBuildDir("foo-bar@1.2.3")
+        expected_suffix = os.path.join("third_party", "rust", "foo_bar", "v1")
+        self.assertEqual(actual_dir, os.path.join(CHROMIUM_DIR,
+                                                  expected_suffix))
+
+        actual_dir = ConvertCrateIdToBuildDir("bar_baz@0.12.3")
+        expected_suffix = os.path.join("third_party", "rust", "bar_baz",
+                                       "v0_12")
+        self.assertEqual(actual_dir, os.path.join(CHROMIUM_DIR,
+                                                  expected_suffix))
+
+    def testConvertCrateIdToGnLabel(self):
+        self.assertEqual(ConvertCrateIdToGnLabel("foo-bar@1.2.3"),
+                         "//third_party/rust/foo_bar/v1:lib")
+        self.assertEqual(ConvertCrateIdToGnLabel("bar_baz@0.12.3"),
+                         "//third_party/rust/bar_baz/v0_12:lib")
+
+    def testConvertCrateIdToVendorDir(self):
+        actual_dir = ConvertCrateIdToVendorDir("foo-bar@1.2.3")
+        expected_suffix = os.path.join("third_party", "rust",
+                                       "chromium_crates_io", "vendor",
+                                       "foo-bar-v1")
+        self.assertEqual(actual_dir, os.path.join(CHROMIUM_DIR,
+                                                  expected_suffix))
+
+        actual_dir = ConvertCrateIdToVendorDir("bar_baz@0.12.3")
+        expected_suffix = os.path.join("third_party", "rust",
+                                       "chromium_crates_io", "vendor",
+                                       "bar_baz-v0_12")
+        self.assertEqual(actual_dir, os.path.join(CHROMIUM_DIR,
+                                                  expected_suffix))
+
+    def testConvertCrateIdToCrateName(self):
+        self.assertEqual(ConvertCrateIdToCrateName("foo-bar@1.2.3"), "foo-bar")
+
+    def testConvertCrateIdToCrateVersion(self):
+        self.assertEqual(ConvertCrateIdToCrateVersion("foo-bar@1.2.3"), "1.2.3")
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/third_party/skia b/third_party/skia
index 504ccf4..c140738 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 504ccf45fba464bf74b396cc686494629f37b718
+Subproject commit c1407387eeaf31674891a4d12505970d3237e86f
diff --git a/tools/accessibility/rebase_dump_accessibility_tree_tests.py b/tools/accessibility/rebase_dump_accessibility_tree_tests.py
index 075a2385..bd2c60a 100755
--- a/tools/accessibility/rebase_dump_accessibility_tree_tests.py
+++ b/tools/accessibility/rebase_dump_accessibility_tree_tests.py
@@ -140,7 +140,8 @@
       capture_output=True,
       text=True,
   ).stdout):
-    raise ValueError('Did not find an issue attached to the current branch.')
+    raise ValueError('Did not find an issue attached to the current branch. '
+                     'Note for Googlers: you might just need to run gcert.')
   return json.loads(output)
 
 
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 420c106..316567b 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -39,8 +39,8 @@
 # These fields are written by //tools/clang/scripts/upload_revision.py, and
 # should not be changed manually.
 # They are also read by build/config/compiler/BUILD.gn.
-CLANG_REVISION = 'llvmorg-21-init-9266-g09006611'
-CLANG_SUB_REVISION = 2
+CLANG_REVISION = 'llvmorg-21-init-11777-gfd3fecfc'
+CLANG_SUB_REVISION = 1
 
 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION)
 RELEASE_VERSION = '21'
diff --git a/tools/crates/create_update_cl.py b/tools/crates/create_update_cl.py
index c0cf940..3c1d329f 100755
--- a/tools/crates/create_update_cl.py
+++ b/tools/crates/create_update_cl.py
@@ -21,8 +21,25 @@
 from dataclasses import dataclass
 from typing import List, Set, Dict
 
-# Throughout the script, the following naming conventions are used (illustrated
-# with a crate named `syn` and published as version `2.0.50`):
+THIS_DIR = os.path.dirname(__file__)
+CHROMIUM_DIR = os.path.normpath(os.path.join(THIS_DIR, '..', '..'))
+THIRD_PARTY_RUST = os.path.join(CHROMIUM_DIR, "third_party", "rust")
+CRATES_DIR = os.path.join(THIRD_PARTY_RUST, "chromium_crates_io")
+VENDOR_DIR = os.path.join(CRATES_DIR, "vendor")
+INCLUSIVE_LANG_SCRIPT = os.path.join(
+    CHROMIUM_DIR, "infra", "update_inclusive_language_presubmit_exempt_dirs.sh")
+INCLUSIVE_LANG_CONFIG = os.path.join(
+    CHROMIUM_DIR, "infra", "inclusive_language_presubmit_exempt_dirs.txt")
+RUN_GNRT = os.path.join(THIS_DIR, "run_gnrt.py")
+UPDATE_RUST_SCRIPT = os.path.join(CHROMIUM_DIR, "tools", "rust",
+                                  "update_rust.py")
+
+sys.path.append(CRATES_DIR)
+import crate_utils
+
+# As in `third_party/rust/chromium_crates_io/crate_utils.py`, the following
+# naming conventions are used in this script (illustrated with a crate named
+# `syn` and published as version `2.0.50`):
 #
 # * `crate_name`   : "syn" string
 # * `crate_version`: "2.0.50" string
@@ -35,20 +52,6 @@
 # change during a minor version update (such as the one that this script
 # produces in `auto` and `single` modes).
 
-THIS_DIR = os.path.dirname(__file__)
-CHROMIUM_DIR = os.path.normpath(os.path.join(THIS_DIR, '..', '..'))
-THIRD_PARTY_RUST = os.path.join(CHROMIUM_DIR, "third_party", "rust")
-CRATES_DIR = os.path.join(THIRD_PARTY_RUST, "chromium_crates_io")
-VENDOR_DIR = os.path.join(CRATES_DIR, "vendor")
-CARGO_LOCK = os.path.join(CRATES_DIR, "Cargo.lock")
-INCLUSIVE_LANG_SCRIPT = os.path.join(
-    CHROMIUM_DIR, "infra", "update_inclusive_language_presubmit_exempt_dirs.sh")
-INCLUSIVE_LANG_CONFIG = os.path.join(
-    CHROMIUM_DIR, "infra", "inclusive_language_presubmit_exempt_dirs.txt")
-RUN_GNRT = os.path.join(THIS_DIR, "run_gnrt.py")
-UPDATE_RUST_SCRIPT = os.path.join(CHROMIUM_DIR, "tools", "rust",
-                                  "update_rust.py")
-
 g_is_verbose = False
 
 timestamp = datetime.datetime.now()
@@ -121,10 +124,10 @@
 
 def GnrtUpdateCrate(old_crate_id: str, new_crate_id: str, check_stdout: bool,
                     check_exitcode: bool):
-    old_crate_version = ConvertCrateIdToCrateVersion(old_crate_id)
-    new_crate_version = ConvertCrateIdToCrateVersion(new_crate_id)
-    old_epoch = GetEpoch(old_crate_version)
-    new_epoch = GetEpoch(new_crate_version)
+    old_crate_version = crate_utils.ConvertCrateIdToCrateVersion(old_crate_id)
+    new_crate_version = crate_utils.ConvertCrateIdToCrateVersion(new_crate_id)
+    old_epoch = crate_utils.ConvertCrateIdToCrateEpoch(old_crate_id)
+    new_epoch = crate_utils.ConvertCrateIdToCrateEpoch(new_crate_id)
     is_major_update = (old_epoch != new_epoch)
 
     cargo_update_args = [old_crate_id, "--precise", f"{new_crate_version}"]
@@ -136,31 +139,19 @@
                       check_exitcode=check_exitcode)
 
 
-def GetCurrentCrateIds() -> Set[str]:
-    """Parses Cargo.lock and returns a set of crate ids
-    (e.g. "serde@1.0.197", "syn@2.0.50", ...)."""
-    t = toml.load(open(CARGO_LOCK))
-    result = set()
-    for p in t["package"]:
-        name = p["name"]
-        version = p["version"]
-        crate_id = f"{name}@{version}"
-        assert crate_id not in result
-        result.add(crate_id)
-    return result
-
-
 @dataclass(eq=True, order=True)
 class UpdatedCrate:
     old_crate_id: str
     new_crate_id: str
 
     def __str__(self):
-        name = ConvertCrateIdToCrateName(self.old_crate_id)
-        assert name == ConvertCrateIdToCrateName(self.new_crate_id)
+        name = crate_utils.ConvertCrateIdToCrateName(self.old_crate_id)
+        assert name == crate_utils.ConvertCrateIdToCrateName(self.new_crate_id)
 
-        old_version = ConvertCrateIdToCrateVersion(self.old_crate_id)
-        new_version = ConvertCrateIdToCrateVersion(self.new_crate_id)
+        old_version = crate_utils.ConvertCrateIdToCrateVersion(
+            self.old_crate_id)
+        new_version = crate_utils.ConvertCrateIdToCrateVersion(
+            self.new_crate_id)
 
         return f"{name}: {old_version} => {new_version}"
 
@@ -193,10 +184,10 @@
         that it will be stable for tracking a crate version across updates."""
         result = dict()
         for crate_id in crate_ids:
-            name = ConvertCrateIdToCrateName(crate_id)
-            version = ConvertCrateIdToCrateVersion(crate_id)
+            name = crate_utils.ConvertCrateIdToCrateName(crate_id)
+            version = crate_utils.ConvertCrateIdToCrateVersion(crate_id)
             if only_minor_updates:
-                epoch = GetEpoch(version)
+                epoch = crate_utils.ConvertCrateIdToCrateEpoch(crate_id)
                 key = f'{name}@{epoch}'
             else:
                 key = name
@@ -236,62 +227,6 @@
                       sorted(added_crate_ids))
 
 
-def GetEpoch(crate_version: str) -> str:
-    v = crate_version.split('.')
-    if v[0] == '0':
-        return f'v0_{v[1]}'
-    return f'v{v[0]}'
-
-
-def ConvertCrateIdToCrateName(crate_id: str) -> str:
-    """ Converts a `crate_id` into a `crate_name`."""
-    return crate_id[:crate_id.find("@")]
-
-
-def ConvertCrateIdToCrateVersion(crate_id: str) -> str:
-    """ Converts a `crate_id` into a `crate_version`."""
-    crate_version = crate_id[crate_id.find("@") + 1:]
-    return crate_version
-
-
-def _ConvertCrateIdToEpochDirRelativeToChromiumRoot(crate_id: str) -> str:
-    """ Converts a `crate_id` (e.g. "foo@1.2.3") into an epoch dir
-    (e.g. "third_party/rust/foo/v_1").  The returned dir is relative
-    to Chromium root. """
-    crate_name = ConvertCrateIdToCrateName(crate_id)
-    crate_name = crate_name.replace("-", "_")
-    epoch = GetEpoch(ConvertCrateIdToCrateVersion(crate_id))
-    target = os.path.join("third_party", "rust", crate_name, epoch)
-    return target
-
-
-def ConvertCrateIdToEpochDir(crate_id: str) -> str:
-    """ Converts a `crate_id` (e.g. "foo@1.2.3") into a path to an epoch dir
-    (e.g. on Windows: "<path to chromium root>\\third_party\\rust\\foo\\v_1").
-    """
-    return os.path.join(
-        CHROMIUM_DIR, _ConvertCrateIdToEpochDirRelativeToChromiumRoot(crate_id))
-
-
-def ConvertCrateIdToVendorDir(crate_id: str) -> str:
-    """ Converts a `crate_id` (e.g. "foo@1.2.3") into a path to a target dir
-    (e.g. on Windows: "<path to chromium root>\\third_party\\rust\\foo\\v_1").
-    """
-    crate_name = ConvertCrateIdToCrateName(crate_id)
-    crate_epoch = GetEpoch(ConvertCrateIdToCrateVersion(crate_id))
-    crate_vendor_dir = os.path.join(VENDOR_DIR, f"{crate_name}-{crate_epoch}")
-    return crate_vendor_dir
-
-
-def ConvertCrateIdToGnLabel(crate_id: str) -> str:
-    """ Converts a `crate_id` (e.g. "foo@1.2.3") into
-    [a GN label](https://gn.googlesource.com/gn/+/main/docs/reference.md#labels)
-    (e.g. "//third_party/rust/foo/v_1:lib").  """
-    dir_name = _ConvertCrateIdToEpochDirRelativeToChromiumRoot(crate_id)
-    dir_name = dir_name.replace(os.sep, "/")  # GN uses `/` as a path separator.
-    return f"//{dir_name}:lib"
-
-
 def DoArgsAskForBreakingChanges(cargo_update_args) -> bool:
     # Hardcoding implementation details of `cargo update` is a bit icky, but it
     # helps to ensure that `DiffCrateIds` won't see dictionary key conflicts.
@@ -304,17 +239,19 @@
     (Idempotent - afterwards it runs `git reset --hard` to undo any changes.)"""
     print("Checking which crates can be updated...")
     assert not IsGitDirty()  # No local changes expected here.
-    old_crate_ids = GetCurrentCrateIds()
+    old_crate_ids = crate_utils.GetCurrentCrateIds()
     GnrtUpdate(args.remaining_args, check_stdout=False, check_exitcode=False)
-    new_crate_ids = GetCurrentCrateIds()
+    new_crate_ids = crate_utils.GetCurrentCrateIds()
     Git("reset", "--hard")
     only_minor_updates = not DoArgsAskForBreakingChanges(args.remaining_args)
     diff = DiffCrateIds(old_crate_ids, new_crate_ids, only_minor_updates)
     crate_updates = [(update.old_crate_id, update.new_crate_id)
                      for update in diff.updates]
     if crate_updates:
-        names = sorted(
-            [ConvertCrateIdToCrateName(id) for (id, _) in crate_updates])
+        names = sorted([
+            crate_utils.ConvertCrateIdToCrateName(id)
+            for (id, _) in crate_updates
+        ])
         names = f"{', '.join(names)}"
         text = f"Found updates for {len(crate_updates)} crates: {names}"
         print("\n".join(textwrap.wrap(text, 80)))
@@ -330,12 +267,12 @@
     print(
         f"Measuring the delta of updating {old_crate_id} => {new_crate_id}...")
     assert not IsGitDirty()  # No local changes expected here.
-    old_crate_ids = GetCurrentCrateIds()
+    old_crate_ids = crate_utils.GetCurrentCrateIds()
     GnrtUpdateCrate(old_crate_id,
                     new_crate_id,
                     check_stdout=False,
                     check_exitcode=False)
-    new_crate_ids = GetCurrentCrateIds()
+    new_crate_ids = crate_utils.GetCurrentCrateIds()
     Git("reset", "--hard")
     diff = DiffCrateIds(old_crate_ids, new_crate_ids, only_minor_updates)
     return diff.size()
@@ -355,9 +292,9 @@
 
 
 def CreateCommitTitle(old_crate_id: str, new_crate_id: str) -> str:
-    crate_name = ConvertCrateIdToCrateName(old_crate_id)
-    old_version = ConvertCrateIdToCrateVersion(old_crate_id)
-    new_version = ConvertCrateIdToCrateVersion(new_crate_id)
+    crate_name = crate_utils.ConvertCrateIdToCrateName(old_crate_id)
+    old_version = crate_utils.ConvertCrateIdToCrateVersion(old_crate_id)
+    new_version = crate_utils.ConvertCrateIdToCrateVersion(new_crate_id)
     roll_summary = f"{crate_name}: " + \
         f"{old_version} => {new_version}"
     title = f"Roll {roll_summary} in //third_party/rust."
@@ -421,13 +358,13 @@
     assert not IsGitDirty()  # No local changes expected here.
 
     # gnrt update
-    old_crate_ids = GetCurrentCrateIds()
+    old_crate_ids = crate_utils.GetCurrentCrateIds()
     print(f"  Running `gnrt update` for {old_crate_id} => {new_crate_id} ...")
     GnrtUpdateCrate(old_crate_id,
                     new_crate_id,
                     check_stdout=True,
                     check_exitcode=True)
-    new_crate_ids = GetCurrentCrateIds()
+    new_crate_ids = crate_utils.GetCurrentCrateIds()
     if old_crate_ids == new_crate_ids:
         print("  `gnrt update` resulted in no changes - "\
               "maybe other steps will handle this crate...")
@@ -461,13 +398,15 @@
     for update in diff.updates:
         updated_old_crate_ids.add(update.old_crate_id)
 
-        old_dir = ConvertCrateIdToVendorDir(update.old_crate_id)
-        new_dir = ConvertCrateIdToVendorDir(update.new_crate_id)
+        old_dir = crate_utils.ConvertCrateIdToVendorDir(update.old_crate_id)
+        new_dir = crate_utils.ConvertCrateIdToVendorDir(update.new_crate_id)
         if old_dir != new_dir:
             Git("mv", "--force", f"{old_dir}", f"{new_dir}")
 
-            old_target_dir = ConvertCrateIdToEpochDir(update.old_crate_id)
-            new_target_dir = ConvertCrateIdToEpochDir(update.new_crate_id)
+            old_target_dir = crate_utils.ConvertCrateIdToBuildDir(
+                update.old_crate_id)
+            new_target_dir = crate_utils.ConvertCrateIdToBuildDir(
+                update.new_crate_id)
             if old_target_dir != new_target_dir:
                 Git("mv", "--force", old_target_dir, new_target_dir)
     GitAddRustFiles()
@@ -504,8 +443,10 @@
     # (in case this is a major version update)
     print(f"  Removing //third_party/rust/.../<old_epoch> ...")
     for update in diff.updates:
-        old_target_dir = ConvertCrateIdToEpochDir(update.old_crate_id)
-        new_target_dir = ConvertCrateIdToEpochDir(update.new_crate_id)
+        old_target_dir = crate_utils.ConvertCrateIdToBuildDir(
+            update.old_crate_id)
+        new_target_dir = crate_utils.ConvertCrateIdToBuildDir(
+            update.new_crate_id)
         if old_target_dir == new_target_dir:
             continue  # Skip minor crate updates
 
@@ -532,8 +473,8 @@
     # (in case this is a major version update)
     print(f"  Updating the target name in BUILD.gn files...")
     for update in diff.updates:
-        old_target = ConvertCrateIdToGnLabel(update.old_crate_id)
-        new_target = ConvertCrateIdToGnLabel(update.new_crate_id)
+        old_target = crate_utils.ConvertCrateIdToGnLabel(update.old_crate_id)
+        new_target = crate_utils.ConvertCrateIdToGnLabel(update.new_crate_id)
         if old_target == new_target: continue
         # `check_exitcode=False` to gracefully handle no hits.
         grep = RunCommandAndCheckForErrors(
@@ -601,8 +542,10 @@
 
 
 def GitClUpload(*args):
-    # TODO(https://crbug.com/405980483): Remove `--bypass-hooks`, or document
-    # why this is still needed.
+    # `--bypass-hooks` to avoid disrupting the process of creating update CLs by
+    # `//third_party/rust/PRESUBMIT.py` (e.g. it's okay to add
+    # `multiversion_cleanup_bug` to `gnrt_config.toml` later, before landing the
+    # CLs).
     #
     # `-o banned-words-skip` is used, because the CL is auto-generated and only
     # modifies third-party libraries (where any banned words would be purely
@@ -632,45 +575,16 @@
             return False
 
 
-def ResolveCrateNameToCrateId(crate_name):
-    """Parses `Cargo.toml` to resolve `crate_name` into "crate-name@1.2.3".
-    Throws if `crate_name` can't be resolved.
-
-    Parameters:
-      crate_name: Either "crate-name" or already "crate-name@1.2.3"
-    """
-    t = toml.load(open(CARGO_LOCK))
-    if '@' in crate_name:
-        resolved_crate_version = ConvertCrateIdToCrateVersion(crate_name)
-        resolved_crate_name = ConvertCrateIdToCrateName(crate_name)
-    else:
-        same_name = [p for p in t["package"] if p["name"] == crate_name]
-        if len(same_name) == 0:
-            raise RuntimeError(
-                f"`Cargo.toml` has no crates matching `{crate_name}`")
-        elif len(same_name) > 1:
-            ver1 = same_name[0]["version"]
-            ver2 = same_name[1]["version"]
-            raise RuntimeError(
-                f"Ambiguous argument - specify which old version to update, "\
-                f"e.g. `{crate_name}@{ver1}` or `{crate_name}@{ver2}")
-        resolved_crate_name = crate_name
-        resolved_crate_version = same_name[0]["version"]
-
-    crate_id = f"{resolved_crate_name}@{resolved_crate_version}"
-    return crate_id
-
-
 def BreakingUpdate(args):
     only_minor_updates = False
 
     # gnrt update
-    old_crate_ids = GetCurrentCrateIds()
+    old_crate_ids = crate_utils.GetCurrentCrateIds()
     print(f"Creating a major version update CL...")
     joined_remaining_args = ' '.join(args.remaining_args)
     print(f"  Running `gnrt update -- {joined_remaining_args}` ...")
     GnrtUpdate(args.remaining_args, check_stdout=True, check_exitcode=True)
-    new_crate_ids = GetCurrentCrateIds()
+    new_crate_ids = crate_utils.GetCurrentCrateIds()
     if old_crate_ids == new_crate_ids:
         print("  `gnrt update` resulted in no changes...")
         return
@@ -707,7 +621,7 @@
     if args.skip:
         todo_crate_updates_without_skips = []
         for old_crate_id, new_crate_id in todo_crate_updates:
-            crate_name = ConvertCrateIdToCrateName(old_crate_id)
+            crate_name = crate_utils.ConvertCrateIdToCrateName(old_crate_id)
             if not any(
                     fnmatch.fnmatch(crate_name, pattern)
                     for pattern in args.skip):
@@ -740,13 +654,13 @@
 
     branch_number = 1
     while todo_crate_updates:
-        old_crate_ids = GetCurrentCrateIds()
+        old_crate_ids = crate_utils.GetCurrentCrateIds()
         for (old_crate_id, new_crate_id) in todo_crate_updates:
             upstream_branch = UpdateCrate(args, old_crate_id, new_crate_id,
                                           upstream_branch, branch_number)
             branch_number += 1
 
-        new_crate_ids = GetCurrentCrateIds()
+        new_crate_ids = crate_utils.GetCurrentCrateIds()
         diff = DiffCrateIds(old_crate_ids, new_crate_ids, only_minor_updates)
         actually_updated_crate_ids = set([u.old_crate_id for u in diff.updates])
         missed_crate_updates = [
@@ -772,9 +686,9 @@
     print(f"Post-processing a manual edit of `Cargo.toml`...")
 
     print(f"  Running `gnrt vendor` to detect `Cargo.lock` changes...")
-    old_crate_ids = GetCurrentCrateIds()
+    old_crate_ids = crate_utils.GetCurrentCrateIds()
     Gnrt("vendor")
-    new_crate_ids = GetCurrentCrateIds()
+    new_crate_ids = crate_utils.GetCurrentCrateIds()
     Git("reset", "--hard")
     Git("clean", "-d", "--force", "--", f"{THIRD_PARTY_RUST}")
     diff = DiffCrateIds(old_crate_ids, new_crate_ids, False)
diff --git a/tools/crates/create_update_cl_unittests.py b/tools/crates/create_update_cl_unittests.py
index 2444f3ac..8c3d790 100755
--- a/tools/crates/create_update_cl_unittests.py
+++ b/tools/crates/create_update_cl_unittests.py
@@ -8,17 +8,10 @@
 import unittest
 
 from create_update_cl import (
-    CHROMIUM_DIR,
-    ConvertCrateIdToCrateName,
-    ConvertCrateIdToCrateVersion,
-    ConvertCrateIdToEpochDir,
-    ConvertCrateIdToGnLabel,
-    ConvertCrateIdToVendorDir,
     CreateCommitDescription,
     CreateCommitTitle,
     CreateCommitTitleForBreakingUpdate,
     DiffCrateIds,
-    GetEpoch,
     SortedMarkdownList,
 )
 
@@ -134,49 +127,6 @@
 
 class OtherTests(unittest.TestCase):
 
-    def testGetEpoch(self):
-        self.assertEqual(GetEpoch("0.1.2"), "v0_1")
-        self.assertEqual(GetEpoch("1.2.3"), "v1")
-
-    def testConvertCrateIdToEpochDir(self):
-        actual_dir = ConvertCrateIdToEpochDir("foo-bar@1.2.3")
-        expected_suffix = os.path.join("third_party", "rust", "foo_bar", "v1")
-        self.assertEqual(actual_dir, os.path.join(CHROMIUM_DIR,
-                                                  expected_suffix))
-
-        actual_dir = ConvertCrateIdToEpochDir("bar_baz@0.12.3")
-        expected_suffix = os.path.join("third_party", "rust", "bar_baz",
-                                       "v0_12")
-        self.assertEqual(actual_dir, os.path.join(CHROMIUM_DIR,
-                                                  expected_suffix))
-
-    def testConvertCrateIdToGnLabel(self):
-        self.assertEqual(ConvertCrateIdToGnLabel("foo-bar@1.2.3"),
-                         "//third_party/rust/foo_bar/v1:lib")
-        self.assertEqual(ConvertCrateIdToGnLabel("bar_baz@0.12.3"),
-                         "//third_party/rust/bar_baz/v0_12:lib")
-
-    def testConvertCrateIdToVendorDir(self):
-        actual_dir = ConvertCrateIdToVendorDir("foo-bar@1.2.3")
-        expected_suffix = os.path.join("third_party", "rust",
-                                       "chromium_crates_io", "vendor",
-                                       "foo-bar-v1")
-        self.assertEqual(actual_dir, os.path.join(CHROMIUM_DIR,
-                                                  expected_suffix))
-
-        actual_dir = ConvertCrateIdToVendorDir("bar_baz@0.12.3")
-        expected_suffix = os.path.join("third_party", "rust",
-                                       "chromium_crates_io", "vendor",
-                                       "bar_baz-v0_12")
-        self.assertEqual(actual_dir, os.path.join(CHROMIUM_DIR,
-                                                  expected_suffix))
-
-    def testConvertCrateIdToCrateName(self):
-        self.assertEqual(ConvertCrateIdToCrateName("foo-bar@1.2.3"), "foo-bar")
-
-    def testConvertCrateIdToCrateVersion(self):
-        self.assertEqual(ConvertCrateIdToCrateVersion("foo-bar@1.2.3"), "1.2.3")
-
     def testSortedMarkdownList(self):
         input = ["bbb " * 25, "aaa " * 30, "ccc " * 35]
         actual_output = SortedMarkdownList(input)
diff --git a/tools/json_schema_compiler/test/web_idl/basics.idl b/tools/json_schema_compiler/test/web_idl/basics.idl
index 32ebe42..370a846 100644
--- a/tools/json_schema_compiler/test/web_idl/basics.idl
+++ b/tools/json_schema_compiler/test/web_idl/basics.idl
@@ -17,6 +17,8 @@
   static double returnsDouble();
   static long returnsLong();
   static DOMString returnsDOMString();
+  static sequence<DOMString> returnsDOMStringSequence();
+  static sequence<ExampleType> returnsCustomTypeSequence();
 
   static undefined takesNoArguments();
   static undefined takesDOMString(DOMString stringArgument);
@@ -25,6 +27,9 @@
       DOMString argument1, optional double argument2);
   static undefined takesOptionalInnerArgument(
       DOMString first, optional DOMString optionalInner, DOMString last);
+  static undefined takesSequenceArgument(sequence<boolean> sequenceArgument);
+  static undefined takesOptionalSequenceArgument(
+      optional sequence<boolean> optionalSequenceArgument);
 
   static ExampleType returnsCustomType();
   static undefined takesCustomType(ExampleType customTypeArgument);
@@ -35,8 +40,10 @@
   static Promise<DOMString?> nullablePromiseReturn();
   static Promise<ExampleType> customTypePromiseReturn();
   static Promise<undefined> undefinedPromiseReturn();
+  static Promise<sequence<long>> longSequencePromiseReturn();
+  static Promise<sequence<ExampleType>> customTypeSequencePromiseReturn();
 
-  // Test items for comment to description processing:
+  // Items for testing the processing of IDL comments to schema descriptions:
 
   static undefined noDescription();
   // One line description.
@@ -94,6 +101,8 @@
   double someNumber;
   // Comment with HTML comment. <!-- Which should get through -->
   boolean? optionalBoolean;
+  // Comment on sequence type.
+  sequence<boolean> booleanSequence;
 };
 
 partial interface Browser {
diff --git a/tools/json_schema_compiler/web_idl_schema.py b/tools/json_schema_compiler/web_idl_schema.py
index 13fcad5b..733d579 100755
--- a/tools/json_schema_compiler/web_idl_schema.py
+++ b/tools/json_schema_compiler/web_idl_schema.py
@@ -301,6 +301,11 @@
       # with 'parameters' list that has a single element for the type.
       properties['parameters'] = self._ExtractParametersFromPromiseType(
           type_details)
+    elif type_details.IsA('Sequence'):
+      properties['type'] = 'array'
+      # Sequences are used to represent array types, which have an associated
+      # 'items' key that detail what type the array holds.
+      properties['items'] = ArrayType(type_details).Process()
     else:
       raise SchemaCompilerError('Unsupported type class when processing type.',
                                 type_details)
@@ -422,6 +427,13 @@
     return self.properties
 
 
+class ArrayType(TypedProperty):
+  """Handles processing for the type an array (IDL Sequence) consists of."""
+
+  def Process(self) -> dict:
+    return self.properties
+
+
 class DictionaryMember(TypedProperty):
   """Handles processing for members of custom types (dictionaries)."""
 
diff --git a/tools/json_schema_compiler/web_idl_schema_test.py b/tools/json_schema_compiler/web_idl_schema_test.py
index 50de0a9..2217d1f 100755
--- a/tools/json_schema_compiler/web_idl_schema_test.py
+++ b/tools/json_schema_compiler/web_idl_schema_test.py
@@ -165,6 +165,22 @@
         'name': 'returnsCustomType',
         '$ref': 'ExampleType'
     }, getFunctionReturn(schema, 'returnsCustomType'))
+    self.assertEqual(
+        {
+            'name': 'returnsDOMStringSequence',
+            'type': 'array',
+            'items': {
+                'type': 'string'
+            }
+        }, getFunctionReturn(schema, 'returnsDOMStringSequence'))
+    self.assertEqual(
+        {
+            'name': 'returnsCustomTypeSequence',
+            'type': 'array',
+            'items': {
+                '$ref': 'ExampleType'
+            }
+        }, getFunctionReturn(schema, 'returnsCustomTypeSequence'))
 
   def testPromiseBasedReturn(self):
     schema = self.idl_basics
@@ -198,6 +214,28 @@
         'parameters': [],
         'type': 'promise'
     }, getFunctionAsyncReturn(schema, 'undefinedPromiseReturn'))
+    self.assertEqual(
+        {
+            'name': 'callback',
+            'parameters': [{
+                'type': 'array',
+                'items': {
+                    'type': 'integer'
+                }
+            }],
+            'type': 'promise'
+        }, getFunctionAsyncReturn(schema, 'longSequencePromiseReturn'))
+    self.assertEqual(
+        {
+            'name': 'callback',
+            'parameters': [{
+                'type': 'array',
+                'items': {
+                    '$ref': 'ExampleType'
+                }
+            }],
+            'type': 'promise'
+        }, getFunctionAsyncReturn(schema, 'customTypeSequencePromiseReturn'))
 
   # Tests function parameters are processed as expected.
   def testFunctionParameters(self):
@@ -234,6 +272,21 @@
         'type': 'string'
     }], getFunctionParameters(schema, 'takesOptionalInnerArgument'))
     self.assertEqual([{
+        'name': 'sequenceArgument',
+        'type': 'array',
+        'items': {
+            'type': 'boolean'
+        }
+    }], getFunctionParameters(schema, 'takesSequenceArgument'))
+    self.assertEqual([{
+        'name': 'optionalSequenceArgument',
+        'type': 'array',
+        'optional': True,
+        'items': {
+            'type': 'boolean'
+        }
+    }], getFunctionParameters(schema, 'takesOptionalSequenceArgument'))
+    self.assertEqual([{
         'name': 'customTypeArgument',
         '$ref': 'ExampleType'
     }], getFunctionParameters(schema, 'takesCustomType'))
@@ -325,47 +378,47 @@
   # processed into types on the resulting namespace.
   def testApiTypesOnNamespace(self):
     schema = self.idl_basics
+    custom_type = getType(schema, 'ExampleType')
+    self.assertEqual('ExampleType', custom_type['id'])
+    self.assertEqual('object', custom_type['type'])
     self.assertEqual(
         {
-            'id': 'ExampleType',
-            'properties': {
-                'someString': {
-                    'name':
-                    'someString',
-                    'type':
-                    'string',
-                    'description':
-                    ('Attribute comment attached to ExampleType.someString.'),
-                },
-                'someNumber': {
-                    'name':
-                    'someNumber',
-                    'type':
-                    'number',
-                    'description':
-                    ('Comment where <var>someNumber</var> has some markup.'),
-                },
-                # TODO(crbug.com/379052294): using HTML comments like this is a
-                # bit of a hack to allow us to add comments in IDL files (e.g.
-                # for TODOs) and to not have them end up on the documentation
-                # site. We should probably just filter them out during
-                # compilation.
-                'optionalBoolean': {
-                    'name':
-                    'optionalBoolean',
-                    'type':
-                    'boolean',
-                    'optional':
-                    True,
-                    'description':
-                    ('Comment with HTML comment. <!-- Which should get'
-                     ' through -->'),
-                },
+            'name': 'someString',
+            'type': 'string',
+            'description':
+            'Attribute comment attached to ExampleType.someString.'
+        }, custom_type['properties']['someString'])
+    self.assertEqual(
+        {
+            'name': 'someNumber',
+            'type': 'number',
+            'description':
+            'Comment where <var>someNumber</var> has some markup.'
+        }, custom_type['properties']['someNumber'])
+    # TODO(crbug.com/379052294): using HTML comments like this is a bit of a
+    # hack to allow us to add comments in IDL files (e.g. for TODOs) and to not
+    # have them end up on the documentation site. We should probably just filter
+    # them out during compilation.
+    self.assertEqual(
+        {
+            'name':
+            'optionalBoolean',
+            'type':
+            'boolean',
+            'optional':
+            True,
+            'description':
+            'Comment with HTML comment. <!-- Which should get through -->'
+        }, custom_type['properties']['optionalBoolean'])
+    self.assertEqual(
+        {
+            'name': 'booleanSequence',
+            'type': 'array',
+            'items': {
+                'type': 'boolean'
             },
-            'type': 'object',
-        },
-        getType(schema, 'ExampleType'),
-    )
+            'description': 'Comment on sequence type.',
+        }, custom_type['properties']['booleanSequence'])
 
   # Tests that a top level API comment is processed into a description
   # attribute, with HTML paragraph nodes added due to the blank commented line.
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 487878c..fde26c3 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -40133,6 +40133,24 @@
   </description>
 </action>
 
+<action name="Signin_Signin_FromNonModalSigninBookmarkPromo">
+  <owner>kanouche@google.com</owner>
+  <owner>bling-mony-pod@google.com</owner>
+  <description>
+    Recorded on sign in start from access point
+    signin_metrics::AccessPoint::kNonModalSigninBookmarkPromo.
+  </description>
+</action>
+
+<action name="Signin_Signin_FromNonModalSigninPasswordPromo">
+  <owner>kanouche@google.com</owner>
+  <owner>bling-mony-pod@google.com</owner>
+  <description>
+    Recorded on sign in start from access point
+    signin_metrics::AccessPoint::kNonModalSigninPasswordPromo.
+  </description>
+</action>
+
 <action name="Signin_Signin_FromNotificationsOptInScreenContentToggle">
   <owner>hiramahmood@google.com</owner>
   <owner>scottyoder@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 2de32181..a08dc3c 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -4078,24 +4078,6 @@
   </summary>
 </histogram>
 
-<histogram name="Ash.Frame.ColorChangeCount.{AppType}" units="count"
-    expires_after="2025-05-11">
-  <owner>lingyufeng@google.com</owner>
-  <owner>arc-framework@google.com</owner>
-  <summary>
-    Tracks the number of frame color changes when a {AppType} is launched. The
-    data is collected once per app launching.
-  </summary>
-  <token key="AppType">
-    <variant name="ArcApp"/>
-    <variant name="Browser"/>
-    <variant name="ChromeApp"/>
-    <variant name="CrostiniApp"/>
-    <variant name="Others"/>
-    <variant name="SystemApp"/>
-  </token>
-</histogram>
-
 <histogram name="Ash.FullRestore.Browser.FirstInputDelay" units="ms"
     expires_after="2025-11-02">
   <owner>esum@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index deda7fbc..1a2e11c 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -70,6 +70,12 @@
       summary="Only product description was visible"/>
 </variants>
 
+<variants name="Autofill.CreditCardBenefitSource">
+  <variant name="Amex" summary="American Express"/>
+  <variant name="Bmo" summary="BMO"/>
+  <variant name="Curinos" summary="Curinos"/>
+</variants>
+
 <variants name="Autofill.CreditCardIssuerId">
   <variant name="Amex" summary="card issued by American Express"/>
   <variant name="Anz" summary="card issued by ANZ"/>
@@ -84,11 +90,6 @@
   <variant name="Natwest" summary="card issued by Natwest"/>
 </variants>
 
-<variants name="Autofill.CreditCardIssuerId.WithBenefits">
-  <variant name="Amex" summary="card issued by American Express"/>
-  <variant name="Bmo" summary="card issued by BMO"/>
-</variants>
-
 <variants name="Autofill.CreditCardNetwork">
   <variant name="Mastercard" summary="card with the Mastercard network."/>
   <variant name="Visa" summary="card with the Visa network."/>
@@ -3079,19 +3080,18 @@
   </summary>
 </histogram>
 
-<histogram name="Autofill.FormEvents.CreditCard.WithBenefits.{CardIssuerId}"
+<histogram
+    name="Autofill.FormEvents.CreditCard.WithBenefits.{CardBenefitSource}"
     enum="AutofillFormEvent" expires_after="2025-11-09">
-  <owner>alexandertekle@google.com</owner>
   <owner>yishuil@google.com</owner>
   <summary>
     Autofill form events for credit card forms that contain at least one
     suggestion where a card benefit is available. This includes logging for when
     card suggestions with benefits are shown, selected, filled, and submitted,
-    and logs at each of those times. Log emission pertains to the credit card
-    issuer, {CardIssuerId}.
+    and logs at each of those times. Log emission pertains to credit cards where
+    the benefit source is {CardBenefitSource}.
   </summary>
-  <token key="CardIssuerId"
-      variants="Autofill.CreditCardIssuerId.WithBenefits"/>
+  <token key="CardBenefitSource" variants="Autofill.CreditCardBenefitSource"/>
 </histogram>
 
 <histogram name="Autofill.FormEvents.CreditCard.WithOffer"
diff --git a/tools/metrics/histograms/metadata/collaboration_service/enums.xml b/tools/metrics/histograms/metadata/collaboration_service/enums.xml
index 0403b0d..d015402 100644
--- a/tools/metrics/histograms/metadata/collaboration_service/enums.xml
+++ b/tools/metrics/histograms/metadata/collaboration_service/enums.xml
@@ -161,18 +161,6 @@
 
 <!-- LINT.ThenChange(//components/collaboration/internal/metrics.h:CollaborationServiceShareOrManageEvent) -->
 
-<!-- LINT.IfChange(CollaborationServiceStep) -->
-
-<enum name="CollaborationServiceStep">
-  <int value="0" label="Unknown"/>
-  <int value="1" label="Time for authentication success"/>
-  <int value="2" label="Time for services initialization"/>
-  <int value="3" label="Time for link to be ready after group creation"/>
-  <int value="4" label="Time for tab group to be fetched after group creation"/>
-</enum>
-
-<!-- LINT.ThenChange(//components/collaboration/internal/metrics.h:CollaborationServiceStep) -->
-
 </enums>
 
 </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/collaboration_service/histograms.xml b/tools/metrics/histograms/metadata/collaboration_service/histograms.xml
index 00bda2f..cf71d8a 100644
--- a/tools/metrics/histograms/metadata/collaboration_service/histograms.xml
+++ b/tools/metrics/histograms/metadata/collaboration_service/histograms.xml
@@ -22,6 +22,18 @@
 
 <histograms>
 
+<variants name="CollaborationServiceStep">
+  <variant name="AuthenticationInitToSuccess"
+      summary="Authentication initiated to successful completion"/>
+  <variant name="LinkReadyAfterGroupCreation"
+      summary="Link ready after group creation"/>
+  <variant name="TabGroupFetchedAfterPeopleGroupJoined"
+      summary="Tab group fetched after group creation"/>
+  <variant name="Unknown" summary="Unknown"/>
+  <variant name="WaitingForServicesInitialization"
+      summary="Waiting time for service initialization"/>
+</variants>
+
 <histogram name="CollaborationService.JoinFlow"
     enum="CollaborationServiceJoinEvent" expires_after="2025-10-11">
   <owner>dljames@chromium.org</owner>
@@ -45,17 +57,18 @@
   </summary>
 </histogram>
 
-<histogram name="CollaborationService.Latency" enum="CollaborationServiceStep"
-    expires_after="2025-10-11">
+<histogram name="CollaborationService.Latency2.{CollaborationServiceStep}"
+    units="ms" expires_after="2025-10-11">
   <owner>haileywang@google.com</owner>
   <owner>chrome-tab-group-eng@google.com</owner>
   <summary>
     [ All platforms ] Tracks the time in milliseconds between when a flow step
     is started and finished.
 
-    Recorded by the CollaborationService for each step in a collaboration flow
-    that has user wait time.
+    Recorded by the CollaborationService for each {CollaborationServiceStep} in
+    a collaboration flow that has user wait time.
   </summary>
+  <token key="CollaborationServiceStep" variants="CollaborationServiceStep"/>
 </histogram>
 
 <histogram name="CollaborationService.ShareOrManageFlow"
diff --git a/tools/metrics/histograms/metadata/enterprise/enums.xml b/tools/metrics/histograms/metadata/enterprise/enums.xml
index 8f1d648..ed3fe225 100644
--- a/tools/metrics/histograms/metadata/enterprise/enums.xml
+++ b/tools/metrics/histograms/metadata/enterprise/enums.xml
@@ -34,6 +34,7 @@
 <enum name="CertificatePrivateKeySource">
   <int value="0" label="Unexportable"/>
   <int value="1" label="Software"/>
+  <int value="2" label="OsSoftware"/>
 </enum>
 
 <enum name="CertificateProvisioningError">
diff --git a/tools/metrics/histograms/metadata/glic/enums.xml b/tools/metrics/histograms/metadata/glic/enums.xml
index 837bd02..7f47872 100644
--- a/tools/metrics/histograms/metadata/glic/enums.xml
+++ b/tools/metrics/histograms/metadata/glic/enums.xml
@@ -56,6 +56,28 @@
 
 <!-- LINT.ThenChange(//chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h:DeepScanAccessPoint) -->
 
+<!-- LINT.IfChange(FreWebUiState) -->
+
+<enum name="FreWebUiState">
+  <int value="0" label="Glic fre app controller not started."/>
+  <int value="1" label="Web client begins loading; no visible UI."/>
+  <int value="2"
+      label="Loading panel is displayed. This state, combined with the
+             `hold-loading` state, will be held for `kMinHoldLoadingTimeMs`
+             if entered."/>
+  <int value="3"
+      label="Loading panel is still displayed, but the web client is ready.
+             This state will be held for the remainder of
+             `kMinHoldLoadingTimeMs`."/>
+  <int value="4"
+      label="Loading panel is displayed until web client is ready, or until"/>
+  <int value="5" label="'Something went wrong' error panel is displayed."/>
+  <int value="6" label="Connection offline panel is displayed."/>
+  <int value="7" label="Web view is displayed."/>
+</enum>
+
+<!-- LINT.ThenChange(//chrome/browser/glic/fre/glic_fre.mojom:FreWebUiState) -->
+
 <!-- LINT.IfChange(GlicAttachChangeReason) -->
 
 <enum name="GlicAttachChangeReason">
diff --git a/tools/metrics/histograms/metadata/glic/histograms.xml b/tools/metrics/histograms/metadata/glic/histograms.xml
index 59e4d26..195ac2a2 100644
--- a/tools/metrics/histograms/metadata/glic/histograms.xml
+++ b/tools/metrics/histograms/metadata/glic/histograms.xml
@@ -166,6 +166,13 @@
   </summary>
 </histogram>
 
+<histogram name="Glic.FreModalWebUiState.FinishState" enum="FreWebUiState"
+    expires_after="2026-01-15">
+  <owner>cuianthony@google.com</owner>
+  <owner>iwells@google.com</owner>
+  <summary>Record the current state of the FRE modal when it closes.</summary>
+</histogram>
+
 <histogram name="Glic.FrePresentationTime" units="ms"
     expires_after="2026-01-15">
   <owner>dewittj@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/net/enums.xml b/tools/metrics/histograms/metadata/net/enums.xml
index 6e602ce..a1c9a8b 100644
--- a/tools/metrics/histograms/metadata/net/enums.xml
+++ b/tools/metrics/histograms/metadata/net/enums.xml
@@ -273,6 +273,17 @@
 
 <!-- LINT.ThenChange(//net/device_bound_sessions/session_error.h:DeviceBoundSessionError) -->
 
+<!-- LINT.IfChange(DeviceBoundSessionUsage) -->
+
+<enum name="DeviceBoundSessionUsage">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="Not in scope of any session"/>
+  <int value="2" label="In scope but not deferred"/>
+  <int value="3" label="In scope and deferred"/>
+</enum>
+
+<!-- LINT.ThenChange(//net/device_bound_sessions/session_usage.h:DeviceBoundSessionUsage) -->
+
 <enum name="DNS.AttemptType">
   <int value="0" label="DnsUDPAttempt"/>
   <int value="1" label="DnsTCPAttempt due to low UDP entropy"/>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index f654280..947ca38c 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -1538,7 +1538,20 @@
   <summary>
     This records how many times a request was deferred due to a Device Bound
     Session (https://github.com/w3c/webappsec-dbsc/blob/main/README.md). This is
-    logged once for every network request.
+    logged once for most network requests that can add a cookie header; requests
+    that attempt to refresh but fail are omitted.
+  </summary>
+</histogram>
+
+<histogram name="Net.DeviceBoundSessions.RequestDeferralDecision"
+    enum="DeviceBoundSessionUsage" expires_after="2025-11-13">
+  <owner>thefrog@chromium.org</owner>
+  <owner>chrome-counter-abuse-alerts@google.com</owner>
+  <summary>
+    This records whether a request was deferred due to a Device Bound Session
+    (https://github.com/w3c/webappsec-dbsc/blob/main/README.md) and the reason
+    for that decision. This is logged once for most network requests that can
+    add a cookie header; requests that attempt to refresh but fail are omitted.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml
index be5fd27..a4f38c4f 100644
--- a/tools/metrics/histograms/metadata/optimization/histograms.xml
+++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -2195,8 +2195,8 @@
 <histogram name="OptimizationGuide.TextSafetyChecker.InferenceResult"
     enum="OptimizationGuideTextSafetyInferenceResult"
     expires_after="2025-10-26">
-  <owner>rockot@google.com</owner>
-  <owner>sophiechange@chromium.org</owner>
+  <owner>holte@google.com</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     The result of a text safety inference request. Recorded once for each such
     request.
@@ -2205,8 +2205,8 @@
 
 <histogram name="OptimizationGuide.TextSafetyChecker.InitTime" units="ms"
     expires_after="2025-10-19">
-  <owner>rockot@google.com</owner>
-  <owner>sophiechange@chromium.org</owner>
+  <owner>holte@google.com</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     The duration of the text safety checker's initialization time. Recorded once
     for each new model execution session.
@@ -2215,8 +2215,8 @@
 
 <histogram name="OptimizationGuide.TextSafetyChecker.ModelCreationTime"
     units="ms" expires_after="2025-10-19">
-  <owner>rockot@google.com</owner>
-  <owner>sophiechange@chromium.org</owner>
+  <owner>holte@google.com</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     The duration elapsed during text safety model creation. Recorded once for
     each text safety inference request.
@@ -2225,8 +2225,8 @@
 
 <histogram name="OptimizationGuide.TextSafetyChecker.ModelExecutionTime"
     units="ms" expires_after="M145">
-  <owner>rockot@google.com</owner>
-  <owner>sophiechange@chromium.org</owner>
+  <owner>holte@google.com</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     The duration of text safety model execution. Recorded once for each text
     safety inference request.
@@ -2235,8 +2235,8 @@
 
 <histogram name="OptimizationGuide.TextSafetyChecker.TokensPerSecond"
     units="counts" expires_after="2025-10-26">
-  <owner>rockot@google.com</owner>
-  <owner>sophiechange@chromium.org</owner>
+  <owner>holte@google.com</owner>
+  <owner>sophiechang@chromium.org</owner>
   <summary>
     An estimate of the text safety model's inference throughput in tokens per
     second. Recorded once for each text safety inference request.
diff --git a/tools/metrics/histograms/metadata/signin/enums.xml b/tools/metrics/histograms/metadata/signin/enums.xml
index 9fd5191..8ff089e 100644
--- a/tools/metrics/histograms/metadata/signin/enums.xml
+++ b/tools/metrics/histograms/metadata/signin/enums.xml
@@ -763,6 +763,10 @@
   <int value="81" label="History sync educational tip module (Android only)"/>
   <int value="82"
       label="Managed profile was automatically signed in (iOS only)"/>
+  <int value="83"
+      label="Contextual non modal sign-in password promo (iOS only)"/>
+  <int value="84"
+      label="Contextual non modal sign-in bookmark promo (iOS only)"/>
 </enum>
 
 <enum name="SigninAccountReconcilorState">
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml
index 8301b77..36e67a8 100644
--- a/tools/metrics/histograms/metadata/tab/histograms.xml
+++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -3573,6 +3573,26 @@
   </summary>
 </histogram>
 
+<histogram name="TabStrip.Tab.ContextMenuReloadCount" units="tabs"
+    expires_after="2025-11-14">
+  <owner>agale@chromium.org</owner>
+  <owner>top-chrome-desktop-ui@google.com</owner>
+  <summary>
+    When the user reloads a tab using the tab context menu, records the number
+    of tabs being reloaded.
+  </summary>
+</histogram>
+
+<histogram name="TabStrip.Tab.ReloadCount" units="tabs"
+    expires_after="2025-11-14">
+  <owner>agale@chromium.org</owner>
+  <owner>top-chrome-desktop-ui@google.com</owner>
+  <summary>
+    When the user reloads a tab using the toolbar button, hotkey, or contents
+    context menu, records the number of tabs being reloaded.
+  </summary>
+</histogram>
+
 <histogram name="TabStrip.Tab.{Framework}.ActivationAction"
     enum="TabActivationTypes" expires_after="2025-09-14">
   <owner>yuhengh@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 1559545..5a93941 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,7 +6,7 @@
         },
         "win": {
             "hash": "51491773ab5c0cecb7f5dfa9cd5003db755da0f3",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/9fa4d6fe6c2b7e26c3a87d2c0adee33f2898030c/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/6690560f58167a82a9302a6df05303324f0e91bb/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "99f971ca131f6d11c73f4b918099d434bdd8093c",
diff --git a/tools/rust/update_rust.py b/tools/rust/update_rust.py
index e4cf4e0c..805a9c6e 100755
--- a/tools/rust/update_rust.py
+++ b/tools/rust/update_rust.py
@@ -32,7 +32,7 @@
 # These fields are written by //tools/clang/scripts/upload_revision.py, and
 # should not be changed manually.
 # They are also read by build/config/compiler/BUILD.gn.
-RUST_REVISION = 'c8f94230282a8e8c1148f3e657f0199aad909228'
+RUST_REVISION = '4a0969e06dbeaaa43914d2d00b2e843d49aa3886'
 RUST_SUB_REVISION = 1
 
 # The revision of Crubit to use from https://github.com/google/crubit
@@ -47,7 +47,7 @@
 # Hash of src/stage0.json, which itself contains the stage0 toolchain hashes.
 # We trust the Rust build system checks, but to ensure it is not tampered with
 # itself check the hash.
-STAGE0_JSON_SHA256 = '1113296e1412c791d09f3033355001061e7ca36e06e796ff0f1f798791a6d93b'
+STAGE0_JSON_SHA256 = '981bcaeac1c5f7035166cd59941e4a8e2070c9eb977bc9ef881e656b60c79055'
 
 THIS_DIR = os.path.abspath(os.path.dirname(__file__))
 CHROMIUM_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..'))
diff --git a/ui/android/javatests/src/org/chromium/ui/test/util/RenderTestRule.java b/ui/android/javatests/src/org/chromium/ui/test/util/RenderTestRule.java
index b9208161..d8daecd 100644
--- a/ui/android/javatests/src/org/chromium/ui/test/util/RenderTestRule.java
+++ b/ui/android/javatests/src/org/chromium/ui/test/util/RenderTestRule.java
@@ -140,6 +140,7 @@
         Component.UI_BROWSER_AUTOFILL,
         Component.UI_BROWSER_BOOKMARKS,
         Component.UI_BROWSER_BUBBLES_PAGE_INFO,
+        Component.UI_BROWSER_CHROME_TABS_CHROME_TAB_GROUPS_SHARED_TAB_GROUPS,
         Component.UI_BROWSER_CONTENT_SUGGESTIONS,
         Component.UI_BROWSER_CONTENT_SUGGESTIONS_FEED,
         Component.UI_BROWSER_CONTENT_SUGGESTIONS_HISTORY,
@@ -174,7 +175,7 @@
         Component.UI_BROWSER_TOOLBAR,
         Component.UI_BROWSER_THUMBNAIL,
         Component.UI_BROWSER_WEB_APP_INSTALLS,
-        Component.UI_SETTINGS_PRIVACY
+        Component.UI_SETTINGS_PRIVACY,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Component {
@@ -190,6 +191,8 @@
         String UI_BROWSER_AUTOFILL = "UI>Browser>Autofill";
         String UI_BROWSER_BOOKMARKS = "UI>Browser>Bookmarks";
         String UI_BROWSER_BUBBLES_PAGE_INFO = "UI>Browser>Bubbles>PageInfo";
+        String UI_BROWSER_CHROME_TABS_CHROME_TAB_GROUPS_SHARED_TAB_GROUPS =
+                "UI>Browser>ChromeTabs>ChromeTabGroups>SharedTabGroups";
         String UI_BROWSER_CONTENT_SUGGESTIONS = "UI>Browser>ContentSuggestions";
         String UI_BROWSER_CONTENT_SUGGESTIONS_FEED = "UI>Browser>ContentSuggestions>Feed";
         String UI_BROWSER_CONTENT_SUGGESTIONS_HISTORY = "UI>Browser>ContentSuggestions>History";
diff --git a/ui/gfx/buffer_types.h b/ui/gfx/buffer_types.h
index b9745cf..9de8271ca 100644
--- a/ui/gfx/buffer_types.h
+++ b/ui/gfx/buffer_types.h
@@ -7,8 +7,6 @@
 
 #include <stdint.h>
 
-#include <tuple>
-
 namespace gfx {
 
 // The format needs to be taken into account when mapping a buffer into the
@@ -75,7 +73,7 @@
       : usage(usage), format(format) {}
 
   bool operator==(const BufferUsageAndFormat& other) const {
-    return std::tie(usage, format) == std::tie(other.usage, other.format);
+    return usage == other.usage && format == other.format;
   }
 
   BufferUsage usage;
diff --git a/ui/menus/android/menu_model_bridge.cc b/ui/menus/android/menu_model_bridge.cc
index 5d49cfe..da2a4c4 100644
--- a/ui/menus/android/menu_model_bridge.cc
+++ b/ui/menus/android/menu_model_bridge.cc
@@ -26,6 +26,9 @@
   JNIEnv* env = base::android::AttachCurrentThread();
   java_obj_ = Java_MenuModelBridge_create(env);
 }
+
+MenuModelBridge::~MenuModelBridge() = default;
+
 void MenuModelBridge::AddExtensionItems(ui::MenuModel* menu_model) {
   JNIEnv* env = base::android::AttachCurrentThread();
   for (size_t i = 0; i < menu_model->GetItemCount(); ++i) {
diff --git a/url/url_canon.h b/url/url_canon.h
index 9de4f64a..c93dbf68 100644
--- a/url/url_canon.h
+++ b/url/url_canon.h
@@ -345,13 +345,11 @@
 //
 // The 8-bit version requires UTF-8 encoding.
 COMPONENT_EXPORT(URL)
-bool CanonicalizeScheme(const char* spec,
-                        const Component& scheme,
+bool CanonicalizeScheme(std::optional<std::string_view> input,
                         CanonOutput* output,
                         Component* out_scheme);
 COMPONENT_EXPORT(URL)
-bool CanonicalizeScheme(const char16_t* spec,
-                        const Component& scheme,
+bool CanonicalizeScheme(std::optional<std::u16string_view> input,
                         CanonOutput* output,
                         Component* out_scheme);
 
diff --git a/url/url_canon_etc.cc b/url/url_canon_etc.cc
index dcb5e3f..96b98303 100644
--- a/url/url_canon_etc.cc
+++ b/url/url_canon_etc.cc
@@ -118,17 +118,18 @@
 }
 
 template <typename CHAR, typename UCHAR>
-bool DoScheme(const CHAR* spec,
-              const Component& scheme,
+bool DoScheme(std::optional<std::basic_string_view<CHAR>> input,
               CanonOutput* output,
               Component* out_scheme) {
-  if (scheme.is_empty()) {
+  if (!input.has_value() || input->empty()) {
     // Scheme is unspecified or empty, convert to empty by appending a colon.
     *out_scheme = Component(output->length(), 0);
     output->push_back(':');
     return false;
   }
 
+  auto input_value = input.value();
+
   // The output scheme starts from the current position.
   out_scheme->begin = output->length();
 
@@ -138,13 +139,11 @@
   // FindAndCompareScheme, which could cause some security checks on
   // schemes to be incorrect.
   bool success = true;
-  size_t begin = static_cast<size_t>(scheme.begin);
-  size_t end = static_cast<size_t>(scheme.end());
-  for (size_t i = begin; i < end; i++) {
-    UCHAR ch = static_cast<UCHAR>(spec[i]);
+  for (size_t i = 0; i < input_value.length(); i++) {
+    UCHAR ch = static_cast<UCHAR>(input_value[i]);
     char replacement = 0;
     if (ch < 0x80) {
-      if (i == begin) {
+      if (i == 0) {
         // Need to do a special check for the first letter of the scheme.
         if (IsSchemeFirstChar(static_cast<unsigned char>(ch)))
           replacement = kSchemeCanonical[ch];
@@ -167,7 +166,8 @@
 
       // This will escape the output and also handle encoding issues.
       // Ignore the return value since we already failed.
-      AppendUTF8EscapedChar(spec, &i, end, output);
+      AppendUTF8EscapedChar(input_value.data(), &i, input_value.length(),
+                            output);
     }
   }
 
@@ -363,18 +363,16 @@
   return kSchemeCanonical[ch];
 }
 
-bool CanonicalizeScheme(const char* spec,
-                        const Component& scheme,
+bool CanonicalizeScheme(std::optional<std::string_view> input,
                         CanonOutput* output,
                         Component* out_scheme) {
-  return DoScheme<char, unsigned char>(spec, scheme, output, out_scheme);
+  return DoScheme<char, unsigned char>(input, output, out_scheme);
 }
 
-bool CanonicalizeScheme(const char16_t* spec,
-                        const Component& scheme,
+bool CanonicalizeScheme(std::optional<std::u16string_view> input,
                         CanonOutput* output,
                         Component* out_scheme) {
-  return DoScheme<char16_t, char16_t>(spec, scheme, output, out_scheme);
+  return DoScheme<char16_t, char16_t>(input, output, out_scheme);
 }
 
 bool CanonicalizeUserInfo(const char* username_source,
diff --git a/url/url_canon_non_special_url.cc b/url/url_canon_non_special_url.cc
index 8c55bac1..9a6b856 100644
--- a/url/url_canon_non_special_url.cc
+++ b/url/url_canon_non_special_url.cc
@@ -32,8 +32,9 @@
   DCHECK(!parsed.has_opaque_path);
 
   // Scheme: this will append the colon.
-  bool success = CanonicalizeScheme(source.scheme, parsed.scheme, &output,
-                                    &new_parsed.scheme);
+  bool success =
+      CanonicalizeScheme(parsed.scheme.maybe_as_string_view_on(source.scheme),
+                         &output, &new_parsed.scheme);
   bool have_authority =
       (parsed.username.is_valid() || parsed.password.is_valid() ||
        parsed.host.is_valid() || parsed.port.is_valid());
diff --git a/url/url_canon_pathurl.cc b/url/url_canon_pathurl.cc
index 17269084..0798270 100644
--- a/url/url_canon_pathurl.cc
+++ b/url/url_canon_pathurl.cc
@@ -59,8 +59,9 @@
                            CanonOutput* output,
                            Parsed* new_parsed) {
   // Scheme: this will append the colon.
-  bool success = CanonicalizeScheme(source.scheme, parsed.scheme,
-                                    output, &new_parsed->scheme);
+  bool success =
+      CanonicalizeScheme(parsed.scheme.maybe_as_string_view_on(source.scheme),
+                         output, &new_parsed->scheme);
 
   // We assume there's no authority for path URLs. Note that hosts should never
   // have -1 length.
diff --git a/url/url_canon_stdurl.cc b/url/url_canon_stdurl.cc
index 659d0ee..eeb14e6 100644
--- a/url/url_canon_stdurl.cc
+++ b/url/url_canon_stdurl.cc
@@ -28,8 +28,9 @@
   DCHECK(!parsed.has_opaque_path);
 
   // Scheme: this will append the colon.
-  bool success = CanonicalizeScheme(source.scheme, parsed.scheme,
-                                    output, &new_parsed->scheme);
+  bool success =
+      CanonicalizeScheme(parsed.scheme.maybe_as_string_view_on(source.scheme),
+                         output, &new_parsed->scheme);
 
   bool scheme_supports_user_info =
       (scheme_type == SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION);
diff --git a/url/url_canon_unittest.cc b/url/url_canon_unittest.cc
index b297c7c2..f1b27b6c 100644
--- a/url/url_canon_unittest.cc
+++ b/url/url_canon_unittest.cc
@@ -334,8 +334,8 @@
 
     out_str.clear();
     StdStringCanonOutput output1(&out_str);
-    bool success =
-        CanonicalizeScheme(scheme_case.input, in_comp, &output1, &out_comp);
+    bool success = CanonicalizeScheme(
+        in_comp.as_string_view_on(scheme_case.input), &output1, &out_comp);
     output1.Complete();
 
     EXPECT_EQ(scheme_case.expected_success, success);
@@ -349,8 +349,8 @@
 
     std::u16string wide_input(base::UTF8ToUTF16(scheme_case.input));
     in_comp.len = static_cast<int>(wide_input.length());
-    success = CanonicalizeScheme(wide_input.c_str(), in_comp, &output2,
-                                 &out_comp);
+    success = CanonicalizeScheme(in_comp.as_string_view_on(wide_input.c_str()),
+                                 &output2, &out_comp);
     output2.Complete();
 
     EXPECT_EQ(scheme_case.expected_success, success);
@@ -365,7 +365,8 @@
   out_str.clear();
   StdStringCanonOutput output(&out_str);
 
-  EXPECT_FALSE(CanonicalizeScheme("", Component(0, -1), &output, &out_comp));
+  EXPECT_FALSE(CanonicalizeScheme(std::optional<std::string_view>(std::nullopt),
+                                  &output, &out_comp));
   output.Complete();
 
   EXPECT_EQ(":", out_str);
diff --git a/url/url_util.cc b/url/url_util.cc
index 67c4c5f..e09d63e 100644
--- a/url/url_util.cc
+++ b/url/url_util.cc
@@ -458,8 +458,8 @@
     // the existing spec.
     STACK_UNINITIALIZED RawCanonOutput<128> scheme_replaced;
     Component scheme_replaced_parsed;
-    CanonicalizeScheme(replacements.sources().scheme,
-                       replacements.components().scheme,
+    CanonicalizeScheme(replacements.components().scheme.as_string_view_on(
+                           replacements.sources().scheme),
                        &scheme_replaced, &scheme_replaced_parsed);
 
     // We can assume that the input is canonicalized, which means it always has
diff --git a/v8 b/v8
index 5532a66..a6505e5 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 5532a667175e9b1a2597111ab674e8ba09c8d505
+Subproject commit a6505e5f6d22a63788a3ee59f44ca539774fbe4c