diff --git a/.gitignore b/.gitignore
index d54f60e4..595430f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,6 +58,7 @@
 Thumbs.db
 v8.log
 vs-chromium-project.txt
+/.cache/
 /.clangd/
 /.clangd-index/
 # Settings directories for eclipse
@@ -324,5 +325,8 @@
 # Ignore IntelliJ files.
 .idea/
 
+# Ignore cache folder created by clangd
+.cache
+
 # Ignore the default results output directory for tools/run-swarmed.py
 /results
diff --git a/DEPS b/DEPS
index 84156b0..137a711f 100644
--- a/DEPS
+++ b/DEPS
@@ -194,11 +194,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '9421094d01b1c47e1b913b4b6c594058c521c2fc',
+  'skia_revision': '14fdcdc891cc2f2f795354890b09ac528f3387c9',
   # 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': 'a721ddbab67cddef2aa3a686d0f60113c2514c32',
+  'v8_revision': 'b0b637030dd5b92b5ef11dad6d0d2f1e7904187e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -206,7 +206,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '4ad0f250a01010651985f2a1772c5cff11257d7a',
+  'angle_revision': 'c44b2b2567aeb73cca60343fcdb13a9db0f3e598',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -214,7 +214,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'a61a55a444b3bff3047de4bcc495d1cf92c76d93',
+  'pdfium_revision': '8516651130b5e2b1a382ad9d9e43e4eccc3abc81',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -245,7 +245,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '5fe7c044c25bba9dfae315ef56bacfc83976ddd0',
+  'freetype_revision': 'b7c467b6efa5a91945854de81632be45d6f360ff',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
@@ -257,7 +257,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': '49d9f039e26bc6da5267ff4afe44a19db8b2a44a',
+  'catapult_revision': 'f4db4dad69d7426c19b8de58ca973858f3c01f94',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -265,7 +265,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '4290f3d1534febb4e672bde73944fe2d5f80d86d',
+  'devtools_frontend_revision': '2a41471831919582f75a836c80716ebecc6f2acf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -301,7 +301,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.
-  'spv_tools_revision': '40c3c1cace0ae23f89a5da6f5d3111f299985694',
+  'spv_tools_revision': '4c33fb0d3dbaf8b2579c112cdbb7e9794143e337',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -317,7 +317,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': 'b31f5e717e2d5de567ee7a5b6a32acdf16ba180c',
+  'dawn_revision': '212c5bd9b2f06dd8f9f47a527d352717d83e8ed1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -541,7 +541,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '3117c254c4bd8fc6b681b10334ef0882a9461ff2',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '3002e9a73f9b6c070495fc7f27d1cc183b8bdd4f',
       'condition': 'checkout_ios',
   },
 
@@ -733,7 +733,7 @@
   },
 
   'src/third_party/android_sdk/androidx_browser/src': {
-      'url': Var('chromium_git') + '/external/gob/android/platform/frameworks/support/browser.git' + '@' + 'ac2f9c348999e8943567c6e4d50a82a5010ca263',
+      'url': Var('chromium_git') + '/external/gob/android/platform/frameworks/support/browser.git' + '@' + '37242f782de8096e24dff528b1bcac55a364b756',
       'condition': 'checkout_android',
   },
 
@@ -1241,7 +1241,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '55ef680dab933301b0a9aec7d3021714dcde26cd',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '73b607f9e3b436b7fc32f45263375b3de5a62dba',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1338,7 +1338,7 @@
   },
 
   'src/third_party/re2/src':
-    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'a65cf8adc4eb975683f1db54ff788caa7a9b4f01',
+    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'ca11026a032ce2a3de4b3c389ee53d2bdc8794d6',
 
   'src/third_party/r8': {
       'packages': [
@@ -1541,7 +1541,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@24010e318dc48b5e77cc7cd9916a45b0825cb47a',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@25a5e06a7d176721b02336031e210183d2d4808e',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/base/memory/checked_ptr.cc b/base/memory/checked_ptr.cc
index 0010b24..96767c6 100644
--- a/base/memory/checked_ptr.cc
+++ b/base/memory/checked_ptr.cc
@@ -9,13 +9,18 @@
 namespace base {
 namespace internal {
 
-#if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL) && \
-    ENABLE_TAG_FOR_CHECKED_PTR2
+#if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
 
-BASE_EXPORT bool CheckedPtr2ImplPartitionAllocSupport::EnabledForPtr(
+BASE_EXPORT bool CheckedPtr2OrMTEImplPartitionAllocSupport::EnabledForPtr(
     void* ptr) {
-  // CheckedPtr2Impl works only when memory is allocated by PartitionAlloc *and*
-  // the pointer points to the beginning of the allocated slot.
+  // CheckedPtr2 and MTECheckedPtr algorithms work only when memory is allocated
+  // by PartitionAlloc, from normal buckets pool. CheckedPtr2 additionally
+  // requires that the pointer points to the beginning of the allocated slot.
+  //
+  // TODO(bartekn): Allow direct-map buckets for MTECheckedPtr, once
+  // PartitionAlloc supports it. (Currently not implemented for simplicity, but
+  // there are no technological obstacles preventing it; whereas in case of
+  // CheckedPtr2, PartitionAllocGetSlotOffset won't work with direct-map.)
   //
   // NOTE, CheckedPtr doesn't know which thread-safery PartitionAlloc variant
   // it's dealing with. Just use ThreadSafe variant, because it's more common.
@@ -23,8 +28,11 @@
   // transitioned to Oilpan. PartitionAllocGetSlotOffset is expected to return
   // the same result regardless, anyway.
   // TODO(bartekn): Figure out the thread-safety mismatch.
-  return IsManagedByPartitionAllocNormalBuckets(ptr) &&
-         PartitionAllocGetSlotOffset<ThreadSafe>(ptr) == 0;
+  return IsManagedByPartitionAllocNormalBuckets(ptr)
+#if ENABLE_TAG_FOR_CHECKED_PTR2
+         && PartitionAllocGetSlotOffset<ThreadSafe>(ptr) == 0
+#endif
+      ;
 }
 
 #endif
diff --git a/base/memory/checked_ptr.h b/base/memory/checked_ptr.h
index 1687d312..87bd0b0f 100644
--- a/base/memory/checked_ptr.h
+++ b/base/memory/checked_ptr.h
@@ -79,8 +79,7 @@
   static ALWAYS_INLINE void IncrementSwapCountForTest() {}
 };
 
-#if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL) && \
-    ENABLE_TAG_FOR_CHECKED_PTR2
+#if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
 
 constexpr int kValidAddressBits = 48;
 constexpr uintptr_t kAddressMask = (1ull << kValidAddressBits) - 1;
@@ -92,17 +91,39 @@
 static_assert((kTopBit & kGenerationMask) > 0,
               "kTopBit bit must be inside the generation region");
 
-// This functionality is outside of CheckedPtr2Impl, so that it can be
-// overridden by tests. The implementation is in the .cc file, because including
-// partition_alloc.h here could lead to cyclic includes.
-struct CheckedPtr2ImplPartitionAllocSupport {
-  // Checks if CheckedPtr2 support is enabled in PartitionAlloc for |ptr|.
+// This functionality is outside of CheckedPtr2OrMTEImpl, so that it can be
+// overridden by tests.
+struct CheckedPtr2OrMTEImplPartitionAllocSupport {
+  // Checks if the necessary support is enabled in PartitionAlloc for |ptr|.
+  //
+  // The implementation is in the .cc file, because including partition_alloc.h
+  // here could lead to cyclic includes.
   // TODO(bartekn): Check if this function gets inlined.
   BASE_EXPORT static bool EnabledForPtr(void* ptr);
+
+  // Returns pointer to the tag that protects are pointed by |ptr|.
+  static ALWAYS_INLINE void* TagPointer(void* ptr) {
+    return PartitionTagPointer(ptr);
+  }
+
+#if CHECKED_PTR2_AVOID_BRANCH_WHEN_CHECKING_ENABLED
+  // Returns offset of the tag from the beginning of the slot. Works only with
+  // CheckedPtr2 algorithm.
+  static constexpr size_t TagOffset() {
+#if ENABLE_TAG_FOR_CHECKED_PTR2
+    return kPartitionTagOffset;
+#else
+    // Unreachable, but can't use NOTREACHED() due to constexpr. Return
+    // something weird so that the caller is very likely to crash.
+    return 0x87654321FEDCBA98;
+#endif
+  }
+#endif
 };
 
-template <typename PartitionAllocSupport = CheckedPtr2ImplPartitionAllocSupport>
-struct CheckedPtr2Impl {
+template <typename PartitionAllocSupport =
+              CheckedPtr2OrMTEImplPartitionAllocSupport>
+struct CheckedPtr2OrMTEImpl {
   // This implementation assumes that pointers are 64 bits long and at least 16
   // top bits are unused. The latter is harder to verify statically, but this is
   // true for all currently supported 64-bit architectures (DCHECK when wrapping
@@ -126,9 +147,11 @@
     }
 
     // Read the generation and place it in the top bits of the address.
-    static_assert(sizeof(PartitionTag) * 8 == kGenerationBits, "");
-    uintptr_t generation =
-        *(static_cast<volatile PartitionTag*>(PartitionTagPointer(ptr)));
+    // Even if PartitionAlloc's tag has less than kGenerationBits, we'll read
+    // what's given and pad the rest with 0s.
+    static_assert(sizeof(PartitionTag) * 8 <= kGenerationBits, "");
+    uintptr_t generation = *(static_cast<volatile PartitionTag*>(
+        PartitionAllocSupport::TagPointer(ptr)));
 
     generation <<= kValidAddressBits;
     addr |= generation;
@@ -151,6 +174,11 @@
   static ALWAYS_INLINE void* SafelyUnwrapPtrForDereference(
       uintptr_t wrapped_ptr) {
 #if CHECKED_PTR2_AVOID_BRANCH_WHEN_CHECKING_ENABLED
+    // This variant cannot be used with MTECheckedPtr algorithm, because it
+    // relies on the generation to exist at a constant offset before the
+    // allocation.
+    static_assert(!ENABLE_TAG_FOR_MTE_CHECKED_PTR, "");
+
     // Top bit tells if the protection is enabled. Use it to decide whether to
     // read the word before the allocation, which exists only if the protection
     // is enabled. Otherwise it may crash, in which case read the data from the
@@ -189,7 +217,7 @@
     //         matter what we read, as long as this read doesn't crash)
     volatile PartitionTag* generation_ptr =
         static_cast<volatile PartitionTag*>(ExtractPtr(wrapped_ptr)) -
-        offset * (kPartitionTagOffset / sizeof(PartitionTag));
+        offset * (PartitionAllocSupport::TagOffset() / sizeof(PartitionTag));
     uintptr_t generation = *generation_ptr;
     // Shift generation into the right place and add back the enabled bit.
     //
@@ -227,13 +255,13 @@
 #else  // CHECKED_PTR2_AVOID_BRANCH_WHEN_CHECKING_ENABLED
     uintptr_t ptr_generation = wrapped_ptr >> kValidAddressBits;
     if (ptr_generation > 0) {
-      // Read generation from before the allocation.
+      // Read the generation provided by PartitionAlloc.
       //
       // Cast to volatile to ensure memory is read. E.g. in a tight loop, the
       // compiler could cache the value in a register and thus could miss that
       // another thread freed memory and cleared generation.
       uintptr_t read_generation = *static_cast<volatile PartitionTag*>(
-          PartitionTagPointer(ExtractPtr(wrapped_ptr)));
+          PartitionAllocSupport::TagPointer(ExtractPtr(wrapped_ptr)));
 #if CHECKED_PTR2_AVOID_BRANCH_WHEN_DEREFERENCING
       // Use hardware to detect generation mismatch. CPU will crash if top bits
       // aren't all 0 (technically it won't if all bits are 1, but that's a
@@ -301,8 +329,7 @@
   static constexpr uintptr_t kWrappedNullPtr = 0;
 };
 
-#endif  // defined(ARCH_CPU_64_BITS) && !defined(OS_NACL) &&
-        // ENABLE_TAG_FOR_CHECKED_PTR2
+#endif  // defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
 
 template <typename T>
 struct DereferencedPointerType {
@@ -331,8 +358,8 @@
 //    adding support for cases encountered so far).
 template <typename T,
 #if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL) && \
-    ENABLE_TAG_FOR_CHECKED_PTR2
-          typename Impl = internal::CheckedPtr2Impl<>>
+    (ENABLE_TAG_FOR_CHECKED_PTR2 || ENABLE_TAG_FOR_MTE_CHECKED_PTR)
+          typename Impl = internal::CheckedPtr2OrMTEImpl<>>
 #else
           typename Impl = internal::CheckedPtrNoOpImpl>
 #endif
diff --git a/base/memory/checked_ptr_unittest.cc b/base/memory/checked_ptr_unittest.cc
index 1dd994d..03e9d96 100644
--- a/base/memory/checked_ptr_unittest.cc
+++ b/base/memory/checked_ptr_unittest.cc
@@ -11,7 +11,6 @@
 #include <utility>
 
 #include "base/allocator/partition_allocator/partition_alloc.h"
-#include "base/allocator/partition_allocator/partition_cookie.h"
 #include "base/allocator/partition_allocator/partition_tag.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -620,125 +619,120 @@
 
 }  // namespace
 
-#if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL) && \
-    ENABLE_TAG_FOR_CHECKED_PTR2
+#if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
 
 namespace base {
 namespace internal {
 
-struct CheckedPtr2ImplPartitionAllocSupportEnabled
-    : CheckedPtr2ImplPartitionAllocSupport {
+static constexpr size_t kTagOffsetForTest = 2;
+
+struct CheckedPtr2OrMTEImplPartitionAllocSupportForTest {
   static bool EnabledForPtr(void* ptr) { return true; }
+
+  static ALWAYS_INLINE void* TagPointer(void* ptr) {
+    return static_cast<char*>(ptr) - kTagOffsetForTest;
+  }
+
+#if CHECKED_PTR2_AVOID_BRANCH_WHEN_CHECKING_ENABLED
+  static constexpr size_t TagOffset() { return kTagOffsetForTest; }
+#endif
 };
 
-using CheckedPtr2ImplEnabled =
-    CheckedPtr2Impl<CheckedPtr2ImplPartitionAllocSupportEnabled>;
+using CheckedPtr2OrMTEImplForTest =
+    CheckedPtr2OrMTEImpl<CheckedPtr2OrMTEImplPartitionAllocSupportForTest>;
 
-TEST(CheckedPtr2Impl, WrapNull) {
-  ASSERT_EQ(CheckedPtr2Impl<>::GetWrappedNullPtr(), 0u);
-  ASSERT_EQ(CheckedPtr2Impl<>::WrapRawPtr(nullptr), 0u);
+TEST(CheckedPtr2OrMTEImpl, WrapNull) {
+  ASSERT_EQ(CheckedPtr2OrMTEImpl<>::GetWrappedNullPtr(), 0u);
+  ASSERT_EQ(CheckedPtr2OrMTEImpl<>::WrapRawPtr(nullptr), 0u);
 }
 
-TEST(CheckedPtr2Impl, SafelyUnwrapNull) {
-  ASSERT_EQ(CheckedPtr2ImplEnabled::SafelyUnwrapPtrForExtraction(0), nullptr);
+TEST(CheckedPtr2OrMTEImpl, SafelyUnwrapNull) {
+  ASSERT_EQ(CheckedPtr2OrMTEImplForTest::SafelyUnwrapPtrForExtraction(0),
+            nullptr);
 }
 
 TEST(CheckedPtr2Impl, WrapAndSafelyUnwrap) {
-  // Create a fake allocation, with first 32B for generation and optionally
-  // cookie for Debug builds (ignored), 16B each. Put generation both 16B and
-  // 32B before the "object", so that it works on both Debug and Release builds.
-  // We can use a fake allocation, instead of PartitionAlloc, because
-  // CheckedPtr2ImplEnabled fakes the functionality is enabled for this pointer.
-  char bytes[] = {0xBA, 0x42, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
-                  0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xBA, 0x42,
-                  0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
-                  0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x89};
-  void* ptr = bytes + 32;
+  // Create a fake allocation, with first 2B for generation.
+  // It is ok to use a fake allocation, instead of PartitionAlloc, because
+  // CheckedPtr2OrMTEImplForTest fakes the functionality is enabled for this
+  // pointer and points to the tag appropriately.
+  char bytes[] = {0xBA, 0x42, 0x78, 0x89};
+  void* ptr = bytes + kTagOffsetForTest;
   ASSERT_EQ(0x78, *static_cast<char*>(ptr));
   uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
 
   uintptr_t set_top_bit = 0x0000000000000000;
-  uintptr_t mask = 0xFFFFFFFFFFFFFFFF;
 #if CHECKED_PTR2_AVOID_BRANCH_WHEN_CHECKING_ENABLED
   set_top_bit = 0x8000000000000000;
 #endif
+  uintptr_t mask = 0xFFFFFFFFFFFFFFFF;
+  if (sizeof(PartitionTag) < 2)
+    mask = 0x00FFFFFFFFFFFFFF;
 
-  uintptr_t wrapped = CheckedPtr2ImplEnabled::WrapRawPtr(ptr);
-  // First 2 bytes in the preceding 16B block will be used as generation (in
-  // reverse order due to little-endianness).
+  uintptr_t wrapped = CheckedPtr2OrMTEImplForTest::WrapRawPtr(ptr);
+  // The bytes before the allocation will be used as generation (in reverse
+  // order due to little-endianness).
 #if CHECKED_PTR2_USE_NO_OP_WRAPPER
   ASSERT_EQ(wrapped, addr);
   std::ignore = set_top_bit;
   std::ignore = mask;
 #else
-  ASSERT_EQ(wrapped, (addr | 0x42BA000000000000 | set_top_bit) & mask);
+  ASSERT_EQ(wrapped, (addr | 0x42BA000000000000) & mask | set_top_bit);
 #endif
-  ASSERT_EQ(CheckedPtr2ImplEnabled::SafelyUnwrapPtrForDereference(wrapped),
+  ASSERT_EQ(CheckedPtr2OrMTEImplForTest::SafelyUnwrapPtrForDereference(wrapped),
             ptr);
 
-  // Modify the generation associated with the fake allocation.
-  bytes[1] |= 0x80;                // for Debug builds
-  bytes[kCookieSize + 1] |= 0x80;  // for Release builds
-  wrapped = CheckedPtr2ImplEnabled::WrapRawPtr(ptr);
+  // Modify the generation in the fake allocation.
+  bytes[0] |= 0x40;
+  wrapped = CheckedPtr2OrMTEImplForTest::WrapRawPtr(ptr);
 #if CHECKED_PTR2_USE_NO_OP_WRAPPER
   ASSERT_EQ(wrapped, addr);
 #else
-  ASSERT_EQ(wrapped, (addr | 0xC2BA000000000000 | set_top_bit) & mask);
+  ASSERT_EQ(wrapped, (addr | 0x42FA000000000000) & mask | set_top_bit);
 #endif
-  ASSERT_EQ(CheckedPtr2ImplEnabled::SafelyUnwrapPtrForDereference(wrapped),
+  ASSERT_EQ(CheckedPtr2OrMTEImplForTest::SafelyUnwrapPtrForDereference(wrapped),
             ptr);
 
 #if CHECKED_PTR2_AVOID_BRANCH_WHEN_DEREFERENCING
   // Clear the generation associated with the fake allocation.
-  bytes[0] = 0;  // for Debug builds
+  bytes[0] = 0;
   bytes[1] = 0;
-  bytes[kCookieSize] = 0;  // for Release builds
-  bytes[kCookieSize + 1] = 0;
-  mask = 0xFFFFFFFFFFFFFFFF;
 #if CHECKED_PTR2_AVOID_BRANCH_WHEN_CHECKING_ENABLED
-  mask = 0x7FFFFFFFFFFFFFFF;
+  mask &= 0x7FFFFFFFFFFFFFFF;
 #endif
 
   // Mask out the top bit, because in some cases (not all), it may differ.
   ASSERT_EQ(
       reinterpret_cast<uintptr_t>(
-          CheckedPtr2ImplEnabled::SafelyUnwrapPtrForDereference(wrapped)) &
+          CheckedPtr2OrMTEImplForTest::SafelyUnwrapPtrForDereference(wrapped)) &
           mask,
       wrapped & mask);
 #endif  // CHECKED_PTR2_AVOID_BRANCH_WHEN_DEREFERENCING
 }
 
-TEST(CheckedPtr2Impl, SafelyUnwrapDisabled) {
-  // Create a fake allocation, with first 32B for generation and optionally
-  // cookie for Debug builds (ignored), 16B each. Put generation both 16B and
-  // 32B before the "object", so that it works on both Debug and Release builds.
-  // We can use a fake allocation, instead of PartitionAlloc, because
-  // CheckedPtr2ImplEnabled fakes the functionality is enabled for this pointer.
-  char bytes[] = {0xBA, 0x42, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
-                  0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xBA, 0x42,
-                  0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
-                  0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x89};
-  void* ptr = bytes + 32;
+TEST(CheckedPtr2OrMTEImpl, SafelyUnwrapDisabled) {
+  // Create a fake allocation, with first 2B for generation.
+  // It is ok to use a fake allocation, instead of PartitionAlloc, because
+  // CheckedPtr2OrMTEImplForTest fakes the functionality is enabled for this
+  // pointer and points to the tag appropriately.
+  char bytes[] = {0xBA, 0x42, 0x78, 0x89};
+  void* ptr = bytes + kTagOffsetForTest;
   ASSERT_EQ(0x78, *static_cast<char*>(ptr));
   uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
-  ASSERT_EQ(CheckedPtr2ImplEnabled::SafelyUnwrapPtrForDereference(addr), ptr);
+  ASSERT_EQ(CheckedPtr2OrMTEImplForTest::SafelyUnwrapPtrForDereference(addr),
+            ptr);
 }
 
 TEST(CheckedPtr2Impl, CrashOnGenerationMismatch) {
-  // Create a fake allocation, with first 32B for generation and optionally
-  // cookie for Debug builds (ignored), 16B each. Put generation both 16B and
-  // 32B before the "object", so that it works on both Debug and Release builds.
-  // We can use a fake allocation, instead of PartitionAlloc, because
-  // CheckedPtr2ImplEnabled fakes the functionality is enabled for this pointer.
-  char bytes[] = {0xBA, 0x42, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
-                  0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xBA, 0x42,
-                  0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
-                  0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x89};
-  CheckedPtr<char, CheckedPtr2ImplEnabled> ptr = bytes + 32;
+  // Create a fake allocation, with first 2B for generation.
+  // It is ok to use a fake allocation, instead of PartitionAlloc, because
+  // CheckedPtr2OrMTEImplForTest fakes the functionality is enabled for this
+  // pointer and points to the tag appropriately.
+  char bytes[] = {0xBA, 0x42, 0x78, 0x89};
+  CheckedPtr<char, CheckedPtr2OrMTEImplForTest> ptr = bytes + kTagOffsetForTest;
   EXPECT_TRUE(*ptr == 0x78);
   // Clobber the generation associated with the fake allocation.
-  bytes[0] = 0;            // for Debug builds
-  bytes[kCookieSize] = 0;  // for Release builds
+  bytes[0] = 0;
   EXPECT_DEATH_IF_SUPPORTED(if (*ptr == 0x78) return, "");
 }
 
@@ -749,5 +743,4 @@
 }  // namespace internal
 }  // namespace base
 
-#endif  // defined(ARCH_CPU_64_BITS) && !defined(OS_NACL) &&
-        // ENABLE_TAG_FOR_CHECKED_PTR2
+#endif  // defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
diff --git a/base/values.cc b/base/values.cc
index 27d4a34..04ea709 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -1571,7 +1571,7 @@
   result = subdict->RemovePath(path.substr(delimiter_position + 1),
                                out_value);
   if (result && subdict->empty())
-    RemoveWithoutPathExpansion(subdict_path, nullptr);
+    RemoveKey(subdict_path);
 
   return result;
 }
diff --git a/base/win/scoped_handle_verifier.cc b/base/win/scoped_handle_verifier.cc
index 4b6899e..c972292 100644
--- a/base/win/scoped_handle_verifier.cc
+++ b/base/win/scoped_handle_verifier.cc
@@ -10,6 +10,7 @@
 
 #include <unordered_map>
 
+#include "base/compiler_specific.h"
 #include "base/debug/alias.h"
 #include "base/debug/stack_trace.h"
 #include "base/synchronization/lock_impl.h"
@@ -25,17 +26,19 @@
 }
 }  // extern C
 
+namespace base {
+namespace win {
+namespace internal {
+
 namespace {
 
-base::win::internal::ScopedHandleVerifier* g_active_verifier = nullptr;
+ScopedHandleVerifier* g_active_verifier = nullptr;
 using GetHandleVerifierFn = void* (*)();
 using HandleMap =
-    std::unordered_map<HANDLE,
-                       base::win::internal::ScopedHandleVerifierInfo,
-                       base::win::internal::HandleHash>;
+    std::unordered_map<HANDLE, ScopedHandleVerifierInfo, HandleHash>;
 using NativeLock = base::internal::LockImpl;
 
-NativeLock* GetLock() {
+NativeLock* GetScopedHandleVerifierLock() {
   static auto* native_lock = new NativeLock();
   return native_lock;
 }
@@ -53,11 +56,26 @@
   DISALLOW_COPY_AND_ASSIGN(AutoNativeLock);
 };
 
-}  // namespace
+NOINLINE void ReportErrorOnScopedHandleOperation(
+    const base::debug::StackTrace& creation_stack) {
+  auto creation_stack_copy = creation_stack;
+  base::debug::Alias(&creation_stack_copy);
+  CHECK(false);
+  __builtin_unreachable();
+}
 
-namespace base {
-namespace win {
-namespace internal {
+NOINLINE void ReportErrorOnScopedHandleOperation(
+    const base::debug::StackTrace& creation_stack,
+    const ScopedHandleVerifierInfo& other) {
+  auto other_copy = other;
+  base::debug::Alias(&other_copy);
+  auto creation_stack_copy = creation_stack;
+  base::debug::Alias(&creation_stack_copy);
+  CHECK(false);
+  __builtin_unreachable();
+}
+
+}  // namespace
 
 ScopedHandleVerifier::ScopedHandleVerifier(bool enabled)
     : enabled_(enabled), lock_(GetLock()) {}
@@ -76,12 +94,12 @@
   return true;
 }
 
-// Assigns the g_active_verifier global within the GetLock() lock.
+// Assigns the g_active_verifier global within the ScopedHandleVerifier lock.
 // If |existing_verifier| is non-null then |enabled| is ignored.
 void ThreadSafeAssignOrCreateScopedHandleVerifier(
     ScopedHandleVerifier* existing_verifier,
     bool enabled) {
-  AutoNativeLock lock(*GetLock());
+  AutoNativeLock lock(*GetScopedHandleVerifierLock());
   // Another thread in this module might be trying to assign the global
   // verifier, so check that within the lock here.
   if (g_active_verifier)
@@ -142,61 +160,23 @@
 
 // static
 NativeLock* ScopedHandleVerifier::GetLock() {
-  return ::GetLock();
+  return GetScopedHandleVerifierLock();
 }
 
 void ScopedHandleVerifier::StartTracking(HANDLE handle,
                                          const void* owner,
                                          const void* pc1,
                                          const void* pc2) {
-  if (!enabled_)
-    return;
-  TRACE_EVENT0("base", "ScopedHandleVerifier::StartTracking");
-
-  // Grab the thread id before the lock.
-  DWORD thread_id = GetCurrentThreadId();
-
-  // Grab the thread stacktrace before the lock.
-  ScopedHandleVerifierInfo handle_info = {owner, pc1, pc2,
-                                          base::debug::StackTrace(), thread_id};
-  std::pair<HANDLE, ScopedHandleVerifierInfo> item(handle, handle_info);
-
-  AutoNativeLock lock(*lock_);
-  std::pair<HandleMap::iterator, bool> result = map_.insert(item);
-  if (!result.second) {
-    ScopedHandleVerifierInfo other = result.first->second;
-    base::debug::Alias(&other);
-    auto creation_stack = creation_stack_;
-    base::debug::Alias(&creation_stack);
-    CHECK(false);  // Attempt to start tracking already tracked handle.
-  }
+  if (enabled_)
+    StartTrackingImpl(handle, owner, pc1, pc2);
 }
 
 void ScopedHandleVerifier::StopTracking(HANDLE handle,
                                         const void* owner,
                                         const void* pc1,
                                         const void* pc2) {
-  if (!enabled_)
-    return;
-  TRACE_EVENT0("base", "ScopedHandleVerifier::StopTracking");
-
-  AutoNativeLock lock(*lock_);
-  HandleMap::iterator i = map_.find(handle);
-  if (i == map_.end()) {
-    auto creation_stack = creation_stack_;
-    base::debug::Alias(&creation_stack);
-    CHECK(false);  // Attempting to close an untracked handle.
-  }
-
-  ScopedHandleVerifierInfo other = i->second;
-  if (other.owner != owner) {
-    base::debug::Alias(&other);
-    auto creation_stack = creation_stack_;
-    base::debug::Alias(&creation_stack);
-    CHECK(false);  // Attempting to close a handle not owned by opener.
-  }
-
-  map_.erase(i);
+  if (enabled_)
+    StopTrackingImpl(handle, owner, pc1, pc2);
 }
 
 void ScopedHandleVerifier::Disable() {
@@ -204,30 +184,70 @@
 }
 
 void ScopedHandleVerifier::OnHandleBeingClosed(HANDLE handle) {
-  if (!enabled_)
-    return;
-
-  if (closing_.Get())
-    return;
-
-  TRACE_EVENT0("base", "ScopedHandleVerifier::OnHandleBeingClosed");
-
-  AutoNativeLock lock(*lock_);
-  HandleMap::iterator i = map_.find(handle);
-  if (i == map_.end())
-    return;
-
-  ScopedHandleVerifierInfo other = i->second;
-  base::debug::Alias(&other);
-  auto creation_stack = creation_stack_;
-  base::debug::Alias(&creation_stack);
-  CHECK(false);  // CloseHandle called on tracked handle.
+  if (enabled_)
+    OnHandleBeingClosedImpl(handle);
 }
 
 HMODULE ScopedHandleVerifier::GetModule() const {
   return CURRENT_MODULE();
 }
 
+NOINLINE void ScopedHandleVerifier::StartTrackingImpl(HANDLE handle,
+                                                      const void* owner,
+                                                      const void* pc1,
+                                                      const void* pc2) {
+  TRACE_EVENT0("base", "ScopedHandleVerifier::StartTrackingImpl");
+
+  // Grab the thread id before the lock.
+  DWORD thread_id = GetCurrentThreadId();
+
+  // Grab the thread stacktrace before the lock.
+  auto item = std::make_pair(
+      handle, ScopedHandleVerifierInfo{owner, pc1, pc2,
+                                       base::debug::StackTrace(), thread_id});
+
+  AutoNativeLock lock(*lock_);
+  std::pair<HandleMap::iterator, bool> result = map_.insert(item);
+  if (!result.second) {
+    // Attempt to start tracking already tracked handle.
+    ReportErrorOnScopedHandleOperation(creation_stack_, result.first->second);
+  }
+}
+
+NOINLINE void ScopedHandleVerifier::StopTrackingImpl(HANDLE handle,
+                                                     const void* owner,
+                                                     const void* pc1,
+                                                     const void* pc2) {
+  TRACE_EVENT0("base", "ScopedHandleVerifier::StopTrackingImpl");
+
+  AutoNativeLock lock(*lock_);
+  HandleMap::iterator i = map_.find(handle);
+  if (i == map_.end()) {
+    // Attempting to close an untracked handle.
+    ReportErrorOnScopedHandleOperation(creation_stack_);
+  }
+
+  if (i->second.owner != owner) {
+    // Attempting to close a handle not owned by opener.
+    ReportErrorOnScopedHandleOperation(creation_stack_, i->second);
+  }
+
+  map_.erase(i);
+}
+
+NOINLINE void ScopedHandleVerifier::OnHandleBeingClosedImpl(HANDLE handle) {
+  TRACE_EVENT0("base", "ScopedHandleVerifier::OnHandleBeingClosedImpl");
+  if (closing_.Get())
+    return;
+
+  AutoNativeLock lock(*lock_);
+  HandleMap::iterator i = map_.find(handle);
+  if (i != map_.end()) {
+    // CloseHandle called on tracked handle.
+    ReportErrorOnScopedHandleOperation(creation_stack_, i->second);
+  }
+}
+
 HMODULE GetHandleVerifierModuleForTesting() {
   return g_active_verifier->GetModule();
 }
diff --git a/base/win/scoped_handle_verifier.h b/base/win/scoped_handle_verifier.h
index 1900daf..74bec7bb 100644
--- a/base/win/scoped_handle_verifier.h
+++ b/base/win/scoped_handle_verifier.h
@@ -66,6 +66,12 @@
  private:
   ~ScopedHandleVerifier();  // Not implemented.
 
+  void StartTrackingImpl(HANDLE handle, const void* owner, const void* pc1,
+                         const void* pc2);
+  void StopTrackingImpl(HANDLE handle, const void* owner, const void* pc1,
+                        const void* pc2);
+  void OnHandleBeingClosedImpl(HANDLE handle);
+
   static base::internal::LockImpl* GetLock();
   static void InstallVerifier();
 
diff --git a/build/android/gyp/compile_java.py b/build/android/gyp/compile_java.py
index 5c695d2..8159980 100755
--- a/build/android/gyp/compile_java.py
+++ b/build/android/gyp/compile_java.py
@@ -5,6 +5,7 @@
 # found in the LICENSE file.
 
 import distutils.spawn
+import functools
 import logging
 import multiprocessing
 import optparse
@@ -235,28 +236,14 @@
   return '\n'.join(map(ApplyColors, filter(ApplyFilters, output.split('\n'))))
 
 
-def _ExtractClassFiles(jar_path, dest_dir, java_files):
-  """Extracts all .class files not corresponding to |java_files|."""
-  # Two challenges exist here:
-  # 1. |java_files| have prefixes that are not represented in the the jar paths.
-  # 2. A single .java file results in multiple .class files when it contains
-  #    nested classes.
-  # Here's an example:
-  #   source path: ../../base/android/java/src/org/chromium/Foo.java
-  #   jar paths: org/chromium/Foo.class, org/chromium/Foo$Inner.class
-  # To extract only .class files not related to the given .java files, we strip
-  # off ".class" and "$*.class" and use a substring match against java_files.
-  def extract_predicate(path):
-    if not path.endswith('.class'):
-      return False
-    path_without_suffix = re.sub(r'(?:\$|\.)[^/]*class$', '', path)
-    partial_java_path = path_without_suffix + '.java'
-    return not any(p.endswith(partial_java_path) for p in java_files)
+def CheckErrorproneStderrWarning(jar_path, expected_warning_regex,
+                                 javac_output):
+  if not re.search(expected_warning_regex, javac_output):
+    raise Exception('Expected `{}` warning when compiling `{}`'.format(
+        expected_warning_regex, os.path.basename(jar_path)))
 
-  logging.info('Extracting class files from %s', jar_path)
-  build_utils.ExtractAll(jar_path, path=dest_dir, predicate=extract_predicate)
-  for path in build_utils.FindInDirectory(dest_dir, '*.class'):
-    shutil.copystat(jar_path, path)
+  # Do not print warning
+  return ''
 
 
 def _ParsePackageAndClassNames(java_file):
@@ -378,16 +365,19 @@
     logging.info('Completed info file: %s', output_path)
 
 
-def _CreateJarFile(jar_path, provider_configurations, additional_jar_files,
-                   classes_dir):
+def _CreateJarFile(jar_path, service_provider_configuration_dir,
+                   additional_jar_files, classes_dir):
   logging.info('Start creating jar file: %s', jar_path)
   with build_utils.AtomicOutput(jar_path) as f:
     with zipfile.ZipFile(f.name, 'w') as z:
       build_utils.ZipDir(z, classes_dir)
-      if provider_configurations:
-        for config in provider_configurations:
-          zip_path = 'META-INF/services/' + os.path.basename(config)
-          build_utils.AddToZipHermetic(z, zip_path, src_path=config)
+      if service_provider_configuration_dir:
+        config_files = build_utils.FindInDirectory(
+            service_provider_configuration_dir)
+        for config_file in config_files:
+          zip_path = os.path.relpath(config_file,
+                                     service_provider_configuration_dir)
+          build_utils.AddToZipHermetic(z, zip_path, src_path=config_file)
 
       if additional_jar_files:
         for src_path, zip_path in additional_jar_files:
@@ -442,6 +432,8 @@
   try:
     classes_dir = os.path.join(temp_dir, 'classes')
     transitive_classes = os.path.join(temp_dir, 'transitive_classes')
+    service_provider_configuration = os.path.join(
+        temp_dir, 'service_provider_configuration')
 
     if save_outputs:
       input_srcjars_dir = os.path.join(options.generated_dir, 'input_srcjars')
@@ -486,6 +478,14 @@
                                  pattern='META-INF*.class')
       # Specifying the root directory is required, see:
       # https://docs.oracle.com/javase/8/docs/technotes/tools/findingclasses.html#userclass
+
+      # Extract META-INF/services/* so that it can be copied into the output
+      # .jar
+      build_utils.ExtractAll(options.header_jar,
+                             no_clobber=True,
+                             path=service_provider_configuration,
+                             pattern='META-INF/services/*')
+
       classpath.append(
           os.path.join(transitive_classes, 'META-INF', 'TRANSITIVE'))
       logging.info('Done extracting transitive classes')
@@ -514,13 +514,22 @@
         f.write(' '.join(java_files))
       cmd += ['@' + java_files_rsp_path]
 
+
+      # |errorprone_expected_warning_regex| is used in tests for errorprone
+      # warnings. Fail compile if expected warning is not present.
+      stderr_filter = ProcessJavacOutput
+      if (options.enable_errorprone
+          and options.errorprone_expected_warning_regex):
+        stderr_filter = functools.partial(
+            CheckErrorproneStderrWarning, options.jar_path,
+            options.errorprone_expected_warning_regex)
+
       logging.debug('Build command %s', cmd)
       start = time.time()
-      build_utils.CheckOutput(
-          cmd,
-          print_stdout=options.chromium_code,
-          stdout_filter=ProcessJavacOutput,
-          stderr_filter=ProcessJavacOutput)
+      build_utils.CheckOutput(cmd,
+                              print_stdout=options.chromium_code,
+                              stdout_filter=ProcessJavacOutput,
+                              stderr_filter=stderr_filter)
       end = time.time() - start
       logging.info('Java compilation took %ss', end)
 
@@ -531,7 +540,7 @@
         if annotation_processor_java_files:
           info_file_context.SubmitFiles(annotation_processor_java_files)
 
-      _CreateJarFile(jar_path, options.provider_configurations,
+      _CreateJarFile(jar_path, service_provider_configuration,
                      options.additional_jar_files, classes_dir)
 
       info_file_context.Commit(jar_path + '.info')
@@ -581,12 +590,6 @@
       action='append',
       help='key=value arguments for the annotation processors.')
   parser.add_option(
-      '--provider-configuration',
-      dest='provider_configurations',
-      action='append',
-      help='File to specify a service provider. Will be included '
-      'in the jar under META-INF/services.')
-  parser.add_option(
       '--additional-jar-file',
       dest='additional_jar_files',
       action='append',
@@ -610,6 +613,10 @@
       action='store_true',
       help='Enable errorprone checks')
   parser.add_option(
+      '--errorprone-expected-warning-regex',
+      help='When set, throws an exception if the errorprone compile does not '
+      'log a warning which matches the regex.')
+  parser.add_option(
       '--warnings-as-errors',
       action='store_true',
       help='Treat all warnings as errors.')
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index cd8d59b..3d7ce3d 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -2938,9 +2938,6 @@
   #  use_turbine: If True, compile headers using turbine.py.
   #  apk_name: Optional APK name. If provided, will tell compile_java.py to also
   #    generate an .apk.jar.info file under size-info/${apk_name}.apk.jar.info
-  #  provider_configurations: Optional list of paths to Java service
-  #    provider configuration files [1]. These will be copied under
-  #    META-INF/services/ in the final .jar file.
   #  processor_args_javac: List of annotation processor arguments, each one
   #    will be passed to javac as -A<entry>.
   #  deps: Dependencies for the corresponding target.
@@ -2954,11 +2951,6 @@
     _build_config = invoker.build_config
     _chromium_code = invoker.chromium_code
 
-    _provider_configurations = []
-    if (defined(invoker.provider_configurations)) {
-      _provider_configurations = invoker.provider_configurations
-    }
-
     _processor_args = []
     if (defined(invoker.processor_args_javac)) {
       _processor_args = invoker.processor_args_javac
@@ -3110,7 +3102,8 @@
       }
       if (_chromium_code) {
         args += [ "--chromium-code=1" ]
-        if (java_warnings_as_errors) {
+        if (java_warnings_as_errors &&
+            !defined(invoker.errorprone_expected_warning_regex)) {
           args += [ "--warnings-as-errors" ]
         }
       }
@@ -3130,9 +3123,9 @@
           "--processorpath=@FileArg($_rebased_errorprone_buildconfig:deps_info:host_classpath)",
           "--enable-errorprone",
         ]
-      }
-      foreach(e, _provider_configurations) {
-        args += [ "--provider-configuration=" + rebase_path(e, root_build_dir) ]
+        if (defined(invoker.errorprone_expected_warning_regex)) {
+          args += [ "--errorprone-expected-warning-regex=${invoker.errorprone_expected_warning_regex}" ]
+        }
       }
       foreach(e, _processor_args) {
         args += [ "--processor-arg=" + e ]
@@ -3240,7 +3233,9 @@
   #  requires_android: Optional. True if target can only run on Android.
   #  java_files: Optional list of Java source file paths for this target.
   #  javac_args: Optional list of extra arguments to pass to javac.
-  #  errorprone_args: Optional list of extra arguments to pass to .
+  #  errorprone_args: Optional list of extra arguments to pass to.
+  #  errorprone_expected_warning_regex: When set, throws an exception if the
+  #    errorprone compile does not log a warning which matches the regex.
   #  srcjar_deps: Optional list of .srcjar targets (not file paths). The Java
   #    source files they contain will also be compiled for this target.
   #  java_sources_file: Optional path to a file which will be written with
@@ -3736,7 +3731,6 @@
         "additional_jar_files",
         "apk_name",
         "processor_args_javac",
-        "provider_configurations",
         "javac_args",
         "jar_excluded_patterns",
       ]
@@ -3773,6 +3767,10 @@
             }
             javac_args += invoker.errorprone_args
           }
+          if (defined(invoker.errorprone_expected_warning_regex)) {
+            errorprone_expected_warning_regex =
+                invoker.errorprone_expected_warning_regex
+          }
           deps = [ ":$_header_target_name" ]
           header_jar_path = _final_ijar_path
           generated_jar_path = _generated_jar_path
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index a60eee6..12a82f8 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1478,6 +1478,8 @@
   #
   #   javac_args: Additional arguments to pass to javac.
   #   errorprone_args: Additional arguments to pass to errorprone.
+  #   errorprone_expected_warning_regex: When set, throws an exception if the
+  #     errorprone compile does not log a warning which matches the regex.
   #
   #   data_deps, testonly
   #
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 1663aba..e7bda5f 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200714.1.1
+0.20200715.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index f5db53b..e7bda5f 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20200714.2.1
+0.20200715.1.1
diff --git a/build/toolchain/toolchain.gni b/build/toolchain/toolchain.gni
index 80c2e7b5..c7e7656 100644
--- a/build/toolchain/toolchain.gni
+++ b/build/toolchain/toolchain.gni
@@ -39,7 +39,12 @@
 
 declare_args() {
   # Clang compiler version. Clang files are placed at version-dependent paths.
-  clang_version = "11.0.0"
+  if (llvm_force_head_revision) {
+    clang_version = "12.0.0"
+  } else {
+    # TODO(crbug.com/1105518): Remove in the next Clang roll.
+    clang_version = "11.0.0"
+  }
 }
 
 # Check target_os here instead of is_ios as this file is loaded for secondary
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index 1ed476f..61a4515 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -182,3 +182,8 @@
 !false isn't funny because it's true.
 
 Lalala
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Vestibulum rhoncus neque sodales nibh lobortis, non fringilla odio aliquet.
+Praesent ultrices quam eu pretium ultrices.
+Quisque et consequat ex. Curabitur sed nunc neque.
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index f3a20d7..ba82a5a5 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -971,6 +971,7 @@
     "//chrome/browser/fullscreen/android:java",
     "//chrome/browser/offline_pages/android:java",
     "//chrome/browser/paint_preview/android:java",
+    "//chrome/browser/password_check/android:public_java",
     "//chrome/browser/password_manager/android_test_helpers:test_support_java",
     "//chrome/browser/performance_hints/android:java",
     "//chrome/browser/preferences:java",
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index cb37e5d..840d1d2 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -701,6 +701,7 @@
   "java/res/drawable/ic_error.xml",
   "java/res/drawable/ic_error_googred_36dp.xml",
   "java/res/drawable/ic_event_round.xml",
+  "java/res/drawable/ic_expand_more_in_circle_24dp.xml",
   "java/res/drawable/ic_file_download_24dp.xml",
   "java/res/drawable/ic_file_download_36dp.xml",
   "java/res/drawable/ic_file_download_scheduled_24dp.xml",
diff --git a/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected b/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
index a4c555a8..943e38a 100644
--- a/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
@@ -7,6 +7,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools">
   <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+  <uses-feature android:name="android.software.leanback" android:required="false"/>
+  <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
+  <uses-feature android:glEsVersion="0x00020000"/>
   <application
       android:extractNativeLibs="false"
       android:icon="@drawable/icon_webview"
diff --git a/chrome/android/features/start_surface/internal/BUILD.gn b/chrome/android/features/start_surface/internal/BUILD.gn
index 0dca333..3cd34ad 100644
--- a/chrome/android/features/start_surface/internal/BUILD.gn
+++ b/chrome/android/features/start_surface/internal/BUILD.gn
@@ -95,7 +95,6 @@
 
     deps += [
       "//chrome/browser/profiles/android:java",
-      "//components/signin/public/android:java",
       "//content/public/android:content_java",
       "//third_party/android_sdk/androidx_browser:androidx_browser_java",
       "//ui/android:ui_utils_java",
diff --git a/chrome/android/features/start_surface/internal/java/res/layout/feed_loading_layout.xml b/chrome/android/features/start_surface/internal/java/res/layout/feed_loading_layout.xml
index baab0dde..90bf0ab 100644
--- a/chrome/android/features/start_surface/internal/java/res/layout/feed_loading_layout.xml
+++ b/chrome/android/features/start_surface/internal/java/res/layout/feed_loading_layout.xml
@@ -33,12 +33,6 @@
     </LinearLayout>
 
     <LinearLayout
-        android:id="@+id/sign_in_box"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"/>
-
-    <LinearLayout
         android:id="@+id/placeholders_layout"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedLoadingCoordinator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedLoadingCoordinator.java
index ff66ead..40c1ec74 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedLoadingCoordinator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedLoadingCoordinator.java
@@ -13,12 +13,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.chrome.browser.ntp.cards.SignInPromo;
-import org.chromium.chrome.browser.signin.ProfileDataCache;
-import org.chromium.chrome.browser.signin.SigninPromoController;
-import org.chromium.chrome.browser.signin.SigninPromoUtil;
 import org.chromium.chrome.start_surface.R;
-import org.chromium.components.signin.metrics.SigninAccessPoint;
 
 /** The coordinator to control the loading feed surface. */
 public class FeedLoadingCoordinator {
@@ -41,16 +36,6 @@
         mFeedLoadingView = (FeedLoadingLayout) LayoutInflater.from(mContext).inflate(
                 R.layout.feed_loading_layout, null, false);
         mParentView.addView(mFeedLoadingView);
-
-        if (SignInPromo.shouldCreatePromo()) {
-            SigninPromoController signinPromoController =
-                    new SigninPromoController(SigninAccessPoint.NTP_CONTENT_SUGGESTIONS);
-            int imageSize =
-                    mContext.getResources().getDimensionPixelSize(R.dimen.user_picture_size);
-            ProfileDataCache profileDataCache = new ProfileDataCache(mContext, imageSize);
-            SigninPromoUtil.setupPromoViewFromCache(signinPromoController, profileDataCache,
-                    mFeedLoadingView.getSigninPromoView(), null);
-        }
     }
 
     void onOverviewShownAtLaunch(long activityCreationTimeMs) {
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedLoadingLayout.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedLoadingLayout.java
index 32ff822..2651c78 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedLoadingLayout.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/FeedLoadingLayout.java
@@ -12,14 +12,10 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.TypedValue;
-import android.view.LayoutInflater;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
-import androidx.annotation.Nullable;
-
-import org.chromium.chrome.browser.signin.PersonalizedSigninPromoView;
 import org.chromium.chrome.start_surface.R;
 import org.chromium.components.browser_ui.widget.displaystyle.HorizontalDisplayStyle;
 import org.chromium.components.browser_ui.widget.displaystyle.UiConfig;
@@ -42,7 +38,6 @@
     private static final int TEXT_PLACEHOLDER_RADIUS_DP = 11;
 
     private Context mContext;
-    private @Nullable PersonalizedSigninPromoView mSigninPromoView;
     private Resources mResources;
     private long mLayoutInflationCompleteMs;
 
@@ -66,22 +61,6 @@
         setPlaceholders();
     }
 
-    /** @return The {@link PersonalizedSigninPromoView} for this class. */
-    PersonalizedSigninPromoView getSigninPromoView() {
-        if (mSigninPromoView == null) {
-            mSigninPromoView = (PersonalizedSigninPromoView) LayoutInflater.from(mContext).inflate(
-                    R.layout.personalized_signin_promo_view_modern_content_suggestions, null,
-                    false);
-            LinearLayout signView = findViewById(R.id.sign_in_box);
-            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-            signView.setLayoutParams(lp);
-            lp.setMargins(0, 0, 0, dpToPx(12));
-            signView.addView(mSigninPromoView);
-        }
-        return mSigninPromoView;
-    }
-
     private void setPlaceholders() {
         setPadding();
         boolean isLandscape = getResources().getConfiguration().orientation
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
index 85775d2e..6eb11e7 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
@@ -63,7 +63,6 @@
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.homepage.HomepageManager;
-import org.chromium.chrome.browser.ntp.cards.SignInPromo;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.TabState;
@@ -657,7 +656,6 @@
         createThumbnailBitmapAndWriteToFile(0);
         TabAttributeCache.setTitleForTesting(0, "Google");
 
-        SignInPromo.setDisablePromoForTests(true);
         startMainActivityFromLauncher();
         CriteriaHelper.pollUiThread(
                 () -> mActivityTestRule.getActivity().getLayoutManager().overviewVisible());
diff --git a/chrome/android/java/AndroidManifest_trichrome_library.xml b/chrome/android/java/AndroidManifest_trichrome_library.xml
index b85427f..37ff48e 100644
--- a/chrome/android/java/AndroidManifest_trichrome_library.xml
+++ b/chrome/android/java/AndroidManifest_trichrome_library.xml
@@ -12,6 +12,10 @@
     package="{{ manifest_package }}"
     tools:ignore="MissingVersion,MissingLeanbackLauncher">
 
+    <uses-feature android:glEsVersion="0x00020000" />
+    <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
+    <uses-feature android:name="android.software.leanback" android:required="false" />
+
     <!-- TODO(torne): we should specify an icon, roundIcon, and label from resources. -->
     <application
         android:label="{{ application_label|default('Trichrome Library') }}"
diff --git a/chrome/android/java/res/drawable/ic_expand_more_in_circle_24dp.xml b/chrome/android/java/res/drawable/ic_expand_more_in_circle_24dp.xml
new file mode 100644
index 0000000..08c0a50
--- /dev/null
+++ b/chrome/android/java/res/drawable/ic_expand_more_in_circle_24dp.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:strokeWidth="1"
+      android:pathData="M23.5,11.9999C23.5,18.3512 18.3513,23.4999 12,23.4999C5.6487,23.4999 0.5,18.3512 0.5,11.9999C0.5,5.6486 5.6487,0.4999 12,0.4999C18.3513,0.4999 23.5,5.6486 23.5,11.9999Z"
+      android:strokeColor="@color/default_chip_outline_color_light"/>
+  <path
+      android:pathData="M12.5892,14.7487C12.4383,14.9039 12.23,14.9999 12,14.9999C11.77,14.9999 11.5617,14.9039 11.4108,14.7487L7.2442,10.463C7.0933,10.3079 7,10.0936 7,9.857C7,9.3839 7.3733,8.9999 7.8333,8.9999C8.0633,8.9999 8.2717,9.0959 8.4225,9.251L12,12.9307L15.5775,9.251C15.7283,9.0959 15.9367,8.9999 16.1667,8.9999C16.6267,8.9999 17,9.3839 17,9.857C17,10.0936 16.9067,10.3079 16.7558,10.463L12.5892,14.7487Z"
+      android:fillColor="@color/default_chip_outline_color_dark"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/chrome/android/java/res/layout/account_picker_row.xml b/chrome/android/java/res/layout/account_picker_row.xml
index e3e49eb..efa1d3a 100644
--- a/chrome/android/java/res/layout/account_picker_row.xml
+++ b/chrome/android/java/res/layout/account_picker_row.xml
@@ -3,7 +3,6 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -43,6 +42,6 @@
         android:layout_height="24dp"
         android:layout_marginStart="16dp"
         tools:ignore="ContentDescription"
-        android:src="@drawable/ic_check_googblue_24dp"
-        app:tint="@color/default_icon_color_blue" />
+        tools:src="@drawable/ic_check_googblue_24dp"
+        tools:tint="@color/default_icon_color_blue" />
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/account_picker_row_legacy.xml b/chrome/android/java/res/layout/account_picker_row_legacy.xml
index 434187ba..4eca7c82 100644
--- a/chrome/android/java/res/layout/account_picker_row_legacy.xml
+++ b/chrome/android/java/res/layout/account_picker_row_legacy.xml
@@ -3,7 +3,6 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -45,6 +44,6 @@
         android:layout_height="24dp"
         android:layout_marginStart="16dp"
         tools:ignore="ContentDescription"
-        android:src="@drawable/ic_check_googblue_24dp"
-        app:tint="@color/default_icon_color_blue" />
+        tools:src="@drawable/ic_check_googblue_24dp"
+        tools:tint="@color/default_icon_color_blue" />
 </LinearLayout>
diff --git a/chrome/android/java/res/values-night/colors.xml b/chrome/android/java/res/values-night/colors.xml
index 3f97cb7..a1c3504 100644
--- a/chrome/android/java/res/values-night/colors.xml
+++ b/chrome/android/java/res/values-night/colors.xml
@@ -10,7 +10,7 @@
     <color name="bottom_system_nav_divider_color">@android:color/black</color>
 
     <!-- Account Signin Colors -->
-    <color name="signin_header_animation_background">@color/signin_header_animation_bg_dark</color>
+    <color name="signin_header_animation_background">@color/header_background_dark</color>
     <color name="signin_header_animation_line_light">@color/modern_grey_700</color>
     <color name="signin_header_animation_line_dark">@color/modern_grey_700</color>
     <color name="signin_header_animation_laptop_screen">@color/modern_grey_900</color>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
index ef33731..2b1d838 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
@@ -61,6 +61,9 @@
 public abstract class AppHooks {
     private static AppHooksImpl sInstance;
 
+    @Nullable
+    private ExternalAuthUtils mExternalAuthUtils;
+
     /**
      * Sets a mocked instance for testing.
      */
@@ -139,6 +142,19 @@
     }
 
     /**
+     * @return The singleton instance of ExternalAuthUtils.
+     *
+     * TODO(https://crbug.com/1104817): Make createExternalAuthUtils protected.
+     */
+    public ExternalAuthUtils getExternalAuthUtils() {
+        if (mExternalAuthUtils == null) {
+            mExternalAuthUtils = createExternalAuthUtils();
+        }
+
+        return mExternalAuthUtils;
+    }
+
+    /**
      * @return An instance of {@link FeedbackReporter} to report feedback.
      */
     public FeedbackReporter createFeedbackReporter() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
index 9b41535..a6270f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
@@ -158,8 +158,6 @@
                             // because the entire TextView will be clickable.
                             new NoUnderlineClickableSpan(mContext.getResources(), (view) -> {})));
             viewParams.previewLoadOriginalMessage = loadOriginalSpan;
-
-            viewParams.previewStaleTimestamp = bridge.getStalePreviewTimestamp(mWebContents);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
index c6c8d34..c4b6dd6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettings.java
@@ -31,6 +31,7 @@
 import org.chromium.chrome.browser.help.HelpAndFeedback;
 import org.chromium.chrome.browser.password_check.PasswordCheck;
 import org.chromium.chrome.browser.password_check.PasswordCheckFactory;
+import org.chromium.chrome.browser.password_check.PasswordCheckPreference;
 import org.chromium.chrome.browser.password_manager.PasswordManagerLauncher;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -102,7 +103,7 @@
     private Preference mSecurityKey;
     private ChromeSwitchPreference mSavePasswordsSwitch;
     private ChromeBaseCheckBoxPreference mAutoSignInSwitch;
-    private ChromeBasePreference mCheckPasswords;
+    private PasswordCheckPreference mCheckPasswords;
     private TextMessagePreference mEmptyView;
     private boolean mSearchRecorded;
     private Menu mMenu;
@@ -474,13 +475,17 @@
     }
 
     private void createCheckPasswords() {
-        mCheckPasswords = new ChromeBasePreference(getStyledContext(), null);
+        final int numCheckLaunched =
+                getPrefService().getInteger(Pref.SETTINGS_LAUNCHED_PASSWORD_CHECKS);
+        mCheckPasswords = new PasswordCheckPreference(getStyledContext(), numCheckLaunched < 3);
         mCheckPasswords.setKey(PREF_CHECK_PASSWORDS);
         mCheckPasswords.setTitle(R.string.passwords_check_title);
         mCheckPasswords.setOrder(ORDER_CHECK_PASSWORDS);
         mCheckPasswords.setSummary(R.string.passwords_check_description);
         // Add a listener which launches a settings page for the leak password check
         mCheckPasswords.setOnPreferenceClickListener(preference -> {
+            getPrefService().setInteger(
+                    Pref.SETTINGS_LAUNCHED_PASSWORD_CHECKS, numCheckLaunched + 1);
             PasswordCheck passwordCheck = PasswordCheckFactory.create();
             passwordCheck.showUi(getStyledContext());
             // Return true to notify the click was handled
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/previews/PreviewsAndroidBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/previews/PreviewsAndroidBridge.java
index bd60390f..0397bf8b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/previews/PreviewsAndroidBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/previews/PreviewsAndroidBridge.java
@@ -49,17 +49,6 @@
     }
 
     /**
-     * If the current preview is a stale preview, this returns the timestamp text to display to the
-     * user. An empty string is returned if the current preview is not a stale preview.
-     */
-    public String getStalePreviewTimestamp(WebContents webContents) {
-        assert shouldShowPreviewUI(webContents)
-            : "getStalePreviewTimestamp called on a non-preview page";
-        return PreviewsAndroidBridgeJni.get().getStalePreviewTimestamp(
-                mNativePreviewsAndroidBridge, PreviewsAndroidBridge.this, webContents);
-    }
-
-    /**
      * Requests that the original page be loaded.
      */
     public void loadOriginal(WebContents webContents) {
@@ -94,8 +83,6 @@
         long init(PreviewsAndroidBridge caller);
         boolean shouldShowPreviewUI(long nativePreviewsAndroidBridge, PreviewsAndroidBridge caller,
                 WebContents webContents);
-        String getStalePreviewTimestamp(long nativePreviewsAndroidBridge,
-                PreviewsAndroidBridge caller, WebContents webContents);
         void loadOriginal(long nativePreviewsAndroidBridge, PreviewsAndroidBridge caller,
                 WebContents webContents);
         String getPreviewsType(long nativePreviewsAndroidBridge, PreviewsAndroidBridge caller,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
index 656deb3..4a07e433 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
@@ -97,8 +97,7 @@
             ExistingAccountRowViewBinder.bindAccountView(accountProfileData, mSelectedAccountView);
 
             ImageView rowEndImage = mSelectedAccountView.findViewById(R.id.account_selection_mark);
-            rowEndImage.setImageResource(R.drawable.ic_expand_more_black_24dp);
-            rowEndImage.setColorFilter(R.color.default_icon_color);
+            rowEndImage.setImageResource(R.drawable.ic_expand_more_in_circle_24dp);
 
             String continueAsButtonText = mContext.getString(R.string.signin_promo_continue_as,
                     accountProfileData.getGivenNameOrFullNameOrEmail());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/ExistingAccountRowViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/ExistingAccountRowViewBinder.java
index 9a826fb..e18c741 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/ExistingAccountRowViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/ExistingAccountRowViewBinder.java
@@ -12,6 +12,8 @@
 import android.widget.TextView;
 
 import androidx.annotation.LayoutRes;
+import androidx.core.content.ContextCompat;
+import androidx.core.widget.ImageViewCompat;
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -45,9 +47,15 @@
             bindAccountView(profileData, view);
         } else if (propertyKey == ExistingAccountRowProperties.IS_SELECTED_ACCOUNT) {
             ImageView selectionMark = view.findViewById(R.id.account_selection_mark);
-            selectionMark.setVisibility(model.get(ExistingAccountRowProperties.IS_SELECTED_ACCOUNT)
-                            ? View.VISIBLE
-                            : View.GONE);
+            if (model.get(ExistingAccountRowProperties.IS_SELECTED_ACCOUNT)) {
+                selectionMark.setImageResource(R.drawable.ic_check_googblue_24dp);
+                ImageViewCompat.setImageTintList(selectionMark,
+                        ContextCompat.getColorStateList(
+                                view.getContext(), R.color.default_icon_color_blue));
+                selectionMark.setVisibility(View.VISIBLE);
+            } else {
+                selectionMark.setVisibility(View.GONE);
+            }
         } else {
             throw new IllegalArgumentException(
                     "Cannot update the view for propertyKey: " + propertyKey);
diff --git a/chrome/android/javatests/DEPS b/chrome/android/javatests/DEPS
index 5bd89b63..2d2aa09 100644
--- a/chrome/android/javatests/DEPS
+++ b/chrome/android/javatests/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+chrome/app",
   "+chrome/browser/android/lifecycle",
+  "+chrome/browser/password_check/android",
   "+chrome/browser/profiles/android/java",
   "+chrome/browser/share/android/java",
   "+chrome/browser/tab/java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
index 59f6beb..5a248993 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
@@ -95,6 +95,7 @@
 import org.chromium.chrome.browser.history.HistoryActivity;
 import org.chromium.chrome.browser.history.HistoryManager;
 import org.chromium.chrome.browser.history.StubbedHistoryProvider;
+import org.chromium.chrome.browser.password_check.PasswordCheckPreference;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.settings.SettingsActivity;
@@ -736,6 +737,77 @@
     }
 
     /**
+     * Check that Pref.SETTINGS_LAUNCHED_PASSWORD_CHECKS is being correctly incremented when
+     * the Check passwords preference is clicked.
+     */
+    @Test
+    @SmallTest
+    @Feature({"Preferences"})
+    @EnableFeatures(ChromeFeatureList.PASSWORD_CHECK)
+    public void testCheckPasswordsPrefIncremented() {
+        mBrowserTestRule.addAndSignInTestAccount();
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { getPrefService().setInteger(Pref.SETTINGS_LAUNCHED_PASSWORD_CHECKS, 0); });
+
+        final SettingsActivity settingsActivity = mSettingsActivityTestRule.startSettingsActivity();
+        PasswordSettings passwordPrefs = mSettingsActivityTestRule.getFragment();
+        PasswordCheckPreference passwordCheck =
+                passwordPrefs.findPreference(PasswordSettings.PREF_CHECK_PASSWORDS);
+        Assert.assertNotNull(passwordCheck);
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            passwordCheck.performClick();
+            Assert.assertEquals(
+                    getPrefService().getInteger(Pref.SETTINGS_LAUNCHED_PASSWORD_CHECKS), 1);
+        });
+    }
+
+    /**
+     * Check that the image above the Check passwords preference is shown if the value of
+     * Pref.SETTINGS_LAUNCHED_PASSWORD_CHECKS is less than 3.
+     */
+    @Test
+    @SmallTest
+    @Feature({"Preferences"})
+    @EnableFeatures(ChromeFeatureList.PASSWORD_CHECK)
+    public void testCheckPasswordsImageShown() {
+        mBrowserTestRule.addAndSignInTestAccount();
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { getPrefService().setInteger(Pref.SETTINGS_LAUNCHED_PASSWORD_CHECKS, 2); });
+
+        final SettingsActivity settingsActivity = mSettingsActivityTestRule.startSettingsActivity();
+        PasswordSettings passwordPrefs = mSettingsActivityTestRule.getFragment();
+        PasswordCheckPreference passwordCheck =
+                passwordPrefs.findPreference(PasswordSettings.PREF_CHECK_PASSWORDS);
+        Assert.assertNotNull(passwordCheck);
+        int promoImageVisibility =
+                passwordCheck.getPromoImageView(passwordPrefs.getActivity()).getVisibility();
+        Assert.assertEquals(promoImageVisibility, View.VISIBLE);
+    }
+
+    /**
+     * Check that the image above the Check passwords preference is not shown if the value of
+     * Pref.SETTINGS_LAUNCHED_PASSWORD_CHECKS is greater than or equal to 3.
+     */
+    @Test
+    @SmallTest
+    @Feature({"Preferences"})
+    @EnableFeatures(ChromeFeatureList.PASSWORD_CHECK)
+    public void testCheckPasswordsImageNotShown() {
+        mBrowserTestRule.addAndSignInTestAccount();
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { getPrefService().setInteger(Pref.SETTINGS_LAUNCHED_PASSWORD_CHECKS, 3); });
+
+        final SettingsActivity settingsActivity = mSettingsActivityTestRule.startSettingsActivity();
+        PasswordSettings passwordPrefs = mSettingsActivityTestRule.getFragment();
+        PasswordCheckPreference passwordCheck =
+                passwordPrefs.findPreference(PasswordSettings.PREF_CHECK_PASSWORDS);
+        Assert.assertNotNull(passwordCheck);
+        int promoImageVisibility =
+                passwordCheck.getPromoImageView(passwordPrefs.getActivity()).getVisibility();
+        Assert.assertEquals(promoImageVisibility, View.GONE);
+    }
+
+    /**
      * Check that the check passwords preference is not shown when the corresponding feature is
      * enabled but the user is not signed in.
      */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
index 17b2411d..9515316 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
@@ -116,6 +116,7 @@
         onView(withText(R.string.signin_account_picker_dialog_title)).check(matches(isDisplayed()));
         onView(withText(ACCOUNT_NAME1)).check(matches(isDisplayed()));
         onView(withText(FULL_NAME1)).check(matches(isDisplayed()));
+        onView(withId(R.id.account_selection_mark)).check(matches(isDisplayed()));
         String continueAsText = mActivityTestRule.getActivity().getString(
                 R.string.signin_promo_continue_as, GIVEN_NAME1);
         onView(withText(continueAsText)).check(matches(isDisplayed()));
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 85f1e74..a73b7c8 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5339,6 +5339,9 @@
     The next time you restart your device, your administrator will perform a one-time update that will delete your local data.
   </message>
 
+  <message name="IDS_RELEASE_NOTES_DEVICE_SPECIFIC_NOTIFICATION_TITLE" desc="Text for the notification title informing the user that the device has been updated and patch notes are available. Will specify the user's Chrome OS device.">
+    See what's new on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>
+  </message>
   <message name="IDS_RELEASE_NOTES_NOTIFICATION_TITLE" desc="Text for the notification title informing the user that the device has been updated and patch notes are available.">
     See what's new on Chromebook
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_RELEASE_NOTES_DEVICE_SPECIFIC_NOTIFICATION_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_RELEASE_NOTES_DEVICE_SPECIFIC_NOTIFICATION_TITLE.png.sha1
new file mode 100644
index 0000000..ca13fd8
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_RELEASE_NOTES_DEVICE_SPECIFIC_NOTIFICATION_TITLE.png.sha1
@@ -0,0 +1 @@
+76cb4679fbbc7d77ab048559d8cf7147920b9fab
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e4281f69a..a2098e014 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1000,8 +1000,6 @@
     "page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer.h",
     "page_load_metrics/observers/no_state_prefetch_page_load_metrics_observer.cc",
     "page_load_metrics/observers/no_state_prefetch_page_load_metrics_observer.h",
-    "page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.cc",
-    "page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.h",
     "page_load_metrics/observers/omnibox_suggestion_used_page_load_metrics_observer.cc",
     "page_load_metrics/observers/omnibox_suggestion_used_page_load_metrics_observer.h",
     "page_load_metrics/observers/optimization_guide_page_load_metrics_observer.cc",
@@ -1310,8 +1308,6 @@
     "previews/previews_https_notification_infobar_decider.h",
     "previews/previews_lite_page_infobar_delegate.cc",
     "previews/previews_lite_page_infobar_delegate.h",
-    "previews/previews_offline_helper.cc",
-    "previews/previews_offline_helper.h",
     "previews/previews_service.cc",
     "previews/previews_service.h",
     "previews/previews_service_factory.cc",
@@ -1802,6 +1798,7 @@
     "//components/autofill/core/browser",
     "//components/nacl/common:buildflags",
     "//components/payments/core",
+    "//components/policy/proto",
     "//components/safe_browsing:buildflags",
     "//components/services/storage/public/mojom",
     "//components/sync",
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 559e5177..bc06e23 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -798,8 +798,9 @@
     _localPrefRegistrar.Init(localState);
     _localPrefRegistrar.Add(
         prefs::kAllowFileSelectionDialogs,
-        base::Bind(&chrome::BrowserCommandController::UpdateOpenFileState,
-                   _menuState.get()));
+        base::BindRepeating(
+            &chrome::BrowserCommandController::UpdateOpenFileState,
+            _menuState.get()));
   }
 
   _handoff_active_url_observer_bridge.reset(
@@ -1630,10 +1631,9 @@
   _profilePrefRegistrar->Init(_lastProfile->GetPrefs());
   _profilePrefRegistrar->Add(
       prefs::kIncognitoModeAvailability,
-      base::Bind(&chrome::BrowserCommandController::
-                     UpdateSharedCommandsForIncognitoAvailability,
-                 _menuState.get(),
-                 _lastProfile));
+      base::BindRepeating(&chrome::BrowserCommandController::
+                              UpdateSharedCommandsForIncognitoAvailability,
+                          _menuState.get(), _lastProfile));
 }
 
 - (void)updateMenuItemKeyEquivalents {
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index 360e3ee..d665b190 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -95,9 +95,11 @@
   [controller getUrl:AppleEventToOpenUrl(url) withReply:nullptr];
 }
 
-void RunClosureWhenProfileInitialized(const base::Closure& closure,
+void RunClosureWhenProfileInitialized(const base::RepeatingClosure& closure,
                                       Profile* profile,
                                       Profile::CreateStatus status) {
+  // This will be called multiple times. Wait until the profile is initialized
+  // fully to quit the loop.
   if (status == Profile::CREATE_STATUS_INITIALIZED)
     closure.Run();
 }
@@ -275,7 +277,7 @@
 }
 
 // Called when the ProfileManager has created a profile.
-void CreateProfileCallback(const base::Closure& quit_closure,
+void CreateProfileCallback(const base::RepeatingClosure& quit_closure,
                            Profile* profile,
                            Profile::CreateStatus status) {
   EXPECT_TRUE(profile);
@@ -288,9 +290,9 @@
 }
 
 void CreateAndWaitForSystemProfile() {
-  ProfileManager::CreateCallback create_callback =
-      base::Bind(&CreateProfileCallback,
-                 base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
+  ProfileManager::CreateCallback create_callback = base::BindRepeating(
+      &CreateProfileCallback,
+      base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
   g_browser_process->profile_manager()->CreateProfileAsync(
       ProfileManager::GetSystemProfilePath(),
       create_callback,
@@ -614,10 +616,9 @@
   base::RunLoop run_loop;
   profile_manager->CreateProfileAsync(
       profile2_path,
-      base::Bind(&RunClosureWhenProfileInitialized,
-                 run_loop.QuitClosure()),
-      base::string16(),
-      std::string());
+      base::BindRepeating(&RunClosureWhenProfileInitialized,
+                          run_loop.QuitClosure()),
+      base::string16(), std::string());
   run_loop.Run();
   Profile* profile2 = profile_manager->GetProfileByPath(profile2_path);
   ASSERT_TRUE(profile2);
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index 17a81f4..6bb4a2a 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -93,16 +93,11 @@
 
 std::string FormStructuresToString(
     const std::map<FormRendererId, std::unique_ptr<FormStructure>>& forms) {
-  std::map<uint32_t, const FormStructure*> sorted_forms;
-  for (const auto& form_kv : forms) {
-    const auto* form = form_kv.second.get();
-    uint32_t renderer_id = form->unique_renderer_id().value();
-    EXPECT_TRUE(sorted_forms.emplace(renderer_id, form).second);
-  }
-
   std::string forms_string;
-  for (const auto& kv : sorted_forms) {
-    const auto* form = kv.second;
+  // The forms are sorted by renderer ID, which should make the order
+  // deterministic.
+  for (const auto& kv : forms) {
+    const auto* form = kv.second.get();
     for (const auto& field : *form) {
       forms_string += field->Type().ToString();
       forms_string += " | " + base::UTF16ToUTF8(field->name);
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 77faedcc..6456829 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -318,14 +318,14 @@
   // Initialize the notification for the default browser setting policy.
   pref_change_registrar_.Add(
       prefs::kDefaultBrowserSettingEnabled,
-      base::Bind(&BrowserProcessImpl::ApplyDefaultBrowserPolicy,
-                 base::Unretained(this)));
+      base::BindRepeating(&BrowserProcessImpl::ApplyDefaultBrowserPolicy,
+                          base::Unretained(this)));
 
 #if !defined(OS_ANDROID)
   // This preference must be kept in sync with external values; update them
   // whenever the preference or its controlling policy changes.
   pref_change_registrar_.Add(metrics::prefs::kMetricsReportingEnabled,
-                             base::Bind(&ApplyMetricsReportingPolicy));
+                             base::BindRepeating(&ApplyMetricsReportingPolicy));
 #endif
 
   DCHECK(!webrtc_event_log_manager_);
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc
index 12bcab2c..04fdf58 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.cc
+++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -172,7 +172,7 @@
   primary_profile_shutdown_subscription_ =
       PrimaryProfileServicesShutdownNotifierFactory::GetInstance()
           ->Get(primary_profile)
-          ->Subscribe(base::Bind(
+          ->Subscribe(base::BindRepeating(
               &BrowserProcessPlatformPart::ShutdownPrimaryProfileServices,
               base::Unretained(this)));
   browser_policy_connector_chromeos()
@@ -226,10 +226,10 @@
         GetTimezoneResolverManager(),
         g_browser_process->shared_url_loader_factory(),
         chromeos::SimpleGeolocationProvider::DefaultGeolocationProviderURL(),
-        base::Bind(&chromeos::system::ApplyTimeZone),
-        base::Bind(&chromeos::DelayNetworkCall,
-                   base::TimeDelta::FromMilliseconds(
-                       chromeos::kDefaultNetworkRetryDelayMS)),
+        base::BindRepeating(&chromeos::system::ApplyTimeZone),
+        base::BindRepeating(&chromeos::DelayNetworkCall,
+                            base::TimeDelta::FromMilliseconds(
+                                chromeos::kDefaultNetworkRetryDelayMS)),
         g_browser_process->local_state()));
   }
   return timezone_resolver_.get();
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index f07cfe66..5641c6e 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -943,9 +943,9 @@
 #endif
 
 mojo::PendingRemote<prerender::mojom::PrerenderCanceler> GetPrerenderCanceler(
-    const base::Callback<content::WebContents*()>& wc_getter) {
+    base::OnceCallback<content::WebContents*()> wc_getter) {
   mojo::PendingRemote<prerender::mojom::PrerenderCanceler> canceler;
-  prerender::PrerenderContents::FromWebContents(wc_getter.Run())
+  prerender::PrerenderContents::FromWebContents(std::move(wc_getter).Run())
       ->AddPrerenderCancelerReceiver(canceler.InitWithNewPipeAndPassReceiver());
   return canceler;
 }
@@ -5211,10 +5211,8 @@
     content::PreviewsState initial_state,
     content::NavigationHandle* navigation_handle,
     const GURL& current_navigation_url) {
-  content::PreviewsState state = DetermineAllowedPreviewsWithoutHoldback(
+  return DetermineAllowedPreviewsWithoutHoldback(
       initial_state, navigation_handle, current_navigation_url);
-
-  return previews::MaybeCoinFlipHoldbackBeforeCommit(state, navigation_handle);
 }
 
 content::PreviewsState
@@ -5303,29 +5301,6 @@
     return content::ALL_SUPPORTED_PREVIEWS;
   }
 
-  bool is_reload =
-      navigation_handle->GetReloadType() != content::ReloadType::NONE;
-
-  content::PreviewsState server_previews_enabled_state =
-      content::SERVER_LITE_PAGE_ON;
-
-  // For now, treat server previews types as a single decision, and do not
-  // re-evaluate upon redirect. Plumbing does not exist to modify the CPAT
-  // header, nor does the plumbing exist to modify the PreviewsState within the
-  // URLLoader.
-  if (previews_triggering_logic_already_ran) {
-    // Copy the server state that was used before the redirect for the initial
-    // URL.
-    previews_state |=
-        (previews_data->AllowedPreviewsState() & server_previews_enabled_state);
-  } else {
-    if (previews_decider_impl->ShouldAllowPreviewAtNavigationStart(
-            previews_data, navigation_handle, is_reload,
-            previews::PreviewsType::LITE_PAGE)) {
-      previews_state |= server_previews_enabled_state;
-    }
-  }
-
   // Evaluate client-side previews.
   previews_state |= previews::DetermineAllowedClientPreviewsState(
       previews_data, previews_triggering_logic_already_ran,
@@ -5378,13 +5353,9 @@
   if (!previews::HasEnabledPreviews(initial_state))
     return content::PREVIEWS_OFF;
 
-  // Check if the server sent a preview directive.
-  content::PreviewsState previews_state =
-      previews::DetermineCommittedServerPreviewsState(drp_data, initial_state);
-
   // Check the various other client previews types.
   return previews::DetermineCommittedClientPreviewsState(
-      previews_user_data, url, previews_state, previews_decider,
+      previews_user_data, url, initial_state, previews_decider,
       navigation_handle);
 }
 
@@ -5437,23 +5408,6 @@
   if (!previews_service || !previews_service->previews_ui_service())
     return content::PREVIEWS_OFF;
 
-// Check if offline previews are being used and set it in the user data.
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-  offline_pages::OfflinePageTabHelper* tab_helper =
-      offline_pages::OfflinePageTabHelper::FromWebContents(
-          navigation_handle->GetWebContents());
-
-  bool is_offline_page = tab_helper && tab_helper->IsLoadingOfflinePage();
-  bool is_offline_preview = tab_helper && tab_helper->GetOfflinePreviewItem();
-
-  // If this is an offline page, but not a preview, then we should not attempt
-  // any previews or surface the previews UI.
-  if (is_offline_page && !is_offline_preview)
-    return content::PREVIEWS_OFF;
-
-  previews_user_data->set_offline_preview_used(is_offline_preview);
-#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
-
   // Annotate request if no-transform directive found in response headers.
   if (response_headers &&
       response_headers->HasHeaderValue("cache-control", "no-transform")) {
diff --git a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
index be44c1ca..23a47ed 100644
--- a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
+++ b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
@@ -115,8 +115,8 @@
   // message after a time delay, in order to rate limit. The association
   // protects against the render process host ID being recycled in that time
   // gap between the preparation and the execution of that IPC.
-  associated_registry->AddInterface(
-      base::Bind(&CacheStatsRecorder::Create, render_process_host->GetID()));
+  associated_registry->AddInterface(base::BindRepeating(
+      &CacheStatsRecorder::Create, render_process_host->GetID()));
 
   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner =
       content::GetUIThreadTaskRunner({});
diff --git a/chrome/browser/chrome_plugin_browsertest.cc b/chrome/browser/chrome_plugin_browsertest.cc
index f4035bc3..0c57c2a4 100644
--- a/chrome/browser/chrome_plugin_browsertest.cc
+++ b/chrome/browser/chrome_plugin_browsertest.cc
@@ -44,45 +44,6 @@
 #include "ui/aura/window_tree_host.h"
 #endif
 
-namespace {
-
-class CallbackBarrier : public base::RefCountedThreadSafe<CallbackBarrier> {
- public:
-  explicit CallbackBarrier(const base::Closure& target_callback)
-      : target_callback_(target_callback),
-        outstanding_callbacks_(0),
-        did_enable_(true) {
-  }
-
-  base::Callback<void(bool)> CreateCallback() {
-    outstanding_callbacks_++;
-    return base::Bind(&CallbackBarrier::MayRunTargetCallback, this);
-  }
-
- private:
-  friend class base::RefCountedThreadSafe<CallbackBarrier>;
-
-  ~CallbackBarrier() {
-    EXPECT_TRUE(target_callback_.is_null());
-  }
-
-  void MayRunTargetCallback(bool did_enable) {
-    EXPECT_GT(outstanding_callbacks_, 0);
-    did_enable_ = did_enable_ && did_enable;
-    if (--outstanding_callbacks_ == 0) {
-      EXPECT_TRUE(did_enable_);
-      target_callback_.Run();
-      target_callback_.Reset();
-    }
-  }
-
-  base::Closure target_callback_;
-  int outstanding_callbacks_;
-  bool did_enable_;
-};
-
-}  // namespace
-
 class ChromePluginTest : public InProcessBrowserTest {
  protected:
   ChromePluginTest() {}
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
index 0768f995..34d5d18 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -115,10 +115,10 @@
 
 template <typename T>
 static void ExpectResultAndRun(T expected,
-                               const base::Closure& continuation,
+                               base::OnceClosure continuation,
                                T actual) {
   EXPECT_EQ(expected, actual);
-  continuation.Run();
+  std::move(continuation).Run();
 }
 
 // http://crbug.com/368570
@@ -450,9 +450,11 @@
         ->GetMainFrame()
         ->ExecuteJavaScriptForTests(
             base::ASCIIToUTF16(js),
-            base::BindOnce([](const base::Closure& quit_callback,
-                              base::Value result) { quit_callback.Run(); },
-                           run_loop.QuitClosure()));
+            base::BindOnce(
+                [](base::OnceClosure quit_callback, base::Value result) {
+                  std::move(quit_callback).Run();
+                },
+                run_loop.QuitClosure()));
     run_loop.Run();
   }
 
@@ -466,10 +468,10 @@
         "else reportOnFetch = true;");
   }
 
-  static void ManifestCallbackAndRun(const base::Closure& continuation,
+  static void ManifestCallbackAndRun(base::OnceClosure continuation,
                                      const GURL&,
                                      const blink::Manifest&) {
-    continuation.Run();
+    std::move(continuation).Run();
   }
 
   DISALLOW_COPY_AND_ASSIGN(ChromeServiceWorkerLinkFetchTest);
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index c22990fb..dc165d5 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1977,6 +1977,8 @@
     "policy/display_rotation_default_handler.h",
     "policy/display_settings_handler.cc",
     "policy/display_settings_handler.h",
+    "policy/dlp/enterprise_clipboard_dlp_controller.cc",
+    "policy/dlp/enterprise_clipboard_dlp_controller.h",
     "policy/dm_token_storage.cc",
     "policy/dm_token_storage.h",
     "policy/enrollment_config.cc",
diff --git a/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc b/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc
index 92af85e..0c8bea1 100644
--- a/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc
+++ b/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc
@@ -90,13 +90,12 @@
 }
 
 bool AccessibilityNodeInfoDataWrapper::CanBeAccessibilityFocused() const {
-  // Using HasText() here is incomplete because it doesn't match the
-  // populated ax name. However, this method is used only from AXTreeSourceArc
-  // and not used for actual focusability computation of ChromeVox, and it's
-  // enough to check only hasText().
-  return (IsAccessibilityFocusableContainer() ||
-          HasAccessibilityFocusableText()) &&
-         HasText();
+  if (!IsAccessibilityFocusableContainer() && !HasAccessibilityFocusableText())
+    return false;
+  ui::AXNodeData data;
+  Serialize(&data);
+  // TODO (sarakato): Move name computation to a separate function.
+  return data.HasStringAttribute(ax::mojom::StringAttribute::kName);
 }
 
 bool AccessibilityNodeInfoDataWrapper::IsAccessibilityFocusableContainer()
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
index 18ccaae..c454a58 100644
--- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
+++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
@@ -380,8 +380,8 @@
       // Sometimes Android sets focus on unfocusable node, e.g. ListView.
       AccessibilityInfoDataWrapper* adjusted_node =
           FindFirstFocusableNode(source_node);
-      android_focused_id_ = IsValid(adjusted_node) ? adjusted_node->GetId()
-                                                   : event_data.source_id;
+      if (IsValid(adjusted_node))
+        android_focused_id_ = adjusted_node->GetId();
     }
   } else if (event_data.event_type == AXEventType::VIEW_SELECTED) {
     // In Android, VIEW_SELECTED event is dispatched in the two cases below:
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc
index adba50c..1523696 100644
--- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc
+++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc
@@ -1050,6 +1050,7 @@
   SetProperty(node1, AXBooleanProperty::FOCUSABLE, true);
   SetProperty(node1, AXBooleanProperty::IMPORTANCE, true);
   SetProperty(node1, AXBooleanProperty::VISIBLE_TO_USER, true);
+  SetProperty(node1, AXStringProperty::CONTENT_DESCRIPTION, "node1");
   node1->bounds_in_screen = gfx::Rect(0, 0, 50, 50);
 
   event->node_data.emplace_back(AXNodeInfoData::New());
@@ -1065,7 +1066,7 @@
   AXNodeInfoData* node3 = event->node_data.back().get();
   node3->id = 3;
 
-  // Initially |node1| has a focus.
+  // Initially |node1| has focus.
   CallNotifyAccessibilityEvent(event.get());
   ui::AXTreeData data;
   EXPECT_TRUE(CallGetTreeData(&data));
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.cc
index 09f38d1..77a17d9 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.cc
@@ -7,6 +7,7 @@
 #include "base/bind_helpers.h"
 #include "base/notreached.h"
 #include "base/optional.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/common/pref_names.h"
@@ -53,35 +54,47 @@
 
 //===================== CertProfile ============================================
 
+CertProfile::CertProfile(CertProfileId profile_id,
+                         std::string policy_version,
+                         bool is_va_enabled,
+                         base::TimeDelta renewal_period)
+    : profile_id(profile_id),
+      policy_version(policy_version),
+      is_va_enabled(is_va_enabled),
+      renewal_period(renewal_period) {}
+
 base::Optional<CertProfile> CertProfile::MakeFromValue(
     const base::Value& value) {
-  static_assert(kVersion == 3, "This function should be updated");
+  static_assert(kVersion == 4, "This function should be updated");
 
   const std::string* id = value.FindStringKey(kCertProfileIdKey);
   const std::string* policy_version =
       value.FindStringKey(kCertProfilePolicyVersionKey);
   base::Optional<bool> is_va_enabled =
       value.FindBoolKey(kCertProfileIsVaEnabledKey);
+  base::Optional<int> renewal_period_sec =
+      value.FindIntKey(kCertProfileRenewalPeroidSec);
+
   if (!id || !policy_version) {
     return base::nullopt;
   }
-  if (!is_va_enabled) {
-    is_va_enabled = true;
-  }
 
   CertProfile result;
   result.profile_id = *id;
   result.policy_version = *policy_version;
-  result.is_va_enabled = *is_va_enabled;
+  result.is_va_enabled = is_va_enabled.value_or(true);
+  result.renewal_period =
+      base::TimeDelta::FromSeconds(renewal_period_sec.value_or(0));
 
   return result;
 }
 
 bool CertProfile::operator==(const CertProfile& other) const {
-  static_assert(kVersion == 3, "This function should be updated");
+  static_assert(kVersion == 4, "This function should be updated");
   return ((profile_id == other.profile_id) &&
           (policy_version == other.policy_version) &&
-          (is_va_enabled == other.is_va_enabled));
+          (is_va_enabled == other.is_va_enabled) &&
+          (renewal_period == other.renewal_period));
 }
 
 bool CertProfile::operator!=(const CertProfile& other) const {
@@ -90,10 +103,11 @@
 
 bool CertProfileComparator::operator()(const CertProfile& a,
                                        const CertProfile& b) const {
-  static_assert(CertProfile::kVersion == 3, "This function should be updated");
+  static_assert(CertProfile::kVersion == 4, "This function should be updated");
   return ((a.profile_id < b.profile_id) ||
           (a.policy_version < b.policy_version) ||
-          (a.is_va_enabled < b.is_va_enabled));
+          (a.is_va_enabled < b.is_va_enabled) ||
+          (a.renewal_period < b.renewal_period));
 }
 
 //==============================================================================
@@ -109,6 +123,15 @@
       prefs::kCertificateProvisioningStateForDevice);
 }
 
+const char* GetPrefNameForCertProfiles(CertScope scope) {
+  switch (scope) {
+    case CertScope::kUser:
+      return prefs::kRequiredClientCertificateForUser;
+    case CertScope::kDevice:
+      return prefs::kRequiredClientCertificateForDevice;
+  }
+}
+
 const char* GetPrefNameForSerialization(CertScope scope) {
   switch (scope) {
     case CertScope::kUser:
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h
index 4c5e311..9d2a6ad6 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/callback_forward.h"
 #include "base/optional.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
 #include "chromeos/dbus/constants/attestation_constants.h"
@@ -66,20 +67,32 @@
 // with definitions of RequiredClientCertificateForDevice and
 // RequiredClientCertificateForUser policies in policy_templates.json file.
 const char kCertProfileIdKey[] = "cert_profile_id";
+const char kCertProfileRenewalPeroidSec[] = "renewal_period_seconds";
 const char kCertProfilePolicyVersionKey[] = "policy_version";
 const char kCertProfileIsVaEnabledKey[] = "enable_remote_attestation_check";
 
 struct CertProfile {
+  static base::Optional<CertProfile> MakeFromValue(const base::Value& value);
+
+  CertProfile() = default;
+  // For tests.
+  CertProfile(CertProfileId profile_id,
+              std::string policy_version,
+              bool is_va_enabled,
+              base::TimeDelta renewal_period);
+
   CertProfileId profile_id;
   std::string policy_version;
   bool is_va_enabled = true;
+  // Default renewal period 0 means that a certificate will be renewed only
+  // after the previous one has expired (0 seconds before it is expires).
+  base::TimeDelta renewal_period = base::TimeDelta::FromSeconds(0);
 
   // IMPORTANT:
   // Increment this when you add/change any member in CertProfile (and update
   // all functions that fail to compile because of it).
-  static constexpr int kVersion = 3;
+  static constexpr int kVersion = 4;
 
-  static base::Optional<CertProfile> MakeFromValue(const base::Value& value);
   bool operator==(const CertProfile& other) const;
   bool operator!=(const CertProfile& other) const;
 };
@@ -90,6 +103,7 @@
 
 void RegisterProfilePrefs(PrefRegistrySimple* registry);
 void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
+const char* GetPrefNameForCertProfiles(CertScope scope);
 const char* GetPrefNameForSerialization(CertScope scope);
 
 // Returns the nickname (CKA_LABEL) for keys created for the |profile_id|.
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers.cc
index 30551504..35eba28 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers.cc
@@ -17,49 +17,49 @@
 namespace chromeos {
 namespace cert_provisioning {
 
-// ========= CertProvisioningCertsWithIdsGetter ================================
+// ========= CertIterator ======================================================
 
-CertProvisioningCertsWithIdsGetter::CertProvisioningCertsWithIdsGetter() =
-    default;
-
-CertProvisioningCertsWithIdsGetter::~CertProvisioningCertsWithIdsGetter() =
-    default;
-
-bool CertProvisioningCertsWithIdsGetter::IsRunning() const {
-  return !callback_.is_null();
-}
-
-void CertProvisioningCertsWithIdsGetter::GetCertsWithIds(
+CertIterator::CertIterator(
     CertScope cert_scope,
-    platform_keys::PlatformKeysService* platform_keys_service,
-    GetCertsWithIdsCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(platform_keys_service);
-  DCHECK(callback_.is_null());
+    platform_keys::PlatformKeysService* platform_keys_service)
+    : cert_scope_(cert_scope), platform_keys_service_(platform_keys_service) {}
+CertIterator::~CertIterator() = default;
 
-  cert_scope_ = cert_scope;
-  platform_keys_service_ = platform_keys_service;
-  callback_ = std::move(callback);
+void CertIterator::IterateAll(
+    CertIteratorForEachCallback for_each_callback,
+    CertIteratorOnFinishedCallback on_finished_callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  Cancel();
+  for_each_callback_ = std::move(for_each_callback);
+  on_finished_callback_ = std::move(on_finished_callback);
 
   platform_keys_service_->GetCertificates(
       GetPlatformKeysTokenId(cert_scope_),
-      base::BindRepeating(
-          &CertProvisioningCertsWithIdsGetter::OnGetCertificatesDone,
-          weak_factory_.GetWeakPtr()));
+      base::BindRepeating(&CertIterator::OnGetCertificatesDone,
+                          weak_factory_.GetWeakPtr()));
 }
 
-void CertProvisioningCertsWithIdsGetter::OnGetCertificatesDone(
+void CertIterator::Cancel() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  weak_factory_.InvalidateWeakPtrs();
+  for_each_callback_.Reset();
+  on_finished_callback_.Reset();
+}
+
+void CertIterator::OnGetCertificatesDone(
     std::unique_ptr<net::CertificateList> existing_certs,
     const std::string& error_message) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!error_message.empty()) {
-    std::move(callback_).Run(/*existing_cert_ids=*/{}, error_message);
+    StopIteration(error_message);
     return;
   }
 
+  // No work to do, return empty error message.
   if (!existing_certs || existing_certs->empty()) {
-    std::move(callback_).Run(/*existing_cert_ids=*/{}, /*error_message=*/"");
+    StopIteration(error_message);
     return;
   }
 
@@ -70,136 +70,238 @@
     platform_keys_service_->GetAttributeForKey(
         GetPlatformKeysTokenId(cert_scope_), public_key,
         platform_keys::KeyAttributeType::CertificateProvisioningId,
-        base::BindOnce(&CertProvisioningCertsWithIdsGetter::CollectOneResult,
+        base::BindOnce(&CertIterator::OnGetAttributeForKeyDone,
                        weak_factory_.GetWeakPtr(), cert));
   }
 }
 
-void CertProvisioningCertsWithIdsGetter::CollectOneResult(
+void CertIterator::OnGetAttributeForKeyDone(
     scoped_refptr<net::X509Certificate> cert,
-    const base::Optional<CertProfileId>& cert_id,
+    const base::Optional<std::string>& attr_value,
     const std::string& error_message) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(wait_counter_ > 0);
 
-  // |callback_| could have been already used in case of an error in a parallel
-  // task.
-  if (callback_.is_null()) {
-    return;
-  }
-
   // TODO(crbug.com/1073512): Currently if GetAttributeForKey fails to get the
   // attribute (because it was not set or any other reason), it will return
-  // nullopt for cert_id and empty error message. When PlatformKeysService
-  // switches to error codes, a code for such situation should not be returned
-  // via callback and cert collection can be continued.
+  // nullopt for cert_profile_id and empty error message. When
+  // PlatformKeysService switches to error codes, a code for such situation
+  // should not be returned via callback and cert collection can be continued.
   if (!error_message.empty()) {
-    std::move(callback_).Run(/*existing_cert_ids=*/{}, error_message);
+    StopIteration(error_message);
     return;
   }
 
-  if (cert_id) {
-    certs_with_ids_[cert_id.value()] = cert;
+  if (attr_value) {
+    for_each_callback_.Run(cert, attr_value.value(), /*error_message=*/"");
   }
 
   --wait_counter_;
-  if (wait_counter_ != 0) {
-    return;
+  if (wait_counter_ == 0) {
+    StopIteration(/*error_message=*/"");
   }
-
-  // Move the result into the callback argument to allow deleting this object
-  // before using the result.
-  std::move(callback_).Run(std::move(certs_with_ids_), /*error_message=*/"");
 }
 
-// ========= CertProvisioningCertDeleter =======================================
-
-CertProvisioningCertDeleter::CertProvisioningCertDeleter() = default;
-CertProvisioningCertDeleter::~CertProvisioningCertDeleter() = default;
-
-void CertProvisioningCertDeleter::DeleteCerts(
-    CertScope cert_scope,
-    platform_keys::PlatformKeysService* platform_keys_service,
-    base::flat_set<CertProfileId> cert_profile_ids_to_keep,
-    DeleteCertsCallback callback) {
+void CertIterator::StopIteration(const std::string& error_message) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(platform_keys_service);
-  DCHECK(callback_.is_null());
+  DCHECK(!on_finished_callback_.is_null());
 
-  cert_scope_ = cert_scope;
-  platform_keys_service_ = platform_keys_service;
+  weak_factory_.InvalidateWeakPtrs();
+  std::move(on_finished_callback_).Run(error_message);
+}
+
+// ========= LatestCertsWithIdsGetter ==========================================
+
+LatestCertsWithIdsGetter::LatestCertsWithIdsGetter(
+    CertScope cert_scope,
+    platform_keys::PlatformKeysService* platform_keys_service)
+    : iterator_(cert_scope, platform_keys_service) {}
+
+LatestCertsWithIdsGetter::~LatestCertsWithIdsGetter() = default;
+
+void LatestCertsWithIdsGetter::GetCertsWithIds(
+    LatestCertsWithIdsGetterCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  Cancel();
   callback_ = std::move(callback);
-  cert_profile_ids_to_keep_ = std::move(cert_profile_ids_to_keep);
 
-  cert_getter_ = std::make_unique<CertProvisioningCertsWithIdsGetter>();
-  cert_getter_->GetCertsWithIds(
-      cert_scope, platform_keys_service,
-      base::BindOnce(&CertProvisioningCertDeleter::OnGetCertsWithIdsDone,
+  iterator_.IterateAll(
+      base::BindRepeating(&LatestCertsWithIdsGetter::ProcessOneCert,
+                          weak_factory_.GetWeakPtr()),
+      base::BindOnce(&LatestCertsWithIdsGetter::OnIterationFinished,
                      weak_factory_.GetWeakPtr()));
 }
 
-void CertProvisioningCertDeleter::OnGetCertsWithIdsDone(
-    base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>>
-        certs_with_ids,
+void LatestCertsWithIdsGetter::Cancel() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  weak_factory_.InvalidateWeakPtrs();
+  callback_.Reset();
+}
+
+bool LatestCertsWithIdsGetter::IsRunning() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return !callback_.is_null();
+}
+
+void LatestCertsWithIdsGetter::ProcessOneCert(
+    scoped_refptr<net::X509Certificate> new_cert,
+    const CertProfileId& cert_profile_id,
     const std::string& error_message) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!error_message.empty()) {
-    std::move(callback_).Run(error_message);
+    OnIterationFinished(error_message);
     return;
   }
 
-  if (certs_with_ids.empty()) {
-    std::move(callback_).Run(/*error_message=*/"");
+  auto cert_iter = certs_with_ids_.find(cert_profile_id);
+  if (cert_iter == certs_with_ids_.end()) {
+    certs_with_ids_[cert_profile_id] = new_cert;
     return;
   }
 
-  wait_counter_ = certs_with_ids.size();
-
-  for (const auto& kv : certs_with_ids) {
-    const CertProfileId& cert_id = kv.first;
-    if (base::Contains(cert_profile_ids_to_keep_, cert_id)) {
-      AccountOneResult();
-      continue;
-    }
-
-    const scoped_refptr<net::X509Certificate>& cert = kv.second;
-    platform_keys_service_->RemoveCertificate(
-        GetPlatformKeysTokenId(cert_scope_), cert,
-        base::BindRepeating(
-            &CertProvisioningCertDeleter::OnRemoveCertificateDone,
-            weak_factory_.GetWeakPtr()));
+  const auto& existing_cert = cert_iter->second;
+  if (existing_cert->valid_expiry() < new_cert->valid_expiry()) {
+    cert_iter->second = new_cert;
+    return;
   }
 }
 
-void CertProvisioningCertDeleter::OnRemoveCertificateDone(
+void LatestCertsWithIdsGetter::OnIterationFinished(
     const std::string& error_message) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!callback_.is_null());
+
+  weak_factory_.InvalidateWeakPtrs();
+
+  if (!error_message.empty()) {
+    certs_with_ids_ = {};
+  }
+
+  std::move(callback_).Run(std::move(certs_with_ids_), error_message);
+}
+
+// ========= CertDeleter =======================================================
+
+CertDeleter::CertDeleter(
+    CertScope cert_scope,
+    platform_keys::PlatformKeysService* platform_keys_service)
+    : cert_scope_(cert_scope),
+      platform_keys_service_(platform_keys_service),
+      iterator_(cert_scope, platform_keys_service) {}
+
+CertDeleter::~CertDeleter() = default;
+
+void CertDeleter::DeleteCerts(
+    base::flat_set<CertProfileId> cert_profile_ids_to_keep,
+    CertDeleterCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  Cancel();
+  callback_ = std::move(callback);
+  cert_profile_ids_to_keep_ = std::move(cert_profile_ids_to_keep);
+
+  iterator_.IterateAll(base::BindRepeating(&CertDeleter::ProcessOneCert,
+                                           weak_factory_.GetWeakPtr()),
+                       base::BindOnce(&CertDeleter::OnIterationFinished,
+                                      weak_factory_.GetWeakPtr()));
+}
+
+void CertDeleter::Cancel() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  weak_factory_.InvalidateWeakPtrs();
+  iteration_finished_ = false;
+  pending_delete_tasks_counter_ = 0;
+  callback_.Reset();
+  certs_with_ids_.clear();
+}
+
+void CertDeleter::ProcessOneCert(scoped_refptr<net::X509Certificate> cert,
+                                 const CertProfileId& cert_profile_id,
+                                 const std::string& error_message) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!error_message.empty()) {
-    std::move(callback_).Run(error_message);
+    ReturnStatus(error_message);
     return;
   }
 
-  AccountOneResult();
+  RememberOrDelete(cert, cert_profile_id);
 }
 
-void CertProvisioningCertDeleter::AccountOneResult() {
+void CertDeleter::RememberOrDelete(scoped_refptr<net::X509Certificate> new_cert,
+                                   const CertProfileId& cert_profile_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(wait_counter_ > 0);
 
-  // |callback_| could have been already used in case of an error in a parallel
-  // task.
-  if (callback_.is_null()) {
+  if ((!base::Contains(cert_profile_ids_to_keep_, cert_profile_id)) ||
+      (base::Time::Now() > new_cert->valid_expiry())) {
+    DeleteCert(new_cert);
     return;
   }
 
-  --wait_counter_;
-  if (wait_counter_ != 0) {
+  auto cert_iter = certs_with_ids_.find(cert_profile_id);
+  if (cert_iter == certs_with_ids_.end()) {
+    certs_with_ids_[cert_profile_id] = new_cert;
     return;
   }
 
-  std::move(callback_).Run(/*error_message=*/"");
+  // Keep only the newest certificate.
+  const auto& existing_cert = cert_iter->second;
+  if (existing_cert->valid_expiry() < new_cert->valid_expiry()) {
+    DeleteCert(existing_cert);
+    cert_iter->second = new_cert;
+    return;
+  } else {
+    DeleteCert(new_cert);
+    return;
+  }
+}
+
+void CertDeleter::DeleteCert(scoped_refptr<net::X509Certificate> cert) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  ++pending_delete_tasks_counter_;
+  platform_keys_service_->RemoveCertificate(
+      GetPlatformKeysTokenId(cert_scope_), cert,
+      base::BindRepeating(&CertDeleter::OnDeleteCertDone,
+                          weak_factory_.GetWeakPtr()));
+}
+
+void CertDeleter::OnDeleteCertDone(const std::string& error_message) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(pending_delete_tasks_counter_ > 0);
+
+  if (!error_message.empty()) {
+    ReturnStatus(error_message);
+    return;
+  }
+
+  --pending_delete_tasks_counter_;
+  CheckStateAndMaybeFinish();
+}
+
+void CertDeleter::OnIterationFinished(const std::string& error_message) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  iteration_finished_ = true;
+  CheckStateAndMaybeFinish();
+}
+
+void CertDeleter::CheckStateAndMaybeFinish() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!iteration_finished_ || (pending_delete_tasks_counter_ > 0)) {
+    return;
+  }
+
+  ReturnStatus(/*error_message=*/"");
+}
+
+void CertDeleter::ReturnStatus(const std::string& error_message) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!callback_.is_null());
+
+  weak_factory_.InvalidateWeakPtrs();
+  std::move(callback_).Run(error_message);
 }
 
 }  // namespace cert_provisioning
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers.h b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers.h
index c84e695..0222279 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers.h
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers.h
@@ -22,96 +22,150 @@
 namespace chromeos {
 namespace cert_provisioning {
 
-// ========= CertProvisioningCertsWithIdsGetter ================================
+// ========= CertIterator ======================================================
 
-using GetCertsWithIdsCallback = base::OnceCallback<void(
-    base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>>
-        certs_with_ids,
-    const std::string& error_message)>;
+using CertIteratorForEachCallback =
+    base::RepeatingCallback<void(scoped_refptr<net::X509Certificate> cert,
+                                 const CertProfileId& cert_profile_id,
+                                 const std::string& error_message)>;
+using CertIteratorOnFinishedCallback =
+    base::OnceCallback<void(const std::string& error_message)>;
 
-// Helper class that retrieves list of all certificates in a given scope with
-// their certificate profile ids. Certificates without the id are ignored.
-class CertProvisioningCertsWithIdsGetter {
+// Iterates over all existing certificates of a given |cert_scope| and combines
+// them with their certificate provisioning ids when possible. Runs |callback|
+// on every (cert, cert_profile_id) pair that had a present and non-empty
+// |cert_profile_id|. If |error_message| is not empty, then the pair is not
+// valid.
+class CertIterator {
  public:
-  CertProvisioningCertsWithIdsGetter();
-  CertProvisioningCertsWithIdsGetter(
-      const CertProvisioningCertsWithIdsGetter&) = delete;
-  CertProvisioningCertsWithIdsGetter& operator=(
-      const CertProvisioningCertsWithIdsGetter&) = delete;
-  ~CertProvisioningCertsWithIdsGetter();
+  CertIterator(CertScope cert_scope,
+               platform_keys::PlatformKeysService* platform_keys_service);
+  CertIterator(const CertIterator&) = delete;
+  CertIterator& operator=(const CertIterator&) = delete;
+  ~CertIterator();
 
-  bool IsRunning() const;
-
-  void GetCertsWithIds(
-      CertScope cert_scope,
-      platform_keys::PlatformKeysService* platform_keys_service,
-      GetCertsWithIdsCallback callback);
+  // Can be called more than once. If previous iteration is not finished, it
+  // will be canceled.
+  void IterateAll(CertIteratorForEachCallback for_each_callback,
+                  CertIteratorOnFinishedCallback on_finished_callback);
+  void Cancel();
 
  private:
   void OnGetCertificatesDone(
       std::unique_ptr<net::CertificateList> existing_certs,
       const std::string& error_message);
+  void OnGetAttributeForKeyDone(scoped_refptr<net::X509Certificate> cert,
+                                const base::Optional<std::string>& attr_value,
+                                const std::string& error_message);
+  void StopIteration(const std::string& error_message);
 
-  void CollectOneResult(scoped_refptr<net::X509Certificate> cert,
-                        const base::Optional<CertProfileId>& cert_id,
-                        const std::string& error_message);
-
-  CertScope cert_scope_ = CertScope::kDevice;
-  platform_keys::PlatformKeysService* platform_keys_service_ = nullptr;
+  const CertScope cert_scope_ = CertScope::kDevice;
+  platform_keys::PlatformKeysService* const platform_keys_service_ = nullptr;
 
   size_t wait_counter_ = 0;
-  base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>>
-      certs_with_ids_;
-  GetCertsWithIdsCallback callback_;
+  CertIteratorForEachCallback for_each_callback_;
+  CertIteratorOnFinishedCallback on_finished_callback_;
 
   SEQUENCE_CHECKER(sequence_checker_);
-  base::WeakPtrFactory<CertProvisioningCertsWithIdsGetter> weak_factory_{this};
+  base::WeakPtrFactory<CertIterator> weak_factory_{this};
 };
 
-// ========= CertProvisioningCertDeleter =======================================
+// ========= LatestCertsWithIdsGetter ==========================================
 
-using DeleteCertsCallback =
-    base::OnceCallback<void(const std::string& error_message)>;
+using LatestCertsWithIdsGetterCallback = base::OnceCallback<void(
+    base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>>
+        certs_with_ids,
+    const std::string& error_message)>;
 
-// Helper class that deletes all certificates in a given scope with certificate
-// profile ids that are not specified to be kept. Certificates without the id
-// are ignored.
-class CertProvisioningCertDeleter {
+// Collects map of certificates with their certificate provisioning ids and
+// returns it via |callback|. If there are several certificates for the same id,
+// only the newest one will be stored in the map. Only one call to
+// GetCertsWithIds() for one instance is allowed.
+class LatestCertsWithIdsGetter {
  public:
-  CertProvisioningCertDeleter();
-  CertProvisioningCertDeleter(const CertProvisioningCertDeleter&) = delete;
-  CertProvisioningCertDeleter& operator=(const CertProvisioningCertDeleter&) =
-      delete;
-  ~CertProvisioningCertDeleter();
+  LatestCertsWithIdsGetter(
+      CertScope cert_scope,
+      platform_keys::PlatformKeysService* platform_keys_service);
+  LatestCertsWithIdsGetter(const LatestCertsWithIdsGetter&) = delete;
+  LatestCertsWithIdsGetter& operator=(const LatestCertsWithIdsGetter&) = delete;
+  ~LatestCertsWithIdsGetter();
 
-  void DeleteCerts(CertScope cert_scope,
-                   platform_keys::PlatformKeysService* platform_keys_service,
-                   base::flat_set<CertProfileId> cert_profile_ids_to_keep,
-                   DeleteCertsCallback callback);
+  // Can be called more than once. If previous task is not finished, it will be
+  // canceled.
+  void GetCertsWithIds(LatestCertsWithIdsGetterCallback callback);
+  bool IsRunning() const;
+  void Cancel();
 
  private:
-  void OnGetCertsWithIdsDone(
-      base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>>
-          certs_with_ids,
-      const std::string& error_message);
+  void ProcessOneCert(scoped_refptr<net::X509Certificate> new_cert,
+                      const CertProfileId& cert_profile_id,
+                      const std::string& error_message);
+  void OnIterationFinished(const std::string& error_message);
 
-  void OnRemoveCertificateDone(const std::string& error_message);
+  CertIterator iterator_;
 
-  // Keeps track of how many certificates are already processed. Calls the
-  // |callback_| when all work is done.
-  void AccountOneResult();
-
-  CertScope cert_scope_ = CertScope::kDevice;
-  platform_keys::PlatformKeysService* platform_keys_service_ = nullptr;
-
-  size_t wait_counter_ = 0;
-  base::flat_set<CertProfileId> cert_profile_ids_to_keep_;
-  DeleteCertsCallback callback_;
-
-  std::unique_ptr<CertProvisioningCertsWithIdsGetter> cert_getter_;
+  // Accumulates results that will be returned at the end via |callback_|.
+  base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>>
+      certs_with_ids_;
+  LatestCertsWithIdsGetterCallback callback_;
 
   SEQUENCE_CHECKER(sequence_checker_);
-  base::WeakPtrFactory<CertProvisioningCertDeleter> weak_factory_{this};
+  base::WeakPtrFactory<LatestCertsWithIdsGetter> weak_factory_{this};
+};
+
+// ========= CertDeleter =======================================================
+
+using CertDeleterCallback =
+    base::OnceCallback<void(const std::string& error_message)>;
+
+// Finds and deletes certificates that 1) have ids that are not in
+// |cert_profile_ids_to_keep| set or 2) have another certificate for the same
+// id with later expiration date. Only one call to DeleteCerts() for one
+// instance is allowed.
+class CertDeleter {
+ public:
+  CertDeleter(CertScope cert_scope,
+              platform_keys::PlatformKeysService* platform_keys_service);
+  CertDeleter(const CertDeleter&) = delete;
+  CertDeleter& operator=(const CertDeleter&) = delete;
+  ~CertDeleter();
+  void Cancel();
+
+  // Can be called more than once. If previous task is not finished, it will be
+  // canceled.
+  void DeleteCerts(base::flat_set<CertProfileId> cert_profile_ids_to_keep,
+                   CertDeleterCallback callback);
+
+ private:
+  void ProcessOneCert(scoped_refptr<net::X509Certificate> cert,
+                      const CertProfileId& cert_profile_id,
+                      const std::string& error_message);
+  void RememberOrDelete(scoped_refptr<net::X509Certificate> new_cert,
+                        const CertProfileId& cert_profile_id);
+  void DeleteCert(scoped_refptr<net::X509Certificate> cert);
+  void OnDeleteCertDone(const std::string& error_message);
+  void OnIterationFinished(const std::string& error_message);
+  void CheckStateAndMaybeFinish();
+  void ReturnStatus(const std::string& error_message);
+
+  const CertScope cert_scope_ = CertScope::kDevice;
+  platform_keys::PlatformKeysService* const platform_keys_service_ = nullptr;
+
+  CertIterator iterator_;
+  bool iteration_finished_ = false;
+  size_t pending_delete_tasks_counter_ = 0;
+  CertDeleterCallback callback_;
+
+  // Contains list of currently existing certificate profile ids. Certificates
+  // with ids outside of this set can be deleted.
+  base::flat_set<CertProfileId> cert_profile_ids_to_keep_;
+
+  // Stores previously seen certificates that allows to find duplicates.
+  base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>>
+      certs_with_ids_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  base::WeakPtrFactory<CertDeleter> weak_factory_{this};
 };
 
 }  // namespace cert_provisioning
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers_unittest.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers_unittest.cc
index ea57912..672f7d0 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers_unittest.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers_unittest.cc
@@ -5,10 +5,14 @@
 #include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_platform_keys_helpers.h"
 
 #include <memory>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/containers/flat_map.h"
+#include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h"
 #include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_test_helpers.h"
 #include "chrome/browser/chromeos/platform_keys/mock_platform_keys_service.h"
@@ -17,30 +21,164 @@
 #include "net/cert/x509_certificate.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base::test::RunOnceCallback;
+using ::testing::_;
 using ::testing::ElementsAre;
 using ::testing::ElementsAreArray;
+using ::testing::Eq;
+using ::testing::Invoke;
 using ::testing::Key;
 
 namespace chromeos {
 namespace cert_provisioning {
 namespace {
 
-template <typename MapType>
-base::flat_set<typename MapType::key_type> GetKeys(const MapType& map) {
-  base::flat_set<typename MapType::key_type> keys;
-  for (const auto& pair : map) {
-    keys.insert(pair.first);
+class PlatformKeysHelpersTest : public ::testing::Test {
+ public:
+  PlatformKeysHelpersTest() : certificate_helper_(&platform_keys_service_) {}
+  PlatformKeysHelpersTest(const PlatformKeysHelpersTest&) = delete;
+  PlatformKeysHelpersTest& operator=(const PlatformKeysHelpersTest&) = delete;
+  ~PlatformKeysHelpersTest() override = default;
+
+  void RunUntilIdle() { task_environment_.RunUntilIdle(); }
+
+ protected:
+  content::BrowserTaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  ProfileHelperForTesting profile_helper_;
+  platform_keys::MockPlatformKeysService platform_keys_service_;
+  CertificateHelperForTesting certificate_helper_;
+};
+
+//================= CertProvisioningCertIteratorTest ===========================
+
+class CertProvisioningCertIteratorTest : public PlatformKeysHelpersTest {};
+
+class IteratorCallbackObserver {
+ public:
+  CertIteratorForEachCallback GetForEachCallback() {
+    return base::BindRepeating(&IteratorCallbackObserver::ForEachCallback,
+                               base::Unretained(this));
   }
-  return keys;
+
+  CertIteratorOnFinishedCallback GetOnFinishedCallback() {
+    return base::BindOnce(&IteratorCallbackObserver::OnFinishedCallback,
+                          base::Unretained(this));
+  }
+
+  MOCK_METHOD(void,
+              ForEachCallback,
+              (scoped_refptr<net::X509Certificate> cert,
+               const CertProfileId& cert_id,
+               const std::string& error_message));
+
+  MOCK_METHOD(void, OnFinishedCallback, (const std::string& error_message));
+};
+
+TEST_F(CertProvisioningCertIteratorTest, NoCertificates) {
+  const CertScope kCertScope = CertScope::kDevice;
+
+  base::RunLoop run_loop;
+  IteratorCallbackObserver callback_observer;
+
+  EXPECT_CALL(callback_observer, OnFinishedCallback(/*error_message=*/""))
+      .Times(1)
+      .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit));
+
+  CertIterator cert_iterator(kCertScope, &platform_keys_service_);
+  cert_iterator.IterateAll(callback_observer.GetForEachCallback(),
+                           callback_observer.GetOnFinishedCallback());
+  run_loop.Run();
 }
 
-class CallbackObserver {
- public:
-  using CertMap =
-      base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>>;
+TEST_F(CertProvisioningCertIteratorTest, OneCertificate) {
+  const CertScope kCertScope = CertScope::kDevice;
+  const char kCertProfileId[] = "cert_profile_id_1";
+  auto cert = certificate_helper_.AddCert(kCertScope, kCertProfileId);
 
-  GetCertsWithIdsCallback GetCallback() {
-    return base::BindOnce(&CallbackObserver::Callback, base::Unretained(this));
+  base::RunLoop run_loop;
+  IteratorCallbackObserver callback_observer;
+
+  {
+    testing::InSequence seq;
+    EXPECT_CALL(callback_observer, ForEachCallback(/*cert=*/cert,
+                                                   /*cert_id=*/kCertProfileId,
+                                                   /*error_message=*/""))
+        .Times(1);
+    EXPECT_CALL(callback_observer, OnFinishedCallback(/*error_message=*/""))
+        .Times(1)
+        .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit));
+  }
+
+  CertIterator cert_iterator(kCertScope, &platform_keys_service_);
+  cert_iterator.IterateAll(callback_observer.GetForEachCallback(),
+                           callback_observer.GetOnFinishedCallback());
+  run_loop.Run();
+}
+
+TEST_F(CertProvisioningCertIteratorTest, ManyCertificates) {
+  const CertScope kCertScope = CertScope::kDevice;
+  std::vector<std::string> ids = {"id1, ids2, id3, id4"};
+
+  base::RunLoop run_loop;
+  IteratorCallbackObserver callback_observer;
+
+  testing::ExpectationSet expect_set;
+  for (const auto& id : ids) {
+    auto cert = certificate_helper_.AddCert(kCertScope, id);
+    expect_set +=
+        EXPECT_CALL(callback_observer,
+                    ForEachCallback(/*cert=*/cert,
+                                    /*cert_id=*/id, /*error_message=*/""))
+            .Times(1);
+  }
+
+  EXPECT_CALL(callback_observer, OnFinishedCallback(/*error_message=*/""))
+      .Times(1)
+      .After(expect_set)
+      .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit));
+
+  CertIterator cert_iterator(kCertScope, &platform_keys_service_);
+  cert_iterator.IterateAll(callback_observer.GetForEachCallback(),
+                           callback_observer.GetOnFinishedCallback());
+  run_loop.Run();
+}
+
+TEST_F(CertProvisioningCertIteratorTest, CertificateWithError) {
+  const CertScope kCertScope = CertScope::kDevice;
+  const char kError[] = "test error";
+
+  certificate_helper_.AddCert(kCertScope, /*cert_profile_id=*/"id1");
+  certificate_helper_.AddCert(kCertScope, /*cert_profile_id=*/"id2");
+  certificate_helper_.AddCert(kCertScope, /*cert_profile_id=*/base::nullopt,
+                              /*error_message=*/kError);
+  certificate_helper_.AddCert(kCertScope, /*cert_profile_id=*/"id3");
+  certificate_helper_.AddCert(kCertScope, /*cert_profile_id=*/"id4");
+
+  base::RunLoop run_loop;
+  IteratorCallbackObserver callback_observer;
+  EXPECT_CALL(callback_observer, OnFinishedCallback(kError))
+      .Times(1)
+      .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit));
+
+  CertIterator cert_iterator(kCertScope, &platform_keys_service_);
+  cert_iterator.IterateAll(callback_observer.GetForEachCallback(),
+                           callback_observer.GetOnFinishedCallback());
+  run_loop.Run();
+}
+
+//================= CertPrivisioningCertGetter =================================
+
+class CertPrivisioningCertGetter : public PlatformKeysHelpersTest {};
+
+using CertMap =
+    base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>>;
+
+class GetterCallbackObserver {
+ public:
+  LatestCertsWithIdsGetterCallback GetCallback() {
+    return base::BindOnce(&GetterCallbackObserver::Callback,
+                          base::Unretained(this));
   }
 
   const CertMap& GetMap() { return cert_map_; }
@@ -60,138 +198,205 @@
   std::string error_message_;
 };
 
-class CertProvisioningCertsWithIdsGetterTest : public ::testing::Test {
- public:
-  CertProvisioningCertsWithIdsGetterTest()
-      : certificate_helper_(&platform_keys_service_) {}
-  CertProvisioningCertsWithIdsGetterTest(
-      const CertProvisioningCertsWithIdsGetterTest&) = delete;
-  CertProvisioningCertsWithIdsGetterTest& operator=(
-      const CertProvisioningCertsWithIdsGetterTest&) = delete;
-  ~CertProvisioningCertsWithIdsGetterTest() override = default;
+TEST_F(CertPrivisioningCertGetter, NoCertificates) {
+  const CertScope kCertScope = CertScope::kDevice;
 
- protected:
-  content::BrowserTaskEnvironment task_environment_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-  ProfileHelperForTesting profile_helper_;
-  platform_keys::MockPlatformKeysService platform_keys_service_;
-  CertificateHelperForTesting certificate_helper_;
-};
-
-TEST_F(CertProvisioningCertsWithIdsGetterTest, NoCertificates) {
-  CertScope cert_scope = CertScope::kDevice;
-
-  CertProvisioningCertsWithIdsGetter cert_getter;
-
-  CallbackObserver callback_observer;
-  cert_getter.GetCertsWithIds(cert_scope, &platform_keys_service_,
-                              callback_observer.GetCallback());
+  GetterCallbackObserver callback_observer;
+  LatestCertsWithIdsGetter cert_getter(kCertScope, &platform_keys_service_);
+  cert_getter.GetCertsWithIds(callback_observer.GetCallback());
   callback_observer.WaitForCallback();
 
   EXPECT_TRUE(callback_observer.GetMap().empty());
   EXPECT_TRUE(callback_observer.GetError().empty());
 }
 
-TEST_F(CertProvisioningCertsWithIdsGetterTest, SingleCertificateWithId) {
-  CertScope cert_scope = CertScope::kDevice;
+TEST_F(CertPrivisioningCertGetter, SingleCertificateWithId) {
+  const CertScope kCertScope = CertScope::kDevice;
   const char kCertProfileId[] = "cert_profile_id_1";
+  CertMap cert_map;
 
-  certificate_helper_.AddCert(cert_scope, kCertProfileId);
+  cert_map[kCertProfileId] =
+      certificate_helper_.AddCert(kCertScope, kCertProfileId);
 
-  CertProvisioningCertsWithIdsGetter cert_getter;
-
-  CallbackObserver callback_observer;
-  cert_getter.GetCertsWithIds(cert_scope, &platform_keys_service_,
-                              callback_observer.GetCallback());
+  GetterCallbackObserver callback_observer;
+  LatestCertsWithIdsGetter cert_getter(kCertScope, &platform_keys_service_);
+  cert_getter.GetCertsWithIds(callback_observer.GetCallback());
   callback_observer.WaitForCallback();
 
-  EXPECT_THAT(GetKeys(callback_observer.GetMap()), ElementsAre(kCertProfileId));
+  EXPECT_EQ(callback_observer.GetMap(), cert_map);
   EXPECT_TRUE(callback_observer.GetError().empty());
 }
 
-TEST_F(CertProvisioningCertsWithIdsGetterTest, ManyCertificatesWithId) {
-  CertScope cert_scope = CertScope::kDevice;
+TEST_F(CertPrivisioningCertGetter, ManyCertificatesWithId) {
+  const CertScope kCertScope = CertScope::kDevice;
   std::vector<std::string> ids{"cert_profile_id_0", "cert_profile_id_1",
                                "cert_profile_id_2"};
+  CertMap cert_map;
 
   for (const auto& id : ids) {
-    certificate_helper_.AddCert(cert_scope, id);
+    cert_map[id] = certificate_helper_.AddCert(kCertScope, id);
   }
 
-  CertProvisioningCertsWithIdsGetter cert_getter;
-
-  CallbackObserver callback_observer;
-  cert_getter.GetCertsWithIds(cert_scope, &platform_keys_service_,
-                              callback_observer.GetCallback());
+  GetterCallbackObserver callback_observer;
+  LatestCertsWithIdsGetter cert_getter(kCertScope, &platform_keys_service_);
+  cert_getter.GetCertsWithIds(callback_observer.GetCallback());
   callback_observer.WaitForCallback();
 
-  EXPECT_THAT(GetKeys(callback_observer.GetMap()), ElementsAreArray(ids));
+  EXPECT_EQ(callback_observer.GetMap(), cert_map);
   EXPECT_TRUE(callback_observer.GetError().empty());
 }
 
-TEST_F(CertProvisioningCertsWithIdsGetterTest, ManyCertificatesWithoutId) {
-  CertScope cert_scope = CertScope::kDevice;
+TEST_F(CertPrivisioningCertGetter, ManyCertificatesWithoutId) {
+  const CertScope kCertScope = CertScope::kDevice;
   size_t cert_count = 4;
   for (size_t i = 0; i < cert_count; ++i) {
-    certificate_helper_.AddCert(cert_scope, /*cert_profile_id=*/base::nullopt);
+    certificate_helper_.AddCert(kCertScope, /*cert_profile_id=*/base::nullopt);
   }
 
-  CertProvisioningCertsWithIdsGetter cert_getter;
-
-  CallbackObserver callback_observer;
-  cert_getter.GetCertsWithIds(cert_scope, &platform_keys_service_,
-                              callback_observer.GetCallback());
+  GetterCallbackObserver callback_observer;
+  LatestCertsWithIdsGetter cert_getter(kCertScope, &platform_keys_service_);
+  cert_getter.GetCertsWithIds(callback_observer.GetCallback());
   callback_observer.WaitForCallback();
 
   EXPECT_TRUE(callback_observer.GetMap().empty());
   EXPECT_TRUE(callback_observer.GetError().empty());
 }
 
-TEST_F(CertProvisioningCertsWithIdsGetterTest, CertificatesWithAndWithoutIds) {
-  CertScope cert_scope = CertScope::kDevice;
+TEST_F(CertPrivisioningCertGetter, CertificatesWithAndWithoutIds) {
+  const CertScope kCertScope = CertScope::kDevice;
+  CertMap cert_map;
 
   size_t cert_without_id_count = 4;
   for (size_t i = 0; i < cert_without_id_count; ++i) {
-    certificate_helper_.AddCert(cert_scope, /*cert_profile_id=*/base::nullopt);
+    certificate_helper_.AddCert(kCertScope, /*cert_profile_id=*/base::nullopt);
   }
 
   std::vector<std::string> ids{"cert_profile_id_0", "cert_profile_id_1",
                                "cert_profile_id_2"};
   for (const auto& id : ids) {
-    certificate_helper_.AddCert(cert_scope, id);
+    cert_map[id] = certificate_helper_.AddCert(kCertScope, id);
   }
 
-  CertProvisioningCertsWithIdsGetter cert_getter;
-
-  CallbackObserver callback_observer;
-  cert_getter.GetCertsWithIds(cert_scope, &platform_keys_service_,
-                              callback_observer.GetCallback());
+  GetterCallbackObserver callback_observer;
+  LatestCertsWithIdsGetter cert_getter(kCertScope, &platform_keys_service_);
+  cert_getter.GetCertsWithIds(callback_observer.GetCallback());
   callback_observer.WaitForCallback();
 
-  EXPECT_THAT(GetKeys(callback_observer.GetMap()), ElementsAreArray(ids));
+  EXPECT_EQ(callback_observer.GetMap(), cert_map);
   EXPECT_TRUE(callback_observer.GetError().empty());
 }
 
-TEST_F(CertProvisioningCertsWithIdsGetterTest, CertificateWithError) {
-  CertScope cert_scope = CertScope::kDevice;
-  const char kError[] = "test error";
+//================= CertProvisioningCertDeleterTest ============================
 
-  certificate_helper_.AddCert(cert_scope, /*cert_profile_id=*/"id1");
-  certificate_helper_.AddCert(cert_scope, /*cert_profile_id=*/"id2");
-  certificate_helper_.AddCert(cert_scope, /*cert_profile_id=*/base::nullopt,
-                              /*error_message=*/kError);
-  certificate_helper_.AddCert(cert_scope, /*cert_profile_id=*/"id3");
-  certificate_helper_.AddCert(cert_scope, /*cert_profile_id=*/"id4");
+class CertProvisioningCertDeleterTest : public PlatformKeysHelpersTest {};
 
-  CertProvisioningCertsWithIdsGetter cert_getter;
+class DeleterCallbackObserver {
+ public:
+  CertDeleterCallback GetCallback() {
+    return base::BindOnce(&DeleterCallbackObserver::Callback,
+                          base::Unretained(this));
+  }
 
-  CallbackObserver callback_observer;
-  cert_getter.GetCertsWithIds(cert_scope, &platform_keys_service_,
-                              callback_observer.GetCallback());
+  const std::string GetError() { return error_message_; }
+  void WaitForCallback() { loop_.Run(); }
+
+ protected:
+  void Callback(const std::string& error_message) {
+    error_message_ = error_message;
+    loop_.Quit();
+  }
+
+  base::RunLoop loop_;
+  std::string error_message_;
+};
+
+TEST_F(CertProvisioningCertDeleterTest, NoCertificates) {
+  const CertScope kCertScope = CertScope::kDevice;
+  base::flat_set<CertProfileId> cert_ids_to_keep;
+
+  EXPECT_CALL(platform_keys_service_, RemoveCertificate).Times(0);
+
+  DeleterCallbackObserver callback_observer;
+  CertDeleter cert_deleter(kCertScope, &platform_keys_service_);
+  cert_deleter.DeleteCerts(std::move(cert_ids_to_keep),
+                           callback_observer.GetCallback());
   callback_observer.WaitForCallback();
 
-  EXPECT_TRUE(callback_observer.GetMap().empty());
-  EXPECT_EQ(callback_observer.GetError(), kError);
+  EXPECT_TRUE(callback_observer.GetError().empty());
+}
+
+TEST_F(CertProvisioningCertDeleterTest, SomeCertsWithoutPolicy) {
+  const CertScope kCertScope = CertScope::kDevice;
+  std::vector<std::string> cert_ids_to_delete{"id1", "id2", "id3"};
+  base::flat_set<CertProfileId> cert_ids_to_keep{"id4", "id5", "id6"};
+
+  for (const auto& id : cert_ids_to_delete) {
+    auto cert = certificate_helper_.AddCert(kCertScope, id);
+    EXPECT_CALL(platform_keys_service_,
+                RemoveCertificate(GetPlatformKeysTokenId(kCertScope), cert,
+                                  /*callback=*/_))
+        .Times(1)
+        .WillOnce(RunOnceCallback<2>(/*error_message=*/""));
+  }
+
+  for (const auto& id : cert_ids_to_keep) {
+    certificate_helper_.AddCert(kCertScope, id);
+  }
+
+  DeleterCallbackObserver callback_observer;
+  CertDeleter cert_deleter(kCertScope, &platform_keys_service_);
+  cert_deleter.DeleteCerts(std::move(cert_ids_to_keep),
+                           callback_observer.GetCallback());
+  callback_observer.WaitForCallback();
+
+  EXPECT_TRUE(callback_observer.GetError().empty());
+}
+
+TEST_F(CertProvisioningCertDeleterTest, CertWasRenewed) {
+  const CertScope kCertScope = CertScope::kDevice;
+  const char kRenewedCertId[] = "id1";
+  const char kCertId2[] = "id2";
+
+  base::Time t1 = base::Time::Now();
+  base::Time t2 = t1 + base::TimeDelta::FromDays(30);
+  base::Time t3 = t2 + base::TimeDelta::FromDays(30);
+
+  auto cert = certificate_helper_.AddCert(kCertScope, kRenewedCertId,
+                                          /*error_message=*/"", t1, t2);
+  EXPECT_CALL(platform_keys_service_,
+              RemoveCertificate(GetPlatformKeysTokenId(kCertScope), cert,
+                                /*callback=*/_))
+      .Times(1)
+      .WillOnce(RunOnceCallback<2>(/*error_message=*/""));
+
+  certificate_helper_.AddCert(kCertScope, kRenewedCertId, /*error_message=*/"",
+                              t2, t3);
+  certificate_helper_.AddCert(kCertScope, kCertId2);
+
+  DeleterCallbackObserver callback_observer;
+  CertDeleter cert_deleter(kCertScope, &platform_keys_service_);
+  cert_deleter.DeleteCerts(/*cert_ids_to_keep=*/{kRenewedCertId, kCertId2},
+                           callback_observer.GetCallback());
+  callback_observer.WaitForCallback();
+
+  EXPECT_TRUE(callback_observer.GetError().empty());
+}
+
+TEST_F(CertProvisioningCertDeleterTest, PropogateError) {
+  const CertScope kCertScope = CertScope::kDevice;
+  const char kErrorMsg[] = "error 123";
+
+  certificate_helper_.AddCert(kCertScope, "id1");
+  EXPECT_CALL(platform_keys_service_, RemoveCertificate)
+      .WillOnce(RunOnceCallback<2>(kErrorMsg));
+
+  DeleterCallbackObserver callback_observer;
+  CertDeleter cert_deleter(kCertScope, &platform_keys_service_);
+  cert_deleter.DeleteCerts(/*cert_ids_to_keep=*/{},  // Delete all certs.
+                           callback_observer.GetCallback());
+  callback_observer.WaitForCallback();
+
+  EXPECT_EQ(callback_observer.GetError(), kErrorMsg);
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.cc
index de397a3..7bdce05 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.cc
@@ -15,6 +15,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/optional.h"
+#include "base/stl_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
@@ -103,6 +104,8 @@
   PrefService* pref_service = profile->GetPrefs();
   policy::CloudPolicyClient* cloud_policy_client =
       GetCloudPolicyClientForUser(profile);
+  platform_keys::PlatformKeysService* platform_keys_service =
+      platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(profile);
   NetworkStateHandler* network_state_handler = GetNetworkStateHandler();
 
   if (!profile || !pref_service || !cloud_policy_client ||
@@ -112,9 +115,8 @@
   }
 
   return std::make_unique<CertProvisioningScheduler>(
-      CertScope::kUser, profile, pref_service,
-      prefs::kRequiredClientCertificateForUser, cloud_policy_client,
-      network_state_handler,
+      CertScope::kUser, profile, pref_service, cloud_policy_client,
+      platform_keys_service, network_state_handler,
       std::make_unique<CertProvisioningUserInvalidatorFactory>(profile));
 }
 
@@ -127,18 +129,19 @@
   PrefService* pref_service = g_browser_process->local_state();
   policy::CloudPolicyClient* cloud_policy_client =
       GetCloudPolicyClientForDevice();
+  platform_keys::PlatformKeysService* platform_keys_service =
+      platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(profile);
   NetworkStateHandler* network_state_handler = GetNetworkStateHandler();
 
   if (!profile || !pref_service || !cloud_policy_client ||
-      !network_state_handler) {
+      !network_state_handler || !platform_keys_service) {
     LOG(ERROR) << "Failed to create device certificate provisioning scheduler";
     return nullptr;
   }
 
   return std::make_unique<CertProvisioningScheduler>(
-      CertScope::kDevice, profile, pref_service,
-      prefs::kRequiredClientCertificateForDevice, cloud_policy_client,
-      network_state_handler,
+      CertScope::kDevice, profile, pref_service, cloud_policy_client,
+      platform_keys_service, network_state_handler,
       std::make_unique<CertProvisioningDeviceInvalidatorFactory>(
           invalidation_service_provider));
 }
@@ -147,26 +150,28 @@
     CertScope cert_scope,
     Profile* profile,
     PrefService* pref_service,
-    const char* pref_name,
     policy::CloudPolicyClient* cloud_policy_client,
+    platform_keys::PlatformKeysService* platform_keys_service,
     NetworkStateHandler* network_state_handler,
     std::unique_ptr<CertProvisioningInvalidatorFactory> invalidator_factory)
     : cert_scope_(cert_scope),
       profile_(profile),
       pref_service_(pref_service),
-      pref_name_(pref_name),
       cloud_policy_client_(cloud_policy_client),
+      platform_keys_service_(platform_keys_service),
       network_state_handler_(network_state_handler),
+      certs_with_ids_getter_(cert_scope, platform_keys_service),
+      cert_deleter_(cert_scope, platform_keys_service),
       invalidator_factory_(std::move(invalidator_factory)) {
-  CHECK(pref_service_);
-  CHECK(pref_name_);
-  CHECK(cloud_policy_client_);
   CHECK(profile);
+  CHECK(pref_service_);
+  CHECK(cloud_policy_client_);
+  CHECK(platform_keys_service_);
+  CHECK(network_state_handler);
   CHECK(invalidator_factory_);
 
-  platform_keys_service_ =
-      platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(profile);
-  CHECK(platform_keys_service_);
+  pref_name_ = GetPrefNameForCertProfiles(cert_scope);
+  CHECK(pref_name_);
 
   network_state_handler_->AddObserver(this, FROM_HERE);
 
@@ -198,16 +203,31 @@
       base::TimeDelta::FromDays(1));
 }
 
-void CertProvisioningScheduler::ScheduleRetry(const CertProfile& profile) {
+void CertProvisioningScheduler::ScheduleRetry(const CertProfileId& profile_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&CertProvisioningScheduler::UpdateOneCertImpl,
-                 weak_factory_.GetWeakPtr(), profile.profile_id),
+                 weak_factory_.GetWeakPtr(), profile_id),
       kInconsistentDataErrorRetryDelay);
 }
 
+void CertProvisioningScheduler::ScheduleRenewal(const CertProfileId& profile_id,
+                                                base::TimeDelta delay) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (base::Contains(scheduled_renewals_, profile_id)) {
+    return;
+  }
+
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&CertProvisioningScheduler::InitiateRenewal,
+                 weak_factory_.GetWeakPtr(), profile_id),
+      delay);
+}
+
 void CertProvisioningScheduler::InitialUpdateCerts() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
@@ -227,9 +247,8 @@
     cert_profile_ids_to_keep = base::flat_set<CertProfileId>(std::move(ids));
   }
 
-  cert_deleter_ = std::make_unique<CertProvisioningCertDeleter>();
-  cert_deleter_->DeleteCerts(
-      cert_scope_, platform_keys_service_, cert_profile_ids_to_keep,
+  cert_deleter_.DeleteCerts(
+      cert_profile_ids_to_keep,
       base::BindOnce(&CertProvisioningScheduler::OnDeleteCertsWithoutPolicyDone,
                      weak_factory_.GetWeakPtr()));
 }
@@ -238,15 +257,12 @@
     const std::string& error_message) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  cert_deleter_.reset();
-
   if (!error_message.empty()) {
     LOG(ERROR) << "Failed to delete certificates without policies: "
                << error_message;
   }
 
   DeserializeWorkers();
-
   CleanVaKeysIfIdle();
 }
 
@@ -326,6 +342,12 @@
   UpdateAllCerts();
 }
 
+void CertProvisioningScheduler::InitiateRenewal(
+    const CertProfileId& cert_profile_id) {
+  scheduled_renewals_.erase(cert_profile_id);
+  UpdateOneCertImpl(cert_profile_id);
+}
+
 void CertProvisioningScheduler::UpdateOneCert(
     const CertProfileId& cert_profile_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -336,6 +358,8 @@
 
 void CertProvisioningScheduler::UpdateOneCertImpl(
     const CertProfileId& cert_profile_id) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
   EraseByKey(failed_cert_profiles_, cert_profile_id);
 
   base::Optional<CertProfile> cert_profile = GetOneCertProfile(cert_profile_id);
@@ -351,6 +375,11 @@
 
   std::vector<CertProfile> profiles = GetCertProfiles();
   CancelWorkersWithoutPolicy(profiles);
+
+  if (profiles.empty()) {
+    return;
+  }
+
   UpdateCertList(std::move(profiles));
 }
 
@@ -362,19 +391,15 @@
     return;
   }
 
-  if (certs_with_ids_getter_ && certs_with_ids_getter_->IsRunning()) {
+  if (certs_with_ids_getter_.IsRunning()) {
     queued_profiles_to_update_.insert(std::make_move_iterator(profiles.begin()),
                                       std::make_move_iterator(profiles.end()));
     return;
   }
 
-  certs_with_ids_getter_ =
-      std::make_unique<CertProvisioningCertsWithIdsGetter>();
-  certs_with_ids_getter_->GetCertsWithIds(
-      cert_scope_, platform_keys_service_,
-      base::BindOnce(
-          &CertProvisioningScheduler::UpdateCertListWithExistingCerts,
-          weak_factory_.GetWeakPtr(), std::move(profiles)));
+  certs_with_ids_getter_.GetCertsWithIds(base::BindOnce(
+      &CertProvisioningScheduler::UpdateCertListWithExistingCerts,
+      weak_factory_.GetWeakPtr(), std::move(profiles)));
 }
 
 void CertProvisioningScheduler::UpdateCertListWithExistingCerts(
@@ -384,20 +409,38 @@
     const std::string& error_message) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  certs_with_ids_getter_.reset();
-
   if (!error_message.empty()) {
     LOG(ERROR) << "Failed to get existing cert ids: " << error_message;
     return;
   }
 
   for (const auto& profile : profiles) {
-    if (base::Contains(existing_certs_with_ids, profile.profile_id) ||
-        base::Contains(failed_cert_profiles_, profile.profile_id)) {
+    if (base::Contains(failed_cert_profiles_, profile.profile_id)) {
       continue;
     }
 
-    ProcessProfile(profile);
+    auto cert_iter = existing_certs_with_ids.find(profile.profile_id);
+    if (cert_iter == existing_certs_with_ids.end()) {
+      // The certificate does not exists and should be provisioned.
+      ProcessProfile(profile);
+      continue;
+    }
+
+    const auto& cert = cert_iter->second;
+    base::Time now = base::Time::Now();
+    if ((now + profile.renewal_period) >= cert->valid_expiry()) {
+      // The certificate should be renewed immediately.
+      ProcessProfile(profile);
+      continue;
+    }
+
+    if ((now + base::TimeDelta::FromDays(1) + profile.renewal_period) >=
+        cert->valid_expiry()) {
+      // The certificate should be renewed within 1 day.
+      base::Time target_time = cert->valid_expiry() - profile.renewal_period;
+      ScheduleRenewal(profile.profile_id, /*delay=*/target_time - now);
+      continue;
+    }
   }
 
   if (!queued_profiles_to_update_.empty()) {
@@ -470,7 +513,7 @@
     case CertProvisioningWorkerState::kInconsistentDataError:
       LOG(WARNING) << "Inconsistent data error for certificate profile: "
                    << profile.profile_id;
-      ScheduleRetry(profile);
+      ScheduleRetry(profile.profile_id);
       break;
     case CertProvisioningWorkerState::kCanceled:
       break;
@@ -574,7 +617,10 @@
     return;
   }
 
-  VLOG(0) << "Waiting for internet connection";
+  if (!workers_.empty()) {
+    VLOG(0) << "Waiting for internet connection";
+  }
+
   is_waiting_for_online_ = true;
   for (auto& kv : workers_) {
     auto& worker_ptr = kv.second;
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.h b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.h
index 33cac42e..c78209bf 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.h
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler.h
@@ -75,8 +75,8 @@
       CertScope cert_scope,
       Profile* profile,
       PrefService* pref_service,
-      const char* pref_name,
       policy::CloudPolicyClient* cloud_policy_client,
+      platform_keys::PlatformKeysService* platform_keys_service,
       NetworkStateHandler* network_state_handler,
       std::unique_ptr<CertProvisioningInvalidatorFactory> invalidator_factory);
   ~CertProvisioningScheduler() override;
@@ -99,8 +99,9 @@
  private:
   void ScheduleInitialUpdate();
   void ScheduleDailyUpdate();
-  // Posts delayed task to call ProcessProfile.
-  void ScheduleRetry(const CertProfile& profile);
+  // Posts delayed task to call UpdateOneCertImpl.
+  void ScheduleRetry(const CertProfileId& profile_id);
+  void ScheduleRenewal(const CertProfileId& profile_id, base::TimeDelta delay);
 
   void InitialUpdateCerts();
   void DeleteCertsWithoutPolicy();
@@ -110,6 +111,7 @@
   void OnCleanVaKeysIfIdleDone(base::Optional<bool> delete_result);
   void RegisterForPrefsChanges();
 
+  void InitiateRenewal(const CertProfileId& cert_profile_id);
   void UpdateOneCertImpl(const CertProfileId& cert_profile_id);
   void UpdateCertList(std::vector<CertProfile> profiles);
   void UpdateCertListWithExistingCerts(
@@ -150,10 +152,14 @@
   PrefService* pref_service_ = nullptr;
   const char* pref_name_ = nullptr;
   policy::CloudPolicyClient* cloud_policy_client_ = nullptr;
-  NetworkStateHandler* network_state_handler_ = nullptr;
   platform_keys::PlatformKeysService* platform_keys_service_ = nullptr;
+  NetworkStateHandler* network_state_handler_ = nullptr;
   PrefChangeRegistrar pref_change_registrar_;
   WorkerMap workers_;
+  // Contains cert profile ids that will be renewed before next daily update.
+  // Helps to prevent creation of more than one delayed task for renewal. When
+  // the renewal starts for a profile id, it is removed from the set.
+  base::flat_set<CertProfileId> scheduled_renewals_;
   // Collection of cert profile ids that failed recently. They will not be
   // retried until next |DailyUpdateCerts|. FailedWorkerInfo contains some extra
   // information about the failure. Profiles that failed with
@@ -167,8 +173,8 @@
   // run, because an update for them was triggered during the current run.
   CertProfileSet queued_profiles_to_update_;
 
-  std::unique_ptr<CertProvisioningCertsWithIdsGetter> certs_with_ids_getter_;
-  std::unique_ptr<CertProvisioningCertDeleter> cert_deleter_;
+  LatestCertsWithIdsGetter certs_with_ids_getter_;
+  CertDeleter cert_deleter_;
   std::unique_ptr<CertProvisioningInvalidatorFactory> invalidator_factory_;
 
   base::WeakPtrFactory<CertProvisioningScheduler> weak_factory_{this};
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler_unittest.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler_unittest.cc
index eda00a1..61c4828 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler_unittest.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/json/json_reader.h"
-#include "base/test/gmock_callback_support.h"
 #include "base/test/values_test_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h"
@@ -23,9 +22,9 @@
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base::Time;
 using base::TimeDelta;
 using base::test::ParseJson;
-using base::test::RunOnceCallback;
 using testing::_;
 using testing::AtLeast;
 using testing::ByMove;
@@ -40,62 +39,10 @@
 namespace cert_provisioning {
 namespace {
 
-const char kWifiServiceGuid[] = "wifi_guid";
-
-//================ CertificateTestHelper =======================================
-
-// Generated by chrome/test/data/policy/test_certs/create_test_certs.sh
-const char kFakeCertificate[] = R"(-----BEGIN CERTIFICATE-----
-MIIDJzCCAg+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxyb290
-X2NhX2NlcnQwHhcNMjAwMjI1MTUyNTU2WhcNMzAwMjIyMTUyNTU2WjAUMRIwEAYD
-VQQDDAkxMjcuMC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDW
-druvpaJovmyWzIcjtsSk/lp319+zNPSYGLzJzTeEmnFoDf/b89ft6xR1NIahmvVd
-UHGOMlzgDKnNkqWw+pgpn6U8dk+leWnwlUefzDz7OY8qXfX29Vh0m/kATQc64lnp
-rX19fEi2DOgH6heCQDSaHI/KAnAXccwl8kdGuTEnvdzbdHqQq8pPGpEqzC/NOjk7
-kDNkUt0J74ZVMm4+jhVOgZ35mFLtC+xjfycBgbnt8yfPOzmOMwXTjYDPNaIy32AZ
-t66oIToteoW5Ilg+j5Mto3unBDHrw8rml3+W/nwHuOPEIgBqLQFfWtXpuX8CbcS6
-SFNK4hxCJOvlzUbgTpsrAgMBAAGjgYAwfjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW
-BBRDEl1/2pL5LtKnpIly+XCj3N6MwDAfBgNVHSMEGDAWgBQrwVEnUQZlX850A2N+
-URfS8BxoyzAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0RBAgw
-BocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAXZd+Ul7GUFZPLSiTZ618hUI2UdO0
-7rtPwBw3TephWuyEeHht+WhzA3sRL3nprEiJqIg5w/Tlfz4dsObpSU3vKmDhLzAx
-HJrN5vKdbEj9wyuhYSRJwvJka1ZOgPzhQcDQOp1SqonNxLx/sSMDR2UIDMBGzrkQ
-sDkn58N5eWm+hZADOAKROHR47j85VcsmYGK7z2x479YzsyWyOm0dbACXv7/HvFkz
-56KvgxRaPZQzQUg5yuXa21IjQz07wyWSYnHpm2duAbYFl6CTR9Rlj5vpRkKsQP1W
-mMhGDBfgEskdbM+0agsZrJupoQMBUbD5gflcJlW3kwlboi3dTtiGixfYWw==
------END CERTIFICATE-----)";
-
-struct CertificateTestHelper {
- public:
-  CertificateTestHelper() {
-    cert = CreateSingleCertificateFromBytes(kFakeCertificate,
-                                            sizeof(kFakeCertificate));
-    DCHECK(cert);
-  }
-
-  void GetCertificates(chromeos::platform_keys::TokenId token_id,
-                       const platform_keys::GetCertificatesCallback& callback) {
-    auto result = std::make_unique<net::CertificateList>();
-    *result = cert_list;
-    std::move(callback).Run(std::move(result), "");
-  }
-
-  void AddCert() {
-    DCHECK(cert_list.empty())
-        << "Current implementation supports only one certificate";
-    cert_list.push_back(cert);
-  }
-
-  scoped_refptr<net::X509Certificate> GetCert() const { return cert; }
-
-  std::string GetPublicKeyForCert() const {
-    return platform_keys::GetSubjectPublicKeyInfo(cert);
-  }
-
- private:
-  scoped_refptr<net::X509Certificate> cert;
-  net::CertificateList cert_list;
-};
+constexpr char kWifiServiceGuid[] = "wifi_guid";
+constexpr char kCertProfileId[] = "cert_profile_id_1";
+constexpr char kCertProfileVersion[] = "cert_profile_version_1";
+constexpr TimeDelta kCertProfileRenewalPeriod = TimeDelta::FromSeconds(0);
 
 //================ CertProvisioningSchedulerTest ===============================
 
@@ -115,28 +62,18 @@
     RegisterProfilePrefs(pref_service_.registry());
     RegisterLocalStatePrefs(pref_service_.registry());
 
-    platform_keys_service_ =
-        static_cast<platform_keys::MockPlatformKeysService*>(
-            platform_keys::PlatformKeysServiceFactory::GetInstance()
-                ->SetTestingFactoryAndUse(
-                    GetProfile(),
-                    base::BindRepeating(
-                        &platform_keys::BuildMockPlatformKeysService)));
-    ASSERT_TRUE(platform_keys_service_);
+    certificate_helper_ =
+        std::make_unique<CertificateHelperForTesting>(&platform_keys_service_);
 
     AddOnlineWifiNetwork();
   }
 
-  void FastForwardBy(base::TimeDelta delta) {
+  void FastForwardBy(TimeDelta delta) {
     task_environment_.FastForwardBy(delta);
   }
 
   void SetUp() override {
     CertProvisioningWorkerFactory::SetFactoryForTesting(&mock_factory_);
-
-    EXPECT_CALL(*platform_keys_service_, GetCertificates)
-        .WillRepeatedly(Invoke(&certificate_helper_,
-                               &CertificateTestHelper::GetCertificates));
   }
 
   void TearDown() override {
@@ -179,19 +116,19 @@
   content::BrowserTaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   ProfileHelperForTesting profile_helper_for_testing_;
-  platform_keys::MockPlatformKeysService* platform_keys_service_ = nullptr;
+  platform_keys::MockPlatformKeysService platform_keys_service_;
+  std::unique_ptr<CertificateHelperForTesting> certificate_helper_;
   StrictMock<SpyingFakeCryptohomeClient> fake_cryptohome_client_;
   TestingPrefServiceSimple pref_service_;
   policy::MockCloudPolicyClient cloud_policy_client_;
   // Only expected creations are allowed.
   StrictMock<MockCertProvisioningWorkerFactory> mock_factory_;
-  CertificateTestHelper certificate_helper_;
   NetworkStateTestHelper network_state_test_helper_;
   std::string wifi_network_service_path_;
 };
 
 TEST_F(CertProvisioningSchedulerTest, Success) {
-  CertScope cert_scope = CertScope::kUser;
+  const CertScope kCertScope = CertScope::kUser;
 
   auto mock_invalidation_factory_obj =
       std::make_unique<MockCertProvisioningInvalidatorFactory>();
@@ -199,8 +136,8 @@
       mock_invalidation_factory_obj.get();
 
   CertProvisioningScheduler scheduler(
-      cert_scope, GetProfile(), &pref_service_,
-      prefs::kRequiredClientCertificateForUser, &cloud_policy_client_,
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
       network_state_test_helper_.network_state_handler(),
       std::move(mock_invalidation_factory_obj));
 
@@ -211,7 +148,7 @@
       .Times(1);
 
   // The policy is empty, so no workers should be created yet.
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
   EXPECT_EQ(scheduler.GetWorkers().size(), 0U);
 
   EXPECT_CALL(*mock_invalidation_factory, Create)
@@ -220,23 +157,21 @@
           Return(ByMove(nullptr)));  // nullptr is good enough for mock worker.
 
   // One worker will be created on prefs update.
-  const char kCertProfileId[] = "cert_profile_id_1";
-  const char kCertProfileVersion[] = "cert_profile_version_1";
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
   MockCertProvisioningWorker* worker =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1),
                           /*is_waiting=*/false, cert_profile);
 
-  // Add 1 certificate profile to the policy ("cert_profile_id" is the same as
-  // above).
+  // Add 1 certificate profile to the policy (the values are the same as
+  // in |cert_profile|).
   base::Value config = ParseJson(
       R"([{"name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version":"cert_profile_version_1",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000}])");
-  pref_service_.Set(prefs::kRequiredClientCertificateForUser, config);
+           "key_algorithm":"rsa"}])");
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
 
   EXPECT_EQ(scheduler.GetWorkers().size(), 1U);
 
@@ -248,31 +183,22 @@
   EXPECT_EQ(scheduler.GetWorkers().size(), 0U);
   EXPECT_TRUE(scheduler.GetFailedCertProfileIds().empty());
 
-  certificate_helper_.AddCert();
-
-  EXPECT_CALL(
-      *platform_keys_service_,
-      GetAttributeForKey(
-          GetPlatformKeysTokenId(cert_scope),
-          certificate_helper_.GetPublicKeyForCert(),
-          platform_keys::KeyAttributeType::CertificateProvisioningId, _))
-      .Times(1)
-      .WillOnce(base::test::RunOnceCallback<3>(kCertProfileId, ""));
+  certificate_helper_->AddCert(kCertScope, kCertProfileId);
 
   // Check one more time that scheduler doesn't create new workers for
   // finished certificate profiles (the factory will fail on an attempt to
   // do so).
   scheduler.UpdateAllCerts();
 
-  FastForwardBy(base::TimeDelta::FromSeconds(100));
+  FastForwardBy(TimeDelta::FromSeconds(100));
 }
 
 TEST_F(CertProvisioningSchedulerTest, WorkerFailed) {
-  CertScope cert_scope = CertScope::kDevice;
+  const CertScope kCertScope = CertScope::kDevice;
 
   CertProvisioningScheduler scheduler(
-      cert_scope, GetProfile(), &pref_service_,
-      prefs::kRequiredClientCertificateForDevice, &cloud_policy_client_,
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
       network_state_test_helper_.network_state_handler(),
       MakeFakeInvalidationFactory());
 
@@ -283,27 +209,25 @@
       .Times(1);
 
   // The policy is empty, so no workers should be created yet.
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
   EXPECT_EQ(scheduler.GetWorkers().size(), 0U);
 
   // One worker will be created on prefs update.
-  const char kCertProfileId[] = "cert_profile_id_1";
-  const char kCertProfileVersion[] = "cert_profile_version_1";
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
   MockCertProvisioningWorker* worker =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1),
                           /*is_waiting=*/false, cert_profile);
 
-  // Add 1 certificate profile to the policy ("cert_profile_id" is the same as
-  // above).
+  // Add 1 certificate profile to the policy (the values are the same as
+  // in |cert_profile|).
   base::Value config = ParseJson(
       R"([{"name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version":"cert_profile_version_1",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000}])");
-  pref_service_.Set(prefs::kRequiredClientCertificateForDevice, config);
+           "key_algorithm":"rsa"}])");
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
 
   // Now 1 worker should be created.
   EXPECT_EQ(scheduler.GetWorkers().size(), 1U);
@@ -318,16 +242,7 @@
   EXPECT_TRUE(
       base::Contains(scheduler.GetFailedCertProfileIds(), kCertProfileId));
 
-  certificate_helper_.AddCert();
-
-  EXPECT_CALL(
-      *platform_keys_service_,
-      GetAttributeForKey(
-          GetPlatformKeysTokenId(cert_scope),
-          certificate_helper_.GetPublicKeyForCert(),
-          platform_keys::KeyAttributeType::CertificateProvisioningId, _))
-      .Times(1)
-      .WillOnce(base::test::RunOnceCallback<3>(kCertProfileId, ""));
+  certificate_helper_->AddCert(kCertScope, kCertProfileId);
 
   // Check one more time that scheduler doesn't create new workers for failed
   // certificate profiles (the factory will fail on an attempt to do so).
@@ -335,24 +250,23 @@
 }
 
 TEST_F(CertProvisioningSchedulerTest, InitialAndDailyUpdates) {
-  CertScope cert_scope = CertScope::kUser;
+  const CertScope kCertScope = CertScope::kUser;
 
-  // Add 1 certificate profile to the policy.
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
+
+  // Add 1 certificate profile to the policy (the values are the same as
+  // in |cert_profile|).
   base::Value config = ParseJson(
       R"([{"name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version":"cert_profile_version_1",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000}])");
-  pref_service_.Set(prefs::kRequiredClientCertificateForUser, config);
-  // Same as in the policy.
-  const char kCertProfileId[] = "cert_profile_id_1";
-  const char kCertProfileVersion[] = "cert_profile_version_1";
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+           "key_algorithm":"rsa"}])");
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
 
   CertProvisioningScheduler scheduler(
-      cert_scope, GetProfile(), &pref_service_,
-      prefs::kRequiredClientCertificateForUser, &cloud_policy_client_,
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
       network_state_test_helper_.network_state_handler(),
       MakeFakeInvalidationFactory());
 
@@ -364,46 +278,47 @@
 
   // Now one worker should be created.
   MockCertProvisioningWorker* worker =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
                           cert_profile);
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
   ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
 
   // Emulate callback from the worker.
-  CertProfile profile{kCertProfileId, kCertProfileVersion};
-  scheduler.OnProfileFinished(profile, CertProvisioningWorkerState::kFailed);
+  scheduler.OnProfileFinished(cert_profile,
+                              CertProvisioningWorkerState::kFailed);
 
   ASSERT_EQ(scheduler.GetWorkers().size(), 0U);
   EXPECT_TRUE(
       base::Contains(scheduler.GetFailedCertProfileIds(), kCertProfileId));
 
   // No workers should be created yet.
-  FastForwardBy(base::TimeDelta::FromHours(20));
+  FastForwardBy(TimeDelta::FromHours(20));
   ASSERT_EQ(scheduler.GetWorkers().size(), 0U);
 
   // Now list of failed profiles should be cleared that will cause a new attempt
   // to provision certificate.
   MockCertProvisioningWorker* worker2 =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker2->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
                            cert_profile);
-  FastForwardBy(base::TimeDelta::FromHours(5));
+  FastForwardBy(TimeDelta::FromHours(5));
   ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
 
   // Emulate callback from the worker.
-  scheduler.OnProfileFinished(profile, CertProvisioningWorkerState::kSucceeded);
+  scheduler.OnProfileFinished(cert_profile,
+                              CertProvisioningWorkerState::kSucceeded);
 
   ASSERT_EQ(scheduler.GetWorkers().size(), 0U);
   EXPECT_TRUE(scheduler.GetFailedCertProfileIds().empty());
 }
 
 TEST_F(CertProvisioningSchedulerTest, MultipleWorkers) {
-  CertScope cert_scope = CertScope::kDevice;
+  const CertScope kCertScope = CertScope::kDevice;
 
   CertProvisioningScheduler scheduler(
-      cert_scope, GetProfile(), &pref_service_,
-      prefs::kRequiredClientCertificateForUser, &cloud_policy_client_,
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
       network_state_test_helper_.network_state_handler(),
       MakeFakeInvalidationFactory());
 
@@ -414,57 +329,57 @@
       .Times(1);
 
   // The policy is empty, so no workers should be created yet.
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
   ASSERT_EQ(scheduler.GetWorkers().size(), 0U);
 
   // New workers will be created on prefs update.
   const char kCertProfileId0[] = "cert_profile_id_0";
   const char kCertProfileVersion0[] = "cert_profile_version_0";
-  CertProfile cert_profile0{kCertProfileId0, kCertProfileVersion0};
+  CertProfile cert_profile0(kCertProfileId0, kCertProfileVersion0,
+                            /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
   const char kCertProfileId1[] = "cert_profile_id_1";
   const char kCertProfileVersion1[] = "cert_profile_version_1";
-  CertProfile cert_profile1{kCertProfileId1, kCertProfileVersion1};
+  CertProfile cert_profile1(kCertProfileId1, kCertProfileVersion1,
+                            /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
   const char kCertProfileId2[] = "cert_profile_id_2";
   const char kCertProfileVersion2[] = "cert_profile_version_2";
-  CertProfile cert_profile2{kCertProfileId2, kCertProfileVersion2};
+  CertProfile cert_profile2(kCertProfileId2, kCertProfileVersion2,
+                            /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
   MockCertProvisioningWorker* worker0 =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile0);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile0);
   worker0->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
                            cert_profile0);
   MockCertProvisioningWorker* worker1 =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile1);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile1);
   worker1->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
                            cert_profile1);
   MockCertProvisioningWorker* worker2 =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile2);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile2);
   worker2->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
                            cert_profile2);
 
-  // Add 3 certificate profiles to the policy ("cert_profile_id"s are the same
-  // as above).
+  // Add 3 certificate profiles to the policy (the values are the same as
+  // in |cert_profile|-s)
   base::Value config = ParseJson(
       R"([{
            "name": "Certificate Profile 0",
            "cert_profile_id":"cert_profile_id_0",
            "policy_version":"cert_profile_version_0",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000
+           "key_algorithm":"rsa"
           },
           {
            "name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version":"cert_profile_version_1",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000
+           "key_algorithm":"rsa"
           },
           {
            "name": "Certificate Profile 2",
            "cert_profile_id":"cert_profile_id_2",
            "policy_version":"cert_profile_version_2",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000
+           "key_algorithm":"rsa"
           }])");
-  pref_service_.Set(prefs::kRequiredClientCertificateForUser, config);
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
 
   // Now one worker for each profile should be created.
   ASSERT_EQ(scheduler.GetWorkers().size(), 3U);
@@ -485,16 +400,7 @@
   EXPECT_TRUE(
       base::Contains(scheduler.GetFailedCertProfileIds(), kCertProfileId2));
 
-  certificate_helper_.AddCert();
-
-  EXPECT_CALL(
-      *platform_keys_service_,
-      GetAttributeForKey(
-          GetPlatformKeysTokenId(cert_scope),
-          certificate_helper_.GetPublicKeyForCert(),
-          platform_keys::KeyAttributeType::CertificateProvisioningId, _))
-      .Times(1)
-      .WillOnce(base::test::RunOnceCallback<3>(kCertProfileId0, ""));
+  certificate_helper_->AddCert(kCertScope, kCertProfileId0);
 
   // Make scheduler check workers state.
   scheduler.UpdateAllCerts();
@@ -503,15 +409,6 @@
   EXPECT_TRUE(
       base::Contains(scheduler.GetFailedCertProfileIds(), kCertProfileId2));
 
-  EXPECT_CALL(
-      *platform_keys_service_,
-      GetAttributeForKey(
-          GetPlatformKeysTokenId(cert_scope),
-          certificate_helper_.GetPublicKeyForCert(),
-          platform_keys::KeyAttributeType::CertificateProvisioningId, _))
-      .Times(1)
-      .WillOnce(base::test::RunOnceCallback<3>(kCertProfileId0, ""));
-
   // Check one more time that scheduler doesn't create new workers for failed
   // certificate profiles (the factory will fail on an attempt to do so).
   scheduler.UpdateAllCerts();
@@ -519,50 +416,40 @@
 }
 
 TEST_F(CertProvisioningSchedulerTest, RemoveCertWithoutPolicy) {
-  CertScope cert_scope = CertScope::kDevice;
-  const char kCertProfileId[] = "cert_profile_id_1";
+  const CertScope kCertScope = CertScope::kDevice;
 
-  certificate_helper_.AddCert();
-
-  EXPECT_CALL(*platform_keys_service_,
-              GetAttributeForKey(
-                  GetPlatformKeysTokenId(cert_scope),
-                  certificate_helper_.GetPublicKeyForCert(),
-                  platform_keys::KeyAttributeType::CertificateProvisioningId,
-                  /*callback=*/_))
-      .Times(1)
-      .WillOnce(base::test::RunOnceCallback<3>(kCertProfileId, ""));
+  certificate_helper_->AddCert(kCertScope, kCertProfileId);
 
   CertProvisioningScheduler scheduler(
-      cert_scope, GetProfile(), &pref_service_,
-      prefs::kRequiredClientCertificateForDevice, &cloud_policy_client_,
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
       network_state_test_helper_.network_state_handler(),
       MakeFakeInvalidationFactory());
 
-  EXPECT_CALL(*platform_keys_service_,
-              RemoveCertificate(GetPlatformKeysTokenId(cert_scope),
-                                /*certificate=*/certificate_helper_.GetCert(),
-                                /*callback=*/_))
+  EXPECT_CALL(
+      platform_keys_service_,
+      RemoveCertificate(GetPlatformKeysTokenId(kCertScope),
+                        /*certificate=*/certificate_helper_->GetCerts().back(),
+                        /*callback=*/_))
       .Times(1);
 
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
 }
 
 TEST_F(CertProvisioningSchedulerTest, DeserializeWorkers) {
-  CertScope cert_scope = CertScope::kUser;
+  const CertScope kCertScope = CertScope::kUser;
 
-  const char kCertProfileId[] = "cert_profile_id_1";
-  const char kCertProfileVersion[] = "cert_profile_version_1";
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
-  // Add 1 certificate profile to the policy.
+  // Add 1 certificate profile to the policy (the values are the same as
+  // in |cert_profile|).
   base::Value cert_profiles = ParseJson(
       R"([{"name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version": "cert_profile_version_1",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000}])");
-  pref_service_.Set(prefs::kRequiredClientCertificateForUser, cert_profiles);
+           "key_algorithm":"rsa"}])");
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), cert_profiles);
   // Add 1 serialized worker for the profile.
   base::Value saved_worker = ParseJson(
       R"({
@@ -578,37 +465,35 @@
   base::Value all_saved_workers(base::Value::Type::DICTIONARY);
   all_saved_workers.SetKey("cert_profile_1", saved_worker.Clone());
 
-  pref_service_.Set(prefs::kCertificateProvisioningStateForUser,
-                    all_saved_workers);
+  pref_service_.Set(GetPrefNameForSerialization(kCertScope), all_saved_workers);
 
   MockCertProvisioningWorker* worker =
-      mock_factory_.ExpectDeserializeReturnMock(cert_scope, saved_worker);
+      mock_factory_.ExpectDeserializeReturnMock(kCertScope, saved_worker);
   // is_waiting==true should be set by Serializer so Scheduler knows that the
   // worker has to be continued manually.
   worker->SetExpectations(/*do_step_times=*/AtLeast(1),
                           /*is_waiting=*/true, cert_profile);
 
   CertProvisioningScheduler scheduler(
-      cert_scope, GetProfile(), &pref_service_,
-      prefs::kRequiredClientCertificateForUser, &cloud_policy_client_,
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
       network_state_test_helper_.network_state_handler(),
       MakeFakeInvalidationFactory());
 
   // Now one worker should be created.
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
   ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
 }
 
 TEST_F(CertProvisioningSchedulerTest, InconsistentDataErrorHandling) {
-  CertScope cert_scope = CertScope::kDevice;
+  const CertScope kCertScope = CertScope::kDevice;
 
-  const char kCertProfileId[] = "cert_profile_id_1";
   const char kCertProfileVersion1[] = "cert_profile_version_1";
   const char kCertProfileVersion2[] = "cert_profile_version_2";
 
   CertProvisioningScheduler scheduler(
-      cert_scope, GetProfile(), &pref_service_,
-      prefs::kRequiredClientCertificateForDevice, &cloud_policy_client_,
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
       network_state_test_helper_.network_state_handler(),
       MakeFakeInvalidationFactory());
 
@@ -619,23 +504,26 @@
       .Times(1);
 
   // The policy is empty, so no workers should be created yet.
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
   EXPECT_EQ(scheduler.GetWorkers().size(), 0U);
 
-  CertProfile cert_profile_v1{kCertProfileId, kCertProfileVersion1};
+  CertProfile cert_profile_v1(kCertProfileId, kCertProfileVersion1,
+                              /*is_va_enabled=*/true,
+                              kCertProfileRenewalPeriod);
+
   MockCertProvisioningWorker* worker =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile_v1);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile_v1);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
                           cert_profile_v1);
 
-  // Add 1 certificate profile to the policy.
+  // Add 1 certificate profile to the policy (the values are the same as
+  // in |cert_profile_v1|).
   base::Value config = ParseJson(
       R"([{"name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version":"cert_profile_version_1",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000}])");
-  pref_service_.Set(prefs::kRequiredClientCertificateForDevice, config);
+           "key_algorithm":"rsa"}])");
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
 
   // Now 1 worker should be created.
   EXPECT_EQ(scheduler.GetWorkers().size(), 1U);
@@ -650,12 +538,12 @@
   EXPECT_TRUE(scheduler.GetFailedCertProfileIds().empty());
 
   // Add a new worker to the factory.
-  worker = mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile_v1);
+  worker = mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile_v1);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
                           cert_profile_v1);
 
   // After some delay a new worker should be created to try again.
-  FastForwardBy(base::TimeDelta::FromSeconds(31));
+  FastForwardBy(TimeDelta::FromSeconds(31));
   EXPECT_EQ(scheduler.GetWorkers().size(), 1U);
 
   // Emulate callback from the worker.
@@ -668,8 +556,10 @@
   EXPECT_TRUE(scheduler.GetFailedCertProfileIds().empty());
 
   // Add a new worker to the factory.
-  CertProfile cert_profile_v2{kCertProfileId, kCertProfileVersion2};
-  worker = mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile_v2);
+  CertProfile cert_profile_v2(kCertProfileId, kCertProfileVersion2,
+                              /*is_va_enabled=*/true,
+                              kCertProfileRenewalPeriod);
+  worker = mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile_v2);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
                           cert_profile_v2);
 
@@ -678,9 +568,8 @@
       R"([{"name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version":"cert_profile_version_2",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000}])");
-  pref_service_.Set(prefs::kRequiredClientCertificateForDevice, config);
+           "key_algorithm":"rsa"}])");
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
   EXPECT_EQ(scheduler.GetWorkers().size(), 1U);
 
   // If another update happens, workers with matching policy versions should not
@@ -694,44 +583,40 @@
       R"([{"name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version":"cert_profile_version_3",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000}])");
+           "key_algorithm":"rsa"}])");
 
   // On policy change scheduler should detect mismatch in policy versions and
   // stop the worker.
   EXPECT_CALL(*worker,
               Stop(CertProvisioningWorkerState::kInconsistentDataError));
 
-  pref_service_.Set(prefs::kRequiredClientCertificateForDevice, config);
-  // EXPECT_EQ(scheduler.GetWorkers().size(), 1U);
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
 
   // Emulate that after some time the worker reports back to scheduler.
-  FastForwardBy(base::TimeDelta::FromSeconds(10));
+  FastForwardBy(TimeDelta::FromSeconds(10));
   scheduler.OnProfileFinished(
       cert_profile_v1, CertProvisioningWorkerState::kInconsistentDataError);
   EXPECT_EQ(scheduler.GetWorkers().size(), 0U);
 }
 
 TEST_F(CertProvisioningSchedulerTest, RetryAfterNoInternetConnection) {
-  CertScope cert_scope = CertScope::kDevice;
+  const CertScope kCertScope = CertScope::kDevice;
   SetWifiNetworkState(shill::kStateIdle);
 
-  // Add 1 certificate profile to the policy.
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
+  // Add 1 certificate profile to the policy (the values are the same as
+  // in |cert_profile|).
   base::Value config = ParseJson(
       R"([{"name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version":"cert_profile_version_1",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000}])");
-  pref_service_.Set(prefs::kRequiredClientCertificateForDevice, config);
-  // Same as in the policy.
-  const char kCertProfileId[] = "cert_profile_id_1";
-  const char kCertProfileVersion[] = "cert_profile_version_1";
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+           "key_algorithm":"rsa"}])");
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
 
   CertProvisioningScheduler scheduler(
-      cert_scope, GetProfile(), &pref_service_,
-      prefs::kRequiredClientCertificateForDevice, &cloud_policy_client_,
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
       network_state_test_helper_.network_state_handler(),
       MakeFakeInvalidationFactory());
 
@@ -741,12 +626,12 @@
                   attestation::AttestationKeyType::KEY_DEVICE, kKeyNamePrefix))
       .Times(1);
 
-  FastForwardBy(base::TimeDelta::FromHours(72));
+  FastForwardBy(TimeDelta::FromHours(72));
   ASSERT_EQ(scheduler.GetWorkers().size(), 0U);
 
   // Add a new worker to the factory.
   MockCertProvisioningWorker* worker =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
                           cert_profile);
 
@@ -756,23 +641,21 @@
 }
 
 TEST_F(CertProvisioningSchedulerTest, DeleteWorkerWithoutPolicy) {
-  CertScope cert_scope = CertScope::kDevice;
+  const CertScope kCertScope = CertScope::kDevice;
 
-  // Add 1 certificate profile to the policy.
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
+  // Add 1 certificate profile to the policy (the values are the same as
+  // in |cert_profile|).
   base::Value config = ParseJson(
       R"([{"name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version":"cert_profile_version_1",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000}])");
-  // Same as in the policy.
-  const char kCertProfileId[] = "cert_profile_id_1";
-  const char kCertProfileVersion[] = "cert_profile_version_1";
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+           "key_algorithm":"rsa"}])");
 
   CertProvisioningScheduler scheduler(
-      cert_scope, GetProfile(), &pref_service_,
-      prefs::kRequiredClientCertificateForDevice, &cloud_policy_client_,
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
       network_state_test_helper_.network_state_handler(),
       MakeFakeInvalidationFactory());
 
@@ -784,24 +667,24 @@
 
   // Add a new worker to the factory.
   MockCertProvisioningWorker* worker =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
                           cert_profile);
 
   // Prefs update will be ignored because initialization task has not finished
   // yet.
-  pref_service_.Set(prefs::kRequiredClientCertificateForDevice, config);
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
   ASSERT_EQ(scheduler.GetWorkers().size(), 0U);
 
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
   EXPECT_EQ(scheduler.GetWorkers().size(), 1U);
 
   EXPECT_CALL(*worker, Stop(CertProvisioningWorkerState::kCanceled));
 
   config = ParseJson("[]");
-  pref_service_.Set(prefs::kRequiredClientCertificateForDevice, config);
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
 
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
   // Emulate callback from the worker.
   scheduler.OnProfileFinished(cert_profile,
                               CertProvisioningWorkerState::kCanceled);
@@ -810,12 +693,12 @@
 }
 
 TEST_F(CertProvisioningSchedulerTest, DeleteVaKeysOnIdle) {
-  CertScope cert_scope = CertScope::kDevice;
+  const CertScope kCertScope = CertScope::kDevice;
 
   {
     CertProvisioningScheduler scheduler(
-        cert_scope, GetProfile(), &pref_service_,
-        prefs::kRequiredClientCertificateForDevice, &cloud_policy_client_,
+        kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+        &platform_keys_service_,
         network_state_test_helper_.network_state_handler(),
         MakeFakeInvalidationFactory());
 
@@ -826,15 +709,15 @@
             attestation::AttestationKeyType::KEY_DEVICE, kKeyNamePrefix))
         .Times(1);
 
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
+    FastForwardBy(TimeDelta::FromSeconds(1));
   }
 
   {
-    const char kCertProfileId[] = "cert_profile_id_1";
-    const char kCertProfileVersion[] = "cert_profile_version_1";
-    CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+    CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                             /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
-    // Add 1 serialized worker for the profile.
+    // Add 1 serialized worker for the profile (the values are the same as
+    // in |cert_profile|).
     base::Value saved_worker = ParseJson(
         R"({
           "cert_profile": {
@@ -849,64 +732,64 @@
     base::Value all_saved_workers(base::Value::Type::DICTIONARY);
     all_saved_workers.SetKey("cert_profile_1", saved_worker.Clone());
 
-    pref_service_.Set(prefs::kCertificateProvisioningStateForDevice,
+    pref_service_.Set(GetPrefNameForSerialization(kCertScope),
                       all_saved_workers);
 
     MockCertProvisioningWorker* worker =
-        mock_factory_.ExpectDeserializeReturnMock(cert_scope, saved_worker);
+        mock_factory_.ExpectDeserializeReturnMock(kCertScope, saved_worker);
     // This worker should be deleted approximately right after creation, hence
     // no calls for DoStep.
     worker->SetExpectations(/*do_step_times=*/Exactly(0),
                             /*is_waiting=*/true, cert_profile);
 
     CertProvisioningScheduler scheduler(
-        cert_scope, GetProfile(), &pref_service_,
-        prefs::kRequiredClientCertificateForDevice, &cloud_policy_client_,
+        kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+        &platform_keys_service_,
         network_state_test_helper_.network_state_handler(),
         MakeFakeInvalidationFactory());
 
     EXPECT_CALL(fake_cryptohome_client_, OnTpmAttestationDeleteKeysByPrefix)
         .Times(0);
 
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
+    FastForwardBy(TimeDelta::FromSeconds(1));
   }
 }
 
 TEST_F(CertProvisioningSchedulerTest, UpdateOneCert) {
-  CertScope cert_scope = CertScope::kUser;
+  const CertScope kCertScope = CertScope::kUser;
 
   CertProvisioningScheduler scheduler(
-      cert_scope, GetProfile(), &pref_service_,
-      prefs::kRequiredClientCertificateForUser, &cloud_policy_client_,
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
       network_state_test_helper_.network_state_handler(),
       MakeFakeInvalidationFactory());
 
-  const char kCertProfileId[] = "cert_profile_id_1";
-  const char kCertProfileVersion[] = "cert_profile_version_1";
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   // From CertProvisioningScheduler::CleanVaKeysIfIdle.
   EXPECT_CALL(fake_cryptohome_client_, OnTpmAttestationDeleteKeysByPrefix);
+  FastForwardBy(TimeDelta::FromSeconds(1));
 
   // There is no policies yet, |kCertProfileId| will not be found.
   scheduler.UpdateOneCert(kCertProfileId);
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
   ASSERT_TRUE(scheduler.GetWorkers().empty());
 
   MockCertProvisioningWorker* worker =
-      mock_factory_.ExpectCreateReturnMock(cert_scope, cert_profile);
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/Exactly(1),
                           /*is_waiting=*/false, cert_profile);
 
-  // Add 1 certificate profile to the policy ("cert_profile_id" is the same as
-  // above). That will trigger creation of a worker.
+  // Add 1 certificate profile to the policy (the values are the same as
+  // in |cert_profile|).
   base::Value config = ParseJson(
       R"([{"name": "Certificate Profile 1",
            "cert_profile_id":"cert_profile_id_1",
            "policy_version":"cert_profile_version_1",
-           "key_algorithm":"rsa",
-           "renewal_period_seconds": 365000}])");
-  pref_service_.Set(prefs::kRequiredClientCertificateForUser, config);
+           "key_algorithm":"rsa"}])");
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
+  FastForwardBy(TimeDelta::FromSeconds(1));
 
   // If worker is waiting, it should be continued.
   {
@@ -914,7 +797,7 @@
                             /*is_waiting=*/true, cert_profile);
 
     scheduler.UpdateOneCert(kCertProfileId);
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
+    FastForwardBy(TimeDelta::FromSeconds(1));
     ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
   }
 
@@ -924,7 +807,7 @@
                             /*is_waiting=*/false, cert_profile);
 
     scheduler.UpdateOneCert(kCertProfileId);
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
+    FastForwardBy(TimeDelta::FromSeconds(1));
     ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
   }
 
@@ -937,38 +820,86 @@
                             /*is_waiting=*/true, cert_profile);
 
     scheduler.UpdateOneCert(kCertProfileId);
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
+    FastForwardBy(TimeDelta::FromSeconds(1));
     ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
 
     worker->SetExpectations(/*do_step_times=*/Exactly(1),
                             /*is_waiting=*/true, cert_profile);
+
     SetWifiNetworkState(shill::kStateOnline);
   }
 
   // Emulate callback from the worker.
   scheduler.OnProfileFinished(cert_profile,
                               CertProvisioningWorkerState::kSucceeded);
-  FastForwardBy(base::TimeDelta::FromSeconds(1));
+  FastForwardBy(TimeDelta::FromSeconds(1));
   ASSERT_TRUE(scheduler.GetWorkers().empty());
 
-  certificate_helper_.AddCert();
-  EXPECT_CALL(
-      *platform_keys_service_,
-      GetAttributeForKey(
-          GetPlatformKeysTokenId(cert_scope),
-          certificate_helper_.GetPublicKeyForCert(),
-          platform_keys::KeyAttributeType::CertificateProvisioningId, _))
-      .Times(1)
-      .WillOnce(base::test::RunOnceCallback<3>(kCertProfileId, ""));
+  certificate_helper_->AddCert(kCertScope, kCertProfileId);
 
   {
     // If a certificate already exists, a new worker should not be created.
     scheduler.UpdateOneCert(kCertProfileId);
-    FastForwardBy(base::TimeDelta::FromSeconds(1));
+    FastForwardBy(TimeDelta::FromSeconds(1));
     ASSERT_TRUE(scheduler.GetWorkers().empty());
   }
 }
 
+TEST_F(CertProvisioningSchedulerTest, CertRenewal) {
+  const CertScope kCertScope = CertScope::kUser;
+  // 1 day == 86400 seconds.
+  const TimeDelta kRenewalPeriod = TimeDelta::FromDays(1);
+
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kRenewalPeriod);
+
+  const Time t1 = Time::Now() - TimeDelta::FromDays(1);
+  const Time t2 = Time::Now() + TimeDelta::FromDays(7);
+  certificate_helper_->AddCert(kCertScope, kCertProfileId, /*error_message=*/"",
+                               /*nat_valid_before=*/t1, /*not_valid_after=*/t2);
+
+  // Add 1 certificate profile to the policy (the values are the same as
+  // in |cert_profile|).
+  base::Value config = ParseJson(
+      R"([{"name": "Certificate Profile 1",
+           "cert_profile_id":"cert_profile_id_1",
+           "policy_version":"cert_profile_version_1",
+           "key_algorithm":"rsa",
+           "renewal_period_seconds": 86400}])");
+  pref_service_.Set(GetPrefNameForCertProfiles(kCertScope), config);
+
+  CertProvisioningScheduler scheduler(
+      kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
+      &platform_keys_service_,
+      network_state_test_helper_.network_state_handler(),
+      MakeFakeInvalidationFactory());
+
+  // From CertProvisioningScheduler::CleanVaKeysIfIdle.
+  EXPECT_CALL(fake_cryptohome_client_,
+              OnTpmAttestationDeleteKeysByPrefix(
+                  attestation::AttestationKeyType::KEY_USER, kKeyNamePrefix))
+      .Times(1);
+
+  // The certificate already exists, nothing should happen on scheduler
+  // creation.
+  FastForwardBy(TimeDelta::FromSeconds(1));
+  ASSERT_EQ(scheduler.GetWorkers().size(), 0U);
+
+  // Also nothing should happen in the next ~6 days.
+  FastForwardBy(TimeDelta::FromDays(5) + TimeDelta::FromHours(23));
+  ASSERT_EQ(scheduler.GetWorkers().size(), 0U);
+
+  MockCertProvisioningWorker* worker =
+      mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
+  worker->SetExpectations(/*do_step_times=*/AtLeast(1),
+                          /*is_waiting=*/false, cert_profile);
+
+  // One day (according to the policy) before the certificate expires, scheduler
+  // should create a new worker to provision a replacement.
+  FastForwardBy(TimeDelta::FromHours(1));
+  ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
+}
+
 }  // namespace
 }  // namespace cert_provisioning
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_serializer.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_serializer.cc
index eee13b8..4b0b6f45 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_serializer.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_serializer.cc
@@ -7,6 +7,7 @@
 #include "base/base64.h"
 #include "base/logging.h"
 #include "base/optional.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_common.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
@@ -16,15 +17,16 @@
 
 namespace {
 
-const char kKeyNameCertScope[] = "cert_scope";
-const char kKeyNameCertProfile[] = "cert_profile";
-const char kKeyNameState[] = "state";
-const char kKeyNamePublicKey[] = "public_key";
-const char kKeyNameInvalidationTopic[] = "invalidation_topic";
+constexpr char kKeyNameCertScope[] = "cert_scope";
+constexpr char kKeyNameCertProfile[] = "cert_profile";
+constexpr char kKeyNameState[] = "state";
+constexpr char kKeyNamePublicKey[] = "public_key";
+constexpr char kKeyNameInvalidationTopic[] = "invalidation_topic";
 
-const char kKeyNameCertProfileId[] = "profile_id";
-const char kKeyNameCertProfileVersion[] = "policy_version";
-const char kKeyNameCertProfileVaEnabled[] = "va_enabled";
+constexpr char kKeyNameCertProfileId[] = "profile_id";
+constexpr char kKeyNameCertProfileVersion[] = "policy_version";
+constexpr char kKeyNameCertProfileVaEnabled[] = "va_enabled";
+constexpr char kKeyNameCertProfileRenewalPeriod[] = "renewal_period";
 
 template <typename T>
 bool ConvertToEnum(int value, T* dst) {
@@ -71,21 +73,34 @@
   return true;
 }
 
+bool DeserializeRenewalPeriod(const base::Value& parent_value,
+                              const char* value_name,
+                              base::TimeDelta* dst) {
+  base::Optional<int> serialized_time = parent_value.FindIntKey(value_name);
+  *dst = base::TimeDelta::FromSeconds(serialized_time.value_or(0));
+  return true;
+}
+
 base::Value SerializeCertProfile(const CertProfile& profile) {
-  static_assert(CertProfile::kVersion == 3, "This function should be updated");
+  static_assert(CertProfile::kVersion == 4, "This function should be updated");
 
   base::Value result(base::Value::Type::DICTIONARY);
   result.SetStringKey(kKeyNameCertProfileId, profile.profile_id);
   result.SetStringKey(kKeyNameCertProfileVersion, profile.policy_version);
   result.SetBoolKey(kKeyNameCertProfileVaEnabled, profile.is_va_enabled);
 
+  if (!profile.renewal_period.is_zero()) {
+    result.SetIntKey(kKeyNameCertProfileRenewalPeriod,
+                     profile.renewal_period.InSeconds());
+  }
+
   return result;
 }
 
 bool DeserializeCertProfile(const base::Value& parent_value,
                             const char* value_name,
                             CertProfile* dst) {
-  static_assert(CertProfile::kVersion == 3, "This function should be updated");
+  static_assert(CertProfile::kVersion == 4, "This function should be updated");
 
   const base::Value* serialized_profile =
       parent_value.FindKeyOfType(value_name, base::Value::Type::DICTIONARY);
@@ -104,6 +119,9 @@
   is_ok = is_ok && DeserializeBoolValue(*serialized_profile,
                                         kKeyNameCertProfileVaEnabled,
                                         &(dst->is_va_enabled));
+  is_ok = is_ok && DeserializeRenewalPeriod(*serialized_profile,
+                                            kKeyNameCertProfileRenewalPeriod,
+                                            &(dst->renewal_period));
   return is_ok;
 }
 
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_test_helpers.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_test_helpers.cc
index 4bb7edd..0b587b8 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_test_helpers.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_test_helpers.cc
@@ -6,7 +6,7 @@
 
 #include "base/optional.h"
 #include "base/test/gmock_callback_support.h"
-#include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
+#include "base/time/time.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "net/test/cert_builder.h"
@@ -63,18 +63,15 @@
   std::move(callback).Run(std::move(result), "");
 }
 
-void CertificateHelperForTesting::AddCert(
-    CertScope cert_scope,
-    const base::Optional<CertProfileId>& cert_profile_id) {
-  AddCert(cert_scope, cert_profile_id, /*error_message=*/"");
-}
-
-void CertificateHelperForTesting::AddCert(
+scoped_refptr<net::X509Certificate> CertificateHelperForTesting::AddCert(
     CertScope cert_scope,
     const base::Optional<CertProfileId>& cert_profile_id,
-    const std::string& error_message) {
+    const std::string& error_message,
+    base::Time not_valid_before,
+    base::Time not_valid_after) {
   net::CertBuilder cert_builder(template_cert_->cert_buffer(),
                                 /*issuer=*/nullptr);
+  cert_builder.SetValidity(not_valid_before, not_valid_after);
   auto cert = cert_builder.GetX509Certificate();
 
   EXPECT_CALL(
@@ -86,6 +83,30 @@
       .WillRepeatedly(RunOnceCallback<3>(cert_profile_id, error_message));
 
   cert_list_.push_back(cert);
+  return cert;
+}
+
+scoped_refptr<net::X509Certificate> CertificateHelperForTesting::AddCert(
+    CertScope cert_scope,
+    const base::Optional<CertProfileId>& cert_profile_id) {
+  base::Time not_valid_before =
+      base::Time::Now() - base::TimeDelta::FromDays(1);
+  base::Time not_valid_after =
+      base::Time::Now() + base::TimeDelta::FromDays(365);
+  return AddCert(cert_scope, cert_profile_id, /*error_message=*/"",
+                 not_valid_before, not_valid_after);
+}
+
+scoped_refptr<net::X509Certificate> CertificateHelperForTesting::AddCert(
+    CertScope cert_scope,
+    const base::Optional<CertProfileId>& cert_profile_id,
+    const std::string& error_message) {
+  base::Time not_valid_before =
+      base::Time::Now() - base::TimeDelta::FromDays(1);
+  base::Time not_valid_after =
+      base::Time::Now() + base::TimeDelta::FromDays(365);
+  return AddCert(cert_scope, cert_profile_id, error_message, not_valid_before,
+                 not_valid_after);
 }
 
 void CertificateHelperForTesting::ClearCerts() {
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_test_helpers.h b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_test_helpers.h
index f50160af..b7180702 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_test_helpers.h
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_test_helpers.h
@@ -19,19 +19,41 @@
 
 //================ CertificateHelperForTesting =================================
 
-// Redirects PlatformKeysService::GetCertificate calls to itself. Allows to add
-// certificate to a fake storage with assigned CertProfileId-s.
+// Allows to add certificate to a fake storage with assigned CertProfileId-s.
+// Redirects PlatformKeysService::GetCertificate calls to itself and return all
+// stored certificates as a result.
 struct CertificateHelperForTesting {
  public:
   explicit CertificateHelperForTesting(
       platform_keys::MockPlatformKeysService* platform_keys_service);
   ~CertificateHelperForTesting();
 
-  void AddCert(CertScope cert_scope,
-               const base::Optional<CertProfileId>& cert_profile_id);
-  void AddCert(CertScope cert_scope,
-               const base::Optional<CertProfileId>& cert_profile_id,
-               const std::string& error_message);
+  // Generates and adds a certificate to internal fake certificate storage.
+  // Returns refpointer to the generated certificate. If |error_message| is not
+  // empty, an attempt to retrieve |cert_profile_id| via
+  // PlatformKeysService::GetAttributeForKey() will fail with |error_message|.
+  // |not_valid_before|, |not_valid_after| configure validity period of the
+  // certificate.
+  scoped_refptr<net::X509Certificate> AddCert(
+      CertScope cert_scope,
+      const base::Optional<CertProfileId>& cert_profile_id,
+      const std::string& error_message,
+      base::Time not_valid_before,
+      base::Time not_valid_after);
+
+  // Simplified version of AddCert(). The certificate is not expired and has
+  // |cert_profile_id|.
+  scoped_refptr<net::X509Certificate> AddCert(
+      CertScope cert_scope,
+      const base::Optional<CertProfileId>& cert_profile_id);
+
+  // Simplified version of AddCert(). The certificate is not expired, but fails
+  // to retrieve |cert_profile_id|.
+  scoped_refptr<net::X509Certificate> AddCert(
+      CertScope cert_scope,
+      const base::Optional<CertProfileId>& cert_profile_id,
+      const std::string& error_message);
+
   void ClearCerts();
   const net::CertificateList& GetCerts() const;
 
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.cc
index 58e981f..0c2bfbdc 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker.cc
@@ -109,19 +109,6 @@
   return res;
 }
 
-bool CheckPublicKeyInCertificate(
-    const scoped_refptr<net::X509Certificate>& cert,
-    const std::string& public_key) {
-  base::StringPiece spki_from_cert;
-  if (!net::asn1::ExtractSPKIFromDERCert(
-          net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()),
-          &spki_from_cert)) {
-    return false;
-  }
-
-  return (public_key == spki_from_cert);
-}
-
 }  // namespace
 
 // ============= CertProvisioningWorkerFactory =================================
@@ -633,7 +620,9 @@
     return;
   }
 
-  if (!CheckPublicKeyInCertificate(cert, public_key_)) {
+  std::string public_key_from_cert =
+      platform_keys::GetSubjectPublicKeyInfo(cert);
+  if (public_key_from_cert != public_key_) {
     LOG(ERROR) << "Downloaded certificate does not match the expected key pair";
     UpdateState(CertProvisioningWorkerState::kFailed);
     return;
diff --git a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker_unittest.cc b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker_unittest.cc
index bdfab342..1d63f26 100644
--- a/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker_unittest.cc
+++ b/chrome/browser/chromeos/cert_provisioning/cert_provisioning_worker_unittest.cc
@@ -79,6 +79,8 @@
 
 constexpr char kCertProfileId[] = "cert_profile_1";
 constexpr char kCertProfileVersion[] = "cert_profile_version_1";
+constexpr base::TimeDelta kCertProfileRenewalPeriod =
+    base::TimeDelta::FromSeconds(0);
 // Prefix + certificate profile name.
 constexpr char kCertScopeStrUser[] = "google/chromeos/user";
 constexpr char kCertScopeStrDevice[] = "google/chromeos/device";
@@ -404,7 +406,8 @@
 TEST_F(CertProvisioningWorkerTest, Success) {
   base::HistogramTester histogram_tester;
 
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   MockCertProvisioningInvalidator* mock_invalidator = nullptr;
@@ -480,8 +483,8 @@
 // Checks that the worker makes all necessary requests to other modules during
 // success scenario when VA challenge is not received.
 TEST_F(CertProvisioningWorkerTest, NoVaSuccess) {
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion,
-                           /*is_va_enabled=*/false};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/false, kCertProfileRenewalPeriod);
 
   CertProvisioningWorkerImpl worker(
       CertScope::kUser, GetProfile(), &testing_pref_service_, cert_profile,
@@ -531,7 +534,8 @@
 // Checks that when the server returns try_again_later field, the worker will
 // retry a request when it asked to continue the provisioning.
 TEST_F(CertProvisioningWorkerTest, TryLaterManualRetry) {
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   CertProvisioningWorkerImpl worker(
@@ -633,7 +637,8 @@
 // Checks that when the server returns try_again_later field, the worker will
 // automatically retry a request after some time.
 TEST_F(CertProvisioningWorkerTest, TryLaterWait) {
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   CertProvisioningWorkerImpl worker(
@@ -743,7 +748,8 @@
 // Checks that when the server returns error status, the worker will enter an
 // error state and stop the provisioning.
 TEST_F(CertProvisioningWorkerTest, StatusErrorHandling) {
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   CertProvisioningWorkerImpl worker(
@@ -785,7 +791,8 @@
 TEST_F(CertProvisioningWorkerTest, ResponseErrorHandling) {
   base::HistogramTester histogram_tester;
 
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   auto worker = CertProvisioningWorkerFactory::Get()->Create(
@@ -828,7 +835,8 @@
 }
 
 TEST_F(CertProvisioningWorkerTest, InconsistentDataErrorHandling) {
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   auto worker = CertProvisioningWorkerFactory::Get()->Create(
@@ -867,7 +875,8 @@
 // Checks that when the server returns TEMPORARY_UNAVAILABLE status code, the
 // worker will automatically retry a request using exponential backoff strategy.
 TEST_F(CertProvisioningWorkerTest, BackoffStrategy) {
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   CertProvisioningWorkerImpl worker(
@@ -930,7 +939,8 @@
 TEST_F(CertProvisioningWorkerTest, RemoveRegisteredKey) {
   base::HistogramTester histogram_tester;
 
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   MockCertProvisioningInvalidator* mock_invalidator = nullptr;
   CertProvisioningWorkerImpl worker(
@@ -1017,8 +1027,10 @@
 };
 
 TEST_F(CertProvisioningWorkerTest, SerializationSuccess) {
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
-  CertScope cert_scope = CertScope::kUser;
+  const base::TimeDelta kRenewalPeriod = base::TimeDelta::FromSeconds(1200300);
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kRenewalPeriod);
+  const CertScope kCertScope = CertScope::kUser;
 
   std::unique_ptr<MockCertProvisioningInvalidator> mock_invalidator_obj;
   MockCertProvisioningInvalidator* mock_invalidator = nullptr;
@@ -1026,7 +1038,7 @@
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   std::unique_ptr<CertProvisioningWorker> worker =
       CertProvisioningWorkerFactory::Get()->Create(
-          cert_scope, GetProfile(), &testing_pref_service_, cert_profile,
+          kCertScope, GetProfile(), &testing_pref_service_, cert_profile,
           &cloud_policy_client_, MakeInvalidator(), GetCallback());
 
   StrictMock<PrefServiceObserver> pref_observer(
@@ -1051,7 +1063,8 @@
             "cert_profile": {
               "policy_version": "cert_profile_version_1",
               "profile_id": "cert_profile_1",
-              "va_enabled": true
+              "va_enabled": true,
+              "renewal_period": 1200300
             },
             "cert_scope": 0,
             "invalidation_topic": "",
@@ -1083,7 +1096,7 @@
         .Times(1);
 
     worker = CertProvisioningWorkerFactory::Get()->Deserialize(
-        cert_scope, GetProfile(), &testing_pref_service_,
+        kCertScope, GetProfile(), &testing_pref_service_,
         *pref_val.FindKeyOfType(kCertProfileId, base::Value::Type::DICTIONARY),
         &cloud_policy_client_, MakeInvalidator(&mock_invalidator),
         GetCallback());
@@ -1127,7 +1140,8 @@
             "cert_profile": {
               "policy_version": "cert_profile_version_1",
               "profile_id": "cert_profile_1",
-              "va_enabled": true
+              "va_enabled": true,
+              "renewal_period": 1200300
             },
             "cert_scope": 0,
             "invalidation_topic": "fake_invalidation_topic_1",
@@ -1161,7 +1175,7 @@
         .Times(1);
 
     worker = CertProvisioningWorkerFactory::Get()->Deserialize(
-        cert_scope, GetProfile(), &testing_pref_service_,
+        kCertScope, GetProfile(), &testing_pref_service_,
         *pref_val.FindKeyOfType(kCertProfileId, base::Value::Type::DICTIONARY),
         &cloud_policy_client_, std::move(mock_invalidator_obj), GetCallback());
   }
@@ -1190,7 +1204,8 @@
 }
 
 TEST_F(CertProvisioningWorkerTest, SerializationOnFailure) {
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   auto worker = CertProvisioningWorkerFactory::Get()->Create(
@@ -1250,7 +1265,8 @@
 }
 
 TEST_F(CertProvisioningWorkerTest, InformationalGetters) {
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   CertProvisioningWorkerImpl worker(
@@ -1303,12 +1319,13 @@
 TEST_F(CertProvisioningWorkerTest, CancelDeviceWorker) {
   base::HistogramTester histogram_tester;
 
-  CertScope cert_scope = CertScope::kDevice;
-  CertProfile cert_profile{kCertProfileId, kCertProfileVersion};
+  const CertScope kCertScope = CertScope::kDevice;
+  CertProfile cert_profile(kCertProfileId, kCertProfileVersion,
+                           /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
 
   MockTpmChallengeKeySubtle* mock_tpm_challenge_key = PrepareTpmChallengeKey();
   auto worker = CertProvisioningWorkerFactory::Get()->Create(
-      cert_scope, GetProfile(), &testing_pref_service_, cert_profile,
+      kCertScope, GetProfile(), &testing_pref_service_, cert_profile,
       &cloud_policy_client_, MakeInvalidator(), GetCallback());
 
   EXPECT_CALL(callback_observer_, Callback).Times(0);
diff --git a/chrome/browser/chromeos/login/app_launch_signin_screen.cc b/chrome/browser/chromeos/login/app_launch_signin_screen.cc
index 829393a0..a378b136 100644
--- a/chrome/browser/chromeos/login/app_launch_signin_screen.cc
+++ b/chrome/browser/chromeos/login/app_launch_signin_screen.cc
@@ -89,10 +89,6 @@
   NOTREACHED();
 }
 
-void AppLaunchSigninScreen::ShowEnableDebuggingScreen() {
-  NOTREACHED();
-}
-
 void AppLaunchSigninScreen::ShowKioskEnableScreen() {
   NOTREACHED();
 }
diff --git a/chrome/browser/chromeos/login/app_launch_signin_screen.h b/chrome/browser/chromeos/login/app_launch_signin_screen.h
index eea22757..8dcfb91 100644
--- a/chrome/browser/chromeos/login/app_launch_signin_screen.h
+++ b/chrome/browser/chromeos/login/app_launch_signin_screen.h
@@ -59,7 +59,6 @@
              const SigninSpecifics& specifics) override;
   void OnSigninScreenReady() override;
   void ShowEnterpriseEnrollmentScreen() override;
-  void ShowEnableDebuggingScreen() override;
   void ShowKioskEnableScreen() override;
   void ShowKioskAutolaunchScreen() override;
   void ShowWrongHWIDScreen() override;
diff --git a/chrome/browser/chromeos/login/enable_debugging_browsertest.cc b/chrome/browser/chromeos/login/enable_debugging_browsertest.cc
index 97fbe8d..e81b183 100644
--- a/chrome/browser/chromeos/login/enable_debugging_browsertest.cc
+++ b/chrome/browser/chromeos/login/enable_debugging_browsertest.cc
@@ -174,7 +174,9 @@
   }
 
   void InvokeEnableDebuggingScreen() {
-    test::ExecuteOobeJS("cr.ui.Oobe.handleAccelerator('debugging');");
+    LoginDisplayHost::default_host()->HandleAccelerator(
+        ash::LoginAcceleratorAction::kEnableDebugging);
+
     OobeScreenWaiter(EnableDebuggingScreenView::kScreenId).Wait();
   }
 
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 2da0226e..d91d0365 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -229,15 +229,6 @@
   }
 }
 
-bool CanShowDebuggingFeatures() {
-  // We need to be on the login screen and in dev mode to show this menu item.
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-             chromeos::switches::kSystemDevMode) &&
-         base::CommandLine::ForCurrentProcess()->HasSwitch(
-             chromeos::switches::kLoginManager) &&
-         !session_manager::SessionManager::Get()->IsSessionStarted();
-}
-
 bool IsUpdateRequiredDeadlineReached() {
   policy::MinimumVersionPolicyHandler* policy_handler =
       g_browser_process->platform_part()
@@ -837,11 +828,6 @@
                  weak_factory_.GetWeakPtr()));
 }
 
-void ExistingUserController::OnStartEnableDebuggingScreen() {
-  if (CanShowDebuggingFeatures())
-    ShowEnableDebuggingScreen();
-}
-
 void ExistingUserController::OnStartKioskEnableScreen() {
   KioskAppManager::Get()->GetConsumerKioskAutoLaunchStatus(base::BindOnce(
       &ExistingUserController::OnConsumerKioskAutoLaunchCheckCompleted,
@@ -910,10 +896,6 @@
   GetLoginDisplayHost()->StartWizard(EnrollmentScreenView::kScreenId);
 }
 
-void ExistingUserController::ShowEnableDebuggingScreen() {
-  GetLoginDisplayHost()->StartWizard(EnableDebuggingScreenView::kScreenId);
-}
-
 void ExistingUserController::ShowKioskEnableScreen() {
   GetLoginDisplayHost()->StartWizard(KioskEnableScreenView::kScreenId);
 }
@@ -1588,6 +1570,7 @@
     auto_login_delay_ = 0;
   }
 
+  // TODO(crbug.com/1105387): Part of initial screen logic.
   if (show_update_required_screen) {
     // Update required screen overrides public session auto login.
     StopAutoLoginTimer();
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index 715ca6b5..b0e7eb6 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -107,7 +107,6 @@
              const SigninSpecifics& specifics) override;
   void OnSigninScreenReady() override;
   void OnStartEnterpriseEnrollment() override;
-  void OnStartEnableDebuggingScreen() override;
   void OnStartKioskEnableScreen() override;
   void OnStartKioskAutolaunchScreen() override;
   void ResetAutoLoginTimer() override;
@@ -204,9 +203,6 @@
   // Enters the enterprise enrollment screen.
   void ShowEnrollmentScreen();
 
-  // Shows "enable developer features" screen.
-  void ShowEnableDebuggingScreen();
-
   // Shows privacy notification in case of auto lunch managed guest session.
   void ShowAutoLaunchManagedGuestSessionNotification();
 
diff --git a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
index 23c814f..2f80eb6f 100644
--- a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
@@ -295,8 +295,10 @@
   StartupUtils::MarkOobeCompleted();
 }
 
+// TODO(crbug.com/1104861): Test has been flaky since
+// https://crrev.com/c/2215650 landed.
 IN_PROC_BROWSER_TEST_F(LoginUIKeyboardTestWithUsersAndOwner,
-                       CheckPODScreenKeyboard) {
+                       DISABLED_CheckPODScreenKeyboard) {
   EXPECT_EQ(3, ash::LoginScreenTestApi::GetUsersCount());
 
   std::vector<std::string> expected_input_methods;
diff --git a/chrome/browser/chromeos/login/screens/mock_welcome_screen.cc b/chrome/browser/chromeos/login/screens/mock_welcome_screen.cc
index a8c973e8..005f10e 100644
--- a/chrome/browser/chromeos/login/screens/mock_welcome_screen.cc
+++ b/chrome/browser/chromeos/login/screens/mock_welcome_screen.cc
@@ -11,8 +11,8 @@
     const WelcomeScreen::ScreenExitCallback& exit_callback)
     : WelcomeScreen(view, exit_callback) {}
 
-void MockWelcomeScreen::ExitScreen() {
-  exit_callback()->Run(WelcomeScreen::Result::NEXT);
+void MockWelcomeScreen::ExitScreen(Result result) {
+  exit_callback()->Run(result);
 }
 
 MockWelcomeScreen::~MockWelcomeScreen() = default;
diff --git a/chrome/browser/chromeos/login/screens/mock_welcome_screen.h b/chrome/browser/chromeos/login/screens/mock_welcome_screen.h
index 650c31c..8ae3c9e5 100644
--- a/chrome/browser/chromeos/login/screens/mock_welcome_screen.h
+++ b/chrome/browser/chromeos/login/screens/mock_welcome_screen.h
@@ -23,7 +23,7 @@
   MOCK_METHOD(void, ShowImpl, ());
   MOCK_METHOD(void, HideImpl, ());
 
-  void ExitScreen();
+  void ExitScreen(Result result);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockWelcomeScreen);
diff --git a/chrome/browser/chromeos/login/screens/welcome_screen.cc b/chrome/browser/chromeos/login/screens/welcome_screen.cc
index 7ae9ddc0..929ac561 100644
--- a/chrome/browser/chromeos/login/screens/welcome_screen.cc
+++ b/chrome/browser/chromeos/login/screens/welcome_screen.cc
@@ -69,6 +69,7 @@
     "accessibility-virtual-keyboard-disable";
 constexpr const char kUserActionSetupDemoMode[] = "setupDemoMode";
 constexpr const char kUserActionSetupDemoModeGesture[] = "setupDemoModeGesture";
+constexpr const char kUserActionEnableDebugging[] = "enableDebugging";
 
 struct WelcomeScreenA11yUserAction {
   const char* name_;
@@ -140,6 +141,8 @@
       return "StartDemo";
     case Result::SETUP_DEMO:
       return "SetupDemo";
+    case Result::ENABLE_DEBUGGING:
+      return "EnableDebugging";
   }
 }
 
@@ -294,6 +297,14 @@
     OnUserAction(kUserActionContinueButtonClicked);
     return;
   }
+
+  // TODO(crbug.com/1105387): Part of initial screen logic.
+  PrefService* prefs = g_browser_process->local_state();
+  if (prefs->GetBoolean(prefs::kDebuggingFeaturesRequested)) {
+    OnEnableDebugging();
+    return;
+  }
+
   demo_mode_detector_ = std::make_unique<DemoModeDetector>(
       base::DefaultTickClock::GetInstance(), this);
   if (view_) {
@@ -316,6 +327,10 @@
     OnSetupDemoMode();
     return;
   }
+  if (action_id == kUserActionEnableDebugging) {
+    OnEnableDebugging();
+    return;
+  }
   if (action_id == kUserActionSetupDemoModeGesture) {
     HandleAccelerator(ash::LoginAcceleratorAction::kStartDemoMode);
     return;
@@ -379,6 +394,9 @@
   } else if (action == ash::LoginAcceleratorAction::kStartEnrollment) {
     context()->enrollment_triggered_early = true;
     return true;
+  } else if (action == ash::LoginAcceleratorAction::kEnableDebugging) {
+    OnEnableDebugging();
+    return true;
   }
   return false;
 }
@@ -414,6 +432,11 @@
   exit_callback_.Run(Result::SETUP_DEMO);
 }
 
+void WelcomeScreen::OnEnableDebugging() {
+  demo_mode_detector_.reset();
+  exit_callback_.Run(Result::ENABLE_DEBUGGING);
+}
+
 void WelcomeScreen::OnLanguageChangedCallback(
     const InputEventsBlocker* /* input_events_blocker */,
     const std::string& input_method,
diff --git a/chrome/browser/chromeos/login/screens/welcome_screen.h b/chrome/browser/chromeos/login/screens/welcome_screen.h
index be1a05aa..ad516af 100644
--- a/chrome/browser/chromeos/login/screens/welcome_screen.h
+++ b/chrome/browser/chromeos/login/screens/welcome_screen.h
@@ -63,7 +63,7 @@
     virtual void OnLanguageListReloaded() = 0;
   };
 
-  enum class Result { NEXT, START_DEMO, SETUP_DEMO };
+  enum class Result { NEXT, START_DEMO, SETUP_DEMO, ENABLE_DEBUGGING };
 
   using ScreenExitCallback = base::RepeatingCallback<void(Result result)>;
 
@@ -128,6 +128,8 @@
   void OnContinueButtonPressed();
   // Proceed with Demo mode setup.
   void OnSetupDemoMode();
+  // Proceed with Enable debugging features flow.
+  void OnEnableDebugging();
 
   // Async callback after ReloadResourceBundle(locale) completed.
   void OnLanguageChangedCallback(
diff --git a/chrome/browser/chromeos/login/ui/login_display.h b/chrome/browser/chromeos/login/ui/login_display.h
index ffad7de5..77a8648 100644
--- a/chrome/browser/chromeos/login/ui/login_display.h
+++ b/chrome/browser/chromeos/login/ui/login_display.h
@@ -43,9 +43,6 @@
     // Called when the user requests enterprise enrollment.
     virtual void OnStartEnterpriseEnrollment() = 0;
 
-    // Called when the user requests enable developer features screen.
-    virtual void OnStartEnableDebuggingScreen() = 0;
-
     // Called when the user requests kiosk enable screen.
     virtual void OnStartKioskEnableScreen() = 0;
 
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
index 7a8499d..f9623ff1 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -246,6 +246,7 @@
         prefs::kSigninScreenTimezone);
   }
 
+  // TODO(crbug.com/1105387): Part of initial screen logic.
   if (ShouldShowSigninScreen(first_screen)) {
     display_host->StartSignInScreen();
   } else {
@@ -269,6 +270,7 @@
   DCHECK(session_manager::SessionManager::Get());
   DCHECK(chromeos::LoginDisplayHost::default_host());
   WallpaperControllerClient::Get()->SetInitialWallpaper();
+  // TODO(crbug.com/1105387): Part of initial screen logic.
   MaybeShowDeviceDisabledScreen();
 }
 
diff --git a/chrome/browser/chromeos/login/ui/login_display_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_mojo.cc
index 888aed97..ff04a4d 100644
--- a/chrome/browser/chromeos/login/ui/login_display_mojo.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_mojo.cc
@@ -111,6 +111,7 @@
     if (filtered_users.empty())
       return;
 
+    // TODO(crbug.com/1105387): Part of initial screen logic.
     // Check whether factory reset or debugging feature have been requested in
     // prior session, and start reset or enable debugging wizard as needed.
     // This has to happen after login-prompt-visible, as some reset dialog
@@ -228,10 +229,6 @@
   NOTIMPLEMENTED();
 }
 
-void LoginDisplayMojo::ShowEnableDebuggingScreen() {
-  NOTIMPLEMENTED();
-}
-
 void LoginDisplayMojo::ShowKioskEnableScreen() {
   NOTIMPLEMENTED();
 }
diff --git a/chrome/browser/chromeos/login/ui/login_display_mojo.h b/chrome/browser/chromeos/login/ui/login_display_mojo.h
index 0a8a5cd..4a47ba2f 100644
--- a/chrome/browser/chromeos/login/ui/login_display_mojo.h
+++ b/chrome/browser/chromeos/login/ui/login_display_mojo.h
@@ -53,7 +53,6 @@
   bool IsSigninInProgress() const override;
   void OnSigninScreenReady() override;
   void ShowEnterpriseEnrollmentScreen() override;
-  void ShowEnableDebuggingScreen() override;
   void ShowKioskEnableScreen() override;
   void ShowKioskAutolaunchScreen() override;
   void ShowWrongHWIDScreen() override;
diff --git a/chrome/browser/chromeos/login/ui/login_display_webui.cc b/chrome/browser/chromeos/login/ui/login_display_webui.cc
index 64f4e39..a91d17a4 100644
--- a/chrome/browser/chromeos/login/ui/login_display_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_webui.cc
@@ -210,11 +210,6 @@
     delegate_->OnStartEnterpriseEnrollment();
 }
 
-void LoginDisplayWebUI::ShowEnableDebuggingScreen() {
-  if (delegate_)
-    delegate_->OnStartEnableDebuggingScreen();
-}
-
 void LoginDisplayWebUI::ShowKioskEnableScreen() {
   if (delegate_)
     delegate_->OnStartKioskEnableScreen();
diff --git a/chrome/browser/chromeos/login/ui/login_display_webui.h b/chrome/browser/chromeos/login/ui/login_display_webui.h
index 5c137a8..48603c0 100644
--- a/chrome/browser/chromeos/login/ui/login_display_webui.h
+++ b/chrome/browser/chromeos/login/ui/login_display_webui.h
@@ -54,7 +54,6 @@
   void OnSigninScreenReady() override;
   void CancelUserAdding() override;
   void ShowEnterpriseEnrollmentScreen() override;
-  void ShowEnableDebuggingScreen() override;
   void ShowKioskEnableScreen() override;
   void ShowKioskAutolaunchScreen() override;
   void ShowWrongHWIDScreen() override;
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 1e44f80..5d64af6 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -848,16 +848,20 @@
 void WizardController::OnWelcomeScreenExit(WelcomeScreen::Result result) {
   OnScreenExit(WelcomeView::kScreenId, WelcomeScreen::GetResultString(result));
 
-  if (result == WelcomeScreen::Result::START_DEMO) {
-    LoginDisplayHost::default_host()->StartDemoAppLaunch();
-    return;
+  switch (result) {
+    case WelcomeScreen::Result::START_DEMO:
+      LoginDisplayHost::default_host()->StartDemoAppLaunch();
+      return;
+    case WelcomeScreen::Result::SETUP_DEMO:
+      StartDemoModeSetup();
+      return;
+    case WelcomeScreen::Result::ENABLE_DEBUGGING:
+      ShowEnableDebuggingScreen();
+      return;
+    case WelcomeScreen::Result::NEXT:
+      ShowNetworkScreen();
+      return;
   }
-  if (result == WelcomeScreen::Result::SETUP_DEMO) {
-    StartDemoModeSetup();
-    return;
-  }
-
-  ShowNetworkScreen();
 }
 
 void WizardController::OnNetworkScreenExit(NetworkScreen::Result result) {
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index c8f27b6..5bd0f415 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -696,7 +696,7 @@
     EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
     EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
     EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-    mock_welcome_screen_->ExitScreen();
+    mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
     CheckCurrentScreen(NetworkScreenView::kScreenId);
     EXPECT_CALL(*mock_network_screen_, HideImpl()).Times(1);
@@ -804,7 +804,7 @@
   EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(0);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -842,7 +842,7 @@
   EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(0);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -873,7 +873,7 @@
   EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(0);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -912,7 +912,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -1010,7 +1010,7 @@
   EXPECT_CALL(*mock_update_screen_, ShowImpl()).Times(0);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
 
@@ -1143,7 +1143,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -1187,7 +1187,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -1278,7 +1278,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -1370,7 +1370,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -1500,7 +1500,7 @@
     CheckCurrentScreen(WelcomeView::kScreenId);
     EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
     EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-    mock_welcome_screen_->ExitScreen();
+    mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
     CheckCurrentScreen(NetworkScreenView::kScreenId);
     EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -1601,7 +1601,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -1694,7 +1694,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -1737,7 +1737,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -1792,7 +1792,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -1847,7 +1847,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -2132,7 +2132,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -2179,7 +2179,7 @@
   CheckCurrentScreen(WelcomeView::kScreenId);
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_network_screen_, ShowImpl()).Times(1);
-  mock_welcome_screen_->ExitScreen();
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::NEXT);
 
   CheckCurrentScreen(NetworkScreenView::kScreenId);
   EXPECT_CALL(*mock_eula_screen_, ShowImpl()).Times(1);
@@ -2306,10 +2306,7 @@
   EXPECT_CALL(*mock_welcome_screen_, HideImpl()).Times(1);
   EXPECT_CALL(*mock_enable_debugging_screen_, ShowImpl()).Times(1);
 
-  // Find the enable debugging link element (in the appropriate shadow root),
-  // and click it.
-  test::OobeJS().ClickOnPath(
-      {"connect", "welcomeScreen", "enableDebuggingLink"});
+  mock_welcome_screen_->ExitScreen(WelcomeScreen::Result::ENABLE_DEBUGGING);
 
   content::RunAllPendingInMessageLoop();
 
diff --git a/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.cc b/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.cc
new file mode 100644
index 0000000..ecb7adb
--- /dev/null
+++ b/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.cc
@@ -0,0 +1,17 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.h"
+#include "ui/base/clipboard/clipboard.h"
+
+namespace chromeos {
+
+bool EnterpriseClipboardDlpController::IsDataReadAllowed(
+    const ui::ClipboardDataEndpoint* const data_src,
+    const ui::ClipboardDataEndpoint* const data_dst) const {
+  // TODO(crbug.com/1102332): all the policy logic should be added later.
+  return true;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.h b/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.h
new file mode 100644
index 0000000..afc4cd5
--- /dev/null
+++ b/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.h
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_DLP_ENTERPRISE_CLIPBOARD_DLP_CONTROLLER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_DLP_ENTERPRISE_CLIPBOARD_DLP_CONTROLLER_H_
+
+#include "ui/base/clipboard/clipboard_data_endpoint.h"
+#include "ui/base/clipboard/clipboard_dlp_controller.h"
+
+namespace chromeos {
+
+// EnterpriseClipboardDlpController is responsible for preventing leaks of
+// confidential clipboard data by controlling read operations according to the
+// policy rules set by the admin.
+class EnterpriseClipboardDlpController : public ui::ClipboardDlpController {
+ public:
+  EnterpriseClipboardDlpController() = default;
+  ~EnterpriseClipboardDlpController() override = default;
+
+  EnterpriseClipboardDlpController(const EnterpriseClipboardDlpController&) =
+      delete;
+  void operator=(const EnterpriseClipboardDlpController&) = delete;
+
+  // nullptr can be passed instead of |data_src| or |data_dst|.
+  bool IsDataReadAllowed(
+      const ui::ClipboardDataEndpoint* const data_src,
+      const ui::ClipboardDataEndpoint* const data_dst) const override;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DLP_ENTERPRISE_CLIPBOARD_DLP_CONTROLLER_H_
diff --git a/chrome/browser/chromeos/release_notes/release_notes_notification.cc b/chrome/browser/chromeos/release_notes/release_notes_notification.cc
index 5e4cb0b0c..e63682c2 100644
--- a/chrome/browser/chromeos/release_notes/release_notes_notification.cc
+++ b/chrome/browser/chromeos/release_notes/release_notes_notification.cc
@@ -19,6 +19,7 @@
 #include "chromeos/constants/chromeos_features.h"
 #include "content/public/browser/notification_service.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/chromeos/devicetype_utils.h"
 #include "ui/message_center/public/cpp/notification_delegate.h"
 
 using message_center::Notification;
@@ -51,8 +52,8 @@
 }
 
 void ReleaseNotesNotification::ShowReleaseNotesNotification() {
-  base::string16 title =
-      l10n_util::GetStringUTF16(IDS_RELEASE_NOTES_NOTIFICATION_TITLE);
+  base::string16 title = ui::SubstituteChromeOSDeviceType(
+      IDS_RELEASE_NOTES_DEVICE_SPECIFIC_NOTIFICATION_TITLE);
   base::string16 message =
       l10n_util::GetStringUTF16(IDS_RELEASE_NOTES_NOTIFICATION_MESSAGE);
 
diff --git a/chrome/browser/chromeos/release_notes/release_notes_notification_unittest.cc b/chrome/browser/chromeos/release_notes/release_notes_notification_unittest.cc
index 2291dc99..a0223b8 100644
--- a/chrome/browser/chromeos/release_notes/release_notes_notification_unittest.cc
+++ b/chrome/browser/chromeos/release_notes/release_notes_notification_unittest.cc
@@ -16,6 +16,7 @@
 #include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "components/prefs/testing_pref_service.h"
+#include "ui/chromeos/devicetype_utils.h"
 
 namespace chromeos {
 
@@ -57,6 +58,10 @@
         .has_value();
   }
 
+  message_center::Notification GetReleaseNotesNotification() {
+    return tester_->GetNotification("show_release_notes_notification").value();
+  }
+
   int notification_count_ = 0;
   std::unique_ptr<ReleaseNotesNotification> release_notes_notification_;
 
@@ -79,6 +84,9 @@
   profile()->GetPrefs()->SetInteger(prefs::kReleaseNotesLastShownMilestone, -1);
   release_notes_notification_->MaybeShowReleaseNotes();
   EXPECT_EQ(true, HasReleaseNotesNotification());
+  EXPECT_EQ(ui::SubstituteChromeOSDeviceType(
+                IDS_RELEASE_NOTES_DEVICE_SPECIFIC_NOTIFICATION_TITLE),
+            GetReleaseNotesNotification().title());
   EXPECT_EQ(1, notification_count_);
 }
 
diff --git a/chrome/browser/crash_recovery_browsertest.cc b/chrome/browser/crash_recovery_browsertest.cc
index a50b66cf..1e014d7 100644
--- a/chrome/browser/crash_recovery_browsertest.cc
+++ b/chrome/browser/crash_recovery_browsertest.cc
@@ -140,8 +140,8 @@
   // Use the test server so as not to bypass cache behavior. The title of the
   // active tab should change only when this URL is reloaded.
   embedded_test_server()->RegisterRequestHandler(
-      base::Bind(&CacheMaxAgeHandler::HandleRequest,
-                 base::Owned(new CacheMaxAgeHandler(kTestPath))));
+      base::BindRepeating(&CacheMaxAgeHandler::HandleRequest,
+                          base::Owned(new CacheMaxAgeHandler(kTestPath))));
   ASSERT_TRUE(embedded_test_server()->Start());
   ui_test_utils::NavigateToURL(browser(),
                                embedded_test_server()->GetURL(kTestPath));
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc
index 7a1b3dc..d2f8133 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.cc
@@ -248,18 +248,6 @@
                                                             this);
 }
 
-void DataReductionProxyChromeSettings::SetIgnoreLongTermBlockListRules(
-    bool ignore_long_term_block_list_rules) {
-  // |previews_service| is null if |profile_| is off the record.
-  PreviewsService* previews_service =
-      PreviewsServiceFactory::GetForProfile(profile_);
-  if (previews_service && previews_service->previews_ui_service()) {
-    previews_service->previews_ui_service()
-        ->SetIgnoreLongTermBlockListForServerPreviews(
-            ignore_long_term_block_list_rules);
-  }
-}
-
 std::unique_ptr<data_reduction_proxy::DataReductionProxyData>
 DataReductionProxyChromeSettings::CreateDataFromNavigationHandle(
     content::NavigationHandle* handle,
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h
index 7dc844da..e550b2bc1 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h
@@ -75,9 +75,6 @@
   // Public for testing.
   void MigrateDataReductionProxyOffProxyPrefs(PrefService* prefs);
 
-  void SetIgnoreLongTermBlockListRules(
-      bool ignore_long_term_block_list_rules) override;
-
   // Builds an instance of DataReductionProxyData from the given |handle| and
   // |headers|.
   std::unique_ptr<data_reduction_proxy::DataReductionProxyData>
diff --git a/chrome/browser/devtools/device/android_web_socket.cc b/chrome/browser/devtools/device/android_web_socket.cc
index a3ba3c2..802104c 100644
--- a/chrome/browser/devtools/device/android_web_socket.cc
+++ b/chrome/browser/devtools/device/android_web_socket.cc
@@ -10,6 +10,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/rand_util.h"
 #include "base/single_thread_task_runner.h"
+#include "base/threading/thread_checker.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/devtools/device/android_device_manager.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/download/android/download_manager_service.cc b/chrome/browser/download/android/download_manager_service.cc
index cf79ed0..5ea015b 100644
--- a/chrome/browser/download/android/download_manager_service.cc
+++ b/chrome/browser/download/android/download_manager_service.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_clock.h"
@@ -203,10 +204,7 @@
     : action(other.action), has_user_gesture(other.has_user_gesture) {}
 
 DownloadManagerService::DownloadManagerService()
-    : is_manager_initialized_(false),
-      is_pending_downloads_loaded_(false),
-      original_coordinator_(nullptr),
-      off_the_record_coordinator_(nullptr) {}
+    : is_manager_initialized_(false), is_pending_downloads_loaded_(false) {}
 
 DownloadManagerService::~DownloadManagerService() {}
 
@@ -454,10 +452,12 @@
 
 void DownloadManagerService::OnManagerGoingDown(
     download::SimpleDownloadManagerCoordinator* coordinator) {
-  if (original_coordinator_ == coordinator)
-    original_coordinator_ = nullptr;
-  else if (off_the_record_coordinator_ == coordinator)
-    off_the_record_coordinator_ = nullptr;
+  for (auto it = coordinators_.begin(); it != coordinators_.end(); it++) {
+    if (it->second == coordinator) {
+      coordinators_.erase(it->first);
+      break;
+    }
+  }
 }
 
 void DownloadManagerService::OnDownloadCreated(
@@ -673,22 +673,21 @@
 void DownloadManagerService::OnPendingDownloadsLoaded() {
   is_pending_downloads_loaded_ = true;
 
+  ProfileKey* profile_key = use_existing_profile_key_for_testing_
+                                ? coordinators_.begin()->first
+                                : ProfileManager::GetActiveUserProfile()
+                                      ->GetOriginalProfile()
+                                      ->GetProfileKey();
+
   // Kick-off the auto-resumption handler.
   content::DownloadManager::DownloadVector all_items;
-  original_coordinator_->GetAllDownloads(&all_items);
+  GetCoordinator(profile_key)->GetAllDownloads(&all_items);
 
   if (!download::AutoResumptionHandler::Get())
     CreateAutoResumptionHandler();
 
   download::AutoResumptionHandler::Get()->SetResumableDownloads(all_items);
 
-  ProfileKey* profile_key =
-      use_startup_accessor_profile_key_for_testing_
-          ? ProfileKeyStartupAccessor::GetInstance()->profile_key()
-          : ProfileManager::GetActiveUserProfile()
-                ->GetOriginalProfile()
-                ->GetProfileKey();
-
   for (auto iter = pending_actions_.begin(); iter != pending_actions_.end();
        ++iter) {
     DownloadActionParams params = iter->second;
@@ -727,31 +726,25 @@
 void DownloadManagerService::ResetCoordinatorIfNeeded(ProfileKey* profile_key) {
   download::SimpleDownloadManagerCoordinator* coordinator =
       SimpleDownloadManagerCoordinatorFactory::GetForKey(profile_key);
-  UpdateCoordinator(coordinator, profile_key->IsOffTheRecord());
+  UpdateCoordinator(coordinator, profile_key);
 }
 
 void DownloadManagerService::UpdateCoordinator(
     download::SimpleDownloadManagerCoordinator* new_coordinator,
-    bool is_off_the_record) {
-  // TODO(https://crbug.com/1099577): Update to have separate coordinators per
-  // OTR profile.
-  auto*& coordinator =
-      is_off_the_record ? off_the_record_coordinator_ : original_coordinator_;
-  if (!coordinator || coordinator != new_coordinator) {
-    if (coordinator)
-      coordinator->GetNotifier()->RemoveObserver(this);
-    coordinator = new_coordinator;
-    coordinator->GetNotifier()->AddObserver(this);
+    ProfileKey* profile_key) {
+  bool coordinator_exists = base::Contains(coordinators_, profile_key);
+  if (!coordinator_exists || coordinators_[profile_key] != new_coordinator) {
+    if (coordinator_exists)
+      coordinators_[profile_key]->GetNotifier()->RemoveObserver(this);
+    coordinators_[profile_key] = new_coordinator;
+    new_coordinator->GetNotifier()->AddObserver(this);
   }
 }
 
 download::SimpleDownloadManagerCoordinator*
 DownloadManagerService::GetCoordinator(ProfileKey* profile_key) {
-  // TODO(https://crbug.com/1099577): Update to have separate coordinators per
-  // OTR profile.
-  bool use_original = use_startup_accessor_profile_key_for_testing_ ||
-                      !profile_key->IsOffTheRecord();
-  return use_original ? original_coordinator_ : off_the_record_coordinator_;
+  DCHECK(base::Contains(coordinators_, profile_key));
+  return coordinators_[profile_key];
 }
 
 void DownloadManagerService::RenameDownload(
@@ -817,7 +810,7 @@
   download::InProgressDownloadManager* in_progress_manager =
       DownloadManagerUtils::GetInProgressDownloadManager(
           ProfileKeyStartupAccessor::GetInstance()->profile_key());
-  UseStartupProfileKeyForTesting();
+  UseExistingProfileKeyForTesting();
   std::vector<GURL> url_chain;
   url_chain.emplace_back(ConvertJavaStringToUTF8(env, jurl));
   base::FilePath target_path(ConvertJavaStringToUTF8(env, jtarget_path));
diff --git a/chrome/browser/download/android/download_manager_service.h b/chrome/browser/download/android/download_manager_service.h
index 2986b30..a1a491d 100644
--- a/chrome/browser/download/android/download_manager_service.h
+++ b/chrome/browser/download/android/download_manager_service.h
@@ -201,8 +201,8 @@
       const JavaParamRef<jstring>& jdownload_guid,
       jboolean download_started);
 
-  void UseStartupProfileKeyForTesting() {
-    use_startup_accessor_profile_key_for_testing_ = true;
+  void UseExistingProfileKeyForTesting() {
+    use_existing_profile_key_for_testing_ = true;
   }
 
  private:
@@ -255,7 +255,7 @@
   // profile type.
   void UpdateCoordinator(
       download::SimpleDownloadManagerCoordinator* coordinator,
-      bool is_off_the_record);
+      ProfileKey* profile_key);
 
   // Called to get the content::DownloadManager instance.
   content::DownloadManager* GetDownloadManager(ProfileKey* profile_key);
@@ -298,10 +298,10 @@
 
   ScopedObserver<Profile, ProfileObserver> observed_profiles_{this};
 
-  bool use_startup_accessor_profile_key_for_testing_{false};
+  bool use_existing_profile_key_for_testing_{false};
 
-  download::SimpleDownloadManagerCoordinator* original_coordinator_;
-  download::SimpleDownloadManagerCoordinator* off_the_record_coordinator_;
+  std::map<ProfileKey*, download::SimpleDownloadManagerCoordinator*>
+      coordinators_;
 
   DISALLOW_COPY_AND_ASSIGN(DownloadManagerService);
 };
diff --git a/chrome/browser/download/android/download_manager_service_unittest.cc b/chrome/browser/download/android/download_manager_service_unittest.cc
index 1d585dfe..4f68abcc 100644
--- a/chrome/browser/download/android/download_manager_service_unittest.cc
+++ b/chrome/browser/download/android/download_manager_service_unittest.cc
@@ -36,8 +36,8 @@
         .WillByDefault(::testing::Invoke(
             this, &DownloadManagerServiceTest::GetDownloadByGuid));
     coordinator_.SetSimpleDownloadManager(&manager_, false);
-    service_->UpdateCoordinator(&coordinator_, false);
-    service_->UseStartupProfileKeyForTesting();
+    service_->UpdateCoordinator(&coordinator_, profile_.GetProfileKey());
+    service_->UseExistingProfileKeyForTesting();
   }
 
   void OnResumptionDone(bool success) {
diff --git a/chrome/browser/extensions/api/BUILD.gn b/chrome/browser/extensions/api/BUILD.gn
index 82da612..0747838 100644
--- a/chrome/browser/extensions/api/BUILD.gn
+++ b/chrome/browser/extensions/api/BUILD.gn
@@ -20,6 +20,11 @@
   schema_include_rules = chrome_extensions_api_schema_include_rules
 
   deps = [
+    # This is not directly included by the target, but specified here
+    # to avoid cyclic dependency chain related to private_membership
+    # protos.
+    "//components/policy/proto",
+
     # Different APIs include headers from these targets.
     "//chrome/common:mojo_bindings",
     "//components/zoom",
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc b/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc
index ea1e6819..26f9c18d7 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc
+++ b/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc
@@ -314,9 +314,14 @@
     if (installation.manifest_invalid_error) {
       DCHECK_EQ(failure_reason,
                 InstallStageTracker::FailureReason::MANIFEST_INVALID);
-      UMA_HISTOGRAM_ENUMERATION(
-          "Extensions.ForceInstalledFailureManifestInvalidErrorDetail",
+      base::UmaHistogramEnumeration(
+          "Extensions.ForceInstalledFailureManifestInvalidErrorDetail2",
           installation.manifest_invalid_error.value());
+      if (installation.app_status_error) {
+        base::UmaHistogramEnumeration(
+            "Extensions.ForceInstalledFailureManifestInvalidAppStatusError",
+            installation.app_status_error.value());
+      }
     }
   }
   bool non_misconfigured_failure_occurred =
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc b/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
index db8f35b..3c83731 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
+++ b/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
@@ -101,9 +101,11 @@
     "Extensions.ForceInstalledNotLoadedDisableReason";
 constexpr char kBlocklisted[] = "Extensions.ForceInstalledAndBlackListed";
 constexpr char kExtensionManifestInvalid[] =
-    "Extensions.ForceInstalledFailureManifestInvalidErrorDetail";
+    "Extensions.ForceInstalledFailureManifestInvalidErrorDetail2";
 constexpr char kManifestNoUpdatesInfo[] =
     "Extensions.ForceInstalledFailureNoUpdatesInfo";
+constexpr char kExtensionManifestInvalidAppStatusError[] =
+    "Extensions.ForceInstalledFailureManifestInvalidAppStatusError";
 }  // namespace
 
 namespace extensions {
@@ -728,7 +730,9 @@
       ExtensionBuilder(kExtensionName1).SetID(kExtensionId1).Build();
   tracker_->OnExtensionLoaded(profile_, extension.get());
   install_stage_tracker_->ReportManifestInvalidFailure(
-      kExtensionId2, ManifestInvalidError::INVALID_PROTOCOL_ON_GUPDATE_TAG);
+      kExtensionId2,
+      ExtensionDownloaderDelegate::FailureData(
+          ManifestInvalidError::INVALID_PROTOCOL_ON_GUPDATE_TAG));
   // ForceInstalledMetrics shuts down timer because all extension are either
   // loaded or failed.
   EXPECT_FALSE(fake_timer_->IsRunning());
@@ -737,6 +741,27 @@
       ManifestInvalidError::INVALID_PROTOCOL_ON_GUPDATE_TAG, 1);
 }
 
+// Errors occurred because the fetched update manifest was invalid because app
+// status was not OK.
+TEST_F(ForceInstalledMetricsTest, ExtensionManifestInvalidAppStatusError) {
+  SetupForceList();
+  auto extension =
+      ExtensionBuilder(kExtensionName1).SetID(kExtensionId1).Build();
+  tracker_->OnExtensionLoaded(profile_, extension.get());
+  install_stage_tracker_->ReportManifestInvalidFailure(
+      kExtensionId2,
+      ExtensionDownloaderDelegate::FailureData(
+          ManifestInvalidError::BAD_APP_STATUS, "error-unknownApplication"));
+  // ForceInstalledMetrics shuts down timer because all extension are either
+  // loaded or failed.
+  EXPECT_FALSE(fake_timer_->IsRunning());
+  histogram_tester_.ExpectUniqueSample(kExtensionManifestInvalid,
+                                       ManifestInvalidError::BAD_APP_STATUS, 1);
+  histogram_tester_.ExpectUniqueSample(
+      kExtensionManifestInvalidAppStatusError,
+      InstallStageTracker::AppStatusError::kErrorUnknownApplication, 1);
+}
+
 // Session in which either all the extensions installed successfully, or all
 // failures are admin-side misconfigurations. This test verifies that failure
 // CRX_INSTALL_ERROR with detailed error KIOSK_MODE_ONLY is considered as
diff --git a/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc b/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
index 5a3757d6..39918b2 100644
--- a/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
+++ b/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
@@ -72,6 +72,10 @@
     str << "; no_update_info: "
         << static_cast<int>(data.no_updates_info.value());
   }
+  if (data.app_status_error) {
+    str << "; app_status_error: "
+        << static_cast<int>(data.app_status_error.value());
+  }
 
   return str.str();
 }
@@ -113,10 +117,15 @@
 
 void InstallStageTracker::ReportManifestInvalidFailure(
     const ExtensionId& id,
-    ManifestInvalidError error) {
+    const ExtensionDownloaderDelegate::FailureData& failure_data) {
+  DCHECK(failure_data.manifest_invalid_error);
   InstallationData& data = installation_data_map_[id];
   data.failure_reason = FailureReason::MANIFEST_INVALID;
-  data.manifest_invalid_error = error;
+  data.manifest_invalid_error = failure_data.manifest_invalid_error.value();
+  if (failure_data.app_status_error) {
+    data.app_status_error =
+        GetManifestInvalidAppStatusError(failure_data.app_status_error.value());
+  }
   NotifyObserversOfFailure(id, data.failure_reason.value(), data);
 }
 
@@ -179,6 +188,18 @@
   }
 }
 
+InstallStageTracker::AppStatusError
+InstallStageTracker::GetManifestInvalidAppStatusError(
+    const std::string& status) {
+  if (status == "error-unknownApplication")
+    return AppStatusError::kErrorUnknownApplication;
+  else if (status == "error-invalidAppId")
+    return AppStatusError::kErrorInvalidAppId;
+  else if (status == "error-restricted" || status == "restricted")
+    return AppStatusError::kErrorRestricted;
+  return AppStatusError::kUnknown;
+}
+
 void InstallStageTracker::ReportFetchError(
     const ExtensionId& id,
     FailureReason reason,
diff --git a/chrome/browser/extensions/forced_extensions/install_stage_tracker.h b/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
index c4cc646..630456d 100644
--- a/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
+++ b/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
@@ -208,6 +208,30 @@
     kMaxValue = kErrorUnsupportedProtocol,
   };
 
+  // Status for the app returned by server while fetching manifest when status
+  // was not OK. Enum used for UMA. Do NOT reorder or remove entries. Don't
+  // forget to update enums.xml (name: ManifestInvalidAppStatusError) when
+  // adding new entries.
+  enum class AppStatusError {
+    // Technically it may happen that update server return some unknown value or
+    // no value.
+    kUnknown = 0,
+
+    // The appid was not recognized and no action elements are included.
+    kErrorUnknownApplication = 1,
+
+    // The appid is not properly formed; no action elements are included.
+    kErrorInvalidAppId = 2,
+
+    // The application is not available to this user (usually based on country
+    // export restrictions).
+    kErrorRestricted = 3,
+
+    // Magic constant used by the histogram macros.
+    // Always update it to the max value.
+    kMaxValue = kErrorRestricted,
+  };
+
   // Info field in the update manifest returned by the server when no update is
   // available. Enum used for UMA. Do NOT reorder or remove entries. Don't
   // forget to update enums.xml (name: ExtensionNoUpdatesInfo) when adding new
@@ -263,6 +287,9 @@
     // Info field in the update manifest returned by the server when no update
     // is available.
     base::Optional<NoUpdatesInfo> no_updates_info;
+    // Type of app status error received from update server when manifest was
+    // fetched.
+    base::Optional<AppStatusError> app_status_error;
   };
 
   class Observer : public base::CheckedObserver {
@@ -302,8 +329,9 @@
   // Reports detailed error type when extension fails to install with failure
   // reason MANIFEST_INVALID. See InstallationData::manifest_invalid_error
   // for more details.
-  void ReportManifestInvalidFailure(const ExtensionId& id,
-                                    ManifestInvalidError error);
+  void ReportManifestInvalidFailure(
+      const ExtensionId& id,
+      const ExtensionDownloaderDelegate::FailureData& failure_data);
 
   // Remembers failure reason and in-progress stages in memory.
   void ReportInstallationStage(const ExtensionId& id, Stage stage);
@@ -343,6 +371,9 @@
   void RemoveObserver(Observer* observer);
 
  private:
+  // Helper function that maps the current app status to AppStatusError enum.
+  AppStatusError GetManifestInvalidAppStatusError(const std::string& status);
+
   // Helper function to report installation failures to the observers.
   void NotifyObserversOfFailure(const ExtensionId& id,
                                 FailureReason reason,
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc
index b1b3efa..d9544c3e 100644
--- a/chrome/browser/extensions/updater/extension_updater.cc
+++ b/chrome/browser/extensions/updater/extension_updater.cc
@@ -476,8 +476,7 @@
       break;
     case Error::MANIFEST_INVALID:
       DCHECK(data.manifest_invalid_error);
-      install_stage_tracker->ReportManifestInvalidFailure(
-          id, data.manifest_invalid_error.value());
+      install_stage_tracker->ReportManifestInvalidFailure(id, data);
       break;
     case Error::NO_UPDATE_AVAILABLE:
       install_stage_tracker->ReportFailure(
diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc
index 3e6d3f6b..89ec814f 100644
--- a/chrome/browser/extensions/updater/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc
@@ -908,7 +908,7 @@
     UpdateManifestResults updates;
     std::vector<UpdateManifestResult*> updateable;
     std::set<std::string> not_updateable;
-    ManifestInvalidErrorList errors;
+    ManifestInvalidFailureDataList errors;
     helper.downloader().DetermineUpdates(*fetch_data, updates, &updateable,
                                          &not_updateable, &errors);
     EXPECT_TRUE(updateable.empty());
@@ -1023,7 +1023,7 @@
 
     std::vector<UpdateManifestResult*> updateable;
     std::set<std::string> not_updateable;
-    ManifestInvalidErrorList errors;
+    ManifestInvalidFailureDataList errors;
     helper.downloader().DetermineUpdates(*fetch_data, updates, &updateable,
                                          &not_updateable, &errors);
     EXPECT_THAT(not_updateable, testing::UnorderedElementsAre(id2, id3));
@@ -1031,7 +1031,8 @@
     for (const auto& id : ids_with_error) {
       auto it = std::find_if(
           errors.begin(), errors.end(),
-          [&](const std::pair<ExtensionId, ManifestInvalidError>& error) {
+          [&](const std::pair<
+              ExtensionId, ExtensionDownloaderDelegate::FailureData>& error) {
             return error.first == id;
           });
       EXPECT_TRUE(it != errors.end());
@@ -1073,7 +1074,7 @@
 
     std::vector<UpdateManifestResult*> updateable;
     std::set<std::string> not_updateable;
-    ManifestInvalidErrorList errors;
+    ManifestInvalidFailureDataList errors;
     helper.downloader().DetermineUpdates(*fetch_data, updates, &updateable,
                                          &not_updateable, &errors);
     // All the apps should be updateable.
@@ -1155,7 +1156,7 @@
 
     std::vector<UpdateManifestResult*> updateable;
     std::set<std::string> not_updateable;
-    ManifestInvalidErrorList errors;
+    ManifestInvalidFailureDataList errors;
     helper.downloader().DetermineUpdates(*fetch_data, updates, &updateable,
                                          &not_updateable, &errors);
     EXPECT_THAT(not_updateable, testing::UnorderedElementsAre(id1, id4));
@@ -1163,7 +1164,8 @@
     for (const auto& id : ids_with_error) {
       auto it = std::find_if(
           errors.begin(), errors.end(),
-          [&](const std::pair<ExtensionId, ManifestInvalidError>& error) {
+          [&](const std::pair<
+              ExtensionId, ExtensionDownloaderDelegate::FailureData>& error) {
             return error.first == id;
           });
       EXPECT_TRUE(it != errors.end());
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc
index 964ab99d..4f5c39b 100644
--- a/chrome/browser/file_select_helper.cc
+++ b/chrome/browser/file_select_helper.cc
@@ -120,9 +120,9 @@
   return false;
 }
 
-void InterpretSafeBrowsingVerdict(const base::Callback<void(bool)>& recipient,
+void InterpretSafeBrowsingVerdict(base::OnceCallback<void(bool)> recipient,
                                   safe_browsing::DownloadCheckResult result) {
-  recipient.Run(IsDownloadAllowedBySafeBrowsing(result));
+  std::move(recipient).Run(IsDownloadAllowedBySafeBrowsing(result));
 }
 
 #endif
@@ -634,8 +634,8 @@
       alternate_extensions, profile_,
       base::BindOnce(
           &InterpretSafeBrowsingVerdict,
-          base::Bind(&FileSelectHelper::ProceedWithSafeBrowsingVerdict, this,
-                     default_file_path, base::Passed(&params))));
+          base::BindOnce(&FileSelectHelper::ProceedWithSafeBrowsingVerdict,
+                         this, default_file_path, base::Passed(&params))));
 #endif
 }
 
diff --git a/chrome/browser/font_family_cache.cc b/chrome/browser/font_family_cache.cc
index 915d07c83..41b3c73 100644
--- a/chrome/browser/font_family_cache.cc
+++ b/chrome/browser/font_family_cache.cc
@@ -25,7 +25,8 @@
     : prefs_(profile->GetPrefs()) {
   font_change_registrar_.Register(
       FontPrefChangeNotifierFactory::GetForProfile(profile),
-      base::Bind(&FontFamilyCache::OnPrefsChanged, base::Unretained(this)));
+      base::BindRepeating(&FontFamilyCache::OnPrefsChanged,
+                          base::Unretained(this)));
 }
 
 FontFamilyCache::~FontFamilyCache() = default;
diff --git a/chrome/browser/metrics/antivirus_metrics_provider_win_unittest.cc b/chrome/browser/metrics/antivirus_metrics_provider_win_unittest.cc
index d75097e..b6dc38e31 100644
--- a/chrome/browser/metrics/antivirus_metrics_provider_win_unittest.cc
+++ b/chrome/browser/metrics/antivirus_metrics_provider_win_unittest.cc
@@ -115,7 +115,8 @@
   DISALLOW_COPY_AND_ASSIGN(AntiVirusMetricsProviderTest);
 };
 
-TEST_P(AntiVirusMetricsProviderTest, GetMetricsFullName) {
+// TODO(crbug.com/682286): Flaky on Windows 10.
+TEST_P(AntiVirusMetricsProviderTest, DISABLED_GetMetricsFullName) {
   base::ScopedAllowBlockingForTesting scoped_allow_blocking_;
 
   ASSERT_TRUE(thread_checker_.CalledOnValidThread());
diff --git a/chrome/browser/offline_pages/offline_page_request_handler.cc b/chrome/browser/offline_pages/offline_page_request_handler.cc
index 5cea9d2b..4076be16 100644
--- a/chrome/browser/offline_pages/offline_page_request_handler.cc
+++ b/chrome/browser/offline_pages/offline_page_request_handler.cc
@@ -30,7 +30,6 @@
 #include "components/offline_pages/core/offline_clock.h"
 #include "components/offline_pages/core/offline_page_model.h"
 #include "components/offline_pages/core/request_header/offline_page_header.h"
-#include "components/previews/core/previews_experiments.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
@@ -496,13 +495,6 @@
         FORCE_OFFLINE_ON_CONNECTED_NETWORK;
   }
 
-  // Checks if previews are allowed, the network is slow, and the request is
-  // allowed to be shown for previews. When reloading from an offline page or
-  // through other force checks, previews should not be considered; previews
-  // eligiblity is only checked when |offline_header.reason| is Reason::NONE.
-  if (delegate_->ShouldAllowPreview())
-    return OfflinePageRequestHandler::NetworkState::PROHIBITIVELY_SLOW_NETWORK;
-
   // Otherwise, the network state is a good network.
   return OfflinePageRequestHandler::NetworkState::CONNECTED_NETWORK;
 }
@@ -592,16 +584,6 @@
     return;
   }
 
-  // If the page is being loaded on a slow network, only use the offline page
-  // if it was created within the past day.
-  if (network_state_ == NetworkState::PROHIBITIVELY_SLOW_NETWORK &&
-      OfflineTimeNow() - GetCurrentOfflinePage().creation_time >
-          previews::params::OfflinePreviewFreshnessDuration()) {
-    ReportRequestResult(RequestResult::PAGE_NOT_FRESH, network_state_);
-    delegate_->FallbackToDefault();
-    return;
-  }
-
   // No need to open the file if it has already been opened for the validation.
   if (stream_) {
     DidOpenForServing(net::OK);
diff --git a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
index 7a644d20..df32e859e 100644
--- a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
+++ b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
@@ -397,16 +397,10 @@
 
   bool is_connected_with_good_network() {
     return network_change_notifier_->online() &&
-           // Exclude prohibitively slow network.
-           !allow_preview() &&
            // Exclude flaky network.
            offline_page_header_.reason != OfflinePageHeader::Reason::NET_ERROR;
   }
 
-  void set_allow_preview(bool allow_preview) { allow_preview_ = allow_preview; }
-
-  bool allow_preview() const { return allow_preview_; }
-
  private:
   static std::unique_ptr<KeyedService> BuildTestOfflinePageModel(
       SimpleFactoryKey* key);
@@ -451,7 +445,6 @@
   // setting the state is done first from one thread and reading this state
   // can be from any other thread later.
   std::unique_ptr<TestNetworkChangeNotifier> network_change_notifier_;
-  bool allow_preview_ = false;
 
   // These should only be accessed purely from IO thread.
   base::ScopedTempDir private_archives_temp_base_dir_;
@@ -981,9 +974,6 @@
   network::ResourceRequest request =
       CreateResourceRequest(url, method, extra_headers, is_main_frame);
 
-  request.previews_state =
-      test_->allow_preview() ? content::OFFLINE_PAGE_ON : content::PREVIEWS_OFF;
-
   url_loader_ = OfflinePageURLLoader::Create(
       navigation_ui_data_.get(),
       test_->web_contents()->GetMainFrame()->GetFrameTreeNodeId(), request,
@@ -1169,60 +1159,6 @@
           SHOW_OFFLINE_ON_DISCONNECTED_NETWORK);
 }
 
-TEST_F(OfflinePageRequestHandlerTest,
-       LoadOfflinePageOnProhibitivelySlowNetwork) {
-  this->SimulateHasNetworkConnectivity(true);
-  this->set_allow_preview(true);
-
-  int64_t offline_id = this->SaveInternalPage(Url(), GURL(), kFilename1,
-                                              kFileSize1, std::string());
-
-  this->LoadPage(Url());
-
-  this->ExpectOfflinePageServed(
-      offline_id, kFileSize1,
-      OfflinePageRequestHandler::AggregatedRequestResult::
-          SHOW_OFFLINE_ON_PROHIBITIVELY_SLOW_NETWORK);
-}
-
-TEST_F(OfflinePageRequestHandlerTest,
-       DontLoadReloadOfflinePageOnProhibitivelySlowNetwork) {
-  this->SimulateHasNetworkConnectivity(true);
-  this->set_allow_preview(true);
-
-  int64_t offline_id = this->SaveInternalPage(Url(), GURL(), kFilename1,
-                                              kFileSize1, std::string());
-
-  // Treat this as a reloaded page.
-  net::HttpRequestHeaders extra_headers;
-  extra_headers.AddHeaderFromString(
-      this->UseOfflinePageHeader(OfflinePageHeader::Reason::RELOAD, 0));
-  this->LoadPageWithHeaders(Url(), extra_headers);
-
-  // The existentce of RELOAD header will force to treat the network as
-  // connected regardless current network condition. So we will fall back to
-  // the default handling immediately and no request result should be reported.
-  // Passing AGGREGATED_REQUEST_RESULT_MAX to skip checking request result in
-  // the helper function.
-  this->ExpectNoOfflinePageServed(
-      offline_id, OfflinePageRequestHandler::AggregatedRequestResult::
-                      AGGREGATED_REQUEST_RESULT_MAX);
-}
-
-TEST_F(OfflinePageRequestHandlerTest, PageNotFoundOnProhibitivelySlowNetwork) {
-  this->SimulateHasNetworkConnectivity(true);
-  this->set_allow_preview(true);
-
-  int64_t offline_id = this->SaveInternalPage(Url(), GURL(), kFilename1,
-                                              kFileSize1, std::string());
-
-  this->LoadPage(Url2());
-
-  this->ExpectNoOfflinePageServed(
-      offline_id, OfflinePageRequestHandler::AggregatedRequestResult::
-                      PAGE_NOT_FOUND_ON_PROHIBITIVELY_SLOW_NETWORK);
-}
-
 TEST_F(OfflinePageRequestHandlerTest, LoadOfflinePageOnFlakyNetwork) {
   this->SimulateHasNetworkConnectivity(true);
 
@@ -1540,22 +1476,6 @@
                       DIGEST_MISMATCH_ON_DISCONNECTED_NETWORK);
 }
 
-TEST_F(OfflinePageRequestHandlerTest,
-       FileSizeMismatchOnProhibitivelySlowNetwork) {
-  this->SimulateHasNetworkConnectivity(true);
-  this->set_allow_preview(true);
-
-  // Save an offline page in public location with mismatched file size.
-  int64_t offline_id = this->SavePublicPage(Url(), GURL(), kFilename1,
-                                            kMismatchedFileSize, kDigest1);
-
-  this->LoadPage(Url());
-
-  this->ExpectNoOfflinePageServed(
-      offline_id, OfflinePageRequestHandler::AggregatedRequestResult::
-                      DIGEST_MISMATCH_ON_PROHIBITIVELY_SLOW_NETWORK);
-}
-
 TEST_F(OfflinePageRequestHandlerTest, FileSizeMismatchOnConnectedNetwork) {
   this->SimulateHasNetworkConnectivity(true);
 
@@ -1608,22 +1528,6 @@
                       DIGEST_MISMATCH_ON_DISCONNECTED_NETWORK);
 }
 
-TEST_F(OfflinePageRequestHandlerTest,
-       DigestMismatchOnProhibitivelySlowNetwork) {
-  this->SimulateHasNetworkConnectivity(true);
-  this->set_allow_preview(true);
-
-  // Save an offline page in public location with mismatched digest.
-  int64_t offline_id = this->SavePublicPage(Url(), GURL(), kFilename1,
-                                            kFileSize1, kMismatchedDigest);
-
-  this->LoadPage(Url());
-
-  this->ExpectNoOfflinePageServed(
-      offline_id, OfflinePageRequestHandler::AggregatedRequestResult::
-                      DIGEST_MISMATCH_ON_PROHIBITIVELY_SLOW_NETWORK);
-}
-
 TEST_F(OfflinePageRequestHandlerTest, DigestMismatchOnConnectedNetwork) {
   this->SimulateHasNetworkConnectivity(true);
 
diff --git a/chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.cc
deleted file mode 100644
index 7a1a638..0000000
--- a/chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.cc
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "base/optional.h"
-#include "base/time/time.h"
-#include "components/offline_pages/buildflags/buildflags.h"
-#include "components/page_load_metrics/browser/page_load_metrics_util.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/web_contents.h"
-
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-#include "chrome/browser/offline_pages/offline_page_tab_helper.h"
-#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
-
-namespace previews {
-
-namespace internal {
-
-const char kHistogramOfflinePreviewsDOMContentLoadedEventFired[] =
-    "PageLoad.Clients.Previews.OfflinePages.DocumentTiming."
-    "NavigationToDOMContentLoadedEventFired";
-const char kHistogramOfflinePreviewsLoadEventFired[] =
-    "PageLoad.Clients.Previews.OfflinePages.DocumentTiming."
-    "NavigationToLoadEventFired";
-const char kHistogramOfflinePreviewsFirstContentfulPaint[] =
-    "PageLoad.Clients.Previews.OfflinePages.PaintTiming."
-    "NavigationToFirstContentfulPaint";
-const char kHistogramOfflinePreviewsParseStart[] =
-    "PageLoad.Clients.Previews.OfflinePages.ParseTiming.NavigationToParseStart";
-const char kHistogramOfflinePreviewsPageEndReason[] =
-    "Previews.PageEndReason.Offline";
-
-}  // namespace internal
-
-OfflinePagePreviewsPageLoadMetricsObserver::
-    OfflinePagePreviewsPageLoadMetricsObserver() {}
-
-OfflinePagePreviewsPageLoadMetricsObserver::
-    ~OfflinePagePreviewsPageLoadMetricsObserver() {}
-
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-OfflinePagePreviewsPageLoadMetricsObserver::OnCommit(
-    content::NavigationHandle* navigation_handle,
-    ukm::SourceId source_id) {
-  return IsOfflinePreview(navigation_handle->GetWebContents())
-             ? CONTINUE_OBSERVING
-             : STOP_OBSERVING;
-}
-
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-OfflinePagePreviewsPageLoadMetricsObserver::ShouldObserveMimeType(
-    const std::string& mime_type) const {
-  // On top of base-supported types, support MHTML. Offline previews are served
-  // as MHTML (multipart/related).
-  return PageLoadMetricsObserver::ShouldObserveMimeType(mime_type) ==
-                     CONTINUE_OBSERVING ||
-                 mime_type == "multipart/related"
-             ? CONTINUE_OBSERVING
-             : STOP_OBSERVING;
-}
-
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-OfflinePagePreviewsPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
-    const page_load_metrics::mojom::PageLoadTiming& timing) {
-  RecordPageLoadMetrics();
-  return STOP_OBSERVING;
-}
-
-void OfflinePagePreviewsPageLoadMetricsObserver::OnComplete(
-    const page_load_metrics::mojom::PageLoadTiming& timing) {
-  RecordPageLoadMetrics();
-}
-
-void OfflinePagePreviewsPageLoadMetricsObserver::OnDomContentLoadedEventStart(
-    const page_load_metrics::mojom::PageLoadTiming& timing) {
-  if (!page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
-          timing.document_timing->dom_content_loaded_event_start,
-          GetDelegate())) {
-    return;
-  }
-  PAGE_LOAD_HISTOGRAM(
-      internal::kHistogramOfflinePreviewsDOMContentLoadedEventFired,
-      timing.document_timing->dom_content_loaded_event_start.value());
-}
-
-void OfflinePagePreviewsPageLoadMetricsObserver::OnLoadEventStart(
-    const page_load_metrics::mojom::PageLoadTiming& timing) {
-  if (!page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
-          timing.document_timing->load_event_start, GetDelegate())) {
-    return;
-  }
-  PAGE_LOAD_HISTOGRAM(internal::kHistogramOfflinePreviewsLoadEventFired,
-                      timing.document_timing->load_event_start.value());
-}
-
-void OfflinePagePreviewsPageLoadMetricsObserver::OnFirstContentfulPaintInPage(
-    const page_load_metrics::mojom::PageLoadTiming& timing) {
-  if (!page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
-          timing.paint_timing->first_contentful_paint, GetDelegate())) {
-    return;
-  }
-  PAGE_LOAD_HISTOGRAM(internal::kHistogramOfflinePreviewsFirstContentfulPaint,
-                      timing.paint_timing->first_contentful_paint.value());
-}
-
-void OfflinePagePreviewsPageLoadMetricsObserver::OnParseStart(
-    const page_load_metrics::mojom::PageLoadTiming& timing) {
-  if (!page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
-          timing.parse_timing->parse_start, GetDelegate())) {
-    return;
-  }
-  PAGE_LOAD_HISTOGRAM(internal::kHistogramOfflinePreviewsParseStart,
-                      timing.parse_timing->parse_start.value());
-}
-
-bool OfflinePagePreviewsPageLoadMetricsObserver::IsOfflinePreview(
-    content::WebContents* web_contents) const {
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-  offline_pages::OfflinePageTabHelper* tab_helper =
-      offline_pages::OfflinePageTabHelper::FromWebContents(web_contents);
-  return tab_helper && tab_helper->GetOfflinePreviewItem();
-#else
-  return false;
-#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
-}
-
-void OfflinePagePreviewsPageLoadMetricsObserver::RecordPageLoadMetrics() {
-  UMA_HISTOGRAM_ENUMERATION(
-      internal::kHistogramOfflinePreviewsPageEndReason,
-      GetDelegate().GetPageEndReason(),
-      page_load_metrics::PageEndReason::PAGE_END_REASON_COUNT);
-}
-
-}  // namespace previews
diff --git a/chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.h
deleted file mode 100644
index a260699..0000000
--- a/chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_OFFLINE_PAGE_PREVIEWS_PAGE_LOAD_METRICS_OBSERVER_H_
-#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_OFFLINE_PAGE_PREVIEWS_PAGE_LOAD_METRICS_OBSERVER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
-#include "services/metrics/public/cpp/ukm_source.h"
-
-namespace content {
-class NavigationHandle;
-class WebContents;
-}  // namespace content
-
-namespace previews {
-
-namespace internal {
-
-// Various UMA histogram names for Previews core page load metrics.
-extern const char kHistogramOfflinePreviewsDOMContentLoadedEventFired[];
-extern const char kHistogramOfflinePreviewsLoadEventFired[];
-extern const char kHistogramOfflinePreviewsFirstContentfulPaint[];
-extern const char kHistogramOfflinePreviewsParseStart[];
-extern const char kHistogramOfflinePreviewsPageEndReason[];
-
-}  // namespace internal
-
-// Observer responsible for recording core page load metrics relevant to
-// Previews.
-class OfflinePagePreviewsPageLoadMetricsObserver
-    : public page_load_metrics::PageLoadMetricsObserver {
- public:
-  OfflinePagePreviewsPageLoadMetricsObserver();
-  ~OfflinePagePreviewsPageLoadMetricsObserver() override;
-
-  // page_load_metrics::PageLoadMetricsObserver:
-  ObservePolicy OnCommit(content::NavigationHandle* navigation_handle,
-                         ukm::SourceId source_id) override;
-  ObservePolicy FlushMetricsOnAppEnterBackground(
-      const page_load_metrics::mojom::PageLoadTiming& timing) override;
-  void OnComplete(
-      const page_load_metrics::mojom::PageLoadTiming& timing) override;
-  void OnDomContentLoadedEventStart(
-      const page_load_metrics::mojom::PageLoadTiming& timing) override;
-  void OnLoadEventStart(
-      const page_load_metrics::mojom::PageLoadTiming& timing) override;
-  void OnFirstContentfulPaintInPage(
-      const page_load_metrics::mojom::PageLoadTiming& timing) override;
-  void OnParseStart(
-      const page_load_metrics::mojom::PageLoadTiming& timing) override;
-  ObservePolicy ShouldObserveMimeType(
-      const std::string& mime_type) const override;
-
- private:
-  // Whether |web_contents| is showing an offline pages preview. Overridden in
-  // testing.
-  virtual bool IsOfflinePreview(content::WebContents* web_contents) const;
-
-  // Records metrics derived from global page load state.
-  void RecordPageLoadMetrics();
-
-  DISALLOW_COPY_AND_ASSIGN(OfflinePagePreviewsPageLoadMetricsObserver);
-};
-
-}  // namespace previews
-
-#endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_OFFLINE_PAGE_PREVIEWS_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer_unittest.cc
deleted file mode 100644
index baedd1c..0000000
--- a/chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer_unittest.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.h"
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/optional.h"
-#include "base/time/time.h"
-#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
-#include "components/page_load_metrics/browser/page_load_tracker.h"
-#include "components/page_load_metrics/common/page_load_timing.h"
-#include "components/page_load_metrics/common/test/page_load_metrics_test_util.h"
-#include "content/public/browser/web_contents.h"
-
-namespace previews {
-
-namespace {
-
-const char kDefaultTestUrl1[] = "https://google.com";
-const char kDefaultTestUrl2[] = "https://example.com";
-
-class TestOfflinePagePreviewsPageLoadMetricsObserver
-    : public OfflinePagePreviewsPageLoadMetricsObserver {
- public:
-  explicit TestOfflinePagePreviewsPageLoadMetricsObserver(bool offline_preview)
-      : offline_preview_(offline_preview) {}
-  ~TestOfflinePagePreviewsPageLoadMetricsObserver() override {}
-
-  bool IsOfflinePreview(content::WebContents* web_contents) const override {
-    return offline_preview_;
-  }
-
- private:
-  bool offline_preview_;
-};
-
-}  // namespace
-
-class OfflinePagePreviewsPageLoadMetricsObserverTest
-    : public page_load_metrics::PageLoadMetricsObserverTestHarness {
- public:
-  OfflinePagePreviewsPageLoadMetricsObserverTest()
-      : is_offline_preview_(false) {}
-
-  void ResetTest() {
-    page_load_metrics::InitPageLoadTimingForTest(&timing_);
-    // Reset to the default testing state. Does not reset histogram state.
-    timing_.navigation_start = base::Time::FromDoubleT(1);
-    timing_.response_start = base::TimeDelta::FromSeconds(2);
-    timing_.parse_timing->parse_start = base::TimeDelta::FromSeconds(3);
-    timing_.paint_timing->first_contentful_paint =
-        base::TimeDelta::FromSeconds(4);
-    timing_.paint_timing->first_image_paint = base::TimeDelta::FromSeconds(5);
-    timing_.document_timing->load_event_start = base::TimeDelta::FromSeconds(7);
-    PopulateRequiredTimingFields(&timing_);
-  }
-
-  void RunTest(bool is_offline_preview) {
-    is_offline_preview_ = is_offline_preview;
-    NavigateAndCommit(GURL(kDefaultTestUrl1));
-    tester()->SimulateTimingUpdate(timing_);
-
-    // Navigate again to force OnComplete, which happens when a new navigation
-    // occurs.
-    NavigateAndCommit(GURL(kDefaultTestUrl2));
-  }
-
-  void ValidateHistograms() {
-    ValidateTimingHistogramsFor(
-        internal::kHistogramOfflinePreviewsDOMContentLoadedEventFired,
-        timing_.document_timing->dom_content_loaded_event_start);
-    ValidateTimingHistogramsFor(
-        internal::kHistogramOfflinePreviewsLoadEventFired,
-        timing_.document_timing->load_event_start);
-    ValidateTimingHistogramsFor(
-        internal::kHistogramOfflinePreviewsFirstContentfulPaint,
-        timing_.paint_timing->first_contentful_paint);
-    ValidateTimingHistogramsFor(internal::kHistogramOfflinePreviewsParseStart,
-                                timing_.parse_timing->parse_start);
-    ValidateHistogramsFor(internal::kHistogramOfflinePreviewsPageEndReason,
-                          page_load_metrics::PageEndReason::END_NEW_NAVIGATION);
-  }
-
-  void ValidateTimingHistogramsFor(
-      const std::string& histogram,
-      const base::Optional<base::TimeDelta>& event) {
-    ValidateHistogramsFor(histogram, static_cast<base::HistogramBase::Sample>(
-                                         event.value().InMilliseconds()));
-  }
-
-  void ValidateHistogramsFor(const std::string& histogram,
-                             const base::HistogramBase::Sample sample) {
-    tester()->histogram_tester().ExpectTotalCount(histogram,
-                                                  is_offline_preview_ ? 1 : 0);
-    if (!is_offline_preview_)
-      return;
-    tester()->histogram_tester().ExpectUniqueSample(histogram, sample, 1);
-  }
-
- protected:
-  void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
-    tracker->AddObserver(
-        base::WrapUnique(new TestOfflinePagePreviewsPageLoadMetricsObserver(
-            is_offline_preview_)));
-  }
-
- private:
-  page_load_metrics::mojom::PageLoadTiming timing_;
-  bool is_offline_preview_;
-
-  DISALLOW_COPY_AND_ASSIGN(OfflinePagePreviewsPageLoadMetricsObserverTest);
-};
-
-TEST_F(OfflinePagePreviewsPageLoadMetricsObserverTest, NoPreview) {
-  ResetTest();
-  RunTest(false);
-  ValidateHistograms();
-}
-
-TEST_F(OfflinePagePreviewsPageLoadMetricsObserverTest, OfflinePreviews) {
-  ResetTest();
-  RunTest(true);
-  ValidateHistograms();
-}
-
-}  // namespace previews
diff --git a/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc b/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc
index 5109a94..081203c 100644
--- a/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/previews_ukm_observer.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/previews/previews_ui_tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "components/offline_pages/buildflags/buildflags.h"
 #include "components/page_load_metrics/browser/page_load_metrics_observer.h"
 #include "components/page_load_metrics/browser/page_load_metrics_util.h"
 #include "components/page_load_metrics/common/page_load_timing.h"
@@ -27,16 +26,10 @@
 #include "services/metrics/public/cpp/ukm_recorder.h"
 #include "services/metrics/public/cpp/ukm_source.h"
 
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-#include "chrome/browser/offline_pages/offline_page_tab_helper.h"
-#endif
-
 namespace previews {
 
 namespace {
 
-const char kOfflinePreviewsMimeType[] = "multipart/related";
-
 bool ShouldOptionalEligibilityReasonBeRecorded(
     base::Optional<previews::PreviewsEligibilityReason> reason) {
   if (!reason.has_value())
@@ -75,30 +68,14 @@
 
   // Only check for preview types that are decided before commit in the
   // |allowed_previews_state|.
-  previews_likely_ =
-      HasEnabledPreviews(previews_user_data->PreHoldbackAllowedPreviewsState() &
-                         kPreCommitPreviews);
   content::PreviewsState previews_state =
       previews_user_data->PreHoldbackCommittedPreviewsState();
 
   // Check all preview types in the |committed_previews_state|. In practice
   // though, this will only set |previews_likely_| if it wasn't before for an
   // Optimization Hints preview.
-  previews_likely_ |= HasEnabledPreviews(previews_state);
+  previews_likely_ = HasEnabledPreviews(previews_state);
 
-  if (navigation_handle->GetWebContents()->GetContentsMimeType() ==
-      kOfflinePreviewsMimeType) {
-    if (!IsOfflinePreview(navigation_handle->GetWebContents()))
-      return STOP_OBSERVING;
-    offline_preview_seen_ = true;
-    DCHECK_EQ(previews::GetMainFramePreviewsType(previews_state),
-              previews::PreviewsType::OFFLINE);
-  }
-
-  if (previews_state && previews::GetMainFramePreviewsType(previews_state) ==
-                            previews::PreviewsType::LITE_PAGE) {
-    lite_page_seen_ = true;
-  }
   if (previews_state && previews::GetMainFramePreviewsType(previews_state) ==
                             previews::PreviewsType::NOSCRIPT) {
     noscript_seen_ = true;
@@ -115,9 +92,6 @@
     origin_opt_out_occurred_ = true;
   }
 
-  lite_page_eligibility_reason_ =
-      previews_user_data->EligibilityReasonForPreview(
-          previews::PreviewsType::LITE_PAGE);
   noscript_eligibility_reason_ =
       previews_user_data->EligibilityReasonForPreview(
           previews::PreviewsType::NOSCRIPT);
@@ -127,23 +101,11 @@
   defer_all_script_eligibility_reason_ =
       previews_user_data->EligibilityReasonForPreview(
           previews::PreviewsType::DEFER_ALL_SCRIPT);
-  offline_eligibility_reason_ = previews_user_data->EligibilityReasonForPreview(
-      previews::PreviewsType::OFFLINE);
 
   return CONTINUE_OBSERVING;
 }
 
 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-PreviewsUKMObserver::ShouldObserveMimeType(const std::string& mime_type) const {
-  if (PageLoadMetricsObserver::ShouldObserveMimeType(mime_type) ==
-          CONTINUE_OBSERVING ||
-      mime_type == kOfflinePreviewsMimeType) {
-    return CONTINUE_OBSERVING;
-  }
-  return STOP_OBSERVING;
-}
-
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
 PreviewsUKMObserver::OnStart(content::NavigationHandle* navigation_handle,
                              const GURL& currently_committed_url,
                              bool started_in_foreground) {
@@ -190,23 +152,19 @@
       page_load_metrics::PageEndReason::PAGE_END_REASON_COUNT);
 
   // Only record previews types when they are active.
-  if (!lite_page_seen_ && !noscript_seen_ && !resource_loading_hints_seen_ &&
-      !defer_all_script_seen_ && !offline_preview_seen_ &&
-      !origin_opt_out_occurred_ && !save_data_enabled_) {
+  if (!noscript_seen_ && !resource_loading_hints_seen_ &&
+      !defer_all_script_seen_ && !origin_opt_out_occurred_ &&
+      !save_data_enabled_) {
     return;
   }
 
   ukm::builders::Previews builder(GetDelegate().GetSourceId());
-  if (lite_page_seen_)
-    builder.Setlite_page(1);
   if (noscript_seen_)
     builder.Setnoscript(1);
   if (resource_loading_hints_seen_)
     builder.Setresource_loading_hints(1);
   if (defer_all_script_seen_)
     builder.Setdefer_all_script(1);
-  if (offline_preview_seen_)
-    builder.Setoffline_preview(1);
   // 2 is set here for legacy reasons as it denotes an optout through the
   // omnibox ui as opposed to the now deprecated infobar.
   if (opt_out_occurred_)
@@ -218,11 +176,6 @@
   if (previews_likely_)
     builder.Setpreviews_likely(1);
 
-  if (ShouldOptionalEligibilityReasonBeRecorded(
-          lite_page_eligibility_reason_)) {
-    builder.Setproxy_lite_page_eligibility_reason(
-        static_cast<int>(lite_page_eligibility_reason_.value()));
-  }
   if (ShouldOptionalEligibilityReasonBeRecorded(noscript_eligibility_reason_)) {
     builder.Setnoscript_eligibility_reason(
         static_cast<int>(noscript_eligibility_reason_.value()));
@@ -237,10 +190,6 @@
     builder.Setdefer_all_script_eligibility_reason(
         static_cast<int>(defer_all_script_eligibility_reason_.value()));
   }
-  if (ShouldOptionalEligibilityReasonBeRecorded(offline_eligibility_reason_)) {
-    builder.Setoffline_eligibility_reason(
-        static_cast<int>(offline_eligibility_reason_.value()));
-  }
   builder.Record(ukm::UkmRecorder::Get());
 }
 
@@ -267,15 +216,4 @@
   return data_reduction_proxy_settings->IsDataReductionProxyEnabled();
 }
 
-bool PreviewsUKMObserver::IsOfflinePreview(
-    content::WebContents* web_contents) const {
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-  offline_pages::OfflinePageTabHelper* tab_helper =
-      offline_pages::OfflinePageTabHelper::FromWebContents(web_contents);
-  return tab_helper && tab_helper->GetOfflinePreviewItem();
-#else
-  return false;
-#endif
-}
-
 }  // namespace previews
diff --git a/chrome/browser/page_load_metrics/observers/previews_ukm_observer.h b/chrome/browser/page_load_metrics/observers/previews_ukm_observer.h
index be3230f..649138f 100644
--- a/chrome/browser/page_load_metrics/observers/previews_ukm_observer.h
+++ b/chrome/browser/page_load_metrics/observers/previews_ukm_observer.h
@@ -16,7 +16,6 @@
 
 namespace content {
 class NavigationHandle;
-class WebContents;
 }  // namespace content
 
 namespace previews {
@@ -41,8 +40,6 @@
   void OnComplete(
       const page_load_metrics::mojom::PageLoadTiming& timing) override;
   void OnEventOccurred(const void* const event_key) override;
-  ObservePolicy ShouldObserveMimeType(
-      const std::string& mime_type) const override;
 
  protected:
   // Returns true if data saver feature is enabled in Chrome. Virtualized for
@@ -50,35 +47,25 @@
   virtual bool IsDataSaverEnabled(
       content::NavigationHandle* navigation_handle) const;
 
-  // Whether the current page load is an Offline Preview. Must be called from
-  // OnCommit. Virtual for testing.
-  virtual bool IsOfflinePreview(content::WebContents* web_contents) const;
-
  private:
   void RecordPreviewsTypes();
 
   // The preview type that was actually committed and seen by the user.
   PreviewsType committed_preview_;
 
-  bool lite_page_seen_ = false;
   bool noscript_seen_ = false;
   bool resource_loading_hints_seen_ = false;
   bool defer_all_script_seen_ = false;
-  bool offline_preview_seen_ = false;
   bool opt_out_occurred_ = false;
   bool origin_opt_out_occurred_ = false;
   bool save_data_enabled_ = false;
   bool previews_likely_ = false;
   base::Optional<previews::PreviewsEligibilityReason>
-      lite_page_eligibility_reason_;
-  base::Optional<previews::PreviewsEligibilityReason>
       noscript_eligibility_reason_;
   base::Optional<previews::PreviewsEligibilityReason>
       resource_loading_hints_eligibility_reason_;
   base::Optional<previews::PreviewsEligibilityReason>
       defer_all_script_eligibility_reason_;
-  base::Optional<previews::PreviewsEligibilityReason>
-      offline_eligibility_reason_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/chrome/browser/page_load_metrics/observers/previews_ukm_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/previews_ukm_observer_unittest.cc
index 96115eb..171f0472 100644
--- a/chrome/browser/page_load_metrics/observers/previews_ukm_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/previews_ukm_observer_unittest.cc
@@ -90,10 +90,6 @@
     return save_data_enabled_;
   }
 
-  bool IsOfflinePreview(content::WebContents* web_contents) const override {
-    return committed_state_ == content::OFFLINE_PAGE_ON;
-  }
-
   content::PreviewsState committed_state_;
   content::PreviewsState allowed_state_;
   bool origin_opt_out_received_;
@@ -123,8 +119,6 @@
     eligibility_reasons_ = eligibility_reasons;
     auto navigation = content::NavigationSimulator::CreateBrowserInitiated(
         GURL(kDefaultTestUrl), web_contents());
-    if (committed_state == content::OFFLINE_PAGE_ON)
-      navigation->SetContentsMimeType("multipart/related");
 
     navigation->Commit();
   }
@@ -155,12 +149,6 @@
     // Collect the set of recorded previews into a PreviewsState bitmask to
     // compare against the expected previews.
     content::PreviewsState recorded_previews = 0;
-    if (tester()->test_ukm_recorder().EntryHasMetric(
-            entry, UkmEntry::koffline_previewName))
-      recorded_previews |= content::OFFLINE_PAGE_ON;
-    if (tester()->test_ukm_recorder().EntryHasMetric(entry,
-                                                     UkmEntry::klite_pageName))
-      recorded_previews |= content::SERVER_LITE_PAGE_ON;
     if (tester()->test_ukm_recorder().EntryHasMetric(entry,
                                                      UkmEntry::knoscriptName))
       recorded_previews |= content::NOSCRIPT_ON;
@@ -188,17 +176,6 @@
               tester()->test_ukm_recorder().EntryHasMetric(
                   entry, UkmEntry::kpreviews_likelyName));
 
-    int want_lite_page_eligibility_reason =
-        static_cast<int>(eligibility_reasons[PreviewsType::LITE_PAGE]);
-    if (want_lite_page_eligibility_reason) {
-      tester()->test_ukm_recorder().ExpectEntryMetric(
-          entry, UkmEntry::kproxy_lite_page_eligibility_reasonName,
-          want_lite_page_eligibility_reason);
-    } else {
-      EXPECT_FALSE(tester()->test_ukm_recorder().EntryHasMetric(
-          entry, UkmEntry::kproxy_lite_page_eligibility_reasonName));
-    }
-
     int want_noscript_eligibility_reason =
         static_cast<int>(eligibility_reasons[PreviewsType::NOSCRIPT]);
     if (want_noscript_eligibility_reason) {
@@ -220,17 +197,6 @@
       EXPECT_FALSE(tester()->test_ukm_recorder().EntryHasMetric(
           entry, UkmEntry::kresource_loading_hints_eligibility_reasonName));
     }
-
-    int want_offline_eligibility_reason =
-        static_cast<int>(eligibility_reasons[PreviewsType::OFFLINE]);
-    if (want_offline_eligibility_reason) {
-      tester()->test_ukm_recorder().ExpectEntryMetric(
-          entry, UkmEntry::koffline_eligibility_reasonName,
-          want_offline_eligibility_reason);
-    } else {
-      EXPECT_FALSE(tester()->test_ukm_recorder().EntryHasMetric(
-          entry, UkmEntry::koffline_eligibility_reasonName));
-    }
   }
 
   void SetUp() override {
@@ -292,37 +258,6 @@
                       {} /* eligibility_reasons */);
 }
 
-TEST_F(PreviewsUKMObserverTest, LitePageSeen) {
-  RunTest(content::SERVER_LITE_PAGE_ON /* committed_state */,
-          content::SERVER_LITE_PAGE_ON |
-              content::DEFER_ALL_SCRIPT_ON /* allowed_state */,
-          false /* origin_opt_out */, false /* save_data_enabled */,
-          {} /* eligibility_reasons */);
-
-  tester()->NavigateToUntrackedUrl();
-
-  ValidatePreviewsUKM(content::SERVER_LITE_PAGE_ON, 0 /* opt_out_value */,
-                      false /* origin_opt_out_expected */,
-                      false /* save_data_enabled_expected */,
-                      true /* previews_likely */, {} /* eligibility_reasons */);
-}
-
-TEST_F(PreviewsUKMObserverTest, LitePageOptOutChip) {
-  RunTest(content::SERVER_LITE_PAGE_ON /* committed_state */,
-          content::SERVER_LITE_PAGE_ON /* allowed_state */,
-          false /* origin_opt_out */, false /* save_data_enabled */,
-          {} /* eligibility_reasons */);
-
-  tester()->metrics_web_contents_observer()->BroadcastEventToObservers(
-      PreviewsUITabHelper::OptOutEventKey());
-  tester()->NavigateToUntrackedUrl();
-
-  ValidatePreviewsUKM(content::SERVER_LITE_PAGE_ON, 2 /* opt_out_value */,
-                      false /* origin_opt_out_expected */,
-                      false /* save_data_enabled_expected */,
-                      true /* previews_likely */, {} /* eligibility_reasons */);
-}
-
 TEST_F(PreviewsUKMObserverTest, NoScriptOptOutChip) {
   RunTest(content::NOSCRIPT_ON /* committed_state */,
           content::PREVIEWS_UNSPECIFIED /* allowed_state */,
@@ -339,20 +274,6 @@
                       true /* previews_likely */, {} /* eligibility_reasons */);
 }
 
-TEST_F(PreviewsUKMObserverTest, OfflinePreviewsSeen) {
-  RunTest(content::OFFLINE_PAGE_ON /* committed_state */,
-          content::PREVIEWS_UNSPECIFIED /* allowed_state */,
-          false /* origin_opt_out */, false /* save_data_enabled */,
-          {} /* eligibility_reasons */);
-
-  tester()->NavigateToUntrackedUrl();
-
-  ValidatePreviewsUKM(content::OFFLINE_PAGE_ON, 0 /* opt_out_value */,
-                      false /* origin_opt_out_expected */,
-                      false /* save_data_enabled_expected */,
-                      true /* previews_likely */, {} /* eligibility_reasons */);
-}
-
 TEST_F(PreviewsUKMObserverTest, ResourceLoadingHintsSeen) {
   RunTest(content::RESOURCE_LOADING_HINTS_ON /* committed_state */,
           content::PREVIEWS_UNSPECIFIED /* allowed_state */,
@@ -443,20 +364,6 @@
                       {} /* eligibility_reasons */);
 }
 
-TEST_F(PreviewsUKMObserverTest, PreviewsLikelySet_PreCommitDecision) {
-  RunTest(content::OFFLINE_PAGE_ON /* committed_state */,
-          content::OFFLINE_PAGE_ON | content::NOSCRIPT_ON /* allowed_state */,
-          false /* origin_opt_out */, true /* save_data_enabled */,
-          {} /* eligibility_reasons */);
-
-  tester()->NavigateToUntrackedUrl();
-
-  ValidatePreviewsUKM(content::OFFLINE_PAGE_ON, 0 /* opt_out_value */,
-                      false /* origin_opt_out_expected */,
-                      true /* save_data_enabled_expected */,
-                      true /* previews_likely */, {} /* eligibility_reasons */);
-}
-
 TEST_F(PreviewsUKMObserverTest, PreviewsLikelyNotSet_PostCommitDecision) {
   RunTest(content::PREVIEWS_OFF /* committed_state */,
           content::NOSCRIPT_ON /* allowed_state */, false /* origin_opt_out */,
@@ -486,28 +393,28 @@
 }
 
 TEST_F(PreviewsUKMObserverTest, CoinFlipResult_Holdback) {
-  RunTest(content::OFFLINE_PAGE_ON /* committed_state */,
-          content::OFFLINE_PAGE_ON /* allowed_state */,
+  RunTest(content::DEFER_ALL_SCRIPT_ON /* committed_state */,
+          content::DEFER_ALL_SCRIPT_ON /* allowed_state */,
           false /* origin_opt_out */, true /* save_data_enabled */,
           {} /* eligibility_reasons */);
 
   tester()->NavigateToUntrackedUrl();
 
-  ValidatePreviewsUKM(content::OFFLINE_PAGE_ON, 0 /* opt_out_value */,
+  ValidatePreviewsUKM(content::DEFER_ALL_SCRIPT_ON, 0 /* opt_out_value */,
                       false /* origin_opt_out_expected */,
                       true /* save_data_enabled_expected */,
                       true /* previews_likely */, {} /* eligibility_reasons */);
 }
 
 TEST_F(PreviewsUKMObserverTest, CoinFlipResult_Allowed) {
-  RunTest(content::OFFLINE_PAGE_ON /* committed_state */,
-          content::OFFLINE_PAGE_ON /* allowed_state */,
+  RunTest(content::DEFER_ALL_SCRIPT_ON /* committed_state */,
+          content::DEFER_ALL_SCRIPT_ON /* allowed_state */,
           false /* origin_opt_out */, true /* save_data_enabled */,
           {} /* eligibility_reasons */);
 
   tester()->NavigateToUntrackedUrl();
 
-  ValidatePreviewsUKM(content::OFFLINE_PAGE_ON, 0 /* opt_out_value */,
+  ValidatePreviewsUKM(content::DEFER_ALL_SCRIPT_ON, 0 /* opt_out_value */,
                       false /* origin_opt_out_expected */,
                       true /* save_data_enabled_expected */,
                       true /* previews_likely */, {} /* eligibility_reasons */);
@@ -517,12 +424,7 @@
   RunTest(content::PREVIEWS_OFF /* committed_state */,
           content::PREVIEWS_UNSPECIFIED /* allowed_state */,
           false /* origin_opt_out */, true /* save_data_enabled */,
-
-          {{PreviewsType::OFFLINE,
-            PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE},
-           {PreviewsType::LITE_PAGE,
-            PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE},
-           // ALLOWED is equal to zero and should not be recorded.
+          {// ALLOWED is equal to zero and should not be recorded.
            {PreviewsType::NOSCRIPT,
             PreviewsEligibilityReason::ALLOWED}} /* eligibility_reasons */);
 
@@ -532,23 +434,14 @@
                       false /* origin_opt_out_expected */,
                       true /* save_data_enabled_expected */,
                       false /* previews_likely */,
-                      {{PreviewsType::OFFLINE,
-                        PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE},
-                       {PreviewsType::LITE_PAGE,
-                        PreviewsEligibilityReason::
-                            BLOCKLIST_UNAVAILABLE}} /* eligibility_reasons */);
+                      {} /* eligibility_reasons */);
 }
 
 TEST_F(PreviewsUKMObserverTest, LogPreviewsEligibilityReason_NoneAllowed) {
   RunTest(content::PREVIEWS_OFF /* committed_state */,
           content::PREVIEWS_UNSPECIFIED /* allowed_state */,
           false /* origin_opt_out */, true /* save_data_enabled */,
-
-          {{PreviewsType::OFFLINE,
-            PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE},
-           {PreviewsType::LITE_PAGE,
-            PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE},
-           {PreviewsType::NOSCRIPT,
+          {{PreviewsType::NOSCRIPT,
             PreviewsEligibilityReason::
                 BLOCKLIST_DATA_NOT_LOADED}} /* eligibility_reasons */);
 
@@ -558,11 +451,7 @@
       content::PREVIEWS_UNSPECIFIED, 0 /* opt_out_value */,
       false /* origin_opt_out_expected */,
       true /* save_data_enabled_expected */, false /* previews_likely */,
-      {{PreviewsType::OFFLINE,
-        PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE},
-       {PreviewsType::LITE_PAGE,
-        PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE},
-       {PreviewsType::NOSCRIPT,
+      {{PreviewsType::NOSCRIPT,
         PreviewsEligibilityReason::
             BLOCKLIST_DATA_NOT_LOADED}} /* eligibility_reasons */);
 }
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index 1c1b94d..17019b7 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/no_state_prefetch_page_load_metrics_observer.h"
-#include "chrome/browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/omnibox_suggestion_used_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/optimization_guide_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/portal_page_load_metrics_observer.h"
@@ -110,9 +109,6 @@
     tracker->AddObserver(
         std::make_unique<MultiTabLoadingPageLoadMetricsObserver>());
     tracker->AddObserver(
-        std::make_unique<
-            previews::OfflinePagePreviewsPageLoadMetricsObserver>());
-    tracker->AddObserver(
         std::make_unique<OptimizationGuidePageLoadMetricsObserver>());
     tracker->AddObserver(
         std::make_unique<previews::PreviewsPageLoadMetricsObserver>());
diff --git a/chrome/browser/password_check/android/BUILD.gn b/chrome/browser/password_check/android/BUILD.gn
index 892baf1..ec6879d2 100644
--- a/chrome/browser/password_check/android/BUILD.gn
+++ b/chrome/browser/password_check/android/BUILD.gn
@@ -28,6 +28,8 @@
     ":public_ui_java",
     "internal:public_ui_factory_java",
     "//base:base_java",
+    "//components/browser_ui/settings/android:java",
+    "//components/browser_ui/widget/android:java",
     "//third_party/android_deps:androidx_fragment_fragment_java",
     "//third_party/android_deps:androidx_preference_preference_java",
     "//third_party/android_deps:androidx_recyclerview_recyclerview_java",
@@ -36,6 +38,7 @@
     "java/src/org/chromium/chrome/browser/password_check/CompromisedCredential.java",
     "java/src/org/chromium/chrome/browser/password_check/PasswordCheck.java",
     "java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java",
+    "java/src/org/chromium/chrome/browser/password_check/PasswordCheckPreference.java",
   ]
 }
 
@@ -87,8 +90,13 @@
 }
 android_resources("java_resources") {
   sources = [
+    "java/res/drawable-night/password_check_neutral.xml",
     "java/res/drawable-night/password_checkup_warning.xml",
+    "java/res/drawable/password_check_neutral.xml",
     "java/res/drawable/password_checkup_warning.xml",
+    "java/res/layout/password_check_preference_button.xml",
+    "java/res/values-night/colors.xml",
+    "java/res/values/colors.xml",
   ]
   deps = [ "//chrome/browser/ui/android/strings:ui_strings_grd" ]
   custom_package = "org.chromium.chrome.browser.password_check"
diff --git a/chrome/browser/password_check/android/java/res/drawable-night/password_check_neutral.xml b/chrome/browser/password_check/android/java/res/drawable-night/password_check_neutral.xml
new file mode 100644
index 0000000..c06c025
--- /dev/null
+++ b/chrome/browser/password_check/android/java/res/drawable-night/password_check_neutral.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:targetApi="21"
+    tools:ignore="VectorRaster"
+    android:width="360dp"
+    android:height="120dp"
+    android:viewportWidth="360"
+    android:viewportHeight="120">
+    <path android:pathData="M0 0h360v120H0z"
+        android:fillColor="#28282B"
+        android:fillType="evenOdd"/>
+    <path android:pathData="M288.585 52.215V47c10.735 0 19.175-3 25.09-8.955 9.29-9.36 9.325-23.015 9.325-23.15l5.25-0.04c0 0.645 0 15.9-10.815 26.82-6.935 6.995-16.645 10.54-28.85 10.54z"
+        android:fillColor="#414447"/>
+    <path android:pathData="M253.87 83h-5.245a40.45 40.45 0 0 1 5-18c4.605-8.21 14.4-18 34.96-18v5.215c-14.465 0-24.685 5.17-30.385 15.36A35.345 35.345 0 0 0 253.87 83z"
+        android:fillColor="#81C995"/>
+    <path android:pathData="M254.61 94.5h-90.72V32.325a2.65 2.65 0 0 1 2.64-2.64h85.44a2.65 2.65 0 0 1 2.64 2.64V94.5z"
+        android:fillColor="#262628"/>
+    <path android:pathData="M250.29 30.225A3.785 3.785 0 0 1 254.07 34v59.945h-89.64V34a3.785 3.785 0 0 1 3.78-3.78h82.08m0-0.54h-82.08a4.335 4.335 0 0 0-4.32 4.32v60.5h90.72V34a4.335 4.335 0 0 0-4.32-4.32zm-99.36 68.585h116.64v0.54H150.93v-0.54z"
+        android:fillColor="#4E5154"/>
+    <path android:pathData="M56 57.915H38.175v-0.27a8.91 8.91 0 0 1 17.82 0L56 57.915zm-17.275-0.54H55.45a8.37 8.37 0 0 0-16.73 0h0.005z"
+        android:fillColor="#5F6368"/>
+    <path android:pathData="M335 88.66h20v4h-20z"
+        android:fillColor="#414447"/>
+    <path android:pathData="M338.268 98.32l10-17.32 3.464 2-10 17.32z"
+        android:fillColor="#414447"/>
+    <path android:pathData="M348.268 100.32l-10-17.32 3.464-2 10 17.32z"
+        android:fillColor="#414447"/>
+    <path android:pathData="M118 18h56a6 6 0 0 1 6 6v80a6 6 0 0 1-6 6h-56a6 6 0 0 1-6-6V24a6 6 0 0 1 6-6z"
+        android:strokeWidth=".5"
+        android:fillColor="#262628"
+        android:strokeColor="#4E5154"/>
+    <path android:pathData="M124 65h12v2h-12z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M126.134 70.696l6-10.392 1.732 1-6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M132.134 71.696l-6-10.392 1.732-1 6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M140 65h12v2h-12z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M142.134 70.696l6-10.392 1.732 1-6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M148.134 71.696l-6-10.392 1.732-1 6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M156 65h12v2h-12z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M158.134 70.696l6-10.392 1.732 1-6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M164.134 71.696l-6-10.392 1.732-1 6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M124.5 85h13a0.5 0.5 0 0 1 0.5 0.5 0.5 0.5 0 0 1-0.5 0.5h-13a0.5 0.5 0 0 1-0.5-0.5 0.5 0.5 0 0 1 0.5-0.5z"
+        android:fillColor="#4E5154"/>
+    <path android:pathData="M124.5 43h15a0.5 0.5 0 0 1 0.5 0.5 0.5 0.5 0 0 1-0.5 0.5h-15a0.5 0.5 0 0 1-0.5-0.5 0.5 0.5 0 0 1 0.5-0.5z"
+        android:fillColor="#4E5154"/>
+    <path android:pathData="M124.5 50h27a0.5 0.5 0 0 1 0.5 0.5 0.5 0.5 0 0 1-0.5 0.5h-27a0.5 0.5 0 0 1-0.5-0.5 0.5 0.5 0 0 1 0.5-0.5z"
+        android:fillColor="#4E5154"/>
+    <path android:pathData="M146 10a7 7 0 0 1 7 7v7h-14v-7a7 7 0 0 1 7-7z"
+        android:strokeWidth=".5"
+        android:fillColor="#262628"
+        android:strokeColor="#4E5154"/>
+    <path android:pathData="M143 17a3 3 0 1 1 6 0 3 3 0 1 1-6 0"
+        android:strokeWidth=".5"
+        android:fillColor="#262628"
+        android:strokeColor="#4E5154"/>
+    <path android:pathData="M162 24h-32a6 6 0 0 0-6 6v4h44v-4a6 6 0 0 0-6-6z"
+        android:strokeWidth=".5"
+        android:fillColor="#262628"
+        android:strokeColor="#4E5154"/>
+    <path android:pathData="M79.6 58.42a12.935 12.935 0 0 0-10.1 4.82A8.62 8.62 0 0 0 58 71.38h34.56c0-7.158-5.802-12.96-12.96-12.96z"
+        android:fillColor="#28282B"/>
+    <path android:pathData="M92.83 71.65h-35.1v-0.27a8.89 8.89 0 0 1 11.695-8.455A13.23 13.23 0 0 1 92.83 71.38v0.27zm-34.555-0.54h34a12.69 12.69 0 0 0-22.56-7.7l-0.12 0.15-0.18-0.065A8.35 8.35 0 0 0 58.26 71.11h0.015z"
+        android:fillColor="#4E5154"/>
+    <path android:pathData="M38.12 82.36l3.705-3.705c7.59 7.59 15.69 11.43 24.075 11.41 13.17-0.03 22.855-9.655 22.95-9.75l3.735 3.675c-0.45 0.46-11.235 11.25-26.61 11.315C56.12 95.345 46.75 91 38.12 82.36z"
+        android:fillColor="#F7BB2A"/>
+    <path android:pathData="M-8.2 79.58l-3.705-3.705a40.45 40.45 0 0 1 16.25-9.18c9.075-2.57 22.945-2.58 37.5 11.96L38.14 82.36C27.89 72.13 17 68.555 5.77 71.735A35.345 35.345 0 0 0-8.2 79.58z"
+        android:fillColor="#414447"/>
+    <path android:pathData="M197.889 56c1.165 0.002 2.11 1.075 2.111 2.4v19.2c-0.001 1.325-0.946 2.398-2.111 2.4H126.11c-1.165-0.002-2.11-1.075-2.111-2.4V58.4c0.001-1.325 0.946-2.398 2.111-2.4h71.778z"
+        android:fillColor="#8AB4F8"/>
+    <path android:pathData="M179.75 56H198a2 2 0 0 1 2 2v20a2 2 0 0 1-2 2h-18.25V56z"
+        android:fillColor="#8AB4F8"
+        android:fillType="evenOdd"/>
+    <path android:pathData="M191 62a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1 1 1 0 0 1-1-1V63a1 1 0 0 1 1-1z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M132 67h10v2h-10z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M133.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M138.634 72.83l-5-8.66 1.732-1 5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M146 67h10v2h-10z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M147.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M152.634 72.83l-5-8.66 1.732-1 5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M160 67h10v2h-10z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M161.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M166.634 72.83l-5-8.66 1.732-1 5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M174 67h10v2h-10z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M175.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M180.634 72.83l-5-8.66 1.732-1 5 8.66z"
+        android:fillColor="#FFF"/>
+</vector>
+
diff --git a/chrome/browser/password_check/android/java/res/drawable/password_check_neutral.xml b/chrome/browser/password_check/android/java/res/drawable/password_check_neutral.xml
new file mode 100644
index 0000000..81f588f
--- /dev/null
+++ b/chrome/browser/password_check/android/java/res/drawable/password_check_neutral.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:targetApi="21"
+    tools:ignore="VectorRaster"
+    android:width="360dp"
+    android:height="120dp"
+    android:viewportWidth="360"
+    android:viewportHeight="120">
+    <path android:pathData="M0 0h360v120H0z"
+        android:fillColor="#F8F9FA"
+        android:fillType="evenOdd"/>
+    <path android:pathData="M288.585 52.215V47c10.735 0 19.175-3 25.09-8.955 9.29-9.36 9.325-23.015 9.325-23.15l5.25-0.04c0 0.645 0 15.9-10.815 26.82-6.935 6.995-16.645 10.54-28.85 10.54z"
+        android:fillColor="#E8E9EB"/>
+    <path android:pathData="M253.87 83h-5.245a40.45 40.45 0 0 1 5-18c4.605-8.21 14.4-18 34.96-18v5.215c-14.465 0-24.685 5.17-30.385 15.36A35.345 35.345 0 0 0 253.87 83z"
+        android:fillColor="#34A751"/>
+    <path android:pathData="M254.61 94.5h-90.72V32.325a2.65 2.65 0 0 1 2.64-2.64h85.44a2.65 2.65 0 0 1 2.64 2.64V94.5z"
+        android:fillColor="#F8F9FA"/>
+    <path android:pathData="M250.29 30.225A3.785 3.785 0 0 1 254.07 34v59.945h-89.64V34a3.785 3.785 0 0 1 3.78-3.78h82.08m0-0.54h-82.08a4.335 4.335 0 0 0-4.32 4.32v60.5h90.72V34a4.335 4.335 0 0 0-4.32-4.32zm-99.36 68.585h116.64v0.54H150.93v-0.54zM56 57.915H38.175v-0.27a8.91 8.91 0 0 1 17.82 0L56 57.915zm-17.275-0.54H55.45a8.37 8.37 0 0 0-16.73 0h0.005z"
+        android:fillColor="#BDC0C5"/>
+    <path android:pathData="M335 88.66h20v4h-20z"
+        android:fillColor="#E8E9EB"/>
+    <path android:pathData="M338.268 98.32l10-17.32 3.464 2-10 17.32z"
+        android:fillColor="#E8E9EB"/>
+    <path android:pathData="M348.268 100.32l-10-17.32 3.464-2 10 17.32z"
+        android:fillColor="#E8E9EB"/>
+    <path android:pathData="M118 18h56a6 6 0 0 1 6 6v80a6 6 0 0 1-6 6h-56a6 6 0 0 1-6-6V24a6 6 0 0 1 6-6z"
+        android:strokeWidth=".5"
+        android:fillColor="#F8F9FA"
+        android:strokeColor="#BDC0C5"/>
+    <path android:pathData="M124 65h12v2h-12z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M126.134 70.696l6-10.392 1.732 1-6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M132.134 71.696l-6-10.392 1.732-1 6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M140 65h12v2h-12z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M142.134 70.696l6-10.392 1.732 1-6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M148.134 71.696l-6-10.392 1.732-1 6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M156 65h12v2h-12z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M158.134 70.696l6-10.392 1.732 1-6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M164.134 71.696l-6-10.392 1.732-1 6 10.392z"
+        android:fillColor="#4285F4"/>
+    <path android:pathData="M124.5 85h13a0.5 0.5 0 0 1 0.5 0.5 0.5 0.5 0 0 1-0.5 0.5h-13a0.5 0.5 0 0 1-0.5-0.5 0.5 0.5 0 0 1 0.5-0.5z"
+        android:fillColor="#BDC0C5"/>
+    <path android:pathData="M124.5 43h15a0.5 0.5 0 0 1 0.5 0.5 0.5 0.5 0 0 1-0.5 0.5h-15a0.5 0.5 0 0 1-0.5-0.5 0.5 0.5 0 0 1 0.5-0.5z"
+        android:fillColor="#BDC0C5"/>
+    <path android:pathData="M124.5 50h27a0.5 0.5 0 0 1 0.5 0.5 0.5 0.5 0 0 1-0.5 0.5h-27a0.5 0.5 0 0 1-0.5-0.5 0.5 0.5 0 0 1 0.5-0.5z"
+        android:fillColor="#BDC0C5"/>
+    <path android:pathData="M146 10a7 7 0 0 1 7 7v7h-14v-7a7 7 0 0 1 7-7z"
+        android:strokeWidth=".5"
+        android:fillColor="#F8F9FA"
+        android:strokeColor="#BDC0C5"/>
+    <path android:pathData="M143 17a3 3 0 1 1 6 0 3 3 0 1 1-6 0"
+        android:strokeWidth=".5"
+        android:fillColor="#F8F9FA"
+        android:strokeColor="#BDC0C5"/>
+    <path android:pathData="M162 24h-32a6 6 0 0 0-6 6v4h44v-4a6 6 0 0 0-6-6z"
+        android:strokeWidth=".5"
+        android:fillColor="#F8F9FA"
+        android:strokeColor="#BDC0C5"/>
+    <path android:pathData="M79.6 58.42a12.935 12.935 0 0 0-10.1 4.82A8.62 8.62 0 0 0 58 71.38h34.56c0-7.158-5.802-12.96-12.96-12.96z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M92.83 71.65h-35.1v-0.27a8.89 8.89 0 0 1 11.695-8.455A13.23 13.23 0 0 1 92.83 71.38v0.27zm-34.555-0.54h34a12.69 12.69 0 0 0-22.56-7.7l-0.12 0.15-0.18-0.065A8.35 8.35 0 0 0 58.26 71.11h0.015z"
+        android:fillColor="#BDC0C5"/>
+    <path android:pathData="M38.12 82.36l3.705-3.705c7.59 7.59 15.69 11.43 24.075 11.41 13.17-0.03 22.855-9.655 22.95-9.75l3.735 3.675c-0.45 0.46-11.235 11.25-26.61 11.315C56.12 95.345 46.75 91 38.12 82.36z"
+        android:fillColor="#F7BB2A"/>
+    <path android:pathData="M-8.2 79.58l-3.705-3.705a40.45 40.45 0 0 1 16.25-9.18c9.075-2.57 22.945-2.58 37.5 11.96L38.14 82.36C27.89 72.13 17 68.555 5.77 71.735A35.345 35.345 0 0 0-8.2 79.58z"
+        android:fillColor="#E8E9EB"/>
+    <path android:pathData="M197.889 56c1.165 0.002 2.11 1.075 2.111 2.4v19.2c-0.001 1.325-0.946 2.398-2.111 2.4H126.11c-1.165-0.002-2.11-1.075-2.111-2.4V58.4c0.001-1.325 0.946-2.398 2.111-2.4h71.778z"
+        android:fillColor="#3A7BEE"/>
+    <path android:pathData="M179.75 56H198a2 2 0 0 1 2 2v20a2 2 0 0 1-2 2h-18.25V56z"
+        android:fillColor="#1967D2"
+        android:fillType="evenOdd"/>
+    <path android:pathData="M191 62a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1 1 1 0 0 1-1-1V63a1 1 0 0 1 1-1z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M132 67h10v2h-10z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M133.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M138.634 72.83l-5-8.66 1.732-1 5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M146 67h10v2h-10z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M147.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M152.634 72.83l-5-8.66 1.732-1 5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M160 67h10v2h-10z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M161.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M166.634 72.83l-5-8.66 1.732-1 5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M174 67h10v2h-10z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M175.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M180.634 72.83l-5-8.66 1.732-1 5 8.66z"
+        android:fillColor="#FFF"/>
+</vector>
+
diff --git a/chrome/browser/password_check/android/java/res/layout/password_check_preference_button.xml b/chrome/browser/password_check/android/java/res/layout/password_check_preference_button.xml
new file mode 100644
index 0000000..d6e3bd4
--- /dev/null
+++ b/chrome/browser/password_check/android/java/res/layout/password_check_preference_button.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<!-- Layout for a preference with a title and a compound drawable above. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/PreferenceLayout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:orientation="vertical"
+    android:scaleType="center">
+  <ImageView android:id="@+id/password_check_preference_image"
+      android:importantForAccessibility="no"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:layout_marginBottom ="12dp"
+      android:background="@color/password_check_neutral_background"
+      android:src="@drawable/password_check_neutral"
+      android:visibility="visible"/>
+  <TextView
+      android:id="@android:id/title"
+      style="@style/PreferenceTitle"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"/>
+  <TextView
+      android:id="@android:id/summary"
+      style="@style/PreferenceSummary"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"/>
+</LinearLayout>
+
diff --git a/chrome/browser/password_check/android/java/res/values-night/colors.xml b/chrome/browser/password_check/android/java/res/values-night/colors.xml
new file mode 100644
index 0000000..79f91f9bb
--- /dev/null
+++ b/chrome/browser/password_check/android/java/res/values-night/colors.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file.
+-->
+<resources>
+  <color name="password_check_neutral_background">@color/header_background_dark</color>
+</resources>
diff --git a/chrome/browser/password_check/android/java/res/values/colors.xml b/chrome/browser/password_check/android/java/res/values/colors.xml
new file mode 100644
index 0000000..f0be79f8
--- /dev/null
+++ b/chrome/browser/password_check/android/java/res/values/colors.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file.
+-->
+<resources>
+  <color name="password_check_neutral_background">@color/modern_grey_50</color>
+</resources>
diff --git a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckPreference.java b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckPreference.java
new file mode 100644
index 0000000..d7380d2
--- /dev/null
+++ b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckPreference.java
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.password_check;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * A {@link Preference} customized for the password check button in the password settings menu.
+ */
+public class PasswordCheckPreference extends Preference {
+    private final boolean mShowImage;
+
+    /**
+     * Constructor for inflating from XML.
+     */
+    public PasswordCheckPreference(Context context, boolean showImage) {
+        super(context, null);
+        setLayoutResource(R.layout.password_check_preference_button);
+        mShowImage = showImage;
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        holder.findViewById(R.id.password_check_preference_image)
+                .setVisibility(mShowImage ? View.VISIBLE : View.GONE);
+    }
+
+    @VisibleForTesting
+    public ImageView getPromoImageView(Activity activity) {
+        return activity.findViewById(R.id.password_check_preference_image);
+    }
+}
diff --git a/chrome/browser/password_manager/android/credential_leak_controller_android.cc b/chrome/browser/password_manager/android/credential_leak_controller_android.cc
index 8831995b..0c87da7 100644
--- a/chrome/browser/password_manager/android/credential_leak_controller_android.cc
+++ b/chrome/browser/password_manager/android/credential_leak_controller_android.cc
@@ -20,10 +20,12 @@
 
 CredentialLeakControllerAndroid::CredentialLeakControllerAndroid(
     password_manager::CredentialLeakType leak_type,
+    password_manager::CompromisedSitesCount saved_sites,
     const GURL& origin,
     const base::string16& username,
     ui::WindowAndroid* window_android)
     : leak_type_(leak_type),
+      saved_sites_(saved_sites),
       origin_(origin),
       username_(username),
       window_android_(window_android) {}
@@ -94,6 +96,11 @@
 }
 
 base::string16 CredentialLeakControllerAndroid::GetDescription() const {
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::kPasswordCheck)) {
+    return password_manager::GetDescriptionWithCount(leak_type_, origin_,
+                                                     saved_sites_);
+  }
   return password_manager::GetDescription(leak_type_, origin_);
 }
 
diff --git a/chrome/browser/password_manager/android/credential_leak_controller_android.h b/chrome/browser/password_manager/android/credential_leak_controller_android.h
index 8f6a7d8..f62dacd 100644
--- a/chrome/browser/password_manager/android/credential_leak_controller_android.h
+++ b/chrome/browser/password_manager/android/credential_leak_controller_android.h
@@ -23,6 +23,7 @@
  public:
   CredentialLeakControllerAndroid(
       password_manager::CredentialLeakType leak_type,
+      password_manager::CompromisedSitesCount saved_sites,
       const GURL& origin,
       const base::string16& username,
       ui::WindowAndroid* window_android);
@@ -70,6 +71,7 @@
  private:
   // Used to customize the UI.
   const password_manager::CredentialLeakType leak_type_;
+  const password_manager::CompromisedSitesCount saved_sites_;
 
   const GURL origin_;
 
diff --git a/chrome/browser/password_manager/android/credential_leak_controller_android_unittest.cc b/chrome/browser/password_manager/android/credential_leak_controller_android_unittest.cc
index 32795d4b5..0d66ef5 100644
--- a/chrome/browser/password_manager/android/credential_leak_controller_android_unittest.cc
+++ b/chrome/browser/password_manager/android/credential_leak_controller_android_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "components/password_manager/core/browser/compromised_credentials_table.h"
 #include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -27,8 +28,8 @@
                                                 IsSyncing is_syncing) {
   return new CredentialLeakControllerAndroid(
       CreateLeakType(is_saved, is_reused, is_syncing),
-      GURL("https://example.com"), base::ASCIIToUTF16("test_username"),
-      nullptr);
+      password_manager::CompromisedSitesCount(0), GURL("https://example.com"),
+      base::ASCIIToUTF16("test_username"), nullptr);
 }
 
 }  // namespace
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 80c2030..e861f5a 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -541,6 +541,7 @@
 
 void ChromePasswordManagerClient::NotifyUserCredentialsWereLeaked(
     password_manager::CredentialLeakType leak_type,
+    password_manager::CompromisedSitesCount saved_sites,
     const GURL& origin,
     const base::string16& username) {
 #if defined(OS_ANDROID)
@@ -550,7 +551,8 @@
   }
   HideSavePasswordInfobar(web_contents());
   (new CredentialLeakControllerAndroid(
-       leak_type, origin, username, web_contents()->GetTopLevelNativeWindow()))
+       leak_type, saved_sites, origin, username,
+       web_contents()->GetTopLevelNativeWindow()))
       ->ShowDialog();
 #else   // !defined(OS_ANDROID)
   PasswordsClientUIDelegate* manage_passwords_ui_controller =
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index cd09cf0..8a4619b5 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -141,6 +141,7 @@
       const password_manager::PasswordFormManagerForUI* form_manager) override;
   void NotifyUserCredentialsWereLeaked(
       password_manager::CredentialLeakType leak_type,
+      password_manager::CompromisedSitesCount saved_sites,
       const GURL& origin,
       const base::string16& username) override;
   void TriggerReauthForPrimaryAccount(
diff --git a/chrome/browser/performance_manager/decorators/process_metrics_decorator.h b/chrome/browser/performance_manager/decorators/process_metrics_decorator.h
index 13e9b78..4c14deb2 100644
--- a/chrome/browser/performance_manager/decorators/process_metrics_decorator.h
+++ b/chrome/browser/performance_manager/decorators/process_metrics_decorator.h
@@ -26,6 +26,10 @@
   void SetGraphForTesting(Graph* graph) { graph_ = graph; }
   bool IsTimerRunningForTesting() const { return refresh_timer_.IsRunning(); }
 
+  base::TimeDelta GetTimerDelayForTesting() const {
+    return refresh_timer_.GetCurrentDelay();
+  }
+
  protected:
   // Starts/Stop the timer responsible for refreshing the process nodes metrics.
   void StartTimer();
diff --git a/chrome/browser/performance_manager/decorators/process_metrics_decorator_unittest.cc b/chrome/browser/performance_manager/decorators/process_metrics_decorator_unittest.cc
index 35820643..0f01156 100644
--- a/chrome/browser/performance_manager/decorators/process_metrics_decorator_unittest.cc
+++ b/chrome/browser/performance_manager/decorators/process_metrics_decorator_unittest.cc
@@ -150,7 +150,7 @@
   EXPECT_CALL(sys_node_observer, OnProcessMemoryMetricsAvailable(testing::_));
 
   // Advance the timer, this should trigger a refresh of the metrics.
-  task_env().FastForwardBy(base::TimeDelta::FromMinutes(2));
+  task_env().FastForwardBy(decorator()->GetTimerDelayForTesting());
 
   EXPECT_EQ(kFakeResidentSetKb, mock_graph()->process->resident_set_kb());
   EXPECT_EQ(kFakePrivateFootprintKb,
@@ -173,7 +173,7 @@
       .WillOnce(
           testing::Return(testing::ByMove(std::move(partial_memory_dump))));
 
-  task_env().FastForwardBy(base::TimeDelta::FromMinutes(2));
+  task_env().FastForwardBy(decorator()->GetTimerDelayForTesting());
 
   EXPECT_EQ(kFakeResidentSetKb, mock_graph()->process->resident_set_kb());
   EXPECT_EQ(kFakePrivateFootprintKb,
@@ -188,7 +188,7 @@
       .WillOnce(
           testing::Return(testing::ByMove(std::move(partial_memory_dump2))));
 
-  task_env().FastForwardBy(base::TimeDelta::FromMinutes(2));
+  task_env().FastForwardBy(decorator()->GetTimerDelayForTesting());
 
   EXPECT_EQ(kFakeResidentSetKb, mock_graph()->process->resident_set_kb());
   EXPECT_EQ(kFakePrivateFootprintKb,
@@ -204,7 +204,7 @@
   EXPECT_CALL(*decorator(), GetMemoryDump())
       .WillOnce(testing::Return(testing::ByMove(base::nullopt)));
 
-  task_env().FastForwardBy(base::TimeDelta::FromMinutes(2));
+  task_env().FastForwardBy(decorator()->GetTimerDelayForTesting());
 
   EXPECT_EQ(0U, mock_graph()->process->resident_set_kb());
   EXPECT_EQ(0U, mock_graph()->process->private_footprint_kb());
diff --git a/chrome/browser/performance_manager/policies/policy_features.cc b/chrome/browser/performance_manager/policies/policy_features.cc
index 823ab3c..035f342 100644
--- a/chrome/browser/performance_manager/policies/policy_features.cc
+++ b/chrome/browser/performance_manager/policies/policy_features.cc
@@ -81,8 +81,13 @@
     "PageFreezingFromPerformanceManager", base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kUrgentDiscardingFromPerformanceManager{
-    "UrgentDiscardingFromPerformanceManager",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+  "UrgentDiscardingFromPerformanceManager",
+#if defined(OS_CHROMEOS)
+      base::FEATURE_DISABLED_BY_DEFAULT
+#else
+      base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+};
 
 UrgentDiscardingParams::UrgentDiscardingParams() = default;
 UrgentDiscardingParams::UrgentDiscardingParams(
diff --git a/chrome/browser/performance_manager/policies/policy_features.h b/chrome/browser/performance_manager/policies/policy_features.h
index a96f2d8..3e436e7 100644
--- a/chrome/browser/performance_manager/policies/policy_features.h
+++ b/chrome/browser/performance_manager/policies/policy_features.h
@@ -92,7 +92,8 @@
   // Integer values are specified to allow conversion from the integer value in
   // the DiscardStrategy feature param.
   enum class DiscardStrategy : int {
-    // Discards the least recently used tab among the eligible ones.
+    // Discards the least recently used tab among the eligible ones. This is the
+    // default strategy.
     LRU = 0,
     // Discard the tab with the biggest resident set among the eligible ones.
     BIGGEST_RSS = 1,
@@ -102,7 +103,7 @@
 
   static constexpr base::FeatureParam<int> kDiscardStrategy{
       &features::kUrgentDiscardingFromPerformanceManager, "DiscardStrategy",
-      static_cast<int>(DiscardStrategy::BIGGEST_RSS)};
+      static_cast<int>(DiscardStrategy::LRU)};
 
  private:
   UrgentDiscardingParams();
diff --git a/chrome/browser/platform_util_unittest.cc b/chrome/browser/platform_util_unittest.cc
index 4ca9f11..2632c152 100644
--- a/chrome/browser/platform_util_unittest.cc
+++ b/chrome/browser/platform_util_unittest.cc
@@ -201,11 +201,11 @@
  private:
   std::unique_ptr<base::RunLoop> run_loop_;
 
-  static void OnOpenOperationDone(const base::Closure& closure,
+  static void OnOpenOperationDone(base::OnceClosure closure,
                                   OpenOperationResult* store_result,
                                   OpenOperationResult result) {
     *store_result = result;
-    closure.Run();
+    std::move(closure).Run();
   }
 };
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index daceb15..56ff87f 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -58,7 +58,6 @@
 #include "chrome/browser/prefs/origin_trial_prefs.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/previews/previews_https_notification_infobar_decider.h"
-#include "chrome/browser/previews/previews_offline_helper.h"
 #include "chrome/browser/printing/print_preview_sticky_settings.h"
 #include "chrome/browser/profiles/chrome_version_service.h"
 #include "chrome/browser/profiles/profile.h"
@@ -561,6 +560,9 @@
 const char kStricterMixedContentTreatmentEnabled[] =
     "security_state.stricter_mixed_content_treatment_enabled";
 
+// Deprecated 7/2020
+const char kHashedAvailablePages[] = "previews.offline_helper.available_pages";
+
 // Register local state used only for migration (clearing or moving to a new
 // key).
 void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
@@ -665,6 +667,8 @@
   registry->RegisterDictionaryPref(kPreviewsLPROriginProbeCache);
 
   registry->RegisterBooleanPref(kStricterMixedContentTreatmentEnabled, true);
+
+  registry->RegisterDictionaryPref(kHashedAvailablePages);
 }
 
 }  // namespace
@@ -911,7 +915,6 @@
   PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry);
   PrefsTabHelper::RegisterProfilePrefs(registry, locale);
   PreviewsHTTPSNotificationInfoBarDecider::RegisterProfilePrefs(registry);
-  PreviewsOfflineHelper::RegisterProfilePrefs(registry);
   Profile::RegisterProfilePrefs(registry);
   ProfileImpl::RegisterProfilePrefs(registry);
   ProfileNetworkContextService::RegisterProfilePrefs(registry);
@@ -1317,4 +1320,7 @@
 
   // Added 6/2020
   profile_prefs->ClearPref(kStricterMixedContentTreatmentEnabled);
+
+  // Added 7/2020.
+  profile_prefs->ClearPref(kHashedAvailablePages);
 }
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 25d856b..ac02525 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -30,10 +30,7 @@
 #include "base/test/simple_test_tick_clock.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/thread_restrictions.h"
-//#include "base/values.h"
 #include "build/build_config.h"
-//#include
-//"chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
@@ -376,8 +373,7 @@
 class PrerenderBrowserTest : public test_utils::PrerenderInProcessBrowserTest {
  public:
   PrerenderBrowserTest()
-      : call_javascript_(true),
-        check_load_events_(true),
+      : check_load_events_(true),
         loader_path_("/prerender/prerender_loader.html") {}
 
   ~PrerenderBrowserTest() override {}
@@ -468,18 +464,6 @@
     OpenURLWithJSImpl("ClickPing", dest_url_, ping_url, false);
   }
 
-  void OpenDestURLViaClickNewWindow() const {
-    OpenURLWithJSImpl("ShiftClick", dest_url_, GURL(), true);
-  }
-
-  void OpenDestURLViaClickNewForegroundTab() const {
-#if defined(OS_MACOSX)
-    OpenURLWithJSImpl("MetaShiftClick", dest_url_, GURL(), true);
-#else
-    OpenURLWithJSImpl("CtrlShiftClick", dest_url_, GURL(), true);
-#endif
-  }
-
   void OpenDestURLViaWindowOpen() const { OpenURLViaWindowOpen(dest_url_); }
 
   void OpenURLViaWindowOpen(const GURL& url) const {
@@ -520,10 +504,6 @@
     EXPECT_TRUE(original_prerender_page);
   }
 
-  void DisableJavascriptCalls() { call_javascript_ = false; }
-
-  void EnableJavascriptCalls() { call_javascript_ = true; }
-
   void DisableLoadEventCheck() { check_load_events_ = false; }
 
   const PrerenderLinkManager* GetPrerenderLinkManager() const {
@@ -614,14 +594,8 @@
     return GetPrerenderLinkManager()->CountRunningPrerenders();
   }
 
-  void SetLoaderHostOverride(const std::string& host) {
-    loader_host_override_ = host;
-  }
-
   void set_loader_path(const std::string& path) { loader_path_ = path; }
 
-  void set_loader_query(const std::string& query) { loader_query_ = query; }
-
   GURL GetCrossDomainTestUrl(const std::string& path) {
     static const std::string secondary_domain = "www.foo.com";
     std::string url_str(base::StringPrintf(
@@ -712,11 +686,7 @@
     dest_url_ = prerender_url;
 
     GURL loader_url = ServeLoaderURL(loader_path_, "REPLACE_WITH_PRERENDER_URL",
-                                     prerender_url, "&" + loader_query_);
-    GURL::Replacements loader_replacements;
-    if (!loader_host_override_.empty())
-      loader_replacements.SetHostStr(loader_host_override_);
-    loader_url = loader_url.ReplaceComponents(loader_replacements);
+                                     prerender_url, "");
 
     std::vector<std::unique_ptr<TestPrerender>> prerenders =
         NavigateWithPrerenders(loader_url, expected_final_status_queue);
@@ -742,11 +712,6 @@
       CHECK(prerender_contents);
       EXPECT_EQ(FINAL_STATUS_UNKNOWN, prerender_contents->final_status());
       EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(0));
-
-      if (call_javascript_) {
-        // Check if page behaves as expected while in prerendered state.
-        EXPECT_TRUE(DidPrerenderPass(prerender_contents->prerender_contents()));
-      }
     }
 
     // Test for proper event ordering.
@@ -775,8 +740,6 @@
 
     if (web_contents && expect_swap_to_succeed) {
       EXPECT_EQ(web_contents, target_web_contents);
-      if (call_javascript_)
-        EXPECT_TRUE(DidDisplayPass(web_contents));
     }
   }
 
@@ -813,11 +776,8 @@
   base::SimpleTestTickClock clock_;
 
   GURL dest_url_;
-  bool call_javascript_;
   bool check_load_events_;
-  std::string loader_host_override_;
   std::string loader_path_;
-  std::string loader_query_;
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<content::URLLoaderInterceptor> interceptor_;
 };
@@ -865,28 +825,6 @@
   NavigateToDestURL();
 }
 
-// Checks that renderers using excessive memory will be terminated.
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderExcessiveMemory) {
-  ASSERT_TRUE(GetPrerenderManager());
-  GetPrerenderManager()->mutable_config().max_bytes = 30 * 1024 * 1024;
-  // The excessive memory kill may happen before or after the load event as it
-  // happens asynchronously with IPC calls. Even if the test does not start
-  // allocating until after load, the browser process might notice before the
-  // message gets through. This happens on XP debug bots because they're so
-  // slow. Instead, don't bother checking the load event count.
-  DisableLoadEventCheck();
-  PrerenderTestURL("/prerender/prerender_excessive_memory.html",
-                   FINAL_STATUS_MEMORY_LIMIT_EXCEEDED, 0);
-}
-
-// Checks shutdown code while a prerender is active.
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderQuickQuit) {
-  DisableJavascriptCalls();
-  DisableLoadEventCheck();
-  PrerenderTestURL("/prerender/prerender_page.html",
-                   FINAL_STATUS_APP_TERMINATING, 0);
-}
-
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, OpenTaskManagerBeforePrerender) {
   const base::string16 any_prerender = MatchTaskManagerPrerender("*");
   const base::string16 any_tab = MatchTaskManagerTab("*");
@@ -956,53 +894,6 @@
   ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, any_prerender));
 }
 
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderCancelAll) {
-  std::unique_ptr<TestPrerender> prerender = PrerenderTestURL(
-      "/prerender/prerender_page.html", FINAL_STATUS_CANCELLED, 1);
-
-  GetPrerenderManager()->CancelAllPrerenders();
-  prerender->WaitForStop();
-
-  EXPECT_FALSE(prerender->contents());
-}
-
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderEvents) {
-  std::unique_ptr<TestPrerender> prerender = PrerenderTestURL(
-      "/prerender/prerender_page.html", FINAL_STATUS_CANCELLED, 1);
-
-  GetPrerenderManager()->CancelAllPrerenders();
-  prerender->WaitForStop();
-
-  WaitForPrerenderStartEventForLinkNumber(0);
-  WaitForPrerenderStopEventForLinkNumber(0);
-  EXPECT_FALSE(HadPrerenderEventErrors());
-}
-
-// Cancels the prerender of a page with its own prerender.  The second prerender
-// should never be started.
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
-                       PrerenderCancelPrerenderWithPrerender) {
-  std::unique_ptr<TestPrerender> prerender = PrerenderTestURL(
-      "/prerender/prerender_infinite_a.html", FINAL_STATUS_CANCELLED, 1);
-
-  GetPrerenderManager()->CancelAllPrerenders();
-  prerender->WaitForStop();
-
-  EXPECT_FALSE(prerender->contents());
-}
-
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderClickNewWindow) {
-  PrerenderTestURL("/prerender/prerender_page_with_link.html",
-                   FINAL_STATUS_APP_TERMINATING, 1);
-  OpenDestURLViaClickNewWindow();
-}
-
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderClickNewForegroundTab) {
-  PrerenderTestURL("/prerender/prerender_page_with_link.html",
-                   FINAL_STATUS_APP_TERMINATING, 1);
-  OpenDestURLViaClickNewForegroundTab();
-}
-
 // Checks that the referrer policy is used when prerendering.
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderReferrerPolicy) {
   set_loader_path("/prerender/prerender_loader_with_referrer_policy.html");
diff --git a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
index f54a382..942ba32 100644
--- a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
+++ b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/task_manager/task_manager_browsertest_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -44,6 +45,8 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/result_codes.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test.h"
@@ -119,6 +122,137 @@
 const char kPrefetchSubresourceRedirectPage[] =
     "/prerender/prefetch_subresource_redirect.html";
 const char kServiceWorkerLoader[] = "/prerender/service_worker.html";
+const char kHungPrerenderPage[] = "/prerender/hung_prerender_page.html";
+
+// A navigation observer to wait on either a new load or a swap of a
+// WebContents. On swap, if the new WebContents is still loading, wait for that
+// load to complete as well. Note that the load must begin after the observer is
+// attached.
+class NavigationOrSwapObserver : public content::WebContentsObserver,
+                                 public TabStripModelObserver {
+ public:
+  // Waits for either a new load or a swap of |tab_strip_model|'s active
+  // WebContents.
+  NavigationOrSwapObserver(TabStripModel* tab_strip_model,
+                           content::WebContents* web_contents)
+      : content::WebContentsObserver(web_contents),
+        tab_strip_model_(tab_strip_model),
+        did_start_loading_(false),
+        number_of_loads_(1) {
+    EXPECT_NE(TabStripModel::kNoTab,
+              tab_strip_model->GetIndexOfWebContents(web_contents));
+    tab_strip_model_->AddObserver(this);
+  }
+
+  // Waits for either |number_of_loads| loads or a swap of |tab_strip_model|'s
+  // active WebContents.
+  NavigationOrSwapObserver(TabStripModel* tab_strip_model,
+                           content::WebContents* web_contents,
+                           int number_of_loads)
+      : content::WebContentsObserver(web_contents),
+        tab_strip_model_(tab_strip_model),
+        did_start_loading_(false),
+        number_of_loads_(number_of_loads) {
+    EXPECT_NE(TabStripModel::kNoTab,
+              tab_strip_model->GetIndexOfWebContents(web_contents));
+    tab_strip_model_->AddObserver(this);
+  }
+
+  ~NavigationOrSwapObserver() override {
+    tab_strip_model_->RemoveObserver(this);
+  }
+
+  void set_did_start_loading() { did_start_loading_ = true; }
+
+  void Wait() { loop_.Run(); }
+
+  // content::WebContentsObserver implementation:
+  void DidStartLoading() override { did_start_loading_ = true; }
+  void DidStopLoading() override {
+    if (!did_start_loading_)
+      return;
+    number_of_loads_--;
+    if (number_of_loads_ == 0)
+      loop_.Quit();
+  }
+
+  // TabStripModelObserver implementation:
+  void OnTabStripModelChanged(
+      TabStripModel* tab_strip_model,
+      const TabStripModelChange& change,
+      const TabStripSelectionChange& selection) override {
+    if (change.type() != TabStripModelChange::kReplaced)
+      return;
+
+    auto* replace = change.GetReplace();
+    if (replace->old_contents != web_contents())
+      return;
+
+    // Switch to observing the new WebContents.
+    Observe(replace->new_contents);
+    if (replace->new_contents->IsLoading()) {
+      // If the new WebContents is still loading, wait for it to complete.
+      // Only one load post-swap is supported.
+      did_start_loading_ = true;
+      number_of_loads_ = 1;
+    } else {
+      loop_.Quit();
+    }
+  }
+
+ private:
+  TabStripModel* tab_strip_model_;
+  bool did_start_loading_;
+  int number_of_loads_;
+  base::RunLoop loop_;
+};
+
+// Waits for a new tab to open and a navigation or swap in it.
+class NewTabNavigationOrSwapObserver : public TabStripModelObserver,
+                                       public BrowserListObserver {
+ public:
+  NewTabNavigationOrSwapObserver() {
+    BrowserList::AddObserver(this);
+    for (const Browser* browser : *BrowserList::GetInstance())
+      browser->tab_strip_model()->AddObserver(this);
+  }
+
+  ~NewTabNavigationOrSwapObserver() override {
+    BrowserList::RemoveObserver(this);
+  }
+
+  void Wait() {
+    new_tab_run_loop_.Run();
+    swap_observer_->Wait();
+  }
+
+  // TabStripModelObserver:
+  void OnTabStripModelChanged(
+      TabStripModel* tab_strip_model,
+      const TabStripModelChange& change,
+      const TabStripSelectionChange& selection) override {
+    if (change.type() != TabStripModelChange::kInserted || swap_observer_)
+      return;
+
+    content::WebContents* new_tab = change.GetInsert()->contents[0].contents;
+    swap_observer_ =
+        std::make_unique<NavigationOrSwapObserver>(tab_strip_model, new_tab);
+    swap_observer_->set_did_start_loading();
+
+    new_tab_run_loop_.Quit();
+  }
+
+  // BrowserListObserver:
+  void OnBrowserAdded(Browser* browser) override {
+    browser->tab_strip_model()->AddObserver(this);
+  }
+
+ private:
+  base::RunLoop new_tab_run_loop_;
+  std::unique_ptr<NavigationOrSwapObserver> swap_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(NewTabNavigationOrSwapObserver);
+};
 
 class NoStatePrefetchBrowserTest
     : public test_utils::PrerenderInProcessBrowserTest {
@@ -176,22 +310,69 @@
   // test server.
   std::unique_ptr<TestPrerender> PrefetchFromURL(
       const GURL& target_url,
-      FinalStatus expected_final_status) {
+      FinalStatus expected_final_status,
+      int expected_number_of_loads = 0) {
     GURL loader_url = ServeLoaderURL(
         kPrefetchLoaderPath, "REPLACE_WITH_PREFETCH_URL", target_url, "");
     std::vector<FinalStatus> expected_final_status_queue(1,
                                                          expected_final_status);
     std::vector<std::unique_ptr<TestPrerender>> prerenders =
         NavigateWithPrerenders(loader_url, expected_final_status_queue);
-    prerenders[0]->WaitForStop();
+    prerenders[0]->WaitForLoads(0);
+
+    // Ensure that the referring page receives the right start and load events.
+    WaitForPrerenderStartEventForLinkNumber(0);
+    if (check_load_events_) {
+      WaitForPrerenderEventCount(0, "webkitprerenderload",
+                                 expected_number_of_loads);
+    }
+
+    if (ShouldAbortPrerenderBeforeSwap(expected_final_status_queue.front())) {
+      // The prerender will abort on its own. Assert it does so correctly.
+      prerenders[0]->WaitForStop();
+      EXPECT_FALSE(prerenders[0]->contents());
+      WaitForPrerenderStopEventForLinkNumber(0);
+    } else {
+      // Otherwise, check that it prerendered correctly.
+      test_utils::TestPrerenderContents* prerender_contents =
+          prerenders[0]->contents();
+      if (prerender_contents) {
+        EXPECT_EQ(FINAL_STATUS_UNKNOWN, prerender_contents->final_status());
+        EXPECT_FALSE(DidReceivePrerenderStopEventForLinkNumber(0));
+      }
+    }
+
+    // Test for proper event ordering.
+    EXPECT_FALSE(HadPrerenderEventErrors());
+
     return std::move(prerenders[0]);
   }
 
+  // Returns true if the prerender is expected to abort on its own, before
+  // attempting to swap it.
+  bool ShouldAbortPrerenderBeforeSwap(FinalStatus status) {
+    switch (status) {
+      case FINAL_STATUS_USED:
+      case FINAL_STATUS_APP_TERMINATING:
+      case FINAL_STATUS_PROFILE_DESTROYED:
+      case FINAL_STATUS_CACHE_OR_HISTORY_CLEARED:
+      // We'll crash the renderer after it's loaded.
+      case FINAL_STATUS_RENDERER_CRASHED:
+      case FINAL_STATUS_CANCELLED:
+        return false;
+      default:
+        return true;
+    }
+  }
+
+  void DisableLoadEventCheck() { check_load_events_ = false; }
+
   std::unique_ptr<TestPrerender> PrefetchFromFile(
       const std::string& html_file,
-      FinalStatus expected_final_status) {
-    return PrefetchFromURL(src_server()->GetURL(html_file),
-                           expected_final_status);
+      FinalStatus expected_final_status,
+      int expected_number_of_loads = 0) {
+    return PrefetchFromURL(src_server()->GetURL(MakeAbsolute(html_file)),
+                           expected_final_status, expected_number_of_loads);
   }
 
   // Returns length of |prerender_manager_|'s history, or SIZE_MAX on failure.
@@ -218,6 +399,110 @@
     // BrowsingDataRemover deletes itself.
   }
 
+  // Synchronization note: The IPCs used to communicate DOM events back to the
+  // referring web page (see blink::mojom::PrerenderHandleClient) may race w/
+  // the IPCs used here to inject script. The WaitFor* variants should be used
+  // when an event was expected to happen or to happen soon.
+
+  int GetPrerenderEventCount(int index, const std::string& type) const {
+    int event_count;
+    std::string expression = base::StringPrintf(
+        "window.domAutomationController.send("
+        "    GetPrerenderEventCount(%d, '%s'))",
+        index, type.c_str());
+
+    CHECK(content::ExecuteScriptAndExtractInt(GetActiveWebContents(),
+                                              expression, &event_count));
+    return event_count;
+  }
+
+  bool DidReceivePrerenderStartEventForLinkNumber(int index) const {
+    return GetPrerenderEventCount(index, "webkitprerenderstart") > 0;
+  }
+
+  int GetPrerenderLoadEventCountForLinkNumber(int index) const {
+    return GetPrerenderEventCount(index, "webkitprerenderload");
+  }
+
+  bool DidReceivePrerenderStopEventForLinkNumber(int index) const {
+    return GetPrerenderEventCount(index, "webkitprerenderstop") > 0;
+  }
+
+  void WaitForPrerenderEventCount(int index,
+                                  const std::string& type,
+                                  int count) const {
+    int dummy;
+    std::string expression = base::StringPrintf(
+        "WaitForPrerenderEventCount(%d, '%s', %d,"
+        "    window.domAutomationController.send.bind("
+        "        window.domAutomationController, 0))",
+        index, type.c_str(), count);
+
+    CHECK(content::ExecuteScriptAndExtractInt(GetActiveWebContents(),
+                                              expression, &dummy));
+    CHECK_EQ(0, dummy);
+  }
+
+  void WaitForPrerenderStartEventForLinkNumber(int index) const {
+    WaitForPrerenderEventCount(index, "webkitprerenderstart", 1);
+  }
+
+  void WaitForPrerenderStopEventForLinkNumber(int index) const {
+    WaitForPrerenderEventCount(index, "webkitprerenderstart", 1);
+  }
+
+  bool HadPrerenderEventErrors() const {
+    bool had_prerender_event_errors;
+    CHECK(content::ExecuteScriptAndExtractBool(
+        GetActiveWebContents(),
+        "window.domAutomationController.send(Boolean("
+        "    hadPrerenderEventErrors))",
+        &had_prerender_event_errors));
+    return had_prerender_event_errors;
+  }
+
+  // Opens the prerendered page using javascript functions in the loader
+  // page. |javascript_function_name| should be a 0 argument function which is
+  // invoked. |new_web_contents| is true if the navigation is expected to
+  // happen in a new WebContents via OpenURL.
+  void OpenURLWithJSImpl(const std::string& javascript_function_name,
+                         const GURL& url,
+                         const GURL& ping_url,
+                         bool new_web_contents) const {
+    content::WebContents* web_contents = GetActiveWebContents();
+    content::RenderFrameHost* render_frame_host = web_contents->GetMainFrame();
+    // Extra arguments in JS are ignored.
+    std::string javascript =
+        base::StringPrintf("%s('%s', '%s')", javascript_function_name.c_str(),
+                           url.spec().c_str(), ping_url.spec().c_str());
+
+    if (new_web_contents) {
+      NewTabNavigationOrSwapObserver observer;
+      render_frame_host->ExecuteJavaScriptWithUserGestureForTests(
+          base::ASCIIToUTF16(javascript));
+      observer.Wait();
+    } else {
+      NavigationOrSwapObserver observer(current_browser()->tab_strip_model(),
+                                        web_contents);
+      render_frame_host->ExecuteJavaScriptForTests(
+          base::ASCIIToUTF16(javascript), base::NullCallback());
+      observer.Wait();
+    }
+  }
+
+  void OpenDestURLViaClickNewWindow(GURL& dest_url) const {
+    OpenURLWithJSImpl("ShiftClick", dest_url, GURL(), true);
+  }
+
+  void OpenDestURLViaClickNewForegroundTab(GURL& dest_url) const {
+#if defined(OS_MACOSX)
+    OpenURLWithJSImpl("MetaShiftClick", dest_url, GURL(), true);
+#else
+    OpenURLWithJSImpl("CtrlShiftClick", dest_url, GURL(), true);
+#endif
+  }
+
+  bool check_load_events_ = true;
   base::SimpleTestTickClock clock_;
 
  private:
@@ -966,7 +1251,7 @@
                        PrefetchRedirectUnsupportedScheme) {
   PrefetchFromFile(
       CreateServerRedirect("invalidscheme://www.google.com/test.html"),
-      FINAL_STATUS_UNSUPPORTED_SCHEME);
+      FINAL_STATUS_UNSUPPORTED_SCHEME, 1);
 }
 
 // Checks that a 302 redirect is followed.
@@ -1428,7 +1713,7 @@
 // Checks that when the history is cleared, NoStatePrefetch history is cleared.
 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, ClearHistory) {
   std::unique_ptr<TestPrerender> test_prerender = PrefetchFromFile(
-      "/prerender/prerender_page.html", FINAL_STATUS_NOSTATE_PREFETCH_FINISHED);
+      kHungPrerenderPage, FINAL_STATUS_CACHE_OR_HISTORY_CLEARED);
 
   ClearBrowsingData(current_browser(),
                     ChromeBrowsingDataRemoverDelegate::DATA_TYPE_HISTORY);
@@ -1442,15 +1727,80 @@
 // cleared.
 IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, ClearCache) {
   std::unique_ptr<TestPrerender> prerender = PrefetchFromFile(
-      "/prerender/prerender_page.html", FINAL_STATUS_NOSTATE_PREFETCH_FINISHED);
+      kHungPrerenderPage, FINAL_STATUS_CACHE_OR_HISTORY_CLEARED);
 
   ClearBrowsingData(current_browser(),
                     content::BrowsingDataRemover::DATA_TYPE_CACHE);
   prerender->WaitForStop();
 
   // Make sure prerender history was not cleared.  Not a vital behavior, but
-  // used to compare with PrerenderClearHistory test.
+  // used to compare with ClearHistory test.
   EXPECT_EQ(1U, GetHistoryLength());
 }
 
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, CancelAll) {
+  GURL url = src_server()->GetURL(kHungPrerenderPage);
+  std::unique_ptr<TestPrerender> prerender =
+      PrefetchFromURL(url, FINAL_STATUS_CANCELLED, 0);
+
+  GetPrerenderManager()->CancelAllPrerenders();
+  prerender->WaitForStop();
+
+  EXPECT_FALSE(prerender->contents());
+}
+
+// Cancels the prerender of a page with its own prerender.  The second prerender
+// should never be started.
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest,
+                       CancelPrerenderWithPrerender) {
+  GURL url = src_server()->GetURL("/prerender/prerender_infinite_a.html");
+
+  std::unique_ptr<TestPrerender> prerender =
+      PrefetchFromURL(url, FINAL_STATUS_CANCELLED);
+
+  GetPrerenderManager()->CancelAllPrerenders();
+  prerender->WaitForStop();
+
+  EXPECT_FALSE(prerender->contents());
+}
+
+// Checks shutdown code while a prerender is active.
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrerenderQuickQuit) {
+  DisableLoadEventCheck();
+  GURL url = src_server()->GetURL(kHungPrerenderPage);
+  std::unique_ptr<TestPrerender> prerender =
+      PrefetchFromURL(url, FINAL_STATUS_APP_TERMINATING);
+}
+
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrerenderClickNewWindow) {
+  GURL url = src_server()->GetURL("/prerender/prerender_page_with_link.html");
+  std::unique_ptr<TestPrerender> prerender =
+      PrefetchFromURL(url, FINAL_STATUS_NOSTATE_PREFETCH_FINISHED);
+  OpenDestURLViaClickNewWindow(url);
+}
+
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest,
+                       PrerenderClickNewForegroundTab) {
+  GURL url = src_server()->GetURL("/prerender/prerender_page_with_link.html");
+  std::unique_ptr<TestPrerender> prerender =
+      PrefetchFromURL(url, FINAL_STATUS_NOSTATE_PREFETCH_FINISHED);
+
+  OpenDestURLViaClickNewForegroundTab(url);
+}
+
+// Checks that renderers using excessive memory will be terminated.
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, PrerenderExcessiveMemory) {
+  ASSERT_TRUE(GetPrerenderManager());
+  GetPrerenderManager()->mutable_config().max_bytes = 100;
+  // The excessive memory kill may happen before or after the load event as it
+  // happens asynchronously with IPC calls. Even if the test does not start
+  // allocating until after load, the browser process might notice before the
+  // message gets through. This happens on XP debug bots because they're so
+  // slow. Instead, don't bother checking the load event count.
+  DisableLoadEventCheck();
+  PrefetchFromURL(
+      src_server()->GetURL("/prerender/prerender_excessive_memory.html"),
+      FINAL_STATUS_MEMORY_LIMIT_EXCEEDED);
+}
+
 }  // namespace prerender
diff --git a/chrome/browser/previews/android/previews_android_bridge.cc b/chrome/browser/previews/android/previews_android_bridge.cc
index 12cdf21..21530a7 100644
--- a/chrome/browser/previews/android/previews_android_bridge.cc
+++ b/chrome/browser/previews/android/previews_android_bridge.cc
@@ -63,26 +63,6 @@
   return tab_helper->should_display_android_omnibox_badge();
 }
 
-base::android::ScopedJavaLocalRef<jstring>
-PreviewsAndroidBridge::GetStalePreviewTimestamp(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj,
-    const base::android::JavaParamRef<jobject>& j_web_contents) {
-  content::WebContents* web_contents =
-      content::WebContents::FromJavaWebContents(j_web_contents);
-  if (!web_contents)
-    return base::android::ScopedJavaLocalRef<jstring>();
-
-  PreviewsUITabHelper* tab_helper =
-      PreviewsUITabHelper::FromWebContents(web_contents);
-  if (!tab_helper)
-    return base::android::ScopedJavaLocalRef<jstring>();
-
-  return base::android::ScopedJavaLocalRef<jstring>(
-      base::android::ConvertUTF16ToJavaString(
-          env, tab_helper->GetStalePreviewTimestampText()));
-}
-
 void PreviewsAndroidBridge::LoadOriginal(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/previews/android/previews_android_bridge.h b/chrome/browser/previews/android/previews_android_bridge.h
index 9dbc03f..167de00 100644
--- a/chrome/browser/previews/android/previews_android_bridge.h
+++ b/chrome/browser/previews/android/previews_android_bridge.h
@@ -32,11 +32,6 @@
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jobject>& j_web_contents);
 
-  base::android::ScopedJavaLocalRef<jstring> GetStalePreviewTimestamp(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jobject>& j_web_contents);
-
   void LoadOriginal(JNIEnv* env,
                     const base::android::JavaParamRef<jobject>& obj,
                     const base::android::JavaParamRef<jobject>& j_web_contents);
diff --git a/chrome/browser/previews/previews_content_util.cc b/chrome/browser/previews/previews_content_util.cc
index bc2f0fb..8ced5f4 100644
--- a/chrome/browser/previews/previews_content_util.cc
+++ b/chrome/browser/previews/previews_content_util.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h"
-#include "chrome/browser/previews/previews_offline_helper.h"
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/previews/previews_ui_tab_helper.h"
@@ -87,32 +86,11 @@
   if (!is_data_saver_user)
     return previews_state;
 
-  auto* previews_service =
-      navigation_handle && navigation_handle->GetWebContents()
-          ? PreviewsServiceFactory::GetForProfile(Profile::FromBrowserContext(
-                navigation_handle->GetWebContents()->GetBrowserContext()))
-          : nullptr;
-
   if (previews_triggering_logic_already_ran) {
     // Record that the navigation was redirected.
     previews_data->set_is_redirect(true);
   }
 
-  bool allow_offline = true;
-  // If |previews_service| is null, skip the previews offline helper check.
-  // This only happens in testing.
-  if (previews_service) {
-    allow_offline = previews_service->previews_offline_helper()
-                        ->ShouldAttemptOfflinePreview(url);
-  }
-  allow_offline =
-      allow_offline && previews_decider->ShouldAllowPreviewAtNavigationStart(
-                           previews_data, navigation_handle, is_reload,
-                           previews::PreviewsType::OFFLINE);
-
-  if (allow_offline)
-    previews_state |= content::OFFLINE_PAGE_ON;
-
   // Check commit-time preview types first.
   bool allow_commit_time_previews = false;
   if (previews_decider->ShouldAllowPreviewAtNavigationStart(
@@ -133,29 +111,10 @@
     previews_state |= content::NOSCRIPT_ON;
     allow_commit_time_previews = true;
   }
-  bool commit_time_previews_are_available = false;
-  if (allow_commit_time_previews) {
-    commit_time_previews_are_available =
-        previews_decider->AreCommitTimePreviewsAvailable(navigation_handle);
-  }
 
   return previews_state;
 }
 
-content::PreviewsState DetermineCommittedServerPreviewsState(
-    data_reduction_proxy::DataReductionProxyData* data,
-    content::PreviewsState initial_state) {
-  if (!data) {
-    return initial_state &= ~(content::SERVER_LITE_PAGE_ON);
-  }
-  content::PreviewsState updated_state = initial_state;
-  if (!data->lite_page_received()) {
-    // Turn off LitePage bit.
-    updated_state &= ~(content::SERVER_LITE_PAGE_ON);
-  }
-  return updated_state;
-}
-
 void LogCommittedPreview(previews::PreviewsUserData* previews_data,
                          PreviewsType type) {
   net::EffectiveConnectionType navigation_ect = previews_data->navigation_ect();
@@ -221,23 +180,6 @@
     content::PreviewsState previews_state,
     const previews::PreviewsDecider* previews_decider,
     content::NavigationHandle* navigation_handle) {
-  // Check if an offline preview was actually served.
-  if (previews_data && previews_data->offline_preview_used()) {
-    DCHECK(previews_state & content::OFFLINE_PAGE_ON);
-    LogCommittedPreview(previews_data, PreviewsType::OFFLINE);
-    return content::OFFLINE_PAGE_ON;
-  }
-  previews_state &= ~content::OFFLINE_PAGE_ON;
-
-  // If a server preview is set, retain only the bits determined for the server.
-  // |previews_state| must already have been updated for server previews from
-  // the main frame response headers (so if they are set here, then they are
-  // the specify the committed preview).
-  if (previews_state & content::SERVER_LITE_PAGE_ON) {
-    LogCommittedPreview(previews_data, PreviewsType::LITE_PAGE);
-    return previews_state & content::SERVER_LITE_PAGE_ON;
-  }
-
   if (previews_data && previews_data->cache_control_no_transform_directive()) {
     if (HasEnabledPreviews(previews_state)) {
       UMA_HISTOGRAM_ENUMERATION(
@@ -362,42 +304,6 @@
   return content::PREVIEWS_OFF;
 }
 
-content::PreviewsState MaybeCoinFlipHoldbackBeforeCommit(
-    content::PreviewsState initial_state,
-    content::NavigationHandle* navigation_handle) {
-  if (!base::FeatureList::IsEnabled(features::kCoinFlipHoldback))
-    return initial_state;
-
-  // Get PreviewsUserData to store the result of the coin flip. If it can't be
-  // gotten, return early.
-  PreviewsUITabHelper* ui_tab_helper =
-      PreviewsUITabHelper::FromWebContents(navigation_handle->GetWebContents());
-  PreviewsUserData* previews_data =
-      ui_tab_helper ? ui_tab_helper->GetPreviewsUserData(navigation_handle)
-                    : nullptr;
-  if (!previews_data)
-    return initial_state;
-
-  // It is possible that any number of at-commit-decided previews are enabled,
-  // but do not hold them back until the commit time logic runs.
-  if (!HasEnabledPreviews(initial_state & kPreCommitPreviews))
-    return initial_state;
-
-  if (previews_data->CoinFlipForNavigation()) {
-    // Holdback all previews. It is possible that some number of client previews
-    // will also be held back here. However, since a before-commit preview was
-    // likely, we turn off all of them to make analysis simpler and this code
-    // more robust.
-    UpdatePreviewsUserDataAndRecordCoinFlipResult(
-        navigation_handle, previews_data, CoinFlipHoldbackResult::kHoldback);
-    return content::PREVIEWS_OFF;
-  }
-
-  UpdatePreviewsUserDataAndRecordCoinFlipResult(
-      navigation_handle, previews_data, CoinFlipHoldbackResult::kAllowed);
-  return initial_state;
-}
-
 content::PreviewsState MaybeCoinFlipHoldbackAfterCommit(
     content::PreviewsState initial_state,
     content::NavigationHandle* navigation_handle) {
@@ -418,16 +324,6 @@
     return initial_state;
 
   if (previews_data->CoinFlipForNavigation()) {
-    // No pre-commit previews should be set, since such a preview would have
-    // already committed and we don't want to incorrectly clear that state. If
-    // it did, at least make everything functionally correct.
-    if (HasEnabledPreviews(initial_state & kPreCommitPreviews)) {
-      NOTREACHED();
-      previews_data->set_coin_flip_holdback_result(
-          CoinFlipHoldbackResult::kNotSet);
-      return initial_state;
-    }
-
     UpdatePreviewsUserDataAndRecordCoinFlipResult(
         navigation_handle, previews_data, CoinFlipHoldbackResult::kHoldback);
     return content::PREVIEWS_OFF;
@@ -441,10 +337,6 @@
 previews::PreviewsType GetMainFramePreviewsType(
     content::PreviewsState previews_state) {
   // The order is important here.
-  if (previews_state & content::OFFLINE_PAGE_ON)
-    return previews::PreviewsType::OFFLINE;
-  if (previews_state & content::SERVER_LITE_PAGE_ON)
-    return previews::PreviewsType::LITE_PAGE;
   if (previews_state & content::DEFER_ALL_SCRIPT_ON)
     return previews::PreviewsType::DEFER_ALL_SCRIPT;
   if (previews_state & content::RESOURCE_LOADING_HINTS_ON)
diff --git a/chrome/browser/previews/previews_content_util.h b/chrome/browser/previews/previews_content_util.h
index 9fbde0b..acf7223a 100644
--- a/chrome/browser/previews/previews_content_util.h
+++ b/chrome/browser/previews/previews_content_util.h
@@ -12,17 +12,8 @@
 class NavigationHandle;
 }
 
-namespace data_reduction_proxy {
-class DataReductionProxyData;
-}
-
 namespace previews {
 
-// This bit mask is all the preview types that are fully decided
-// before commit.
-static const content::PreviewsState kPreCommitPreviews =
-    content::SERVER_LITE_PAGE_ON | content::OFFLINE_PAGE_ON;
-
 // Returns whether |previews_state| has any enabled previews.
 bool HasEnabledPreviews(content::PreviewsState previews_state);
 
@@ -40,14 +31,6 @@
     previews::PreviewsDecider* previews_decider,
     content::NavigationHandle* navigation_handle);
 
-// If this Chrome session is in a coin flip holdback, possibly modify the
-// previews state of the navigation according to a random coin flip. This method
-// should only be called before commit (at navigation start or redirect) and
-// will only impact previews that are decided before commit.
-content::PreviewsState MaybeCoinFlipHoldbackBeforeCommit(
-    content::PreviewsState initial_state,
-    content::NavigationHandle* navigation_handle);
-
 // Returns an updated PreviewsState given |previews_state| that has already
 // been updated wrt server previews. This should be called at Navigation Commit
 // time. It will defer to any server preview set, otherwise it chooses which
@@ -59,14 +42,6 @@
     const previews::PreviewsDecider* previews_decider,
     content::NavigationHandle* navigation_handle);
 
-// Returns an updated PreviewsState with respect to server previews
-// given the main frame's committed |request| and the |initial_state|
-// of enabled previews. |data| must have already been updated with
-// respect to the main frame response headers.
-content::PreviewsState DetermineCommittedServerPreviewsState(
-    data_reduction_proxy::DataReductionProxyData* data,
-    content::PreviewsState initial_state);
-
 // If this Chrome session is in a coin flip holdback, possibly modify the
 // previews state of the navigation according to a random coin flip. This method
 // should only be called after commit and may impact all preview types. This
diff --git a/chrome/browser/previews/previews_content_util_unittest.cc b/chrome/browser/previews/previews_content_util_unittest.cc
index 9c0632b4..c42a53a 100644
--- a/chrome/browser/previews/previews_content_util_unittest.cc
+++ b/chrome/browser/previews/previews_content_util_unittest.cc
@@ -82,17 +82,11 @@
     return IsEnabled(type);
   }
 
-  bool AreCommitTimePreviewsAvailable(
-      content::NavigationHandle* navigation_handle) override {
-    return navigation_handle->GetURL().host_piece().ends_with(
-        "hintcachedhost.com");
-  }
-
  private:
   bool IsEnabled(PreviewsType type) const {
     switch (type) {
-      case previews::PreviewsType::OFFLINE:
-        return params::IsOfflinePreviewsEnabled();
+      case previews::PreviewsType::DEPRECATED_OFFLINE:
+        return false;
       case previews::PreviewsType::DEPRECATED_LOFI:
         return false;
       case previews::PreviewsType::DEPRECATED_AMP_REDIRECTION:
@@ -105,7 +99,7 @@
         return false;
       case previews::PreviewsType::DEFER_ALL_SCRIPT:
         return params::IsDeferAllScriptPreviewsEnabled();
-      case PreviewsType::LITE_PAGE:
+      case PreviewsType::DEPRECATED_LITE_PAGE:
       case PreviewsType::NONE:
       case PreviewsType::UNSPECIFIED:
       case PreviewsType::LAST:
@@ -179,48 +173,6 @@
 }
 
 TEST_F(PreviewsContentUtilTest,
-       DetermineAllowedClientPreviewsStateOfflineAndRedirects) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitFromCommandLine(
-      "Previews,OfflinePreviews",
-      "DeferAllScript,ResourceLoadingHints,NoScriptPreviews");
-  PreviewsUserData user_data(1);
-  bool is_reload = false;
-  bool previews_triggering_logic_already_ran = false;
-  bool is_data_saver_user = true;
-
-  EXPECT_EQ(content::OFFLINE_PAGE_ON,
-            previews::CallDetermineAllowedClientPreviewsState(
-                &user_data, GURL("http://www.google.com"), is_reload,
-                previews_triggering_logic_already_ran, is_data_saver_user,
-                enabled_previews_decider(), nullptr));
-  EXPECT_FALSE(user_data.is_redirect());
-  user_data.set_allowed_previews_state(content::OFFLINE_PAGE_ON);
-
-  previews_triggering_logic_already_ran = true;
-  EXPECT_EQ(content::OFFLINE_PAGE_ON,
-            previews::CallDetermineAllowedClientPreviewsState(
-                &user_data, GURL("http://www.google.com"), is_reload,
-                previews_triggering_logic_already_ran, is_data_saver_user,
-                enabled_previews_decider(), nullptr));
-  EXPECT_TRUE(user_data.is_redirect());
-
-  user_data.set_allowed_previews_state(content::PREVIEWS_OFF);
-  EXPECT_EQ(content::OFFLINE_PAGE_ON,
-            previews::CallDetermineAllowedClientPreviewsState(
-                &user_data, GURL("http://www.google.com"), is_reload,
-                previews_triggering_logic_already_ran, is_data_saver_user,
-                enabled_previews_decider(), nullptr));
-
-  previews_triggering_logic_already_ran = false;
-  EXPECT_EQ(content::OFFLINE_PAGE_ON,
-            previews::CallDetermineAllowedClientPreviewsState(
-                &user_data, GURL("http://www.google.com"), is_reload,
-                previews_triggering_logic_already_ran, is_data_saver_user,
-                enabled_previews_decider(), nullptr));
-}
-
-TEST_F(PreviewsContentUtilTest,
        DetermineAllowedClientPreviewsStateDeferAllScript) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitFromCommandLine("Previews,DeferAllScript",
@@ -303,23 +255,8 @@
       "Previews,NoScriptPreviews,ResourceLoadingHints,DeferAllScript",
       std::string());
   PreviewsUserData user_data(1);
-  user_data.set_navigation_ect(net::EFFECTIVE_CONNECTION_TYPE_2G);
-  base::HistogramTester histogram_tester;
-
-  // Server bits take precedence over NoScript:
-  EXPECT_EQ(content::SERVER_LITE_PAGE_ON,
-            previews::DetermineCommittedClientPreviewsState(
-                &user_data, GURL("https://www.google.com"),
-                content::SERVER_LITE_PAGE_ON | content::NOSCRIPT_ON,
-                enabled_previews_decider(), nullptr));
-  histogram_tester.ExpectUniqueSample(
-      "Previews.Triggered.EffectiveConnectionType2.LitePage",
-      static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_2G), 1);
-  histogram_tester.ExpectTotalCount(
-      "Previews.Triggered.EffectiveConnectionType2", 1);
-
-  // Try different navigation ECT value.
   user_data.set_navigation_ect(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+  base::HistogramTester histogram_tester;
 
   // DeferAllScript has precedence over NoScript and ResourceLoadingHints.
   EXPECT_EQ(content::DEFER_ALL_SCRIPT_ON,
@@ -332,7 +269,7 @@
       "Previews.Triggered.EffectiveConnectionType2.DeferAllScript",
       static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G), 1);
   histogram_tester.ExpectTotalCount(
-      "Previews.Triggered.EffectiveConnectionType2", 2);
+      "Previews.Triggered.EffectiveConnectionType2", 1);
 
   // RESOURCE_LOADING_HINTS has precedence over NoScript.
   EXPECT_EQ(content::RESOURCE_LOADING_HINTS_ON,
@@ -344,7 +281,7 @@
       "Previews.Triggered.EffectiveConnectionType2.ResourceLoadingHints",
       static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G), 1);
   histogram_tester.ExpectTotalCount(
-      "Previews.Triggered.EffectiveConnectionType2", 3);
+      "Previews.Triggered.EffectiveConnectionType2", 2);
 
   // Only NoScript:
   EXPECT_EQ(content::NOSCRIPT_ON,
@@ -396,34 +333,8 @@
                 content::NOSCRIPT_ON, enabled_previews_decider(), nullptr));
 }
 
-TEST_F(PreviewsContentUtilTest, DetermineCommittedServerPreviewsStateLitePage) {
-  content::PreviewsState enabled_previews =
-      content::SERVER_LITE_PAGE_ON | content::NOSCRIPT_ON;
-
-  // Add DataReductionProxyData for LitePage to URLRequest.
-  data_reduction_proxy::DataReductionProxyData data_reduction_proxy_data;
-  data_reduction_proxy_data.set_used_data_reduction_proxy(true);
-  data_reduction_proxy_data.set_lite_page_received(true);
-
-  // Verify selects LitePage bit but doesn't touch client-only NoScript bit.
-  EXPECT_EQ(content::SERVER_LITE_PAGE_ON | content::NOSCRIPT_ON,
-            DetermineCommittedServerPreviewsState(&data_reduction_proxy_data,
-                                                  enabled_previews));
-}
-
-TEST_F(PreviewsContentUtilTest, DetermineCommittedServerPreviewsStateNoProxy) {
-  content::PreviewsState enabled_previews =
-      content::SERVER_LITE_PAGE_ON | content::NOSCRIPT_ON;
-
-  // Verify doesn't touch client-only NoScript bit.
-  EXPECT_EQ(content::NOSCRIPT_ON,
-            DetermineCommittedServerPreviewsState(nullptr, enabled_previews));
-}
-
 TEST_F(PreviewsContentUtilTest, GetMainFramePreviewsType) {
   // Simple cases:
-  EXPECT_EQ(previews::PreviewsType::LITE_PAGE,
-            previews::GetMainFramePreviewsType(content::SERVER_LITE_PAGE_ON));
   EXPECT_EQ(previews::PreviewsType::NOSCRIPT,
             previews::GetMainFramePreviewsType(content::NOSCRIPT_ON));
   EXPECT_EQ(
@@ -438,12 +349,6 @@
   EXPECT_EQ(previews::PreviewsType::NONE,
             previews::GetMainFramePreviewsType(content::PREVIEWS_NO_TRANSFORM));
 
-  // Precedence cases when server preview is available:
-  EXPECT_EQ(previews::PreviewsType::LITE_PAGE,
-            previews::GetMainFramePreviewsType(
-                content::SERVER_LITE_PAGE_ON | content::NOSCRIPT_ON |
-                content::RESOURCE_LOADING_HINTS_ON));
-
   // Precedence cases when server preview is not available:
   EXPECT_EQ(previews::PreviewsType::NOSCRIPT,
             previews::GetMainFramePreviewsType(content::NOSCRIPT_ON));
@@ -515,138 +420,6 @@
   std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_;
 };
 
-TEST_F(PreviewsContentSimulatedNavigationTest, TestCoinFlipBeforeCommit) {
-  struct TestCase {
-    std::string msg;
-    bool enable_feature;
-    // True maps to previews::CoinFlipHoldbackResult::kHoldback.
-    bool set_random_coin_flip_for_navigation;
-    bool want_ukm;
-    previews::CoinFlipHoldbackResult want_coin_flip_result;
-    content::PreviewsState initial_state;
-    content::PreviewsState want_returned;
-  };
-  const TestCase kTestCases[]{
-      {
-          .msg = "Feature disabled, no affect, heads",
-          .enable_feature = false,
-          .set_random_coin_flip_for_navigation = true,
-          .want_ukm = false,
-          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
-          .initial_state = content::NOSCRIPT_ON,
-          .want_returned = content::NOSCRIPT_ON,
-      },
-      {
-          .msg = "Feature disabled, no affect, tails",
-          .enable_feature = false,
-          .set_random_coin_flip_for_navigation = false,
-          .want_ukm = false,
-          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
-          .initial_state = content::NOSCRIPT_ON,
-          .want_returned = content::NOSCRIPT_ON,
-      },
-      {
-          .msg = "After-commit decided previews are not affected before commit "
-                 "on true coin flip",
-          .enable_feature = true,
-          .set_random_coin_flip_for_navigation = true,
-          .want_ukm = false,
-          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
-          .initial_state = content::NOSCRIPT_ON,
-          .want_returned = content::NOSCRIPT_ON,
-      },
-      {
-          .msg = "After-commit decided previews are not affected before commit "
-                 "on false coin flip",
-          .enable_feature = true,
-          .set_random_coin_flip_for_navigation = false,
-          .want_ukm = false,
-          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
-          .initial_state = content::NOSCRIPT_ON,
-          .want_returned = content::NOSCRIPT_ON,
-      },
-      {
-          .msg =
-              "Before-commit decided previews are affected on true coin flip",
-          .enable_feature = true,
-          .set_random_coin_flip_for_navigation = true,
-          .want_ukm = true,
-          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kHoldback,
-          .initial_state = content::OFFLINE_PAGE_ON,
-          .want_returned = content::PREVIEWS_OFF,
-      },
-      {
-          .msg = "Before-commit decided previews are logged on false coin flip",
-          .enable_feature = true,
-          .set_random_coin_flip_for_navigation = false,
-          .want_ukm = true,
-          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kAllowed,
-          .initial_state = content::OFFLINE_PAGE_ON,
-          .want_returned = content::OFFLINE_PAGE_ON,
-      },
-      {
-          .msg =
-              "True coin flip impacts both pre and post commit previews when "
-              "both exist",
-          .enable_feature = true,
-          .set_random_coin_flip_for_navigation = true,
-          .want_ukm = true,
-          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kHoldback,
-          .initial_state = content::OFFLINE_PAGE_ON | content::NOSCRIPT_ON,
-          .want_returned = content::PREVIEWS_OFF,
-      },
-      {
-          .msg = "False coin flip logs both pre and post commit previews when "
-                 "both exist",
-          .enable_feature = true,
-          .set_random_coin_flip_for_navigation = false,
-          .want_ukm = true,
-          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kAllowed,
-          .initial_state = content::OFFLINE_PAGE_ON | content::NOSCRIPT_ON,
-          .want_returned = content::OFFLINE_PAGE_ON | content::NOSCRIPT_ON,
-      },
-  };
-
-  for (const TestCase& test_case : kTestCases) {
-    SCOPED_TRACE(test_case.msg);
-
-    // Starting the navigation will cause content to call into
-    // |MaybeCoinFlipHoldbackBeforeCommit| as part of the navigation simulation.
-    // So don't enable the feature until afterwards.
-    content::NavigationHandle* handle = StartNavigation();
-
-    base::test::ScopedFeatureList scoped_feature_list;
-    if (test_case.enable_feature) {
-      scoped_feature_list.InitAndEnableFeatureWithParameters(
-          previews::features::kCoinFlipHoldback,
-          {{"force_coin_flip_always_holdback",
-            test_case.set_random_coin_flip_for_navigation ? "true" : "false"},
-           {"force_coin_flip_always_allow",
-            !test_case.set_random_coin_flip_for_navigation ? "true"
-                                                           : "false"}});
-    } else {
-      scoped_feature_list.InitAndDisableFeature(
-          previews::features::kCoinFlipHoldback);
-    }
-
-    content::PreviewsState returned =
-        MaybeCoinFlipHoldbackBeforeCommit(test_case.initial_state, handle);
-
-    EXPECT_EQ(test_case.want_returned, returned);
-    EXPECT_EQ(test_case.want_coin_flip_result,
-              GetPreviewsUserData(handle)->coin_flip_holdback_result());
-
-    using UkmEntry = ukm::builders::PreviewsCoinFlip;
-    auto entries = ukm_recorder()->GetEntriesByName(UkmEntry::kEntryName);
-    EXPECT_EQ(test_case.want_ukm ? 1u : 0u, entries.size());
-    for (auto* entry : entries) {
-      ukm_recorder()->ExpectEntryMetric(
-          entry, UkmEntry::kcoin_flip_resultName,
-          static_cast<int>(test_case.want_coin_flip_result));
-    }
-  }
-}
-
 TEST_F(PreviewsContentSimulatedNavigationTest, TestCoinFlipAfterCommit) {
   struct TestCase {
     std::string msg;
diff --git a/chrome/browser/previews/previews_offline_helper.cc b/chrome/browser/previews/previews_offline_helper.cc
deleted file mode 100644
index 967306d..0000000
--- a/chrome/browser/previews/previews_offline_helper.cc
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/previews/previews_offline_helper.h"
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/feature_list.h"
-#include "base/hash/hash.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/optional.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/task/task_traits.h"
-#include "base/time/time.h"
-#include "chrome/browser/offline_pages/offline_page_model_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/offline_pages/buildflags/buildflags.h"
-#include "components/offline_pages/core/page_criteria.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/previews/core/previews_experiments.h"
-#include "components/previews/core/previews_features.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace {
-// The maximum number of entries to keep in the pref.
-const size_t kOfflinePreviewsHelperMaxPrefSize = 100;
-
-// Pref key for the available hashed pages kept in class.
-const char kHashedAvailablePages[] = "previews.offline_helper.available_pages";
-
-void RecordShouldAttemptOfflinePreviewResult(bool result) {
-  UMA_HISTOGRAM_BOOLEAN("Previews.Offline.FalsePositivePrevention.Allowed",
-                        result);
-}
-
-std::string HashURL(const GURL& url) {
-  // We are ok with some hash collisions in exchange for non-arbitrary key
-  // lengths (as in using the url.spec()). Therefore, use a hash and return that
-  // as a string since base::DictionaryValue only accepts strings as keys.
-  std::string clean_url = url.GetAsReferrer().spec();
-  uint32_t hash = base::PersistentHash(clean_url);
-  return base::StringPrintf("%x", hash);
-}
-
-std::string TimeToDictionaryValue(base::Time time) {
-  return base::NumberToString(time.ToDeltaSinceWindowsEpoch().InMicroseconds());
-}
-
-base::Optional<base::Time> TimeFromDictionaryValue(std::string value) {
-  int64_t int_value = 0;
-  if (!base::StringToInt64(value, &int_value))
-    return base::nullopt;
-
-  return base::Time::FromDeltaSinceWindowsEpoch(
-      base::TimeDelta::FromMicroseconds(int_value));
-}
-
-// Cleans up the given dictionary by removing all stale (expiry has passed)
-// entries.
-void RemoveStaleOfflinePageEntries(base::DictionaryValue* dict) {
-  base::Time earliest_expiry = base::Time::Max();
-  std::string earliest_key;
-  std::vector<std::string> keys_to_delete;
-  for (const auto& iter : dict->DictItems()) {
-    // Check for a corrupted value and throw it out if so.
-    if (!iter.second.is_string()) {
-      keys_to_delete.push_back(iter.first);
-      continue;
-    }
-
-    base::Optional<base::Time> time =
-        TimeFromDictionaryValue(iter.second.GetString());
-    if (!time.has_value()) {
-      keys_to_delete.push_back(iter.first);
-      continue;
-    }
-
-    base::Time expiry =
-        time.value() + previews::params::OfflinePreviewFreshnessDuration();
-    bool is_expired = expiry <= base::Time::Now();
-
-    if (is_expired) {
-      keys_to_delete.push_back(iter.first);
-      continue;
-    }
-
-    if (expiry < earliest_expiry) {
-      earliest_key = iter.first;
-      earliest_expiry = expiry;
-    }
-  }
-
-  for (const std::string& key : keys_to_delete)
-    dict->RemoveKey(key);
-
-  // RemoveStaleOfflinePageEntries is called for every new added page, so it's
-  // fine to just remove one at a time to keep the pref size below a threshold.
-  if (dict->DictSize() > kOfflinePreviewsHelperMaxPrefSize) {
-    dict->RemoveKey(earliest_key);
-  }
-}
-
-void AddSingleOfflineItemEntry(
-    base::DictionaryValue* available_pages,
-    const offline_pages::OfflinePageItem& added_page) {
-  available_pages->SetKey(
-      HashURL(added_page.url),
-      base::Value(TimeToDictionaryValue(added_page.creation_time)));
-
-  // Also remember the original url (pre-redirects) if one exists.
-  if (!added_page.original_url_if_different.is_empty()) {
-    available_pages->SetKey(
-        HashURL(added_page.original_url_if_different),
-        base::Value(TimeToDictionaryValue(added_page.creation_time)));
-  }
-}
-
-}  // namespace
-
-PreviewsOfflineHelper::PreviewsOfflineHelper(
-    content::BrowserContext* browser_context)
-    : pref_service_(nullptr),
-      available_pages_(std::make_unique<base::DictionaryValue>()),
-      offline_page_model_(nullptr) {
-  if (!browser_context || browser_context->IsOffTheRecord())
-    return;
-
-  pref_service_ = Profile::FromBrowserContext(browser_context)->GetPrefs();
-
-  available_pages_ =
-      pref_service_->GetDictionary(kHashedAvailablePages)->CreateDeepCopy();
-
-  // Tidy up the pref in case it's been a while since the last stale item
-  // removal.
-  RemoveStaleOfflinePageEntries(available_pages_.get());
-  UpdatePref();
-
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-  offline_page_model_ =
-      offline_pages::OfflinePageModelFactory::GetForBrowserContext(
-          browser_context);
-
-  if (offline_page_model_) {
-    offline_page_model_->AddObserver(this);
-    // Schedule a low priority task with a slight delay to ensure that the
-    // expensive DB query doesn't occur during startup or during other user
-    // visible actions.
-    content::GetUIThreadTaskRunner(
-        {base::MayBlock(), base::TaskPriority::LOWEST,
-         base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})
-        ->PostDelayedTask(
-            FROM_HERE,
-            base::BindOnce(&PreviewsOfflineHelper::RequestDBUpdate,
-                           weak_factory_.GetWeakPtr()),
-            base::TimeDelta::FromSeconds(30));
-  }
-#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
-}
-
-PreviewsOfflineHelper::~PreviewsOfflineHelper() {
-  if (offline_page_model_)
-    offline_page_model_->RemoveObserver(this);
-}
-
-// static
-void PreviewsOfflineHelper::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterDictionaryPref(kHashedAvailablePages);
-}
-
-bool PreviewsOfflineHelper::ShouldAttemptOfflinePreview(const GURL& url) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  std::string hashed_url = HashURL(url);
-
-  base::Value* value = available_pages_->FindKey(hashed_url);
-  if (!value) {
-    RecordShouldAttemptOfflinePreviewResult(false);
-    return false;
-  }
-
-  if (!value->is_string()) {
-    NOTREACHED();
-    RecordShouldAttemptOfflinePreviewResult(false);
-    return false;
-  }
-  base::Optional<base::Time> time_value =
-      TimeFromDictionaryValue(value->GetString());
-  if (!time_value.has_value()) {
-    RecordShouldAttemptOfflinePreviewResult(false);
-    return false;
-  }
-
-  base::Time expiry =
-      time_value.value() + previews::params::OfflinePreviewFreshnessDuration();
-  bool is_expired = expiry <= base::Time::Now();
-  if (is_expired) {
-    available_pages_->RemoveKey(hashed_url);
-    UpdatePref();
-  }
-
-  RecordShouldAttemptOfflinePreviewResult(!is_expired);
-  return !is_expired;
-}
-
-void PreviewsOfflineHelper::Shutdown() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (offline_page_model_) {
-    offline_page_model_->RemoveObserver(this);
-    offline_page_model_ = nullptr;
-  }
-}
-
-void PreviewsOfflineHelper::RequestDBUpdate() {
-  offline_pages::PageCriteria criteria;
-  criteria.maximum_matches = kOfflinePreviewsHelperMaxPrefSize;
-
-  offline_page_model_->GetPagesWithCriteria(
-      criteria, base::BindOnce(&PreviewsOfflineHelper::UpdateAllPrefEntries,
-                               weak_factory_.GetWeakPtr()));
-}
-
-void PreviewsOfflineHelper::UpdateAllPrefEntries(
-    const offline_pages::MultipleOfflinePageItemResult& pages) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // Totally reset the pref with the given vector. We presume that the given
-  // |pages| are a full result from a Offline DB query which we take as the
-  // source of truth.
-  available_pages_->Clear();
-  for (const offline_pages::OfflinePageItem& page : pages)
-    AddSingleOfflineItemEntry(available_pages_.get(), page);
-  RemoveStaleOfflinePageEntries(available_pages_.get());
-  UpdatePref();
-
-  UMA_HISTOGRAM_COUNTS_100("Previews.Offline.FalsePositivePrevention.PrefSize",
-                           available_pages_->size());
-}
-
-void PreviewsOfflineHelper::OfflinePageModelLoaded(
-    offline_pages::OfflinePageModel* model) {
-  // Ignored.
-}
-
-void PreviewsOfflineHelper::OfflinePageAdded(
-    offline_pages::OfflinePageModel* model,
-    const offline_pages::OfflinePageItem& added_page) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  AddSingleOfflineItemEntry(available_pages_.get(), added_page);
-  RemoveStaleOfflinePageEntries(available_pages_.get());
-  UpdatePref();
-}
-
-void PreviewsOfflineHelper::OfflinePageDeleted(
-    const offline_pages::OfflinePageItem& deleted_page) {
-  // Do nothing. OfflinePageModel calls |OfflinePageDeleted| when pages are
-  // refreshed, but because we only key on URL and not the offline page id, it
-  // is difficult to tell when this happens. So instead, it's ok if we
-  // over-trigger for a few pages until the next DB query.
-}
-
-void PreviewsOfflineHelper::UpdatePref() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (pref_service_)
-    pref_service_->Set(kHashedAvailablePages, *available_pages_);
-}
diff --git a/chrome/browser/previews/previews_offline_helper.h b/chrome/browser/previews/previews_offline_helper.h
deleted file mode 100644
index 37143f7..0000000
--- a/chrome/browser/previews/previews_offline_helper.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PREVIEWS_PREVIEWS_OFFLINE_HELPER_H_
-#define CHROME_BROWSER_PREVIEWS_PREVIEWS_OFFLINE_HELPER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/values.h"
-#include "components/offline_pages/core/offline_page_model.h"
-#include "url/gurl.h"
-
-class PrefService;
-
-namespace content {
-class BrowserContext;
-}  // namespace content
-
-class PrefRegistrySimple;
-class PrefService;
-
-// This class keeps track of available offline pages to help optimize triggering
-// of offline previews for cases that have a high probability of actually having
-// an offline page to load.
-class PreviewsOfflineHelper : public offline_pages::OfflinePageModel::Observer {
- public:
-  explicit PreviewsOfflineHelper(content::BrowserContext* browser_context);
-  ~PreviewsOfflineHelper() override;
-
-  // Registers the prefs used in this class.
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
-  // Returns true if there is a high likelihood that a offline page exists with
-  // the given URL.
-  bool ShouldAttemptOfflinePreview(const GURL& url);
-
-  // Removes |this| as an observer from offline pages.
-  void Shutdown();
-
-  // Updates all entries in the pref with the given result from an offline page
-  // database query.
-  void UpdateAllPrefEntries(
-      const offline_pages::MultipleOfflinePageItemResult& pages);
-
-  // offline_pages::OfflinePageModel::Observer:
-  void OfflinePageModelLoaded(offline_pages::OfflinePageModel* model) override;
-  void OfflinePageAdded(
-      offline_pages::OfflinePageModel* model,
-      const offline_pages::OfflinePageItem& added_page) override;
-  void OfflinePageDeleted(
-      const offline_pages::OfflinePageItem& deleted_page) override;
-
-  void SetPrefServiceForTesting(PrefService* pref_service) {
-    pref_service_ = pref_service;
-  }
-
- private:
-  // Requests all eligible pages from Offline Page Model. This is defined as a
-  // separate method so that it can be scheduled at a low priority since the
-  // Offline DB query is expensive, and only needs to be done at most once per
-  // session.
-  void RequestDBUpdate();
-
-  // Helper method to update |available_pages_| in |pref_service_|.
-  void UpdatePref();
-
-  // A reference to the profile's |PrefService|.
-  PrefService* pref_service_;
-
-  // A mapping from url_hash to original storage time (as a double).
-  std::unique_ptr<base::DictionaryValue> available_pages_;
-
-  offline_pages::OfflinePageModel* offline_page_model_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  base::WeakPtrFactory<PreviewsOfflineHelper> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(PreviewsOfflineHelper);
-};
-
-#endif  // CHROME_BROWSER_PREVIEWS_PREVIEWS_OFFLINE_HELPER_H_
diff --git a/chrome/browser/previews/previews_offline_helper_unittest.cc b/chrome/browser/previews/previews_offline_helper_unittest.cc
deleted file mode 100644
index 0f56c29..0000000
--- a/chrome/browser/previews/previews_offline_helper_unittest.cc
+++ /dev/null
@@ -1,339 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/previews/previews_offline_helper.h"
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind_helpers.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/time/time.h"
-#include "chrome/browser/offline_pages/offline_page_model_factory.h"
-#include "chrome/browser/offline_pages/request_coordinator_factory.h"
-#include "chrome/browser/offline_pages/test_offline_page_model_builder.h"
-#include "chrome/browser/offline_pages/test_request_coordinator_builder.h"
-#include "chrome/browser/profiles/profile_key.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/offline_pages/buildflags/buildflags.h"
-#include "components/offline_pages/core/offline_page_test_archiver.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/previews/core/previews_experiments.h"
-#include "components/previews/core/previews_features.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/navigation_simulator.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class PreviewsOfflineHelperTest : public ChromeRenderViewHostTestHarness {
- public:
-  void TearDown() override {
-    if (helper_)
-      helper_->Shutdown();
-    ChromeRenderViewHostTestHarness::TearDown();
-  }
-
-  PreviewsOfflineHelper* NewHelper(content::BrowserContext* browser_context) {
-    helper_.reset(new PreviewsOfflineHelper(browser_context));
-    return helper_.get();
-  }
-
-  offline_pages::OfflinePageItem MakeAddedPageItem(
-      const std::string& url,
-      const std::string& original_url,
-      const base::Time& creation_time) {
-    offline_pages::OfflinePageItem item;
-    item.url = GURL(url);
-    item.original_url_if_different = GURL(original_url);
-    item.creation_time = creation_time;
-    return item;
-  }
-
- private:
-  std::unique_ptr<PreviewsOfflineHelper> helper_;
-};
-
-TEST_F(PreviewsOfflineHelperTest, TestAddRemovePages) {
-  struct TestCase {
-    std::string msg;
-    std::vector<std::string> add_fresh_pages;
-    std::vector<std::string> add_expired_pages;
-    std::vector<std::string> want_pages;
-    std::vector<std::string> not_want_pages;
-    std::string original_url;
-    size_t want_pref_size;
-  };
-  const TestCase kTestCases[]{
-      {
-          .msg = "Unknown page returns false",
-          .add_fresh_pages = {},
-          .add_expired_pages = {},
-          .want_pages = {},
-          .not_want_pages = {"http://chromium.org"},
-          .original_url = "",
-          .want_pref_size = 0,
-      },
-      {
-          .msg = "Fresh page returns true",
-          .add_fresh_pages = {"http://chromium.org"},
-          .add_expired_pages = {},
-          .want_pages = {"http://chromium.org"},
-          .not_want_pages = {},
-          .original_url = "",
-          .want_pref_size = 1,
-      },
-      {
-          .msg = "Fresh page with the original URL returns true",
-          .add_fresh_pages = {"http://chromium.org"},
-          .add_expired_pages = {},
-          .want_pages = {"http://google.com"},
-          .not_want_pages = {},
-          .original_url = "http://google.com",
-          .want_pref_size = 2,
-      },
-      {
-          .msg = "Expired page returns false",
-          .add_fresh_pages = {},
-          .add_expired_pages = {"http://chromium.org"},
-          .want_pages = {},
-          .not_want_pages = {"http://chromium.org"},
-          .original_url = "",
-          .want_pref_size = 0,
-      },
-      {
-          .msg = "Expired then refreshed page returns true",
-          .add_fresh_pages = {"http://chromium.org"},
-          .add_expired_pages = {"http://chromium.org"},
-          .want_pages = {"http://chromium.org"},
-          .not_want_pages = {},
-          .original_url = "",
-          .want_pref_size = 1,
-      },
-      {
-          .msg = "URL Fragments don't matter",
-          .add_fresh_pages = {"http://chromium.org"},
-          .add_expired_pages = {},
-          .want_pages = {"http://chromium.org",
-                         "http://chromium.org/#previews"},
-          .not_want_pages = {},
-          .original_url = "",
-          .want_pref_size = 1,
-      },
-      {
-          .msg = "URLs with paths are different",
-          .add_fresh_pages = {"http://chromium.org/fresh"},
-          .add_expired_pages = {"http://chromium.org/old"},
-          .want_pages = {"http://chromium.org/fresh"},
-          .not_want_pages = {"http://chromium.org/old"},
-          .original_url = "",
-          .want_pref_size = 1,
-      },
-  };
-
-  base::Time fresh = base::Time::Now();
-  base::Time expired = fresh -
-                       previews::params::OfflinePreviewFreshnessDuration() -
-                       base::TimeDelta::FromHours(1);
-
-  const char kDictKey[] = "previews.offline_helper.available_pages";
-
-  for (const TestCase& test_case : kTestCases) {
-    SCOPED_TRACE(test_case.msg);
-
-    base::HistogramTester histogram_tester;
-
-    TestingPrefServiceSimple test_prefs;
-    PreviewsOfflineHelper::RegisterProfilePrefs(test_prefs.registry());
-
-    PreviewsOfflineHelper* helper = NewHelper(nullptr);
-    helper->SetPrefServiceForTesting(&test_prefs);
-
-    // The tests above rely on this ordering.
-    for (const std::string& expired_page : test_case.add_expired_pages) {
-      helper->OfflinePageAdded(
-          nullptr,
-          MakeAddedPageItem(expired_page, test_case.original_url, expired));
-    }
-    for (const std::string& fresh_page : test_case.add_fresh_pages) {
-      helper->OfflinePageAdded(
-          nullptr,
-          MakeAddedPageItem(fresh_page, test_case.original_url, fresh));
-    }
-
-    EXPECT_EQ(test_prefs.GetDictionary(kDictKey)->size(),
-              test_case.want_pref_size);
-
-    for (const std::string& want : test_case.want_pages) {
-      EXPECT_TRUE(helper->ShouldAttemptOfflinePreview(GURL(want)));
-    }
-
-    for (const std::string& not_want : test_case.not_want_pages) {
-      EXPECT_FALSE(helper->ShouldAttemptOfflinePreview(GURL(not_want)));
-    }
-
-    histogram_tester.ExpectTotalCount(
-        "Previews.Offline.FalsePositivePrevention.Allowed",
-        test_case.not_want_pages.size() + test_case.want_pages.size());
-
-    if (test_case.not_want_pages.size() > 0) {
-      histogram_tester.ExpectBucketCount(
-          "Previews.Offline.FalsePositivePrevention.Allowed", false,
-          test_case.not_want_pages.size());
-    }
-    if (test_case.want_pages.size() > 0) {
-      histogram_tester.ExpectBucketCount(
-          "Previews.Offline.FalsePositivePrevention.Allowed", true,
-          test_case.want_pages.size());
-    }
-  }
-}
-
-TEST_F(PreviewsOfflineHelperTest, TestMaxPrefSize) {
-  PreviewsOfflineHelper* helper = NewHelper(nullptr);
-
-  base::Time first = base::Time::Now();
-  base::Time second = first + base::TimeDelta::FromMilliseconds(1);
-
-  helper->OfflinePageAdded(
-      nullptr, MakeAddedPageItem("http://test.first.com", "", first));
-  helper->OfflinePageAdded(
-      nullptr, MakeAddedPageItem("http://test.second.com", "", second));
-  EXPECT_TRUE(
-      helper->ShouldAttemptOfflinePreview(GURL("http://test.first.com")));
-  EXPECT_TRUE(
-      helper->ShouldAttemptOfflinePreview(GURL("http://test.second.com")));
-
-  // kOfflinePreviewsHelperMaxPrefSize = 100;
-  for (int i = 0; i < 99; i++) {
-    helper->OfflinePageAdded(
-        nullptr,
-        MakeAddedPageItem(base::StringPrintf("http://test.%d.com", i), "",
-                          second + base::TimeDelta::FromMilliseconds(i)));
-  }
-
-  EXPECT_FALSE(
-      helper->ShouldAttemptOfflinePreview(GURL("http://test.first.com")));
-  EXPECT_TRUE(
-      helper->ShouldAttemptOfflinePreview(GURL("http://test.second.com")));
-}
-
-TEST_F(PreviewsOfflineHelperTest, TestUpdateAllPrefEntries) {
-  base::HistogramTester histogram_tester;
-
-  PreviewsOfflineHelper* helper = NewHelper(nullptr);
-  base::Time now = base::Time::Now();
-
-  helper->OfflinePageAdded(nullptr,
-                           MakeAddedPageItem("http://cleared.com", "", now));
-  EXPECT_TRUE(helper->ShouldAttemptOfflinePreview(GURL("http://cleared.com")));
-
-  helper->UpdateAllPrefEntries({MakeAddedPageItem("http://new.com", "", now),
-                                MakeAddedPageItem("http://new2.com", "", now)});
-  EXPECT_FALSE(helper->ShouldAttemptOfflinePreview(GURL("http://cleared.com")));
-  EXPECT_TRUE(helper->ShouldAttemptOfflinePreview(GURL("http://new.com")));
-  EXPECT_TRUE(helper->ShouldAttemptOfflinePreview(GURL("http://new2.com")));
-
-  histogram_tester.ExpectUniqueSample(
-      "Previews.Offline.FalsePositivePrevention.PrefSize", 2, 1);
-}
-
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-
-class PreviewsOfflinePagesIntegrationTest
-    : public PreviewsOfflineHelperTest,
-      public offline_pages::OfflinePageTestArchiver::Observer {
- public:
-  void SetUp() override {
-    PreviewsOfflineHelperTest::SetUp();
-
-    // Sets up the factories for testing.
-    offline_pages::OfflinePageModelFactory::GetInstance()
-        ->SetTestingFactoryAndUse(
-            profile()->GetProfileKey(),
-            base::BindRepeating(&offline_pages::BuildTestOfflinePageModel));
-    base::RunLoop().RunUntilIdle();
-    offline_pages::RequestCoordinatorFactory::GetInstance()
-        ->SetTestingFactoryAndUse(
-            profile(),
-            base::BindRepeating(&offline_pages::BuildTestRequestCoordinator));
-    base::RunLoop().RunUntilIdle();
-
-    model_ = offline_pages::OfflinePageModelFactory::GetForBrowserContext(
-        browser_context());
-  }
-
-  void NavigateAndCommit(const GURL& url) {
-    content::NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(),
-                                                               url);
-  }
-
-  std::unique_ptr<offline_pages::OfflinePageArchiver> CreatePageArchiver(
-      content::WebContents* web_contents) {
-    std::unique_ptr<offline_pages::OfflinePageTestArchiver> archiver(
-        new offline_pages::OfflinePageTestArchiver(
-            this, web_contents->GetLastCommittedURL(),
-            offline_pages::OfflinePageArchiver::ArchiverResult::
-                SUCCESSFULLY_CREATED,
-            base::string16(), 1234, std::string(),
-            base::ThreadTaskRunnerHandle::Get()));
-    return std::move(archiver);
-  }
-
-  void SavePage(content::WebContents* web_contents) {
-    offline_pages::OfflinePageModel::SavePageParams save_page_params;
-    save_page_params.url = web_contents->GetLastCommittedURL();
-    save_page_params.client_id = offline_pages::ClientId("default", "id");
-    save_page_params.proposed_offline_id = 4321;
-    save_page_params.is_background = false;
-    save_page_params.original_url = web_contents->GetLastCommittedURL();
-
-    model_->SavePage(save_page_params, CreatePageArchiver(web_contents),
-                     web_contents, base::DoNothing());
-  }
-
-  // OfflinePageTestArchiver::Observer:
-  void SetLastPathCreatedByArchiver(const base::FilePath& file_path) override {}
-
- private:
-  offline_pages::OfflinePageModel* model_;
-};
-
-TEST_F(PreviewsOfflinePagesIntegrationTest, TestOfflinePagesDBQuery) {
-  GURL url("http://test.com/");
-  NavigateAndCommit(url);
-  SavePage(web_contents());
-  base::RunLoop().RunUntilIdle();
-
-  PreviewsOfflineHelper* helper = NewHelper(browser_context());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(helper->ShouldAttemptOfflinePreview(url));
-  EXPECT_FALSE(helper->ShouldAttemptOfflinePreview(GURL("http://other.com")));
-}
-
-// This test checks that expired entries are not queried and populated in the
-// pref. Since creating a stale offline page with this infrastructure is tricky,
-// we instead set the freshness duration to negative to make any newly saved
-// offline page stale.
-TEST_F(PreviewsOfflinePagesIntegrationTest, TestOfflinePagesDBQuery_Expired) {
-  ASSERT_TRUE(base::AssociateFieldTrialParams(
-      "ClientSidePreviews", "Enabled",
-      {{"offline_preview_freshness_duration_in_days", "-1"}}));
-  ASSERT_TRUE(
-      base::FieldTrialList::CreateFieldTrial("ClientSidePreviews", "Enabled"));
-
-  GURL url("http://test.com/");
-  NavigateAndCommit(url);
-  SavePage(web_contents());
-  base::RunLoop().RunUntilIdle();
-
-  PreviewsOfflineHelper* helper = NewHelper(browser_context());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(helper->ShouldAttemptOfflinePreview(url));
-}
-
-#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
diff --git a/chrome/browser/previews/previews_service.cc b/chrome/browser/previews/previews_service.cc
index a96f4cfb..07a9c33 100644
--- a/chrome/browser/previews/previews_service.cc
+++ b/chrome/browser/previews/previews_service.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
-#include "chrome/browser/previews/previews_offline_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_constants.h"
 #include "components/blocklist/opt_out_blocklist/opt_out_store.h"
@@ -57,13 +56,13 @@
 // Returns true if previews can be shown for |type|.
 bool IsPreviewsTypeEnabled(previews::PreviewsType type) {
   switch (type) {
-    case previews::PreviewsType::OFFLINE:
-      return previews::params::IsOfflinePreviewsEnabled();
+    case previews::PreviewsType::DEPRECATED_OFFLINE:
+      return false;
     case previews::PreviewsType::DEPRECATED_LOFI:
       return false;
     case previews::PreviewsType::DEPRECATED_LITE_PAGE_REDIRECT:
       return false;
-    case previews::PreviewsType::LITE_PAGE:
+    case previews::PreviewsType::DEPRECATED_LITE_PAGE:
       return false;
     case previews::PreviewsType::NOSCRIPT:
       return previews::params::IsNoScriptPreviewsEnabled();
@@ -88,10 +87,6 @@
 // specified in field trial config.
 int GetPreviewsTypeVersion(previews::PreviewsType type) {
   switch (type) {
-    case previews::PreviewsType::OFFLINE:
-      return previews::params::OfflinePreviewsVersion();
-    case previews::PreviewsType::LITE_PAGE:
-      return 0;
     case previews::PreviewsType::NOSCRIPT:
       return previews::params::NoScriptPreviewsVersion();
     case previews::PreviewsType::RESOURCE_LOADING_HINTS:
@@ -102,8 +97,10 @@
     case previews::PreviewsType::UNSPECIFIED:
     case previews::PreviewsType::LAST:
     case previews::PreviewsType::DEPRECATED_AMP_REDIRECTION:
-    case previews::PreviewsType::DEPRECATED_LOFI:
+    case previews::PreviewsType::DEPRECATED_LITE_PAGE:
     case previews::PreviewsType::DEPRECATED_LITE_PAGE_REDIRECT:
+    case previews::PreviewsType::DEPRECATED_LOFI:
+    case previews::PreviewsType::DEPRECATED_OFFLINE:
       break;
   }
   NOTREACHED();
@@ -158,8 +155,6 @@
     : previews_https_notification_infobar_decider_(
           std::make_unique<PreviewsHTTPSNotificationInfoBarDecider>(
               browser_context)),
-      previews_offline_helper_(
-          std::make_unique<PreviewsOfflineHelper>(browser_context)),
       browser_context_(browser_context),
       // Set cache size to 25 entries.  This should be sufficient since the
       // redirect loop cache is needed for only one navigation.
@@ -214,9 +209,6 @@
 void PreviewsService::Shutdown() {
   if (previews_https_notification_infobar_decider_)
     previews_https_notification_infobar_decider_->Shutdown();
-
-  if (previews_offline_helper_)
-    previews_offline_helper_->Shutdown();
 }
 
 void PreviewsService::ClearBlockList(base::Time begin_time,
diff --git a/chrome/browser/previews/previews_service.h b/chrome/browser/previews/previews_service.h
index e9a15ae..d1dfb02 100644
--- a/chrome/browser/previews/previews_service.h
+++ b/chrome/browser/previews/previews_service.h
@@ -32,8 +32,6 @@
 typedef std::vector<std::unique_ptr<re2::RE2>> RegexpList;
 }  // namespace previews
 
-class PreviewsOfflineHelper;
-
 // Keyed service that owns a previews::PreviewsUIService. PreviewsService lives
 // on the UI thread.
 class PreviewsService : public KeyedService {
@@ -65,10 +63,6 @@
     return previews_https_notification_infobar_decider_.get();
   }
 
-  PreviewsOfflineHelper* previews_offline_helper() {
-    return previews_offline_helper_.get();
-  }
-
   // Returns the enabled PreviewsTypes with their version.
   static blocklist::BlocklistData::AllowedTypesAndVersions GetAllowedPreviews();
 
@@ -98,9 +92,6 @@
   std::unique_ptr<PreviewsHTTPSNotificationInfoBarDecider>
       previews_https_notification_infobar_decider_;
 
-  // The offline previews helper.
-  std::unique_ptr<PreviewsOfflineHelper> previews_offline_helper_;
-
   // Guaranteed to outlive |this|.
   content::BrowserContext* browser_context_;
 
diff --git a/chrome/browser/previews/previews_service_unittest.cc b/chrome/browser/previews/previews_service_unittest.cc
index 71782d9c..a2104aca 100644
--- a/chrome/browser/previews/previews_service_unittest.cc
+++ b/chrome/browser/previews/previews_service_unittest.cc
@@ -33,34 +33,6 @@
 
 }  // namespace
 
-TEST_F(PreviewsServiceTest, TestOfflineFieldTrialNotSet) {
-  blocklist::BlocklistData::AllowedTypesAndVersions allowed_types_and_versions =
-      PreviewsService::GetAllowedPreviews();
-  EXPECT_EQ(allowed_types_and_versions.find(
-                static_cast<int>(previews::PreviewsType::OFFLINE)),
-            allowed_types_and_versions.end());
-}
-
-TEST_F(PreviewsServiceTest, TestOfflineFeatureDisabled) {
-  blocklist::BlocklistData::AllowedTypesAndVersions allowed_types_and_versions =
-      PreviewsService::GetAllowedPreviews();
-  EXPECT_EQ(allowed_types_and_versions.find(
-                static_cast<int>(previews::PreviewsType::OFFLINE)),
-            allowed_types_and_versions.end());
-}
-
-TEST_F(PreviewsServiceTest, TestLitePageNotEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {previews::features::kPreviews} /* enabled features */,
-      {} /* disabled features */);
-  blocklist::BlocklistData::AllowedTypesAndVersions allowed_types_and_versions =
-      PreviewsService::GetAllowedPreviews();
-  EXPECT_EQ(allowed_types_and_versions.find(
-                static_cast<int>(previews::PreviewsType::LITE_PAGE)),
-            allowed_types_and_versions.end());
-}
-
 TEST_F(PreviewsServiceTest, TestNoScriptPreviewsEnabledByFeature) {
 #if !defined(OS_ANDROID)
   // For non-android, default is disabled.
diff --git a/chrome/browser/previews/previews_ui_tab_helper.cc b/chrome/browser/previews/previews_ui_tab_helper.cc
index 5018463..ddccd37 100644
--- a/chrome/browser/previews/previews_ui_tab_helper.cc
+++ b/chrome/browser/previews/previews_ui_tab_helper.cc
@@ -22,8 +22,6 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/network_time/network_time_tracker.h"
-#include "components/offline_pages/buildflags/buildflags.h"
-#include "components/offline_pages/core/offline_page_item.h"
 #include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
 #include "components/previews/content/previews_decider_impl.h"
 #include "components/previews/content/previews_ui_service.h"
@@ -41,19 +39,10 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-#include "chrome/browser/offline_pages/offline_page_tab_helper.h"
-#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
-
 namespace {
 
 const void* const kOptOutEventKey = 0;
 
-const char kMinStalenessParamName[] = "min_staleness_in_minutes";
-const char kMaxStalenessParamName[] = "max_staleness_in_minutes";
-const int kMinStalenessParamDefaultValue = 5;
-const int kMaxStalenessParamDefaultValue = 1440;
-
 // Adds the preview navigation to the black list.
 void AddPreviewNavigationCallback(content::BrowserContext* browser_context,
                                   const GURL& url,
@@ -68,10 +57,6 @@
   }
 }
 
-void RecordStaleness(PreviewsUITabHelper::PreviewsStalePreviewTimestamp value) {
-  UMA_HISTOGRAM_ENUMERATION("Previews.StalePreviewTimestampShown", value);
-}
-
 void InformPLMOfOptOut(content::WebContents* web_contents) {
   page_load_metrics::MetricsWebContentsObserver* metrics_web_contents_observer =
       page_load_metrics::MetricsWebContentsObserver::FromWebContents(
@@ -115,75 +100,6 @@
       ->Add(true);
 }
 
-base::string16 PreviewsUITabHelper::GetStalePreviewTimestampText() {
-  if (previews_freshness_.is_null())
-    return base::string16();
-  if (!base::FeatureList::IsEnabled(
-          previews::features::kStalePreviewsTimestamp)) {
-    return base::string16();
-  }
-
-  int min_staleness_in_minutes = base::GetFieldTrialParamByFeatureAsInt(
-      previews::features::kStalePreviewsTimestamp, kMinStalenessParamName,
-      kMinStalenessParamDefaultValue);
-  int max_staleness_in_minutes = base::GetFieldTrialParamByFeatureAsInt(
-      previews::features::kStalePreviewsTimestamp, kMaxStalenessParamName,
-      kMaxStalenessParamDefaultValue);
-
-  if (min_staleness_in_minutes <= 0 || max_staleness_in_minutes <= 0) {
-    NOTREACHED();
-    return base::string16();
-  }
-  DCHECK_GE(min_staleness_in_minutes, 2);
-
-  base::Time network_time;
-  if (g_browser_process->network_time_tracker()->GetNetworkTime(&network_time,
-                                                                nullptr) !=
-      network_time::NetworkTimeTracker::NETWORK_TIME_AVAILABLE) {
-    // When network time has not been initialized yet, simply rely on the
-    // machine's current time.
-    network_time = base::Time::Now();
-  }
-
-  if (network_time < previews_freshness_) {
-    RecordStaleness(
-        PreviewsStalePreviewTimestamp::kTimestampNotShownStalenessNegative);
-    return base::string16();
-  }
-
-  int staleness_in_minutes = (network_time - previews_freshness_).InMinutes();
-  if (staleness_in_minutes < min_staleness_in_minutes) {
-    if (is_stale_reload_) {
-      RecordStaleness(PreviewsStalePreviewTimestamp::kTimestampUpdatedNowShown);
-      return l10n_util::GetStringUTF16(
-          IDS_PREVIEWS_INFOBAR_TIMESTAMP_UPDATED_NOW);
-    }
-    RecordStaleness(
-        PreviewsStalePreviewTimestamp::kTimestampNotShownPreviewNotStale);
-    return base::string16();
-  }
-  if (staleness_in_minutes > max_staleness_in_minutes) {
-    RecordStaleness(PreviewsStalePreviewTimestamp::
-                        kTimestampNotShownStalenessGreaterThanMax);
-    return base::string16();
-  }
-
-  RecordStaleness(PreviewsStalePreviewTimestamp::kTimestampShown);
-
-  if (staleness_in_minutes < 60) {
-    DCHECK_GE(staleness_in_minutes, 2);
-    return l10n_util::GetStringFUTF16(
-        IDS_PREVIEWS_INFOBAR_TIMESTAMP_MINUTES,
-        base::NumberToString16(staleness_in_minutes));
-  } else if (staleness_in_minutes < 120) {
-    return l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_ONE_HOUR);
-  } else {
-    return l10n_util::GetStringFUTF16(
-        IDS_PREVIEWS_INFOBAR_TIMESTAMP_HOURS,
-        base::NumberToString16(staleness_in_minutes / 60));
-  }
-}
-
 void PreviewsUITabHelper::ReloadWithoutPreviews() {
   DCHECK(GetPreviewsUserData());
   ReloadWithoutPreviews(GetPreviewsUserData()->CommittedPreviewsType());
@@ -198,8 +114,6 @@
   if (on_dismiss_callback_)
     std::move(on_dismiss_callback_).Run(true);
   switch (previews_type) {
-    case previews::PreviewsType::LITE_PAGE:
-    case previews::PreviewsType::OFFLINE:
     case previews::PreviewsType::NOSCRIPT:
     case previews::PreviewsType::RESOURCE_LOADING_HINTS:
     case previews::PreviewsType::DEFER_ALL_SCRIPT:
@@ -212,20 +126,15 @@
     case previews::PreviewsType::UNSPECIFIED:
     case previews::PreviewsType::LAST:
     case previews::PreviewsType::DEPRECATED_AMP_REDIRECTION:
-    case previews::PreviewsType::DEPRECATED_LOFI:
+    case previews::PreviewsType::DEPRECATED_LITE_PAGE:
     case previews::PreviewsType::DEPRECATED_LITE_PAGE_REDIRECT:
+    case previews::PreviewsType::DEPRECATED_LOFI:
+    case previews::PreviewsType::DEPRECATED_OFFLINE:
       NOTREACHED();
       break;
   }
 }
 
-void PreviewsUITabHelper::SetStalePreviewsStateForTesting(
-    base::Time previews_freshness,
-    bool is_reload) {
-  previews_freshness_ = previews_freshness;
-  is_stale_reload_ = is_reload;
-}
-
 void PreviewsUITabHelper::MaybeRecordPreviewReload(
     content::NavigationHandle* navigation_handle) {
   if (navigation_handle->GetReloadType() == content::ReloadType::NONE)
@@ -310,7 +219,6 @@
     std::move(on_dismiss_callback_).Run(false);
   }
 
-  previews_freshness_ = base::Time();
 #if defined(OS_ANDROID)
   should_display_android_omnibox_badge_ = false;
 #endif
@@ -337,76 +245,13 @@
 
   uint64_t page_id = (previews_user_data) ? previews_user_data->page_id() : 0;
 
-  // The ui should only be told if the page was a reload if the previous
-  // page displayed a timestamp.
-  is_stale_reload_ =
-      displayed_preview_timestamp_
-          ? navigation_handle->GetReloadType() != content::ReloadType::NONE
-          : false;
   displayed_preview_ui_ = false;
-  displayed_preview_timestamp_ = false;
-
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-  offline_pages::OfflinePageTabHelper* tab_helper =
-      offline_pages::OfflinePageTabHelper::FromWebContents(web_contents());
-
-  if (tab_helper && tab_helper->GetOfflinePreviewItem()) {
-    DCHECK(previews_user_data);
-    DCHECK_EQ(previews::PreviewsType::OFFLINE,
-              previews_user_data->CommittedPreviewsType());
-    UMA_HISTOGRAM_BOOLEAN("Previews.Offline.CommittedErrorPage",
-                          navigation_handle->IsErrorPage());
-    if (navigation_handle->IsErrorPage()) {
-      return;
-    }
-    data_reduction_proxy::DataReductionProxySettings*
-        data_reduction_proxy_settings =
-            DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-                web_contents()->GetBrowserContext());
-
-    const offline_pages::OfflinePageItem* offline_page =
-        tab_helper->GetOfflinePreviewItem();
-    // From UMA, the median percent of network body bytes loaded out of total
-    // body bytes on a page load. See PageLoad.Experimental.Bytes.Network and
-    // PageLoad.Experimental.Bytes.Total.
-    int64_t uncached_size = offline_page->file_size * 0.55;
-
-    bool data_saver_enabled =
-        data_reduction_proxy_settings->IsDataReductionProxyEnabled();
-
-    data_reduction_proxy_settings->data_reduction_proxy_service()
-        ->UpdateDataUseForHost(0, uncached_size,
-                               navigation_handle->GetRedirectChain()[0].host());
-
-    data_reduction_proxy_settings->data_reduction_proxy_service()
-        ->UpdateContentLengths(0, uncached_size, data_saver_enabled,
-                               data_reduction_proxy::HTTPS, "multipart/related",
-                               true,
-                               data_use_measurement::DataUseUserData::OTHER, 0);
-
-    ShowUIElement(previews::PreviewsType::OFFLINE,
-                  base::BindOnce(&AddPreviewNavigationCallback,
-                                 web_contents()->GetBrowserContext(),
-                                 navigation_handle->GetRedirectChain()[0],
-                                 previews::PreviewsType::OFFLINE, page_id));
-
-    // Don't try to show other UIs if this is an offline preview.
-    return;
-  }
-#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
 
   // Check for committed main frame preview.
   if (previews_user_data && previews_user_data->HasCommittedPreviewsType()) {
     previews::PreviewsType main_frame_preview =
         previews_user_data->CommittedPreviewsType();
     if (main_frame_preview != previews::PreviewsType::NONE) {
-      if (main_frame_preview == previews::PreviewsType::LITE_PAGE) {
-        const net::HttpResponseHeaders* headers =
-            navigation_handle->GetResponseHeaders();
-        if (headers)
-          headers->GetDateValue(&previews_freshness_);
-      }
-
       ShowUIElement(main_frame_preview,
                     base::BindOnce(&AddPreviewNavigationCallback,
                                    web_contents()->GetBrowserContext(),
diff --git a/chrome/browser/previews/previews_ui_tab_helper.h b/chrome/browser/previews/previews_ui_tab_helper.h
index f4f3536..10261c7 100644
--- a/chrome/browser/previews/previews_ui_tab_helper.h
+++ b/chrome/browser/previews/previews_ui_tab_helper.h
@@ -37,24 +37,8 @@
     : public content::WebContentsObserver,
       public content::WebContentsUserData<PreviewsUITabHelper> {
  public:
-  // Values of the UMA Previews.InfoBarTimestamp histogram. This enum must
-  // remain synchronized with the enum of the same name in
-  // metrics/histograms/histograms.xml.
-  enum class PreviewsStalePreviewTimestamp {
-    kTimestampShown = 0,
-    kTimestampNotShownPreviewNotStale = 1,
-    kTimestampNotShownStalenessNegative = 2,
-    kTimestampNotShownStalenessGreaterThanMax = 3,
-    kTimestampUpdatedNowShown = 4,
-    kMaxValue = kTimestampUpdatedNowShown,
-  };
-
   ~PreviewsUITabHelper() override;
 
-  // Returns the text to use for displaying the timestamp of a stale preview to
-  // the user.
-  base::string16 GetStalePreviewTimestampText();
-
   // Trigger the Previews UI to be shown to the user.
   void ShowUIElement(previews::PreviewsType previews_type,
                      OnDismissPreviewsUICallback on_dismiss_callback);
@@ -66,10 +50,6 @@
   // type.
   void ReloadWithoutPreviews(previews::PreviewsType previews_type);
 
-  // Sets |previews_freshness_| and |is_stale_reload_| for testing.
-  void SetStalePreviewsStateForTesting(base::Time previews_freshness,
-                                       bool is_reload);
-
   // Indicates whether the UI for a preview has been shown for the page.
   bool displayed_preview_ui() const { return displayed_preview_ui_; }
 
@@ -88,13 +68,6 @@
   }
 #endif
 
-  // Sets whether the timestamp on the UI for a preview has been shown for
-  // the page. |displayed_preview_timestamp_| is reset to false on
-  // DidStartProvisionalLoadForFrame for the main frame.
-  void set_displayed_preview_timestamp(bool displayed_preview_timestamp) {
-    displayed_preview_timestamp_ = displayed_preview_timestamp;
-  }
-
   // The Previews information related to the navigation that was most recently
   // finished.
   previews::PreviewsUserData* GetPreviewsUserData() const;
@@ -140,15 +113,6 @@
   // True if the UI for a preview has been shown for the page.
   bool displayed_preview_ui_ = false;
 
-  // True if the UI with a timestamp was shown for the page.
-  bool displayed_preview_timestamp_ = false;
-
-  // The time at which the stale preview was created, if any.
-  base::Time previews_freshness_;
-
-  // Whether or not the displayed preview is stale and was caused by a reload.
-  bool is_stale_reload_;
-
 #if defined(OS_ANDROID)
   // True if the Android Omnibox badge should be shown as the Previews UI.
   bool should_display_android_omnibox_badge_ = false;
diff --git a/chrome/browser/previews/previews_ui_tab_helper_unittest.cc b/chrome/browser/previews/previews_ui_tab_helper_unittest.cc
index 1747263..e856b618 100644
--- a/chrome/browser/previews/previews_ui_tab_helper_unittest.cc
+++ b/chrome/browser/previews/previews_ui_tab_helper_unittest.cc
@@ -32,9 +32,6 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "components/data_reduction_proxy/proto/data_store.pb.h"
-#include "components/offline_pages/buildflags/buildflags.h"
-#include "components/offline_pages/core/offline_page_item.h"
-#include "components/offline_pages/core/request_header/offline_page_header.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/previews/content/previews_user_data.h"
 #include "components/previews/core/previews_features.h"
@@ -48,10 +45,6 @@
 #include "net/http/http_util.h"
 #include "services/network/test/test_shared_url_loader_factory.h"
 
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-#include "chrome/browser/offline_pages/offline_page_tab_helper.h"
-#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
-
 namespace {
 const char kTestUrl[] = "http://www.test.com/";
 }
@@ -60,10 +53,6 @@
  protected:
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
-// Insert an OfflinePageTabHelper before PreviewsUITabHelper.
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-    offline_pages::OfflinePageTabHelper::CreateForWebContents(web_contents());
-#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
     PreviewsUITabHelper::CreateForWebContents(web_contents());
     test_handle_ = std::make_unique<content::MockNavigationHandle>(
         GURL(kTestUrl), main_rfh());
@@ -124,7 +113,7 @@
       PreviewsUITabHelper::FromWebContents(web_contents());
   EXPECT_FALSE(ui_tab_helper->displayed_preview_ui());
 
-  SetCommittedPreviewsType(previews::PreviewsType::LITE_PAGE);
+  SetCommittedPreviewsType(previews::PreviewsType::DEFER_ALL_SCRIPT);
   SimulateWillProcessResponse();
   CallDidFinishNavigation();
   base::RunLoop().RunUntilIdle();
@@ -145,7 +134,7 @@
   EXPECT_FALSE(ui_tab_helper->displayed_preview_ui());
   EXPECT_FALSE(ui_tab_helper->should_display_android_omnibox_badge());
 
-  SetCommittedPreviewsType(previews::PreviewsType::LITE_PAGE);
+  SetCommittedPreviewsType(previews::PreviewsType::DEFER_ALL_SCRIPT);
   SimulateWillProcessResponse();
   CallDidFinishNavigation();
   base::RunLoop().RunUntilIdle();
@@ -196,83 +185,6 @@
   EXPECT_FALSE(ui_tab_helper->GetPreviewsUserData());
 }
 
-#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-TEST_F(PreviewsUITabHelperUnitTest, CreateOfflineUI) {
-  PreviewsUITabHelper* ui_tab_helper =
-      PreviewsUITabHelper::FromWebContents(web_contents());
-  EXPECT_FALSE(ui_tab_helper->displayed_preview_ui());
-
-  content::WebContentsTester::For(web_contents())
-      ->SetMainFrameMimeType("multipart/related");
-
-  SimulateCommit();
-  offline_pages::OfflinePageItem item;
-  item.url = GURL(kTestUrl);
-  item.file_size = 100;
-  int64_t expected_file_size = .55 * item.file_size;
-  offline_pages::OfflinePageHeader header;
-  offline_pages::OfflinePageTabHelper::FromWebContents(web_contents())
-      ->SetOfflinePage(
-          item, header,
-          offline_pages::OfflinePageTrustedState::TRUSTED_AS_IN_INTERNAL_DIR,
-          true);
-
-  auto* data_reduction_proxy_settings =
-      DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
-          web_contents()->GetBrowserContext());
-
-  EXPECT_TRUE(data_reduction_proxy_settings->data_reduction_proxy_service()
-                  ->compression_stats()
-                  ->DataUsageMapForTesting()
-                  .empty());
-
-  profile()->GetPrefs()->SetBoolean("data_usage_reporting.enabled", true);
-  base::RunLoop().RunUntilIdle();
-
-  SetCommittedPreviewsType(previews::PreviewsType::OFFLINE);
-
-  CallDidFinishNavigation();
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_TRUE(ui_tab_helper->displayed_preview_ui());
-
-  // Navigate to reset the displayed state.
-  content::WebContentsTester::For(web_contents())
-      ->NavigateAndCommit(GURL(kTestUrl));
-
-  EXPECT_EQ(0, data_reduction_proxy_settings->data_reduction_proxy_service()
-                   ->compression_stats()
-                   ->GetHttpReceivedContentLength());
-
-  // Returns the value the total original size of all HTTP content received from
-  // the network.
-  EXPECT_EQ(expected_file_size,
-            data_reduction_proxy_settings->data_reduction_proxy_service()
-                ->compression_stats()
-                ->GetHttpOriginalContentLength());
-
-  EXPECT_FALSE(data_reduction_proxy_settings->data_reduction_proxy_service()
-                   ->compression_stats()
-                   ->DataUsageMapForTesting()
-                   .empty());
-
-  // Normalize the host name.
-  std::string host = GURL(kTestUrl).host();
-  size_t pos = host.find("://");
-  if (pos != std::string::npos)
-    host = host.substr(pos + 3);
-
-  EXPECT_EQ(expected_file_size,
-            data_reduction_proxy_settings->data_reduction_proxy_service()
-                ->compression_stats()
-                ->DataUsageMapForTesting()
-                .find(host)
-                ->second->original_size());
-
-  EXPECT_FALSE(ui_tab_helper->displayed_preview_ui());
-}
-#endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
-
 namespace {
 
 void OnDismiss(base::Optional<bool>* on_dismiss_value, bool param) {
@@ -291,12 +203,13 @@
 
   base::Optional<bool> on_dismiss_value;
 
-  ui_tab_helper->ShowUIElement(previews::PreviewsType::OFFLINE,
+  ui_tab_helper->ShowUIElement(previews::PreviewsType::DEFER_ALL_SCRIPT,
                                base::BindOnce(&OnDismiss, &on_dismiss_value));
 
   EXPECT_FALSE(on_dismiss_value);
 
-  ui_tab_helper->ReloadWithoutPreviews(previews::PreviewsType::OFFLINE);
+  ui_tab_helper->ReloadWithoutPreviews(
+      previews::PreviewsType::DEFER_ALL_SCRIPT);
 
   EXPECT_TRUE(on_dismiss_value);
   EXPECT_TRUE(on_dismiss_value.value());
@@ -312,7 +225,7 @@
 
   base::Optional<bool> on_dismiss_value;
 
-  ui_tab_helper->ShowUIElement(previews::PreviewsType::OFFLINE,
+  ui_tab_helper->ShowUIElement(previews::PreviewsType::DEFER_ALL_SCRIPT,
                                base::BindOnce(&OnDismiss, &on_dismiss_value));
 
   EXPECT_FALSE(on_dismiss_value);
diff --git a/chrome/browser/process_resource_usage.cc b/chrome/browser/process_resource_usage.cc
index ffba0ea5..b3eb3de 100644
--- a/chrome/browser/process_resource_usage.cc
+++ b/chrome/browser/process_resource_usage.cc
@@ -28,21 +28,21 @@
 void ProcessResourceUsage::RunPendingRefreshCallbacks() {
   DCHECK(thread_checker_.CalledOnValidThread());
   auto task_runner = base::ThreadTaskRunnerHandle::Get();
-  for (const auto& callback : refresh_callbacks_)
-    task_runner->PostTask(FROM_HERE, callback);
-  refresh_callbacks_.clear();
+  for (auto& callback : refresh_callbacks_)
+    task_runner->PostTask(FROM_HERE, std::move(callback));
 }
 
-void ProcessResourceUsage::Refresh(const base::Closure& callback) {
+void ProcessResourceUsage::Refresh(base::OnceClosure callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (!service_ || !service_.is_connected()) {
     if (!callback.is_null())
-      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                    std::move(callback));
     return;
   }
 
   if (!callback.is_null())
-    refresh_callbacks_.push_back(callback);
+    refresh_callbacks_.push_back(std::move(callback));
 
   if (!update_in_progress_) {
     update_in_progress_ = true;
diff --git a/chrome/browser/process_resource_usage.h b/chrome/browser/process_resource_usage.h
index 2265c85..dde6fea 100644
--- a/chrome/browser/process_resource_usage.h
+++ b/chrome/browser/process_resource_usage.h
@@ -65,7 +65,7 @@
 
   // Refresh the resource usage information. |callback| is invoked when the
   // usage data is updated, or when the IPC connection is lost.
-  void Refresh(const base::Closure& callback);
+  void Refresh(base::OnceClosure callback);
 
   // Get V8 memory usage information.
   bool ReportsV8MemoryStats() const;
@@ -83,7 +83,7 @@
 
   mojo::Remote<content::mojom::ResourceUsageReporter> service_;
   bool update_in_progress_;
-  base::circular_deque<base::Closure> refresh_callbacks_;
+  base::circular_deque<base::OnceClosure> refresh_callbacks_;
 
   content::mojom::ResourceUsageDataPtr stats_;
 
diff --git a/chrome/browser/referrer_policy_browsertest.cc b/chrome/browser/referrer_policy_browsertest.cc
index 1fe9f9d..a1f0111 100644
--- a/chrome/browser/referrer_policy_browsertest.cc
+++ b/chrome/browser/referrer_policy_browsertest.cc
@@ -629,7 +629,7 @@
   // Verify that the referrer policy was honored and the main page's origin was
   // send as referrer.
   content::RenderFrameHost* frame = content::FrameMatchingPredicate(
-      tab, base::Bind(&content::FrameIsChildOfMainFrame));
+      tab, base::BindRepeating(&content::FrameIsChildOfMainFrame));
   std::string title;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
       frame,
diff --git a/chrome/browser/resources/chromeos/login/components/fake_oobe.js b/chrome/browser/resources/chromeos/login/components/fake_oobe.js
index 8f5e715..b20a2546 100644
--- a/chrome/browser/resources/chromeos/login/components/fake_oobe.js
+++ b/chrome/browser/resources/chromeos/login/components/fake_oobe.js
@@ -7,8 +7,6 @@
  * closure_compiler coverage.
  */
 
-/** @typedef {string} */
-var ACCELERATOR_ENABLE_DEBBUGING = '1';
 
 /** @typedef {string} */
 var ACCELERATOR_DEVICE_REQUISITION_REMORA = '2';
@@ -34,7 +32,6 @@
 
   /**
    * @param {
-   *     ACCELERATOR_ENABLE_DEBBUGING |
    *     ACCELERATOR_DEVICE_REQUISITION_REMORA |
    *     ACCELERATOR_DEVICE_REQUISITION
    * } accelerator
diff --git a/chrome/browser/resources/chromeos/login/cr_ui.js b/chrome/browser/resources/chromeos/login/cr_ui.js
index b231a38..6fa252a8 100644
--- a/chrome/browser/resources/chromeos/login/cr_ui.js
+++ b/chrome/browser/resources/chromeos/login/cr_ui.js
@@ -267,7 +267,7 @@
    */
   Oobe.guestLoginForTesting = function() {
     Oobe.skipToLoginForTesting();
-    chrome.send('launchIncognito');
+    chrome.send('launchIncognitoForTesting');
   };
 
   /**
diff --git a/chrome/browser/resources/chromeos/login/oobe_hid_detection.js b/chrome/browser/resources/chromeos/login/oobe_hid_detection.js
index 7992f5f..46a39af0 100644
--- a/chrome/browser/resources/chromeos/login/oobe_hid_detection.js
+++ b/chrome/browser/resources/chromeos/login/oobe_hid_detection.js
@@ -133,7 +133,6 @@
   ready() {
     this.initializeLoginScreen('HIDDetectionScreen', {
       resetAllowed: false,
-      enableDebuggingAllowed: true,
     });
   },
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_reset.js b/chrome/browser/resources/chromeos/login/oobe_reset.js
index 3b77623..5cb07ed 100644
--- a/chrome/browser/resources/chromeos/login/oobe_reset.js
+++ b/chrome/browser/resources/chromeos/login/oobe_reset.js
@@ -171,7 +171,6 @@
   ready() {
     this.initializeLoginScreen('ResetScreen', {
       resetAllowed: false,
-      enableDebuggingAllowed: false,
     });
   },
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_terms_of_service.js b/chrome/browser/resources/chromeos/login/oobe_terms_of_service.js
index 7c596b68..c0fac61 100644
--- a/chrome/browser/resources/chromeos/login/oobe_terms_of_service.js
+++ b/chrome/browser/resources/chromeos/login/oobe_terms_of_service.js
@@ -56,7 +56,6 @@
   ready() {
     this.initializeLoginScreen('TermsOfServiceScreen', {
       resetAllowed: true,
-      enableDebuggingAllowed: true,
     });
   },
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.js b/chrome/browser/resources/chromeos/login/oobe_welcome.js
index 078efcc..d4085ea 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.js
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.js
@@ -94,7 +94,6 @@
   ready() {
     this.initializeLoginScreen('WelcomeScreen', {
       resetAllowed: true,
-      enableDebuggingAllowed: true,
     });
     this.updateLocalizedContent();
   },
@@ -281,7 +280,7 @@
    * @private
    */
   onEnableDebuggingClicked_() {
-    cr.ui.Oobe.handleAccelerator(ACCELERATOR_ENABLE_DEBBUGING);
+    this.userActed('enableDebugging');
   },
 
   /**
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
index 7f6df3d..bcc5063 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -815,8 +815,6 @@
     }
 
     params.doSamlRedirect = (this.screenMode_ == AuthMode.SAML_INTERSTITIAL);
-    params.menuGuestMode = data.guestSignin;
-    params.menuKeyboardOptions = false;
     params.menuEnterpriseEnrollment =
         !(data.enterpriseManagedDevice || data.hasDeviceOwner);
     params.isFirstUser = !(data.enterpriseManagedDevice || data.hasDeviceOwner);
@@ -980,10 +978,7 @@
    * @private
    */
   onMenuItemClicked_(e) {
-    if (e.detail == 'gm') {
-      Oobe.disableSigninUI();
-      chrome.send('launchIncognito');
-    } else if (e.detail == 'ee') {
+    if (e.detail == 'ee') {
       cr.ui.Oobe.handleAccelerator(ACCELERATOR_ENROLLMENT);
     }
   },
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js
index c641a03..f8e0765 100644
--- a/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -133,8 +133,6 @@
     'platformVersion',           // Version of the OS build.
     'releaseChannel',            // Installation channel.
     'endpointGen',               // Current endpoint generation.
-    'menuGuestMode',             // Enables "Guest mode" menu item
-    'menuKeyboardOptions',       // Enables "Keyboard options" menu item
     'menuEnterpriseEnrollment',  // Enables "Enterprise enrollment" menu item.
     'lsbReleaseBoard',           // Chrome OS Release board name
     'isFirstUser',               // True if this is non-enterprise device,
@@ -639,18 +637,8 @@
       if (data.endpointGen) {
         url = appendParam(url, 'endpoint_gen', data.endpointGen);
       }
-      let mi = '';
-      if (data.menuGuestMode) {
-        mi += 'gm,';
-      }
-      if (data.menuKeyboardOptions) {
-        mi += 'ko,';
-      }
       if (data.menuEnterpriseEnrollment) {
-        mi += 'ee,';
-      }
-      if (mi.length) {
-        url = appendParam(url, 'mi', mi);
+        url = appendParam(url, 'mi', 'ee');
       }
 
       if (data.isFirstUser) {
diff --git a/chrome/browser/safe_xml_parser_browsertest.cc b/chrome/browser/safe_xml_parser_browsertest.cc
index cc9b386..f0ebf5fc7c 100644
--- a/chrome/browser/safe_xml_parser_browsertest.cc
+++ b/chrome/browser/safe_xml_parser_browsertest.cc
@@ -53,7 +53,7 @@
   }
 
  private:
-  void XmlParsingDone(base::Closure quit_loop_closure,
+  void XmlParsingDone(base::OnceClosure quit_loop_closure,
                       std::unique_ptr<base::Value> expected_value,
                       data_decoder::DataDecoder::ValueOrError result) {
     base::ScopedClosureRunner runner(std::move(quit_loop_closure));
@@ -78,4 +78,3 @@
   TestParse("[\"this is JSON not XML\"]", "");
   TestParse(kTestXml, kTestJson);
 }
-
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java
index 741e076..140edfb 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java
@@ -86,6 +86,7 @@
     protected void destroy() {
         if (mWindowAndroid != null) {
             mWindowAndroid.removeActivityStateObserver(this);
+            mWindowAndroid = null;
         }
     }
 
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service.cc b/chrome/browser/supervised_user/supervised_user_settings_service.cc
index fd96b438..4cb5f9f0 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_settings_service.cc
@@ -171,7 +171,7 @@
   if (value)
     local_settings_->SetWithoutPathExpansion(key, std::move(value));
   else
-    local_settings_->RemoveWithoutPathExpansion(key, nullptr);
+    local_settings_->RemoveKey(key);
 
   InformSubscribers();
 }
@@ -350,7 +350,7 @@
       case SyncChange::ACTION_DELETE: {
         DLOG_IF(WARNING, !dict->HasKey(key)) << "Trying to delete nonexistent "
                                              << "key " << key;
-        dict->RemoveWithoutPathExpansion(key, nullptr);
+        dict->RemoveKey(key);
         break;
       }
       case SyncChange::ACTION_INVALID: {
diff --git a/chrome/browser/supervised_user/supervised_user_whitelist_service.cc b/chrome/browser/supervised_user/supervised_user_whitelist_service.cc
index 786400e..a0124cc 100644
--- a/chrome/browser/supervised_user/supervised_user_whitelist_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_whitelist_service.cc
@@ -293,7 +293,7 @@
     const std::string& id) {
   base::RecordAction(base::UserMetricsAction("ManagedUsers_Whitelist_Removed"));
 
-  pref_dict->RemoveWithoutPathExpansion(id, NULL);
+  pref_dict->RemoveKey(id);
   installer_->UnregisterWhitelist(client_id_, id);
   UnloadWhitelist(id);
 }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index ad8bc80..6c1b824 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -724,28 +724,27 @@
 void OmniboxViewViews::SetTextAndSelectedRanges(
     const base::string16& text,
     const std::vector<gfx::Range>& ranges) {
-  // Will try to fit as much of unselected text as possible. If possible,
-  // guarantees at least |pad_left| chars of the unselected text are visible. If
-  // possible given the prior guarantee, also guarantees |pad_right| chars of
-  // the selected text are visible.
-  static const uint32_t kPadRight = 30;
-  static const uint32_t kPadLeft = 10;
+  DCHECK(!ranges.empty());
 
-  SetText(text, ranges[0].end());
-  // Select all the text to prioritize showing unselected text.
-  SetSelectedRange(gfx::Range(ranges[0].start(), 0));
-  // Scroll range right, to ensure |kPadRight| chars of selected text are
-  // shown.
-  SetSelectedRange(
-      gfx::Range(ranges[0].start(),
-                 std::min(ranges[0].end() + kPadRight, ranges[0].start())));
-  // Scroll range left, to ensure |kPadLeft| chars of unselected text are
-  // shown.
-  SetSelectedRange(
-      gfx::Range(ranges[0].start(),
-                 ranges[0].end() - std::min(kPadLeft, ranges[0].end())));
-  // Select the specified ranges.
-  SetSelectedRanges(ranges);
+  // Will try to fit as much of the text preceding the cursor as possible. If
+  // possible, guarantees at least |kPadLeading| chars of the text preceding the
+  // the cursor are visible. If possible given the prior guarantee, also
+  // guarantees |kPadTrailing| chars of the text following the cursor are
+  // visible.
+  static const uint32_t kPadTrailing = 30;
+  static const uint32_t kPadLeading = 10;
+
+  // We use SetTextAndScrollAndSelectRange instead of SetText and
+  // SetSelectedRange in order to avoid triggering accessibility events multiple
+  // times.
+  SetTextAndScrollAndSelectRange(
+      text, ranges[0].end(),
+      {0, std::min<size_t>(ranges[0].end() + kPadTrailing, text.size()),
+       ranges[0].end() - std::min(kPadLeading, ranges[0].end())},
+      ranges[0]);
+  for (size_t i = 1; i < ranges.size(); i++)
+    SetSelectedRange(ranges[i], false);
+
   // Clear the additional text.
   SetAdditionalText(base::string16());
 }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index 723b45f..adb7663 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -804,6 +804,30 @@
             (std::vector<Range>{{10, 5}, {0, 2}}));
 }
 
+TEST_F(OmniboxViewViewsTest, OverflowingAutocompleteText) {
+  // Make the Omnibox narrow so it can't fit the entire string (~650px), but
+  // wide enough to fit the user text (~65px).
+  int kOmniboxWidth = 100;
+  gfx::RenderText* render_text = omnibox_view()->GetRenderText();
+  render_text->SetDisplayRect(gfx::Rect(0, 0, kOmniboxWidth, 10));
+
+  omnibox_textfield()->OnFocus();
+  omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
+      base::ASCIIToUTF16("user text. Followed by very long autocompleted text "
+                         "that is unlikely to fit in |kOmniboxWidth|"),
+      0, 10);
+
+  // NOTE: Technically (depending on the font), this expectation could fail if
+  // 'user text' doesn't fit in 100px or the entire string fits in 100px.
+  EXPECT_EQ(render_text->GetUpdatedDisplayOffset().x(), 0);
+  EXPECT_FALSE(omnibox_view()->IsSelectAll());
+
+  // On blur, the display should remain to the start of the text.
+  omnibox_textfield()->OnBlur();
+  EXPECT_EQ(render_text->GetUpdatedDisplayOffset().x(), 0);
+  EXPECT_FALSE(omnibox_view()->IsSelectAll());
+}
+
 class OmniboxViewViewsClipboardTest
     : public OmniboxViewViewsTest,
       public ::testing::WithParamInterface<ui::TextEditCommand> {
@@ -2293,28 +2317,3 @@
   ASSERT_TRUE(elide_animation);
   EXPECT_TRUE(elide_animation->IsAnimating());
 }
-
-// TODO (manukh) move up to where the other OmniboxViewViewsTest tests are.
-TEST_F(OmniboxViewViewsTest, OverflowingAutocompleteText) {
-  // Make the Omnibox narrow so it can't fit the entire string (~650px), but
-  // wide enough to fit the user text (~65px).
-  int kOmniboxWidth = 100;
-  gfx::RenderText* render_text = omnibox_view()->GetRenderText();
-  render_text->SetDisplayRect(gfx::Rect(0, 0, kOmniboxWidth, 10));
-
-  omnibox_textfield()->OnFocus();
-  omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
-      base::ASCIIToUTF16("user text. Followed by very long autocompleted text "
-                         "that is unlikely to fit in |kOmniboxWidth|"),
-      0, 10);
-
-  // NOTE: Technically (depending on the font), this expectation could fail if
-  // 'user text' doesn't fit in 100px or the entire string fits in 100px.
-  EXPECT_EQ(render_text->GetUpdatedDisplayOffset().x(), 0);
-  EXPECT_FALSE(omnibox_view()->IsSelectAll());
-
-  // On blur, the display should remain to the start of the text.
-  omnibox_textfield()->OnBlur();
-  EXPECT_EQ(render_text->GetUpdatedDisplayOffset().x(), 0);
-  EXPECT_FALSE(omnibox_view()->IsSelectAll());
-}
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 5d1b69b..b374e51 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -50,7 +50,6 @@
 #include "ui/views/event_monitor.h"
 #include "ui/views/view_tracker.h"
 #include "ui/views/widget/root_view.h"
-#include "ui/views/widget/widget.h"
 
 #if defined(OS_CHROMEOS)
 #include "ash/public/cpp/ash_features.h"
@@ -411,8 +410,7 @@
   if (g_tab_drag_controller == this)
     g_tab_drag_controller = nullptr;
 
-  if (move_loop_widget_)
-    move_loop_widget_->RemoveObserver(this);
+  widget_observer_.RemoveAll();
 
   if (is_dragging_window())
     GetAttachedBrowserWidget()->EndMoveLoop();
@@ -687,6 +685,10 @@
   Drag(GetCursorScreenPoint());
 }
 
+void TabDragController::OnWidgetDestroyed(views::Widget* widget) {
+  widget_observer_.Remove(widget);
+}
+
 void TabDragController::OnSourceTabStripEmpty() {
   // NULL out source_context_ so that we don't attempt to add back to it (in
   // the case of a revert).
@@ -876,7 +878,8 @@
     // results in a move). That'll cause all sorts of problems.  Reset the
     // observer so we don't get notified and process the event.
 #if defined(OS_CHROMEOS)
-    move_loop_widget_->RemoveObserver(this);
+    if (widget_observer_.IsObserving(move_loop_widget_))
+      widget_observer_.Remove(move_loop_widget_);
     move_loop_widget_ = nullptr;
 #endif  // OS_CHROMEOS
     views::Widget* browser_widget = GetAttachedBrowserWidget();
@@ -1394,7 +1397,7 @@
 
   move_loop_widget_ = GetAttachedBrowserWidget();
   DCHECK(move_loop_widget_);
-  move_loop_widget_->AddObserver(this);
+  widget_observer_.Add(move_loop_widget_);
   current_state_ = DragState::kDraggingWindow;
   base::WeakPtr<TabDragController> ref(weak_factory_.GetWeakPtr());
   if (can_release_capture_) {
@@ -1422,10 +1425,10 @@
 
   if (!ref)
     return;
-  if (move_loop_widget_) {
-    move_loop_widget_->RemoveObserver(this);
-    move_loop_widget_ = nullptr;
-  }
+
+  if (widget_observer_.IsObserving(move_loop_widget_))
+    widget_observer_.Remove(move_loop_widget_);
+  move_loop_widget_ = nullptr;
 
   if (current_state_ == DragState::kDraggingWindow) {
     current_state_ = DragState::kWaitingToStop;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h
index 4d53fe1b..7a06075 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -12,6 +12,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/views/tabs/tab_drag_context.h"
@@ -20,6 +21,7 @@
 #include "ui/base/models/list_selection_model.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_observer.h"
 
 namespace ui {
@@ -268,6 +270,7 @@
   // Overriden from views::WidgetObserver:
   void OnWidgetBoundsChanged(views::Widget* widget,
                              const gfx::Rect& new_bounds) override;
+  void OnWidgetDestroyed(views::Widget* widget) override;
 
   // Forget the source tabstrip. It doesn't exist any more, so it doesn't
   // make sense to insert dragged tabs back into it if the drag is reverted.
@@ -690,6 +693,8 @@
 
   std::unique_ptr<WindowFinder> window_finder_;
 
+  ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this};
+
   base::WeakPtrFactory<TabDragController> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TabDragController);
diff --git a/chrome/browser/ui/webui/autofill_and_password_manager_internals/autofill_internals_ui_browsertest.cc b/chrome/browser/ui/webui/autofill_and_password_manager_internals/autofill_internals_ui_browsertest.cc
new file mode 100644
index 0000000..07c7626
--- /dev/null
+++ b/chrome/browser/ui/webui/autofill_and_password_manager_internals/autofill_internals_ui_browsertest.cc
@@ -0,0 +1,79 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+
+namespace {
+
+class AutofillInternalsWebUIBrowserTest : public InProcessBrowserTest {
+ public:
+  content::EvalJsResult EvalJs(const std::string& code) {
+    content::WebContents* contents =
+        browser()->tab_strip_model()->GetActiveWebContents();
+    return content::EvalJs(contents, code,
+                           content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
+                           1 /* world_id */);
+  }
+
+  ::testing::AssertionResult ExecJs(const std::string& code) {
+    content::WebContents* contents =
+        browser()->tab_strip_model()->GetActiveWebContents();
+    return content::ExecJs(contents, code,
+                           content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
+                           1 /* world_id */);
+  }
+
+  void SpinRunLoop() {
+    base::RunLoop run_loop;
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(),
+        base::TimeDelta::FromMilliseconds(20));
+    run_loop.Run();
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(AutofillInternalsWebUIBrowserTest, ResetCache) {
+  ui_test_utils::NavigateToURL(browser(), GURL("chrome://autofill-internals"));
+
+  // Wait for reset-fake-button to become visible
+  constexpr char kGetResetButtonDisplayStyle[] =
+      "document.getElementById('reset-cache-fake-button').style.display";
+  while ("inline-block" != EvalJs(kGetResetButtonDisplayStyle))
+    SpinRunLoop();
+
+  // Trigger reset button.
+  constexpr char kClickResetButton[] =
+      "document.getElementById('reset-cache-fake-button').click();";
+  EXPECT_TRUE(ExecJs(kClickResetButton));
+
+  // Wait for dialog to appear.
+  constexpr char kDialogTextVisible[] =
+      "document.getElementsByClassName('modal-dialog-text').length > 0";
+  while (!EvalJs(kDialogTextVisible).ExtractBool())
+    SpinRunLoop();
+
+  // Check result text.
+  constexpr char kDialogText[] =
+      "document.getElementsByClassName('modal-dialog-text')[0].innerText";
+  EXPECT_EQ(autofill::kCacheResetDone, EvalJs(kDialogText));
+
+  // Close dialog.
+  constexpr char kClickCloseButton[] =
+      "document.getElementsByClassName('modal-dialog-close-button')[0]"
+      ".click();";
+  EXPECT_TRUE(ExecJs(kClickCloseButton));
+
+  // Wait for dialog to disappear.
+  while (EvalJs(kDialogTextVisible).ExtractBool())
+    SpinRunLoop();
+}
+
+}  // namespace
diff --git a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc
index 148cc97..e782fb85 100644
--- a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc
+++ b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.cc
@@ -16,6 +16,8 @@
 #include "components/version_info/version_info.h"
 #include "components/version_ui/version_handler_helper.h"
 #include "components/version_ui/version_ui_constants.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browsing_data_filter_builder.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 
@@ -44,6 +46,42 @@
   return source;
 }
 
+AutofillCacheResetter::AutofillCacheResetter(
+    content::BrowserContext* browser_context)
+    : remover_(
+          content::BrowserContext::GetBrowsingDataRemover(browser_context)) {
+  remover_->AddObserver(this);
+}
+
+AutofillCacheResetter::~AutofillCacheResetter() {
+  remover_->RemoveObserver(this);
+}
+
+void AutofillCacheResetter::ResetCache(Callback callback) {
+  if (callback_) {
+    std::move(callback).Run(kCacheResetAlreadyInProgress);
+    return;
+  }
+
+  callback_ = std::move(callback);
+
+  std::unique_ptr<content::BrowsingDataFilterBuilder> filter_builder =
+      content::BrowsingDataFilterBuilder::Create(
+          content::BrowsingDataFilterBuilder::Mode::kDelete);
+  filter_builder->AddOrigin(
+      url::Origin::Create(GURL("https://content-autofill.googleapis.com")));
+  remover_->RemoveWithFilterAndReply(
+      base::Time::Min(), base::Time::Max(),
+      content::BrowsingDataRemover::DATA_TYPE_CACHE,
+      content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB,
+      std::move(filter_builder), this);
+}
+
+void AutofillCacheResetter::OnBrowsingDataRemoverDone(
+    uint64_t failed_data_types) {
+  std::move(callback_).Run(kCacheResetDone);
+}
+
 InternalsUIHandler::InternalsUIHandler(
     std::string call_on_load,
     GetLogRouterFunction get_log_router_function)
@@ -58,6 +96,9 @@
   web_ui()->RegisterMessageCallback(
       "loaded", base::BindRepeating(&InternalsUIHandler::OnLoaded,
                                     base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "resetCache", base::BindRepeating(&InternalsUIHandler::OnResetCache,
+                                        base::Unretained(this)));
 }
 
 void InternalsUIHandler::OnJavascriptAllowed() {
@@ -71,6 +112,10 @@
 void InternalsUIHandler::OnLoaded(const base::ListValue* args) {
   AllowJavascript();
   CallJavascriptFunction(call_on_load_);
+  // This is only available in contents, because the iOS BrowsingDataRemover
+  // does not allow selectively deleting data per origin and we don't want to
+  // wipe the entire cache.
+  CallJavascriptFunction("enableResetCacheButton");
   CallJavascriptFunction(
       "notifyAboutIncognito",
       base::Value(Profile::FromWebUI(web_ui())->IsIncognitoProfile()));
@@ -78,6 +123,19 @@
                          *version_ui::GetVariationsList());
 }
 
+void InternalsUIHandler::OnResetCache(const base::ListValue* args) {
+  if (!autofill_cache_resetter_) {
+    content::BrowserContext* browser_context = Profile::FromWebUI(web_ui());
+    autofill_cache_resetter_.emplace(browser_context);
+  }
+  autofill_cache_resetter_->ResetCache(base::Bind(
+      &InternalsUIHandler::OnResetCacheDone, base::Unretained(this)));
+}
+
+void InternalsUIHandler::OnResetCacheDone(const std::string& message) {
+  CallJavascriptFunction("notifyResetDone", base::Value(message));
+}
+
 void InternalsUIHandler::StartSubscription() {
   LogRouter* log_router =
       get_log_router_function_.Run(Profile::FromWebUI(web_ui()));
diff --git a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h
index 8a6594f..2d274054 100644
--- a/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h
+++ b/chrome/browser/ui/webui/autofill_and_password_manager_internals/internals_ui_handler.h
@@ -9,7 +9,9 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "base/optional.h"
 #include "components/autofill/core/browser/logging/log_receiver.h"
+#include "content/public/browser/browsing_data_remover.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 namespace autofill {
@@ -22,9 +24,35 @@
 }  // namespace content
 
 namespace autofill {
+
+constexpr char kCacheResetDone[] =
+    "Done. Please close and reopen all tabs that should be affected by the "
+    "cache reset.";
+constexpr char kCacheResetAlreadyInProgress[] = "Reset already in progress";
+
 content::WebUIDataSource* CreateInternalsHTMLSource(
     const std::string& source_name);
 
+// Class that wipes responses from the Autofill server from the HTTP cache.
+class AutofillCacheResetter : public content::BrowsingDataRemover::Observer {
+ public:
+  using Callback = base::OnceCallback<void(const std::string&)>;
+
+  explicit AutofillCacheResetter(content::BrowserContext* browser_context);
+  ~AutofillCacheResetter() override;
+  AutofillCacheResetter(const AutofillCacheResetter&) = delete;
+  AutofillCacheResetter operator=(const AutofillCacheResetter) = delete;
+
+  void ResetCache(Callback callback);
+
+ private:
+  // Implements content::BrowsingDataRemover::Observer.
+  void OnBrowsingDataRemoverDone(uint64_t failed_data_types) override;
+
+  content::BrowsingDataRemover* remover_;
+  Callback callback_;
+};
+
 // UI handler for chrome://password-manager-internals and
 // chrome://autofill-internals that takes care of subscribing to the autofill
 // logging instance.
@@ -54,6 +82,9 @@
 
   // JavaScript call handler.
   void OnLoaded(const base::ListValue* args);
+  void OnResetCache(const base::ListValue* args);
+
+  void OnResetCacheDone(const std::string& message);
 
   // JavaScript function to be called on load.
   std::string call_on_load_;
@@ -62,6 +93,8 @@
   // Whether |this| is registered as a log receiver with the LogRouter.
   bool registered_with_log_router_ = false;
 
+  base::Optional<AutofillCacheResetter> autofill_cache_resetter_;
+
   DISALLOW_COPY_AND_ASSIGN(InternalsUIHandler);
 };
 
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
index 2778e76..aaa1316 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -152,8 +152,6 @@
               &CoreOobeHandler::HandleSkipToUpdateForTesting);
   AddCallback("launchHelpApp", &CoreOobeHandler::HandleLaunchHelpApp);
   AddCallback("toggleResetScreen", &CoreOobeHandler::HandleToggleResetScreen);
-  AddCallback("toggleEnableDebuggingScreen",
-              &CoreOobeHandler::HandleEnableDebuggingScreen);
   AddCallback("raiseTabKeyEvent", &CoreOobeHandler::HandleRaiseTabKeyEvent);
   // Note: Used by enterprise_RemoraRequisitionDisplayUsage.py:
   // TODO(felixe): Use chrome.system.display or cros_display_config.mojom,
@@ -181,12 +179,6 @@
   LaunchResetScreen();
 }
 
-void CoreOobeHandler::ShowEnableDebuggingScreen() {
-  DCHECK(LoginDisplayHost::default_host());
-  LoginDisplayHost::default_host()->StartWizard(
-      EnableDebuggingScreenView::kScreenId);
-}
-
 void CoreOobeHandler::ShowEnableAdbSideloadingScreen() {
   DCHECK(LoginDisplayHost::default_host());
   LoginDisplayHost::default_host()->StartWizard(
@@ -310,10 +302,6 @@
   LaunchResetScreen();
 }
 
-void CoreOobeHandler::HandleEnableDebuggingScreen() {
-  ShowEnableDebuggingScreen();
-}
-
 void CoreOobeHandler::ShowOobeUI(bool show) {
   if (show == show_oobe_ui_)
     return;
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
index 1aacf561..4af5bc0 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
@@ -67,7 +67,6 @@
   virtual void SetDialogPaddingMode(DialogPaddingMode mode) = 0;
   virtual void ShowDeviceResetScreen() = 0;
   virtual void ShowEnableAdbSideloadingScreen() = 0;
-  virtual void ShowEnableDebuggingScreen() = 0;
   virtual void UpdateKeyboardState() = 0;
 };
 
@@ -141,7 +140,6 @@
   void SetDialogPaddingMode(CoreOobeView::DialogPaddingMode mode) override;
   void ShowDeviceResetScreen() override;
   void ShowEnableAdbSideloadingScreen() override;
-  void ShowEnableDebuggingScreen() override;
 
   void UpdateKeyboardState() override;
 
@@ -161,7 +159,6 @@
   void HandleSkipToUpdateForTesting();
   void HandleLaunchHelpApp(double help_topic_id);
   void HandleToggleResetScreen();
-  void HandleEnableDebuggingScreen();
   void HandleGetPrimaryDisplayNameForTesting(const base::ListValue* args);
   void GetPrimaryDisplayNameCallback(
       const base::Value& callback_id,
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 3e90576..1d5554c 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -1464,12 +1464,11 @@
   }
   UpdateState(NetworkError::ERROR_REASON_UPDATE);
 
+  // TODO(crbug.com/1105387): Part of initial screen logic.
   if (core_oobe_view_) {
     PrefService* prefs = g_browser_process->local_state();
     if (prefs->GetBoolean(prefs::kFactoryResetRequested)) {
       core_oobe_view_->ShowDeviceResetScreen();
-    } else if (prefs->GetBoolean(prefs::kDebuggingFeaturesRequested)) {
-      core_oobe_view_->ShowEnableDebuggingScreen();
     }
   }
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index 9944873..7a438a7 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -407,14 +407,13 @@
   AddCallback("authenticateUser", &SigninScreenHandler::HandleAuthenticateUser);
   AddCallback("completeOfflineAuthentication",
               &SigninScreenHandler::HandleCompleteOfflineAuthentication);
-  AddCallback("launchIncognito", &SigninScreenHandler::HandleLaunchIncognito);
+  AddCallback("launchIncognitoForTesting",
+              &SigninScreenHandler::HandleLaunchIncognitoForTesting);
   AddCallback("launchSAMLPublicSession",
               &SigninScreenHandler::HandleLaunchSAMLPublicSession);
   AddRawCallback("offlineLogin", &SigninScreenHandler::HandleOfflineLogin);
   AddCallback("toggleEnrollmentScreen",
               &SigninScreenHandler::HandleToggleEnrollmentScreen);
-  AddCallback("toggleEnableDebuggingScreen",
-              &SigninScreenHandler::HandleToggleEnableDebuggingScreen);
   AddCallback("toggleKioskEnableScreen",
               &SigninScreenHandler::HandleToggleKioskEnableScreen);
   AddCallback("accountPickerReady",
@@ -1032,7 +1031,7 @@
                            false /* authenticated_by_pin */);
 }
 
-void SigninScreenHandler::HandleLaunchIncognito() {
+void SigninScreenHandler::HandleLaunchIncognitoForTesting() {
   UserContext context(user_manager::USER_TYPE_GUEST, EmptyAccountId());
   if (delegate_)
     delegate_->Login(context, SigninSpecifics());
@@ -1068,11 +1067,6 @@
     delegate_->ShowEnterpriseEnrollmentScreen();
 }
 
-void SigninScreenHandler::HandleToggleEnableDebuggingScreen() {
-  if (delegate_)
-    delegate_->ShowEnableDebuggingScreen();
-}
-
 void SigninScreenHandler::HandleToggleKioskEnableScreen() {
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index d88b50d..184150b 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -98,9 +98,6 @@
   // Shows Enterprise Enrollment screen.
   virtual void ShowEnterpriseEnrollmentScreen() = 0;
 
-  // Shows Enable Developer Features screen.
-  virtual void ShowEnableDebuggingScreen() = 0;
-
   // Shows Kiosk Enable screen.
   virtual void ShowKioskEnableScreen() = 0;
 
@@ -275,11 +272,10 @@
                               bool authenticated_by_pin);
   void HandleCompleteOfflineAuthentication(const std::string& email,
                                            const std::string& password);
-  void HandleLaunchIncognito();
+  void HandleLaunchIncognitoForTesting();
   void HandleLaunchSAMLPublicSession(const std::string& email);
   void HandleOfflineLogin(const base::ListValue* args);
   void HandleToggleEnrollmentScreen();
-  void HandleToggleEnableDebuggingScreen();
   void HandleToggleKioskEnableScreen();
   void HandleToggleResetScreen();
   void HandleToggleKioskAutolaunchScreen();
diff --git a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc
index 759d2751..2e6dc1a 100644
--- a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.cc
@@ -70,17 +70,13 @@
     return;
   }
 
+  // TODO(crbug.com/1105387): Part of initial screen logic.
   PrefService* prefs = g_browser_process->local_state();
   if (prefs->GetBoolean(prefs::kFactoryResetRequested)) {
     if (core_oobe_view_)
       core_oobe_view_->ShowDeviceResetScreen();
 
     return;
-  } else if (prefs->GetBoolean(prefs::kDebuggingFeaturesRequested)) {
-    if (core_oobe_view_)
-      core_oobe_view_->ShowEnableDebuggingScreen();
-
-    return;
   }
 
   base::DictionaryValue welcome_screen_params;
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc
index fbce5852..87c31b3 100644
--- a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc
+++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc
@@ -35,7 +35,6 @@
 const char kPreviewsAllowedHtmlId[] = "previews-allowed-status";
 const char kNoScriptPreviewsHtmlId[] = "noscript-preview-status";
 const char kResourceLoadingHintsHtmlId[] = "resource-loading-hints-status";
-const char kOfflinePreviewsHtmlId[] = "offline-preview-status";
 const char kDeferAllScriptPreviewsHtmlId[] = "defer-all-script-preview-status";
 
 // Descriptions for previews.
@@ -43,21 +42,16 @@
 const char kNoScriptDescription[] = "NoScript Previews";
 const char kResourceLoadingHintsDescription[] = "ResourceLoadingHints Previews";
 const char kDeferAllScriptPreviewsDescription[] = "DeferAllScript Previews";
-const char kOfflineDesciption[] = "Offline Previews";
 
 // Flag feature name.
 const char kPreviewsAllowedFeatureName[] = "Previews";
 const char kNoScriptFeatureName[] = "NoScriptPreviews";
 const char kResourceLoadingHintsFeatureName[] = "ResourceLoadingHints";
 const char kDeferAllScriptFeatureName[] = "DeferAllScript";
-#if defined(OS_ANDROID)
-const char kOfflinePageFeatureName[] = "OfflinePreviews";
-#endif  // OS_ANDROID
 
 // HTML DOM ID used in the JavaScript code. The IDs are generated here so that
 // the DOM would have sensible name instead of autogenerated IDs.
 const char kPreviewsAllowedFlagHtmlId[] = "previews-flag";
-const char kOfflinePageFlagHtmlId[] = "offline-page-flag";
 const char kResourceLoadingHintsFlagHtmlId[] = "resource-loading-hints-flag";
 const char kDeferAllScriptFlagHtmlId[] = "defer-all-script-flag";
 const char kNoScriptFlagHtmlId[] = "noscript-flag";
@@ -69,7 +63,6 @@
 // Links to flags in chrome://flags.
 // TODO(thanhdle): Refactor into vector of structs. crbug.com/787010.
 const char kPreviewsAllowedFlagLink[] = "chrome://flags/#allow-previews";
-const char kOfflinePageFlagLink[] = "chrome://flags/#enable-offline-previews";
 const char kResourceLoadingHintsFlagLink[] =
     "chrome://flags/#enable-resource-loading-hints";
 const char kDeferAllScriptFlagLink[] =
@@ -225,12 +218,6 @@
   previews_allowed_status->htmlId = kPreviewsAllowedHtmlId;
   statuses.push_back(std::move(previews_allowed_status));
 
-  auto offline_status = mojom::PreviewsStatus::New();
-  offline_status->description = kOfflineDesciption;
-  offline_status->enabled = previews::params::IsOfflinePreviewsEnabled();
-  offline_status->htmlId = kOfflinePreviewsHtmlId;
-  statuses.push_back(std::move(offline_status));
-
   auto resource_loading_hints_status = mojom::PreviewsStatus::New();
   resource_loading_hints_status->description = kResourceLoadingHintsDescription;
   resource_loading_hints_status->enabled =
@@ -268,19 +255,6 @@
   previews_allowed_status->htmlId = kPreviewsAllowedFlagHtmlId;
   flags.push_back(std::move(previews_allowed_status));
 
-  auto offline_page_status = mojom::PreviewsFlag::New();
-#if defined(OS_ANDROID)
-  offline_page_status->description =
-      flag_descriptions::kEnableOfflinePreviewsName;
-  offline_page_status->value = GetFeatureFlagStatus(kOfflinePageFeatureName);
-#else
-  offline_page_status->description = "Offline Page Previews";
-  offline_page_status->value = "Only support on Android";
-#endif  // OS_ANDROID
-  offline_page_status->link = kOfflinePageFlagLink;
-  offline_page_status->htmlId = kOfflinePageFlagHtmlId;
-  flags.push_back(std::move(offline_page_status));
-
   auto resource_loading_hints_status = mojom::PreviewsFlag::New();
   resource_loading_hints_status->description =
       flag_descriptions::kEnableResourceLoadingHintsName;
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
index f61271fc..55255ef8 100644
--- a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
@@ -53,7 +53,6 @@
 
 // The HTML DOM ID used in Javascript.
 constexpr char kPreviewsAllowedHtmlId[] = "previews-allowed-status";
-constexpr char kOfflinePreviewsHtmlId[] = "offline-preview-status";
 constexpr char kResourceLoadingHintsHtmlId[] = "resource-loading-hints-status";
 constexpr char kDeferAllScriptPreviewsHtmlId[] =
     "defer-all-script-preview-status";
@@ -61,14 +60,12 @@
 
 // Descriptions for previews.
 constexpr char kPreviewsAllowedDescription[] = "Previews Allowed";
-constexpr char kOfflineDesciption[] = "Offline Previews";
 constexpr char kResourceLoadingHintsDescription[] =
     "ResourceLoadingHints Previews";
 constexpr char kDeferAllScriptPreviewsDescription[] = "DeferAllScript Previews";
 constexpr char kNoScriptDescription[] = "NoScript Previews";
 
 // The HTML DOM ID used in Javascript.
-constexpr char kOfflinePageFlagHtmlId[] = "offline-page-flag";
 constexpr char kResourceLoadingHintsFlagHtmlId[] =
     "resource-loading-hints-flag";
 constexpr char kDeferAllScriptFlagHtmlId[] = "defer-all-script-flag";
@@ -80,8 +77,6 @@
     "data-reduction-proxy-server-experiment";
 
 // Links to flags in chrome://flags.
-constexpr char kOfflinePageFlagLink[] =
-    "chrome://flags/#enable-offline-previews";
 constexpr char kResourceLoadingHintsFlagLink[] =
     "chrome://flags/#enable-resource-loading-hints";
 constexpr char kDeferAllScriptFlagLink[] =
@@ -95,7 +90,6 @@
     "chrome://flags/#enable-data-reduction-proxy-server-experiment";
 
 // Flag features names.
-constexpr char kOfflinePageFeatureName[] = "OfflinePreviews";
 constexpr char kResourceLoadingHintsFeatureName[] = "ResourceLoadingHints";
 constexpr char kDeferAllScriptFeatureName[] = "DeferAllScriptPreviews";
 constexpr char kNoScriptFeatureName[] = "NoScriptPreviews";
@@ -327,7 +321,7 @@
   page_handler_->GetPreviewsEnabled(
       base::BindOnce(&MockGetPreviewsEnabledCallback));
 
-  constexpr size_t expected = 5;
+  constexpr size_t expected = 4;
   EXPECT_EQ(expected, passed_in_modes.size());
 }
 
@@ -411,33 +405,6 @@
   EXPECT_TRUE(resource_loading_hints->second->enabled);
 }
 
-TEST_F(InterventionsInternalsPageHandlerTest, OfflinePreviewsDisabled) {
-  // Init with kOfflinePreviews disabled.
-  scoped_feature_list_->InitWithFeatures(
-      {}, {previews::features::kOfflinePreviews});
-
-  page_handler_->GetPreviewsEnabled(
-      base::BindOnce(&MockGetPreviewsEnabledCallback));
-  auto offline_previews = passed_in_modes.find(kOfflinePreviewsHtmlId);
-  ASSERT_NE(passed_in_modes.end(), offline_previews);
-  EXPECT_EQ(kOfflineDesciption, offline_previews->second->description);
-  EXPECT_FALSE(offline_previews->second->enabled);
-}
-
-TEST_F(InterventionsInternalsPageHandlerTest, OfflinePreviewsEnabled) {
-  // Init with kOfflinePreviews enabled.
-  scoped_feature_list_->InitWithFeatures({previews::features::kOfflinePreviews},
-                                         {});
-
-  page_handler_->GetPreviewsEnabled(
-      base::BindOnce(&MockGetPreviewsEnabledCallback));
-  auto offline_previews = passed_in_modes.find(kOfflinePreviewsHtmlId);
-  ASSERT_NE(passed_in_modes.end(), offline_previews);
-  EXPECT_TRUE(offline_previews->second);
-  EXPECT_EQ(kOfflineDesciption, offline_previews->second->description);
-  EXPECT_TRUE(offline_previews->second->enabled);
-}
-
 TEST_F(InterventionsInternalsPageHandlerTest, DeferAllScriptPreviewsDisabled) {
   // Init with kDeferAllScriptPreviews disabled.
   scoped_feature_list_->InitWithFeatures(
@@ -470,7 +437,7 @@
   page_handler_->GetPreviewsFlagsDetails(
       base::BindOnce(&MockGetPreviewsFlagsCallback));
 
-  constexpr size_t expected = 8;
+  constexpr size_t expected = 7;
   EXPECT_EQ(expected, passed_in_flags.size());
 }
 
@@ -744,66 +711,6 @@
   EXPECT_EQ(kDataSaverAltConfigLink, alt_config_flag->second->link);
 }
 
-#if defined(OS_ANDROID)
-#define TestAndroid(x) x
-#else
-#define TestAndroid(x) DISABLED_##x
-#endif  // OS_ANDROID
-TEST_F(InterventionsInternalsPageHandlerTest,
-       TestAndroid(GetFlagsOfflinePageDefaultValue)) {
-  page_handler_->GetPreviewsFlagsDetails(
-      base::BindOnce(&MockGetPreviewsFlagsCallback));
-  auto offline_page_flag = passed_in_flags.find(kOfflinePageFlagHtmlId);
-
-  ASSERT_NE(passed_in_flags.end(), offline_page_flag);
-#if defined(OS_ANDROID)
-  EXPECT_EQ(flag_descriptions::kEnableOfflinePreviewsName,
-            offline_page_flag->second->description);
-#endif  // OS_ANDROID
-  EXPECT_EQ(kDefaultFlagValue, offline_page_flag->second->value);
-  EXPECT_EQ(kOfflinePageFlagLink, offline_page_flag->second->link);
-}
-
-TEST_F(InterventionsInternalsPageHandlerTest,
-       TestAndroid(GetFlagsOfflinePageEnabled)) {
-  base::test::ScopedCommandLine scoped_command_line;
-  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
-  command_line->AppendSwitchASCII(switches::kEnableFeatures,
-                                  kOfflinePageFeatureName);
-
-  page_handler_->GetPreviewsFlagsDetails(
-      base::BindOnce(&MockGetPreviewsFlagsCallback));
-  auto offline_page_flag = passed_in_flags.find(kOfflinePageFlagHtmlId);
-
-  ASSERT_NE(passed_in_flags.end(), offline_page_flag);
-#if defined(OS_ANDROID)
-  EXPECT_EQ(flag_descriptions::kEnableOfflinePreviewsName,
-            offline_page_flag->second->description);
-#endif  // OS_ANDROID
-  EXPECT_EQ(kEnabledFlagValue, offline_page_flag->second->value);
-  EXPECT_EQ(kOfflinePageFlagLink, offline_page_flag->second->link);
-}
-
-TEST_F(InterventionsInternalsPageHandlerTest,
-       TestAndroid(GetFlagsOfflinePageDisabled)) {
-  base::test::ScopedCommandLine scoped_command_line;
-  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
-  command_line->AppendSwitchASCII(switches::kDisableFeatures,
-                                  kOfflinePageFeatureName);
-
-  page_handler_->GetPreviewsFlagsDetails(
-      base::BindOnce(&MockGetPreviewsFlagsCallback));
-  auto offline_page_flag = passed_in_flags.find(kOfflinePageFlagHtmlId);
-
-  ASSERT_NE(passed_in_flags.end(), offline_page_flag);
-#if defined(OS_ANDROID)
-  EXPECT_EQ(flag_descriptions::kEnableOfflinePreviewsName,
-            offline_page_flag->second->description);
-#endif  // OS_ANDROID
-  EXPECT_EQ(kDisabledFlagValue, offline_page_flag->second->value);
-  EXPECT_EQ(kOfflinePageFlagLink, offline_page_flag->second->link);
-}
-
 TEST_F(InterventionsInternalsPageHandlerTest, OnNewMessageLogAddedPostToPage) {
   const previews::PreviewsLogger::MessageLog expected_messages[] = {
       previews::PreviewsLogger::MessageLog(
diff --git a/chrome/browser/web_applications/components/web_app_install_utils.cc b/chrome/browser/web_applications/components/web_app_install_utils.cc
index 6b4405f1..a4d884da 100644
--- a/chrome/browser/web_applications/components/web_app_install_utils.cc
+++ b/chrome/browser/web_applications/components/web_app_install_utils.cc
@@ -152,6 +152,9 @@
   if (manifest.display != DisplayMode::kUndefined)
     web_app_info->display_mode = manifest.display;
 
+  if (!manifest.display_override.empty())
+    web_app_info->display_override = manifest.display_override;
+
   // Create the WebApplicationInfo icons list *outside* of |web_app_info|, so
   // that we can decide later whether or not to replace the existing icons array
   // (conditionally on whether there were any that didn't have purpose ANY).
diff --git a/chrome/browser/web_applications/components/web_app_install_utils_unittest.cc b/chrome/browser/web_applications/components/web_app_install_utils_unittest.cc
index 1a9e1a7d..99f852d0 100644
--- a/chrome/browser/web_applications/components/web_app_install_utils_unittest.cc
+++ b/chrome/browser/web_applications/components/web_app_install_utils_unittest.cc
@@ -112,6 +112,7 @@
   EXPECT_EQ(AppUrl(), web_app_info.app_url);
   EXPECT_EQ(AppUrl().GetWithoutFilename(), web_app_info.scope);
   EXPECT_EQ(DisplayMode::kBrowser, web_app_info.display_mode);
+  EXPECT_TRUE(web_app_info.display_override.empty());
 
   // The icon info from |web_app_info| should be left as is, since the manifest
   // doesn't have any icon information.
@@ -133,10 +134,15 @@
   // Add an icon without purpose ANY (expect to be ignored).
   icon.purpose = {blink::Manifest::ImageResource::Purpose::MONOCHROME};
   manifest.icons.push_back(icon);
+  manifest.display_override.push_back(DisplayMode::kMinimalUi);
+  manifest.display_override.push_back(DisplayMode::kStandalone);
 
   UpdateWebAppInfoFromManifest(manifest, &web_app_info);
   EXPECT_EQ(base::UTF8ToUTF16(kAppTitle), web_app_info.title);
   EXPECT_EQ(DisplayMode::kMinimalUi, web_app_info.display_mode);
+  ASSERT_EQ(2u, web_app_info.display_override.size());
+  EXPECT_EQ(DisplayMode::kMinimalUi, web_app_info.display_override[0]);
+  EXPECT_EQ(DisplayMode::kStandalone, web_app_info.display_override[1]);
 
   EXPECT_EQ(2u, web_app_info.icon_infos.size());
   EXPECT_EQ(AppIcon2(), web_app_info.icon_infos[0].url);
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index b4b586c1..29b48f4 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1594771186-d832f8303da18f87f12d9f2a0dd0e6f277bb9e8f.profdata
+chrome-mac-master-1594814211-0517d79b9f4059a1b68c79d5638e00f140bf56b4.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index a0fea18..76cb488 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1594640123-fdf8a72e5b13627e142e52b62a8ba89cbc874f73.profdata
+chrome-win64-master-1594771186-8c7f3834398f8caaba6f32c369440926161c5207.profdata
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
index 8385bc2..acc4134d 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
@@ -336,10 +336,6 @@
   // system should allow us to design a system that is simple enough to explain
   // yet powerful enough to encapsulate all the messages we want to display.
   ChromePermissionMessageRule rules_arr[] = {
-      // BEGIN POWERFUL PERMISSIONS:
-      // The following permissions are shown in the chrome://management page.
-      // See also GetPowerfulPermissionMessages().
-
       // Full access permission messages.
       {IDS_EXTENSION_PROMPT_WARNING_DEBUGGER, {APIPermission::kDebugger}, {}},
       {IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS,
@@ -394,6 +390,21 @@
        {APIPermission::kNewTabPageOverride},
        {}},
 
+      // Video and audio capture.
+      {IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE,
+       {APIPermission::kAudioCapture, APIPermission::kVideoCapture},
+       {}},
+      {IDS_EXTENSION_PROMPT_WARNING_AUDIO_CAPTURE,
+       {APIPermission::kAudioCapture},
+       {}},
+      {IDS_EXTENSION_PROMPT_WARNING_VIDEO_CAPTURE,
+       {APIPermission::kVideoCapture},
+       {}},
+
+      {IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION,
+       {APIPermission::kGeolocation},
+       {}},
+
       // History-related permission messages.
       // History already allows reading favicons, tab access and accessing the
       // list of most frequently visited sites.
@@ -438,8 +449,6 @@
        {APIPermission::kPrintingMetrics},
        {}},
 
-      // END POWERFUL PERMISSIONS
-
       {IDS_EXTENSION_PROMPT_WARNING_DECLARATIVE_WEB_REQUEST,
        {APIPermission::kDeclarativeWebRequest},
        {}},
@@ -542,17 +551,6 @@
        {APIPermission::kFileSystemDirectory},
        {}},
 
-      // Video and audio capture.
-      {IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE,
-       {APIPermission::kAudioCapture, APIPermission::kVideoCapture},
-       {}},
-      {IDS_EXTENSION_PROMPT_WARNING_AUDIO_CAPTURE,
-       {APIPermission::kAudioCapture},
-       {}},
-      {IDS_EXTENSION_PROMPT_WARNING_VIDEO_CAPTURE,
-       {APIPermission::kVideoCapture},
-       {}},
-
       // Network-related permissions.
       {IDS_EXTENSION_PROMPT_WARNING_NETWORKING_PRIVATE,
        {APIPermission::kNetworkingOnc},
@@ -606,9 +604,6 @@
       {IDS_EXTENSION_PROMPT_WARNING_IDENTITY_EMAIL,
        {APIPermission::kIdentityEmail},
        {}},
-      {IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION,
-       {APIPermission::kGeolocation},
-       {}},
 
       {IDS_EXTENSION_PROMPT_WARNING_SYSTEM_STORAGE,
        {APIPermission::kSystemStorage},
diff --git a/chrome/common/web_application_info.h b/chrome/common/web_application_info.h
index 898ad621..f0951bb9 100644
--- a/chrome/common/web_application_info.h
+++ b/chrome/common/web_application_info.h
@@ -124,6 +124,9 @@
   // https://w3c.github.io/manifest/#display-modes
   blink::mojom::DisplayMode display_mode = blink::mojom::DisplayMode::kBrowser;
 
+  // App preference to control display fallback ordering
+  std::vector<blink::mojom::DisplayMode> display_override;
+
   // User preference as to whether the app should be opened in a window.
   // If false, the app will be opened in a tab.
   // If true, the app will be opened in a window, with minimal-ui buttons
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 35dc5d8..5000e82 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1346,6 +1346,7 @@
       "../browser/ui/web_applications/web_app_ui_manager_impl_browsertest.cc",
       "../browser/ui/web_applications/web_app_uninstall_browsertest.cc",
       "../browser/ui/webauthn/authenticator_dialog_browsertest.cc",
+      "../browser/ui/webui/autofill_and_password_manager_internals/autofill_internals_ui_browsertest.cc",
       "../browser/ui/webui/autofill_and_password_manager_internals/password_manager_internals_ui_browsertest.cc",
       "../browser/ui/webui/bookmarks/bookmarks_browsertest.cc",
       "../browser/ui/webui/bookmarks/bookmarks_browsertest.h",
@@ -3273,7 +3274,6 @@
     "../browser/page_load_metrics/observers/local_network_requests_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_unittest.cc",
-    "../browser/page_load_metrics/observers/offline_page_previews_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc",
     "../browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h",
     "../browser/page_load_metrics/observers/previews_page_load_metrics_observer_unittest.cc",
@@ -3374,7 +3374,6 @@
     "../browser/previews/previews_content_util_unittest.cc",
     "../browser/previews/previews_https_notification_infobar_decider_unittest.cc",
     "../browser/previews/previews_lite_page_infobar_delegate_unittest.cc",
-    "../browser/previews/previews_offline_helper_unittest.cc",
     "../browser/previews/previews_service_render_view_unittest.cc",
     "../browser/previews/previews_service_unittest.cc",
     "../browser/previews/previews_ui_tab_helper_unittest.cc",
diff --git a/chrome/test/data/prerender/hung_prerender_page.html b/chrome/test/data/prerender/hung_prerender_page.html
new file mode 100644
index 0000000..776279f
--- /dev/null
+++ b/chrome/test/data/prerender/hung_prerender_page.html
@@ -0,0 +1,28 @@
+<html>
+<!-- 
+This test checks to make sure that a prerendered page is loaded.
+-->
+<head>
+<title>Prerender Page</title>
+
+<script>
+var pageWasPrerendered = false;
+
+// function DidPrerenderPass() {
+//   pageWasPrerendered = true;
+//   return true;
+// }
+
+// Make sure DidPrerenderPass() was called first.  Otherwise, the page was
+// most likely reloaded instead of using the prerendered page.
+// function DidDisplayPass() {
+//   return pageWasPrerendered;
+// }
+</script>
+
+</head>
+<body>
+  Text that is necessary for a FirstContentfulPaint metric to be recorded.
+  <img src="/hung">
+</body>
+</html>
diff --git a/chrome/test/data/prerender/prefetch_loader.html b/chrome/test/data/prerender/prefetch_loader.html
index 327d545c..09cfc69 100644
--- a/chrome/test/data/prerender/prefetch_loader.html
+++ b/chrome/test/data/prerender/prefetch_loader.html
@@ -1,7 +1,15 @@
 <html>
 <head>
   <title>Prefetch Loader</title>
-  <link rel='prerender' href='REPLACE_WITH_PREFETCH_URL'/>
+  <script src="prerender_events_common.js"></script>
 </head>
-<body></body>
+<body>
+  <script>
+    var numLinksToInsert =
+        ExtractGetParameterBadlyAndInsecurely('links_to_insert', 1);
+    for (var i = 0; i < numLinksToInsert; ++i) {
+      AddPrerender('REPLACE_WITH_PREFETCH_URL', i);
+    }
+    </script>
+</body>
 </html>
diff --git a/chrome/test/data/prerender/prerender_excessive_memory.html b/chrome/test/data/prerender/prerender_excessive_memory.html
index 96b13f6..d027eac 100644
--- a/chrome/test/data/prerender/prerender_excessive_memory.html
+++ b/chrome/test/data/prerender/prerender_excessive_memory.html
@@ -7,21 +7,7 @@
   <title>Prerender -- Excessive Memory Use</title>
 </head>
 <body>
-  Makes the renderer use an excessive amount of memory.
-  <script type="text/javascript">
-    var string = "";
-    while (string.length < 1024*1024)
-      string = string + "---------";
-
-    // This allows a sufficiently long string to be created with less copying
-    // and reallocation of data, speeding the test and hopefully eliminating
-    // flake.
-    var array = [];
-    // The maximum for the sake of this test is 30 MB, so allocate just a
-    // little more.
-    for (var i = 0; i < 31; ++i)
-      array[i] = string;
-    string = array.join();
-  </script>
+  <img src="image.png">
+  <img src="/hung">
 </body>
 </html>
diff --git a/chrome/test/data/prerender/prerender_infinite_a.html b/chrome/test/data/prerender/prerender_infinite_a.html
index 448d4e57..c6d0e0d 100644
--- a/chrome/test/data/prerender/prerender_infinite_a.html
+++ b/chrome/test/data/prerender/prerender_infinite_a.html
@@ -16,5 +16,6 @@
   <body>
     <link rel="prerender" href="prerender_infinite_b.html">
     <a href="prerender_infinite_b.html">B</a>
+    <img src="/hung">
   </body>
 </html>
diff --git a/chrome/test/data/prerender/prerender_page.html b/chrome/test/data/prerender/prerender_page.html
index e47ca35..f206d97 100644
--- a/chrome/test/data/prerender/prerender_page.html
+++ b/chrome/test/data/prerender/prerender_page.html
@@ -8,16 +8,16 @@
 <script>
 var pageWasPrerendered = false;
 
-function DidPrerenderPass() {
-  pageWasPrerendered = true;
-  return true;
-}
+// function DidPrerenderPass() {
+//   pageWasPrerendered = true;
+//   return true;
+// }
 
 // Make sure DidPrerenderPass() was called first.  Otherwise, the page was
 // most likely reloaded instead of using the prerendered page.
-function DidDisplayPass() {
-  return pageWasPrerendered;
-}
+// function DidDisplayPass() {
+//   return pageWasPrerendered;
+// }
 </script>
 
 </head>
diff --git a/chrome/utility/importer/firefox_importer.cc b/chrome/utility/importer/firefox_importer.cc
index b5a464ad0..00e4c4e 100644
--- a/chrome/utility/importer/firefox_importer.cc
+++ b/chrome/utility/importer/firefox_importer.cc
@@ -10,7 +10,6 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/json/json_file_value_serializer.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -401,8 +400,6 @@
   }
 
   if (!cancelled()) {
-    UMA_HISTOGRAM_COUNTS_10000("Import.NumberOfImportedPasswords.Firefox",
-                               forms.size());
     for (size_t i = 0; i < forms.size(); ++i) {
       if (!forms[i].username_value.empty() ||
           !forms[i].password_value.empty() || forms[i].blocked_by_user) {
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 5372723..aedabf79 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -37,14 +37,16 @@
   if (is_chromeos_device) {
     configs += [ "//build/config/compiler:use_orderfile_for_hugepage" ]
   }
-  public_deps = [ "//chromeos/constants" ]
+  public_deps = [
+    "//chromeos/constants",
+    "//components/policy/proto",
+  ]
   deps = [
     ":chromeos_export",
     "//base",
     "//base:i18n",
     "//chromeos/dbus",
     "//chromeos/dbus/constants",
-    "//components/policy/proto",
     "//google_apis",
     "//services/network/public/cpp:cpp",
     "//third_party/protobuf:protobuf_lite",
@@ -155,6 +157,7 @@
     "//build/config/linux/dbus",
     "//build/config/linux/nss:system_nss_no_ssl_config",
   ]
+
   deps = [
     ":chromeos_buildflags",
     ":test_support",
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 093b6f08..456a3054 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-13342.0.0
\ No newline at end of file
+13349.0.0
\ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/PRESUBMIT.py b/chromeos/components/camera_app_ui/PRESUBMIT.py
new file mode 100644
index 0000000..5832af18
--- /dev/null
+++ b/chromeos/components/camera_app_ui/PRESUBMIT.py
@@ -0,0 +1,41 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+def CheckChangeOnUpload(input_api, output_api):
+  return _CommonChecks(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  return _CommonChecks(input_api, output_api)
+
+
+def _CommonChecks(input_api, output_api):
+  results = input_api.canned_checks.CheckPatchFormatted(input_api, output_api,
+                                                        check_js=True)
+  affected = input_api.AffectedFiles()
+  if any(f for f in affected if f.LocalPath().endswith('.html')):
+    results += _CheckHtml(input_api, output_api)
+  results += _CheckWebDevStyle(input_api, output_api)
+  return results
+
+
+def _CheckHtml(input_api, output_api):
+  return input_api.canned_checks.CheckLongLines(
+      input_api, output_api, 80, lambda x: x.LocalPath().endswith('.html'))
+
+
+def _CheckWebDevStyle(input_api, output_api):
+  results = []
+
+  try:
+    import sys
+    old_sys_path = sys.path[:]
+    cwd = input_api.PresubmitLocalPath()
+    sys.path += [input_api.os_path.join(cwd, '..', '..', '..', 'tools')]
+    from web_dev_style import presubmit_support
+    results += presubmit_support.CheckStyle(input_api, output_api)
+  finally:
+    sys.path = old_sys_path
+
+  return results
\ No newline at end of file
diff --git a/chromeos/components/camera_app_ui/resources/src/js/background.js b/chromeos/components/camera_app_ui/resources/src/js/background.js
index 984e388a..98494da 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/background.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/background.js
@@ -309,6 +309,7 @@
  */
 class Background {
   /**
+   * @public
    */
   constructor() {
     /**
diff --git a/chromeos/components/camera_app_ui/resources/src/js/metrics.js b/chromeos/components/camera_app_ui/resources/src/js/metrics.js
index 44a548b..444a576 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/metrics.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/metrics.js
@@ -59,7 +59,7 @@
 export function setMetricsEnabled(enabled) {
   assert(ready !== null);
 
-  ready.then(async() => {
+  ready.then(async () => {
     // This value reflects the logging constent option in OS settings.
     const canSendMetrics = await browserProxy.isCrashReportingEnabled();
     window[`ga-disable-${GA_ID}`] = !enabled || !canSendMetrics;
@@ -119,7 +119,7 @@
     window.ga('set', 'checkProtocolTask', null);
   })();
 
-  ready.then(async() => {
+  ready.then(async () => {
     // The metrics is default enabled.
     await setMetricsEnabled(true);
   });
@@ -164,6 +164,9 @@
  * @record
  */
 export class CaptureEventParam {
+  /**
+   * @public
+   */
   constructor() {
     /**
      * @type {!Facing} Camera facing of the capture.
diff --git a/chromeos/components/camera_app_ui/resources/src/js/models/async_writer.js b/chromeos/components/camera_app_ui/resources/src/js/models/async_writer.js
index 9b9f691d..b3bb2b0 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/models/async_writer.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/models/async_writer.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {AsyncJobQueue} from '../async_job_queue.js'
+import {AsyncJobQueue} from '../async_job_queue.js';
 import {assert} from '../chrome_util.js';
 
 /**
diff --git a/chromeos/components/camera_app_ui/resources/src/js/models/mp4_video_processor.js b/chromeos/components/camera_app_ui/resources/src/js/models/mp4_video_processor.js
index 313b0dc9..37e84b9 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/models/mp4_video_processor.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/models/mp4_video_processor.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {AsyncJobQueue} from '../async_job_queue.js'
+import {AsyncJobQueue} from '../async_job_queue.js';
 import {assert, assertNotReached} from '../chrome_util.js';
 import * as Comlink from '../lib/comlink.js';
 import runFFmpeg from '../lib/ffmpeg.js';
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera.js
index fc41406..afa3e9c 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/views/camera.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera.js
@@ -231,13 +231,13 @@
       element: videoShutter,
       state: state.State.TAKING,
       onLabel: 'record_video_stop_button',
-      offLabel: 'record_video_start_button'
+      offLabel: 'record_video_start_button',
     });
     util.bindElementAriaLabelWithState({
       element: pauseShutter,
       state: state.State.RECORDING_PAUSED,
       onLabel: 'record_video_resume_button',
-      offLabel: 'record_video_pause_button'
+      offLabel: 'record_video_pause_button',
     });
 
     // Monitor the states to stop camera when locked/minimized.
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera_intent.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera_intent.js
index 9348e52..156cbebd 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/views/camera_intent.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera_intent.js
@@ -163,7 +163,7 @@
         resolution: result.resolution,
         intentResult: confirmed ? metrics.IntentResultType.CONFIRMED :
                                   metrics.IntentResultType.CANCELED,
-        shutterType: this.shutterType_
+        shutterType: this.shutterType_,
       });
       if (confirmed) {
         await this.intent_.finish();
diff --git a/chromeos/dbus/authpolicy/BUILD.gn b/chromeos/dbus/authpolicy/BUILD.gn
index 9f0c3fe..a9c5de5 100644
--- a/chromeos/dbus/authpolicy/BUILD.gn
+++ b/chromeos/dbus/authpolicy/BUILD.gn
@@ -9,6 +9,8 @@
 component("authpolicy") {
   defines = [ "IS_AUTHPOLICY_IMPL" ]
 
+  public_deps = [ "//components/policy/proto" ]
+
   deps = [
     ":authpolicy_proto",
     "//base",
@@ -21,7 +23,6 @@
     "//chromeos/dbus/session_manager",
     "//chromeos/tpm",
     "//components/policy:cloud_policy_proto_generated_compile",
-    "//components/policy/proto",
   ]
 
   sources = [
diff --git a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css
index 36b5c68b..d1c50491 100644
--- a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css
+++ b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css
@@ -27,7 +27,7 @@
   padding-inline-end: 1em;
 }
 
-#marker-fake-button {
+.fake-button {
   background-color: lightgray;
   border: 1px solid black;
   margin-inline-end: 1em;
@@ -209,3 +209,27 @@
 .country_data td {
   vertical-align: text-top;
 }
+
+.modal-dialog {
+  background-color: rgb(255, 255, 255);
+  border: 1px solid rgb(0, 0, 0);
+  display: block;
+  height: 100px;
+  left: 10%;
+  overflow: auto;
+  position: fixed;
+  right: 10%;
+  top: 10%;
+  width: 80%;
+  z-index: 1;
+}
+
+.modal-dialog-content {
+  padding: 20px;
+}
+
+.modal-dialog-close-button {
+  bottom: 20px;
+  position: absolute;
+  right: 20px;
+}
diff --git a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
index 279c5c7..2eb1f55 100644
--- a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
+++ b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
@@ -14,8 +14,10 @@
 <div>
   <h1 id="h1-title"></h1>
   <div id="log-display-config">
-    <span id="marker-fake-button">Add Marker</span>
+    <span id="marker-fake-button" class="fake-button">Add Marker</span>
     <input type="checkbox" id="enable-autoscroll" checked><label for="enable-autoscroll">Enable autoscroll</label>
+    <span id="checkbox-placeholder"></span>
+    <span id="reset-cache-fake-button" class="fake-button" style="display: none">Reset Cache</span>
   </div>
 </div>
 <div id="logging-note"></div>
diff --git a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
index 49bf6b5a..a9915de 100644
--- a/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
+++ b/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
@@ -2,6 +2,32 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// Renders a simple dialog with |text| as a message and a close button.
+function showModalDialog(text) {
+  const dialog = document.createElement('div');
+  dialog.className = 'modal-dialog';
+
+  const content = document.createElement('div');
+  content.className = 'modal-dialog-content';
+
+  const closeButton = document.createElement('span');
+  closeButton.className = 'modal-dialog-close-button fake-button';
+  closeButton.innerText = 'Close';
+
+  const textContent = document.createElement('p');
+  textContent.className = 'modal-dialog-text';
+  textContent.innerText = text;
+
+  content.appendChild(closeButton);
+  content.appendChild(textContent);
+  dialog.appendChild(content);
+  window.document.body.append(dialog);
+
+  closeButton.addEventListener('click', () => {
+    window.document.body.removeChild(dialog);
+  });
+}
+
 // Autoscrolling keeps the page scrolled down. Intended usage is as follows:
 // before modifying the DOM, check needsScrollDown(), and afterwards invoke
 // scrollDown() if needsScrollDown() was true.
@@ -127,25 +153,30 @@
 }
 
 function setUpAutofillInternals() {
-    document.title = "Autofill Internals";
-    document.getElementById("h1-title").textContent = "Autofill Internals";
-    document.getElementById("logging-note").innerText =
-      "Captured autofill logs are listed below. Logs are cleared and no longer \
-      captured when all autofill-internals pages are closed.";
-    document.getElementById("logging-note-incognito").innerText =
-      "Captured autofill logs are not available in Incognito.";
-    setUpLogDisplayConfig();
+  document.title = 'Autofill Internals';
+  document.getElementById('h1-title').textContent = 'Autofill Internals';
+  document.getElementById('logging-note').innerText =
+      'Captured autofill logs are listed below. Logs are cleared and no longer \
+      captured when all autofill-internals pages are closed.';
+  document.getElementById('logging-note-incognito').innerText =
+      'Captured autofill logs are not available in Incognito.';
+  setUpLogDisplayConfig();
 }
 
 function setUpPasswordManagerInternals() {
-    document.title = "Password Manager Internals";
-    document.getElementById("h1-title").textContent =
-      "Password Manager Internals";
-    document.getElementById("logging-note").innerText =
-      "Captured password manager logs are listed below. Logs are cleared and \
-      no longer captured when all password-manager-internals pages are closed.";
-    document.getElementById("logging-note-incognito").innerText =
-      "Captured password manager logs are not available in Incognito.";
+  document.title = 'Password Manager Internals';
+  document.getElementById('h1-title').textContent =
+      'Password Manager Internals';
+  document.getElementById('logging-note').innerText =
+      'Captured password manager logs are listed below. Logs are cleared and \
+      no longer captured when all password-manager-internals pages are closed.';
+  document.getElementById('logging-note-incognito').innerText =
+      'Captured password manager logs are not available in Incognito.';
+}
+
+function enableResetCacheButton() {
+  document.getElementById('reset-cache-fake-button').style.display =
+      'inline-block';
 }
 
 function notifyAboutIncognito(isIncognito) {
@@ -179,6 +210,7 @@
   const displayConfigDiv = document.getElementById('log-display-config');
   const logDiv = document.getElementById('log-entries');
   const autoScrollInput = document.getElementById('enable-autoscroll');
+  const checkboxPlaceholder = document.getElementById('checkbox-placeholder');
 
   displayConfigDiv.style.display = 'block';
   displayConfigDiv.parentElement.classList.add('sticky-bar');
@@ -214,8 +246,8 @@
     const label = document.createElement('label');
     label.setAttribute('for', `checkbox-${scope}`);
     label.innerText = scope;
-    displayConfigDiv.appendChild(input);
-    displayConfigDiv.appendChild(label);
+    checkboxPlaceholder.appendChild(input);
+    checkboxPlaceholder.appendChild(label);
   }
 
   // Initialize marker field: when pressed, add fake log event.
@@ -241,6 +273,16 @@
   });
 }
 
+function notifyResetDone(message) {
+  showModalDialog(message);
+}
+
 document.addEventListener("DOMContentLoaded", function(event) {
   chrome.send('loaded');
+
+  const resetCacheFakeButton =
+      document.getElementById('reset-cache-fake-button');
+  resetCacheFakeButton.addEventListener('click', () => {
+    chrome.send('resetCache');
+  });
 });
diff --git a/components/autofill/core/browser/autofill_download_manager_unittest.cc b/components/autofill/core/browser/autofill_download_manager_unittest.cc
index 22fd6ac3..ad89862 100644
--- a/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -45,8 +45,6 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
-#include "net/url_request/url_request_status.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/network/public/cpp/data_element.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_shared_url_loader_factory.h"
diff --git a/components/autofill/core/browser/field_types.cc b/components/autofill/core/browser/field_types.cc
index d5f7ede..e45e5f9 100644
--- a/components/autofill/core/browser/field_types.cc
+++ b/components/autofill/core/browser/field_types.cc
@@ -5,6 +5,7 @@
 #include "components/autofill/core/browser/field_types.h"
 
 #include "base/notreached.h"
+#include "base/strings/string_piece.h"
 #include "components/autofill/core/common/autofill_features.h"
 
 namespace autofill {
@@ -132,4 +133,101 @@
   return false;
 }
 
+base::StringPiece FieldTypeToStringPiece(HtmlFieldType type) {
+  switch (type) {
+    case HTML_TYPE_UNSPECIFIED:
+      return "HTML_TYPE_UNSPECIFIED";
+    case HTML_TYPE_NAME:
+      return "HTML_TYPE_NAME";
+    case HTML_TYPE_HONORIFIC_PREFIX:
+      return "HTML_TYPE_HONORIFIC_PREFIX";
+    case HTML_TYPE_GIVEN_NAME:
+      return "HTML_TYPE_GIVEN_NAME";
+    case HTML_TYPE_ADDITIONAL_NAME:
+      return "HTML_TYPE_ADDITIONAL_NAME";
+    case HTML_TYPE_FAMILY_NAME:
+      return "HTML_TYPE_FAMILY_NAME";
+    case HTML_TYPE_ORGANIZATION:
+      return "HTML_TYPE_ORGANIZATION";
+    case HTML_TYPE_STREET_ADDRESS:
+      return "HTML_TYPE_STREET_ADDRESS";
+    case HTML_TYPE_ADDRESS_LINE1:
+      return "HTML_TYPE_ADDRESS_LINE1";
+    case HTML_TYPE_ADDRESS_LINE2:
+      return "HTML_TYPE_ADDRESS_LINE2";
+    case HTML_TYPE_ADDRESS_LINE3:
+      return "HTML_TYPE_ADDRESS_LINE3";
+    case HTML_TYPE_ADDRESS_LEVEL1:
+      return "HTML_TYPE_ADDRESS_LEVEL1";
+    case HTML_TYPE_ADDRESS_LEVEL2:
+      return "HTML_TYPE_ADDRESS_LEVEL2";
+    case HTML_TYPE_ADDRESS_LEVEL3:
+      return "HTML_TYPE_ADDRESS_LEVEL3";
+    case HTML_TYPE_COUNTRY_CODE:
+      return "HTML_TYPE_COUNTRY_CODE";
+    case HTML_TYPE_COUNTRY_NAME:
+      return "HTML_TYPE_COUNTRY_NAME";
+    case HTML_TYPE_POSTAL_CODE:
+      return "HTML_TYPE_POSTAL_CODE";
+    case HTML_TYPE_FULL_ADDRESS:
+      return "HTML_TYPE_FULL_ADDRESS";
+    case HTML_TYPE_CREDIT_CARD_NAME_FULL:
+      return "HTML_TYPE_CREDIT_CARD_NAME_FULL";
+    case HTML_TYPE_CREDIT_CARD_NAME_FIRST:
+      return "HTML_TYPE_CREDIT_CARD_NAME_FIRST";
+    case HTML_TYPE_CREDIT_CARD_NAME_LAST:
+      return "HTML_TYPE_CREDIT_CARD_NAME_LAST";
+    case HTML_TYPE_CREDIT_CARD_NUMBER:
+      return "HTML_TYPE_CREDIT_CARD_NUMBER";
+    case HTML_TYPE_CREDIT_CARD_EXP:
+      return "HTML_TYPE_CREDIT_CARD_EXP";
+    case HTML_TYPE_CREDIT_CARD_EXP_MONTH:
+      return "HTML_TYPE_CREDIT_CARD_EXP_MONTH";
+    case HTML_TYPE_CREDIT_CARD_EXP_YEAR:
+      return "HTML_TYPE_CREDIT_CARD_EXP_YEAR";
+    case HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE:
+      return "HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE";
+    case HTML_TYPE_CREDIT_CARD_TYPE:
+      return "HTML_TYPE_CREDIT_CARD_TYPE";
+    case HTML_TYPE_TEL:
+      return "HTML_TYPE_TEL";
+    case HTML_TYPE_TEL_COUNTRY_CODE:
+      return "HTML_TYPE_TEL_COUNTRY_CODE";
+    case HTML_TYPE_TEL_NATIONAL:
+      return "HTML_TYPE_TEL_NATIONAL";
+    case HTML_TYPE_TEL_AREA_CODE:
+      return "HTML_TYPE_TEL_AREA_CODE";
+    case HTML_TYPE_TEL_LOCAL:
+      return "HTML_TYPE_TEL_LOCAL";
+    case HTML_TYPE_TEL_LOCAL_PREFIX:
+      return "HTML_TYPE_TEL_LOCAL_PREFIX";
+    case HTML_TYPE_TEL_LOCAL_SUFFIX:
+      return "HTML_TYPE_TEL_LOCAL_SUFFIX";
+    case HTML_TYPE_TEL_EXTENSION:
+      return "HTML_TYPE_TEL_EXTENSION";
+    case HTML_TYPE_EMAIL:
+      return "HTML_TYPE_EMAIL";
+    case HTML_TYPE_TRANSACTION_AMOUNT:
+      return "HTML_TYPE_TRANSACTION_AMOUNT";
+    case HTML_TYPE_TRANSACTION_CURRENCY:
+      return "HTML_TYPE_TRANSACTION_CURRENCY";
+    case HTML_TYPE_ADDITIONAL_NAME_INITIAL:
+      return "HTML_TYPE_ADDITIONAL_NAME_INITIAL";
+    case HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
+      return "HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR";
+    case HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
+      return "HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR";
+    case HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR:
+      return "HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR";
+    case HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR:
+      return "HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR";
+    case HTML_TYPE_UPI_VPA:
+      return "HTML_TYPE_UPI_VPA";
+    case HTML_TYPE_UNRECOGNIZED:
+      return "HTML_TYPE_UNRECOGNIZED";
+  }
+  NOTREACHED();
+  return "";
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/field_types.h b/components/autofill/core/browser/field_types.h
index 24e11f2b..7c568b1 100644
--- a/components/autofill/core/browser/field_types.h
+++ b/components/autofill/core/browser/field_types.h
@@ -9,6 +9,7 @@
 #include <set>
 
 #include "base/strings/string16.h"
+#include "base/strings/string_piece_forward.h"
 
 namespace autofill {
 
@@ -323,6 +324,9 @@
 // Returns whether the field can be filled with data.
 bool IsFillableFieldType(ServerFieldType field_type);
 
+// Returns a StringPiece describing |type|. As the StringPiece points to a
+// static string, you don't need to worry about memory deallocation.
+base::StringPiece FieldTypeToStringPiece(HtmlFieldType type);
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_FIELD_TYPES_H_
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 1cd873b2..41e5a75 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -2346,16 +2346,23 @@
                   {base::NumberToString(field->GetFieldSignature().value()),
                    " - ",
                    base::NumberToString(
-                       HashFieldSignature(field->GetFieldSignature()))});
+                       HashFieldSignature(field->GetFieldSignature())),
+                   ", unique renderer id: ",
+                   base::NumberToString(field->unique_renderer_id.value())});
     buffer << "\n  Name: " << field->parseable_name();
 
     auto type = field->Type().ToString();
     auto heuristic_type = AutofillType(field->heuristic_type()).ToString();
     auto server_type = AutofillType(field->server_type()).ToString();
+    auto html_type_description =
+        field->html_type() != HTML_TYPE_UNSPECIFIED
+            ? base::StrCat(
+                  {", html: ", FieldTypeToStringPiece(field->html_type())})
+            : "";
 
     buffer << "\n  Type: "
-           << base::StrCat({type, " (heuristic: ", heuristic_type,
-                            ", server: ", server_type, ")"});
+           << base::StrCat({type, " (heuristic: ", heuristic_type, ", server: ",
+                            server_type, html_type_description, ")"});
     buffer << "\n  Section: " << field->section;
 
     constexpr size_t kMaxLabelSize = 100;
@@ -2398,10 +2405,15 @@
     auto type = field->Type().ToString();
     auto heuristic_type = AutofillType(field->heuristic_type()).ToString();
     auto server_type = AutofillType(field->server_type()).ToString();
+    auto html_type_description =
+        field->html_type() != HTML_TYPE_UNSPECIFIED
+            ? base::StrCat(
+                  {", html: ", FieldTypeToStringPiece(field->html_type())})
+            : "";
 
     buffer << Tr{} << "Type:"
-           << base::StrCat({type, " (heuristic: ", heuristic_type,
-                            ", server: ", server_type, ")"});
+           << base::StrCat({type, " (heuristic: ", heuristic_type, ", server: ",
+                            server_type, html_type_description, ")"});
     buffer << Tr{} << "Section:" << field->section;
 
     constexpr size_t kMaxLabelSize = 100;
diff --git a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationManagerProxy.java b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationManagerProxy.java
index f588b70..a92d87d 100644
--- a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationManagerProxy.java
+++ b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationManagerProxy.java
@@ -21,7 +21,6 @@
  */
 public interface NotificationManagerProxy {
     // Implemented by NotificationManagerCompat and thus available on all API levels.
-    // Note that on < Kitkat, this always returns true.
     boolean areNotificationsEnabled();
 
     void cancel(int id);
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/TintedDrawable.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/TintedDrawable.java
index c8cf641..560fd8ad 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/TintedDrawable.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/TintedDrawable.java
@@ -12,7 +12,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.VectorDrawable;
-import android.os.Build;
 
 import androidx.annotation.DrawableRes;
 import androidx.appcompat.content.res.AppCompatResources;
@@ -95,10 +94,6 @@
     @RemovableInRelease
     private static boolean isVectorDrawable(Context context, @DrawableRes int drawableId) {
         Drawable drawable = AppCompatResources.getDrawable(context, drawableId);
-        if (drawable instanceof VectorDrawableCompat) return true;
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            return drawable instanceof VectorDrawable;
-        }
-        return false;
+        return drawable instanceof VectorDrawableCompat || drawable instanceof VectorDrawable;
     }
 }
diff --git a/components/browsing_data/content/cookie_helper.cc b/components/browsing_data/content/cookie_helper.cc
index 6b5cbdd1..f74483b 100644
--- a/components/browsing_data/content/cookie_helper.cc
+++ b/components/browsing_data/content/cookie_helper.cc
@@ -19,8 +19,6 @@
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_util.h"
 #include "net/cookies/parsed_cookie.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "url/gurl.h"
 
diff --git a/components/captive_portal/core/captive_portal_detector.cc b/components/captive_portal/core/captive_portal_detector.cc
index 54e0b042..d6941f69 100644
--- a/components/captive_portal/core/captive_portal_detector.cc
+++ b/components/captive_portal/core/captive_portal_detector.cc
@@ -13,7 +13,6 @@
 #include "net/base/load_flags.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
-#include "net/url_request/url_request_status.h"
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/network/network_configuration_handler.h"
diff --git a/components/cookie_config/README.md b/components/cookie_config/README.md
new file mode 100644
index 0000000..5a7ae44
--- /dev/null
+++ b/components/cookie_config/README.md
@@ -0,0 +1,2 @@
+Implements a cross-platform net::CookieCryptoDelegate that implements encryption
+and decryption of the cookie store if required on a per-platform basis.
diff --git a/components/crash/android/java/src/org/chromium/components/crash/browser/PackagePaths.java b/components/crash/android/java/src/org/chromium/components/crash/browser/PackagePaths.java
index 40c7ac27..884bcc4 100644
--- a/components/crash/android/java/src/org/chromium/components/crash/browser/PackagePaths.java
+++ b/components/crash/android/java/src/org/chromium/components/crash/browser/PackagePaths.java
@@ -7,7 +7,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Build;
 import android.text.TextUtils;
 
 import org.chromium.base.BuildInfo;
@@ -34,9 +33,6 @@
      */
     @CalledByNative
     public static String[] makePackagePaths(String arch) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
-            return new String[] {"", ""};
-        }
         try {
             PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
             PackageInfo pi = pm.getPackageInfo(BuildInfo.getInstance().packageName,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
index 4f086c18..3ebce18d 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -532,9 +532,6 @@
   service_->UpdatePrefetchProxyHosts(
       GetPrefetchProxyHosts(config.prefetch_proxy_config()));
 
-  service_->SetIgnoreLongTermBlockListRules(
-      config.ignore_long_term_block_list_rules());
-
   request_options_->SetSecureSession(config.session_key());
   remote_config_applied_ = true;
   return true;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
index edd615b..5a5b8e7 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
@@ -298,12 +298,6 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-void DataReductionProxyService::SetIgnoreLongTermBlockListRules(
-    bool ignore_long_term_block_list_rules) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  settings_->SetIgnoreLongTermBlockListRules(ignore_long_term_block_list_rules);
-}
-
 void DataReductionProxyService::AddCustomProxyConfigClient(
     mojo::Remote<network::mojom::CustomProxyConfigClient> config_client) {
   proxy_config_clients_.Add(std::move(config_client));
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
index 669f508..6a6ebc0 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
@@ -124,11 +124,6 @@
     settings_ = settings;
   }
 
-  // When triggering previews, prevent long term block list rules. Virtual for
-  // testing.
-  virtual void SetIgnoreLongTermBlockListRules(
-      bool ignore_long_term_black_list_rules);
-
   // Returns the current network quality estimates.
   net::EffectiveConnectionType GetEffectiveConnectionType() const;
   base::Optional<base::TimeDelta> GetHttpRttEstimate() const;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
index e805bd4..7c87ba0 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -157,10 +157,6 @@
   // some of them should have.
   bool IsDataReductionProxyUnreachable();
 
-  // When triggering previews, prevent long term block list rules.
-  virtual void SetIgnoreLongTermBlockListRules(
-      bool ignore_long_term_block_list_rules) {}
-
   ContentLengthList GetDailyContentLengths(const char* pref_name);
 
   // Configures data reduction proxy. |at_startup| is true when this method is
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index 482c87b..e6427f5 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -236,11 +236,6 @@
 
 TestDataReductionProxyService::~TestDataReductionProxyService() {}
 
-void TestDataReductionProxyService::SetIgnoreLongTermBlockListRules(
-    bool ignore_long_term_block_list_rules) {
-  ignore_blocklist_ = ignore_long_term_block_list_rules;
-}
-
 TestDataStore::TestDataStore() {}
 
 TestDataStore::~TestDataStore() {}
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
index 42e465a..ec0a746 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -200,10 +200,6 @@
       const scoped_refptr<base::SequencedTaskRunner>& db_task_runner);
   ~TestDataReductionProxyService() override;
 
-  // Records |ignore_long_term_block_list_rules| as |ignore_blocklist_|.
-  void SetIgnoreLongTermBlockListRules(
-      bool ignore_long_term_block_list_rules) override;
-
   bool ignore_blocklist() const { return ignore_blocklist_; }
 
  private:
diff --git a/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc b/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
index b15b38a0..4c374a4 100644
--- a/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
+++ b/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
@@ -40,7 +40,6 @@
 #include "content/public/common/web_preferences.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/base/url_util.h"
-#include "net/url_request/url_request.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/components/dom_distiller/core/distiller.cc b/components/dom_distiller/core/distiller.cc
index 29a1a6f..7bdd649c6 100644
--- a/components/dom_distiller/core/distiller.cc
+++ b/components/dom_distiller/core/distiller.cc
@@ -25,7 +25,6 @@
 #include "components/dom_distiller/core/distiller_url_fetcher.h"
 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
 #include "components/dom_distiller/core/proto/distilled_page.pb.h"
-#include "net/url_request/url_request_context_getter.h"
 
 namespace {
 // Maximum number of distilled pages in an article.
diff --git a/components/dom_distiller/core/distiller.h b/components/dom_distiller/core/distiller.h
index d46578ca..0a3a2d26 100644
--- a/components/dom_distiller/core/distiller.h
+++ b/components/dom_distiller/core/distiller.h
@@ -21,7 +21,6 @@
 #include "components/dom_distiller/core/distiller_page.h"
 #include "components/dom_distiller/core/distiller_url_fetcher.h"
 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "url/gurl.h"
 
 namespace dom_distiller {
diff --git a/components/dom_distiller/core/distiller_unittest.cc b/components/dom_distiller/core/distiller_unittest.cc
index 4bbfe2f..ce4a6438 100644
--- a/components/dom_distiller/core/distiller_unittest.cc
+++ b/components/dom_distiller/core/distiller_unittest.cc
@@ -28,7 +28,6 @@
 #include "components/dom_distiller/core/fake_distiller_page.h"
 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
 #include "components/dom_distiller/core/proto/distilled_page.pb.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/dom_distiller/core/viewer.cc b/components/dom_distiller/core/viewer.cc
index 51fd0dc..2a14183 100644
--- a/components/dom_distiller/core/viewer.cc
+++ b/components/dom_distiller/core/viewer.cc
@@ -25,7 +25,6 @@
 #include "components/grit/components_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "net/base/escape.h"
-#include "net/url_request/url_request.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "url/gurl.h"
diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/media/ActivityContentVideoViewEmbedder.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/media/ActivityContentVideoViewEmbedder.java
index 7c2eed9..f434f3c 100644
--- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/media/ActivityContentVideoViewEmbedder.java
+++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/media/ActivityContentVideoViewEmbedder.java
@@ -6,7 +6,6 @@
 
 import android.annotation.SuppressLint;
 import android.app.Activity;
-import android.os.Build;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -57,9 +56,6 @@
         } else {
             mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
         }
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
-            return;
-        }
 
         int systemUiVisibility = decor.getSystemUiVisibility();
         int flags = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
diff --git a/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc b/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc
index e93d123..c55e90d 100644
--- a/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc
+++ b/components/enterprise/browser/controller/chrome_browser_cloud_management_helper.cc
@@ -20,7 +20,6 @@
 #include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h"
 #include "components/policy/core/common/cloud/machine_level_user_cloud_policy_store.h"
 #include "components/prefs/pref_service.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace policy {
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
index daad9db..0722d86 100644
--- a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
@@ -18,7 +18,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
-import android.os.Build;
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.provider.Browser;
@@ -1494,8 +1493,6 @@
      * capable activities. If the intent is pdf type, return the platform pdf viewer if
      * it is available so user don't need to choose it from Intent picker.
      *
-     * Note this function is slow on Android versions less than Lollipop.
-     *
      * @param intent Intent to open.
      * @param allowSelfOpen Whether chrome itself is allowed to open the intent.
      * @return true if the intent can be resolved, or false otherwise.
@@ -1712,7 +1709,6 @@
 
     @VisibleForTesting
     protected String getDefaultSmsPackageNameFromSystem() {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null;
         return Telephony.Sms.getDefaultSmsPackage(ContextUtils.getApplicationContext());
     }
 
diff --git a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
index 6bc9ee2..63b8c61b 100644
--- a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
+++ b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
@@ -33,7 +33,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Batch;
-import org.chromium.base.test.util.DisableIf;
 import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
@@ -53,8 +52,6 @@
  */
 @RunWith(BaseJUnit4ClassRunner.class)
 // clang-format off
-@DisableIf.Build(message = "Flaky on K - see https://crbug.com/851444",
-        sdk_is_less_than = Build.VERSION_CODES.LOLLIPOP)
 @Batch(Batch.UNIT_TESTS)
 public class ExternalNavigationHandlerTest {
     // clang-format on
diff --git a/components/favicon_base/favicon_url_parser.cc b/components/favicon_base/favicon_url_parser.cc
index 48b7d4a..2b557403 100644
--- a/components/favicon_base/favicon_url_parser.cc
+++ b/components/favicon_base/favicon_url_parser.cc
@@ -4,10 +4,10 @@
 
 #include "components/favicon_base/favicon_url_parser.h"
 
+#include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
 #include "components/favicon_base/favicon_types.h"
 #include "net/base/url_util.h"
-#include "net/url_request/url_request.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/gfx/favicon_size.h"
 
diff --git a/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMMessage.java b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMMessage.java
index 217aac7..9865957 100644
--- a/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMMessage.java
+++ b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMMessage.java
@@ -4,8 +4,6 @@
 
 package org.chromium.components.gcm_driver;
 
-import android.annotation.TargetApi;
-import android.os.Build;
 import android.os.Bundle;
 
 import androidx.annotation.IntDef;
@@ -129,7 +127,6 @@
      * been created through {@link #toBundle}.
      */
     @Nullable
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public static GCMMessage createFromBundle(Bundle bundle) {
         return create(bundle, new BundleReader());
     }
@@ -263,7 +260,6 @@
      * for purposes of scheduling a job. Only methods available in BaseBundle may be used here,
      * as it may have to be converted to a PersistableBundle.
      */
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public Bundle toBundle() {
         return serialize(new BundleWriter());
     }
diff --git a/components/gcm_driver/android/junit/src/org/chromium/components/gcm_driver/GCMMessageTest.java b/components/gcm_driver/android/junit/src/org/chromium/components/gcm_driver/GCMMessageTest.java
index 1b1008d..f39d2b5d 100644
--- a/components/gcm_driver/android/junit/src/org/chromium/components/gcm_driver/GCMMessageTest.java
+++ b/components/gcm_driver/android/junit/src/org/chromium/components/gcm_driver/GCMMessageTest.java
@@ -7,7 +7,6 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 
-import android.os.Build;
 import android.os.Bundle;
 
 import org.json.JSONException;
@@ -17,7 +16,6 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.MinAndroidSdkLevel;
 
 /**
  * Unit tests for GCMMessage.
@@ -109,7 +107,6 @@
      * because it depends on PersistableBundle.
      */
     @Test
-    @MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP)
     public void testSerializationToPersistableBundle() {
         Bundle extras = new Bundle();
 
@@ -141,7 +138,6 @@
      * on PersistableBundle.
      */
     @Test
-    @MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP)
     public void testRawDataSerializationBehaviour() {
         Bundle extras = new Bundle();
         extras.putString("subtype", "MyAppId");
diff --git a/components/history/core/browser/browsing_history_service_unittest.cc b/components/history/core/browser/browsing_history_service_unittest.cc
index 6f6900f..c769b822 100644
--- a/components/history/core/browser/browsing_history_service_unittest.cc
+++ b/components/history/core/browser/browsing_history_service_unittest.cc
@@ -23,7 +23,6 @@
 #include "components/sync/driver/fake_sync_service.h"
 #include "components/sync/driver/sync_service_observer.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
diff --git a/components/invalidation/impl/fcm_invalidation_service_unittest.cc b/components/invalidation/impl/fcm_invalidation_service_unittest.cc
index 06c3efd..de020b8 100644
--- a/components/invalidation/impl/fcm_invalidation_service_unittest.cc
+++ b/components/invalidation/impl/fcm_invalidation_service_unittest.cc
@@ -29,7 +29,6 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
diff --git a/components/invalidation/impl/per_user_topic_subscription_manager.h b/components/invalidation/impl/per_user_topic_subscription_manager.h
index 36144e19..734de410 100644
--- a/components/invalidation/impl/per_user_topic_subscription_manager.h
+++ b/components/invalidation/impl/per_user_topic_subscription_manager.h
@@ -20,7 +20,6 @@
 #include "components/invalidation/public/invalidation_util.h"
 #include "components/invalidation/public/invalidator_state.h"
 #include "net/base/backoff_entry.h"
-#include "net/url_request/url_request_context_getter.h"
 
 class PrefRegistrySimple;
 class PrefService;
diff --git a/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc b/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc
index fedfb98..67daaec 100644
--- a/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_subscription_request_unittest.cc
@@ -18,7 +18,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/management_strings.grdp b/components/management_strings.grdp
index ca93ce1..3d1fc30 100644
--- a/components/management_strings.grdp
+++ b/components/management_strings.grdp
@@ -228,7 +228,7 @@
     Text you paste or attach is sent to Google Cloud or third parties for analysis. For example, it might be scanned for sensitive data.
   </message>
   <message name="IDS_MANAGEMENT_ENTERPRISE_REPORTING_VISIBLE_DATA" desc="Description of the visible data for the Connectors reporting feature">
-    When security events are flagged by Chrome Enterprise Connectors, relevant data about the event is sent to your administrator. This can include URLs of pages you visit in Chrome, file names or metadata, and the username that you use to sign in to your device and Chrome.
+    When security events are flagged by Chrome Enterprise Connectors, relevant data about the events is sent to your administrator. This can include URLs of pages you visit in Chrome, file names or metadata, and the username that you use to sign in to your device and Chrome.
   </message>
   <message name="IDS_MANAGEMENT_PAGE_VISITED_VISIBLE_DATA" desc="Description of the visible data for the real time URL check feature.">
     URLs of pages you visit are sent to Google Cloud or third parties for analysis. For example, they might be scanned to detect unsafe websites.
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_ENTERPRISE_REPORTING_VISIBLE_DATA.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_ENTERPRISE_REPORTING_VISIBLE_DATA.png.sha1
index e88b7c0..e5e43a7 100644
--- a/components/management_strings_grdp/IDS_MANAGEMENT_ENTERPRISE_REPORTING_VISIBLE_DATA.png.sha1
+++ b/components/management_strings_grdp/IDS_MANAGEMENT_ENTERPRISE_REPORTING_VISIBLE_DATA.png.sha1
@@ -1 +1 @@
-fe07e19a701b3e8ee95eb5062063ac53cfdbe4f3
\ No newline at end of file
+3ab0a9b283bbaf437ba3a869373c260e0439d341
\ No newline at end of file
diff --git a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadJobService.java b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadJobService.java
index abbcb96..07f4e67 100644
--- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadJobService.java
+++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadJobService.java
@@ -3,13 +3,11 @@
 // found in the LICENSE file.
 package org.chromium.components.minidump_uploader;
 
-import android.annotation.TargetApi;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
 import android.app.job.JobScheduler;
 import android.app.job.JobService;
 import android.content.Context;
-import android.os.Build;
 import android.os.PersistableBundle;
 
 import org.chromium.base.ContextUtils;
@@ -18,7 +16,6 @@
 /**
  * Class that interacts with the Android JobScheduler to upload Minidumps at appropriate times.
  */
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public abstract class MinidumpUploadJobService extends JobService {
     private static final String TAG = "MinidumpJobService";
 
diff --git a/components/module_installer/android/java/src/org/chromium/components/module_installer/util/CrashKeyRecorder.java b/components/module_installer/android/java/src/org/chromium/components/module_installer/util/CrashKeyRecorder.java
index 23c062ee..be7ab57 100644
--- a/components/module_installer/android/java/src/org/chromium/components/module_installer/util/CrashKeyRecorder.java
+++ b/components/module_installer/android/java/src/org/chromium/components/module_installer/util/CrashKeyRecorder.java
@@ -8,7 +8,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Build;
 import android.text.TextUtils;
 
 import com.google.android.play.core.splitinstall.SplitInstallManager;
@@ -34,17 +33,14 @@
         // Get modules that are fully installed as split APKs (excluding base which is always
         // installed). Tree set to have ordered and, thus, deterministic results.
         Set<String> fullyInstalledModules = new TreeSet<>();
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            // Split APKs are only supported on Android L+.
-            try {
-                PackageManager pm = context.getPackageManager();
-                PackageInfo packageInfo = pm.getPackageInfo(BuildInfo.getInstance().packageName, 0);
-                if (packageInfo.splitNames != null) {
-                    fullyInstalledModules.addAll(Arrays.asList(packageInfo.splitNames));
-                }
-            } catch (NameNotFoundException e) {
-                throw new RuntimeException(e);
+        try {
+            PackageManager pm = context.getPackageManager();
+            PackageInfo packageInfo = pm.getPackageInfo(BuildInfo.getInstance().packageName, 0);
+            if (packageInfo.splitNames != null) {
+                fullyInstalledModules.addAll(Arrays.asList(packageInfo.splitNames));
             }
+        } catch (NameNotFoundException e) {
+            throw new RuntimeException(e);
         }
 
         // Create temporary split install manager to retrieve both fully installed and emulated
diff --git a/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc b/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc
index 0c6135c..7b383ba 100644
--- a/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc
+++ b/components/offline_pages/core/prefetch/generate_page_bundle_request_unittest.cc
@@ -9,7 +9,6 @@
 #include "components/offline_pages/core/prefetch/prefetch_types.h"
 #include "components/offline_pages/core/prefetch/proto/offline_pages.pb.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/url_request_status.h"
 #include "services/network/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "url/gurl.h"
diff --git a/components/offline_pages/core/prefetch/get_operation_request_unittest.cc b/components/offline_pages/core/prefetch/get_operation_request_unittest.cc
index 5a680c4..5ee041d1 100644
--- a/components/offline_pages/core/prefetch/get_operation_request_unittest.cc
+++ b/components/offline_pages/core/prefetch/get_operation_request_unittest.cc
@@ -9,7 +9,6 @@
 #include "components/offline_pages/core/prefetch/prefetch_types.h"
 #include "components/offline_pages/core/prefetch/proto/offline_pages.pb.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/url_request_status.h"
 #include "services/network/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "url/gurl.h"
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
index 5a7b7add..d5e148d 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
@@ -21,7 +21,6 @@
 #include "components/offline_pages/core/prefetch/tasks/get_visuals_info_task.h"
 #include "components/offline_pages/task/task_queue.h"
 #include "components/version_info/channel.h"
-#include "net/url_request/url_request_context_getter.h"
 
 class PrefService;
 
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
index a361c7d..55ce75d0 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
@@ -46,7 +46,6 @@
 #include "components/offline_pages/core/stub_offline_page_model.h"
 #include "components/version_info/channel.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc b/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc
index 2fca71c..78130e7c 100644
--- a/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_network_request_factory_impl_unittest.cc
@@ -15,7 +15,6 @@
 #include "components/offline_pages/core/prefetch/prefetch_request_test_base.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/version_info/channel.h"
-#include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/offline_pages/core/prefetch/prefetch_request_fetcher_unittest.cc b/components/offline_pages/core/prefetch/prefetch_request_fetcher_unittest.cc
index 1aa33cf4..32b31788 100644
--- a/components/offline_pages/core/prefetch/prefetch_request_fetcher_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_request_fetcher_unittest.cc
@@ -9,7 +9,6 @@
 #include "components/offline_pages/core/prefetch/prefetch_request_test_base.h"
 #include "components/offline_pages/core/prefetch/prefetch_types.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/url_request_status.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "url/gurl.h"
 
diff --git a/components/offline_pages/core/prefetch/prefetch_request_operation_response_unittest.cc b/components/offline_pages/core/prefetch/prefetch_request_operation_response_unittest.cc
index e0c1240..02f5ca7 100644
--- a/components/offline_pages/core/prefetch/prefetch_request_operation_response_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_request_operation_response_unittest.cc
@@ -11,7 +11,6 @@
 #include "components/offline_pages/core/prefetch/proto/offline_pages.pb.h"
 #include "components/offline_pages/core/prefetch/proto/operation.pb.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/url_request_status.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "url/gurl.h"
 
diff --git a/components/ownership/BUILD.gn b/components/ownership/BUILD.gn
index 2cf3c64..cc9385ea 100644
--- a/components/ownership/BUILD.gn
+++ b/components/ownership/BUILD.gn
@@ -20,6 +20,8 @@
 
     defines = [ "OWNERSHIP_IMPLEMENTATION" ]
 
+    public_deps = [ "//components/policy/proto" ]
+
     deps = [
       "//base",
       "//components/keyed_service/core",
@@ -30,7 +32,7 @@
     ]
 
     if (use_nss_certs) {
-      public_deps = [ "//crypto:platform" ]
+      public_deps += [ "//crypto:platform" ]
     }
   }
 
diff --git a/components/page_info/android/java/res/layout/page_info.xml b/components/page_info/android/java/res/layout/page_info.xml
index c10820608..af3fb20 100644
--- a/components/page_info/android/java/res/layout/page_info.xml
+++ b/components/page_info/android/java/res/layout/page_info.xml
@@ -86,13 +86,6 @@
             android:visibility="gone" />
 
         <TextView
-            android:id="@+id/page_info_stale_preview_timestamp"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textAppearance="@style/TextAppearance.TextSmall.Secondary"
-            android:visibility="gone" />
-
-        <TextView
             android:id="@+id/page_info_preview_load_original"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/components/page_info/android/java/res/layout/page_info_v2.xml b/components/page_info/android/java/res/layout/page_info_v2.xml
index cbb4bc25..57a6f45 100644
--- a/components/page_info/android/java/res/layout/page_info_v2.xml
+++ b/components/page_info/android/java/res/layout/page_info_v2.xml
@@ -48,13 +48,6 @@
             android:visibility="gone" />
 
         <TextView
-            android:id="@+id/page_info_stale_preview_timestamp"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textAppearance="@style/TextAppearance.TextSmall.Secondary"
-            android:visibility="gone" />
-
-        <TextView
             android:id="@+id/page_info_preview_load_original"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java
index 0dc58e2..bb368ed 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java
@@ -9,7 +9,6 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.text.Layout;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -172,7 +171,6 @@
 
         public CharSequence url;
         public CharSequence previewLoadOriginalMessage;
-        public CharSequence previewStaleTimestamp;
         public int urlOriginLength;
     }
 
@@ -208,7 +206,6 @@
     // completely.
     protected ElidedUrlTextView mUrlTitle;
     protected TextView mPreviewMessage;
-    protected TextView mPreviewStaleTimestamp;
     protected TextView mPreviewLoadOriginal;
     protected View mPreviewSeparator;
     protected Button mInstantAppButton;
@@ -265,20 +262,13 @@
 
     protected void initPreview(PageInfoViewParams params) {
         mPreviewMessage = findViewById(R.id.page_info_preview_message);
-        mPreviewStaleTimestamp = findViewById(R.id.page_info_stale_preview_timestamp);
         mPreviewLoadOriginal = findViewById(R.id.page_info_preview_load_original);
         mPreviewSeparator = findViewById(R.id.page_info_preview_separator);
         initializePageInfoViewChild(mPreviewMessage, params.previewUIShown, 0f, null);
         initializePageInfoViewChild(mPreviewLoadOriginal, params.previewUIShown, 0f,
                 params.previewShowOriginalClickCallback);
-        initializePageInfoViewChild(mPreviewStaleTimestamp,
-                params.previewUIShown && !TextUtils.isEmpty(params.previewStaleTimestamp), 0f,
-                null);
         initializePageInfoViewChild(mPreviewSeparator, params.previewSeparatorShown, 0f, null);
         mPreviewLoadOriginal.setText(params.previewLoadOriginalMessage);
-        if (!TextUtils.isEmpty(params.previewStaleTimestamp)) {
-            mPreviewStaleTimestamp.setText(params.previewStaleTimestamp);
-        }
     }
 
     protected void initConnection(PageInfoViewParams params) {
@@ -480,7 +470,6 @@
         animatableViews.add(mPerformanceMessage);
         animatableViews.add(mPreviewSeparator);
         animatableViews.add(mPreviewMessage);
-        animatableViews.add(mPreviewStaleTimestamp);
         animatableViews.add(mPreviewLoadOriginal);
         animatableViews.add(mHttpsImageCompressionMessage);
         animatableViews.add(mInstantAppButton);
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java
index f9b7a08d..1e2ff8a 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java
@@ -83,8 +83,7 @@
      */
     @Override
     protected List<View> collectAnimatableViews() {
-        return Arrays.asList(mUrlTitle, mPreviewMessage, mPreviewStaleTimestamp,
-                mPreviewLoadOriginal, mPreviewSeparator, mInstantAppButton, mRowWrapper,
-                mSiteSettingsButton);
+        return Arrays.asList(mUrlTitle, mPreviewMessage, mPreviewLoadOriginal, mPreviewSeparator,
+                mInstantAppButton, mRowWrapper, mSiteSettingsButton);
     }
 }
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index 3b2dffe..96b9c4b 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -539,6 +539,7 @@
     "credential_manager_impl_unittest.cc",
     "credential_manager_logger_unittest.cc",
     "credential_manager_password_form_manager_unittest.cc",
+    "credential_manager_pending_request_task_unittest.cc",
     "credentials_cleaner_runner_unittest.cc",
     "credentials_cleaner_unittest.cc",
     "export/csv_writer_unittest.cc",
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc b/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
index dea78886..7e2b3a2 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_backend.cc
@@ -20,7 +20,6 @@
 #include "components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher.h"
 #include "components/password_manager/core/browser/android_affiliation/facet_manager.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace password_manager {
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
index c3a264a5..dd42c28 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
@@ -24,7 +24,6 @@
 #include "components/password_manager/core/browser/android_affiliation/facet_manager.h"
 #include "components/password_manager/core/browser/android_affiliation/fake_affiliation_api.h"
 #include "components/password_manager/core/browser/android_affiliation/mock_affiliation_consumer.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_network_connection_tracker.h"
diff --git a/components/password_manager/core/browser/credential_manager_impl.cc b/components/password_manager/core/browser/credential_manager_impl.cc
index b410898d..874b7f9 100644
--- a/components/password_manager/core/browser/credential_manager_impl.cc
+++ b/components/password_manager/core/browser/credential_manager_impl.cc
@@ -147,14 +147,20 @@
         metrics_util::CredentialManagerGetResult::kNoneZeroClickOff, mediation);
     return;
   }
-
+  StoresToQuery stores_to_query = GetAccountPasswordStore()
+                                      ? StoresToQuery::kProfileAndAccountStores
+                                      : StoresToQuery::kProfileStore;
   pending_request_ = std::make_unique<CredentialManagerPendingRequestTask>(
       this, base::BindOnce(&RunGetCallback, std::move(callback)), mediation,
-      include_passwords, federations);
+      include_passwords, federations, stores_to_query);
   // This will result in a callback to
   // PendingRequestTask::OnGetPasswordStoreResults().
   GetProfilePasswordStore()->GetLogins(GetSynthesizedFormForOrigin(),
                                        pending_request_.get());
+  if (GetAccountPasswordStore()) {
+    GetAccountPasswordStore()->GetLogins(GetSynthesizedFormForOrigin(),
+                                         pending_request_.get());
+  }
 }
 
 bool CredentialManagerImpl::IsZeroClickAllowed() const {
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index 3f90e5b..bc7edea 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -87,13 +87,23 @@
     SendCredentialCallback callback,
     CredentialMediationRequirement mediation,
     bool include_passwords,
-    const std::vector<GURL>& request_federations)
+    const std::vector<GURL>& request_federations,
+    StoresToQuery stores_to_query)
     : delegate_(delegate),
       send_callback_(std::move(callback)),
       mediation_(mediation),
       origin_(delegate_->GetOrigin()),
       include_passwords_(include_passwords) {
   CHECK(!net::IsCertStatusError(delegate_->client()->GetMainFrameCertStatus()));
+  switch (stores_to_query) {
+    case StoresToQuery::kProfileStore:
+      expected_stores_to_respond_ = 1;
+      break;
+    case StoresToQuery::kProfileAndAccountStores:
+      expected_stores_to_respond_ = 2;
+      break;
+  }
+
   for (const GURL& federation : request_federations)
     federations_.insert(
         url::Origin::Create(federation.GetOrigin()).Serialize());
@@ -111,12 +121,24 @@
         origin_, delegate_->client(), this);
     return;
   }
-  ProcessForms(std::move(results));
+  AggregatePasswordStoreResults(std::move(results));
 }
 
 void CredentialManagerPendingRequestTask::ProcessMigratedForms(
     std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
-  ProcessForms(std::move(forms));
+  AggregatePasswordStoreResults(std::move(forms));
+}
+
+void CredentialManagerPendingRequestTask::AggregatePasswordStoreResults(
+    std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+  // Store the results.
+  for (auto& form : results)
+    partial_results_.push_back(std::move(form));
+
+  // If we're still awaiting more results, nothing else to do.
+  if (--expected_stores_to_respond_ > 0)
+    return;
+  ProcessForms(std::move(partial_results_));
 }
 
 void CredentialManagerPendingRequestTask::ProcessForms(
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.h b/components/password_manager/core/browser/credential_manager_pending_request_task.h
index bb1d05c..768e8e6 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.h
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.h
@@ -31,6 +31,7 @@
 using SendCredentialCallback =
     base::OnceCallback<void(const CredentialInfo& credential)>;
 
+enum class StoresToQuery { kProfileStore, kProfileAndAccountStores };
 // Sends credentials retrieved from the PasswordStore to CredentialManager API
 // clients and retrieves embedder-dependent information.
 class CredentialManagerPendingRequestTaskDelegate {
@@ -65,7 +66,8 @@
       SendCredentialCallback callback,
       CredentialMediationRequirement mediation,
       bool include_passwords,
-      const std::vector<GURL>& request_federations);
+      const std::vector<GURL>& request_federations,
+      StoresToQuery stores_to_query);
   ~CredentialManagerPendingRequestTask() override;
 
   const url::Origin& origin() const { return origin_; }
@@ -79,6 +81,9 @@
   void ProcessMigratedForms(
       std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override;
 
+  void AggregatePasswordStoreResults(
+      std::vector<std::unique_ptr<autofill::PasswordForm>> results);
+
   void ProcessForms(
       std::vector<std::unique_ptr<autofill::PasswordForm>> results);
 
@@ -88,6 +93,11 @@
   const url::Origin origin_;
   const bool include_passwords_;
   std::set<std::string> federations_;
+  int expected_stores_to_respond_;
+  // In case of querying both the profile and account stores, it contains the
+  // partial results received from one store until the second store responds and
+  // then all results are processed.
+  std::vector<std::unique_ptr<autofill::PasswordForm>> partial_results_;
 
   std::unique_ptr<HttpPasswordStoreMigrator> http_migrator_;
 
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc b/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc
new file mode 100644
index 0000000..0faeadf9
--- /dev/null
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/credential_manager_pending_request_task.h"
+
+#include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "components/password_manager/core/common/credential_manager_types.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+namespace {
+class CredentialManagerPendingRequestTaskDelegateMock
+    : public CredentialManagerPendingRequestTaskDelegate {
+ public:
+  CredentialManagerPendingRequestTaskDelegateMock() = default;
+  ~CredentialManagerPendingRequestTaskDelegateMock() = default;
+
+  MOCK_METHOD(bool, IsZeroClickAllowed, (), (const, override));
+  MOCK_METHOD(url::Origin, GetOrigin, (), (const, override));
+  MOCK_METHOD(PasswordManagerClient*, client, (), (const, override));
+  MOCK_METHOD(void,
+              SendCredential,
+              (SendCredentialCallback send_callback,
+               const CredentialInfo& credential),
+              (override));
+  MOCK_METHOD(void,
+              SendPasswordForm,
+              (SendCredentialCallback send_callback,
+               CredentialMediationRequirement mediation,
+               const autofill::PasswordForm* form),
+              (override));
+};
+}  // namespace
+class CredentialManagerPendingRequestTaskTest : public ::testing::Test {
+ public:
+  CredentialManagerPendingRequestTaskTest() {
+    ON_CALL(delegate_mock_, client).WillByDefault(testing::Return(&client_));
+  }
+  ~CredentialManagerPendingRequestTaskTest() override = default;
+
+ protected:
+  testing::NiceMock<CredentialManagerPendingRequestTaskDelegateMock>
+      delegate_mock_;
+
+ private:
+  StubPasswordManagerClient client_;
+};
+
+TEST_F(CredentialManagerPendingRequestTaskTest, QueryProfileStore) {
+  CredentialManagerPendingRequestTask task(
+      &delegate_mock_, /*callback=*/base::DoNothing(),
+      CredentialMediationRequirement::kSilent, /*include_passwords=*/false,
+      /*request_federations=*/{}, StoresToQuery::kProfileStore);
+
+  // We are expecting results from only one store, delegate should be called
+  // upon getting a response from the store.
+  EXPECT_CALL(delegate_mock_, SendCredential);
+  task.OnGetPasswordStoreResults({});
+}
+
+TEST_F(CredentialManagerPendingRequestTaskTest, QueryProfileAndAccountStores) {
+  CredentialManagerPendingRequestTask task(
+      &delegate_mock_, /*callback=*/base::DoNothing(),
+      CredentialMediationRequirement::kSilent, /*include_passwords=*/false,
+      /*request_federations=*/{}, StoresToQuery::kProfileAndAccountStores);
+
+  // We are expecting results from 2 stores, the delegate shouldn't be called
+  // until both stores respond.
+  EXPECT_CALL(delegate_mock_, SendCredential).Times(0);
+  task.OnGetPasswordStoreResults({});
+
+  testing::Mock::VerifyAndClearExpectations(&delegate_mock_);
+
+  EXPECT_CALL(delegate_mock_, SendCredential);
+  task.OnGetPasswordStoreResults({});
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection_delegate.cc b/components/password_manager/core/browser/leak_detection_delegate.cc
index ef1e159..96a622c 100644
--- a/components/password_manager/core/browser/leak_detection_delegate.cc
+++ b/components/password_manager/core/browser/leak_detection_delegate.cc
@@ -98,7 +98,8 @@
     IsSaved is_saved,
     IsReused is_reused,
     GURL url,
-    base::string16 username) {
+    base::string16 username,
+    CompromisedSitesCount saved_sites) {
   bool force_dialog_for_testing = base::GetFieldTrialParamByFeatureAsBool(
       password_manager::features::kPasswordChange,
       password_manager::features::
@@ -111,7 +112,8 @@
         CreateLeakType(is_saved, IsReused(false),
                        IsSyncing(client_->GetPasswordSyncState() ==
                                  SYNCING_NORMAL_ENCRYPTION));
-    client_->NotifyUserCredentialsWereLeaked(leak_type, url, username);
+    client_->NotifyUserCredentialsWereLeaked(leak_type, saved_sites, url,
+                                             username);
     return;
   }
 
@@ -128,7 +130,8 @@
                             IsPasswordUsedOnOtherSites(leak_type));
   base::UmaHistogramBoolean("PasswordManager.LeakDetection.IsSyncing",
                             IsSyncingPasswordsNormally(leak_type));
-  client_->NotifyUserCredentialsWereLeaked(leak_type, url, username);
+  client_->NotifyUserCredentialsWereLeaked(leak_type, saved_sites, url,
+                                           username);
 }
 
 void LeakDetectionDelegate::OnError(LeakDetectionError error) {
diff --git a/components/password_manager/core/browser/leak_detection_delegate.h b/components/password_manager/core/browser/leak_detection_delegate.h
index d74bce3..c024fee 100644
--- a/components/password_manager/core/browser/leak_detection_delegate.h
+++ b/components/password_manager/core/browser/leak_detection_delegate.h
@@ -59,7 +59,8 @@
   void OnShowLeakDetectionNotification(IsSaved is_saved,
                                        IsReused is_reused,
                                        GURL url,
-                                       base::string16 username);
+                                       base::string16 username,
+                                       CompromisedSitesCount saved_sites);
 
   void OnError(LeakDetectionError error) override;
 
diff --git a/components/password_manager/core/browser/leak_detection_delegate_helper.cc b/components/password_manager/core/browser/leak_detection_delegate_helper.cc
index e9e7dc1..e5b412e 100644
--- a/components/password_manager/core/browser/leak_detection_delegate_helper.cc
+++ b/components/password_manager/core/browser/leak_detection_delegate_helper.cc
@@ -4,6 +4,7 @@
 
 #include "components/password_manager/core/browser/leak_detection_delegate_helper.h"
 
+#include "base/containers/flat_set.h"
 #include "base/feature_list.h"
 #include "components/password_manager/core/browser/leak_detection/encryption_utils.h"
 #include "components/password_manager/core/browser/password_store.h"
@@ -32,11 +33,13 @@
 
 void LeakDetectionDelegateHelper::OnGetPasswordStoreResults(
     std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+  base::flat_set<std::string> distinct_origins;
   if (base::FeatureList::IsEnabled(features::kPasswordCheck)) {
     base::string16 canonicalized_username = CanonicalizeUsername(username_);
     for (const auto& form : results) {
       if (CanonicalizeUsername(form->username_value) ==
           canonicalized_username) {
+        distinct_origins.insert(form->signon_realm);
         store_->AddCompromisedCredentials(
             {form->signon_realm, form->username_value, base::Time::Now(),
              CompromiseType::kLeaked});
@@ -49,9 +52,12 @@
         return form->url == url_ && form->username_value == username_;
       }));
 
+  // Number of compromised origins that the user saved.
+  CompromisedSitesCount saved_sites(distinct_origins.size());
+
   IsReused is_reused(results.size() > (is_saved ? 1 : 0));
   std::move(callback_).Run(is_saved, is_reused, std::move(url_),
-                           std::move(username_));
+                           std::move(username_), saved_sites);
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection_delegate_helper.h b/components/password_manager/core/browser/leak_detection_delegate_helper.h
index c8ddc35..e766e6d0 100644
--- a/components/password_manager/core/browser/leak_detection_delegate_helper.h
+++ b/components/password_manager/core/browser/leak_detection_delegate_helper.h
@@ -23,8 +23,8 @@
 class LeakDetectionDelegateHelper : public PasswordStoreConsumer {
  public:
   // Type alias for |callback_|.
-  using LeakTypeReply =
-      base::OnceCallback<void(IsSaved, IsReused, GURL, base::string16)>;
+  using LeakTypeReply = base::OnceCallback<
+      void(IsSaved, IsReused, GURL, base::string16, CompromisedSitesCount)>;
 
   LeakDetectionDelegateHelper(scoped_refptr<PasswordStore> store,
                               LeakTypeReply callback);
diff --git a/components/password_manager/core/browser/leak_detection_delegate_helper_unittest.cc b/components/password_manager/core/browser/leak_detection_delegate_helper_unittest.cc
index bdef280..6d53c66f 100644
--- a/components/password_manager/core/browser/leak_detection_delegate_helper_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection_delegate_helper_unittest.cc
@@ -60,6 +60,8 @@
  protected:
   void SetUp() override {
     store_ = new testing::StrictMock<MockPasswordStore>;
+    feature_list_.InitAndEnableFeature(
+        password_manager::features::kPasswordCheck);
     CHECK(store_->Init(nullptr));
 
     delegate_helper_ =
@@ -91,10 +93,12 @@
   }
 
   // Set the expectation for the |CredentialLeakType| in the callback_.
-  void SetOnShowLeakDetectionNotificationExpectation(IsSaved is_saved,
-                                                     IsReused is_reused) {
+  void SetOnShowLeakDetectionNotificationExpectation(
+      IsSaved is_saved,
+      IsReused is_reused,
+      CompromisedSitesCount other_sites) {
     EXPECT_CALL(callback_, Run(is_saved, is_reused, GURL(kLeakedOrigin),
-                               ASCIIToUTF16(kLeakedUsername)))
+                               ASCIIToUTF16(kLeakedUsername), other_sites))
         .Times(1);
   }
 
@@ -103,6 +107,7 @@
   MockCallback<LeakDetectionDelegateHelper::LeakTypeReply> callback_;
   scoped_refptr<MockPasswordStore> store_;
   std::unique_ptr<LeakDetectionDelegateHelper> delegate_helper_;
+  base::test::ScopedFeatureList feature_list_;
 };
 
 // Credentials are neither saved nor is the password reused.
@@ -110,8 +115,8 @@
   std::vector<PasswordForm> password_forms;
 
   SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
-  SetOnShowLeakDetectionNotificationExpectation(IsSaved(false),
-                                                IsReused(false));
+  SetOnShowLeakDetectionNotificationExpectation(IsSaved(false), IsReused(false),
+                                                CompromisedSitesCount(0));
   InitiateGetCredentialLeakType();
 }
 
@@ -121,7 +126,8 @@
       CreateForm(kLeakedOrigin, kLeakedUsername)};
 
   SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
-  SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(false));
+  SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(false),
+                                                CompromisedSitesCount(1));
   EXPECT_CALL(*store_, AddCompromisedCredentialsImpl)
       .Times(base::FeatureList::IsEnabled(features::kPasswordCheck));
   InitiateGetCredentialLeakType();
@@ -135,7 +141,8 @@
       CreateForm(kOtherOrigin, kLeakedUsername)};
 
   SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
-  SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(true));
+  SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(true),
+                                                CompromisedSitesCount(2));
   EXPECT_CALL(*store_, AddCompromisedCredentialsImpl)
       .Times(2 * base::FeatureList::IsEnabled(features::kPasswordCheck));
   InitiateGetCredentialLeakType();
@@ -150,7 +157,8 @@
       CreateForm(kLeakedOrigin, kOtherUsername)};
 
   SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
-  SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(true));
+  SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(true),
+                                                CompromisedSitesCount(1));
   EXPECT_CALL(*store_, AddCompromisedCredentialsImpl)
       .Times(base::FeatureList::IsEnabled(features::kPasswordCheck));
   InitiateGetCredentialLeakType();
@@ -162,7 +170,8 @@
       CreateForm(kLeakedOrigin, kOtherUsername)};
 
   SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
-  SetOnShowLeakDetectionNotificationExpectation(IsSaved(false), IsReused(true));
+  SetOnShowLeakDetectionNotificationExpectation(IsSaved(false), IsReused(true),
+                                                CompromisedSitesCount(0));
   InitiateGetCredentialLeakType();
 }
 
@@ -172,7 +181,8 @@
       CreateForm(kOtherOrigin, kLeakedUsername)};
 
   SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
-  SetOnShowLeakDetectionNotificationExpectation(IsSaved(false), IsReused(true));
+  SetOnShowLeakDetectionNotificationExpectation(IsSaved(false), IsReused(true),
+                                                CompromisedSitesCount(1));
   EXPECT_CALL(*store_, AddCompromisedCredentialsImpl)
       .Times(base::FeatureList::IsEnabled(features::kPasswordCheck));
   InitiateGetCredentialLeakType();
@@ -185,7 +195,8 @@
       CreateForm(kOtherOrigin, kOtherUsername)};
 
   SetGetLoginByPasswordConsumerInvocation(std::move(password_forms));
-  SetOnShowLeakDetectionNotificationExpectation(IsSaved(false), IsReused(true));
+  SetOnShowLeakDetectionNotificationExpectation(IsSaved(false), IsReused(true),
+                                                CompromisedSitesCount(0));
   InitiateGetCredentialLeakType();
 }
 
@@ -198,7 +209,8 @@
       {CreateForm(kLeakedOrigin, kLeakedUsername, kLeakedPassword),
        CreateForm(kOtherOrigin, kLeakedUsername, kLeakedPassword),
        CreateForm(kLeakedOrigin, kOtherUsername, kLeakedPassword)});
-  SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(true));
+  SetOnShowLeakDetectionNotificationExpectation(IsSaved(true), IsReused(true),
+                                                CompromisedSitesCount(2));
   EXPECT_CALL(*store_, AddCompromisedCredentialsImpl(CompromisedCredentials{
                            GetSignonRealm(GURL(kLeakedOrigin)),
                            ASCIIToUTF16(kLeakedUsername), base::Time::Now(),
@@ -217,7 +229,8 @@
 
   SetGetLoginByPasswordConsumerInvocation({CreateForm(
       kOtherOrigin, kLeakedUsernameNonCanonicalized, kLeakedPassword)});
-  SetOnShowLeakDetectionNotificationExpectation(IsSaved(false), IsReused(true));
+  SetOnShowLeakDetectionNotificationExpectation(IsSaved(false), IsReused(true),
+                                                CompromisedSitesCount(1));
 
   EXPECT_CALL(*store_, AddCompromisedCredentialsImpl(CompromisedCredentials{
                            GetSignonRealm(GURL(kOtherOrigin)),
diff --git a/components/password_manager/core/browser/leak_detection_delegate_unittest.cc b/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
index 40c5066..6d0bae1e 100644
--- a/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
@@ -13,6 +13,7 @@
 #include "components/password_manager/core/browser/leak_detection/leak_detection_check.h"
 #include "components/password_manager/core/browser/leak_detection/mock_leak_detection_check_factory.h"
 #include "components/password_manager/core/browser/leak_detection_delegate.h"
+#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
 #include "components/password_manager/core/browser/mock_password_store.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
@@ -54,8 +55,9 @@
 
   MOCK_CONST_METHOD0(IsIncognito, bool());
   MOCK_CONST_METHOD0(GetPrefs, PrefService*());
-  MOCK_METHOD3(NotifyUserCredentialsWereLeaked,
+  MOCK_METHOD4(NotifyUserCredentialsWereLeaked,
                void(password_manager::CredentialLeakType,
+                    password_manager::CompromisedSitesCount,
                     const GURL&,
                     const base::string16& username));
   MOCK_CONST_METHOD0(GetProfilePasswordStore, PasswordStore*());
@@ -290,7 +292,7 @@
               NotifyUserCredentialsWereLeaked(
                   password_manager::CreateLeakType(
                       IsSaved(false), IsReused(false), IsSyncing(false)),
-                  form.url, form.username_value));
+                  CompromisedSitesCount(0), form.url, form.username_value));
 
   delegate_interface->OnLeakDetectionDone(
       /*is_leaked=*/false, form.url, form.username_value, form.password_value);
@@ -314,7 +316,7 @@
               NotifyUserCredentialsWereLeaked(
                   password_manager::CreateLeakType(
                       IsSaved(false), IsReused(false), IsSyncing(false)),
-                  form.url, form.username_value));
+                  CompromisedSitesCount(0), form.url, form.username_value));
   delegate_interface->OnLeakDetectionDone(
       /*is_leaked=*/true, form.url, form.username_value, form.password_value);
   WaitForPasswordStore();
@@ -339,8 +341,9 @@
           Return(ByMove(std::make_unique<NiceMock<MockLeakDetectionCheck>>())));
   delegate().StartLeakCheck(form);
 
-  EXPECT_CALL(client(), NotifyUserCredentialsWereLeaked(_, form.url,
-                                                        form.username_value));
+  EXPECT_CALL(client(),
+              NotifyUserCredentialsWereLeaked(_, CompromisedSitesCount(1),
+                                              form.url, form.username_value));
   delegate_interface->OnLeakDetectionDone(
       /*is_leaked=*/true, form.url, form.username_value, form.password_value);
 
diff --git a/components/password_manager/core/browser/leak_detection_dialog_utils.cc b/components/password_manager/core/browser/leak_detection_dialog_utils.cc
index f3b9ac7..1c4358b7 100644
--- a/components/password_manager/core/browser/leak_detection_dialog_utils.cc
+++ b/components/password_manager/core/browser/leak_detection_dialog_utils.cc
@@ -5,6 +5,7 @@
 #include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
 
 #include "base/feature_list.h"
+#include "base/i18n/message_formatter.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -88,6 +89,21 @@
   }
 }
 
+base::string16 GetDescriptionWithCount(CredentialLeakType leak_type,
+                                       const GURL& origin,
+                                       CompromisedSitesCount saved_sites) {
+  IsSaved is_saved(IsPasswordSaved(leak_type));
+  if (ShouldCheckPasswords(leak_type) || is_saved) {
+    DCHECK_GE(saved_sites.value(), 1);
+    // saved_sites must be reduced by 1 if the saved sites include the origin as
+    // the origin is mentioned explicitly in the message.
+    return base::i18n::MessageFormatter::FormatWithNumberedArgs(
+        l10n_util::GetStringUTF16(IDS_CREDENTIAL_LEAK_SAVED_PASSWORDS_MESSAGE),
+        GetFormattedUrl(origin), saved_sites.value() - (is_saved ? 1 : 0));
+  }
+  return GetDescription(leak_type, origin);
+}
+
 base::string16 GetTitle(CredentialLeakType leak_type) {
   return l10n_util::GetStringUTF16(ShouldCheckPasswords(leak_type)
                                        ? IDS_CREDENTIAL_LEAK_TITLE_CHECK
diff --git a/components/password_manager/core/browser/leak_detection_dialog_utils.h b/components/password_manager/core/browser/leak_detection_dialog_utils.h
index bb90727..fc271ab 100644
--- a/components/password_manager/core/browser/leak_detection_dialog_utils.h
+++ b/components/password_manager/core/browser/leak_detection_dialog_utils.h
@@ -36,10 +36,13 @@
 // Contains combination of CredentialLeakFlags values.
 using CredentialLeakType = std::underlying_type_t<CredentialLeakFlags>;
 
+// Contains a number of compromised sites.
+using CompromisedSitesCount =
+    util::StrongAlias<class CompromisedSitesCountTag, int>;
+
 using IsSaved = util::StrongAlias<class IsSavedTag, bool>;
 using IsReused = util::StrongAlias<class IsReusedTag, bool>;
 using IsSyncing = util::StrongAlias<class IsSyncingTag, bool>;
-
 // Creates CredentialLeakType from strong booleans.
 CredentialLeakType CreateLeakType(IsSaved is_saved,
                                   IsReused is_reused,
@@ -65,6 +68,12 @@
 base::string16 GetDescription(password_manager::CredentialLeakType leak_type,
                               const GURL& origin);
 
+// Returns the leak dialog message based on leak type and count of leaked sites.
+base::string16 GetDescriptionWithCount(
+    password_manager::CredentialLeakType leak_type,
+    const GURL& origin,
+    CompromisedSitesCount saved_sites);
+
 // Returns the leak dialog title based on leak type.
 base::string16 GetTitle(password_manager::CredentialLeakType leak_type);
 
diff --git a/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc b/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
index 861ec2ae..bd3754b 100644
--- a/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
@@ -4,9 +4,11 @@
 
 #include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
 
+#include "base/i18n/message_formatter.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "components/password_manager/core/browser/compromised_credentials_table.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/elide_url.h"
@@ -15,6 +17,7 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
+using password_manager::CompromisedSitesCount;
 using password_manager::CreateLeakType;
 using password_manager::CredentialLeakFlags;
 using password_manager::CredentialLeakType;
@@ -195,6 +198,76 @@
             GetTitle(GetParam().leak_type));
 }
 
+TEST_F(BulkCheckCredentialLeakDialogUtilsTest,
+       GetChangeDescriptionWitCountForSingleLeak) {
+  const CredentialLeakType leak_type =
+      CreateLeakType(IsSaved(true), IsReused(false), IsSyncing(true));
+  const GURL origin("https://example.com");
+  base::string16 expected_message =
+      base::i18n::MessageFormatter::FormatWithNumberedArgs(
+          l10n_util::GetStringUTF16(
+              IDS_CREDENTIAL_LEAK_SAVED_PASSWORDS_MESSAGE),
+          url_formatter::FormatOriginForSecurityDisplay(
+              url::Origin::Create(origin),
+              url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS),
+          0);
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_CREDENTIAL_LEAK_TITLE_CHANGE),
+            GetTitle(leak_type));
+  EXPECT_FALSE(ShouldCheckPasswords(leak_type));
+  EXPECT_FALSE(ShouldShowCancelButton(leak_type));
+  EXPECT_EQ(expected_message, GetDescriptionWithCount(
+                                  leak_type, origin, CompromisedSitesCount(1)));
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_OK), GetAcceptButtonLabel(leak_type));
+}
+
+TEST_F(BulkCheckCredentialLeakDialogUtilsTest,
+       GetCheckDescriptionWitCountForMultipleLeaks) {
+  const CredentialLeakType leak_type =
+      CreateLeakType(IsSaved(true), IsReused(true), IsSyncing(true));
+  const GURL origin("https://example.com");
+  base::string16 expected_message =
+      base::i18n::MessageFormatter::FormatWithNumberedArgs(
+          l10n_util::GetStringUTF16(
+              IDS_CREDENTIAL_LEAK_SAVED_PASSWORDS_MESSAGE),
+          url_formatter::FormatOriginForSecurityDisplay(
+              url::Origin::Create(origin),
+              url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS),
+          2);
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_CREDENTIAL_LEAK_TITLE_CHECK),
+            GetTitle(leak_type));
+  EXPECT_TRUE(ShouldCheckPasswords(leak_type));
+  EXPECT_TRUE(ShouldShowCancelButton(leak_type));
+  EXPECT_EQ(expected_message, GetDescriptionWithCount(
+                                  leak_type, origin, CompromisedSitesCount(3)));
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_LEAK_CHECK_CREDENTIALS),
+            GetAcceptButtonLabel(leak_type));
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_CLOSE), GetCancelButtonLabel());
+}
+
+TEST_F(BulkCheckCredentialLeakDialogUtilsTest,
+       GetCheckDescriptionWitCountForUnsavedOriginWithMultipleLeaks) {
+  const CredentialLeakType leak_type =
+      CreateLeakType(IsSaved(false), IsReused(true), IsSyncing(true));
+  const GURL origin("https://example.com");
+  base::string16 expected_message =
+      base::i18n::MessageFormatter::FormatWithNumberedArgs(
+          l10n_util::GetStringUTF16(
+              IDS_CREDENTIAL_LEAK_SAVED_PASSWORDS_MESSAGE),
+          url_formatter::FormatOriginForSecurityDisplay(
+              url::Origin::Create(origin),
+              url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS),
+          3);
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_CREDENTIAL_LEAK_TITLE_CHECK),
+            GetTitle(leak_type));
+  EXPECT_TRUE(ShouldCheckPasswords(leak_type));
+  EXPECT_TRUE(ShouldShowCancelButton(leak_type));
+  EXPECT_EQ(expected_message, GetDescriptionWithCount(
+                                  leak_type, origin, CompromisedSitesCount(3)));
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_LEAK_CHECK_CREDENTIALS),
+            GetAcceptButtonLabel(leak_type));
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_CLOSE), GetCancelButtonLabel());
+}
+
 INSTANTIATE_TEST_SUITE_P(InstantiationName,
                          BulkCheckCredentialLeakDialogUtilsTest,
                          testing::ValuesIn(kBulkCheckTestCases));
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index d3797416..372d595 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -999,16 +999,6 @@
 
 void LoginDatabase::ReportBubbleSuppressionMetrics() {
 #if !defined(OS_IOS) && !defined(OS_ANDROID)
-  // Number of times the user needs to dismiss a save/update bubble for it to
-  // not be shown again. This happens only on desktop platforms.
-  int threshold =
-      password_bubble_experiment::GetSmartBubbleDismissalThreshold();
-  LogAccountStatHiRes(
-      "PasswordManager.BubbleSuppression.DomainsWithSuppressedBubble",
-      stats_table_.GetNumDomainsWithAtLeastNDismissals(threshold));
-  LogAccountStatHiRes(
-      "PasswordManager.BubbleSuppression.AccountsWithSuppressedBubble",
-      stats_table_.GetNumAccountsWithAtLeastNDismissals(threshold));
   LogAccountStatHiRes(
       "PasswordManager.BubbleSuppression.AccountsInStatisticsTable",
       stats_table_.GetNumAccounts());
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc
index b8701aed..ca3f8d7 100644
--- a/components/password_manager/core/browser/login_database_unittest.cc
+++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -1633,10 +1633,6 @@
                                       0, 1);
 #if !defined(OS_IOS) && !defined(OS_ANDROID)
   histogram_tester.ExpectUniqueSample(
-      "PasswordManager.BubbleSuppression.DomainsWithSuppressedBubble", 2, 1);
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.BubbleSuppression.AccountsWithSuppressedBubble", 3, 1);
-  histogram_tester.ExpectUniqueSample(
       "PasswordManager.BubbleSuppression.AccountsInStatisticsTable", 4, 1);
 #endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
 }
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index f01691ed..d1892f1 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -234,6 +234,8 @@
   registry->RegisterTimePref(prefs::kAccountStoreDateLastUsedForFilling,
                              base::Time());
 
+  registry->RegisterIntegerPref(prefs::kSettingsLaunchedPasswordChecks, 0);
+
 #if defined(OS_MACOSX)
   registry->RegisterIntegerPref(prefs::kKeychainMigrationStatus,
                                 4 /* MIGRATED_DELETED */);
diff --git a/components/password_manager/core/browser/password_manager_client.cc b/components/password_manager/core/browser/password_manager_client.cc
index ac7fd054..0e81070 100644
--- a/components/password_manager/core/browser/password_manager_client.cc
+++ b/components/password_manager/core/browser/password_manager_client.cc
@@ -54,6 +54,7 @@
 
 void PasswordManagerClient::NotifyUserCredentialsWereLeaked(
     password_manager::CredentialLeakType leak_type,
+    password_manager::CompromisedSitesCount saved_sites,
     const GURL& origin,
     const base::string16& username) {}
 
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h
index 7892425a..0bc497cf 100644
--- a/components/password_manager/core/browser/password_manager_client.h
+++ b/components/password_manager/core/browser/password_manager_client.h
@@ -243,9 +243,11 @@
                                 const PasswordFormManagerForUI* form_manager);
 
   // Informs the embedder that user credentials were leaked.
-  virtual void NotifyUserCredentialsWereLeaked(CredentialLeakType leak_type,
-                                               const GURL& origin,
-                                               const base::string16& username);
+  virtual void NotifyUserCredentialsWereLeaked(
+      CredentialLeakType leak_type,
+      CompromisedSitesCount saved_sites,
+      const GURL& origin,
+      const base::string16& username);
 
   // Requests a reauth for the primary account with |access_point| representing
   // where the reauth was triggered.
diff --git a/components/password_manager/core/browser/statistics_table.cc b/components/password_manager/core/browser/statistics_table.cc
index 82439375f..b291001 100644
--- a/components/password_manager/core/browser/statistics_table.cc
+++ b/components/password_manager/core/browser/statistics_table.cc
@@ -177,24 +177,6 @@
   return success;
 }
 
-int StatisticsTable::GetNumDomainsWithAtLeastNDismissals(int64_t n) {
-  sql::Statement select_statement(
-      db_->GetCachedStatement(SQL_FROM_HERE,
-                              "SELECT COUNT(DISTINCT origin_domain) FROM stats "
-                              "WHERE dismissal_count >= ?"));
-  select_statement.BindInt64(0, n);
-  return select_statement.Step() ? select_statement.ColumnInt(0) : 0u;
-}
-
-int StatisticsTable::GetNumAccountsWithAtLeastNDismissals(int64_t n) {
-  sql::Statement select_statement(
-      db_->GetCachedStatement(SQL_FROM_HERE,
-                              "SELECT COUNT(1) FROM stats "
-                              "WHERE dismissal_count >= ?"));
-  select_statement.BindInt64(0, n);
-  return select_statement.Step() ? select_statement.ColumnInt(0) : 0u;
-}
-
 int StatisticsTable::GetNumAccounts() {
   sql::Statement select_statement(
       db_->GetCachedStatement(SQL_FROM_HERE, "SELECT COUNT(1) FROM stats"));
diff --git a/components/password_manager/core/browser/statistics_table.h b/components/password_manager/core/browser/statistics_table.h
index 59ec582..9295dec 100644
--- a/components/password_manager/core/browser/statistics_table.h
+++ b/components/password_manager/core/browser/statistics_table.h
@@ -75,14 +75,6 @@
       base::Time delete_begin,
       base::Time delete_end);
 
-  // Returns the number of distinct domains for which at least one account has
-  // |n| or more dismissals.
-  int GetNumDomainsWithAtLeastNDismissals(int64_t n);
-
-  // Returns the number of distinct accounts for which have at least |n| or more
-  // dismissals.
-  int GetNumAccountsWithAtLeastNDismissals(int64_t n);
-
   // Returns the number of rows (origin/username pairs) in the table.
   int GetNumAccounts();
 
diff --git a/components/password_manager/core/browser/statistics_table_unittest.cc b/components/password_manager/core/browser/statistics_table_unittest.cc
index 198332a..2ef8c6d 100644
--- a/components/password_manager/core/browser/statistics_table_unittest.cc
+++ b/components/password_manager/core/browser/statistics_table_unittest.cc
@@ -207,12 +207,6 @@
   }
 
   EXPECT_EQ(5, db()->GetNumAccounts());  // A,B,C,D,E
-
-  EXPECT_EQ(3, db()->GetNumDomainsWithAtLeastNDismissals(1));   // (A,B,C), D, E
-  EXPECT_EQ(2, db()->GetNumDomainsWithAtLeastNDismissals(10));  // (A,B), E
-
-  EXPECT_EQ(5, db()->GetNumAccountsWithAtLeastNDismissals(1));   // A,B,C,D,E
-  EXPECT_EQ(3, db()->GetNumAccountsWithAtLeastNDismissals(10));  // A,B,E
 }
 
 }  // namespace
diff --git a/components/password_manager/core/common/password_manager_pref_names.cc b/components/password_manager/core/common/password_manager_pref_names.cc
index c64c046..608f7e0 100644
--- a/components/password_manager/core/common/password_manager_pref_names.cc
+++ b/components/password_manager/core/common/password_manager_pref_names.cc
@@ -68,5 +68,8 @@
 const char kAccountStoreDateLastUsedForFilling[] =
     "password_manager.account_store_date_last_used_for_filling";
 
+const char kSettingsLaunchedPasswordChecks[] =
+    "profile.settings_launched_password_checks";
+
 }  // namespace prefs
 }  // namespace password_manager
diff --git a/components/password_manager/core/common/password_manager_pref_names.h b/components/password_manager/core/common/password_manager_pref_names.h
index 4f350f6..99095cef 100644
--- a/components/password_manager/core/common/password_manager_pref_names.h
+++ b/components/password_manager/core/common/password_manager_pref_names.h
@@ -104,6 +104,10 @@
 extern const char kProfileStoreDateLastUsedForFilling[];
 extern const char kAccountStoreDateLastUsedForFilling[];
 
+// Number of times the check for leaked password has been performed from the
+// password settings.
+extern const char kSettingsLaunchedPasswordChecks[];
+
 }  // namespace prefs
 }  // namespace password_manager
 
diff --git a/components/password_manager_strings.grdp b/components/password_manager_strings.grdp
index d66f56e..fe14620 100644
--- a/components/password_manager_strings.grdp
+++ b/components/password_manager_strings.grdp
@@ -25,6 +25,12 @@
   <message name="IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE" desc="The text that is used in credential leak detection dialog when the leaked credentials were not saved but used on multiple sites. The leaked credentials may have been leaked by the current website, some other third-party website or even a third-party app used by the user. It could also be coincidental reuse of a trivial password used by some other users in the world and exposed in a public leak.">
     A data breach on a site or app exposed your password. Chrome recommends checking your saved passwords and changing your password on <ph name="ORIGIN">$1<ex>example.com</ex></ph> now.
   </message>
+  <message name="IDS_CREDENTIAL_LEAK_SAVED_PASSWORDS_MESSAGE" desc="The text that is used in credential leak detection dialog when the leaked credentials were saved for at least one and X other sites. The leaked credentials may have been leaked by the current website, some other third-party website or even a third-party app used by the user. It could also be coincidental reuse of a trivial password used by some other users in the world and exposed in a public leak.">
+  {1, plural,
+     =0 {A data breach on a site or app exposed your saved password for <ph name="ORIGIN">{0}<ex>example.com</ex></ph>. Chrome recommends changing your password on <ph name="ORIGIN">{0}<ex>example.com</ex></ph> now.}
+     =1 {A data breach on a site or app exposed your saved password for <ph name="ORIGIN">{0}<ex>example.com</ex></ph> and one other site. Chrome recommends checking your saved passwords now.}
+     other {A data breach on a site or app exposed your saved password for <ph name="ORIGIN">{0}<ex>example.com</ex></ph> and <ph name="SITES_COUNT">#<ex>2</ex></ph> other sites. Chrome recommends checking your saved passwords now.}}
+  </message>
   <if expr="is_ios">
     <message name="IDS_IOS_SUGGEST_PASSWORD" desc="Button title in the keyboard accessory bar to show a dialog with a generated password. [Length: 20em] [iOS only]">
       Suggest Password...
diff --git a/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_SAVED_PASSWORDS_MESSAGE.png.sha1 b/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_SAVED_PASSWORDS_MESSAGE.png.sha1
new file mode 100644
index 0000000..b7a7014
--- /dev/null
+++ b/components/password_manager_strings_grdp/IDS_CREDENTIAL_LEAK_SAVED_PASSWORDS_MESSAGE.png.sha1
@@ -0,0 +1 @@
+dc7b365cedcbeffe5a3848a7db5092d38eb1738f
\ No newline at end of file
diff --git a/components/payments/content/autofill_payment_app_unittest.cc b/components/payments/content/autofill_payment_app_unittest.cc
index acaf906..a465d7d 100644
--- a/components/payments/content/autofill_payment_app_unittest.cc
+++ b/components/payments/content/autofill_payment_app_unittest.cc
@@ -21,7 +21,6 @@
 #include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/payments/core/test_payment_request_delegate.h"
 #include "components/strings/grit/components_strings.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
diff --git a/components/payments/content/service_worker_payment_app_finder.cc b/components/payments/content/service_worker_payment_app_finder.cc
index ed22125..5dc754e 100644
--- a/components/payments/content/service_worker_payment_app_finder.cc
+++ b/components/payments/content/service_worker_payment_app_finder.cc
@@ -31,7 +31,6 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/stored_payment_app.h"
 #include "content/public/browser/web_contents.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "ui/gfx/image/image.h"
 #include "url/url_canon.h"
 
diff --git a/components/payments/core/payment_manifest_downloader_unittest.cc b/components/payments/core/payment_manifest_downloader_unittest.cc
index 9d72ec2..4cf6aab 100644
--- a/components/payments/core/payment_manifest_downloader_unittest.cc
+++ b/components/payments/core/payment_manifest_downloader_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/payments/core/error_logger.h"
 #include "net/http/http_response_headers.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
diff --git a/components/payments/core/test_payment_request_delegate.h b/components/payments/core/test_payment_request_delegate.h
index df0b9dca..ff638f5 100644
--- a/components/payments/core/test_payment_request_delegate.h
+++ b/components/payments/core/test_payment_request_delegate.h
@@ -14,7 +14,6 @@
 #include "components/autofill/core/browser/test_address_normalizer.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/payments/core/payment_request_delegate.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
diff --git a/components/policy/android/java/src/org/chromium/policy/AppRestrictionsProvider.java b/components/policy/android/java/src/org/chromium/policy/AppRestrictionsProvider.java
index d2061f5..1412114 100644
--- a/components/policy/android/java/src/org/chromium/policy/AppRestrictionsProvider.java
+++ b/components/policy/android/java/src/org/chromium/policy/AppRestrictionsProvider.java
@@ -4,10 +4,8 @@
 
 package org.chromium.policy;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.os.UserManager;
@@ -25,17 +23,11 @@
         super(context);
 
         // getApplicationRestrictions method of UserManager was introduced in JELLY_BEAN_MR2.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-            mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        } else {
-            mUserManager = null;
-        }
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
     }
 
     @Override
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
     protected Bundle getApplicationRestrictions(String packageName) {
-        if (mUserManager == null) return new Bundle();
         try {
             long startTime = SystemClock.elapsedRealtime();
             Bundle bundle = mUserManager.getApplicationRestrictions(packageName);
@@ -57,10 +49,7 @@
     }
 
     @Override
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     protected String getRestrictionChangeIntentAction() {
-        // Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED was introduced in LOLLIPOP.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return null;
         return Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED;
     }
 }
diff --git a/components/policy/android/java/src/org/chromium/policy/PolicyConverter.java b/components/policy/android/java/src/org/chromium/policy/PolicyConverter.java
index a243b240..957b709f 100644
--- a/components/policy/android/java/src/org/chromium/policy/PolicyConverter.java
+++ b/components/policy/android/java/src/org/chromium/policy/PolicyConverter.java
@@ -4,8 +4,6 @@
 
 package org.chromium.policy;
 
-import android.annotation.TargetApi;
-import android.os.Build;
 import android.os.Bundle;
 
 import androidx.annotation.VisibleForTesting;
@@ -65,46 +63,44 @@
                     mNativePolicyConverter, PolicyConverter.this, key, (String[]) value);
             return;
         }
-        // App restrictions can only contain bundles and bundle arrays on Android M, however our
-        // version of Robolectric only supports Lollipop, and allowing this on LOLLIPOP doesn't
-        // cause problems.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            if (value instanceof Bundle) {
-                Bundle bundle = (Bundle) value;
-                // JNI can't take a Bundle argument without a lot of extra work, but the native code
-                // already accepts arbitrary JSON strings, so convert to JSON.
-                try {
-                    PolicyConverterJni.get().setPolicyString(mNativePolicyConverter,
-                            PolicyConverter.this, key, convertBundleToJson(bundle).toString());
-                } catch (JSONException e) {
-                    // Chrome requires all policies to be expressible as JSON, so this can't be a
-                    // valid policy.
-                    Log.w(TAG, "Invalid bundle in app restrictions " + bundle.toString()
-                                    + " for key " + key);
-                }
-                return;
+        // App restrictions can only contain bundles and bundle arrays on Android M, but
+        // allowing this on LOLLIPOP doesn't cause problems.
+        if (value instanceof Bundle) {
+            Bundle bundle = (Bundle) value;
+            // JNI can't take a Bundle argument without a lot of extra work, but the native code
+            // already accepts arbitrary JSON strings, so convert to JSON.
+            try {
+                PolicyConverterJni.get().setPolicyString(mNativePolicyConverter,
+                        PolicyConverter.this, key, convertBundleToJson(bundle).toString());
+            } catch (JSONException e) {
+                // Chrome requires all policies to be expressible as JSON, so this can't be a
+                // valid policy.
+                Log.w(TAG,
+                        "Invalid bundle in app restrictions " + bundle.toString() + " for key "
+                                + key);
             }
-            if (value instanceof Bundle[]) {
-                Bundle[] bundleArray = (Bundle[]) value;
-                // JNI can't take a Bundle[] argument without a lot of extra work, but the native
-                // code already accepts arbitrary JSON strings, so convert to JSON.
-                try {
-                    PolicyConverterJni.get().setPolicyString(mNativePolicyConverter,
-                            PolicyConverter.this, key,
-                            convertBundleArrayToJson(bundleArray).toString());
-                } catch (JSONException e) {
-                    // Chrome requires all policies to be expressible as JSON, so this can't be a
-                    // valid policy.
-                    Log.w(TAG, "Invalid bundle array in app restrictions "
-                                    + Arrays.toString(bundleArray) + " for key " + key);
-                }
-                return;
+            return;
+        }
+        if (value instanceof Bundle[]) {
+            Bundle[] bundleArray = (Bundle[]) value;
+            // JNI can't take a Bundle[] argument without a lot of extra work, but the native
+            // code already accepts arbitrary JSON strings, so convert to JSON.
+            try {
+                PolicyConverterJni.get().setPolicyString(mNativePolicyConverter,
+                        PolicyConverter.this, key,
+                        convertBundleArrayToJson(bundleArray).toString());
+            } catch (JSONException e) {
+                // Chrome requires all policies to be expressible as JSON, so this can't be a
+                // valid policy.
+                Log.w(TAG,
+                        "Invalid bundle array in app restrictions " + Arrays.toString(bundleArray)
+                                + " for key " + key);
             }
+            return;
         }
         assert false : "Invalid setting " + value + " for key " + key;
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     private JSONObject convertBundleToJson(Bundle bundle) throws JSONException {
         JSONObject json = new JSONObject();
         Set<String> keys = bundle.keySet();
@@ -117,7 +113,6 @@
         return json;
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     private JSONArray convertBundleArrayToJson(Bundle[] bundleArray) throws JSONException {
         JSONArray json = new JSONArray();
         for (Bundle bundle : bundleArray) {
diff --git a/components/previews/content/previews_decider.h b/components/previews/content/previews_decider.h
index 7c0bd4a..05ae1f6 100644
--- a/components/previews/content/previews_decider.h
+++ b/components/previews/content/previews_decider.h
@@ -37,11 +37,6 @@
                                    content::NavigationHandle* navigation_handle,
                                    PreviewsType type) const = 0;
 
-  // Whether there may be commit-time preview guidance available for the URL
-  // associated with |navigation_handle|.
-  virtual bool AreCommitTimePreviewsAvailable(
-      content::NavigationHandle* navigation_handle) = 0;
-
  protected:
   PreviewsDecider() {}
   virtual ~PreviewsDecider() {}
diff --git a/components/previews/content/previews_decider_impl.cc b/components/previews/content/previews_decider_impl.cc
index d53bea9..86b9e3c1 100644
--- a/components/previews/content/previews_decider_impl.cc
+++ b/components/previews/content/previews_decider_impl.cc
@@ -46,51 +46,6 @@
       ->Add(static_cast<int>(status));
 }
 
-bool ShouldCheckOptimizationHints(PreviewsType type) {
-  switch (type) {
-    // These types may have server optimization hints.
-    case PreviewsType::NOSCRIPT:
-    case PreviewsType::RESOURCE_LOADING_HINTS:
-    case PreviewsType::DEFER_ALL_SCRIPT:
-      return true;
-    // These types do not have server optimization hints.
-    case PreviewsType::OFFLINE:
-    case PreviewsType::LITE_PAGE:
-      return false;
-    case PreviewsType::NONE:
-    case PreviewsType::UNSPECIFIED:
-    case PreviewsType::DEPRECATED_AMP_REDIRECTION:
-    case PreviewsType::DEPRECATED_LOFI:
-    case PreviewsType::DEPRECATED_LITE_PAGE_REDIRECT:
-    case PreviewsType::LAST:
-      break;
-  }
-  NOTREACHED();
-  return false;
-}
-
-// Returns true if the decision to apply |type| can wait until commit time.
-bool IsCommitTimePreview(PreviewsType type) {
-  switch (type) {
-    case PreviewsType::NOSCRIPT:
-    case PreviewsType::RESOURCE_LOADING_HINTS:
-    case PreviewsType::DEFER_ALL_SCRIPT:
-      return true;
-    case PreviewsType::OFFLINE:
-    case PreviewsType::LITE_PAGE:
-      return false;
-    case PreviewsType::NONE:
-    case PreviewsType::UNSPECIFIED:
-    case PreviewsType::DEPRECATED_AMP_REDIRECTION:
-    case PreviewsType::DEPRECATED_LOFI:
-    case PreviewsType::DEPRECATED_LITE_PAGE_REDIRECT:
-    case PreviewsType::LAST:
-      break;
-  }
-  NOTREACHED();
-  return false;
-}
-
 }  // namespace
 
 PreviewsDeciderImpl::PreviewsDeciderImpl(base::Clock* clock)
@@ -200,11 +155,9 @@
     return false;
   }
 
-  bool is_drp_server_preview = (type == PreviewsType::LITE_PAGE);
   std::vector<PreviewsEligibilityReason> passed_reasons;
-  PreviewsEligibilityReason eligibility =
-      DeterminePreviewEligibility(previews_data, navigation_handle, is_reload,
-                                  type, is_drp_server_preview, &passed_reasons);
+  PreviewsEligibilityReason eligibility = DeterminePreviewEligibility(
+      previews_data, navigation_handle, is_reload, type, &passed_reasons);
   LogPreviewDecisionMade(eligibility, url, clock_->Now(), type,
                          std::move(passed_reasons), previews_data);
   return eligibility == PreviewsEligibilityReason::ALLOWED;
@@ -224,7 +177,6 @@
     content::NavigationHandle* navigation_handle,
     bool is_reload,
     PreviewsType type,
-    bool is_drp_server_preview,
     std::vector<PreviewsEligibilityReason>* passed_reasons) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(previews::params::ArePreviewsAllowed());
@@ -252,49 +204,6 @@
   // TODO(sophiechang): Remove the ECT unknown and offline checks when
   // optimization guide checks for those values specifically.
 
-  // Check whether the page load is painful or not for previews that require a
-  // decision at navigation start. This does not do the checking for HTTP server
-  // previews because the server will perform its own ECT check. This also does
-  // not do the checking for commit-time previews since more information may
-  // become available later on in the page load.
-  if (!is_drp_server_preview && !IsCommitTimePreview(type)) {
-    if (effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
-      return PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE;
-    }
-    passed_reasons->push_back(
-        PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE);
-
-    // Network quality estimator may sometimes return effective connection type
-    // as offline when the Android APIs incorrectly return device connectivity
-    // as null. See https://crbug.com/838969. So, we do not trigger previews
-    // when |observed_effective_connection_type| is
-    // net::EFFECTIVE_CONNECTION_TYPE_OFFLINE.
-    if (effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_OFFLINE) {
-      return PreviewsEligibilityReason::DEVICE_OFFLINE;
-    }
-    passed_reasons->push_back(PreviewsEligibilityReason::DEVICE_OFFLINE);
-
-    // If the optimization type is not a commit-time preview, determine whether
-    // we should show a Preview here.
-    if (!IsCommitTimePreview(type)) {
-      // ECT should not be checked if we are able to evaluate whether a page
-      // load is painful or not.
-      if (previews_opt_guide_) {
-        if (!previews_opt_guide_->ShouldShowPreview(navigation_handle)) {
-          return PreviewsEligibilityReason::PAGE_LOAD_PREDICTION_NOT_PAINFUL;
-        }
-        passed_reasons->push_back(
-            PreviewsEligibilityReason::PAGE_LOAD_PREDICTION_NOT_PAINFUL);
-      } else {
-        if (effective_connection_type_ >
-            previews::params::GetECTThresholdForPreview(type)) {
-          return PreviewsEligibilityReason::NETWORK_NOT_SLOW;
-        }
-        passed_reasons->push_back(PreviewsEligibilityReason::NETWORK_NOT_SLOW);
-      }
-    }
-  }
-
   if (is_reload) {
     return PreviewsEligibilityReason::RELOAD_DISALLOWED;
   }
@@ -306,39 +215,22 @@
            switches::kEnableDeferAllScriptWithoutOptimizationHints));
 
   // Check optimization hints, if provided.
-  if (ShouldCheckOptimizationHints(type) && !skip_hint_check) {
+  if (!skip_hint_check) {
     if (previews_opt_guide_) {
       // Optimization hints are configured, so determine if those hints
       // allow the optimization type (as of start-of-navigation time anyway).
-      return ShouldAllowPreviewPerOptimizationHints(
-          previews_data, navigation_handle, type, passed_reasons);
-    } else if (type == PreviewsType::RESOURCE_LOADING_HINTS ||
-               type == PreviewsType::NOSCRIPT ||
-               type == PreviewsType::DEFER_ALL_SCRIPT) {
+      return PreviewsEligibilityReason::ALLOWED;
+    } else {
       return PreviewsEligibilityReason::OPTIMIZATION_HINTS_NOT_AVAILABLE;
     }
   }
 
-  // Skip blocklist checks if the blocklist is ignored or defer check until
-  // commit time if preview type is to be decided at commit time.
-  if (!blocklist_ignored_ && !IsCommitTimePreview(type)) {
-    PreviewsEligibilityReason status =
-        CheckLocalBlocklist(url, type, is_drp_server_preview, passed_reasons);
-    if (status != PreviewsEligibilityReason::ALLOWED) {
-      if (type == PreviewsType::LITE_PAGE) {
-        previews_data->set_block_listed_for_lite_page(true);
-      }
-      return status;
-    }
-  }
-
   return PreviewsEligibilityReason::ALLOWED;
 }
 
 PreviewsEligibilityReason PreviewsDeciderImpl::CheckLocalBlocklist(
     const GURL& url,
     PreviewsType type,
-    bool is_drp_server_preview,
     std::vector<PreviewsEligibilityReason>* passed_reasons) const {
   if (!previews_block_list_)
     return PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE;
@@ -355,20 +247,7 @@
 
   // The blocklist will disallow certain hosts for periods of time based on
   // user's opting out of the preview.
-  return previews_block_list_->IsLoadedAndAllowed(
-      url, type,
-      is_drp_server_preview && ignore_long_term_blocklist_for_server_previews_,
-      passed_reasons);
-}
-
-bool PreviewsDeciderImpl::AreCommitTimePreviewsAvailable(
-    content::NavigationHandle* navigation_handle) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (!previews_opt_guide_)
-    return false;
-
-  return previews_opt_guide_->AreCommitTimePreviewsAvailable(navigation_handle);
+  return previews_block_list_->IsLoadedAndAllowed(url, type, passed_reasons);
 }
 
 bool PreviewsDeciderImpl::ShouldCommitPreview(
@@ -382,8 +261,8 @@
 
   const GURL committed_url = navigation_handle->GetURL();
 
-  // Re-check server optimization hints (if provided) on this commit-time URL.
-  if (ShouldCheckOptimizationHints(type) && previews_opt_guide_) {
+  // Check optimization hints (if provided) on this commit-time URL.
+  if (previews_opt_guide_) {
     std::vector<PreviewsEligibilityReason> passed_reasons;
     PreviewsEligibilityReason status = ShouldCommitPreviewPerOptimizationHints(
         previews_data, navigation_handle, type, &passed_reasons);
@@ -395,10 +274,10 @@
   }
 
   // Check local blocklist for commit-time preview (if blocklist not ignored).
-  if (!blocklist_ignored_ && IsCommitTimePreview(type)) {
+  if (!blocklist_ignored_) {
     std::vector<PreviewsEligibilityReason> passed_reasons;
     PreviewsEligibilityReason status =
-        CheckLocalBlocklist(committed_url, type, false, &passed_reasons);
+        CheckLocalBlocklist(committed_url, type, &passed_reasons);
     if (status != PreviewsEligibilityReason::ALLOWED) {
       LogPreviewDecisionMade(status, committed_url, clock_->Now(), type,
                              std::move(passed_reasons), previews_data);
@@ -410,20 +289,6 @@
 }
 
 PreviewsEligibilityReason
-PreviewsDeciderImpl::ShouldAllowPreviewPerOptimizationHints(
-    PreviewsUserData* previews_data,
-    content::NavigationHandle* navigation_handle,
-    PreviewsType type,
-    std::vector<PreviewsEligibilityReason>* passed_reasons) const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(type == PreviewsType::NOSCRIPT ||
-         type == PreviewsType::RESOURCE_LOADING_HINTS ||
-         type == PreviewsType::DEFER_ALL_SCRIPT);
-
-  return PreviewsEligibilityReason::ALLOWED;
-}
-
-PreviewsEligibilityReason
 PreviewsDeciderImpl::ShouldCommitPreviewPerOptimizationHints(
     PreviewsUserData* previews_data,
     content::NavigationHandle* navigation_handle,
@@ -470,8 +335,7 @@
   // connectivity as null. See https://crbug.com/838969. So, we do not trigger
   // previews when |ect| is net::EFFECTIVE_CONNECTION_TYPE_OFFLINE.
   net::EffectiveConnectionType ect = previews_data->navigation_ect();
-  if (IsCommitTimePreview(type) &&
-      ect == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
+  if (ect == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
     // Update the |ect| to the current value.
     ect = effective_connection_type_;
   }
@@ -495,13 +359,6 @@
   return ++page_id_;
 }
 
-void PreviewsDeciderImpl::SetIgnoreLongTermBlockListForServerPreviews(
-    bool ignore_long_term_blocklist_for_server_previews) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  ignore_long_term_blocklist_for_server_previews_ =
-      ignore_long_term_blocklist_for_server_previews;
-}
-
 void PreviewsDeciderImpl::SetEffectiveConnectionType(
     net::EffectiveConnectionType effective_connection_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/components/previews/content/previews_decider_impl.h b/components/previews/content/previews_decider_impl.h
index 73a9178..e9fb0e49 100644
--- a/components/previews/content/previews_decider_impl.h
+++ b/components/previews/content/previews_decider_impl.h
@@ -119,13 +119,6 @@
                            content::NavigationHandle* navigation_handle,
                            PreviewsType type) const override;
 
-  // Set whether to ignore the long term blocklist rules for server previews.
-  void SetIgnoreLongTermBlockListForServerPreviews(
-      bool ignore_long_term_blocklist_for_server_previews);
-
-  bool AreCommitTimePreviewsAvailable(
-      content::NavigationHandle* navigation_handle) override;
-
   // Generates a page ID that is guaranteed to be unique from any other page ID
   // generated in this browser session. Also, guaranteed to be non-zero.
   uint64_t GeneratePageId();
@@ -160,14 +153,12 @@
       content::NavigationHandle* navigation_handle,
       bool is_reload,
       PreviewsType type,
-      bool is_drp_server_preview,
       std::vector<PreviewsEligibilityReason>* passed_reasons) const;
 
   // Returns previews eligibility with respect to the local blocklist.
   PreviewsEligibilityReason CheckLocalBlocklist(
       const GURL& url,
       PreviewsType type,
-      bool is_drp_server_preview,
       std::vector<PreviewsEligibilityReason>* passed_reasons) const;
 
   // Whether the preview |type| should be allowed to be considered for |url|
@@ -204,9 +195,6 @@
   // set it in flags. See previews::IsPreviewsBlocklistIgnoredViaFlag.
   bool blocklist_ignored_;
 
-  // Whether to ignore the blocklist for server previews.
-  bool ignore_long_term_blocklist_for_server_previews_ = false;
-
   // The estimate of how slow a user's connection is. Used for triggering
   // Previews.
   net::EffectiveConnectionType effective_connection_type_ =
diff --git a/components/previews/content/previews_decider_impl_unittest.cc b/components/previews/content/previews_decider_impl_unittest.cc
index 3cdf198..985d9d54 100644
--- a/components/previews/content/previews_decider_impl_unittest.cc
+++ b/components/previews/content/previews_decider_impl_unittest.cc
@@ -60,19 +60,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-// TODO(crbug.com/961023): Fix memory leaks in tests and re-enable on LSAN.
-#ifdef LEAK_SANITIZER
-#define MAYBE_TestSetBlocklistBoolDueToBlockListState \
-  DISABLED_TestSetBlocklistBoolDueToBlockListState
-#define MAYBE_TestDisallowPreviewBecauseOfBlockListState \
-  DISABLED_TestDisallowPreviewBecauseOfBlockListState
-#else
-#define MAYBE_TestSetBlocklistBoolDueToBlockListState \
-  TestSetBlocklistBoolDueToBlockListState
-#define MAYBE_TestDisallowPreviewBecauseOfBlockListState \
-  TestDisallowPreviewBecauseOfBlockListState
-#endif
-
 namespace previews {
 
 namespace {
@@ -85,9 +72,10 @@
 // offline previews check.
 bool IsPreviewFieldTrialEnabled(PreviewsType type) {
   switch (type) {
-    case PreviewsType::OFFLINE:
-    case PreviewsType::LITE_PAGE:
-      return params::IsOfflinePreviewsEnabled();
+    case PreviewsType::DEPRECATED_OFFLINE:
+      return false;
+    case PreviewsType::DEPRECATED_LITE_PAGE:
+      return false;
     case PreviewsType::DEPRECATED_AMP_REDIRECTION:
       return false;
     case PreviewsType::DEPRECATED_LOFI:
@@ -126,16 +114,12 @@
   PreviewsEligibilityReason IsLoadedAndAllowed(
       const GURL& url,
       PreviewsType type,
-      bool ignore_long_term_block_list_rules,
       std::vector<PreviewsEligibilityReason>* passed_reasons) const override {
     std::vector<PreviewsEligibilityReason> ordered_reasons = {
         PreviewsEligibilityReason::BLOCKLIST_DATA_NOT_LOADED,
-        PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT};
-
-    if (!ignore_long_term_block_list_rules) {
-      ordered_reasons.push_back(PreviewsEligibilityReason::USER_BLOCKLISTED);
-      ordered_reasons.push_back(PreviewsEligibilityReason::HOST_BLOCKLISTED);
-    }
+        PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT,
+        PreviewsEligibilityReason::USER_BLOCKLISTED,
+        PreviewsEligibilityReason::HOST_BLOCKLISTED};
 
     for (auto reason : ordered_reasons) {
       if (status_ == reason) {
@@ -311,6 +295,7 @@
       PreviewsType type,
       std::vector<PreviewsEligibilityReason>&& passed_reasons,
       uint64_t page_id) override {
+    LOG(INFO) << "Decision is logged";
     decision_reasons_.push_back(reason);
     decision_urls_.push_back(GURL(url));
     decision_times_.push_back(time);
@@ -415,8 +400,6 @@
   void InitializeUIServiceWithoutWaitingForBlockList(
       bool include_previews_opt_guide) {
     blocklist::BlocklistData::AllowedTypesAndVersions allowed_types;
-    allowed_types[static_cast<int>(PreviewsType::OFFLINE)] = 0;
-    allowed_types[static_cast<int>(PreviewsType::LITE_PAGE)] = 0;
     allowed_types[static_cast<int>(PreviewsType::NOSCRIPT)] = 0;
     allowed_types[static_cast<int>(PreviewsType::RESOURCE_LOADING_HINTS)] = 0;
     allowed_types[static_cast<int>(PreviewsType::DEFER_ALL_SCRIPT)] = 0;
@@ -489,7 +472,7 @@
 TEST_F(PreviewsDeciderImplTest, TestDisallowBasicAuthentication) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
+      {features::kPreviews, features::kDeferAllScriptPreviews}, {});
   InitializeUIService();
   ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_2G);
 
@@ -498,221 +481,19 @@
   content::MockNavigationHandle navigation_handle;
   navigation_handle.set_url(GURL("https://user:pass@www.google.com"));
   EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
+      &user_data, &navigation_handle, false, PreviewsType::DEFER_ALL_SCRIPT));
   histogram_tester.ExpectBucketCount(
       "Previews.EligibilityReason",
       static_cast<int>(PreviewsEligibilityReason::URL_HAS_BASIC_AUTH), 1);
   histogram_tester.ExpectBucketCount(
-      "Previews.EligibilityReason.Offline",
+      "Previews.EligibilityReason.DeferAllScript",
       static_cast<int>(PreviewsEligibilityReason::URL_HAS_BASIC_AUTH), 1);
 }
 
-// Tests most of the reasons that a preview could be disallowed because of the
-// state of the blocklist. Excluded values are USER_RECENTLY_OPTED_OUT,
-// USER_BLOCKLISTED, HOST_BLOCKLISTED. These are internal to the blocklist.
-TEST_F(PreviewsDeciderImplTest,
-       MAYBE_TestDisallowPreviewBecauseOfBlockListState) {
+TEST_F(PreviewsDeciderImplTest, TestDisallowOnReload) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  base::HistogramTester histogram_tester;
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-
-  InitializeUIServiceWithoutWaitingForBlockList(
-      /*include_previews_opt_guide=*/true);
-
-  // The blocklist is not loaded yet.
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
-  histogram_tester.ExpectBucketCount(
-      "Previews.EligibilityReason",
-      static_cast<int>(PreviewsEligibilityReason::BLOCKLIST_DATA_NOT_LOADED),
-      1);
-  histogram_tester.ExpectBucketCount(
-      "Previews.EligibilityReason.Offline",
-      static_cast<int>(PreviewsEligibilityReason::BLOCKLIST_DATA_NOT_LOADED),
-      1);
-
-  base::RunLoop().RunUntilIdle();
-
-  histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 1);
-
-  // Return one of the failing statuses from the blocklist; cause the blocklist
-  // to not be loaded by clearing the blocklist.
-  base::Time now = base::Time::Now();
-  previews_decider_impl()->ClearBlockList(now, now);
-
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
-  histogram_tester.ExpectBucketCount(
-      "Previews.EligibilityReason.Offline",
-      static_cast<int>(PreviewsEligibilityReason::BLOCKLIST_DATA_NOT_LOADED),
-      2);
-  histogram_tester.ExpectBucketCount(
-      "Previews.EligibilityReason",
-      static_cast<int>(PreviewsEligibilityReason::BLOCKLIST_DATA_NOT_LOADED),
-      2);
-  histogram_tester.ExpectTotalCount("Previews.EligibilityReason.NoScript", 0);
-
-  variations::testing::ClearAllVariationParams();
-}
-
-TEST_F(PreviewsDeciderImplTest, MAYBE_TestSetBlocklistBoolDueToBlockListState) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-
-  base::HistogramTester histogram_tester;
-  InitializeUIServiceWithoutWaitingForBlockList(
-      /*include_previews_opt_guide=*/true);
-  base::RunLoop().RunUntilIdle();
-  previews_decider_impl()->AddPreviewNavigation(
-      GURL("https://www.google.com"), true, PreviewsType::LITE_PAGE, 1);
-
-  EXPECT_FALSE(user_data.block_listed_for_lite_page());
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::LITE_PAGE));
-  EXPECT_TRUE(user_data.block_listed_for_lite_page());
-}
-
-TEST_F(PreviewsDeciderImplTest,
-       TestDisallowOfflineWhenNetworkQualityUnavailable) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService();
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
-
-  base::HistogramTester histogram_tester;
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
-  histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason.Offline",
-      static_cast<int>(PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE),
-      1);
-  histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason",
-      static_cast<int>(PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE),
-      1);
-}
-
-TEST_F(PreviewsDeciderImplTest, TestAllowLitePageWhenNetworkQualityFast) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService(/*include_previews_opt_guide=*/false);
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-
-  // LitePage check NQE on its own.
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_4G);
-
-  base::HistogramTester histogram_tester;
-  EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::LITE_PAGE));
-  histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason.LitePage",
-      static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
-}
-
-TEST_F(PreviewsDeciderImplTest, TestAllowLitePageWhenPageLoadNotPainful) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService(/*include_previews_opt_guide=*/true);
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-
-  // LitePage makes its own judgments about painful page loads.
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_4G);
-
-  base::HistogramTester histogram_tester;
-  EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::LITE_PAGE));
-  histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason.LitePage",
-      static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
-}
-
-TEST_F(PreviewsDeciderImplTest, TestDisallowOfflineWhenNetworkQualityFast) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService(/*include_previews_opt_guide=*/false);
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_3G);
-  base::HistogramTester histogram_tester;
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
-  histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason.Offline",
-      static_cast<int>(PreviewsEligibilityReason::NETWORK_NOT_SLOW), 1);
-}
-
-TEST_F(PreviewsDeciderImplTest, TestDisallowOfflineWhenPageLoadNotPainful) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService(/*include_previews_opt_guide=*/true);
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_3G);
-  base::HistogramTester histogram_tester;
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
-  histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason.Offline",
-      static_cast<int>(
-          PreviewsEligibilityReason::PAGE_LOAD_PREDICTION_NOT_PAINFUL),
-      1);
-}
-
-TEST_F(PreviewsDeciderImplTest, TestDisallowOfflineWhenNetworkOffline) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService();
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
-  base::HistogramTester histogram_tester;
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
-  histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason.Offline",
-      static_cast<int>(PreviewsEligibilityReason::DEVICE_OFFLINE), 1);
-}
-
-TEST_F(PreviewsDeciderImplTest, TestDisallowOfflineOnReload) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
+      {features::kPreviews, features::kDeferAllScriptPreviews}, {});
   InitializeUIService();
 
   ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_2G);
@@ -723,132 +504,30 @@
 
   base::HistogramTester histogram_tester;
   EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, true, PreviewsType::OFFLINE));
+      &user_data, &navigation_handle, true, PreviewsType::DEFER_ALL_SCRIPT));
   histogram_tester.ExpectUniqueSample(
       "Previews.EligibilityReason",
       static_cast<int>(PreviewsEligibilityReason::RELOAD_DISALLOWED), 1);
   histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason.Offline",
+      "Previews.EligibilityReason.DeferAllScript",
       static_cast<int>(PreviewsEligibilityReason::RELOAD_DISALLOWED), 1);
 }
 
-TEST_F(PreviewsDeciderImplTest, TestDisallowOfflineOnReloadWithExperiment) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService();
-
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_2G);
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-
-  base::HistogramTester histogram_tester;
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, true, PreviewsType::OFFLINE));
-  histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason",
-      static_cast<int>(PreviewsEligibilityReason::RELOAD_DISALLOWED), 1);
-  histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason.Offline",
-      static_cast<int>(PreviewsEligibilityReason::RELOAD_DISALLOWED), 1);
-}
-
-TEST_F(PreviewsDeciderImplTest, TestAllowOffline) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService();
-
-  const struct {
-    net::EffectiveConnectionType effective_connection_type;
-    bool expected_offline_allowed;
-  } tests[] = {
-      {net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN, false},
-      {net::EFFECTIVE_CONNECTION_TYPE_OFFLINE, false},
-      {net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, true},
-      {net::EFFECTIVE_CONNECTION_TYPE_2G, true},
-      {net::EFFECTIVE_CONNECTION_TYPE_3G, false},
-  };
-  for (const auto& test : tests) {
-    ReportEffectiveConnectionType(test.effective_connection_type);
-
-    PreviewsUserData user_data(kDefaultPageId);
-    content::MockNavigationHandle navigation_handle;
-    navigation_handle.set_url(GURL("https://www.google.com"));
-    base::HistogramTester histogram_tester;
-    EXPECT_EQ(test.expected_offline_allowed,
-              previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-                  &user_data, &navigation_handle, false, PreviewsType::OFFLINE))
-        << " effective_connection_type=" << test.effective_connection_type;
-    if (test.expected_offline_allowed) {
-      histogram_tester.ExpectUniqueSample(
-          "Previews.EligibilityReason.Offline",
-          static_cast<int>(PreviewsEligibilityReason::ALLOWED), 1);
-    } else {
-      histogram_tester.ExpectBucketCount(
-          "Previews.EligibilityReason.Offline",
-          static_cast<int>(PreviewsEligibilityReason::ALLOWED), 0);
-    }
-  }
-}
-
-TEST_F(PreviewsDeciderImplTest, OfflineDisallowedWhenFeatureDisabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({features::kPreviews},
-                                       {features::kOfflinePreviews});
-  InitializeUIService();
-
-  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
-            params::GetECTThresholdForPreview(PreviewsType::OFFLINE));
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_2G);
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-  base::HistogramTester histogram_tester;
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
-  histogram_tester.ExpectTotalCount("Previews.EligibilityReason.Offline", 0);
-}
-
-TEST_F(PreviewsDeciderImplTest,
-       OfflineDisallowedWhenNetworkQualityUnavailable) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService();
-
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
-
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-  base::HistogramTester histogram_tester;
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
-  histogram_tester.ExpectUniqueSample(
-      "Previews.EligibilityReason.Offline",
-      static_cast<int>(PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE),
-      1);
-}
-
 TEST_F(PreviewsDeciderImplTest, MissingHostDisallowed) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
+      {features::kPreviews, features::kDeferAllScriptPreviews}, {});
   InitializeUIService();
 
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
-            params::GetECTThresholdForPreview(PreviewsType::OFFLINE));
+            params::GetECTThresholdForPreview(PreviewsType::DEFER_ALL_SCRIPT));
   ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_2G);
 
   PreviewsUserData user_data(kDefaultPageId);
   content::MockNavigationHandle navigation_handle;
   navigation_handle.set_url(GURL("file:///sdcard"));
   EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
+      &user_data, &navigation_handle, false, PreviewsType::DEFER_ALL_SCRIPT));
 }
 
 TEST_F(PreviewsDeciderImplTest, NoScriptFeatureDefaultBehavior) {
@@ -1361,7 +1040,7 @@
   InitializeUIService();
   const GURL url("http://www.url_a.com/url_a");
   const bool opt_out = true;
-  const PreviewsType type = PreviewsType::OFFLINE;
+  const PreviewsType type = PreviewsType::DEFER_ALL_SCRIPT;
   const base::Time time = base::Time::Now();
   const uint64_t page_id = 1234;
 
@@ -1386,7 +1065,7 @@
       PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE);
   const GURL url("http://www.url_a.com/url_a");
   const base::Time time = base::Time::Now();
-  const PreviewsType type = PreviewsType::OFFLINE;
+  const PreviewsType type = PreviewsType::DEFER_ALL_SCRIPT;
   std::vector<PreviewsEligibilityReason> passed_reasons = {
       PreviewsEligibilityReason::PAGE_LOAD_PREDICTION_NOT_PAINFUL,
       PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT,
@@ -1414,31 +1093,6 @@
   for (size_t i = 0; i < actual_passed_reasons[0].size(); i++) {
     EXPECT_EQ(expected_passed_reasons[i], actual_passed_reasons[0][i]);
   }
-}  // namespace
-
-TEST_F(
-    PreviewsDeciderImplTest,
-    LogDecisionMadeBlocklistUnavailableAtNavigationStartForNonCommitTimePreview) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-
-  InitializeUIService();
-  auto expected_reason = PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE;
-  auto expected_type = PreviewsType::OFFLINE;
-
-  previews_decider_impl()->InjectTestBlocklist(nullptr /* blocklist */);
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-  previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, expected_type);
-  base::RunLoop().RunUntilIdle();
-  // Testing correct log method is called.
-  EXPECT_THAT(ui_service()->decision_reasons(),
-              ::testing::Contains(expected_reason));
-  EXPECT_THAT(ui_service()->decision_types(),
-              ::testing::Contains(expected_type));
 }
 
 TEST_F(
@@ -1466,47 +1120,6 @@
               ::testing::Contains(expected_type));
 }
 
-TEST_F(PreviewsDeciderImplTest, LogDecisionMadeBlocklistStatusesDefault) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService();
-
-  PreviewsEligibilityReason expected_reasons[] = {
-      PreviewsEligibilityReason::BLOCKLIST_DATA_NOT_LOADED,
-      PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT,
-      PreviewsEligibilityReason::USER_BLOCKLISTED,
-      PreviewsEligibilityReason::HOST_BLOCKLISTED,
-  };
-
-  auto expected_type = PreviewsType::OFFLINE;
-  const size_t reasons_size = 4;
-
-  for (size_t i = 0; i < reasons_size; i++) {
-    auto expected_reason = expected_reasons[i];
-
-    std::unique_ptr<TestPreviewsBlockList> blocklist =
-        std::make_unique<TestPreviewsBlockList>(expected_reason,
-                                                previews_decider_impl());
-    previews_decider_impl()->InjectTestBlocklist(std::move(blocklist));
-
-    PreviewsUserData user_data(kDefaultPageId);
-    content::MockNavigationHandle navigation_handle;
-    navigation_handle.set_url(GURL("https://www.google.com"));
-    previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-        &user_data, &navigation_handle, false, expected_type);
-    base::RunLoop().RunUntilIdle();
-    // Testing correct log method is called.
-    // Check for all decision upto current decision is logged.
-    for (size_t j = 0; j <= i; j++) {
-      EXPECT_THAT(ui_service()->decision_reasons(),
-                  ::testing::Contains(expected_reasons[j]));
-    }
-    EXPECT_THAT(ui_service()->decision_types(),
-                ::testing::Contains(expected_type));
-  }
-}
-
 TEST_F(PreviewsDeciderImplTest, ShouldCommitPreviewBlocklistStatuses) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
@@ -1553,44 +1166,6 @@
   }
 }
 
-TEST_F(PreviewsDeciderImplTest, LogDecisionMadeBlocklistStatusesIgnore) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService();
-  auto expected_reason = PreviewsEligibilityReason::ALLOWED;
-  auto expected_type = PreviewsType::OFFLINE;
-
-  PreviewsEligibilityReason blocklist_decisions[] = {
-      PreviewsEligibilityReason::BLOCKLIST_DATA_NOT_LOADED,
-      PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT,
-      PreviewsEligibilityReason::USER_BLOCKLISTED,
-      PreviewsEligibilityReason::HOST_BLOCKLISTED,
-  };
-
-  previews_decider_impl()->SetIgnorePreviewsBlocklistDecision(
-      true /* ignored */);
-
-  for (auto blocklist_decision : blocklist_decisions) {
-    std::unique_ptr<TestPreviewsBlockList> blocklist =
-        std::make_unique<TestPreviewsBlockList>(blocklist_decision,
-                                                previews_decider_impl());
-    previews_decider_impl()->InjectTestBlocklist(std::move(blocklist));
-    PreviewsUserData user_data(kDefaultPageId);
-    content::MockNavigationHandle navigation_handle;
-    navigation_handle.set_url(GURL("https://www.google.com"));
-    previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-        &user_data, &navigation_handle, false, expected_type);
-
-    base::RunLoop().RunUntilIdle();
-    // Testing correct log method is called.
-    EXPECT_THAT(ui_service()->decision_reasons(),
-                ::testing::Contains(expected_reason));
-    EXPECT_THAT(ui_service()->decision_types(),
-                ::testing::Contains(expected_type));
-  }
-}
-
 TEST_F(PreviewsDeciderImplTest, LogDecisionMadeMediaSuffixesAreExcluded) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
@@ -1626,7 +1201,7 @@
 TEST_F(PreviewsDeciderImplTest, IgnoreFlagDoesNotCheckBlocklist) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
+      {features::kPreviews, features::kDeferAllScriptPreviews}, {});
   InitializeUIService();
   ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_2G);
 
@@ -1634,46 +1209,44 @@
       true /* ignored */);
   PreviewsUserData user_data(kDefaultPageId);
   content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-  EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
+  navigation_handle.set_url(GURL("https://allowlisted.example.com"));
+  EXPECT_TRUE(previews_decider_impl()->ShouldCommitPreview(
+      &user_data, &navigation_handle, PreviewsType::DEFER_ALL_SCRIPT));
 
   previews_decider_impl()->AddPreviewReload();
 
-  EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
+  EXPECT_TRUE(previews_decider_impl()->ShouldCommitPreview(
+      &user_data, &navigation_handle, PreviewsType::DEFER_ALL_SCRIPT));
 }
 
 TEST_F(PreviewsDeciderImplTest, ReloadsTriggerFiveMinuteRule) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
+      {features::kPreviews, features::kDeferAllScriptPreviews}, {});
   InitializeUIService();
   ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_2G);
 
   PreviewsUserData user_data(kDefaultPageId);
   content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-  EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
+  navigation_handle.set_url(GURL("https://allowlisted.example.com"));
+  EXPECT_TRUE(previews_decider_impl()->ShouldCommitPreview(
+      &user_data, &navigation_handle, PreviewsType::DEFER_ALL_SCRIPT));
 
   previews_decider_impl()->AddPreviewNavigation(
-      GURL("http://wwww.somedomain.com"), false, PreviewsType::OFFLINE, 1);
+      GURL("http://wwww.somedomain.com"), false, PreviewsType::DEFER_ALL_SCRIPT,
+      1);
 
   previews_decider_impl()->AddPreviewReload();
 
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
+  EXPECT_FALSE(previews_decider_impl()->ShouldCommitPreview(
+      &user_data, &navigation_handle, PreviewsType::DEFER_ALL_SCRIPT));
   EXPECT_EQ(PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT,
             ui_service()->decision_reasons().back());
 
   clock_.Advance(base::TimeDelta::FromMinutes(6));
 
-  EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
-  EXPECT_THAT(
-      ui_service()->decision_passed_reasons().back(),
-      ::testing::Contains(PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT));
+  EXPECT_TRUE(previews_decider_impl()->ShouldCommitPreview(
+      &user_data, &navigation_handle, PreviewsType::DEFER_ALL_SCRIPT));
 }
 
 TEST_F(PreviewsDeciderImplTest,
@@ -1720,93 +1293,10 @@
   }
 }
 
-TEST_F(PreviewsDeciderImplTest, LogDecisionMadePageLoadNotPainful) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService(/*include_previews_opt_guide=*/true);
-  std::unique_ptr<TestPreviewsBlockList> blocklist =
-      std::make_unique<TestPreviewsBlockList>(
-          PreviewsEligibilityReason::ALLOWED, previews_decider_impl());
-  previews_decider_impl()->InjectTestBlocklist(std::move(blocklist));
-
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_4G);
-
-  auto expected_reason =
-      PreviewsEligibilityReason::PAGE_LOAD_PREDICTION_NOT_PAINFUL;
-  auto expected_type = PreviewsType::OFFLINE;
-
-  std::vector<PreviewsEligibilityReason> checked_decisions = {
-      PreviewsEligibilityReason::URL_HAS_BASIC_AUTH,
-      PreviewsEligibilityReason::EXCLUDED_BY_MEDIA_SUFFIX,
-      PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE,
-      PreviewsEligibilityReason::DEVICE_OFFLINE,
-  };
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-  previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, expected_type);
-  base::RunLoop().RunUntilIdle();
-  // Testing correct log method is called.
-  EXPECT_THAT(ui_service()->decision_reasons(),
-              ::testing::Contains(expected_reason));
-  EXPECT_THAT(ui_service()->decision_types(),
-              ::testing::Contains(expected_type));
-
-  EXPECT_EQ(1UL, ui_service()->decision_passed_reasons().size());
-  auto actual_passed_reasons = ui_service()->decision_passed_reasons()[0];
-  EXPECT_EQ(checked_decisions.size(), actual_passed_reasons.size());
-  for (size_t i = 0; i < actual_passed_reasons.size(); i++) {
-    EXPECT_EQ(checked_decisions[i], actual_passed_reasons[i]);
-  }
-}
-
-TEST_F(PreviewsDeciderImplTest, LogDecisionMadeNetworkNotSlow) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService(/*include_previews_opt_guide=*/false);
-  std::unique_ptr<TestPreviewsBlockList> blocklist =
-      std::make_unique<TestPreviewsBlockList>(
-          PreviewsEligibilityReason::ALLOWED, previews_decider_impl());
-  previews_decider_impl()->InjectTestBlocklist(std::move(blocklist));
-
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_4G);
-
-  auto expected_reason = PreviewsEligibilityReason::NETWORK_NOT_SLOW;
-  auto expected_type = PreviewsType::OFFLINE;
-
-  std::vector<PreviewsEligibilityReason> checked_decisions = {
-      PreviewsEligibilityReason::URL_HAS_BASIC_AUTH,
-      PreviewsEligibilityReason::EXCLUDED_BY_MEDIA_SUFFIX,
-      PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE,
-      PreviewsEligibilityReason::DEVICE_OFFLINE,
-  };
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-  previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, expected_type);
-  base::RunLoop().RunUntilIdle();
-  // Testing correct log method is called.
-  EXPECT_THAT(ui_service()->decision_reasons(),
-              ::testing::Contains(expected_reason));
-  EXPECT_THAT(ui_service()->decision_types(),
-              ::testing::Contains(expected_type));
-
-  EXPECT_EQ(1UL, ui_service()->decision_passed_reasons().size());
-  auto actual_passed_reasons = ui_service()->decision_passed_reasons()[0];
-  EXPECT_EQ(checked_decisions.size(), actual_passed_reasons.size());
-  for (size_t i = 0; i < actual_passed_reasons.size(); i++) {
-    EXPECT_EQ(checked_decisions[i], actual_passed_reasons[i]);
-  }
-}
-
 TEST_F(PreviewsDeciderImplTest, LogDecisionMadeReloadDisallowed) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
+      {features::kPreviews, features::kDeferAllScriptPreviews}, {});
   InitializeUIService();
   std::unique_ptr<TestPreviewsBlockList> blocklist =
       std::make_unique<TestPreviewsBlockList>(
@@ -1819,14 +1309,11 @@
   navigation_handle.set_url(GURL("https://www.google.com"));
 
   auto expected_reason = PreviewsEligibilityReason::RELOAD_DISALLOWED;
-  auto expected_type = PreviewsType::OFFLINE;
+  auto expected_type = PreviewsType::DEFER_ALL_SCRIPT;
 
   std::vector<PreviewsEligibilityReason> checked_decisions = {
       PreviewsEligibilityReason::URL_HAS_BASIC_AUTH,
       PreviewsEligibilityReason::EXCLUDED_BY_MEDIA_SUFFIX,
-      PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE,
-      PreviewsEligibilityReason::DEVICE_OFFLINE,
-      PreviewsEligibilityReason::PAGE_LOAD_PREDICTION_NOT_PAINFUL,
   };
 
   previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
@@ -1850,7 +1337,7 @@
 TEST_F(PreviewsDeciderImplTest, IgnoreBlocklistEnabledViaFlag) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
+      {features::kPreviews, features::kDeferAllScriptPreviews}, {});
   base::test::ScopedCommandLine scoped_command_line;
   base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
   command_line->AppendSwitch(switches::kIgnorePreviewsBlocklist);
@@ -1865,65 +1352,9 @@
   ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_2G);
   PreviewsUserData user_data(kDefaultPageId);
   content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-  auto expected_reason = PreviewsEligibilityReason::ALLOWED;
-  EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::OFFLINE));
-
-  base::RunLoop().RunUntilIdle();
-  EXPECT_THAT(ui_service()->decision_reasons(),
-              ::testing::Contains(expected_reason));
-}
-
-TEST_F(PreviewsDeciderImplTest, LogDecisionMadeAllowClientPreviewsWithECT) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService();
-
-  std::unique_ptr<TestPreviewsBlockList> blocklist =
-      std::make_unique<TestPreviewsBlockList>(
-          PreviewsEligibilityReason::ALLOWED, previews_decider_impl());
-
-  previews_decider_impl()->InjectTestBlocklist(std::move(blocklist));
-
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_2G);
-
-  auto expected_reason = PreviewsEligibilityReason::ALLOWED;
-  auto expected_type = PreviewsType::OFFLINE;
-
-  std::vector<PreviewsEligibilityReason> checked_decisions = {
-      PreviewsEligibilityReason::URL_HAS_BASIC_AUTH,
-      PreviewsEligibilityReason::EXCLUDED_BY_MEDIA_SUFFIX,
-      PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE,
-      PreviewsEligibilityReason::DEVICE_OFFLINE,
-      PreviewsEligibilityReason::PAGE_LOAD_PREDICTION_NOT_PAINFUL,
-      PreviewsEligibilityReason::RELOAD_DISALLOWED,
-      PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE,
-      PreviewsEligibilityReason::BLOCKLIST_DATA_NOT_LOADED,
-      PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT,
-      PreviewsEligibilityReason::USER_BLOCKLISTED,
-      PreviewsEligibilityReason::HOST_BLOCKLISTED,
-  };
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-  previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, expected_type);
-  base::RunLoop().RunUntilIdle();
-
-  // Testing correct log method is called.
-  EXPECT_THAT(ui_service()->decision_reasons(),
-              ::testing::Contains(expected_reason));
-  EXPECT_THAT(ui_service()->decision_types(),
-              ::testing::Contains(expected_type));
-
-  EXPECT_EQ(1UL, ui_service()->decision_passed_reasons().size());
-  auto actual_passed_reasons = ui_service()->decision_passed_reasons()[0];
-  EXPECT_EQ(checked_decisions.size(), actual_passed_reasons.size());
-  for (size_t i = 0; i < actual_passed_reasons.size(); i++) {
-    EXPECT_EQ(checked_decisions[i], actual_passed_reasons[i]);
-  }
+  navigation_handle.set_url(GURL("https://allowlisted.example.com"));
+  EXPECT_TRUE(previews_decider_impl()->ShouldCommitPreview(
+      &user_data, &navigation_handle, PreviewsType::DEFER_ALL_SCRIPT));
 }
 
 TEST_F(PreviewsDeciderImplTest, LogDecisionMadeAllowHintPreviewWithoutECT) {
@@ -2029,34 +1460,6 @@
   EXPECT_EQ(page_id_set.end(), page_id_set.find(0u));
 }
 
-TEST_F(PreviewsDeciderImplTest, TestIgnoreLongTermRule) {
-  // Verify that when long term rules can be ignored, and the caller is fine
-  // with ignoring long term rules, they are not checked.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {features::kPreviews, features::kOfflinePreviews}, {});
-  InitializeUIService();
-
-  std::unique_ptr<TestPreviewsBlockList> blocklist =
-      std::make_unique<TestPreviewsBlockList>(
-          PreviewsEligibilityReason::HOST_BLOCKLISTED, previews_decider_impl());
-  previews_decider_impl()->InjectTestBlocklist(std::move(blocklist));
-
-  // DataReductionProxy LitePage checks NQE on their own.
-  ReportEffectiveConnectionType(net::EFFECTIVE_CONNECTION_TYPE_3G);
-  PreviewsUserData user_data(kDefaultPageId);
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://www.google.com"));
-  base::HistogramTester histogram_tester;
-  previews_decider_impl()->SetIgnoreLongTermBlockListForServerPreviews(false);
-  EXPECT_FALSE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::LITE_PAGE));
-
-  previews_decider_impl()->SetIgnoreLongTermBlockListForServerPreviews(true);
-  EXPECT_TRUE(previews_decider_impl()->ShouldAllowPreviewAtNavigationStart(
-      &user_data, &navigation_handle, false, PreviewsType::LITE_PAGE));
-}
-
 }  // namespace
 
 }  // namespace previews
diff --git a/components/previews/content/previews_optimization_guide.cc b/components/previews/content/previews_optimization_guide.cc
index 7b6e86b8..1aef72b 100644
--- a/components/previews/content/previews_optimization_guide.cc
+++ b/components/previews/content/previews_optimization_guide.cc
@@ -168,36 +168,6 @@
   return true;
 }
 
-bool PreviewsOptimizationGuide::AreCommitTimePreviewsAvailable(
-    content::NavigationHandle* navigation_handle) {
-  // We use this method as a way of enforcing some sort of preview ordering.
-  // Thus, we check if we can potentially apply any of the client-side previews,
-  // and if any of them potentially can be applied, then we return true.
-  const std::vector<optimization_guide::proto::OptimizationType>
-      optimization_types_to_check = {
-          optimization_guide::proto::DEFER_ALL_SCRIPT,
-          optimization_guide::proto::RESOURCE_LOADING,
-          optimization_guide::proto::NOSCRIPT};
-
-  bool might_have_hint = false;
-  for (const auto optimization_type : optimization_types_to_check) {
-    // Don't check for the hint if the optimization type is not enabled.
-    if (registered_optimization_types_.find(optimization_type) ==
-        registered_optimization_types_.end()) {
-      continue;
-    }
-
-    if (optimization_guide_decider_->CanApplyOptimization(
-            navigation_handle->GetURL(), optimization_type,
-            /*optimization_metadata=*/nullptr) !=
-        optimization_guide::OptimizationGuideDecision::kFalse) {
-      might_have_hint = true;
-      break;
-    }
-  }
-  return might_have_hint;
-}
-
 bool PreviewsOptimizationGuide::GetResourceLoadingHints(
     const GURL& url,
     std::vector<std::string>* out_resource_patterns_to_block) {
diff --git a/components/previews/content/previews_optimization_guide.h b/components/previews/content/previews_optimization_guide.h
index 2ea060f..6248b29 100644
--- a/components/previews/content/previews_optimization_guide.h
+++ b/components/previews/content/previews_optimization_guide.h
@@ -47,11 +47,6 @@
                                content::NavigationHandle* navigation_handle,
                                PreviewsType type);
 
-  // Returns whether there may be commit-time preview guidance available for the
-  // URL associated with |navigation_handle|.
-  virtual bool AreCommitTimePreviewsAvailable(
-      content::NavigationHandle* navigation_handle);
-
   // Whether |url| has loaded resource loading hints and, if it does, populates
   // |out_resource_patterns_to_block| with the resource patterns to block.
   virtual bool GetResourceLoadingHints(
diff --git a/components/previews/content/previews_optimization_guide_unittest.cc b/components/previews/content/previews_optimization_guide_unittest.cc
index 494f396..fca7192 100644
--- a/components/previews/content/previews_optimization_guide_unittest.cc
+++ b/components/previews/content/previews_optimization_guide_unittest.cc
@@ -435,52 +435,4 @@
   EXPECT_FALSE(guide.ShouldShowPreview(&navigation_handle));
 }
 
-TEST_F(
-    PreviewsOptimizationGuideTest,
-    AreCommitTimePreviewsAvailableWithAtLeastOneNonFalseDecisionReturnsTrue) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {previews::features::kDeferAllScriptPreviews,
-       previews::features::kNoScriptPreviews,
-       previews::features::kResourceLoadingHints},
-      {});
-
-  PreviewsOptimizationGuide guide(optimization_guide_decider());
-  SeedOptimizationGuideDeciderWithDefaultResponses();
-
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(hint_not_loaded_url());
-
-  EXPECT_TRUE(guide.AreCommitTimePreviewsAvailable(&navigation_handle));
-}
-
-TEST_F(
-    PreviewsOptimizationGuideTest,
-    AreCommitTimePreviewsAvailableReturnsFalseIfNoClientSidePreviewsEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      {}, {previews::features::kDeferAllScriptPreviews,
-           previews::features::kNoScriptPreviews,
-           previews::features::kResourceLoadingHints});
-
-  PreviewsOptimizationGuide guide(optimization_guide_decider());
-  SeedOptimizationGuideDeciderWithDefaultResponses();
-
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(hint_not_loaded_url());
-
-  EXPECT_FALSE(guide.AreCommitTimePreviewsAvailable(&navigation_handle));
-}
-
-TEST_F(PreviewsOptimizationGuideTest,
-       AreCommitTimePreviewsAvailableWithAllFalseDecisionsReturnsFalse) {
-  PreviewsOptimizationGuide guide(optimization_guide_decider());
-  SeedOptimizationGuideDeciderWithDefaultResponses();
-
-  content::MockNavigationHandle navigation_handle;
-  navigation_handle.set_url(GURL("https://nohints.com"));
-
-  EXPECT_FALSE(guide.AreCommitTimePreviewsAvailable(&navigation_handle));
-}
-
 }  // namespace previews
diff --git a/components/previews/content/previews_ui_service.cc b/components/previews/content/previews_ui_service.cc
index 421ccc2..255aeca7 100644
--- a/components/previews/content/previews_ui_service.cc
+++ b/components/previews/content/previews_ui_service.cc
@@ -102,15 +102,6 @@
   return previews_decider_impl_.get();
 }
 
-// When triggering previews, prevent long term block list rules.
-void PreviewsUIService::SetIgnoreLongTermBlockListForServerPreviews(
-    bool ignore_long_term_block_list_rules_allowed) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  previews_decider_impl_->SetIgnoreLongTermBlockListForServerPreviews(
-      ignore_long_term_block_list_rules_allowed);
-}
-
 void PreviewsUIService::ClearBlockList(base::Time begin_time,
                                        base::Time end_time) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/components/previews/content/previews_ui_service.h b/components/previews/content/previews_ui_service.h
index 4ee1032..b7980c3f 100644
--- a/components/previews/content/previews_ui_service.h
+++ b/components/previews/content/previews_ui_service.h
@@ -120,10 +120,6 @@
   // non-null.
   PreviewsDeciderImpl* previews_decider_impl() const;
 
-  // When triggering previews, prevent long term block list rules.
-  void SetIgnoreLongTermBlockListForServerPreviews(
-      bool ignore_long_term_block_list_rules_allowed);
-
  private:
   // The decision making object for Previews triggering. Guaranteed to be
   // non-null.
diff --git a/components/previews/content/previews_ui_service_unittest.cc b/components/previews/content/previews_ui_service_unittest.cc
index 4066d78..4f28311 100644
--- a/components/previews/content/previews_ui_service_unittest.cc
+++ b/components/previews/content/previews_ui_service_unittest.cc
@@ -219,7 +219,7 @@
 
 TEST_F(PreviewsUIServiceTest, TestLogPreviewNavigationPassInCorrectParams) {
   const GURL url_a = GURL("http://www.url_a.com/url_a");
-  const PreviewsType type_a = PreviewsType::LITE_PAGE;
+  const PreviewsType type_a = PreviewsType::DEFER_ALL_SCRIPT;
   const bool opt_out_a = true;
   const base::Time time_a = base::Time::Now();
   const uint64_t page_id_a = 1234;
@@ -234,7 +234,7 @@
   EXPECT_EQ(page_id_a, logger_ptr_->navigation_page_id());
 
   const GURL url_b = GURL("http://www.url_b.com/url_b");
-  const PreviewsType type_b = PreviewsType::OFFLINE;
+  const PreviewsType type_b = PreviewsType::DEFER_ALL_SCRIPT;
   const bool opt_out_b = false;
   const base::Time time_b = base::Time::Now();
   const uint64_t page_id_b = 4321;
@@ -254,7 +254,7 @@
       PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE;
   const GURL url_a("http://www.url_a.com/url_a");
   const base::Time time_a = base::Time::Now();
-  PreviewsType type_a = PreviewsType::OFFLINE;
+  PreviewsType type_a = PreviewsType::DEFER_ALL_SCRIPT;
   std::vector<PreviewsEligibilityReason> passed_reasons_a = {
       PreviewsEligibilityReason::NETWORK_NOT_SLOW,
       PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT,
@@ -284,7 +284,7 @@
       PreviewsEligibilityReason::NETWORK_NOT_SLOW;
   const GURL url_b("http://www.url_b.com/url_b");
   const base::Time time_b = base::Time::Now();
-  PreviewsType type_b = PreviewsType::OFFLINE;
+  PreviewsType type_b = PreviewsType::DEFER_ALL_SCRIPT;
   std::vector<PreviewsEligibilityReason> passed_reasons_b = {
       PreviewsEligibilityReason::NOT_ALLOWED_BY_OPTIMIZATION_GUIDE,
       PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE,
diff --git a/components/previews/content/previews_user_data.cc b/components/previews/content/previews_user_data.cc
index 7730f58..0df6525 100644
--- a/components/previews/content/previews_user_data.cc
+++ b/components/previews/content/previews_user_data.cc
@@ -24,7 +24,6 @@
       data_savings_inflation_percent_(other.data_savings_inflation_percent_),
       cache_control_no_transform_directive_(
           other.cache_control_no_transform_directive_),
-      offline_preview_used_(other.offline_preview_used_),
       block_listed_for_lite_page_(other.block_listed_for_lite_page_),
       committed_previews_type_without_holdback_(
           other.committed_previews_type_without_holdback_),
diff --git a/components/previews/content/previews_user_data.h b/components/previews/content/previews_user_data.h
index d6e46cb..c2c6302 100644
--- a/components/previews/content/previews_user_data.h
+++ b/components/previews/content/previews_user_data.h
@@ -121,12 +121,6 @@
   // Sets the committed previews type for testing. Can be called multiple times.
   void SetCommittedPreviewsTypeForTesting(previews::PreviewsType previews_type);
 
-  bool offline_preview_used() const { return offline_preview_used_; }
-  // Whether an offline preview is being served.
-  void set_offline_preview_used(bool offline_preview_used) {
-    offline_preview_used_ = offline_preview_used;
-  }
-
   // The PreviewsState that was allowed for the navigation. This should be used
   // for metrics only since it does not respect the coin flip holdback.
   content::PreviewsState PreHoldbackAllowedPreviewsState() const;
@@ -211,9 +205,6 @@
   // Whether the origin provided a no-transform directive.
   bool cache_control_no_transform_directive_ = false;
 
-  // Whether an offline preview is being served.
-  bool offline_preview_used_ = false;
-
   // Whether a lite page preview was prevented from being shown due to the
   // blocklist.
   bool block_listed_for_lite_page_ = false;
diff --git a/components/previews/content/previews_user_data_unittest.cc b/components/previews/content/previews_user_data_unittest.cc
index 4dfda8c5e..2ff9e33 100644
--- a/components/previews/content/previews_user_data_unittest.cc
+++ b/components/previews/content/previews_user_data_unittest.cc
@@ -20,7 +20,7 @@
 TEST(PreviewsUserDataTest, TestSetEligibilityReason) {
   PreviewsUserData data(1u);
   EXPECT_EQ(base::nullopt,
-            data.EligibilityReasonForPreview(PreviewsType::OFFLINE));
+            data.EligibilityReasonForPreview(PreviewsType::DEFER_ALL_SCRIPT));
 
   data.SetEligibilityReasonForPreview(
       PreviewsType::NOSCRIPT, PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE);
@@ -29,7 +29,7 @@
       PreviewsEligibilityReason::BLOCKLIST_DATA_NOT_LOADED);
 
   EXPECT_EQ(base::nullopt,
-            data.EligibilityReasonForPreview(PreviewsType::OFFLINE));
+            data.EligibilityReasonForPreview(PreviewsType::DEFER_ALL_SCRIPT));
   EXPECT_EQ(PreviewsEligibilityReason::BLOCKLIST_DATA_NOT_LOADED,
             data.EligibilityReasonForPreview(PreviewsType::NOSCRIPT));
 }
@@ -44,12 +44,10 @@
   EXPECT_FALSE(data->cache_control_no_transform_directive());
   EXPECT_EQ(previews::PreviewsType::NONE, data->CommittedPreviewsType());
   EXPECT_FALSE(data->block_listed_for_lite_page());
-  EXPECT_FALSE(data->offline_preview_used());
 
   data->set_data_savings_inflation_percent(123);
   data->set_cache_control_no_transform_directive();
   data->SetCommittedPreviewsType(previews::PreviewsType::NOSCRIPT);
-  data->set_offline_preview_used(true);
   data->set_block_listed_for_lite_page(true);
 
   PreviewsUserData data_copy(*data);
@@ -60,7 +58,6 @@
   EXPECT_EQ(previews::PreviewsType::NOSCRIPT,
             data_copy.CommittedPreviewsType());
   EXPECT_TRUE(data_copy.block_listed_for_lite_page());
-  EXPECT_TRUE(data_copy.offline_preview_used());
 }
 
 TEST(PreviewsUserDataTest, TestCoinFlip_HasCommittedPreviewsType) {
diff --git a/components/previews/core/previews_block_list.cc b/components/previews/core/previews_block_list.cc
index 3aba7ae..426c721 100644
--- a/components/previews/core/previews_block_list.cc
+++ b/components/previews/core/previews_block_list.cc
@@ -112,15 +112,13 @@
 PreviewsEligibilityReason PreviewsBlockList::IsLoadedAndAllowed(
     const GURL& url,
     PreviewsType type,
-    bool ignore_long_term_block_list_rules,
     std::vector<PreviewsEligibilityReason>* passed_reasons) const {
   DCHECK(url.has_host());
 
   std::vector<blocklist::BlocklistReason> passed_blocklist_reasons;
   blocklist::BlocklistReason reason =
       blocklist::OptOutBlocklist::IsLoadedAndAllowed(
-          url.host(), static_cast<int>(type), ignore_long_term_block_list_rules,
-          &passed_blocklist_reasons);
+          url.host(), static_cast<int>(type), false, &passed_blocklist_reasons);
   for (auto passed_reason : passed_blocklist_reasons) {
     passed_reasons->push_back(BlocklistReasonToPreviewsReason(passed_reason));
   }
diff --git a/components/previews/core/previews_block_list.h b/components/previews/core/previews_block_list.h
index 84b184c..53e2a1cd 100644
--- a/components/previews/core/previews_block_list.h
+++ b/components/previews/core/previews_block_list.h
@@ -131,7 +131,6 @@
   virtual PreviewsEligibilityReason IsLoadedAndAllowed(
       const GURL& url,
       PreviewsType type,
-      bool ignore_long_term_block_list_rules,
       std::vector<PreviewsEligibilityReason>* passed_reasons) const;
 
  protected:
diff --git a/components/previews/core/previews_block_list_unittest.cc b/components/previews/core/previews_block_list_unittest.cc
index eb46c01..85cbcb59 100644
--- a/components/previews/core/previews_block_list_unittest.cc
+++ b/components/previews/core/previews_block_list_unittest.cc
@@ -104,7 +104,7 @@
     }
 
     blocklist::BlocklistData::AllowedTypesAndVersions allowed_types;
-    allowed_types[static_cast<int>(PreviewsType::OFFLINE)] = 0;
+    allowed_types[static_cast<int>(PreviewsType::DEFER_ALL_SCRIPT)] = 0;
     block_list_ = std::make_unique<TestPreviewsBlockList>(
         nullptr, &test_clock_, &blocklist_delegate_, std::move(allowed_types));
 
@@ -177,13 +177,13 @@
 
   StartTest();
 
-  block_list_->AddPreviewNavigation(url, false, PreviewsType::OFFLINE);
-  histogram_tester.ExpectUniqueSample("Previews.OptOut.UserOptedOut.Offline", 0,
-                                      1);
+  block_list_->AddPreviewNavigation(url, false, PreviewsType::DEFER_ALL_SCRIPT);
+  histogram_tester.ExpectUniqueSample(
+      "Previews.OptOut.UserOptedOut.DeferAllScript", 0, 1);
   histogram_tester.ExpectUniqueSample("Previews.OptOut.UserOptedOut", 0, 1);
-  block_list_->AddPreviewNavigation(url, true, PreviewsType::OFFLINE);
-  histogram_tester.ExpectBucketCount("Previews.OptOut.UserOptedOut.Offline", 1,
-                                     1);
+  block_list_->AddPreviewNavigation(url, true, PreviewsType::DEFER_ALL_SCRIPT);
+  histogram_tester.ExpectBucketCount(
+      "Previews.OptOut.UserOptedOut.DeferAllScript", 1, 1);
   histogram_tester.ExpectBucketCount("Previews.OptOut.UserOptedOut", 1, 1);
 }
 
diff --git a/components/previews/core/previews_experiments.cc b/components/previews/core/previews_experiments.cc
index baabd1d..0911294b 100644
--- a/components/previews/core/previews_experiments.cc
+++ b/components/previews/core/previews_experiments.cc
@@ -177,24 +177,13 @@
                          "single_opt_out_duration_in_seconds", 60 * 5));
 }
 
-base::TimeDelta OfflinePreviewFreshnessDuration() {
-  return base::TimeDelta::FromDays(
-      GetParamValueAsInt(kClientSidePreviewsFieldTrial,
-                         "offline_preview_freshness_duration_in_days", 7));
-}
-
 net::EffectiveConnectionType GetECTThresholdForPreview(
     previews::PreviewsType type) {
   switch (type) {
-    case PreviewsType::OFFLINE:
-      return GetParamValueAsECTByFeature(features::kOfflinePreviews,
-                                         kEffectiveConnectionTypeThreshold,
-                                         net::EFFECTIVE_CONNECTION_TYPE_2G);
     case PreviewsType::NOSCRIPT:
       return GetParamValueAsECTByFeature(features::kNoScriptPreviews,
                                          kEffectiveConnectionTypeThreshold,
                                          net::EFFECTIVE_CONNECTION_TYPE_2G);
-    case PreviewsType::LITE_PAGE:
       NOTREACHED();
       break;
     case PreviewsType::NONE:
@@ -209,7 +198,9 @@
                                          net::EFFECTIVE_CONNECTION_TYPE_2G);
     case PreviewsType::DEPRECATED_AMP_REDIRECTION:
     case PreviewsType::DEPRECATED_LOFI:
+    case PreviewsType::DEPRECATED_LITE_PAGE:
     case PreviewsType::DEPRECATED_LITE_PAGE_REDIRECT:
+    case PreviewsType::DEPRECATED_OFFLINE:
     case PreviewsType::LAST:
       break;
   }
@@ -227,10 +218,6 @@
   return base::FeatureList::IsEnabled(features::kPreviews);
 }
 
-bool IsOfflinePreviewsEnabled() {
-  return base::FeatureList::IsEnabled(features::kOfflinePreviews);
-}
-
 bool IsNoScriptPreviewsEnabled() {
   if (base::FeatureList::IsEnabled(features::kEligibleForUserConsistentStudy) &&
       base::FeatureList::IsEnabled(
@@ -264,10 +251,6 @@
   return base::FeatureList::IsEnabled(features::kDeferAllScriptPreviews);
 }
 
-int OfflinePreviewsVersion() {
-  return GetParamValueAsInt(kClientSidePreviewsFieldTrial, kVersion, 0);
-}
-
 int NoScriptPreviewsVersion() {
   return GetFieldTrialParamByFeatureAsInt(GetNoScriptPreviewsFeature(),
                                           kVersion, 0);
@@ -369,10 +352,6 @@
   switch (type) {
     case PreviewsType::NONE:
       return "None";
-    case PreviewsType::OFFLINE:
-      return "Offline";
-    case PreviewsType::LITE_PAGE:
-      return "LitePage";
     case PreviewsType::NOSCRIPT:
       return "NoScript";
     case PreviewsType::UNSPECIFIED:
@@ -381,9 +360,11 @@
       return "ResourceLoadingHints";
     case PreviewsType::DEFER_ALL_SCRIPT:
       return "DeferAllScript";
-    case PreviewsType::DEPRECATED_LITE_PAGE_REDIRECT:
     case PreviewsType::DEPRECATED_AMP_REDIRECTION:
+    case PreviewsType::DEPRECATED_LITE_PAGE:
+    case PreviewsType::DEPRECATED_LITE_PAGE_REDIRECT:
     case PreviewsType::DEPRECATED_LOFI:
+    case PreviewsType::DEPRECATED_OFFLINE:
     case PreviewsType::LAST:
       break;
   }
diff --git a/components/previews/core/previews_experiments.h b/components/previews/core/previews_experiments.h
index 7c461a1..41070fb 100644
--- a/components/previews/core/previews_experiments.h
+++ b/components/previews/core/previews_experiments.h
@@ -21,14 +21,16 @@
   // Used to indicate that there is no preview type.
   NONE = 0,
 
-  // The user is shown an offline page as a preview.
-  OFFLINE = 1,
+  // The user is shown an offline page as a preview. Deprecated, and should not
+  // be used.
+  DEPRECATED_OFFLINE = 1,
 
   // Replace images with placeholders. Deprecated, and should not be used.
   DEPRECATED_LOFI = 2,
 
-  // The user is shown a server lite page.
-  LITE_PAGE = 3,
+  // The user is shown a server lite page. Deprecated, and should not
+  // be used.
+  DEPRECATED_LITE_PAGE = 3,
 
   // AMP version of the page is shown as a preview. Deprecated, and should not
   // be used.
@@ -104,10 +106,6 @@
 // The amount of time after any opt out that no previews should be shown.
 base::TimeDelta SingleOptOutDuration();
 
-// The amount of time that an offline page is considered fresh enough to be
-// shown as a preview.
-base::TimeDelta OfflinePreviewFreshnessDuration();
-
 // The default EffectiveConnectionType threshold where preview |type| will be
 // triggered.
 net::EffectiveConnectionType GetECTThresholdForPreview(
@@ -123,13 +121,11 @@
 bool ArePreviewsAllowed();
 
 // Whether the preview type is enabled.
-bool IsOfflinePreviewsEnabled();
 bool IsNoScriptPreviewsEnabled();
 bool IsResourceLoadingHintsEnabled();
 bool IsDeferAllScriptPreviewsEnabled();
 
 // The blocklist version for each preview type.
-int OfflinePreviewsVersion();
 int NoScriptPreviewsVersion();
 int ResourceLoadingHintsVersion();
 int DeferAllScriptPreviewsVersion();
diff --git a/components/previews/core/previews_experiments_unittest.cc b/components/previews/core/previews_experiments_unittest.cc
index 99a89906..4350c3f 100644
--- a/components/previews/core/previews_experiments_unittest.cc
+++ b/components/previews/core/previews_experiments_unittest.cc
@@ -29,8 +29,8 @@
 const char kEnabled[] = "Enabled";
 
 // Verifies that the default params are correct, and that custom params can be
-// set, for both the previews blocklist and offline previews.
-TEST(PreviewsExperimentsTest, TestParamsForBlockListAndOffline) {
+// set,
+TEST(PreviewsExperimentsTest, TestParams) {
   // Verify that the default params are correct.
   EXPECT_EQ(4u, params::MaxStoredHistoryLengthForPerHostBlockList());
   EXPECT_EQ(10u, params::MaxStoredHistoryLengthForHostIndifferentBlockList());
@@ -42,13 +42,8 @@
             params::HostIndifferentBlockListPerHostDuration());
   EXPECT_EQ(base::TimeDelta::FromSeconds(60 * 5),
             params::SingleOptOutDuration());
-  EXPECT_EQ(base::TimeDelta::FromDays(7),
-            params::OfflinePreviewFreshnessDuration());
-  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
-            params::GetECTThresholdForPreview(PreviewsType::OFFLINE));
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
             params::GetECTThresholdForPreview(PreviewsType::NOSCRIPT));
-  EXPECT_EQ(0, params::OfflinePreviewsVersion());
 
   // Set some custom params. Somewhat random yet valid values.
   // TODO(crbug.com/1092102) : Migrate blacklist names to blocklist.
@@ -61,7 +56,6 @@
       {"per_host_black_list_duration_in_days", "99"},
       {"host_indifferent_black_list_duration_in_days", "64"},
       {"single_opt_out_duration_in_seconds", "28"},
-      {"offline_preview_freshness_duration_in_days", "12"},
       {"max_allowed_effective_connection_type", "4G"},
       {"version", "10"},
   };
@@ -79,13 +73,8 @@
   EXPECT_EQ(base::TimeDelta::FromDays(64),
             params::HostIndifferentBlockListPerHostDuration());
   EXPECT_EQ(base::TimeDelta::FromSeconds(28), params::SingleOptOutDuration());
-  EXPECT_EQ(base::TimeDelta::FromDays(12),
-            params::OfflinePreviewFreshnessDuration());
-  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
-            params::GetECTThresholdForPreview(PreviewsType::OFFLINE));
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
             params::GetECTThresholdForPreview(PreviewsType::NOSCRIPT));
-  EXPECT_EQ(10, params::OfflinePreviewsVersion());
 
   variations::testing::ClearAllVariationParams();
 }
diff --git a/components/previews/core/previews_logger_unittest.cc b/components/previews/core/previews_logger_unittest.cc
index 569d35c3..33113596 100644
--- a/components/previews/core/previews_logger_unittest.cc
+++ b/components/previews/core/previews_logger_unittest.cc
@@ -118,7 +118,7 @@
       PreviewsEligibilityReason reason,
       bool final_reason) {
     const base::Time time = base::Time::Now();
-    PreviewsType type = PreviewsType::OFFLINE;
+    PreviewsType type = PreviewsType::DEFER_ALL_SCRIPT;
     const GURL url("http://www.url_a.com/url");
     const uint64_t page_id = 1234;
     TestPreviewsLoggerObserver observer;
@@ -152,8 +152,7 @@
 TEST_F(PreviewsLoggerTest, LogPreviewDecisionMadeLogMessage) {
   const base::Time time = base::Time::Now();
 
-  PreviewsType type_a = PreviewsType::OFFLINE;
-  PreviewsType type_b = PreviewsType::LITE_PAGE;
+  PreviewsType type_a = PreviewsType::DEFER_ALL_SCRIPT;
   PreviewsEligibilityReason reason_a =
       PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE;
   std::vector<PreviewsEligibilityReason> passed_reasons_a = {};
@@ -173,7 +172,7 @@
 
   logger_->LogPreviewDecisionMade(reason_a, url_a, time, type_a,
                                   std::move(passed_reasons_a), page_id_a);
-  logger_->LogPreviewDecisionMade(reason_b, url_b, time, type_b,
+  logger_->LogPreviewDecisionMade(reason_b, url_b, time, type_a,
                                   std::move(passed_reasons_b), page_id_b);
 
   auto actual = observer.messages();
@@ -181,7 +180,7 @@
   EXPECT_EQ(expected_size, actual.size());
 
   std::string expected_description_a =
-      "Offline preview - Blocklist failed to be created";
+      "DeferAllScript preview - Blocklist failed to be created";
   EXPECT_EQ(kPreviewsDecisionMadeEventType, actual[0].event_type);
   EXPECT_EQ(expected_description_a, actual[0].event_description);
   EXPECT_EQ(url_a, actual[0].url);
@@ -189,21 +188,23 @@
   EXPECT_EQ(page_id_a, actual[0].page_id);
 
   std::string expected_passed_0 =
-      "LitePage preview - Network quality available";
+      "DeferAllScript preview - Network quality available";
   EXPECT_EQ(kPreviewsDecisionMadeEventType, actual[1].event_type);
   EXPECT_EQ(expected_passed_0, actual[1].event_description);
   EXPECT_EQ(url_b, actual[1].url);
   EXPECT_EQ(time, actual[1].time);
   EXPECT_EQ(page_id_b, actual[1].page_id);
 
-  std::string expected_passed_1 = "LitePage preview - Page reloads allowed";
+  std::string expected_passed_1 =
+      "DeferAllScript preview - Page reloads allowed";
   EXPECT_EQ(kPreviewsDecisionMadeEventType, actual[2].event_type);
   EXPECT_EQ(expected_passed_1, actual[2].event_description);
   EXPECT_EQ(url_b, actual[2].url);
   EXPECT_EQ(time, actual[2].time);
   EXPECT_EQ(page_id_b, actual[2].page_id);
 
-  std::string expected_description_b = "LitePage preview - Network not slow";
+  std::string expected_description_b =
+      "DeferAllScript preview - Network not slow";
   EXPECT_EQ(kPreviewsDecisionMadeEventType, actual[3].event_type);
   EXPECT_EQ(expected_description_b, actual[3].event_description);
   EXPECT_EQ(url_b, actual[3].url);
@@ -214,8 +215,7 @@
 TEST_F(PreviewsLoggerTest, LogPreviewNavigationLogMessage) {
   const base::Time time = base::Time::Now();
 
-  PreviewsType type_a = PreviewsType::OFFLINE;
-  PreviewsType type_b = PreviewsType::LITE_PAGE;
+  PreviewsType type_a = PreviewsType::DEFER_ALL_SCRIPT;
   const GURL url_a("http://www.url_a.com/url_a");
   const GURL url_b("http://www.url_b.com/url_b");
   const uint64_t page_id_a = 1234;
@@ -226,7 +226,7 @@
 
   logger_->LogPreviewNavigation(url_a, type_a, true /* opt_out */, time,
                                 page_id_a);
-  logger_->LogPreviewNavigation(url_b, type_b, false /* opt_out */, time,
+  logger_->LogPreviewNavigation(url_b, type_a, false /* opt_out */, time,
                                 page_id_b);
 
   auto actual = observer.messages();
@@ -234,14 +234,16 @@
   const size_t expected_size = 2;
   EXPECT_EQ(expected_size, actual.size());
 
-  std::string expected_description_a = "Offline preview - user opt-out: True";
+  std::string expected_description_a =
+      "DeferAllScript preview - user opt-out: True";
   EXPECT_EQ(kPreviewsNavigationEventType, actual[0].event_type);
   EXPECT_EQ(expected_description_a, actual[0].event_description);
   EXPECT_EQ(url_a, actual[0].url);
   EXPECT_EQ(time, actual[0].time);
   EXPECT_EQ(page_id_a, actual[0].page_id);
 
-  std::string expected_description_b = "LitePage preview - user opt-out: False";
+  std::string expected_description_b =
+      "DeferAllScript preview - user opt-out: False";
   EXPECT_EQ(kPreviewsNavigationEventType, actual[1].event_type);
   EXPECT_EQ(expected_description_b, actual[1].event_description);
   EXPECT_EQ(url_b, actual[1].url);
@@ -250,7 +252,7 @@
 }
 
 TEST_F(PreviewsLoggerTest, PreviewsLoggerOnlyKeepsCertainNumberOfDecisionLogs) {
-  PreviewsType type = PreviewsType::OFFLINE;
+  PreviewsType type = PreviewsType::DEFER_ALL_SCRIPT;
   PreviewsEligibilityReason reason =
       PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE;
   const base::Time time = base::Time::Now();
@@ -270,7 +272,7 @@
 
 TEST_F(PreviewsLoggerTest,
        PreviewsLoggerOnlyKeepsCertainNumberOfNavigationLogs) {
-  PreviewsType type = PreviewsType::OFFLINE;
+  PreviewsType type = PreviewsType::DEFER_ALL_SCRIPT;
   const GURL url("http://www.url_.com/url_");
   const base::Time time = base::Time::Now();
   const uint64_t page_id = 1234;
@@ -291,7 +293,7 @@
                       GURL("http://www.url_.com/url_"), base::Time::Now(),
                       1234 /* page_id */);
 
-  PreviewsType type = PreviewsType::OFFLINE;
+  PreviewsType type = PreviewsType::DEFER_ALL_SCRIPT;
   PreviewsEligibilityReason final_reason =
       PreviewsEligibilityReason::BLOCKLIST_UNAVAILABLE;
   std::vector<PreviewsEligibilityReason> passed_reasons = {
diff --git a/components/safe_search_api/safe_search/safe_search_url_checker_client.cc b/components/safe_search_api/safe_search/safe_search_url_checker_client.cc
index ce6cb49..a48bf39 100644
--- a/components/safe_search_api/safe_search/safe_search_url_checker_client.cc
+++ b/components/safe_search_api/safe_search/safe_search_url_checker_client.cc
@@ -19,7 +19,6 @@
 #include "components/google/core/common/google_util.h"
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
-#include "net/url_request/url_request_status.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
diff --git a/components/security_interstitials/content/ssl_error_handler_unittest.cc b/components/security_interstitials/content/ssl_error_handler_unittest.cc
index 65e26fd0..555c88e8 100644
--- a/components/security_interstitials/content/ssl_error_handler_unittest.cc
+++ b/components/security_interstitials/content/ssl_error_handler_unittest.cc
@@ -45,7 +45,6 @@
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/test/test_certificate_data.h"
 #include "net/test/test_data_directory.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/network/test/test_shared_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
index c619d13..57325bc 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeImpl.java
@@ -7,7 +7,6 @@
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AuthenticatorDescription;
-import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -335,7 +334,6 @@
         new UpdateAccountRestrictionPatternsTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
     }
 
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     private void subscribeToAppRestrictionChanges() {
         IntentFilter filter = new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
         BroadcastReceiver receiver = new BroadcastReceiver() {
@@ -386,7 +384,6 @@
         }
     }
 
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
     private static String[] getAccountRestrictionPatternPostJellyBeanMr2() {
         // This method uses AppRestrictions directly, rather than using the Policy interface,
         // because it must be callable in contexts in which the native library hasn't been loaded.
diff --git a/components/signin/core/browser/signin_header_helper.cc b/components/signin/core/browser/signin_header_helper.cc
index acdd4d4a..34b1ebd 100644
--- a/components/signin/core/browser/signin_header_helper.cc
+++ b/components/signin/core/browser/signin_header_helper.cc
@@ -15,7 +15,6 @@
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "net/base/escape.h"
 #include "net/http/http_request_headers.h"
-#include "net/url_request/url_request.h"
 
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
 #include "components/signin/core/browser/dice_header_helper.h"
diff --git a/components/suggestions/suggestions_service_impl.cc b/components/suggestions/suggestions_service_impl.cc
index 329de32..c34399f 100644
--- a/components/suggestions/suggestions_service_impl.cc
+++ b/components/suggestions/suggestions_service_impl.cc
@@ -35,8 +35,6 @@
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_status.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
diff --git a/components/sync/engine/net/http_bridge_unittest.cc b/components/sync/engine/net/http_bridge_unittest.cc
index 4bea334..0270226b 100644
--- a/components/sync/engine/net/http_bridge_unittest.cc
+++ b/components/sync/engine/net/http_bridge_unittest.cc
@@ -22,7 +22,6 @@
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/network/test/test_shared_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/zlib/google/compression_utils.h"
diff --git a/components/translate/core/browser/translate_download_manager.h b/components/translate/core/browser/translate_download_manager.h
index f3834d1..f4950f2 100644
--- a/components/translate/core/browser/translate_download_manager.h
+++ b/components/translate/core/browser/translate_download_manager.h
@@ -12,7 +12,6 @@
 #include "base/sequence_checker.h"
 #include "components/translate/core/browser/translate_language_list.h"
 #include "components/translate/core/browser/translate_script.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace base {
diff --git a/components/user_manager/user_manager_base.cc b/components/user_manager/user_manager_base.cc
index 8b9ddabf..5e09ae11 100644
--- a/components/user_manager/user_manager_base.cc
+++ b/components/user_manager/user_manager_base.cc
@@ -1001,24 +1001,19 @@
 void UserManagerBase::RemoveNonCryptohomeData(const AccountId& account_id) {
   PrefService* prefs = GetLocalState();
   DictionaryPrefUpdate prefs_display_name_update(prefs, kUserDisplayName);
-  prefs_display_name_update->RemoveWithoutPathExpansion(
-      account_id.GetUserEmail(), nullptr);
+  prefs_display_name_update->RemoveKey(account_id.GetUserEmail());
 
   DictionaryPrefUpdate prefs_given_name_update(prefs, kUserGivenName);
-  prefs_given_name_update->RemoveWithoutPathExpansion(account_id.GetUserEmail(),
-                                                      nullptr);
+  prefs_given_name_update->RemoveKey(account_id.GetUserEmail());
 
   DictionaryPrefUpdate prefs_display_email_update(prefs, kUserDisplayEmail);
-  prefs_display_email_update->RemoveWithoutPathExpansion(
-      account_id.GetUserEmail(), nullptr);
+  prefs_display_email_update->RemoveKey(account_id.GetUserEmail());
 
   DictionaryPrefUpdate prefs_oauth_update(prefs, kUserOAuthTokenStatus);
-  prefs_oauth_update->RemoveWithoutPathExpansion(account_id.GetUserEmail(),
-                                                 nullptr);
+  prefs_oauth_update->RemoveKey(account_id.GetUserEmail());
 
   DictionaryPrefUpdate prefs_force_online_update(prefs, kUserForceOnlineSignin);
-  prefs_force_online_update->RemoveWithoutPathExpansion(
-      account_id.GetUserEmail(), nullptr);
+  prefs_force_online_update->RemoveKey(account_id.GetUserEmail());
 
   known_user::RemovePrefs(account_id);
 
diff --git a/content/browser/appcache/appcache_host.cc b/content/browser/appcache/appcache_host.cc
index 91d1cc0..2c3ecbe 100644
--- a/content/browser/appcache/appcache_host.cc
+++ b/content/browser/appcache/appcache_host.cc
@@ -24,7 +24,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/url_constants.h"
-#include "net/url_request/url_request.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
diff --git a/content/browser/appcache/appcache_host_unittest.cc b/content/browser/appcache/appcache_host_unittest.cc
index cb357740..1710931 100644
--- a/content/browser/appcache/appcache_host_unittest.cc
+++ b/content/browser/appcache/appcache_host_unittest.cc
@@ -27,7 +27,6 @@
 #include "content/test/test_web_contents.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/test_support/test_utils.h"
-#include "net/url_request/url_request.h"
 #include "storage/browser/quota/quota_client_type.h"
 #include "storage/browser/quota/quota_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/browser/appcache/appcache_request.cc b/content/browser/appcache/appcache_request.cc
index a19a46c..25a6739 100644
--- a/content/browser/appcache/appcache_request.cc
+++ b/content/browser/appcache/appcache_request.cc
@@ -8,7 +8,6 @@
 #include "net/base/isolation_info.h"
 #include "net/url_request/redirect_info.h"
 #include "net/url_request/redirect_util.h"
-#include "net/url_request/url_request.h"
 #include "url/origin.h"
 
 namespace content {
diff --git a/content/browser/appcache/appcache_subresource_url_factory.cc b/content/browser/appcache/appcache_subresource_url_factory.cc
index 29e1451..b621303 100644
--- a/content/browser/appcache/appcache_subresource_url_factory.cc
+++ b/content/browser/appcache/appcache_subresource_url_factory.cc
@@ -22,7 +22,6 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_request.h"
 #include "services/network/public/cpp/request_mode.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
diff --git a/content/browser/appcache/appcache_update_job.h b/content/browser/appcache/appcache_update_job.h
index 9909165..c0c2fd4 100644
--- a/content/browser/appcache/appcache_update_job.h
+++ b/content/browser/appcache/appcache_update_job.h
@@ -30,10 +30,13 @@
 #include "content/common/appcache_interfaces.h"
 #include "content/common/content_export.h"
 #include "net/http/http_response_headers.h"
-#include "net/url_request/url_request.h"
 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
 #include "url/gurl.h"
 
+namespace net {
+class IOBuffer;
+}
+
 namespace content {
 FORWARD_DECLARE_TEST(AppCacheGroupTest, QueueUpdate);
 class AppCacheGroupTest;
diff --git a/content/browser/appcache/appcache_update_url_loader_request.cc b/content/browser/appcache/appcache_update_url_loader_request.cc
index bd69591..395580e 100644
--- a/content/browser/appcache/appcache_update_url_loader_request.cc
+++ b/content/browser/appcache/appcache_update_url_loader_request.cc
@@ -10,7 +10,6 @@
 #include "content/browser/storage_partition_impl.h"
 #include "net/base/ip_endpoint.h"
 #include "net/http/http_response_info.h"
-#include "net/url_request/url_request_context.h"
 
 namespace content {
 
diff --git a/content/browser/appcache/chrome_appcache_service_unittest.cc b/content/browser/appcache/chrome_appcache_service_unittest.cc
index 7b52d38..82bca20d 100644
--- a/content/browser/appcache/chrome_appcache_service_unittest.cc
+++ b/content/browser/appcache/chrome_appcache_service_unittest.cc
@@ -22,7 +22,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/test/mock_special_storage_policy.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc
index e15d6a96..6dd0a31 100644
--- a/content/browser/background_fetch/background_fetch_context.cc
+++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -23,7 +23,6 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/web_contents.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 
diff --git a/content/browser/blob_storage/blob_url_unittest.cc b/content/browser/blob_storage/blob_url_unittest.cc
index a64a3c50..a53604d 100644
--- a/content/browser/blob_storage/blob_url_unittest.cc
+++ b/content/browser/blob_storage/blob_url_unittest.cc
@@ -28,7 +28,6 @@
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_request.h"
 #include "services/network/test/test_url_loader_client.h"
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_data_handle.h"
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index 13e7859..992a0bc 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -61,8 +61,6 @@
 #include "media/learning/common/media_learning_tasks.h"
 #include "media/learning/impl/learning_session_impl.h"
 #include "media/mojo/services/video_decode_perf_history.h"
-#include "net/cookies/cookie_store.h"
-#include "net/url_request/url_request_context.h"
 #include "services/content/service.h"
 #include "services/network/public/cpp/features.h"
 #include "storage/browser/blob/blob_storage_context.h"
diff --git a/content/browser/browser_process_sub_thread.cc b/content/browser/browser_process_sub_thread.cc
index d4db78e..a3aa1f0 100644
--- a/content/browser/browser_process_sub_thread.cc
+++ b/content/browser/browser_process_sub_thread.cc
@@ -20,7 +20,6 @@
 #include "content/public/browser/browser_child_process_host_iterator.h"
 #include "content/public/common/process_type.h"
 #include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/jni_android.h"
diff --git a/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc b/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
index 1211d57c..b87880d 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
@@ -51,8 +51,6 @@
 #include "net/http/http_network_session.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/ssl/ssl_client_cert_type.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "services/network/cookie_manager.h"
 #include "services/network/public/cpp/features.h"
diff --git a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
index 9040ed0..a330dce 100644
--- a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
+++ b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
@@ -43,8 +43,6 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/quota/quota_settings.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/public/common/features.h"
diff --git a/content/browser/browsing_data/clear_site_data_handler_unittest.cc b/content/browser/browsing_data/clear_site_data_handler_unittest.cc
index 59aaab464..80fe7fa 100644
--- a/content/browser/browsing_data/clear_site_data_handler_unittest.cc
+++ b/content/browser/browsing_data/clear_site_data_handler_unittest.cc
@@ -19,7 +19,6 @@
 #include "net/http/http_util.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/redirect_info.h"
-#include "net/url_request/url_request_job.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc b/content/browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc
index a1b501f..b2e36c2 100644
--- a/content/browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc
+++ b/content/browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc
@@ -28,8 +28,6 @@
 #include "net/disk_cache/disk_cache.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/http/http_cache.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 
 namespace content {
 
diff --git a/content/browser/browsing_data/same_site_data_remover_impl_unittest.cc b/content/browser/browsing_data/same_site_data_remover_impl_unittest.cc
index 33d6f4e..c43cffac 100644
--- a/content/browser/browsing_data/same_site_data_remover_impl_unittest.cc
+++ b/content/browser/browsing_data/same_site_data_remover_impl_unittest.cc
@@ -20,7 +20,6 @@
 #include "net/cookies/cookie_access_result.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/cookies/cookie_util.h"
-#include "net/url_request/url_request_context.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "storage/browser/test/mock_special_storage_policy.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc b/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
index 0926ea9..7068acda 100644
--- a/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
+++ b/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
@@ -10,8 +10,6 @@
 #include "base/bind.h"
 #include "base/check_op.h"
 #include "net/base/io_buffer.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "third_party/blink/public/common/blob/blob_utils.h"
 #include "url/origin.h"
diff --git a/content/browser/cross_site_transfer_browsertest.cc b/content/browser/cross_site_transfer_browsertest.cc
index 5a34f89..52e40bb 100644
--- a/content/browser/cross_site_transfer_browsertest.cc
+++ b/content/browser/cross_site_transfer_browsertest.cc
@@ -35,8 +35,6 @@
 #include "net/base/escape.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_status.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "url/gurl.h"
 
diff --git a/content/browser/device/README.md b/content/browser/device/README.md
new file mode 100644
index 0000000..b901014
--- /dev/null
+++ b/content/browser/device/README.md
@@ -0,0 +1 @@
+Implementation of //content API's device_service.h.
diff --git a/content/browser/download/save_file_manager.cc b/content/browser/download/save_file_manager.cc
index 7ece75b7..025cce61 100644
--- a/content/browser/download/save_file_manager.cc
+++ b/content/browser/download/save_file_manager.cc
@@ -27,12 +27,8 @@
 #include "content/public/browser/web_ui_url_loader_factory.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/previews_state.h"
-#include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_job_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc
index 03244ed..b8b95a1 100644
--- a/content/browser/download/save_package.cc
+++ b/content/browser/download/save_package.cc
@@ -63,9 +63,7 @@
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "net/base/filename_util.h"
-#include "net/base/io_buffer.h"
 #include "net/base/mime_util.h"
-#include "net/url_request/url_request_context.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 #include "url/url_constants.h"
 
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index d9959a16..5d8ba51 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -50,7 +50,6 @@
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_request_context.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/file_system/file_stream_writer.h"
 #include "storage/browser/file_system/file_writer_delegate.h"
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 6eb6851..83b9df4 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -79,8 +79,6 @@
 #include "net/ssl/ssl_info.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/redirect_util.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "services/network/public/cpp/constants.h"
 #include "services/network/public/cpp/features.h"
diff --git a/content/browser/loader/navigation_url_loader_unittest.cc b/content/browser/loader/navigation_url_loader_unittest.cc
index 637f3c74..8543436 100644
--- a/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_unittest.cc
@@ -30,8 +30,6 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/redirect_info.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/browser/net/reporting_service_proxy.cc b/content/browser/net/reporting_service_proxy.cc
index 24c4c40..21185278 100644
--- a/content/browser/net/reporting_service_proxy.cc
+++ b/content/browser/net/reporting_service_proxy.cc
@@ -18,8 +18,6 @@
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "net/reporting/reporting_report.h"
 #include "net/reporting/reporting_service.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "third_party/blink/public/mojom/reporting/reporting.mojom.h"
 #include "url/gurl.h"
diff --git a/content/browser/renderer_host/media/video_capture_unittest.cc b/content/browser/renderer_host/media/video_capture_unittest.cc
index 5e5bff2..7094b06e 100644
--- a/content/browser/renderer_host/media/video_capture_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/no_destructor.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -33,7 +34,6 @@
 #include "media/base/media_switches.h"
 #include "media/capture/video_capture_types.h"
 #include "mojo/public/cpp/bindings/receiver.h"
-#include "net/url_request/url_request_context.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/mediastream/media_devices.h"
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 2b80b75f..78a6a81 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -200,7 +200,6 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/scoped_message_error_crash_key.h"
 #include "mojo/public/cpp/system/platform_handle.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "sandbox/policy/switches.h"
 #include "services/device/public/mojom/battery_monitor.mojom.h"
 #include "services/device/public/mojom/power_monitor.mojom.h"
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index ac344bb7..d34b836b 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -83,7 +83,6 @@
 #include "content/public/common/url_utils.h"
 #include "media/base/media_switches.h"
 #include "net/base/url_util.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/features.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index ddaa4ba..ab1a589 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -43,7 +43,6 @@
 #include "net/http/http_util.h"
 #include "net/log/net_log.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_request.h"
 #include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
 
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc
index 33b37fbf4..511fa76 100644
--- a/content/browser/service_worker/service_worker_metrics.cc
+++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -19,7 +19,6 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_client.h"
-#include "net/url_request/url_request.h"
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 
 namespace content {
diff --git a/content/browser/speech/speech_recognition_engine_unittest.cc b/content/browser/speech/speech_recognition_engine_unittest.cc
index a68c416..4515d1a 100644
--- a/content/browser/speech/speech_recognition_engine_unittest.cc
+++ b/content/browser/speech/speech_recognition_engine_unittest.cc
@@ -22,7 +22,6 @@
 #include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
diff --git a/content/browser/ssl/ssl_client_auth_handler.cc b/content/browser/ssl/ssl_client_auth_handler.cc
index f2ef4ed..8100461 100644
--- a/content/browser/ssl/ssl_client_auth_handler.cc
+++ b/content/browser/ssl/ssl_client_auth_handler.cc
@@ -16,7 +16,6 @@
 #include "content/public/common/content_client.h"
 #include "net/ssl/client_cert_store.h"
 #include "net/ssl/ssl_private_key.h"
-#include "net/url_request/url_request.h"
 
 namespace content {
 
diff --git a/content/browser/ssl/ssl_error_handler.cc b/content/browser/ssl/ssl_error_handler.cc
index de1a214..f41a6cc 100644
--- a/content/browser/ssl/ssl_error_handler.cc
+++ b/content/browser/ssl/ssl_error_handler.cc
@@ -11,7 +11,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_status_flags.h"
-#include "net/url_request/url_request.h"
 
 using net::SSLInfo;
 
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc
index 8adc688..eb3b67e 100644
--- a/content/browser/ssl/ssl_manager.cc
+++ b/content/browser/ssl/ssl_manager.cc
@@ -28,7 +28,6 @@
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/ssl_host_state_delegate.h"
 #include "content/public/common/content_client.h"
-#include "net/url_request/url_request.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index c65577c..38e137bd 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -96,7 +96,6 @@
 #include "net/cookies/cookie_util.h"
 #include "net/http/http_auth_preferences.h"
 #include "net/ssl/client_cert_store.h"
-#include "net/url_request/url_request_context.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index 83fa3db1..e381ea2 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -44,9 +44,6 @@
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_access_result.h"
 #include "net/cookies/cookie_inclusion_status.h"
-#include "net/cookies/cookie_store.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "services/network/cookie_manager.h"
 #include "storage/browser/quota/quota_client_type.h"
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 355b270..502236fc 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -146,8 +146,6 @@
 #include "net/http/http_cache.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 #include "services/network/public/cpp/features.h"
diff --git a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
index f3c50a9..897ea50 100644
--- a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
@@ -59,8 +59,6 @@
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/test/test_data_directory.h"
 #include "net/test/url_request/url_request_mock_http_job.h"
-#include "net/url_request/url_request_filter.h"
-#include "net/url_request/url_request_interceptor.h"
 #include "services/network/public/cpp/constants.h"
 #include "services/network/public/cpp/features.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
diff --git a/content/browser/webauth/authenticator_common.cc b/content/browser/webauth/authenticator_common.cc
index a90df64..c24b40c 100644
--- a/content/browser/webauth/authenticator_common.cc
+++ b/content/browser/webauth/authenticator_common.cc
@@ -52,8 +52,6 @@
 #include "net/der/input.h"
 #include "net/der/parse_values.h"
 #include "net/der/parser.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "url/url_constants.h"
 #include "url/url_util.h"
diff --git a/content/browser/webui/url_data_manager_backend.cc b/content/browser/webui/url_data_manager_backend.cc
index a9d88c5..4b2bbb3 100644
--- a/content/browser/webui/url_data_manager_backend.cc
+++ b/content/browser/webui/url_data_manager_backend.cc
@@ -38,11 +38,6 @@
 #include "net/filter/source_stream.h"
 #include "net/http/http_status_code.h"
 #include "net/log/net_log_util.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_error_job.h"
-#include "net/url_request/url_request_job.h"
-#include "net/url_request/url_request_job_factory.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "ui/base/template_expressions.h"
 #include "ui/base/webui/i18n_source_stream.h"
diff --git a/content/browser/webui/url_data_manager_backend.h b/content/browser/webui/url_data_manager_backend.h
index 0869836..3df5c86 100644
--- a/content/browser/webui/url_data_manager_backend.h
+++ b/content/browser/webui/url_data_manager_backend.h
@@ -18,7 +18,6 @@
 #include "content/browser/webui/url_data_manager.h"
 #include "content/public/browser/url_data_source.h"
 #include "net/http/http_response_headers.h"
-#include "net/url_request/url_request_job_factory.h"
 
 class GURL;
 
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index 429b7d01..a794c6a3 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -21,8 +21,6 @@
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
-#include "net/url_request/url_request_interceptor.h"
-#include "net/url_request/url_request_job_factory.h"
 #include "services/content/public/mojom/navigable_contents_factory.mojom-forward.h"
 #include "services/network/public/mojom/cors_origin_pattern.mojom-forward.h"
 #include "services/network/public/mojom/network_context.mojom-forward.h"
@@ -95,16 +93,6 @@
 class StoragePartitionConfig;
 class SSLHostStateDelegate;
 
-// A mapping from the scheme name to the protocol handler that services its
-// content.
-using ProtocolHandlerMap =
-    std::map<std::string,
-             std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>>;
-
-// A owning vector of protocol interceptors.
-using URLRequestInterceptorScopedVector =
-    std::vector<std::unique_ptr<net::URLRequestInterceptor>>;
-
 // This class holds the context needed for a browsing session.
 // It lives on the UI thread. All these methods must only be called on the UI
 // thread.
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index f1acef5..762329d 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -40,7 +40,6 @@
 #include "media/mojo/mojom/media_service.mojom.h"
 #include "net/ssl/client_cert_identity.h"
 #include "net/ssl/client_cert_store.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "sandbox/policy/sandbox_type.h"
 #include "services/device/public/cpp/geolocation/location_provider.h"
 #include "services/network/public/cpp/resource_request.h"
diff --git a/content/public/browser/url_data_source.cc b/content/public/browser/url_data_source.cc
index 71f98daa..6312e8a 100644
--- a/content/public/browser/url_data_source.cc
+++ b/content/public/browser/url_data_source.cc
@@ -18,7 +18,6 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/url_constants.h"
-#include "net/url_request/url_request.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 
 namespace {
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index bd72341..4ee793f3 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -106,8 +106,6 @@
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/test/python_utils.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
diff --git a/content/renderer/browser_render_view_browsertest.cc b/content/renderer/browser_render_view_browsertest.cc
index 6c85d3d..d600d52 100644
--- a/content/renderer/browser_render_view_browsertest.cc
+++ b/content/renderer/browser_render_view_browsertest.cc
@@ -35,8 +35,6 @@
 #include "net/base/net_errors.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/http/http_cache.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/web_url_error.h"
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc
index c5c341a..951adf6f 100644
--- a/content/renderer/dom_serializer_browsertest.cc
+++ b/content/renderer/dom_serializer_browsertest.cc
@@ -27,7 +27,6 @@
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "net/base/filename_util.h"
-#include "net/url_request/url_request_context.h"
 #include "third_party/blink/public/platform/web_data.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
index ee77081..c5142c65 100644
--- a/content/test/content_browser_test_utils_internal.cc
+++ b/content/test/content_browser_test_utils_internal.cc
@@ -42,7 +42,6 @@
 #include "content/public/test/test_navigation_observer.h"
 #include "content/shell/browser/shell.h"
 #include "content/shell/browser/shell_javascript_dialog_manager.h"
-#include "net/url_request/url_request.h"
 
 namespace content {
 
diff --git a/docs/ios/build_instructions.md b/docs/ios/build_instructions.md
index dd3f606..188fd0bd 100644
--- a/docs/ios/build_instructions.md
+++ b/docs/ios/build_instructions.md
@@ -13,7 +13,7 @@
 ## System requirements
 
 * A 64-bit Mac running 10.12.6 or later.
-* [Xcode](https://developer.apple.com/xcode) 10.0+.
+* [Xcode](https://developer.apple.com/xcode) 11.4+.
 * The current version of the JDK (required for the Closure compiler).
 
 ## Install `depot_tools`
diff --git a/extensions/browser/updater/extension_downloader.cc b/extensions/browser/updater/extension_downloader.cc
index fffb678..554f06f 100644
--- a/extensions/browser/updater/extension_downloader.cc
+++ b/extensions/browser/updater/extension_downloader.cc
@@ -661,7 +661,8 @@
     ExtensionDownloaderDelegate::Error error,
     const int net_error,
     const int response_code,
-    const base::Optional<ManifestInvalidErrorList>& manifest_invalid_errors) {
+    const base::Optional<ManifestInvalidFailureDataList>&
+        manifest_invalid_errors) {
   const ExtensionIdSet extension_ids = fetch_data->GetExtensionIds();
   ExtensionIdSet extensions_fetched_from_cache;
   for (const auto& extension_id : extension_ids) {
@@ -703,7 +704,7 @@
     return;
   }
   DCHECK(manifest_invalid_errors);
-  ManifestInvalidErrorList errors_for_remaining_extensions;
+  ManifestInvalidFailureDataList errors_for_remaining_extensions;
   for (const auto& manifest_invalid_error : manifest_invalid_errors.value()) {
     if (!extensions_fetched_from_cache.count(manifest_invalid_error.first))
       errors_for_remaining_extensions.push_back(manifest_invalid_error);
@@ -808,14 +809,15 @@
   if (!results) {
     VLOG(2) << "parsing manifest failed (" << fetch_data->full_url() << ")";
     DCHECK(error.has_value());
-    ManifestInvalidErrorList manifest_invalid_errors;
+    ManifestInvalidFailureDataList manifest_invalid_errors;
     const ExtensionIdSet extension_ids = fetch_data->GetExtensionIds();
     manifest_invalid_errors.reserve(extension_ids.size());
     // If the manifest parsing failed for all the extensions with a common
     // error, add all extensions in the list with that error.
     for (const auto& extension_id : extension_ids) {
-      manifest_invalid_errors.push_back(
-          std::make_pair(extension_id, error.value().error));
+      manifest_invalid_errors.push_back(std::make_pair(
+          extension_id,
+          ExtensionDownloaderDelegate::FailureData(error.value().error)));
     }
     TryFetchingExtensionsFromCache(
         fetch_data.get(), ExtensionDownloaderDelegate::Error::MANIFEST_INVALID,
@@ -834,7 +836,7 @@
 
   std::vector<UpdateManifestResult*> to_update;
   std::set<std::string> no_updates;
-  ManifestInvalidErrorList errors;
+  ManifestInvalidFailureDataList errors;
 
   // Examine the parsed manifest and kick off fetches of any new crx files.
   DetermineUpdates(*fetch_data, *results, &to_update, &no_updates, &errors);
@@ -965,7 +967,7 @@
     const UpdateManifestResults& possible_updates,
     std::vector<UpdateManifestResult*>* to_update,
     std::set<std::string>* no_updates,
-    ManifestInvalidErrorList* errors) {
+    ManifestInvalidFailureDataList* errors) {
   DCHECK_NE(nullptr, to_update);
   DCHECK_NE(nullptr, no_updates);
   DCHECK_NE(nullptr, errors);
@@ -1019,13 +1021,20 @@
     if (!extension_errors.count(id))
       continue;
     DCHECK(possible_update.parse_error);
+    ManifestInvalidError error_type = possible_update.parse_error.value().error;
     // Report any error corresponding to an extension.
-    errors->emplace_back(id, possible_update.parse_error.value().error);
+    errors->emplace_back(
+        id, error_type == ManifestInvalidError::BAD_APP_STATUS
+                ? ExtensionDownloaderDelegate::FailureData(
+                      error_type, possible_update.app_status)
+                : ExtensionDownloaderDelegate::FailureData(error_type));
     extension_errors.erase(id);
   }
   // For the remaining extensions, we have missing ids.
-  for (const auto& id : extension_errors)
-    errors->emplace_back(id, ManifestInvalidError::MISSING_APP_ID);
+  for (const auto& id : extension_errors) {
+    errors->emplace_back(id, ExtensionDownloaderDelegate::FailureData(
+                                 ManifestInvalidError::MISSING_APP_ID));
+  }
 }
 
 base::Optional<base::FilePath> ExtensionDownloader::GetCachedExtension(
@@ -1344,13 +1353,12 @@
 }
 
 void ExtensionDownloader::NotifyExtensionsManifestInvalidFailure(
-    const ManifestInvalidErrorList& errors,
+    const ManifestInvalidFailureDataList& errors,
     const std::set<int>& request_ids) {
   for (const auto& error_data : errors) {
     const ExtensionId& extension_id = error_data.first;
-    ManifestInvalidError manifest_invalid_error = error_data.second;
+    ExtensionDownloaderDelegate::FailureData data = error_data.second;
     auto ping_iter = ping_results_.find(extension_id);
-    ExtensionDownloaderDelegate::FailureData data(manifest_invalid_error);
     delegate_->OnExtensionDownloadFailed(
         extension_id, ExtensionDownloaderDelegate::Error::MANIFEST_INVALID,
         ping_iter == ping_results_.end()
diff --git a/extensions/browser/updater/extension_downloader.h b/extensions/browser/updater/extension_downloader.h
index 56ac50d..f327782 100644
--- a/extensions/browser/updater/extension_downloader.h
+++ b/extensions/browser/updater/extension_downloader.h
@@ -48,8 +48,8 @@
 
 namespace extensions {
 
-using ManifestInvalidErrorList =
-    std::vector<std::pair<ExtensionId, ManifestInvalidError>>;
+using ManifestInvalidFailureDataList = std::vector<
+    std::pair<ExtensionId, ExtensionDownloaderDelegate::FailureData>>;
 struct UpdateDetails {
   UpdateDetails(const std::string& id, const base::Version& version);
   ~UpdateDetails();
@@ -303,7 +303,8 @@
       ExtensionDownloaderDelegate::Error error,
       const int net_error,
       const int response_code,
-      const base::Optional<ManifestInvalidErrorList>& manifest_invalid_errors);
+      const base::Optional<ManifestInvalidFailureDataList>&
+          manifest_invalid_errors);
 
   // Makes a retry attempt, reports failure by calling
   // AddFailureDataOnManifestFetchFailed when fetching of update manifest
@@ -334,7 +335,7 @@
                         const UpdateManifestResults& possible_updates,
                         std::vector<UpdateManifestResult*>* to_update,
                         std::set<std::string>* no_updates,
-                        ManifestInvalidErrorList* errors);
+                        ManifestInvalidFailureDataList* errors);
 
   // Checks whether extension is presented in cache. If yes, return path to its
   // cached CRX, base::nullopt otherwise. |manifest_fetch_failed| flag indicates
@@ -361,7 +362,7 @@
       std::vector<UpdateManifestResult> results);
 
   void NotifyExtensionsManifestInvalidFailure(
-      const ManifestInvalidErrorList& errors,
+      const ManifestInvalidFailureDataList& errors,
       const std::set<int>& request_ids);
 
   // Invokes OnExtensionDownloadStageChanged() on the |delegate_| for each
diff --git a/extensions/browser/updater/extension_downloader_delegate.cc b/extensions/browser/updater/extension_downloader_delegate.cc
index 02d98fe..9fdb560 100644
--- a/extensions/browser/updater/extension_downloader_delegate.cc
+++ b/extensions/browser/updater/extension_downloader_delegate.cc
@@ -33,6 +33,12 @@
     : manifest_invalid_error(manifest_invalid_error) {}
 
 ExtensionDownloaderDelegate::FailureData::FailureData(
+    ManifestInvalidError manifest_invalid_error,
+    const std::string& app_status_error)
+    : manifest_invalid_error(manifest_invalid_error),
+      app_status_error(app_status_error) {}
+
+ExtensionDownloaderDelegate::FailureData::FailureData(
     const std::string& additional_info)
     : additional_info(additional_info) {}
 
diff --git a/extensions/browser/updater/extension_downloader_delegate.h b/extensions/browser/updater/extension_downloader_delegate.h
index f529e03..bf0380a8 100644
--- a/extensions/browser/updater/extension_downloader_delegate.h
+++ b/extensions/browser/updater/extension_downloader_delegate.h
@@ -158,6 +158,8 @@
                 const base::Optional<int> response,
                 const int fetch_attempts);
     explicit FailureData(ManifestInvalidError manifest_invalid_error);
+    FailureData(ManifestInvalidError manifest_invalid_error,
+                const std::string& app_status_error);
     explicit FailureData(const std::string& additional_info);
     ~FailureData();
 
@@ -176,6 +178,9 @@
     // only set when no update is available and install fails with the error
     // CRX_FETCH_URL_EMPTY.
     const base::Optional<std::string> additional_info;
+    // Type of app status error returned by update server on fetching the update
+    // manifest.
+    const base::Optional<std::string> app_status_error;
   };
 
   // A callback that is called to indicate if ExtensionDownloader should ignore
diff --git a/extensions/browser/updater/safe_manifest_parser.cc b/extensions/browser/updater/safe_manifest_parser.cc
index 067a0ef..c09262d 100644
--- a/extensions/browser/updater/safe_manifest_parser.cc
+++ b/extensions/browser/updater/safe_manifest_parser.cc
@@ -51,6 +51,14 @@
     return false;
   }
 
+  // Get the app status.
+  result->app_status = GetXmlElementAttribute(app_element, "status");
+  if (!result->app_status.empty() && result->app_status != "ok") {
+    result->parse_error = ManifestParseFailure(
+        "App status is not OK", ManifestInvalidError::BAD_APP_STATUS);
+    return false;
+  }
+
   // Get the updatecheck node.
   std::string updatecheck_name =
       GetXmlQualifiedName(xml_namespace, "updatecheck");
diff --git a/extensions/browser/updater/safe_manifest_parser.h b/extensions/browser/updater/safe_manifest_parser.h
index bcddbfc..541faca 100644
--- a/extensions/browser/updater/safe_manifest_parser.h
+++ b/extensions/browser/updater/safe_manifest_parser.h
@@ -38,8 +38,9 @@
   MISSING_VERSION_FOR_UPDATE_CHECK = 10,
   INVALID_VERSION = 11,
   BAD_UPDATE_SPECIFICATION = 12,
+  BAD_APP_STATUS = 13,
   // Maximum histogram value.
-  kMaxValue = BAD_UPDATE_SPECIFICATION
+  kMaxValue = BAD_APP_STATUS
 };
 
 struct ManifestParseFailure {
@@ -60,6 +61,7 @@
   std::string extension_id;
   std::string version;
   std::string browser_min_version;
+  std::string app_status;
 
   // Error occurred while parsing manifest.
   base::Optional<ManifestParseFailure> parse_error;
diff --git a/gpu/config/gpu_util.cc b/gpu/config/gpu_util.cc
index 8156aca9..7277c62 100644
--- a/gpu/config/gpu_util.cc
+++ b/gpu/config/gpu_util.cc
@@ -310,8 +310,11 @@
 GpuFeatureStatus GetAcceleratedVideoDecodeFeatureStatus(
     const std::set<int>& blocklisted_features,
     bool use_swift_shader) {
-  if (use_swift_shader)
-    return kGpuFeatureStatusDisabled;
+  if (use_swift_shader) {
+    // This is for testing only. Chrome should exercise the GPU accelerated
+    // path on top of SwiftShader driver.
+    return kGpuFeatureStatusEnabled;
+  }
   if (blocklisted_features.count(GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE))
     return kGpuFeatureStatusBlocklisted;
   return kGpuFeatureStatusEnabled;
diff --git a/headless/lib/browser/headless_clipboard.cc b/headless/lib/browser/headless_clipboard.cc
index a4c4994e..44667f3 100644
--- a/headless/lib/browser/headless_clipboard.cc
+++ b/headless/lib/browser/headless_clipboard.cc
@@ -24,6 +24,11 @@
   return GetStore(buffer).sequence_number;
 }
 
+void HeadlessClipboard::SetClipboardDlpController(
+    std::unique_ptr<ui::ClipboardDlpController> dlp_controller) {
+  NOTIMPLEMENTED();
+}
+
 // |data_dst| is not used. It's only passed to be consistent with other
 // platforms.
 bool HeadlessClipboard::IsFormatAvailable(
diff --git a/headless/lib/browser/headless_clipboard.h b/headless/lib/browser/headless_clipboard.h
index e8539aa..67a40dd3 100644
--- a/headless/lib/browser/headless_clipboard.h
+++ b/headless/lib/browser/headless_clipboard.h
@@ -26,6 +26,8 @@
   // Clipboard overrides.
   void OnPreShutdown() override;
   uint64_t GetSequenceNumber(ui::ClipboardBuffer buffer) const override;
+  void SetClipboardDlpController(
+      std::unique_ptr<ui::ClipboardDlpController> dlp_controller) override;
   bool IsFormatAvailable(
       const ui::ClipboardFormatType& format,
       ui::ClipboardBuffer buffer,
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 0172b40d..f35f99c 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -6756,11 +6756,11 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.clang\",\"perf_dashboard_machine_group\":\"ChromiumClang\",\"recipe\":\"chromium\",\"xcode_build_version\":\"11c29\"}"
+      properties: "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.clang\",\"perf_dashboard_machine_group\":\"ChromiumClang\",\"recipe\":\"chromium\",\"xcode_build_version\":\"11e146\"}"
       execution_timeout_secs: 43200
       caches {
-        name: "xcode_ios_11c29"
-        path: "xcode_ios_11c29.app"
+        name: "xcode_ios_11e146"
+        path: "xcode_ios_11e146.app"
       }
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -6788,11 +6788,11 @@
         cipd_version: "refs/heads/master"
         cmd: "recipes"
       }
-      properties: "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.clang\",\"perf_dashboard_machine_group\":\"ChromiumClang\",\"recipe\":\"chromium\",\"xcode_build_version\":\"11c29\"}"
+      properties: "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.clang\",\"perf_dashboard_machine_group\":\"ChromiumClang\",\"recipe\":\"chromium\",\"xcode_build_version\":\"11e146\"}"
       execution_timeout_secs: 43200
       caches {
-        name: "xcode_ios_11c29"
-        path: "xcode_ios_11c29.app"
+        name: "xcode_ios_11e146"
+        path: "xcode_ios_11e146.app"
       }
       build_numbers: YES
       service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/infra/config/generated/luci-notify.cfg b/infra/config/generated/luci-notify.cfg
index fcedbc2..07be0da 100644
--- a/infra/config/generated/luci-notify.cfg
+++ b/infra/config/generated/luci-notify.cfg
@@ -103,6 +103,24 @@
       rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
     }
   }
+  builders {
+    bucket: "ci"
+    name: "Android ASAN (dbg)"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+  tree_closers {
+    tree_status_host: "chromium-status.appspot.com"
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+  }
+}
+notifiers {
+  notifications {
+    on_occurrence: FAILURE
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+    email {
+      rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
+    }
+  }
   notifications {
     on_occurrence: FAILURE
     failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
@@ -123,6 +141,42 @@
 }
 notifiers {
   notifications {
+    on_occurrence: FAILURE
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+    email {
+      rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
+    }
+  }
+  builders {
+    bucket: "ci"
+    name: "Android arm Builder (dbg)"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+  tree_closers {
+    tree_status_host: "chromium-status.appspot.com"
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+  }
+}
+notifiers {
+  notifications {
+    on_occurrence: FAILURE
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+    email {
+      rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
+    }
+  }
+  builders {
+    bucket: "ci"
+    name: "Android arm64 Builder (dbg)"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+  tree_closers {
+    tree_status_host: "chromium-status.appspot.com"
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+  }
+}
+notifiers {
+  notifications {
     on_new_status: FAILURE
     email {
       recipients: "pcc@chromium.org"
@@ -155,6 +209,24 @@
       rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
     }
   }
+  builders {
+    bucket: "ci"
+    name: "Cast Android (dbg)"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+  tree_closers {
+    tree_status_host: "chromium-status.appspot.com"
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+  }
+}
+notifiers {
+  notifications {
+    on_occurrence: FAILURE
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+    email {
+      rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
+    }
+  }
   notifications {
     on_occurrence: FAILURE
     failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
@@ -235,11 +307,22 @@
       recipients: "agrieve@chromium.org"
     }
   }
+  notifications {
+    on_occurrence: FAILURE
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+    email {
+      rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
+    }
+  }
   builders {
     bucket: "ci"
     name: "Deterministic Android"
     repository: "https://chromium.googlesource.com/chromium/src"
   }
+  tree_closers {
+    tree_status_host: "chromium-status.appspot.com"
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+  }
 }
 notifiers {
   notifications {
@@ -249,11 +332,22 @@
       recipients: "agrieve@chromium.org"
     }
   }
+  notifications {
+    on_occurrence: FAILURE
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+    email {
+      rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
+    }
+  }
   builders {
     bucket: "ci"
     name: "Deterministic Android (dbg)"
     repository: "https://chromium.googlesource.com/chromium/src"
   }
+  tree_closers {
+    tree_status_host: "chromium-status.appspot.com"
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+  }
 }
 notifiers {
   notifications {
@@ -2187,6 +2281,60 @@
   }
   builders {
     bucket: "ci"
+    name: "android-lollipop-arm-rel"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+  tree_closers {
+    tree_status_host: "chromium-status.appspot.com"
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+  }
+}
+notifiers {
+  notifications {
+    on_occurrence: FAILURE
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+    email {
+      rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
+    }
+  }
+  builders {
+    bucket: "ci"
+    name: "android-marshmallow-arm64-rel"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+  tree_closers {
+    tree_status_host: "chromium-status.appspot.com"
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+  }
+}
+notifiers {
+  notifications {
+    on_occurrence: FAILURE
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+    email {
+      rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
+    }
+  }
+  builders {
+    bucket: "ci"
+    name: "android-pie-arm64-rel"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+  tree_closers {
+    tree_status_host: "chromium-status.appspot.com"
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+  }
+}
+notifiers {
+  notifications {
+    on_occurrence: FAILURE
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+    email {
+      rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
+    }
+  }
+  builders {
+    bucket: "ci"
     name: "chromeos-amd64-generic-asan-rel"
     repository: "https://chromium.googlesource.com/chromium/src"
   }
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index 1acc18d..8ff66590f8 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -316,6 +316,7 @@
         short_name = '32',
     ),
     execution_timeout = 4 * time.hour,
+    tree_closing = True,
 )
 
 ci.android_builder(
@@ -326,6 +327,7 @@
     ),
     goma_jobs = goma.jobs.MANY_JOBS_FOR_CI,
     execution_timeout = 5 * time.hour,
+    tree_closing = True,
 )
 
 ci.android_builder(
@@ -352,6 +354,7 @@
         category = 'on_cq',
         short_name = 'cst',
     ),
+    tree_closing = True,
 )
 
 ci.android_builder(
@@ -425,6 +428,7 @@
         category = 'on_cq',
         short_name = 'L',
     ),
+    tree_closing = True,
 )
 
 ci.android_builder(
@@ -433,6 +437,7 @@
         category = 'on_cq',
         short_name = 'M',
     ),
+    tree_closing = True,
 )
 
 ci.android_builder(
@@ -466,6 +471,7 @@
         category = 'on_cq',
         short_name = 'P',
     ),
+    tree_closing = True,
 )
 
 ci.chromium_builder(
diff --git a/infra/config/subprojects/chromium/master-only/ci.star b/infra/config/subprojects/chromium/master-only/ci.star
index 7d7c2f0..e066598d 100644
--- a/infra/config/subprojects/chromium/master-only/ci.star
+++ b/infra/config/subprojects/chromium/master-only/ci.star
@@ -167,6 +167,7 @@
     # Higher build timeout since dbg ASAN builds can take a while on a clobber
     # build.
     execution_timeout = 4 * time.hour,
+    tree_closing = True,
 )
 
 ci.android_builder(
@@ -187,6 +188,7 @@
     executable = 'recipe:swarming/deterministic_build',
     execution_timeout = 6 * time.hour,
     notifies = ['Deterministic Android'],
+    tree_closing = True,
 )
 
 ci.android_builder(
@@ -198,6 +200,7 @@
     executable = 'recipe:swarming/deterministic_build',
     execution_timeout = 6 * time.hour,
     notifies = ['Deterministic Android'],
+    tree_closing = True,
 )
 
 ci.android_builder(
@@ -803,7 +806,7 @@
 
 ci.clang_builder(
     name = 'ToTiOS',
-    caches = [xcode_cache.x11c29],
+    caches = [xcode_cache.x11e146],
     console_view_entry = ci.console_view_entry(
         category = 'iOS|public',
         short_name = 'sim',
@@ -811,14 +814,14 @@
     cores = None,
     os = os.MAC_10_14,
     properties = {
-        'xcode_build_version': '11c29'
+        'xcode_build_version': '11e146'
     },
     ssd=True
 )
 
 ci.clang_builder(
     name = 'ToTiOSDevice',
-    caches = [xcode_cache.x11c29],
+    caches = [xcode_cache.x11e146],
     console_view_entry = ci.console_view_entry(
         category = 'iOS|public',
         short_name = 'dev',
@@ -826,7 +829,7 @@
     cores = None,
     os = os.MAC_10_14,
     properties = {
-        'xcode_build_version': '11c29'
+        'xcode_build_version': '11e146'
     },
     ssd=True
 )
diff --git a/ios/chrome/app/application_delegate/url_opener.mm b/ios/chrome/app/application_delegate/url_opener.mm
index 83be66e..7674c919 100644
--- a/ios/chrome/app/application_delegate/url_opener.mm
+++ b/ios/chrome/app/application_delegate/url_opener.mm
@@ -51,10 +51,7 @@
   if (startupInformation.isPresentingFirstRunUI) {
     UMA_HISTOGRAM_ENUMERATION("FirstRun.LaunchSource", [params launchSource],
                               first_run::LAUNCH_SIZE);
-    return NO;
-  }
-
-  if (applicationActive) {
+  } else if (applicationActive) {
     // The app is already active so the applicationDidBecomeActive: method will
     // never be called. Open the requested URL immediately and return YES if
     // the parsed URL was valid.
@@ -105,11 +102,11 @@
       return YES;
     }
     return NO;
+  } else {
+    // Don't record the first user action if application is not active.
+    [startupInformation resetFirstUserActionRecorder];
   }
 
-  // Don't record the first user action.
-  [startupInformation resetFirstUserActionRecorder];
-
   connectionInformation.startupParameters = params;
   return connectionInformation.startupParameters != nil;
 }
diff --git a/ios/chrome/app/application_delegate/url_opener_unittest.mm b/ios/chrome/app/application_delegate/url_opener_unittest.mm
index e309a67..6ec7ae3 100644
--- a/ios/chrome/app/application_delegate/url_opener_unittest.mm
+++ b/ios/chrome/app/application_delegate/url_opener_unittest.mm
@@ -396,6 +396,16 @@
       isPresentingFirstRunUI];
   id connectionInformationMock =
       [OCMockObject mockForProtocol:@protocol(ConnectionInformation)];
+  __block ChromeAppStartupParameters* params = nil;
+  [[connectionInformationMock expect]
+      setStartupParameters:[OCMArg checkWithBlock:^(
+                                       ChromeAppStartupParameters* p) {
+        params = p;
+        EXPECT_NSEQ(net::NSURLWithGURL(p.completeURL), url);
+        EXPECT_EQ(p.callerApp, CALLER_APP_APPLE_MOBILESAFARI);
+        return YES;
+      }]];
+  [[[connectionInformationMock expect] andReturn:params] startupParameters];
 
   id appStateMock = [OCMockObject mockForClass:[AppState class]];
   [[appStateMock expect] launchFromURLHandled:NO];
diff --git a/ios/chrome/browser/autofill/form_structure_browsertest.mm b/ios/chrome/browser/autofill/form_structure_browsertest.mm
index bc18ca1..6605008 100644
--- a/ios/chrome/browser/autofill/form_structure_browsertest.mm
+++ b/ios/chrome/browser/autofill/form_structure_browsertest.mm
@@ -206,16 +206,11 @@
 
 std::string FormStructureBrowserTest::FormStructuresToString(
     const std::map<FormRendererId, std::unique_ptr<FormStructure>>& forms) {
-  std::map<uint32_t, const FormStructure*> sorted_forms;
+  std::string forms_string;
+  // The forms are sorted by renderer ID, which should make the order
+  // deterministic.
   for (const auto& form_kv : forms) {
     const auto* form = form_kv.second.get();
-    uint32_t renderer_id = form->unique_renderer_id().value();
-    EXPECT_TRUE(sorted_forms.emplace(renderer_id, form).second);
-  }
-
-  std::string forms_string;
-  for (const auto& form_kv : sorted_forms) {
-    const auto* form = form_kv.second;
     for (const auto& field : *form) {
       std::string name = base::UTF16ToUTF8(field->name);
       if (base::StartsWith(name, "gChrome~field~",
diff --git a/ios/chrome/browser/metrics/ukm_egtest.mm b/ios/chrome/browser/metrics/ukm_egtest.mm
index 2ba614d..7657ab2 100644
--- a/ios/chrome/browser/metrics/ukm_egtest.mm
+++ b/ios/chrome/browser/metrics/ukm_egtest.mm
@@ -189,13 +189,17 @@
 //
 // Corresponds to IncognitoPlusRegularCheck in //chrome/browser/metrics/
 // ukm_browsertest.cc.
-// TODO(crbug.com/1033726): This test is flaky on iOS 12 and 13.
-- (void)DISABLED_testIncognitoPlusRegular {
+- (void)testIncognitoPlusRegular {
   const uint64_t originalClientID = [MetricsAppInterface UKMClientID];
-  [ChromeEarlGrey closeAllTabs];
-  [ChromeEarlGrey waitForMainTabCount:0];
 
+  // TODO(crbug.com/640977): Due to continuous animations, it is not feasible
+  // to close the regular tab that is already open. The functions closeAllTabs,
+  // closeCurrentTab, and closeAllTabsInCurrentMode close the tab and then hang.
+  //
+  // As a workaround, we open an incognito tab and then close the regular tab to
+  // get to a state in which a single incognito tab is open.
   [self openNewIncognitoTab];
+  [ChromeEarlGrey closeAllNormalTabs];
   GREYAssert([MetricsAppInterface checkUKMRecordingEnabled:NO],
              @"Failed to assert that UKM was not enabled.");
 
@@ -205,7 +209,6 @@
              @"Failed to assert that UKM was not enabled.");
 
   [ChromeEarlGrey closeAllIncognitoTabs];
-  [ChromeEarlGrey waitForIncognitoTabCount:0];
   GREYAssert([MetricsAppInterface checkUKMRecordingEnabled:YES],
              @"Failed to assert that UKM was enabled.");
 
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
index 4243713..2f8d43f 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
@@ -95,6 +95,7 @@
   void NotifyStorePasswordCalled() override;
   void NotifyUserCredentialsWereLeaked(
       password_manager::CredentialLeakType leak_type,
+      password_manager::CompromisedSitesCount saved_sites,
       const GURL& origin,
       const base::string16& username) override;
   bool IsSavingAndFillingEnabled(const GURL& url) const override;
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
index ec4f763..a1401571 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
@@ -205,6 +205,7 @@
 
 void IOSChromePasswordManagerClient::NotifyUserCredentialsWereLeaked(
     password_manager::CredentialLeakType leak_type,
+    password_manager::CompromisedSitesCount saved_sites,
     const GURL& origin,
     const base::string16& username) {
   [bridge_ showPasswordBreachForLeakType:leak_type URL:origin];
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index b5ba36da..815f476 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -297,78 +297,8 @@
       [ContentSuggestionsSchedulerNotifications
           notifyForeground:self.mainInterface.browserState];
     }
-    if (IsSceneStartupSupported()) {
-      if (@available(iOS 13, *)) {
-        // Handle URL opening from
-        // |UIWindowSceneDelegate scene:willConnectToSession:options:|.
-        for (UIOpenURLContext* context in self.sceneState.connectionOptions
-                 .URLContexts) {
-          URLOpenerParams* params =
-              [[URLOpenerParams alloc] initWithUIOpenURLContext:context];
-          [self openTabFromLaunchWithParams:params
-                         startupInformation:self.mainController
-                                   appState:self.sceneState.appState];
-        }
-        if (self.sceneState.connectionOptions.shortcutItem) {
-          [UserActivityHandler
-              performActionForShortcutItem:self.sceneState.connectionOptions
-                                               .shortcutItem
-                         completionHandler:nil
-                                 tabOpener:self
-                     connectionInformation:self
-                        startupInformation:self.mainController
-                         interfaceProvider:self.interfaceProvider];
-        }
 
-        // See if this scene launched as part of a multiwindow URL opening.
-        // If so, load that URL (this also creates a new tab to load the URL
-        // in). No other UI will show in this case.
-        NSUserActivity* activityWithCompletion;
-        for (NSUserActivity* activity in self.sceneState.connectionOptions
-                 .userActivities) {
-          if (ActivityIsURLLoad(activity)) {
-            UrlLoadParams params = LoadParamsFromActivity(activity);
-            UrlLoadingBrowserAgent::FromBrowser(self.mainInterface.browser)
-                ->Load(params);
-          } else if (!activityWithCompletion) {
-            // Completion involves user interaction.
-            // Only one can be triggered.
-            activityWithCompletion = activity;
-          }
-        }
-        if (activityWithCompletion) {
-          [UserActivityHandler continueUserActivity:activityWithCompletion
-                                applicationIsActive:YES
-                                          tabOpener:self
-                              connectionInformation:self
-                                 startupInformation:self.mainController];
-        }
-        self.sceneState.connectionOptions = nil;
-      }
-
-      if (self.startupParameters) {
-        ApplicationModeForTabOpening mode =
-            self.startupParameters.applicationMode;
-        UrlLoadParams params =
-            UrlLoadParams::InNewTab(self.startupParameters.externalURL);
-        BOOL dismissOmnibox =
-            [self.startupParameters postOpeningAction] != FOCUS_OMNIBOX;
-        [self dismissModalsAndOpenSelectedTabInMode:mode
-                                  withUrlLoadParams:params
-                                     dismissOmnibox:dismissOmnibox
-                                         completion:^{
-                                           self.startupParameters = nil;
-                                         }];
-      }
-
-    } else {
-      NSDictionary* launchOptions = self.mainController.launchOptions;
-      URLOpenerParams* params =
-          [[URLOpenerParams alloc] initWithLaunchOptions:launchOptions];
-      [self openTabFromLaunchWithParams:params
-                     startupInformation:self.mainController
-                               appState:self.sceneState.appState];
-    }
+    [self handleExternalIntents];
 
     if (!initializingUIInColdStart && self.tabSwitcherIsActive &&
         [self shouldOpenNTPTabOnActivationOfBrowser:self.currentInterface
@@ -402,6 +332,85 @@
   }
 }
 
+- (void)handleExternalIntents {
+  if (self.mainController.isPresentingFirstRunUI ||
+      self.blockingOverlayViewController) {
+    return;
+  }
+  if (IsSceneStartupSupported()) {
+    if (@available(iOS 13, *)) {
+      // Handle URL opening from
+      // |UIWindowSceneDelegate scene:willConnectToSession:options:|.
+      for (UIOpenURLContext* context in self.sceneState.connectionOptions
+               .URLContexts) {
+        URLOpenerParams* params =
+            [[URLOpenerParams alloc] initWithUIOpenURLContext:context];
+        [self openTabFromLaunchWithParams:params
+                       startupInformation:self.mainController
+                                 appState:self.sceneState.appState];
+      }
+      if (self.sceneState.connectionOptions.shortcutItem) {
+        [UserActivityHandler
+            performActionForShortcutItem:self.sceneState.connectionOptions
+                                             .shortcutItem
+                       completionHandler:nil
+                               tabOpener:self
+                   connectionInformation:self
+                      startupInformation:self.mainController
+                       interfaceProvider:self.interfaceProvider];
+      }
+
+      // See if this scene launched as part of a multiwindow URL opening.
+      // If so, load that URL (this also creates a new tab to load the URL
+      // in). No other UI will show in this case.
+      NSUserActivity* activityWithCompletion;
+      for (NSUserActivity* activity in self.sceneState.connectionOptions
+               .userActivities) {
+        if (ActivityIsURLLoad(activity)) {
+          UrlLoadParams params = LoadParamsFromActivity(activity);
+          UrlLoadingBrowserAgent::FromBrowser(self.mainInterface.browser)
+              ->Load(params);
+        } else if (!activityWithCompletion) {
+          // Completion involves user interaction.
+          // Only one can be triggered.
+          activityWithCompletion = activity;
+        }
+      }
+      if (activityWithCompletion) {
+        [UserActivityHandler continueUserActivity:activityWithCompletion
+                              applicationIsActive:YES
+                                        tabOpener:self
+                            connectionInformation:self
+                               startupInformation:self.mainController];
+      }
+      self.sceneState.connectionOptions = nil;
+    }
+
+    if (self.startupParameters) {
+      ApplicationModeForTabOpening mode =
+          self.startupParameters.applicationMode;
+      UrlLoadParams params =
+          UrlLoadParams::InNewTab(self.startupParameters.externalURL);
+      BOOL dismissOmnibox =
+          [self.startupParameters postOpeningAction] != FOCUS_OMNIBOX;
+      [self dismissModalsAndOpenSelectedTabInMode:mode
+                                withUrlLoadParams:params
+                                   dismissOmnibox:dismissOmnibox
+                                       completion:^{
+                                         self.startupParameters = nil;
+                                       }];
+    }
+
+  } else {
+    NSDictionary* launchOptions = self.mainController.launchOptions;
+    URLOpenerParams* params =
+        [[URLOpenerParams alloc] initWithLaunchOptions:launchOptions];
+    [self openTabFromLaunchWithParams:params
+                   startupInformation:self.mainController
+                             appState:self.sceneState.appState];
+  }
+}
+
 - (void)sceneStateWillShowModalOverlay:(SceneState*)sceneState {
   [self displayBlockingOverlay];
 }
@@ -426,6 +435,10 @@
       }
     }
   }
+
+  if (sceneState.activationLevel >= SceneActivationLevelForegroundActive) {
+    [self handleExternalIntents];
+  }
 }
 
 // TODO(crbug.com/1072408): factor out into a new class.
@@ -491,6 +504,10 @@
   }
   BOOL sceneIsActive =
       self.sceneState.activationLevel >= SceneActivationLevelForegroundActive;
+  if (self.mainController.isPresentingFirstRunUI ||
+      self.blockingOverlayViewController) {
+    sceneIsActive = NO;
+  }
   [UserActivityHandler continueUserActivity:userActivity
                         applicationIsActive:sceneIsActive
                                   tabOpener:self
@@ -736,16 +753,8 @@
       removeObserver:self
                 name:kChromeFirstRunUIWillFinishNotification
               object:nil];
-  if (self.startupParameters) {
-    UrlLoadParams params =
-        UrlLoadParams::InNewTab(self.startupParameters.externalURL);
-    [self dismissModalsAndOpenSelectedTabInMode:ApplicationModeForTabOpening::
-                                                    NORMAL
-                              withUrlLoadParams:params
-                                 dismissOmnibox:YES
-                                     completion:^{
-                                       [self setStartupParameters:nil];
-                                     }];
+  if (self.sceneState.activationLevel >= SceneActivationLevelForegroundActive) {
+    [self handleExternalIntents];
   }
 }
 
@@ -1977,6 +1986,11 @@
   DCHECK(URLsToOpen.count == URLContexts.count || URLContexts.count == 1);
   BOOL active =
       _sceneState.activationLevel >= SceneActivationLevelForegroundActive;
+  if (self.mainController.isPresentingFirstRunUI ||
+      self.blockingOverlayViewController) {
+    active = NO;
+  }
+
   for (URLOpenerParams* options : URLsToOpen) {
     [URLOpener openURL:options
             applicationActive:active
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm b/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm
index 9873e3d6..33b6f9d 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm
@@ -479,13 +479,6 @@
     EARL_GREY_TEST_DISABLED(@"Fails on iOS 12.");
   }
 
-// TODO(crbug.com/1046787): Test is failing for EG1.
-#if defined(CHROME_EARL_GREY_1)
-  if (![ChromeEarlGrey isIPadIdiom]) {
-    EARL_GREY_TEST_SKIPPED(@"Test skipped on Earl Grey 1.");
-  }
-#endif
-
   // Focus omnibox.
   [self focusFakebox];
   [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()]
diff --git a/ios/chrome/browser/ui/settings/cells/settings_check_cell.h b/ios/chrome/browser/ui/settings/cells/settings_check_cell.h
index 41c8e090..89f5630 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_check_cell.h
+++ b/ios/chrome/browser/ui/settings/cells/settings_check_cell.h
@@ -11,14 +11,19 @@
 
 // Cell representation for SettingsCheckItem.
 //  +---------------------------------------------------------+
-//  |                                           +--------+    |
-//  | +--------+                                |trailing|    |
-//  | | leading|  One line title                |image or|    |
-//  | | image  |  Multiline detail text         |spinner |    |
-//  | +--------+                                +--------+    |
+//  | +--------+                                +---------+   |
+//  | |        |  One line title                |trailing |   |
+//  | | leading|                                |image    |   |
+//  | | image  |  Multiline detail text         |spinner  |   |
+//  | |        |  Multiline detail text         |or button|   |
+//  | +--------+                                +---------+   |
 //  +---------------------------------------------------------+
 @interface SettingsCheckCell : TableViewCell
 
+// Button which is used as an anchor to show popover with additional
+// information.
+@property(nonatomic, readonly, strong) UIButton* infoButton;
+
 // Shows |activityIndicator| and starts animation. It will hide |imageView| if
 // it was shown.
 - (void)showActivityIndicator;
@@ -39,6 +44,9 @@
 - (void)setLeadingImage:(UIImage*)leadingImage
           withTintColor:(UIColor*)tintColor;
 
+// Shows/Hides |infoButton|.
+- (void)setInfoButtonHidden:(BOOL)hidden;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_CHECK_CELL_H_
diff --git a/ios/chrome/browser/ui/settings/cells/settings_check_cell.mm b/ios/chrome/browser/ui/settings/cells/settings_check_cell.mm
index 44f1248..ac9f9d41 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_check_cell.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_check_cell.mm
@@ -8,6 +8,7 @@
 #include "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h"
+#import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -37,12 +38,12 @@
 @property(nonatomic, strong) UIImageView* leadingImageView;
 
 // Constraint that is used to define trailing text constraint without
-// |trailingImageView| or |activityIndicator|.
+// |trailingImageView| |activityIndicator| and |infoButton|.
 @property(nonatomic, strong)
     NSLayoutConstraint* textNoTrailingContentsConstraint;
 
 // Constraint that is used to define trailing text constraint with either
-// |trailingImageView| or |activityIndicator| showing.
+// |trailingImageView| or |activityIndicator| or |infoButton| showing.
 @property(nonatomic, strong)
     NSLayoutConstraint* textWithTrailingContentsConstraint;
 
@@ -92,8 +93,8 @@
     _detailTextLabel.textColor = UIColor.cr_secondaryLabelColor;
     [contentView addSubview:_detailTextLabel];
 
-    // Only |_trailingImageView| or |_activityIndicator| is shown, not both at
-    // once. |trailingImage| attributes.
+    // Only |_trailingImageView| or |_activityIndicator| or |_infoButton| is
+    // shown, not all at once. |trailingImage| attributes.
     _trailingImageView = [[UIImageView alloc] init];
     _trailingImageView.translatesAutoresizingMaskIntoConstraints = NO;
     _trailingImageView.tintColor = UIColor.cr_labelColor;
@@ -104,6 +105,15 @@
     _activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
     _activityIndicator.hidden = YES;
     [contentView addSubview:_activityIndicator];
+    // |_infoButton| attribues.
+    _infoButton = [UIButton buttonWithType:UIButtonTypeSystem];
+    _infoButton.translatesAutoresizingMaskIntoConstraints = NO;
+    _infoButton.hidden = YES;
+    UIImage* image = [[UIImage imageNamed:@"settings_info"]
+        imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+    [_infoButton setImage:image forState:UIControlStateNormal];
+    [_infoButton setTintColor:[UIColor colorNamed:kBlueColor]];
+    [contentView addSubview:_infoButton];
 
     // Constraints.
     UILayoutGuide* textLayoutGuide = [[UILayoutGuide alloc] init];
@@ -147,6 +157,18 @@
       [_trailingImageView.leadingAnchor
           constraintEqualToAnchor:_activityIndicator.leadingAnchor],
 
+      // Constraints for |_infoButton| (same position as
+      // |_trailingImageView|).
+      [_infoButton.trailingAnchor
+          constraintEqualToAnchor:self.contentView.trailingAnchor
+                         constant:-kTableViewHorizontalSpacing],
+      [_infoButton.widthAnchor constraintEqualToConstant:kIconImageSize],
+      [_infoButton.heightAnchor constraintEqualToConstant:kIconImageSize],
+      [_infoButton.centerYAnchor
+          constraintEqualToAnchor:textLayoutGuide.centerYAnchor],
+      [_infoButton.leadingAnchor
+          constraintEqualToAnchor:_activityIndicator.leadingAnchor],
+
       // Constraints for |_activityIndictor| (same position as
       // |_trailingImageView|).
       [_activityIndicator.trailingAnchor
@@ -194,8 +216,8 @@
 - (void)showActivityIndicator {
   if (!self.activityIndicator.hidden)
     return;
-
   self.trailingImageView.hidden = YES;
+  self.infoButton.hidden = YES;
   self.activityIndicator.hidden = NO;
   [self.activityIndicator startAnimating];
   [self updateTrailingImageTextConstraints];
@@ -219,7 +241,8 @@
     return;
   self.trailingImageView.hidden = hidden;
   if (!hidden) {
-    [self hideActivityIndicator];
+    self.activityIndicator.hidden = YES;
+    self.infoButton.hidden = YES;
   }
   [self updateTrailingImageTextConstraints];
 }
@@ -240,14 +263,27 @@
   }
 }
 
+- (void)setInfoButtonHidden:(BOOL)hidden {
+  if (hidden == self.infoButton.hidden)
+    return;
+
+  self.infoButton.hidden = hidden;
+  if (!hidden) {
+    self.trailingImageView.hidden = YES;
+    self.activityIndicator.hidden = YES;
+  }
+  [self updateTrailingImageTextConstraints];
+}
+
 #pragma mark - Private Methods
 
 // Updates the constraints around the trailing image for when |trailingImage| or
-// |activityIndicator| is shown or hidden.
+// |activityIndicator| or |infoButton| is shown or hidden.
 - (void)updateTrailingImageTextConstraints {
   // Active proper |textLayoutGuide| trailing constraint to show
-  // |trailingImageView| or |activityIndicator|.
-  if (self.activityIndicator.hidden && self.trailingImageView.hidden) {
+  // |trailingImageView| or |activityIndicator| or |infoButton|.
+  if (self.activityIndicator.hidden && self.trailingImageView.hidden &&
+      self.infoButton.hidden) {
     _textWithTrailingContentsConstraint.active = NO;
     _textNoTrailingContentsConstraint.active = YES;
   } else {
@@ -262,6 +298,9 @@
   [super prepareForReuse];
 
   self.textLabel.text = nil;
+  [self.infoButton removeTarget:nil
+                         action:nil
+               forControlEvents:UIControlEventAllEvents];
   self.detailTextLabel.text = nil;
   self.accessibilityTraits = UIAccessibilityTraitNone;
   [self setTrailingImage:nil withTintColor:nil];
diff --git a/ios/chrome/browser/ui/settings/cells/settings_check_item.h b/ios/chrome/browser/ui/settings/cells/settings_check_item.h
index 31cd585..44122854 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_check_item.h
+++ b/ios/chrome/browser/ui/settings/cells/settings_check_item.h
@@ -29,18 +29,22 @@
 // The image to display on the trailing side of |text| (required). If this image
 // should be tinted to match the text color (e.g. in dark mode), the provided
 // image should have rendering mode UIImageRenderingModeAlwaysTemplate. Don't
-// set image with |isIndicatorHidden| as only either image or
-// |activityIndicator| will be shown.
+// set image with |isIndicatorHidden| equal to false as image won't be shown
+// in that case.
 @property(nonatomic, strong) UIImage* trailingImage;
 
 // Tint color for |trailingImage|.
 @property(nonatomic, copy) UIColor* trailingImageTintColor;
 
-// Controls visibility of |activityIndicator|, if set true |imageView| will be
-// hidden and activity indicator will be shown. In case both image is provided
-// and this property set to false, only |activityIndicator| will be shown.
+// Controls visibility of |activityIndicator|, if set false |trailingImage| or
+// |infoButton| will be hidden and |activityIndicator| will be shown. This
+// property has the highest priority.
 @property(nonatomic, assign, getter=isIndicatorHidden) BOOL indicatorHidden;
 
+// Controls visibility of |infoButton|. This property has no effect in case
+// |trailingImage| is provided or |indicatorHidden| is false.
+@property(nonatomic, assign, getter=isInfoButtonHidden) BOOL infoButtonHidden;
+
 // Disabled cell are automatically drawn with dimmed text and without
 // |trailingImage| or |activityIndicator|.
 @property(nonatomic, assign, getter=isEnabled) BOOL enabled;
diff --git a/ios/chrome/browser/ui/settings/cells/settings_check_item.mm b/ios/chrome/browser/ui/settings/cells/settings_check_item.mm
index 3a3f0a0..5d5cb07 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_check_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_check_item.mm
@@ -31,6 +31,7 @@
   cell.detailTextLabel.text = self.detailText;
   cell.selectionStyle = UITableViewCellSelectionStyleNone;
   if (self.enabled) {
+    [cell setInfoButtonHidden:self.infoButtonHidden];
     [cell setLeadingImage:self.leadingImage
             withTintColor:self.leadingImageTintColor];
     [cell setTrailingImage:self.trailingImage
@@ -44,6 +45,7 @@
             withTintColor:UIColor.cr_secondaryLabelColor];
     [cell setTrailingImage:nil withTintColor:nil];
     [cell hideActivityIndicator];
+    [cell setInfoButtonHidden:YES];
     cell.textLabel.textColor = UIColor.cr_secondaryLabelColor;
     cell.accessibilityTraits |= UIAccessibilityTraitNotEnabled;
   }
diff --git a/ios/chrome/browser/ui/settings/cells/settings_check_item_unittest.mm b/ios/chrome/browser/ui/settings/cells/settings_check_item_unittest.mm
index f8438cfc..ecc9f92 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_check_item_unittest.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_check_item_unittest.mm
@@ -44,4 +44,43 @@
   EXPECT_NSEQ(detailText, CheckCell.detailTextLabel.text);
 }
 
+// Tests that cell is configured properly based on infoButtonHidden property of
+// the item.
+TEST_F(SettingsCheckItemTest, InfoButtonVisibility) {
+  SettingsCheckItem* item = [[SettingsCheckItem alloc] initWithType:0];
+  item.text = @"Test Text";
+  item.detailText = @"Test Text";
+  item.enabled = YES;
+  item.indicatorHidden = YES;
+  item.infoButtonHidden = NO;
+
+  id cell = [[[item cellClass] alloc] init];
+  SettingsCheckCell* CheckCell =
+      base::mac::ObjCCastStrict<SettingsCheckCell>(cell);
+
+  [item configureCell:cell withStyler:[[ChromeTableViewStyler alloc] init]];
+  EXPECT_FALSE(CheckCell.infoButton.hidden);
+
+  item.infoButtonHidden = YES;
+  [item configureCell:cell withStyler:[[ChromeTableViewStyler alloc] init]];
+  EXPECT_TRUE(CheckCell.infoButton.hidden);
+}
+
+// Tests that infoButton won't be shown in case of a conflict.
+TEST_F(SettingsCheckItemTest, InfoButtonVisibilityDuringConflict) {
+  SettingsCheckItem* item = [[SettingsCheckItem alloc] initWithType:0];
+  item.text = @"Test Text";
+  item.detailText = @"Test Text";
+  item.enabled = YES;
+  item.indicatorHidden = NO;
+  item.infoButtonHidden = NO;
+
+  id cell = [[[item cellClass] alloc] init];
+  SettingsCheckCell* CheckCell =
+      base::mac::ObjCCastStrict<SettingsCheckCell>(cell);
+
+  [item configureCell:cell withStyler:[[ChromeTableViewStyler alloc] init]];
+  EXPECT_TRUE(CheckCell.infoButton.hidden);
+}
+
 }  // namespace
diff --git a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
index 48410376..5a05f54e 100644
--- a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
@@ -12,6 +12,7 @@
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/settings/cells/account_sign_in_item.h"
 #import "ios/chrome/browser/ui/settings/cells/copied_to_chrome_item.h"
+#import "ios/chrome/browser/ui/settings/cells/settings_check_cell.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_check_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h"
@@ -84,6 +85,7 @@
   ItemTypeCheck3,
   ItemTypeCheck4,
   ItemTypeCheck5,
+  ItemTypeCheck6,
 };
 }
 
@@ -412,8 +414,8 @@
       @"description.";
   checkFinished.enabled = YES;
   checkFinished.indicatorHidden = YES;
-  checkFinished.trailingImage = [[ChromeIcon infoIcon]
-      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  checkFinished.trailingImage =
+      [UIImage imageNamed:@"table_view_cell_check_mark"];
   [model addItem:checkFinished
       toSectionWithIdentifier:SectionIdentifierSettings];
 
@@ -426,9 +428,9 @@
   checkFinishedWithLeadingImage.leadingImage = [[ChromeIcon infoIcon]
       imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
   checkFinishedWithLeadingImage.enabled = YES;
-  checkFinishedWithLeadingImage.indicatorHidden = NO;
-  checkFinishedWithLeadingImage.trailingImage = [[ChromeIcon infoIcon]
-      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  checkFinishedWithLeadingImage.indicatorHidden = YES;
+  checkFinishedWithLeadingImage.trailingImage =
+      [UIImage imageNamed:@"table_view_cell_check_mark"];
   [model addItem:checkFinishedWithLeadingImage
       toSectionWithIdentifier:SectionIdentifierSettings];
 
@@ -454,6 +456,18 @@
   [model addItem:checkDisabledWithLeadingImage
       toSectionWithIdentifier:SectionIdentifierSettings];
 
+  SettingsCheckItem* checkWithInfoButton =
+      [[SettingsCheckItem alloc] initWithType:ItemTypeCheck6];
+  checkWithInfoButton.text = @"Check item with info ";
+  checkWithInfoButton.detailText =
+      @"This is very long description of check item. Another line of "
+      @"description.";
+  checkWithInfoButton.enabled = YES;
+  checkWithInfoButton.indicatorHidden = YES;
+  checkWithInfoButton.infoButtonHidden = NO;
+  [model addItem:checkWithInfoButton
+      toSectionWithIdentifier:SectionIdentifierSettings];
+
   TableViewLinkHeaderFooterItem* linkFooter =
       [[TableViewLinkHeaderFooterItem alloc] initWithType:ItemTypeLinkFooter];
   linkFooter.text =
@@ -570,6 +584,26 @@
       UIPopoverArrowDirectionAny;
 }
 
+// Called when the user clicks on the information button of the check item
+// setting's UI. Shows a textual bubble with the detailed information.
+- (void)didTapCheckInfoButton:(UIButton*)buttonView {
+  PopoverLabelViewController* popoverViewController =
+      [[PopoverLabelViewController alloc]
+          initWithMessage:@"You clicked settings check item. Here you can see "
+                          @"detailed information."];
+
+  // Set the anchor and arrow direction of the bubble.
+  popoverViewController.popoverPresentationController.sourceView = buttonView;
+  popoverViewController.popoverPresentationController.sourceRect =
+      buttonView.bounds;
+  popoverViewController.popoverPresentationController.permittedArrowDirections =
+      UIPopoverArrowDirectionAny;
+
+  [self presentViewController:popoverViewController
+                     animated:YES
+                   completion:nil];
+}
+
 #pragma mark - UITableViewDataSource
 
 - (UITableViewCell*)tableView:(UITableView*)tableView
@@ -586,6 +620,12 @@
     [managedCell.trailingButton addTarget:self
                                    action:@selector(didTapManagedUIInfoButton:)
                          forControlEvents:UIControlEventTouchUpInside];
+  } else if (itemType == ItemTypeCheck6) {
+    SettingsCheckCell* checkCell =
+        base::mac::ObjCCastStrict<SettingsCheckCell>(cell);
+    [checkCell.infoButton addTarget:self
+                             action:@selector(didTapCheckInfoButton:)
+                   forControlEvents:UIControlEventTouchUpInside];
   }
   return cell;
 }
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index 7922312..048f1c0 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -1200,8 +1200,7 @@
   std::string expiration_string;
   ASSERT_TRUE(broken_alt_svcs_list_entry->GetStringWithoutPathExpansion(
       "broken_until", &expiration_string));
-  broken_alt_svcs_list_entry->RemoveWithoutPathExpansion("broken_until",
-                                                         nullptr);
+  broken_alt_svcs_list_entry->RemoveKey("broken_until");
 
   // Expiration time of "www.google.com:1234" should be 5 minutes minus the
   // update-prefs-delay from when the prefs were written.
diff --git a/services/device/README.md b/services/device/README.md
new file mode 100644
index 0000000..14c0f02f
--- /dev/null
+++ b/services/device/README.md
@@ -0,0 +1,2 @@
+Provides cross-platform public interfaces and per-platform backing
+implementations of various features related to the user's physical device.
diff --git a/services/network/README.md b/services/network/README.md
index d9f0ca0..9cbb5bf 100644
--- a/services/network/README.md
+++ b/services/network/README.md
@@ -27,6 +27,7 @@
 # Related docs
 
 * [URLLoader](url_loader.md)
+* [Slides describing the relationship with the fetch spec](https://docs.google.com/presentation/d/1r9KHuYbNlgqQ6UABAMiWz0ONTpSTnMaDJ8UeYZGWjls/)
 
 # Where does the network service run?
 
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h
index f8698e8e..b6e9366 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h
@@ -20,11 +20,14 @@
 namespace memory_instrumentation {
 
 // This class provides synchronous access to memory metrics for a process with a
-// given |pid|. These interfaces have platform-specific restrictrions:
+// given |pid|. These interfaces have platform-specific restrictions:
 //  * On Android, due to sandboxing restrictions, processes can only access
 //    memory metrics for themselves. Thus |pid| must be equal to getpid().
 //  * On Linux, due to sandboxing restrictions, only the privileged browser
 //    process has access to memory metrics for sandboxed child processes.
+//  * On Fuchsia, due to the API expecting a ProcessId rather than a
+//    ProcessHandle, processes can only access memory metrics for themselves or
+//    for children of base::GetDefaultJob().
 //
 // These restrictions mean that any code that wishes to be cross-platform
 // compatible cannot synchronously obtain memory metrics for a |pid|. Instead,
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_fuchsia.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_fuchsia.cc
index bd14e67..42d7d86 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_fuchsia.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_fuchsia.cc
@@ -36,6 +36,8 @@
 
   dump->resident_set_kb = rss_bytes / 1024;
   dump->platform_private_footprint->rss_anon_bytes = rss_anon_bytes;
+  // Fuchsia has no swap.
+  dump->platform_private_footprint->vm_swap_bytes = 0;
   return true;
 }
 
diff --git a/third_party/android_sdk/androidx_browser/BUILD.gn b/third_party/android_sdk/androidx_browser/BUILD.gn
index de64136..06d5b224 100644
--- a/third_party/android_sdk/androidx_browser/BUILD.gn
+++ b/third_party/android_sdk/androidx_browser/BUILD.gn
@@ -23,6 +23,7 @@
     "./src/browser/browser/src/main/java/androidx/browser/trusted/NotificationApiHelperForM.java",
     "./src/browser/browser/src/main/java/androidx/browser/trusted/NotificationApiHelperForO.java",
     "./src/browser/browser/src/main/java/androidx/browser/trusted/PackageIdentityUtils.java",
+    "./src/browser/browser/src/main/java/androidx/browser/trusted/ScreenOrientation.java",
     "./src/browser/browser/src/main/java/androidx/browser/trusted/Token.java",
     "./src/browser/browser/src/main/java/androidx/browser/trusted/TokenContents.java",
     "./src/browser/browser/src/main/java/androidx/browser/trusted/TokenStore.java",
diff --git a/third_party/android_sdk/androidx_browser/README.chromium b/third_party/android_sdk/androidx_browser/README.chromium
index 122bc15..2e10fd3 100644
--- a/third_party/android_sdk/androidx_browser/README.chromium
+++ b/third_party/android_sdk/androidx_browser/README.chromium
@@ -1,7 +1,7 @@
 Name: AndroidX Browser
 Short Name: AndroidX Browser
 URL: https://chromium.googlesource.com/external/gob/android/platform/frameworks/support/browser
-Version: ac2f9c348999e8943567c6e4d50a82a5010ca263
+Version: 37242f782de8096e24dff528b1bcac55a364b756
 License: Apache 2.0
 Security Critical: yes
 License Android Compatible: yes
diff --git a/third_party/blink/common/manifest/manifest.cc b/third_party/blink/common/manifest/manifest.cc
index 252be9a..69c84bc7 100644
--- a/third_party/blink/common/manifest/manifest.cc
+++ b/third_party/blink/common/manifest/manifest.cc
@@ -42,6 +42,7 @@
 bool Manifest::IsEmpty() const {
   return name.is_null() && short_name.is_null() && start_url.is_empty() &&
          display == blink::mojom::DisplayMode::kUndefined &&
+         display_override.empty() &&
          orientation == device::mojom::ScreenOrientationLockType::DEFAULT &&
          icons.empty() && shortcuts.empty() && !share_target.has_value() &&
          related_applications.empty() && file_handlers.empty() &&
diff --git a/third_party/blink/common/manifest/manifest_mojom_traits.cc b/third_party/blink/common/manifest/manifest_mojom_traits.cc
index c86e168..6868385 100644
--- a/third_party/blink/common/manifest/manifest_mojom_traits.cc
+++ b/third_party/blink/common/manifest/manifest_mojom_traits.cc
@@ -91,6 +91,9 @@
   if (!data.ReadDisplay(&out->display))
     return false;
 
+  if (!data.ReadDisplayOverride(&out->display_override))
+    return false;
+
   if (!data.ReadOrientation(&out->orientation))
     return false;
 
diff --git a/third_party/blink/perf_tests/owp_storage/idb-put-all.html b/third_party/blink/perf_tests/owp_storage/idb-put-all.html
new file mode 100644
index 0000000..8b76aa2d
--- /dev/null
+++ b/third_party/blink/perf_tests/owp_storage/idb-put-all.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<title>IndexedDB Put Test</title>
+<script src="../resources/runner.js"></script>
+<script src="resources/shared.js"></script>
+<script>
+  deleteThenOpen('library',
+    (db) => {
+      const store1 = db.createObjectStore('books_with_index', {keyPath: 'isbn'})
+      store1.createIndex('by_title', 'title')
+      db.createObjectStore('books', {keyPath: 'isbn'})
+    },
+    () => {
+      const test = {
+        description: 'Benchmark modeling the IndexedDB activity of putting a'
+          + ' record into an object store using putAll',
+        unit: 'ms',
+        iterationCount: 20,
+        tracingCategories: 'IndexedDB',
+        traceEventsToMeasure: ['IDBObjectStore::putAll'],
+        path: 'resources/idb-put-all-runner.html'
+      }
+      PerfTestRunner.measurePageLoadTimeAfterDoneMessage(test);
+    }
+  );
+</script>
diff --git a/third_party/blink/perf_tests/owp_storage/resources/idb-put-all-runner.html b/third_party/blink/perf_tests/owp_storage/resources/idb-put-all-runner.html
new file mode 100644
index 0000000..1f6c404
--- /dev/null
+++ b/third_party/blink/perf_tests/owp_storage/resources/idb-put-all-runner.html
@@ -0,0 +1,60 @@
+<!doctype html>
+<title>IDB Put Runner</title>
+<script src="resources/shared.js"></script>
+<script>
+  const contents = [];
+  const blobs = [];
+  const values = [];
+
+  function chooseContent(i) {
+    return contents[i % 3];
+  }
+
+  function chooseBlob(i) {
+    return blobs[i % 4];
+  }
+
+  function chooseTitle(i) {
+    let smallTitle = ((i % 20).toString()).repeat(100);
+    let largeTitle = ((i % 20).toString()).repeat(2000);
+    let titles = [smallTitle, largeTitle]
+    return titles[i % 2]
+  }
+
+  function initHelperValues() {
+    contents.push(new Uint8Array(100));
+    contents.push(new Uint8Array(50000));
+    contents.push(new Uint8Array(150000));
+    blobs.push(null)
+    blobs.push(new Uint8Array(1000));
+    blobs.push(new Uint8Array(200000));
+    blobs.push(new Uint8Array(500000));
+    for(let i = 0; i < 100; i++) {
+        let content = chooseContent(i);
+        let blob = chooseBlob(i);
+        let title = chooseTitle(i);
+        values.push({isbn: i, content: content, blob: blob,
+          title: title, author: 'Fred'});
+    }
+  }
+
+  function start() {
+    const openRequest = window.indexedDB.open('library');
+    openRequest.onsuccess = function() {
+      const db = openRequest.result;
+      const txn = db.transaction(['books_with_index','books'],'readwrite');
+      const store1 = txn.objectStore('books_with_index');
+      const store2 = txn.objectStore('books');
+      logToDocumentBody('Starting Benchmark IDB putAll');
+      store1.putAll(values);
+      store2.putAll(values);
+      logToDocumentBody('Finished Benchmark IDB putAll');
+      txn.oncomplete = () => {
+        reportDone();
+      }
+    }
+  }
+
+  initHelperValues()
+  start();
+</script>
\ No newline at end of file
diff --git a/third_party/blink/public/common/manifest/manifest.h b/third_party/blink/public/common/manifest/manifest.h
index bac0690..ea05f81 100644
--- a/third_party/blink/public/common/manifest/manifest.h
+++ b/third_party/blink/public/common/manifest/manifest.h
@@ -173,6 +173,10 @@
   // present.
   blink::mojom::DisplayMode display = blink::mojom::DisplayMode::kUndefined;
 
+  // Empty if the parsing failed, the field was not present, or all the
+  // values inside the JSON array were invalid.
+  std::vector<blink::mojom::DisplayMode> display_override;
+
   // Set to device::mojom::ScreenOrientationLockType::DEFAULT if the parsing
   // failed or the field was not present.
   device::mojom::ScreenOrientationLockType orientation =
diff --git a/third_party/blink/public/common/manifest/manifest_mojom_traits.h b/third_party/blink/public/common/manifest/manifest_mojom_traits.h
index 8b10200a..c639c0d 100644
--- a/third_party/blink/public/common/manifest/manifest_mojom_traits.h
+++ b/third_party/blink/public/common/manifest/manifest_mojom_traits.h
@@ -71,6 +71,11 @@
     return manifest.display;
   }
 
+  static const std::vector<blink::mojom::DisplayMode> display_override(
+      const ::blink::Manifest& manifest) {
+    return manifest.display_override;
+  }
+
   static device::mojom::ScreenOrientationLockType orientation(
       const ::blink::Manifest& manifest) {
     return manifest.orientation;
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 65126c78..54d15898 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -605,6 +605,12 @@
       kTrustedTypesSinkViolation
       kTrustedTypesPolicyViolation
 
+  type SourceCodeLocation extends object
+    properties
+      string url
+      integer lineNumber
+      integer columnNumber
+
   type ContentSecurityPolicyIssueDetails extends object
     properties
       # The url not included in allowed sources.
@@ -613,6 +619,7 @@
       string violatedDirective
       ContentSecurityPolicyViolationType contentSecurityPolicyViolationType
       optional AffectedFrame frameAncestor
+      optional SourceCodeLocation sourceCodeLocation
 
   # A unique identifier for the type of issue. Each type may use one of the
   # optional fields in InspectorIssueDetails to convey more specific
diff --git a/third_party/blink/public/mojom/devtools/inspector_issue.mojom b/third_party/blink/public/mojom/devtools/inspector_issue.mojom
index f22d358..12a3152 100644
--- a/third_party/blink/public/mojom/devtools/inspector_issue.mojom
+++ b/third_party/blink/public/mojom/devtools/inspector_issue.mojom
@@ -79,6 +79,13 @@
   string violated_directive;
   ContentSecurityPolicyViolationType content_security_policy_violation_type;
   AffectedFrame? frame_ancestor;
+  SourceCodeLocation? source_code_location;
+};
+
+struct SourceCodeLocation {
+  string url;
+  uint32 line_number;
+  uint32 column_number;
 };
 
 enum SameSiteCookieOperation {
diff --git a/third_party/blink/public/mojom/feature_policy/PRESUBMIT.py b/third_party/blink/public/mojom/feature_policy/PRESUBMIT.py
index 4168800..77b0457 100644
--- a/third_party/blink/public/mojom/feature_policy/PRESUBMIT.py
+++ b/third_party/blink/public/mojom/feature_policy/PRESUBMIT.py
@@ -131,7 +131,7 @@
         mojom_messages = "{} are missing in mojom file.\n".format(
             list(mojom_missing_enums)) if mojom_missing_enums else ""
 
-        return [] if json5_enums == mojom_source_path else [
+        return [] if json5_enums == mojom_enums else [
             output_api.PresubmitPromptWarning(
                 "{} and {} are out of sync: {}{}".format(
                     json5_config_path, mojom_source_path, json5_messages,
diff --git a/third_party/blink/public/mojom/manifest/manifest.mojom b/third_party/blink/public/mojom/manifest/manifest.mojom
index 859da93d..65e41a5 100644
--- a/third_party/blink/public/mojom/manifest/manifest.mojom
+++ b/third_party/blink/public/mojom/manifest/manifest.mojom
@@ -24,6 +24,8 @@
 
   DisplayMode display;
 
+  array<DisplayMode> display_override;
+
   device.mojom.ScreenOrientationLockType orientation;
 
   array<ManifestImageResource> icons;
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
index a864e16..ad8cb22 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
@@ -551,7 +551,7 @@
 }
 
 // Replace unmatched surrogates with REPLACEMENT CHARACTER U+FFFD.
-String ReplaceUnmatchedSurrogates(const String& string) {
+String ReplaceUnmatchedSurrogates(String string) {
   // This roughly implements http://heycam.github.io/webidl/#dfn-obtain-unicode
   // but since Blink strings are 16-bits internally, the output is simply
   // re-encoded to UTF-16.
@@ -574,8 +574,8 @@
   unsigned i = 0;
 
   // 4. Initialize U to be an empty sequence of Unicode characters.
-  StringBuilder u;
-  u.ReserveCapacity(n);
+  StringBuffer<UChar> result(n);
+  UChar* u = result.Characters();
 
   // 5. While i < n:
   while (i < n) {
@@ -585,17 +585,17 @@
     if (U16_IS_SINGLE(c)) {
       // c < 0xD800 or c > 0xDFFF
       // Append to U the Unicode character with code point c.
-      u.Append(c);
+      u[i] = c;
     } else if (U16_IS_TRAIL(c)) {
       // 0xDC00 <= c <= 0xDFFF
       // Append to U a U+FFFD REPLACEMENT CHARACTER.
-      u.Append(kReplacementCharacter);
+      u[i] = kReplacementCharacter;
     } else {
       // 0xD800 <= c <= 0xDBFF
       DCHECK(U16_IS_LEAD(c));
       if (i == n - 1) {
         // 1. If i = n-1, then append to U a U+FFFD REPLACEMENT CHARACTER.
-        u.Append(kReplacementCharacter);
+        u[i] = kReplacementCharacter;
       } else {
         // 2. Otherwise, i < n-1:
         DCHECK_LT(i, n - 1);
@@ -607,13 +607,12 @@
           // ..2. Let b be d & 0x3FF.
           // ..3. Append to U the Unicode character with code point
           //      2^16+2^10*a+b.
-          u.Append(U16_GET_SUPPLEMENTARY(c, d));
-          // Blink: This is equivalent to u.append(c); u.append(d);
-          ++i;
+          u[i++] = c;
+          u[i] = d;
         } else {
           // 3. Otherwise, d < 0xDC00 or d > 0xDFFF. Append to U a U+FFFD
           //    REPLACEMENT CHARACTER.
-          u.Append(kReplacementCharacter);
+          u[i] = kReplacementCharacter;
         }
       }
     }
@@ -622,8 +621,8 @@
   }
 
   // 6. Return U.
-  DCHECK_EQ(u.length(), string.length());
-  return u.ToString();
+  DCHECK_EQ(i, string.length());
+  return String::Adopt(result);
 }
 
 XPathNSResolver* ToXPathNSResolver(ScriptState* script_state,
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h
index 9f80279..0ef5eab4 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h
@@ -325,7 +325,7 @@
 }
 
 // USVString conversion helper.
-CORE_EXPORT String ReplaceUnmatchedSurrogates(const String&);
+CORE_EXPORT String ReplaceUnmatchedSurrogates(String);
 
 // FIXME: Remove the special casing for XPathNSResolver.
 XPathNSResolver* ToXPathNSResolver(ScriptState*, v8::Local<v8::Value>);
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade.cc b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
index 323c0e1..a17473e 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
@@ -57,6 +57,14 @@
   return false;
 }
 
+// TODO(crbug.com/1105782): It is currently unclear how to handle 'revert'
+// at computed-value-time. For now we treat it as 'unset'.
+const CSSValue* TreatRevertAsUnset(const CSSValue* value) {
+  if (value && value->IsRevertValue())
+    return cssvalue::CSSUnsetValue::Create();
+  return value;
+}
+
 const CSSValue* Parse(const CSSProperty& property,
                       CSSParserTokenRange range,
                       const CSSParserContext* context) {
@@ -615,7 +623,7 @@
 
   if (ResolveTokensInto(data->Tokens(), resolver, sequence)) {
     if (const auto* parsed = Parse(property, sequence.TokenRange(), context))
-      return parsed;
+      return TreatRevertAsUnset(parsed);
   }
 
   return cssvalue::CSSUnsetValue::Create();
@@ -681,7 +689,7 @@
     // When using var() in a css-logical shorthand (e.g. margin-inline),
     // the longhands here will also be logical.
     if (unvisited_property == &ResolveSurrogate(longhand))
-      return parsed;
+      return TreatRevertAsUnset(parsed);
   }
 
   NOTREACHED();
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc b/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
index 14176e1..cc95a79 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
@@ -1776,6 +1776,37 @@
   EXPECT_EQ("150px", cascade2.ComputedValue("width"));
 }
 
+TEST_F(StyleCascadeTest, CSSWideKeywordsInFallbacks) {
+  {
+    TestCascade cascade(GetDocument());
+    cascade.Add("display:var(--u,initial)");
+    cascade.Add("margin:var(--u,initial)");
+    cascade.Apply();
+  }
+  {
+    TestCascade cascade(GetDocument());
+    cascade.Add("display:var(--u,inherit)");
+    cascade.Add("margin:var(--u,inherit)");
+    cascade.Apply();
+  }
+  {
+    TestCascade cascade(GetDocument());
+    cascade.Add("display:var(--u,unset)");
+    cascade.Add("margin:var(--u,unset)");
+    cascade.Apply();
+  }
+  {
+    TestCascade cascade(GetDocument());
+    cascade.Add("display:var(--u,revert)");
+    cascade.Add("margin:var(--u,revert)");
+    cascade.Apply();
+  }
+
+  // TODO(crbug.com/1105782): Specs and WPT are currently in conflict
+  // regarding the correct behavior here. For now this test just verifies
+  // that we don't crash.
+}
+
 TEST_F(StyleCascadeTest, RegisteredInitial) {
   RegisterProperty(GetDocument(), "--x", "<length>", "0px", false);
 
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index c9edc9d..c0ade72 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -6297,7 +6297,7 @@
   return true;
 }
 
-bool Document::IsValidName(const String& name) {
+bool Document::IsValidName(const StringView& name) {
   unsigned length = name.length();
   if (!length)
     return false;
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index c6eaa231..febf65a 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1051,7 +1051,7 @@
   // The following implements the rule from HTML 4 for what valid names are.
   // To get this right for all the XML cases, we probably have to improve this
   // or move it and make it sensitive to the type of document.
-  static bool IsValidName(const String&);
+  static bool IsValidName(const StringView&);
 
   // The following breaks a qualified name into a prefix and a local name.
   // It also does a validity check, and returns false if the qualified name
diff --git a/third_party/blink/renderer/core/dom/element-hot.cc b/third_party/blink/renderer/core/dom/element-hot.cc
index e96c851..6371b9b 100644
--- a/third_party/blink/renderer/core/dom/element-hot.cc
+++ b/third_party/blink/renderer/core/dom/element-hot.cc
@@ -18,13 +18,59 @@
 
 namespace blink {
 
-void Element::SynchronizeAttribute(const AtomicString& local_name) const {
+WTF::AtomicStringTable::WeakResult Element::WeakLowercaseIfNecessary(
+    const StringView& name) const {
+  if (LIKELY(IsHTMLElement() && IsA<HTMLDocument>(GetDocument()))) {
+#if defined(ARCH_CPU_ARMEL)
+    // The compiler on x64 and ARM32 produces code with very different
+    // performance characteristics for WeakFindLowercased(). On ARM, explicitly
+    // lowercasing the string into a new buffer before doing the lookup in the
+    // AtomicStringTable is ~15% faster than doing the WeakFindLowercased().
+    // This appears to be due to different inlining choices. Thus far, a
+    // single block of code that works well on both platforms hasn't been found
+    // so settling of an ifdef.
+    //
+    // TODO(ajwong): Figure out why this architecture divergence exists and
+    // remove.
+    StringView::StackBackingStore buf;
+    StringView lowered = name.LowerASCIIMaybeUsingBuffer(buf);
+    // TODO(ajwong): Why is this nearly 2x faster than calling the inlined
+    // WeakFind() which also does the same check?
+    if (LIKELY(lowered.IsAtomic())) {
+      return AtomicStringTable::WeakResult(lowered.SharedImpl());
+    } else {
+      return WTF::AtomicStringTable::Instance().WeakFind(lowered);
+    }
+#else
+    return WTF::AtomicStringTable::Instance().WeakFindLowercased(name);
+#endif
+  }
+
+  return WTF::AtomicStringTable::Instance().WeakFind(name);
+}
+
+// Note, SynchronizeAttributeHinted is safe to call between a WeakFind() and
+// a check on the AttributeCollection for the element even though it may
+// modify the AttributeCollection to insert a "style" attribute. The reason
+// is because html_names::kStyleAttr.LocalName() is an AtomicString
+// representing "style". This means the AtomicStringTable will always have
+// an entry for "style" and a `hint` that corresponds to
+// html_names::kStyleAttr.LocalName() will never refer to a deleted object
+// thus it is safe to insert html_names::kStyleAttr.LocalName() into the
+// AttributeCollection collection after the WeakFind() when `hint` is
+// referring to "style". A subsequent lookup will match itself correctly
+// without worry for UaF or false positives.
+void Element::SynchronizeAttributeHinted(
+    const StringView& local_name,
+    WTF::AtomicStringTable::WeakResult hint) const {
   // This version of SynchronizeAttribute() is streamlined for the case where
   // you don't have a full QualifiedName, e.g when called from DOM API.
   if (!GetElementData())
     return;
+  // TODO(ajwong): Does this unnecessarily synchronize style attributes on
+  // SVGElements?
   if (GetElementData()->style_attribute_is_dirty() &&
-      LowercaseIfNecessary(local_name) == html_names::kStyleAttr.LocalName()) {
+      hint == html_names::kStyleAttr.LocalName()) {
     DCHECK(IsStyledElement());
     SynchronizeStyleAttributeInternal();
     return;
@@ -40,62 +86,40 @@
     // svg_attributes_are_dirty_ remains true. This information is available in
     // the attribute->property map in SVGElement.
     To<SVGElement>(this)->SynchronizeSVGAttribute(
-        QualifiedName(g_null_atom, local_name, g_null_atom));
+        QualifiedName(g_null_atom, local_name.ToAtomicString(), g_null_atom));
   }
 }
 
-const AtomicString& Element::getAttribute(
-    const AtomicString& local_name) const {
+const AtomicString& Element::GetAttributeHinted(
+    const StringView& name,
+    WTF::AtomicStringTable::WeakResult hint) const {
   if (!GetElementData())
     return g_null_atom;
-  SynchronizeAttribute(local_name);
+  SynchronizeAttributeHinted(name, hint);
   if (const Attribute* attribute =
-          GetElementData()->Attributes().Find(LowercaseIfNecessary(local_name)))
+          GetElementData()->Attributes().FindHinted(name, hint))
     return attribute->Value();
   return g_null_atom;
 }
 
-std::pair<wtf_size_t, const QualifiedName>
-Element::LookupAttributeQNameInternal(const AtomicString& local_name) const {
-  AtomicString case_adjusted_local_name = LowercaseIfNecessary(local_name);
+std::pair<wtf_size_t, const QualifiedName> Element::LookupAttributeQNameHinted(
+    const StringView& name,
+    WTF::AtomicStringTable::WeakResult hint) const {
   if (!GetElementData()) {
     return std::make_pair(
         kNotFound,
-        QualifiedName(g_null_atom, case_adjusted_local_name, g_null_atom));
+        QualifiedName(g_null_atom, LowercaseIfNecessary(name.ToAtomicString()),
+                      g_null_atom));
   }
 
   AttributeCollection attributes = GetElementData()->Attributes();
-  wtf_size_t index = attributes.FindIndex(case_adjusted_local_name);
+  wtf_size_t index = attributes.FindIndexHinted(name, hint);
   return std::make_pair(
-      index,
-      index != kNotFound
-          ? attributes[index].GetName()
-          : QualifiedName(g_null_atom, case_adjusted_local_name, g_null_atom));
-}
-
-void Element::setAttribute(const AtomicString& local_name,
-                           const AtomicString& value,
-                           ExceptionState& exception_state) {
-  if (!Document::IsValidName(local_name)) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidCharacterError,
-        "'" + local_name + "' is not a valid attribute name.");
-    return;
-  }
-
-  SynchronizeAttribute(local_name);
-  wtf_size_t index;
-  QualifiedName q_name = QualifiedName::Null();
-  std::tie(index, q_name) = LookupAttributeQNameInternal(local_name);
-
-  String trusted_value =
-      TrustedTypesCheckFor(ExpectedTrustedTypeForAttribute(q_name), value,
-                           GetExecutionContext(), exception_state);
-  if (exception_state.HadException())
-    return;
-
-  SetAttributeInternal(index, q_name, AtomicString(trusted_value),
-                       kNotInSynchronizationOfLazyAttribute);
+      index, index != kNotFound
+                 ? attributes[index].GetName()
+                 : QualifiedName(g_null_atom,
+                                 LowercaseIfNecessary(name.ToAtomicString()),
+                                 g_null_atom));
 }
 
 void Element::setAttribute(const QualifiedName& name,
@@ -134,8 +158,35 @@
   SetAttributeInternal(index, name, value, kInSynchronizationOfLazyAttribute);
 }
 
-void Element::setAttribute(
-    const AtomicString& local_name,
+void Element::SetAttributeHinted(const StringView& local_name,
+                                 WTF::AtomicStringTable::WeakResult hint,
+                                 const AtomicString& value,
+                                 ExceptionState& exception_state) {
+  if (!Document::IsValidName(local_name)) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidCharacterError,
+        "'" + local_name + "' is not a valid attribute name.");
+    return;
+  }
+
+  SynchronizeAttributeHinted(local_name, hint);
+  wtf_size_t index;
+  QualifiedName q_name = QualifiedName::Null();
+  std::tie(index, q_name) = LookupAttributeQNameHinted(local_name, hint);
+
+  String trusted_value =
+      TrustedTypesCheckFor(ExpectedTrustedTypeForAttribute(q_name), value,
+                           GetExecutionContext(), exception_state);
+  if (exception_state.HadException())
+    return;
+
+  SetAttributeInternal(index, q_name, AtomicString(trusted_value),
+                       kNotInSynchronizationOfLazyAttribute);
+}
+
+void Element::SetAttributeHinted(
+    const StringView& local_name,
+    WTF::AtomicStringTable::WeakResult hint,
     const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURL&
         string_or_trusted,
     ExceptionState& exception_state) {
@@ -146,10 +197,10 @@
     return;
   }
 
-  SynchronizeAttribute(local_name);
+  SynchronizeAttributeHinted(local_name, hint);
   wtf_size_t index;
   QualifiedName q_name = QualifiedName::Null();
-  std::tie(index, q_name) = LookupAttributeQNameInternal(local_name);
+  std::tie(index, q_name) = LookupAttributeQNameHinted(local_name, hint);
   String value = TrustedTypesCheckFor(ExpectedTrustedTypeForAttribute(q_name),
                                       string_or_trusted, GetExecutionContext(),
                                       exception_state);
@@ -263,14 +314,14 @@
   return old_attr_node;
 }
 
-void Element::removeAttribute(const AtomicString& name) {
+void Element::RemoveAttributeHinted(const StringView& name,
+                                    WTF::AtomicStringTable::WeakResult hint) {
   if (!GetElementData())
     return;
 
-  AtomicString local_name = LowercaseIfNecessary(name);
-  wtf_size_t index = GetElementData()->Attributes().FindIndex(local_name);
+  wtf_size_t index = GetElementData()->Attributes().FindIndexHinted(name, hint);
   if (index == kNotFound) {
-    if (UNLIKELY(local_name == html_names::kStyleAttr) &&
+    if (UNLIKELY(hint == html_names::kStyleAttr.LocalName()) &&
         GetElementData()->style_attribute_is_dirty() && IsStyledElement())
       RemoveAllInlineStyleProperties();
     return;
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index b451687..5921624 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -971,13 +971,17 @@
 }
 
 bool Element::HasAttributeIgnoringNamespace(
-    const AtomicString& local_name) const {
+    const StringView& local_name) const {
   if (!GetElementData())
     return false;
-  SynchronizeAttribute(local_name);
-  AtomicString name = LowercaseIfNecessary(local_name);
+  WTF::AtomicStringTable::WeakResult hint =
+      WeakLowercaseIfNecessary(local_name);
+  SynchronizeAttributeHinted(local_name, hint);
+  if (hint.IsNull()) {
+    return false;
+  }
   for (const Attribute& attribute : GetElementData()->Attributes()) {
-    if (attribute.LocalName() == name)
+    if (hint == attribute.LocalName())
       return true;
   }
   return false;
@@ -2055,21 +2059,22 @@
   // 2. If the context object is in the HTML namespace and its node document is
   // an HTML document, then set qualifiedName to qualifiedName in ASCII
   // lowercase.
-  AtomicString lower_case_name = LowercaseIfNecessary(qualified_name);
+  AtomicString lowercase_name = LowercaseIfNecessary(qualified_name);
+  WTF::AtomicStringTable::WeakResult hint(lowercase_name.Impl());
   // 3. Let attribute be the first attribute in the context object’s attribute
   // list whose qualified name is qualifiedName, and null otherwise.
   // 4. If attribute is null, then
-  if (!getAttribute(lower_case_name)) {
+  if (!GetAttributeHinted(lowercase_name, hint)) {
     // 4. 1. If force is not given or is true, create an attribute whose local
-    // name is qualifiedName, value is the empty string, and node document is
+    // name is qualified_name, value is the empty string, and node document is
     // the context object’s node document, then append this attribute to the
     // context object, and then return true.
-    setAttribute(lower_case_name, g_empty_atom);
+    SetAttributeHinted(lowercase_name, hint, g_empty_atom);
     return true;
   }
   // 5. Otherwise, if force is not given or is false, remove an attribute given
   // qualifiedName and the context object, and then return false.
-  removeAttribute(lower_case_name);
+  RemoveAttributeHinted(lowercase_name, hint);
   return false;
 }
 
@@ -2088,17 +2093,18 @@
   // 2. If the context object is in the HTML namespace and its node document is
   // an HTML document, then set qualifiedName to qualifiedName in ASCII
   // lowercase.
-  AtomicString lower_case_name = LowercaseIfNecessary(qualified_name);
+  AtomicString lowercase_name = LowercaseIfNecessary(qualified_name);
+  WTF::AtomicStringTable::WeakResult hint(lowercase_name.Impl());
   // 3. Let attribute be the first attribute in the context object’s attribute
   // list whose qualified name is qualifiedName, and null otherwise.
   // 4. If attribute is null, then
-  if (!getAttribute(lower_case_name)) {
+  if (!GetAttributeHinted(lowercase_name, hint)) {
     // 4. 1. If force is not given or is true, create an attribute whose local
-    // name is qualifiedName, value is the empty string, and node document is
+    // name is qualified_name, value is the empty string, and node document is
     // the context object’s node document, then append this attribute to the
     // context object, and then return true.
     if (force) {
-      setAttribute(lower_case_name, g_empty_atom);
+      SetAttributeHinted(lowercase_name, hint, g_empty_atom);
       return true;
     }
     // 4. 2. Return false.
@@ -2107,7 +2113,7 @@
   // 5. Otherwise, if force is not given or is false, remove an attribute given
   // qualifiedName and the context object, and then return false.
   if (!force) {
-    removeAttribute(lower_case_name);
+    RemoveAttributeHinted(lowercase_name, hint);
     return false;
   }
   // 6. Return true.
@@ -3803,12 +3809,14 @@
   removeAttribute(QualifiedName(g_null_atom, local_name, namespace_uri));
 }
 
-Attr* Element::getAttributeNode(const AtomicString& local_name) {
+Attr* Element::getAttributeNode(const StringView& local_name) {
   if (!GetElementData())
     return nullptr;
-  SynchronizeAttribute(local_name);
+  WTF::AtomicStringTable::WeakResult hint =
+      WeakLowercaseIfNecessary(local_name);
+  SynchronizeAttributeHinted(local_name, hint);
   const Attribute* attribute =
-      GetElementData()->Attributes().Find(LowercaseIfNecessary(local_name));
+      GetElementData()->Attributes().FindHinted(local_name, hint);
   if (!attribute)
     return nullptr;
   return EnsureAttr(attribute->GetName());
@@ -3826,12 +3834,14 @@
   return EnsureAttr(attribute->GetName());
 }
 
-bool Element::hasAttribute(const AtomicString& local_name) const {
+bool Element::hasAttribute(const StringView& local_name) const {
   if (!GetElementData())
     return false;
-  SynchronizeAttribute(local_name);
-  return GetElementData()->Attributes().FindIndex(
-             LowercaseIfNecessary(local_name)) != kNotFound;
+  WTF::AtomicStringTable::WeakResult hint =
+      WeakLowercaseIfNecessary(local_name);
+  SynchronizeAttributeHinted(local_name, hint);
+  return GetElementData()->Attributes().FindIndexHinted(local_name, hint) !=
+         kNotFound;
 }
 
 bool Element::hasAttributeNS(const AtomicString& namespace_uri,
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index b6137852..63948946 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -41,6 +41,7 @@
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string_table.h"
 
 namespace blink {
 
@@ -213,25 +214,35 @@
 #endif
   bool hasAttributes() const;
 
-  bool hasAttribute(const AtomicString& name) const;
+  bool hasAttribute(const StringView& name) const;
   bool hasAttributeNS(const AtomicString& namespace_uri,
                       const AtomicString& local_name) const;
 
   // Ignores namespace.
-  bool HasAttributeIgnoringNamespace(const AtomicString& local_name) const;
+  bool HasAttributeIgnoringNamespace(const StringView& local_name) const;
 
-  const AtomicString& getAttribute(const AtomicString& name) const;
+  const AtomicString& getAttribute(const StringView& local_name) const {
+    return GetAttributeHinted(local_name, WeakLowercaseIfNecessary(local_name));
+  }
+
   const AtomicString& getAttributeNS(const AtomicString& namespace_uri,
                                      const AtomicString& local_name) const;
 
-  void setAttribute(const AtomicString& name,
+  void setAttribute(const StringView& name,
                     const AtomicString& value,
-                    ExceptionState& = ASSERT_NO_EXCEPTION);
+                    ExceptionState& exception_state = ASSERT_NO_EXCEPTION) {
+    SetAttributeHinted(name, WeakLowercaseIfNecessary(name), value,
+                       exception_state);
+  }
 
   // Trusted Types variant for explicit setAttribute() use.
-  void setAttribute(const AtomicString&,
-                    const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURL&,
-                    ExceptionState&);
+  void setAttribute(const StringView& name,
+                    const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURL&
+                        string_or_trusted,
+                    ExceptionState& exception_state) {
+    SetAttributeHinted(name, WeakLowercaseIfNecessary(name), string_or_trusted,
+                       exception_state);
+  }
 
   // Returns attributes that should be checked against Trusted Types
   virtual const AttrNameToTrustedType& GetCheckedAttributeTypes() const;
@@ -262,6 +273,8 @@
   //   document, then set qualifiedName to qualifiedName in ASCII lowercase.
   //   https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name
   AtomicString LowercaseIfNecessary(const AtomicString&) const;
+  WTF::AtomicStringTable::WeakResult WeakLowercaseIfNecessary(
+      const StringView&) const;
 
   // NoncedElement implementation: this is only used by HTMLElement and
   // SVGElement, but putting the implementation here allows us to use
@@ -332,13 +345,15 @@
 
   void DidMoveToNewDocument(Document&) override;
 
-  void removeAttribute(const AtomicString& name);
+  void removeAttribute(const StringView& name) {
+    RemoveAttributeHinted(name, WeakLowercaseIfNecessary(name));
+  }
   void removeAttributeNS(const AtomicString& namespace_uri,
                          const AtomicString& local_name);
 
   Attr* DetachAttribute(wtf_size_t index);
 
-  Attr* getAttributeNode(const AtomicString& name);
+  Attr* getAttributeNode(const StringView& name);
   Attr* getAttributeNodeNS(const AtomicString& namespace_uri,
                            const AtomicString& local_name);
   Attr* setAttributeNode(Attr*, ExceptionState&);
@@ -854,7 +869,10 @@
   ElementAnimations& EnsureElementAnimations();
   bool HasAnimations() const;
 
-  void SynchronizeAttribute(const AtomicString& local_name) const;
+  void SynchronizeAttribute(const StringView& local_name) const {
+    SynchronizeAttributeHinted(local_name,
+                               WeakLowercaseIfNecessary(local_name));
+  }
 
   MutableCSSPropertyValueSet& EnsureMutableInlineStyle();
   void ClearMutableInlineStyleIfEmpty();
@@ -1087,11 +1105,37 @@
                                SynchronizationOfLazyAttribute);
   void RemoveAttributeInternal(wtf_size_t index,
                                SynchronizationOfLazyAttribute);
-  std::pair<wtf_size_t, const QualifiedName> LookupAttributeQNameInternal(
-      const AtomicString& local_name) const;
   SpecificTrustedType ExpectedTrustedTypeForAttribute(
       const QualifiedName&) const;
 
+  // These Hinted versions of the functions are subtle hot path
+  // optimizations designed to reduce the number of unnecessary AtomicString
+  // creations, AtomicStringTable lookups, and LowerCaseIfNecessary calls.
+  //
+  // The `hint` is the result of a WeakLowercaseIfNecessary() call unless it is
+  // known that the the incoming string already has the right case. Then
+  // the `hint` can be constructed from calling AtomicString::Impl().
+  const AtomicString& GetAttributeHinted(
+      const StringView& name,
+      WTF::AtomicStringTable::WeakResult hint) const;
+  void RemoveAttributeHinted(const StringView& name,
+                             WTF::AtomicStringTable::WeakResult hint);
+  void SynchronizeAttributeHinted(
+      const StringView& name,
+      WTF::AtomicStringTable::WeakResult hint) const;
+  void SetAttributeHinted(const StringView& name,
+                          WTF::AtomicStringTable::WeakResult hint,
+                          const AtomicString& value,
+                          ExceptionState& = ASSERT_NO_EXCEPTION);
+  void SetAttributeHinted(
+      const StringView& name,
+      WTF::AtomicStringTable::WeakResult hint,
+      const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURL&,
+      ExceptionState&);
+  std::pair<wtf_size_t, const QualifiedName> LookupAttributeQNameHinted(
+      const StringView& name,
+      WTF::AtomicStringTable::WeakResult hint) const;
+
   void CancelFocusAppearanceUpdate();
   virtual int DefaultTabIndex() const;
 
diff --git a/third_party/blink/renderer/core/dom/named_node_map.cc b/third_party/blink/renderer/core/dom/named_node_map.cc
index b69b487a..a1f061e 100644
--- a/third_party/blink/renderer/core/dom/named_node_map.cc
+++ b/third_party/blink/renderer/core/dom/named_node_map.cc
@@ -45,8 +45,9 @@
 
 Attr* NamedNodeMap::removeNamedItem(const AtomicString& name,
                                     ExceptionState& exception_state) {
-  wtf_size_t index =
-      element_->Attributes().FindIndex(element_->LowercaseIfNecessary(name));
+  WTF::AtomicStringTable::WeakResult hint =
+      element_->WeakLowercaseIfNecessary(name);
+  wtf_size_t index = element_->Attributes().FindIndexHinted(name, hint);
   if (index == kNotFound) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kNotFoundError,
diff --git a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
index 2bbd35cd..a62692e 100644
--- a/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
+++ b/third_party/blink/renderer/core/editing/serializers/markup_accumulator.cc
@@ -300,7 +300,7 @@
     // 12.5.1. If the local prefixes map contains a key matching prefix, then
     // let prefix be the result of generating a prefix providing as input map,
     // ns, and prefix index
-    if (element.hasAttribute(WTF::g_xmlns_with_colon + prefix)) {
+    if (element.hasAttribute(String(WTF::g_xmlns_with_colon + prefix))) {
       prefix = GeneratePrefix(ns);
     } else {
       // 12.5.2. Add prefix to map given namespace ns.
diff --git a/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc b/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc
index ba8b939e..d9bc279 100644
--- a/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc
+++ b/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc
@@ -16,6 +16,11 @@
 
 namespace blink {
 
+bool FeatureAvailable(const String& feature, ExecutionContext* ec) {
+  return GetDefaultFeatureNameMap().Contains(feature) &&
+         (!DisabledByOriginTrial(feature, ec));
+}
+
 DOMFeaturePolicy::DOMFeaturePolicy(ExecutionContext* context)
     : context_(context) {}
 
@@ -23,7 +28,7 @@
                                      const String& feature) const {
   ExecutionContext* execution_context =
       script_state ? ExecutionContext::From(script_state) : nullptr;
-  if (GetAvailableFeatures(execution_context).Contains(feature)) {
+  if (FeatureAvailable(feature, execution_context)) {
     auto feature_name = GetDefaultFeatureNameMap().at(feature);
     return GetPolicy()->IsFeatureEnabled(feature_name);
   }
@@ -47,7 +52,7 @@
     return false;
   }
 
-  if (!GetAvailableFeatures(execution_context).Contains(feature)) {
+  if (!FeatureAvailable(feature, execution_context)) {
     AddWarningForUnrecognizedFeature(feature);
     return false;
   }
@@ -81,7 +86,7 @@
     const String& feature) const {
   ExecutionContext* execution_context =
       script_state ? ExecutionContext::From(script_state) : nullptr;
-  if (GetAvailableFeatures(execution_context).Contains(feature)) {
+  if (FeatureAvailable(feature, execution_context)) {
     auto feature_name = GetDefaultFeatureNameMap().at(feature);
 
     const FeaturePolicy::Allowlist allowlist =
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index 6c67329..a27547a5 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -1147,7 +1147,7 @@
   if (delegate_)
     delegate_->DispatchViolationEvent(*violation_data, element);
 
-  ReportContentSecurityPolicyIssue(blocked_url, directive_text, violation_type,
+  ReportContentSecurityPolicyIssue(*violation_data, violation_type,
                                    context_frame);
 }
 
@@ -1423,13 +1423,15 @@
 }
 
 void ContentSecurityPolicy::ReportContentSecurityPolicyIssue(
-    const KURL& blocked_url,
-    String violated_directive,
+    const blink::SecurityPolicyViolationEventInit& violation_data,
     ContentSecurityPolicyViolationType violation_type,
     LocalFrame* frame_ancestor) {
   auto cspDetails = mojom::blink::ContentSecurityPolicyIssueDetails::New();
-  cspDetails->blocked_url = blocked_url;
-  cspDetails->violated_directive = violated_directive;
+  if (violation_type == ContentSecurityPolicyViolationType::kURLViolation ||
+      violation_data.violatedDirective() == "frame-ancestors") {
+    cspDetails->blocked_url = KURL(violation_data.blockedURI());
+  }
+  cspDetails->violated_directive = violation_data.violatedDirective();
   cspDetails->content_security_policy_violation_type =
       BuildCSPViolationType(violation_type);
   if (frame_ancestor) {
@@ -1438,6 +1440,14 @@
         frame_ancestor->GetDevToolsFrameToken().ToString().c_str();
     cspDetails->frame_ancestor = std::move(affected_frame);
   }
+  if (violation_data.sourceFile() && violation_data.lineNumber()) {
+    auto source_code_location = mojom::blink::SourceCodeLocation::New();
+    source_code_location->url = violation_data.sourceFile();
+    // The frontend expects 0-based line numbers.
+    source_code_location->line_number = violation_data.lineNumber() - 1;
+    source_code_location->column_number = violation_data.columnNumber();
+    cspDetails->source_code_location = std::move(source_code_location);
+  }
 
   auto details = mojom::blink::InspectorIssueDetails::New();
   details->csp_issue_details = std::move(cspDetails);
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index 9508309f..7985122 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -576,8 +576,7 @@
       ContentSecurityPolicy::ContentSecurityPolicyViolationType violation_type);
 
   void ReportContentSecurityPolicyIssue(
-      const KURL&,
-      String violated_directive,
+      const blink::SecurityPolicyViolationEventInit& violation_data,
       ContentSecurityPolicyViolationType violation_type,
       LocalFrame* = nullptr);
 
diff --git a/third_party/blink/renderer/core/html/forms/image_input_type.cc b/third_party/blink/renderer/core/html/forms/image_input_type.cc
index 27f89ccb..152d42f 100644
--- a/third_party/blink/renderer/core/html/forms/image_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/image_input_type.cc
@@ -105,10 +105,6 @@
   event.SetDefaultHandled();
 }
 
-bool ImageInputType::TypeShouldForceLegacyLayout() const {
-  return true;
-}
-
 LayoutObject* ImageInputType::CreateLayoutObject(const ComputedStyle& style,
                                                  LegacyLayout legacy) const {
   if (use_fallback_content_) {
diff --git a/third_party/blink/renderer/core/html/forms/image_input_type.h b/third_party/blink/renderer/core/html/forms/image_input_type.h
index 647923dc7..112ea7a9 100644
--- a/third_party/blink/renderer/core/html/forms/image_input_type.h
+++ b/third_party/blink/renderer/core/html/forms/image_input_type.h
@@ -50,7 +50,6 @@
   void AppendToFormData(FormData&) const override;
   String ResultForDialogSubmit() const override;
   bool SupportsValidation() const override;
-  bool TypeShouldForceLegacyLayout() const override;
   LayoutObject* CreateLayoutObject(const ComputedStyle&,
                                    LegacyLayout) const override;
   void HandleDOMActivateEvent(Event&) override;
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc b/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
index b02a043..77b5e75 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
@@ -423,7 +423,8 @@
 void InspectorAuditsAgent::InspectorIssueAdded(InspectorIssue* issue) {
   auto issueDetails = protocol::Audits::InspectorIssueDetails::create();
 
-  if (const auto* d = issue->Details()->samesite_cookie_issue_details.get()) {
+  if (issue->Details()->samesite_cookie_issue_details) {
+    const auto* d = issue->Details()->samesite_cookie_issue_details.get();
     auto sameSiteCookieDetails =
         std::move(protocol::Audits::SameSiteCookieIssueDetails::create()
                       .setCookie(BuildAffectedCookie(d->cookie))
@@ -445,7 +446,8 @@
     issueDetails.setSameSiteCookieIssueDetails(sameSiteCookieDetails.build());
   }
 
-  if (const auto* d = issue->Details()->mixed_content_issue_details.get()) {
+  if (issue->Details()->mixed_content_issue_details) {
+    const auto* d = issue->Details()->mixed_content_issue_details.get();
     auto mixedContentDetails =
         protocol::Audits::MixedContentIssueDetails::create()
             .setResourceType(BuildMixedContentResourceType(d->request_context))
@@ -463,8 +465,8 @@
     issueDetails.setMixedContentIssueDetails(std::move(mixedContentDetails));
   }
 
-  if (const auto* d =
-          issue->Details()->blocked_by_response_issue_details.get()) {
+  if (issue->Details()->blocked_by_response_issue_details) {
+    const auto* d = issue->Details()->blocked_by_response_issue_details.get();
     auto blockedByResponseDetails =
         protocol::Audits::BlockedByResponseIssueDetails::create()
             .setRequest(BuildAffectedRequest(d->request))
@@ -477,7 +479,8 @@
         std::move(blockedByResponseDetails));
   }
 
-  if (const auto* d = issue->Details()->csp_issue_details.get()) {
+  if (issue->Details()->csp_issue_details) {
+    const auto* d = issue->Details()->csp_issue_details.get();
     auto cspDetails =
         std::move(protocol::Audits::ContentSecurityPolicyIssueDetails::create()
                       .setViolatedDirective(d->violated_directive)
@@ -488,6 +491,15 @@
     }
     if (d->frame_ancestor)
       cspDetails.setFrameAncestor(BuildAffectedFrame(d->frame_ancestor));
+    if (d->source_code_location) {
+      auto source_location =
+          protocol::Audits::SourceCodeLocation::create()
+              .setUrl(d->source_code_location->url)
+              .setColumnNumber(d->source_code_location->column_number)
+              .setLineNumber(d->source_code_location->line_number)
+              .build();
+      cspDetails.setSourceCodeLocation(std::move(source_location));
+    }
     issueDetails.setContentSecurityPolicyIssueDetails(cspDetails.build());
   }
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
index 5bba8dc..ae012f96 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
@@ -2323,6 +2323,11 @@
 
   element->UpdateDistributionForUnknownReasons();
 
+  // This ensures that active stylesheets are up-to-date, such that
+  // the subsequent collection of matching rules actually match against
+  // the correct RuleSets.
+  element->GetDocument().UpdateStyleAndLayoutTreeForNode(element);
+
   HeapVector<Member<CSSStyleRule>> rules =
       FilterDuplicateRules(style_resolver.PseudoCSSRulesForElement(
           element, pseudo_id, StyleResolver::kAllCSSRules));
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc
index 1b7a9fd..a323e95 100644
--- a/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -92,13 +92,23 @@
 // keeping track of containing blocks at that time is complicated (we are in
 // the middle of recomputing the style so we can't rely on any of its
 // information), which is why it's easier to just update it for every layout.
-static TrackedDescendantsMap* g_positioned_descendants_map = nullptr;
-static TrackedContainerMap* g_positioned_container_map = nullptr;
+TrackedDescendantsMap& GetPositionedDescendantsMap() {
+  DEFINE_STATIC_LOCAL(TrackedDescendantsMap, map, ());
+  return map;
+}
+
+TrackedContainerMap& GetPositionedContainerMap() {
+  DEFINE_STATIC_LOCAL(TrackedContainerMap, map, ());
+  return map;
+}
 
 // This map keeps track of the descendants whose 'height' is percentage
 // associated with a containing block. Like |gPositionedDescendantsMap|, it is
 // also recomputed for every layout (see the comment above about why).
-static TrackedDescendantsMap* g_percent_height_descendants_map = nullptr;
+static TrackedDescendantsMap& GetPercentHeightDescendantsMap() {
+  DEFINE_STATIC_LOCAL(TrackedDescendantsMap, map, ());
+  return map;
+}
 
 LayoutBlock::LayoutBlock(ContainerNode* node)
     : LayoutBox(node),
@@ -123,16 +133,16 @@
 void LayoutBlock::RemoveFromGlobalMaps() {
   if (HasPositionedObjects()) {
     std::unique_ptr<TrackedLayoutBoxListHashSet> descendants =
-        g_positioned_descendants_map->Take(this);
+        GetPositionedDescendantsMap().Take(this);
     DCHECK(!descendants->IsEmpty());
     for (LayoutBox* descendant : *descendants) {
-      DCHECK_EQ(g_positioned_container_map->at(descendant), this);
-      g_positioned_container_map->erase(descendant);
+      DCHECK_EQ(GetPositionedContainerMap().at(descendant), this);
+      GetPositionedContainerMap().erase(descendant);
     }
   }
   if (HasPercentHeightDescendants()) {
     std::unique_ptr<TrackedLayoutBoxListHashSet> descendants =
-        g_percent_height_descendants_map->Take(this);
+        GetPercentHeightDescendantsMap().Take(this);
     DCHECK(!descendants->IsEmpty());
     for (LayoutBox* descendant : *descendants) {
       DCHECK_EQ(descendant->PercentHeightContainer(), this);
@@ -947,8 +957,7 @@
 }
 
 TrackedLayoutBoxListHashSet* LayoutBlock::PositionedObjectsInternal() const {
-  return g_positioned_descendants_map ? g_positioned_descendants_map->at(this)
-                                      : nullptr;
+  return GetPositionedDescendantsMap().at(this);
 }
 
 void LayoutBlock::InsertPositionedObject(LayoutBox* o) {
@@ -957,29 +966,23 @@
 
   o->ClearOverrideContainingBlockContentSize();
 
-  if (g_positioned_container_map) {
-    auto container_map_it = g_positioned_container_map->find(o);
-    if (container_map_it != g_positioned_container_map->end()) {
-      if (container_map_it->value == this) {
-        DCHECK(HasPositionedObjects());
-        DCHECK(PositionedObjects()->Contains(o));
-        PositionedObjects()->AppendOrMoveToLast(o);
-        return;
-      }
-      RemovePositionedObject(o);
+  auto container_map_it = GetPositionedContainerMap().find(o);
+  if (container_map_it != GetPositionedContainerMap().end()) {
+    if (container_map_it->value == this) {
+      DCHECK(HasPositionedObjects());
+      DCHECK(PositionedObjects()->Contains(o));
+      PositionedObjects()->AppendOrMoveToLast(o);
+      return;
     }
-  } else {
-    g_positioned_container_map = new TrackedContainerMap;
+    RemovePositionedObject(o);
   }
-  g_positioned_container_map->Set(o, this);
+  GetPositionedContainerMap().Set(o, this);
 
-  if (!g_positioned_descendants_map)
-    g_positioned_descendants_map = new TrackedDescendantsMap;
   TrackedLayoutBoxListHashSet* descendant_set =
-      g_positioned_descendants_map->at(this);
+      GetPositionedDescendantsMap().at(this);
   if (!descendant_set) {
     descendant_set = new TrackedLayoutBoxListHashSet;
-    g_positioned_descendants_map->Set(this, base::WrapUnique(descendant_set));
+    GetPositionedDescendantsMap().Set(this, base::WrapUnique(descendant_set));
   }
   descendant_set->insert(o);
 
@@ -987,20 +990,17 @@
 }
 
 void LayoutBlock::RemovePositionedObject(LayoutBox* o) {
-  if (!g_positioned_container_map)
-    return;
-
-  LayoutBlock* container = g_positioned_container_map->Take(o);
+  LayoutBlock* container = GetPositionedContainerMap().Take(o);
   if (!container)
     return;
 
   TrackedLayoutBoxListHashSet* positioned_descendants =
-      g_positioned_descendants_map->at(container);
+      GetPositionedDescendantsMap().at(container);
   DCHECK(positioned_descendants);
   DCHECK(positioned_descendants->Contains(o));
   positioned_descendants->erase(o);
   if (positioned_descendants->IsEmpty()) {
-    g_positioned_descendants_map->erase(container);
+    GetPositionedDescendantsMap().erase(container);
     container->has_positioned_objects_ = false;
   }
 }
@@ -1083,12 +1083,12 @@
   }
 
   for (auto* object : dead_objects) {
-    DCHECK_EQ(g_positioned_container_map->at(object), this);
+    DCHECK_EQ(GetPositionedContainerMap().at(object), this);
     positioned_descendants->erase(object);
-    g_positioned_container_map->erase(object);
+    GetPositionedContainerMap().erase(object);
   }
   if (positioned_descendants->IsEmpty()) {
-    g_positioned_descendants_map->erase(this);
+    GetPositionedDescendantsMap().erase(this);
     has_positioned_objects_ = false;
   }
 }
@@ -1122,14 +1122,12 @@
     cb = cb->ContainingBlock();
   }
 
-  if (!g_percent_height_descendants_map)
-    g_percent_height_descendants_map = new TrackedDescendantsMap;
   TrackedLayoutBoxListHashSet* descendant_set =
-      g_percent_height_descendants_map->at(this);
+      GetPercentHeightDescendantsMap().at(this);
   if (!descendant_set) {
     descendant_set = new TrackedLayoutBoxListHashSet;
-    g_percent_height_descendants_map->Set(this,
-                                          base::WrapUnique(descendant_set));
+    GetPercentHeightDescendantsMap().Set(this,
+                                         base::WrapUnique(descendant_set));
   }
   descendant_set->insert(descendant);
 
@@ -1141,7 +1139,7 @@
     descendants->erase(descendant);
     descendant->SetPercentHeightContainer(nullptr);
     if (descendants->IsEmpty()) {
-      g_percent_height_descendants_map->erase(this);
+      GetPercentHeightDescendantsMap().erase(this);
       has_percent_height_descendants_ = false;
     }
   }
@@ -1149,9 +1147,7 @@
 
 TrackedLayoutBoxListHashSet* LayoutBlock::PercentHeightDescendantsInternal()
     const {
-  return g_percent_height_descendants_map
-             ? g_percent_height_descendants_map->at(this)
-             : nullptr;
+  return GetPercentHeightDescendantsMap().at(this);
 }
 
 void LayoutBlock::DirtyForLayoutFromPercentageHeightDescendants(
@@ -2256,9 +2252,6 @@
 
 #if DCHECK_IS_ON()
 void LayoutBlock::CheckPositionedObjectsNeedLayout() {
-  if (!g_positioned_descendants_map)
-    return;
-
   if (LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
     return;
 
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 160a215..3059723f 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2590,6 +2590,12 @@
   }
   const auto& fragment = To<NGPhysicalBoxFragment>(result->PhysicalFragment());
   layout_results_.push_back(std::move(result));
+#if DCHECK_IS_ON()
+  for (const NGPhysicalBoxFragment& fragment : PhysicalFragments()) {
+    if (const NGFragmentItems* fragment_items = fragment.Items())
+      fragment_items->CheckAllItemsAreValid();
+  }
+#endif
   // If this is the last fragment for the node, and its node establishes an
   // inline formatting context, we have some finalization to do.
   if (!fragment.BreakToken() && fragment.Items())
@@ -2622,6 +2628,12 @@
     }
   }
   layout_results_[index] = std::move(result);
+#if DCHECK_IS_ON()
+  for (const NGPhysicalBoxFragment& fragment : PhysicalFragments()) {
+    if (const NGFragmentItems* fragment_items = fragment.Items())
+      fragment_items->CheckAllItemsAreValid();
+  }
+#endif
   // If this is the last fragment for the node, and its node establishes an
   // inline formatting context, we have some finalization to do.
   if (!fragment.BreakToken() && fragment.Items() && (index || got_new_fragment))
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index d87b328..f87f8509 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -79,7 +79,10 @@
 // is the next pointer associated with the key.
 typedef HashMap<const LayoutBoxModelObject*, LayoutBoxModelObject*>
     ContinuationMap;
-static ContinuationMap* g_continuation_map = nullptr;
+static ContinuationMap& GetContinuationMap() {
+  DEFINE_STATIC_LOCAL(ContinuationMap, map, ());
+  return map;
+}
 
 void LayoutBoxModelObject::ContentChanged(ContentChangeType change_type) {
   if (!HasLayer())
@@ -1243,18 +1246,15 @@
 }
 
 LayoutBoxModelObject* LayoutBoxModelObject::Continuation() const {
-  return (!g_continuation_map) ? nullptr : g_continuation_map->at(this);
+  return GetContinuationMap().at(this);
 }
 
 void LayoutBoxModelObject::SetContinuation(LayoutBoxModelObject* continuation) {
   if (continuation) {
     DCHECK(continuation->IsLayoutInline() || continuation->IsLayoutBlockFlow());
-    if (!g_continuation_map)
-      g_continuation_map = new ContinuationMap;
-    g_continuation_map->Set(this, continuation);
+    GetContinuationMap().Set(this, continuation);
   } else {
-    if (g_continuation_map)
-      g_continuation_map->erase(this);
+    GetContinuationMap().erase(this);
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index cc577b1..07d348d 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -92,7 +92,10 @@
 
 class SecureTextTimer;
 typedef HashMap<LayoutText*, SecureTextTimer*> SecureTextTimerMap;
-static SecureTextTimerMap* g_secure_text_timers = nullptr;
+static SecureTextTimerMap& GetSecureTextTimers() {
+  DEFINE_STATIC_LOCAL(SecureTextTimerMap, map, ());
+  return map;
+}
 
 class SecureTextTimer final : public TimerBase {
  public:
@@ -115,7 +118,7 @@
 
  private:
   void Fired() override {
-    DCHECK(g_secure_text_timers->Contains(layout_text_));
+    DCHECK(GetSecureTextTimers().Contains(layout_text_));
     // Forcing setting text as it may be masked later
     layout_text_->ForceSetText(layout_text_->GetText().Impl());
   }
@@ -254,8 +257,7 @@
 }
 
 void LayoutText::WillBeDestroyed() {
-  if (SecureTextTimer* secure_text_timer =
-          g_secure_text_timers ? g_secure_text_timers->Take(this) : nullptr)
+  if (SecureTextTimer* secure_text_timer = GetSecureTextTimers().Take(this))
     delete secure_text_timer;
 
   if (node_id_ != kInvalidDOMNodeId) {
@@ -1920,8 +1922,7 @@
 
   int last_typed_character_offset_to_reveal = -1;
   UChar revealed_text;
-  SecureTextTimer* secure_text_timer =
-      g_secure_text_timers ? g_secure_text_timers->at(this) : nullptr;
+  SecureTextTimer* secure_text_timer = GetSecureTextTimers().at(this);
   if (secure_text_timer && secure_text_timer->IsActive()) {
     last_typed_character_offset_to_reveal =
         secure_text_timer->LastTypedCharacterOffset();
@@ -2484,13 +2485,10 @@
 
 void LayoutText::MomentarilyRevealLastTypedCharacter(
     unsigned last_typed_character_offset) {
-  if (!g_secure_text_timers)
-    g_secure_text_timers = new SecureTextTimerMap;
-
-  SecureTextTimer* secure_text_timer = g_secure_text_timers->at(this);
+  SecureTextTimer* secure_text_timer = GetSecureTextTimers().at(this);
   if (!secure_text_timer) {
     secure_text_timer = new SecureTextTimer(this);
-    g_secure_text_timers->insert(this, secure_text_timer);
+    GetSecureTextTimers().insert(this, secure_text_timer);
   }
   secure_text_timer->RestartWithNewText(last_typed_character_offset);
 }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
index 861d64e..18bb18d1 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
@@ -334,4 +334,11 @@
   }
 }
 
+#if DCHECK_IS_ON()
+void NGFragmentItems::CheckAllItemsAreValid() const {
+  for (const NGFragmentItem& item : Items())
+    DCHECK(!item.IsLayoutObjectDestroyedOrMoved());
+}
+#endif
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h
index 244c207..55ddaad 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h
@@ -77,6 +77,10 @@
   }
   wtf_size_t ByteSize() const { return ByteSizeFor(Size()); }
 
+#if DCHECK_IS_ON()
+  void CheckAllItemsAreValid() const;
+#endif
+
  private:
   const NGFragmentItem* ItemsData() const { return items_; }
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index 8524b349..fd91a99f 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -2006,6 +2006,24 @@
     // and may not be equal to |results[new_end].start_offset|.
     MoveToNextOf(item_results[new_end - 1]);
     trailing_whitespace_ = WhitespaceState::kUnknown;
+    // When space item is followed by empty text, we will break line at empty
+    // text. See http://crbug.com/1104534
+    // Example:
+    //   [0] kOpeNTag 0-0 <i>
+    //   [1] kText 0-10 "012345679"
+    //   [2] kOpenTag 10-10 <b> <= |item_results[new_end - 1]|
+    //   [3] kText 10-10 ""     <= |item_index_|
+    //   [4] kText 10-11 " "
+    //   [5] kCloseTag 11-11 <b>
+    //   [6] kText 11-13 "ab"
+    //   [7] kCloseTag 13-13 <i>
+    // Note: We can have multiple empty |LayoutText| by ::first-letter, nested
+    // <q>, Text.splitText(), etc.
+    const Vector<NGInlineItem>& items = Items();
+    while (item_index_ < items.size() &&
+           items[item_index_].Type() == NGInlineItem::kText &&
+           !items[item_index_].Length())
+      HandleEmptyText(items[item_index_], line_info);
   } else {
     // When rewinding all items, use |results[0].start_offset|.
     const NGInlineItemResult& first_remove = item_results[new_end];
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
index 54b6f64..719c827 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h"
 
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h"
@@ -544,6 +545,34 @@
   EXPECT_EQ(sizes.max_size, LayoutUnit(110));
 }
 
+// For http://crbug.com/1104534
+TEST_F(NGLineBreakerTest, SplitTextZero) {
+  // Note: |V8TestingScope| is needed for |Text::splitText()|.
+  V8TestingScope scope;
+
+  LoadAhem();
+  NGInlineNode node = CreateInlineNode(R"HTML(
+    <!DOCTYPE html>
+    <style>
+    #container {
+      font: 10px/1 Ahem;
+      overflow-wrap: break-word;
+    }
+    </style>
+    <div id=container>0123456789<b id=target> </b>ab</i></div>
+  )HTML");
+
+  To<Text>(GetElementById("target")->firstChild())
+      ->splitText(0, ASSERT_NO_EXCEPTION);
+  UpdateAllLifecyclePhasesForTest();
+
+  Vector<std::pair<String, unsigned>> lines;
+  lines = BreakLines(node, LayoutUnit(100));
+  EXPECT_EQ(2u, lines.size());
+  EXPECT_EQ("0123456789", lines[0].first);
+  EXPECT_EQ("ab", lines[1].first);
+}
+
 TEST_F(NGLineBreakerTest, TableCellWidthCalculationQuirkOutOfFlow) {
   NGInlineNode node = CreateInlineNode(R"HTML(
     <style>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 4de21e1..078ee4f 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -126,7 +126,8 @@
 }
 
 void NGOutOfFlowLayoutPart::Run(const LayoutBox* only_layout) {
-  if (container_builder_->IsBlockFragmentationContextRoot()) {
+  if (container_builder_->IsBlockFragmentationContextRoot() &&
+      container_builder_->HasOutOfFlowFragmentainerDescendants()) {
     Vector<NGLogicalOutOfFlowPositionedNode> fragmentainer_descendants;
     container_builder_->SwapOutOfFlowFragmentainerDescendants(
         &fragmentainer_descendants);
@@ -135,20 +136,20 @@
       LayoutFragmentainerDescendants(&fragmentainer_descendants);
   }
 
-  Vector<NGLogicalOutOfFlowPositionedNode> candidates;
   const LayoutObject* current_container = container_builder_->GetLayoutObject();
+  if (!container_builder_->HasOutOfFlowPositionedCandidates() &&
+      !To<LayoutBlock>(current_container)->HasPositionedObjects())
+    return;
+
   // If the container is display-locked, then we skip the layout of descendants,
   // so we can early out immediately.
   if (current_container->LayoutBlockedByDisplayLock(
           DisplayLockLifecycleTarget::kChildren))
     return;
 
+  Vector<NGLogicalOutOfFlowPositionedNode> candidates;
   container_builder_->SwapOutOfFlowPositionedCandidates(&candidates);
 
-  if (candidates.IsEmpty() &&
-      !To<LayoutBlock>(current_container)->HasPositionedObjects())
-    return;
-
   // Special case: containing block is a split inline.
   // If current container was generated by a split inline, do not position
   // OOF-positioned nodes inside this container. Let its non-anonymous parent
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
index bb4df44..e326e390 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
@@ -104,6 +104,8 @@
       for (NGInlineCursor cursor(*items); cursor; cursor.MoveToNext()) {
         DCHECK(cursor.Current().Item());
         const NGFragmentItem& item = *cursor.Current().Item();
+        if (UNLIKELY(item.IsLayoutObjectDestroyedOrMoved()))
+          continue;
         if (item.Type() == NGFragmentItem::kLine) {
           AddOutlineRectsForDescendant(
               {item.LineBoxFragment(), item.OffsetInContainerBlock()},
@@ -256,6 +258,7 @@
     const PhysicalOffset& additional_offset,
     NGOutlineType outline_type,
     const LayoutBoxModelObject* containing_block) const {
+  DCHECK(!descendant->IsLayoutObjectDestroyedOrMoved());
   if (descendant->IsText() || descendant->IsListMarker())
     return;
 
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
index 5e0c12c..cfb9e9e 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -82,6 +82,7 @@
   manifest_->start_url = ParseStartURL(root_object.get());
   manifest_->scope = ParseScope(root_object.get(), manifest_->start_url);
   manifest_->display = ParseDisplay(root_object.get());
+  manifest_->display_override = ParseDisplayOverride(root_object.get());
   manifest_->orientation = ParseOrientation(root_object.get());
   manifest_->icons = ParseIcons(root_object.get());
 
@@ -306,6 +307,39 @@
   return display_enum;
 }
 
+Vector<mojom::blink::DisplayMode> ManifestParser::ParseDisplayOverride(
+    const JSONObject* object) {
+  Vector<mojom::blink::DisplayMode> display_override;
+  if (!RuntimeEnabledFeatures::DisplayOverrideEnabled())
+    return display_override;
+
+  JSONValue* json_value = object->Get("display_override");
+  if (!json_value)
+    return display_override;
+
+  JSONArray* display_override_list = object->GetArray("display_override");
+  if (!display_override_list) {
+    AddErrorInfo("property 'display_override' ignored, type array expected.");
+    return display_override;
+  }
+
+  for (wtf_size_t i = 0; i < display_override_list->size(); ++i) {
+    String display_enum_string;
+    // AsString will return an empty string if a type error occurs,
+    // which will cause DisplayModeFromString to return kUndefined,
+    // resulting in this entry being ignored.
+    display_override_list->at(i)->AsString(&display_enum_string);
+    display_enum_string = display_enum_string.StripWhiteSpace();
+    mojom::blink::DisplayMode display_enum =
+        DisplayModeFromString(display_enum_string.Utf8());
+
+    if (display_enum != mojom::blink::DisplayMode::kUndefined)
+      display_override.push_back(display_enum);
+  }
+
+  return display_override;
+}
+
 device::mojom::blink::ScreenOrientationLockType
 ManifestParser::ParseOrientation(const JSONObject* object) {
   base::Optional<String> orientation = ParseString(object, "orientation", Trim);
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.h b/third_party/blink/renderer/modules/manifest/manifest_parser.h
index 5d9bc81a..79e11c9 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser.h
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.h
@@ -131,6 +131,13 @@
   // parsing failed.
   blink::mojom::DisplayMode ParseDisplay(const JSONObject* object);
 
+  // Parses the 'display_override' field of the manifest.
+  // https://github.com/WICG/display-override/blob/master/explainer.md
+  // Returns a vector of the parsed DisplayMode if any, an empty vector if
+  // the field was not present or empty.
+  Vector<mojom::blink::DisplayMode> ParseDisplayOverride(
+      const JSONObject* object);
+
   // Parses the 'orientation' field of the manifest, as defined in:
   // https://w3c.github.io/manifest/#dfn-steps-for-processing-the-orientation-member
   // Returns the parsed device::mojom::blink::ScreenOrientationLockType if any,
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc b/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
index f458bb1..e09876dd 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser_unittest.cc
@@ -507,7 +507,7 @@
     EXPECT_EQ(0u, GetErrorCount());
   }
 
-  // Accept 'fullscreen'.
+  // Accept 'standalone'.
   {
     auto& manifest = ParseManifest("{ \"display\": \"standalone\" }");
     EXPECT_EQ(manifest->display, blink::mojom::DisplayMode::kStandalone);
@@ -536,6 +536,133 @@
   }
 }
 
+TEST_F(ManifestParserTest, DisplayOverrideParseRules) {
+  // Smoke test: if no display_override, no value.
+  {
+    auto& manifest = ParseManifest("{ \"display_override\": [] }");
+    EXPECT_TRUE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+
+  // Smoke test: if not array, value will be ignored
+  {
+    auto& manifest = ParseManifest("{ \"display_override\": 23 }");
+    EXPECT_TRUE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(1u, GetErrorCount());
+    EXPECT_EQ("property 'display_override' ignored, type array expected.",
+              errors()[0]);
+  }
+
+  // Smoke test: if array value is not a string, it will be ignored
+  {
+    auto& manifest = ParseManifest("{ \"display_override\": [ 23 ] }");
+    EXPECT_TRUE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+
+  // Smoke test: if array value is not not recognized, it will be ignored
+  {
+    auto& manifest = ParseManifest("{ \"display_override\": [ \"test\" ] }");
+    EXPECT_TRUE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+
+  // Case insensitive
+  {
+    auto& manifest = ParseManifest("{ \"display_override\": [ \"BROWSER\" ] }");
+    EXPECT_FALSE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(manifest->display_override[0],
+              blink::mojom::DisplayMode::kBrowser);
+    EXPECT_FALSE(IsManifestEmpty(manifest));
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+
+  // Trim whitespace
+  {
+    auto& manifest =
+        ParseManifest("{ \"display_override\": [ \" browser \" ] }");
+    EXPECT_FALSE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(manifest->display_override[0],
+              blink::mojom::DisplayMode::kBrowser);
+    EXPECT_FALSE(IsManifestEmpty(manifest));
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+
+  // Accept 'browser'
+  {
+    auto& manifest = ParseManifest("{ \"display_override\": [ \"browser\" ] }");
+    EXPECT_FALSE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(manifest->display_override[0],
+              blink::mojom::DisplayMode::kBrowser);
+    EXPECT_FALSE(IsManifestEmpty(manifest));
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+
+  // Accept 'browser', 'minimal-ui'
+  {
+    auto& manifest = ParseManifest(
+        "{ \"display_override\": [ \"browser\", \"minimal-ui\" ] }");
+    EXPECT_FALSE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(manifest->display_override[0],
+              blink::mojom::DisplayMode::kBrowser);
+    EXPECT_EQ(manifest->display_override[1],
+              blink::mojom::DisplayMode::kMinimalUi);
+    EXPECT_FALSE(IsManifestEmpty(manifest));
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+
+  // if array value is not not recognized, it will be ignored
+  // Accept 'browser', 'minimal-ui'
+  {
+    auto& manifest = ParseManifest(
+        "{ \"display_override\": [ 3, \"browser\", \"invalid-display\", "
+        "\"minimal-ui\" ] }");
+    EXPECT_FALSE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(manifest->display_override[0],
+              blink::mojom::DisplayMode::kBrowser);
+    EXPECT_EQ(manifest->display_override[1],
+              blink::mojom::DisplayMode::kMinimalUi);
+    EXPECT_FALSE(IsManifestEmpty(manifest));
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+
+  // validate both display and display-override fields are parsed
+  // if array value is not not recognized, it will be ignored
+  // Accept 'browser', 'minimal-ui', 'standalone'
+  {
+    auto& manifest = ParseManifest(
+        "{ \"display\": \"standalone\", \"display_override\": [ \"browser\", "
+        "\"minimal-ui\", \"standalone\" ] }");
+    EXPECT_EQ(manifest->display, blink::mojom::DisplayMode::kStandalone);
+    EXPECT_EQ(0u, GetErrorCount());
+    EXPECT_FALSE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(manifest->display_override[0],
+              blink::mojom::DisplayMode::kBrowser);
+    EXPECT_EQ(manifest->display_override[1],
+              blink::mojom::DisplayMode::kMinimalUi);
+    EXPECT_EQ(manifest->display_override[2],
+              blink::mojom::DisplayMode::kStandalone);
+    EXPECT_FALSE(IsManifestEmpty(manifest));
+  }
+
+  // validate duplicate entries.
+  // Accept 'browser', 'minimal-ui', 'browser'
+  {
+    auto& manifest = ParseManifest(
+        "{ \"display_override\": [ \"browser\", \"minimal-ui\", "
+        "\"browser\" ] }");
+    EXPECT_FALSE(manifest->display_override.IsEmpty());
+    EXPECT_EQ(manifest->display_override[0],
+              blink::mojom::DisplayMode::kBrowser);
+    EXPECT_EQ(manifest->display_override[1],
+              blink::mojom::DisplayMode::kMinimalUi);
+    EXPECT_EQ(manifest->display_override[2],
+              blink::mojom::DisplayMode::kBrowser);
+    EXPECT_FALSE(IsManifestEmpty(manifest));
+    EXPECT_EQ(0u, GetErrorCount());
+  }
+}
+
 TEST_F(ManifestParserTest, OrientationParseRules) {
   // Smoke test.
   {
diff --git a/third_party/blink/renderer/modules/webshare/navigator_share.cc b/third_party/blink/renderer/modules/webshare/navigator_share.cc
index 4e2c345..520b1a5 100644
--- a/third_party/blink/renderer/modules/webshare/navigator_share.cc
+++ b/third_party/blink/renderer/modules/webshare/navigator_share.cc
@@ -203,19 +203,19 @@
   }
 
   LocalDOMWindow* window = LocalDOMWindow::From(script_state);
-  KURL url;
-  if (!CanShareInternal(*window, *data, url, &exception_state)) {
-    DCHECK(exception_state.HadException());
-    return ScriptPromise();
-  }
-
-  if (!LocalFrame::HasTransientUserActivation(window->GetFrame())) {
+  if (!LocalFrame::ConsumeTransientUserActivation(window->GetFrame())) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kNotAllowedError,
         "Must be handling a user gesture to perform a share request.");
     return ScriptPromise();
   }
 
+  KURL url;
+  if (!CanShareInternal(*window, *data, url, &exception_state)) {
+    DCHECK(exception_state.HadException());
+    return ScriptPromise();
+  }
+
   if (!service_remote_.is_bound()) {
     // See https://bit.ly/2S0zRAS for task types.
     window->GetFrame()->GetBrowserInterfaceBroker().GetInterface(
diff --git a/third_party/blink/renderer/platform/loader/README.md b/third_party/blink/renderer/platform/loader/README.md
index 0b1c49a..49a5e3d 100644
--- a/third_party/blink/renderer/platform/loader/README.md
+++ b/third_party/blink/renderer/platform/loader/README.md
@@ -15,6 +15,10 @@
 needed to use them from `core/`.  Otherwise they can be used only in
 `platform/`.
 
+The directory conceptually implements https://fetch.spec.whatwg.org/#fetching
+(with lower-level components such as the network service). See also: [slides
+describing the relationship with the fetch spec](https://docs.google.com/presentation/d/1r9KHuYbNlgqQ6UABAMiWz0ONTpSTnMaDJ8UeYZGWjls/)
+
 ## testing
 
 Contains helper files for testing that are available in both
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index d1e7c1e..c18a358a 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -648,6 +648,10 @@
       settable_from_internals: true,
     },
     {
+      name: "DisplayOverride",
+      status: "test",
+    },
+    {
       name: "DocumentCookie",
     },
     {
diff --git a/third_party/blink/renderer/platform/scheduler/BUILD.gn b/third_party/blink/renderer/platform/scheduler/BUILD.gn
index 2684aeca..22550984 100644
--- a/third_party/blink/renderer/platform/scheduler/BUILD.gn
+++ b/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -61,8 +61,6 @@
     "common/web_resource_loading_task_runner_handle.cc",
     "common/web_thread_scheduler.cc",
     "common/worker_pool.cc",
-    "main_thread/agent_interference_recorder.cc",
-    "main_thread/agent_interference_recorder.h",
     "main_thread/agent_scheduling_strategy.cc",
     "main_thread/agent_scheduling_strategy.h",
     "main_thread/attribution_group.h",
@@ -221,7 +219,6 @@
     "common/tracing_helper_unittest.cc",
     "common/ukm_task_sampler_unittest.cc",
     "common/worker_pool_unittest.cc",
-    "main_thread/agent_interference_recorder_unittest.cc",
     "main_thread/agent_scheduling_strategy_unittest.cc",
     "main_thread/auto_advancing_virtual_time_domain_unittest.cc",
     "main_thread/deadline_task_runner_unittest.cc",
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder.cc b/third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder.cc
deleted file mode 100644
index 54866e1..0000000
--- a/third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder.cc
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder.h"
-
-#include <algorithm>
-
-#include "base/metrics/histogram_functions.h"
-#include "base/rand_util.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
-
-namespace blink {
-namespace scheduler {
-
-namespace {
-
-// Park–Miller random number generator. Not secure, used only for sampling.
-// https://en.wikipedia.org/wiki/Lehmer_random_number_generator
-uint32_t GetNextRandomNumber(uint32_t previous_value) {
-  constexpr uint32_t kModulo = (1U << 31) - 1;
-  return 48271 * static_cast<int64_t>(previous_value) % kModulo;
-}
-
-}  // namespace
-
-AgentInterferenceRecorder::AgentInterferenceRecorder(int sampling_rate)
-    : sampling_rate_(sampling_rate),
-      random_value_(static_cast<uint32_t>(base::RandUint64())) {}
-
-AgentInterferenceRecorder::~AgentInterferenceRecorder() = default;
-
-void AgentInterferenceRecorder::OnTaskReady(
-    const void* frame_scheduler,
-    base::sequence_manager::EnqueueOrder enqueue_order,
-    base::sequence_manager::LazyNow* lazy_now) {
-  if (!ShouldSampleNextReadyTask())
-    return;
-
-  if (!frame_scheduler)
-    return;
-
-  base::AutoLock auto_lock(lock_);
-
-  DCHECK(!base::Contains(ready_tasks_, enqueue_order));
-  ReadyTask& ready_task = ready_tasks_[enqueue_order];
-  ready_task.time_for_all_agents_when_ready = time_for_all_agents_;
-  ready_task.agent_data_when_ready = agent_data_;
-#if DCHECK_IS_ON()
-  ready_task.frame_scheduler = frame_scheduler;
-#endif
-
-  // If the currently running task is associated with an agent, adjust the
-  // clock readings in |ready_task| to include its execution time.
-  if (!agent_cluster_id_for_current_task_)
-    return;
-
-  base::TimeDelta running_time = GetCurrentAgentTaskRunningTime(lazy_now);
-  // Clamp the value above zero to handle the case where the time in |lazy_now|
-  // was captured after the current main thread task started running.
-  running_time = std::max(base::TimeDelta(), running_time);
-
-  ready_task.time_for_all_agents_when_ready += running_time;
-  auto agent_data_it =
-      ready_task.agent_data_when_ready.find(agent_cluster_id_for_current_task_);
-  // The agent may have been destroyed before the task completes.
-  if (agent_data_it != ready_task.agent_data_when_ready.end()) {
-    agent_data_it->second.accumulated_running_time += running_time;
-  }
-}
-
-void AgentInterferenceRecorder::OnTaskStarted(
-    MainThreadTaskQueue* queue,
-    base::sequence_manager::EnqueueOrder enqueue_order,
-    base::TimeTicks start_time) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::AutoLock auto_lock(lock_);
-  DCHECK(current_task_start_time_.is_null());
-  DCHECK(!agent_cluster_id_for_current_task_);
-
-  const FrameScheduler* frame_scheduler =
-      queue ? GetFrameSchedulerForQueue(queue) : nullptr;
-  const base::UnguessableToken agent_cluster_id =
-      queue ? GetAgentClusterIdForQueue(queue) : base::UnguessableToken();
-
-  // Insert a default AgentData if there's no value for |agent_cluster_id|.
-  if (agent_cluster_id)
-    agent_data_.emplace(agent_cluster_id, AgentData{});
-
-  auto ready_task_it = ready_tasks_.find(enqueue_order);
-  if (ready_task_it != ready_tasks_.end()) {
-    RecordHistogramForReadyTask(ready_task_it->second, queue, frame_scheduler,
-                                agent_cluster_id, enqueue_order);
-    ready_tasks_.erase(ready_task_it);
-  }
-
-  current_task_start_time_ = start_time;
-  agent_cluster_id_for_current_task_ = agent_cluster_id;
-
-  if (!frame_scheduler)
-    return;
-
-  // Maintain the mapping from frame to agent cluster id.
-  auto frame_to_agent_it = frame_to_agent_cluster_id_.find(frame_scheduler);
-  // If the frame is already tracked and has the same agent as before.
-  if (frame_to_agent_it != frame_to_agent_cluster_id_.end() &&
-      frame_to_agent_it->value == agent_cluster_id) {
-    return;
-  }
-  // If the frame is already tracked, but has a new agent.
-  if (frame_to_agent_it != frame_to_agent_cluster_id_.end()) {
-    DecrementNumFramesForAgent(frame_to_agent_it->value);
-    frame_to_agent_it->value = agent_cluster_id;
-  } else {
-    // If the frame was not tracked before.
-    frame_to_agent_cluster_id_.insert(frame_scheduler, agent_cluster_id);
-  }
-  DCHECK_EQ(frame_to_agent_cluster_id_.find(frame_scheduler)->value,
-            agent_cluster_id);
-  // If the frame was not tracked before, or was tracked but has a new agent.
-  if (agent_cluster_id)
-    ++agent_data_.at(agent_cluster_id).frame_count;
-}
-
-void AgentInterferenceRecorder::OnTaskCompleted(MainThreadTaskQueue* queue,
-                                                base::TimeTicks end_time) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::AutoLock auto_lock(lock_);
-  DCHECK(!end_time.is_null());
-
-  base::sequence_manager::LazyNow lazy_now(end_time);
-  AccumulateCurrentTaskRunningTime(&lazy_now);
-  current_task_start_time_ = base::TimeTicks();
-  agent_cluster_id_for_current_task_ = base::UnguessableToken();
-}
-
-void AgentInterferenceRecorder::OnFrameSchedulerDestroyed(
-    const FrameScheduler* frame_scheduler) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::AutoLock auto_lock(lock_);
-
-  auto frame_to_agent_it = frame_to_agent_cluster_id_.find(frame_scheduler);
-  if (frame_to_agent_it == frame_to_agent_cluster_id_.end())
-    return;
-  DecrementNumFramesForAgent(frame_to_agent_it->value);
-  frame_to_agent_cluster_id_.erase(frame_to_agent_it);
-}
-
-void AgentInterferenceRecorder::AccumulateCurrentTaskRunningTime(
-    base::sequence_manager::LazyNow* lazy_now) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!current_task_start_time_.is_null());
-
-  if (!agent_cluster_id_for_current_task_)
-    return;
-
-  // Update clocks.
-  const base::TimeDelta running_time = GetCurrentAgentTaskRunningTime(lazy_now);
-  DCHECK_GE(running_time, base::TimeDelta());
-
-  time_for_all_agents_ += running_time;
-
-  auto agent_data_it = agent_data_.find(agent_cluster_id_for_current_task_);
-  // The agent may have been destroyed before the task completes.
-  if (agent_data_it != agent_data_.end()) {
-    agent_data_it->second.accumulated_running_time += running_time;
-    DCHECK_GE(time_for_all_agents_,
-              agent_data_it->second.accumulated_running_time);
-  }
-}
-
-base::TimeDelta AgentInterferenceRecorder::GetCurrentAgentTaskRunningTime(
-    base::sequence_manager::LazyNow* lazy_now) const {
-  DCHECK(agent_cluster_id_for_current_task_);
-  DCHECK(!current_task_start_time_.is_null());
-  return lazy_now->Now() - current_task_start_time_;
-}
-
-uint32_t AgentInterferenceRecorder::ShouldSampleNextReadyTask() {
-  uint32_t previous_random_value =
-      random_value_.load(std::memory_order_relaxed);
-  uint32_t next_random_value;
-  do {
-    next_random_value = GetNextRandomNumber(previous_random_value);
-  } while (!random_value_.compare_exchange_weak(
-      previous_random_value, next_random_value, std::memory_order_relaxed));
-  return next_random_value % sampling_rate_ == 0;
-}
-
-void AgentInterferenceRecorder::RecordHistogramForReadyTask(
-    const ReadyTask& ready_task,
-    const MainThreadTaskQueue* queue,
-    const FrameScheduler* frame_scheduler,
-    const base::UnguessableToken& agent_cluster_id,
-    base::sequence_manager::EnqueueOrder enqueue_order) {
-  // Record the histogram if the task is associated with an agent and wasn't
-  // blocked by a fence or by the TaskQueue being disabled.
-  if (agent_cluster_id.is_empty() ||
-      enqueue_order < queue->GetEnqueueOrderAtWhichWeBecameUnblocked()) {
-    return;
-  }
-
-#if DCHECK_IS_ON()
-  DCHECK_EQ(frame_scheduler, ready_task.frame_scheduler);
-#endif
-
-  // |time_for_all_agents_since_ready| and |time_for_this_agent_since_ready| are
-  // clamped above zero to mitigate this problem:
-  //
-  // X = initial |time_for_all_agents_|.
-  //
-  // Thread 1: Captures time T1.
-  //           Invokes OnTaskStarted with T1.
-  //           Captures time T2.
-  // Thread 2: Captures time T3.
-  //           Invokes OnTaskReady with T3. [*]
-  //             |time_for_all_agents_when_ready| = X + T3 - T1
-  //             (Ready task is from the same agent as the running task)
-  // Thread 1: Invokes OnTaskCompleted with T2.
-  //             |time_for_all_agents_| += T2 - T1
-  //           Invokes OnTaskStarted for the next task.
-  //             |time_for_all_agent_since_ready|
-  //                 = |time_for_all_agents_| - |time_for_all_agents_when_ready|
-  //                 = (X + T2 - T1) - (X + T3 - T1)
-  //                 = T2 - T3
-  //             Which is a negative value.
-  //
-  // |time_for_other_agents_since_ready| is clamped above zero for the case
-  // where the ready and running tasks are not from the same agent at [*]. In
-  // that case, |ready_task.time_for_all_agents_when_ready| was incremented with
-  // the current task's running time, but not
-  // |ready_task.time_for_this_agents_when_ready|, which can cause
-  // |time_for_this_agent_since_ready| to be greater than
-  // |time_for_all_agents_since_ready|.
-  //
-  // Note: These problem exists because OnTask*() methods use times captured
-  // outside the scope of |lock_|.
-  auto time_for_this_agent_when_ready_it =
-      ready_task.agent_data_when_ready.find(agent_cluster_id);
-  const base::TimeDelta time_for_this_agent_when_ready =
-      time_for_this_agent_when_ready_it ==
-              ready_task.agent_data_when_ready.end()
-          ? base::TimeDelta()
-          : time_for_this_agent_when_ready_it->second.accumulated_running_time;
-
-  DCHECK_GE(ready_task.time_for_all_agents_when_ready,
-            time_for_this_agent_when_ready);
-  const base::TimeDelta time_for_all_agents_since_ready = std::max(
-      base::TimeDelta(),
-      time_for_all_agents_ - ready_task.time_for_all_agents_when_ready);
-
-  auto agent_data_it = agent_data_.find(agent_cluster_id);
-  DCHECK(agent_data_it != agent_data_.end());
-  const base::TimeDelta time_for_agent =
-      agent_data_it->second.accumulated_running_time;
-  const base::TimeDelta time_for_this_agent_since_ready = std::max(
-      base::TimeDelta(), time_for_agent - time_for_this_agent_when_ready);
-
-  const base::TimeDelta time_for_other_agents_since_ready =
-      std::max(base::TimeDelta(), time_for_all_agents_since_ready -
-                                      time_for_this_agent_since_ready);
-  RecordHistogram(queue, time_for_other_agents_since_ready);
-}
-
-void AgentInterferenceRecorder::DecrementNumFramesForAgent(
-    const base::UnguessableToken& agent_cluster_id) {
-  if (!agent_cluster_id)
-    return;
-  auto agent_data_it = agent_data_.find(agent_cluster_id);
-  DCHECK(agent_data_it != agent_data_.end());
-  DCHECK_GT(agent_data_it->second.frame_count, 0U);
-  // If |frame_count| reaches 0, the data for this agent is cleared as it's
-  // no longer useful.
-  if (--agent_data_it->second.frame_count == 0)
-    agent_data_.erase(agent_data_it);
-}
-
-void AgentInterferenceRecorder::RecordHistogram(
-    const MainThreadTaskQueue* queue,
-    base::TimeDelta sample) {
-  // Histogram should only be recorded for queue types that can be associated
-  // with agents.
-  DCHECK(GetAgentClusterIdForQueue(queue));
-  const MainThreadTaskQueue::QueueType queue_type = queue->queue_type();
-  DCHECK(MainThreadTaskQueue::IsPerFrameTaskQueue(queue_type));
-
-  const std::string histogram_name =
-      std::string("RendererScheduler.TimeRunningOtherAgentsWhileTaskReady.") +
-      (GetFrameSchedulerForQueue(queue)->IsFrameVisible() ? "Visible"
-                                                          : "Hidden");
-  base::UmaHistogramCustomMicrosecondsTimes(
-      histogram_name, sample, base::TimeDelta::FromMicroseconds(1),
-      base::TimeDelta::FromSeconds(1), 100);
-  const std::string histogram_name_with_queue_type =
-      histogram_name + "." + MainThreadTaskQueue::NameForQueueType(queue_type);
-  base::UmaHistogramCustomMicrosecondsTimes(
-      histogram_name_with_queue_type, sample,
-      base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(1),
-      100);
-}
-
-const FrameScheduler* AgentInterferenceRecorder::GetFrameSchedulerForQueue(
-    const MainThreadTaskQueue* queue) {
-  return queue->GetFrameScheduler();
-}
-
-const base::UnguessableToken&
-AgentInterferenceRecorder::GetAgentClusterIdForQueue(
-    const MainThreadTaskQueue* queue) {
-  const FrameSchedulerImpl* frame_scheduler = queue->GetFrameScheduler();
-  return frame_scheduler ? frame_scheduler->GetAgentClusterId()
-                         : base::UnguessableToken::Null();
-}
-
-}  // namespace scheduler
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder.h b/third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder.h
deleted file mode 100644
index 289c2ff..0000000
--- a/third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder.h
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_AGENT_INTERFERENCE_RECORDER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_AGENT_INTERFERENCE_RECORDER_H_
-
-#include <atomic>
-#include <map>
-#include <vector>
-
-#include "base/check_op.h"
-#include "base/containers/flat_map.h"
-#include "base/macros.h"
-#include "base/sequence_checker.h"
-#include "base/synchronization/lock.h"
-#include "base/task/sequence_manager/enqueue_order.h"
-#include "base/task/sequence_manager/lazy_now.h"
-#include "base/thread_annotations.h"
-#include "base/time/time.h"
-#include "base/unguessable_token.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-
-namespace blink {
-namespace scheduler {
-
-class MainThreadTaskQueue;
-
-// Records the RendererScheduler.TimeRunningOtherAgentsWhileTaskReady histogram,
-// which tracks how much time is spent running tasks from other agents between
-// when an agent task becomes ready to run and when it starts running.
-//
-// Implementation details
-// ----------------------
-//
-// The time running tasks from other agents while a task is ready is defined as:
-//
-//   ([Time running tasks for all agents between thread start and task start] -
-//    [Time running tasks for all agents between thread start and task ready]) -
-//   ([Time running tasks for same agent between thread start and task start] -
-//    [Time running tasks for same agent between thread start and task ready]) -
-//
-// To get these values, we maintain the following state:
-//
-// A) For the task that is currently running:
-//     A1) Start time
-//     A2) Associated agent
-// B) For each agent, an accumulator of time running tasks for that agent since
-//    thread start.
-// C) An accumulator of time running tasks for any agent since thread start.
-// D) For each queued task for which we want to record the histogram:
-//     D1) Time running tasks for all agents between thread start and task
-//         queued.
-//     D2) Time running tasks for each agent between thread start and task
-//         queued.
-//
-// At any given time, we can compute:
-//
-// E) The time running tasks for a specific AGENT since thread start:
-//      Read the AGENT's accumulator in B. Add [Current Time] - A1 if A2 is
-//      equal to AGENT.
-// F) The time running tasks for any agent since thread start:
-//      Read C. Add [Current Time] - A1 if A2 is non-null.
-//
-// When a task becomes ready, we decide whether we want to record the histogram
-// for it. If so, we use E and F to add an entry to D.
-//
-// When a task starts running, we check whether it is in D. If so, we use D1,
-// D2, E and F to compute the value to record to the histogram. Then, we update
-// A. When a task finishes running, we update B and C and we clear A. Note that
-// even though we sample the tasks for which we record the histogram, we need to
-// accumulate the time all tasks in B and C since it can contribute to the value
-// recorded for a sampled task.
-//
-// Entering a nested loop is equivalent to finishing the current task. Exiting a
-// nested loop is equivalent to resuming the task that was finished when the
-// nested loop was entered (no histogram is recorded when resuming an existing
-// task).
-class PLATFORM_EXPORT AgentInterferenceRecorder {
- public:
-  // The histogram is recorded for 1 out of |sampling_rate| tasks.
-  explicit AgentInterferenceRecorder(int sampling_rate = 1000);
-  ~AgentInterferenceRecorder();
-
-  // Invoked when a task becomes ready. For a non-delayed task, this is at post
-  // time. For a delayed task, this is when the task's delay expires.
-  //
-  // |frame| is the FrameScheduler associated with the task (passed as void*
-  // because it's only used a key and FrameScheduler isn't thread-safe - void
-  // prevents undesired access).
-  //
-  // This is the only public method of this class that can be called from
-  // another thread than the main thread.
-  void OnTaskReady(const void* frame_scheduler,
-                   base::sequence_manager::EnqueueOrder enqueue_order,
-                   base::sequence_manager::LazyNow* lazy_now);
-
-  // Invoked from the main thread when a task starts/finishes running, or when a
-  // nested loop is exited/entered. When a nested loop is exited,
-  // |enqueue_order| is EnqueueOrder::none().
-  void OnTaskStarted(MainThreadTaskQueue* queue,
-                     base::sequence_manager::EnqueueOrder enqueue_order,
-                     base::TimeTicks start_time);
-  void OnTaskCompleted(MainThreadTaskQueue* queue, base::TimeTicks end_time);
-
-  // Invoked at the end of the destructor of a FrameScheduler, on the main
-  // thread. Cleans up state associated with that FrameScheduler. Does not
-  // dereference |frame_scheduler|.
-  void OnFrameSchedulerDestroyed(const FrameScheduler* frame_scheduler);
-
- private:
-  // Information about an agent.
-  struct AgentData {
-    AgentData() = default;
-
-    // Time running tasks for agent since thread start.
-    base::TimeDelta accumulated_running_time;
-
-    // Number of frames associated with this agent.
-    size_t frame_count = 0;
-  };
-
-  using AgentDataMap = std::map<base::UnguessableToken, AgentData>;
-
-  // Information about a ready task for which the histogram will be recorded.
-  struct ReadyTask {
-    // Time running tasks for all agents when the task became ready (corresponds
-    // to D1 above).
-    base::TimeDelta time_for_all_agents_when_ready;
-
-    // Time running tasks for each agent when the task became ready (corresponds
-    // to D2 above).
-    AgentDataMap agent_data_when_ready;
-
-#if DCHECK_IS_ON()
-    // The FrameScheduler associated with the task. Stored in a void* because
-    // it's only used a key and FrameScheduler isn't thread-safe (so void
-    // prevents undesired access).
-    const void* frame_scheduler = nullptr;
-#endif
-  };
-
-  // Updates |time_for_all_agents_| and
-  // |agent_data_[current_task_agent_cluster_id_]| so that they reflect current
-  // running time.
-  void AccumulateCurrentTaskRunningTime(
-      base::sequence_manager::LazyNow* lazy_now)
-      EXCLUSIVE_LOCKS_REQUIRED(lock_);
-
-  // Returns the running time of the current agent task. Cannot be called if
-  // currently running task isn't an agent task.
-  base::TimeDelta GetCurrentAgentTaskRunningTime(
-      base::sequence_manager::LazyNow* lazy_now) const
-      EXCLUSIVE_LOCKS_REQUIRED(lock_);
-
-  // Records the histogram for |ready_task|.
-  void RecordHistogramForReadyTask(
-      const ReadyTask& ready_task,
-      const MainThreadTaskQueue* queue,
-      const FrameScheduler* frame_scheduler,
-      const base::UnguessableToken& agent_cluster_id,
-      base::sequence_manager::EnqueueOrder enqueue_order)
-      EXCLUSIVE_LOCKS_REQUIRED(lock_);
-
-  // Returns true if the next ready task should be sampled. Thread-safe.
-  uint32_t ShouldSampleNextReadyTask();
-
-  void DecrementNumFramesForAgent(
-      const base::UnguessableToken& agent_cluster_id)
-      EXCLUSIVE_LOCKS_REQUIRED(lock_);
-
-  // Virtual for testing.
-  virtual void RecordHistogram(const MainThreadTaskQueue* queue,
-                               base::TimeDelta sample);
-  virtual const FrameScheduler* GetFrameSchedulerForQueue(
-      const MainThreadTaskQueue* queue);
-  virtual const base::UnguessableToken& GetAgentClusterIdForQueue(
-      const MainThreadTaskQueue* queue);
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  // Sampling rate. The histogram is recorded for 1/|sampling_rate_| tasks.
-  const int sampling_rate_;
-
-  // Current random value. Used to determine which tasks are sampled.
-  std::atomic<uint32_t> random_value_;
-
-  // Protects all members below. Low contention because most accesses are from
-  // the main thread. Is only occasionally acquired from other threads when
-  // OnTaskReady() decides to record the histogram for a task.
-  base::Lock lock_;
-
-  // Start time of the currently running task, or is_null() if no task is
-  // running.
-  base::TimeTicks current_task_start_time_ GUARDED_BY(lock_);
-
-  // Agent cluster id of the currently running task, or Null if the task is not
-  // agent-bound or if no task is running.
-  base::UnguessableToken agent_cluster_id_for_current_task_ GUARDED_BY(lock_);
-
-  // Time spent running tasks for all agents since thread start.
-  base::TimeDelta time_for_all_agents_ GUARDED_BY(lock_);
-
-  AgentDataMap agent_data_ GUARDED_BY(lock_);
-
-  // Association between frames and agents. Frame is stored as a void* because
-  // it's only used a key and FrameScheduler isn't thread-safe (so void prevents
-  // undesired access). The mapping from frame to agent cluster id is maintained
-  // to allow efficiently maintaining the frame count in AgentData. Protected by
-  // |sequence_checker_|.
-  WTF::HashMap<const void*, base::UnguessableToken> frame_to_agent_cluster_id_;
-
-  // Information about ready tasks for which the histogram will be recorded. Key
-  // is the task's sequence number.
-  base::flat_map<base::sequence_manager::EnqueueOrder, ReadyTask> ready_tasks_
-      GUARDED_BY(lock_);
-
-  DISALLOW_COPY_AND_ASSIGN(AgentInterferenceRecorder);
-};
-
-}  // namespace scheduler
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_AGENT_INTERFERENCE_RECORDER_H_
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder_unittest.cc
deleted file mode 100644
index 5f7fc356..0000000
--- a/third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder_unittest.cc
+++ /dev/null
@@ -1,565 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder.h"
-
-#include "base/task/sequence_manager/task_queue.h"
-#include "base/test/task_environment.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
-#include "third_party/blink/renderer/platform/scheduler/public/dummy_schedulers.h"
-
-namespace blink {
-namespace scheduler {
-namespace agent_interference_recorder_test {
-
-using base::sequence_manager::LazyNow;
-using base::sequence_manager::Task;
-
-constexpr base::TimeDelta kDelay = base::TimeDelta::FromSeconds(10);
-
-class AgentInterferenceRecorderTest : public testing::Test {
- public:
-  class MockAgentInterferenceRecorder : public AgentInterferenceRecorder {
-   public:
-    MockAgentInterferenceRecorder(AgentInterferenceRecorderTest* outer)
-        : AgentInterferenceRecorder(/* sampling_rate */ 1), outer_(outer) {}
-
-    void RecordHistogram(const MainThreadTaskQueue* queue,
-                         base::TimeDelta sample) override {
-      MockRecordHistogram(queue, sample);
-    }
-
-    FrameScheduler* GetFrameSchedulerForQueue(
-        const MainThreadTaskQueue* queue) override {
-      if (queue == outer_->queue_frame_agent_a_ ||
-          queue == outer_->other_queue_frame_agent_a_)
-        return outer_->frame_agent_a_.get();
-      if (queue == outer_->queue_frame_agent_b_)
-        return outer_->frame_agent_b_.get();
-      if (queue == outer_->queue_frame_agent_c_)
-        return outer_->frame_agent_c_.get();
-      if (queue == outer_->queue_other_frame_agent_c_)
-        return outer_->other_frame_agent_c_.get();
-      return nullptr;
-    }
-    const base::UnguessableToken& GetAgentClusterIdForQueue(
-        const MainThreadTaskQueue* queue) override {
-      if (queue == outer_->queue_frame_agent_a_ ||
-          queue == outer_->other_queue_frame_agent_a_)
-        return outer_->agent_a_;
-      if (queue == outer_->queue_frame_agent_b_)
-        return outer_->agent_b_;
-      if (queue == outer_->queue_frame_agent_c_ ||
-          queue == outer_->queue_other_frame_agent_c_)
-        return outer_->agent_c_;
-      return base::UnguessableToken::Null();
-    }
-
-    MOCK_METHOD2(MockRecordHistogram,
-                 void(const MainThreadTaskQueue*, base::TimeDelta));
-
-   private:
-    AgentInterferenceRecorderTest* const outer_;
-  };
-
-  class ScopedExpectSample {
-   public:
-    ScopedExpectSample(AgentInterferenceRecorderTest* test,
-                       MainThreadTaskQueue* queue,
-                       base::TimeDelta expected)
-        : test_(test) {
-      EXPECT_CALL(test_->recorder_, MockRecordHistogram(queue, expected));
-    }
-    ~ScopedExpectSample() { testing::Mock::VerifyAndClear(&test_->recorder_); }
-
-   private:
-    AgentInterferenceRecorderTest* const test_;
-  };
-
-  AgentInterferenceRecorderTest() = default;
-
-  static base::sequence_manager::EnqueueOrder EnqueueOrder(int enqueue_order) {
-    return base::sequence_manager::EnqueueOrder::FromIntForTesting(
-        enqueue_order);
-  }
-
-  void FastForwardBy(base::TimeDelta delta) {
-    task_environment_.FastForwardBy(delta);
-  }
-
-  base::TimeTicks NowTicks() const { return task_environment_.NowTicks(); }
-
-  void OnTaskReady(FrameScheduler* frame_scheduler,
-                   base::sequence_manager::EnqueueOrder enqueue_order) {
-    base::sequence_manager::LazyNow lazy_now(GetMockTickClock());
-    recorder_.OnTaskReady(frame_scheduler, enqueue_order, &lazy_now);
-  }
-
-  const base::TickClock* GetMockTickClock() const {
-    return task_environment_.GetMockTickClock();
-  }
-
-  testing::StrictMock<MockAgentInterferenceRecorder> recorder_{this};
-
-  base::UnguessableToken agent_a_ = base::UnguessableToken::Create();
-  base::UnguessableToken agent_b_ = base::UnguessableToken::Create();
-  base::UnguessableToken agent_c_ = base::UnguessableToken::Create();
-
-  std::unique_ptr<FrameScheduler> frame_agent_a_ = CreateDummyFrameScheduler();
-  std::unique_ptr<FrameScheduler> frame_agent_b_ = CreateDummyFrameScheduler();
-  std::unique_ptr<FrameScheduler> frame_agent_c_ = CreateDummyFrameScheduler();
-  std::unique_ptr<FrameScheduler> other_frame_agent_c_ =
-      CreateDummyFrameScheduler();
-
-  scoped_refptr<MainThreadTaskQueue> queue_frame_agent_a_ =
-      CreateMainThreadTaskQueue();
-  scoped_refptr<MainThreadTaskQueue> other_queue_frame_agent_a_ =
-      CreateMainThreadTaskQueue();
-  scoped_refptr<MainThreadTaskQueue> queue_frame_agent_b_ =
-      CreateMainThreadTaskQueue();
-  scoped_refptr<MainThreadTaskQueue> queue_frame_agent_c_ =
-      CreateMainThreadTaskQueue();
-  scoped_refptr<MainThreadTaskQueue> queue_other_frame_agent_c_ =
-      CreateMainThreadTaskQueue();
-
-  // GetFrameSchedulerForQueue() will return nullptr for this queue.
-  scoped_refptr<MainThreadTaskQueue> queue_no_frame_ =
-      CreateMainThreadTaskQueue();
-
-  base::test::TaskEnvironment task_environment_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-
- private:
-  scoped_refptr<MainThreadTaskQueue> CreateMainThreadTaskQueue() {
-    return WrapRefCounted(new MainThreadTaskQueue(
-        nullptr, base::sequence_manager::TaskQueue::Spec(""),
-        MainThreadTaskQueue::QueueCreationParams(
-            MainThreadTaskQueue::QueueType::kDefault),
-        nullptr));
-  }
-};
-
-// Verify that zero interference is recorded if no task runs between when a
-// frame task is posted and when it runs.
-TEST_F(AgentInterferenceRecorderTest, NoInterferenceSingleTask) {
-  SCOPED_TRACE(NowTicks());
-
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(1));
-  FastForwardBy(kDelay);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_a_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_frame_agent_a_.get(), EnqueueOrder(1),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_a_.get(), end);
-  }
-}
-
-// Verify that zero interference is recorded when tasks from the same queue run.
-TEST_F(AgentInterferenceRecorderTest, NoInterferenceMultipleTasksSameQueue) {
-  SCOPED_TRACE(NowTicks());
-
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(1));
-  FastForwardBy(kDelay);
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(2));
-  FastForwardBy(kDelay);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_a_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_frame_agent_a_.get(), EnqueueOrder(1),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_a_.get(), end);
-  }
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_a_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_frame_agent_a_.get(), EnqueueOrder(2),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_a_.get(), end);
-  }
-}
-
-// Verify that zero interference is recorded when tasks from different queues
-// associated with the same frame run.
-TEST_F(AgentInterferenceRecorderTest, NoInterferenceMultipleQueuesSameAgent) {
-  SCOPED_TRACE(NowTicks());
-
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(1));
-  FastForwardBy(kDelay);
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(2));
-  FastForwardBy(kDelay);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_a_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_frame_agent_a_.get(), EnqueueOrder(1),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_a_.get(), end);
-  }
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, other_queue_frame_agent_a_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(other_queue_frame_agent_a_.get(), EnqueueOrder(2),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(other_queue_frame_agent_a_.get(), end);
-  }
-}
-
-// Verify that zero interference is recorded when tasks from different frame
-// associated with the same agent run.
-TEST_F(AgentInterferenceRecorderTest, NoInterferenceMultipleFramesSameAgent) {
-  SCOPED_TRACE(NowTicks());
-
-  OnTaskReady(frame_agent_c_.get(), EnqueueOrder(1));
-  FastForwardBy(kDelay);
-  OnTaskReady(other_frame_agent_c_.get(), EnqueueOrder(2));
-  FastForwardBy(kDelay);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_c_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_frame_agent_c_.get(), EnqueueOrder(1),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_c_.get(), end);
-  }
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_other_frame_agent_c_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_other_frame_agent_c_.get(), EnqueueOrder(2),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_other_frame_agent_c_.get(), end);
-  }
-}
-
-// Verify that zero interference is recorded when a non-frame task runs between
-// when a frame task is ready and when it runs.
-TEST_F(AgentInterferenceRecorderTest, NoInterferenceNoAgentQueue) {
-  SCOPED_TRACE(NowTicks());
-
-  OnTaskReady(nullptr, EnqueueOrder(1));
-  FastForwardBy(kDelay);
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(2));
-  FastForwardBy(kDelay);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    recorder_.OnTaskStarted(queue_no_frame_.get(), EnqueueOrder(1), start);
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_no_frame_.get(), end);
-  }
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, other_queue_frame_agent_a_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(other_queue_frame_agent_a_.get(), EnqueueOrder(2),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(other_queue_frame_agent_a_.get(), end);
-  }
-}
-
-// Verify that interference is recorded when a task from another agent runs
-// between when a agent task becomes ready and when it runs.
-TEST_F(AgentInterferenceRecorderTest, InterferenceFromOneOtherAgent) {
-  SCOPED_TRACE(NowTicks());
-
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(1));
-  FastForwardBy(kDelay);
-  OnTaskReady(frame_agent_b_.get(), EnqueueOrder(2));
-  FastForwardBy(kDelay);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_a_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_frame_agent_a_.get(), EnqueueOrder(1),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_a_.get(), end);
-  }
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_b_.get(),
-                                       kDelay);
-      recorder_.OnTaskStarted(queue_frame_agent_b_.get(), EnqueueOrder(2),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_b_.get(), end);
-  }
-}
-
-// Verify that interference is recorded correctly when tasks from multiple
-// agents run.
-TEST_F(AgentInterferenceRecorderTest, InterferenceFromManyOtherFrames) {
-  SCOPED_TRACE(NowTicks());
-
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(1));
-  // Add FastForwardBy()'s in between; those shouldn't matter.
-  FastForwardBy(kDelay * 32);
-  OnTaskReady(frame_agent_b_.get(), EnqueueOrder(2));
-  FastForwardBy(kDelay * 64);
-  OnTaskReady(frame_agent_c_.get(), EnqueueOrder(3));
-  FastForwardBy(kDelay * 128);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_a_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_frame_agent_a_.get(), EnqueueOrder(1),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_a_.get(), end);
-  }
-
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(4));
-  FastForwardBy(kDelay);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      // Had to wait for task 1.
-      ScopedExpectSample expect_sample(this, queue_frame_agent_b_.get(),
-                                       kDelay);
-      recorder_.OnTaskStarted(queue_frame_agent_b_.get(), EnqueueOrder(2),
-                              start);
-    }
-    FastForwardBy(2 * kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_b_.get(), end);
-  }
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      // Had to wait for tasks 1 and 2.
-      ScopedExpectSample expect_sample(this, queue_frame_agent_c_.get(),
-                                       3 * kDelay);
-      recorder_.OnTaskStarted(queue_frame_agent_c_.get(), EnqueueOrder(3),
-                              start);
-    }
-    FastForwardBy(4 * kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_c_.get(), end);
-  }
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      // Had to wait for tasks 2 and 3.
-      ScopedExpectSample expect_sample(this, other_queue_frame_agent_a_.get(),
-                                       6 * kDelay);
-      recorder_.OnTaskStarted(other_queue_frame_agent_a_.get(), EnqueueOrder(4),
-                              start);
-    }
-    FastForwardBy(8 * kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(other_queue_frame_agent_a_.get(), end);
-  }
-}
-
-// Verify that interference is recorded correctly when there are nested tasks.
-TEST_F(AgentInterferenceRecorderTest, Nesting) {
-  SCOPED_TRACE(NowTicks());
-
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(1));
-  FastForwardBy(kDelay);
-  OnTaskReady(frame_agent_b_.get(), EnqueueOrder(2));
-  FastForwardBy(kDelay);
-  OnTaskReady(frame_agent_b_.get(), EnqueueOrder(3));
-  FastForwardBy(kDelay);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_a_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_frame_agent_a_.get(), EnqueueOrder(1),
-                              start);
-    }
-    FastForwardBy(kDelay);
-
-    // Run task 2 nested.
-    {
-      // When a nested loop is entered, complete the current task.
-      recorder_.OnTaskCompleted(queue_frame_agent_a_.get(), NowTicks());
-
-      const base::TimeTicks nested_start = NowTicks();
-      {
-        ScopedExpectSample expect_sample(this, queue_frame_agent_b_.get(),
-                                         kDelay);
-        recorder_.OnTaskStarted(queue_frame_agent_b_.get(), EnqueueOrder(2),
-                                nested_start);
-      }
-      FastForwardBy(8 * kDelay);
-      const base::TimeTicks nested_end = NowTicks();
-      recorder_.OnTaskCompleted(queue_frame_agent_b_.get(), nested_end);
-
-      // When a nested loop is exited, resume the task that was running when the
-      // nested loop was entered.
-      recorder_.OnTaskStarted(queue_frame_agent_a_.get(),
-                              base::sequence_manager::EnqueueOrder::none(),
-                              NowTicks());
-    }
-
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_a_.get(), end);
-  }
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      // Only includes the execution time of task 1, not the nested execution
-      // time of task 2, which is from the same frame.
-      ScopedExpectSample expect_sample(this, queue_frame_agent_b_.get(),
-                                       2 * kDelay);
-      recorder_.OnTaskStarted(queue_frame_agent_b_.get(), EnqueueOrder(3),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_b_.get(), end);
-  }
-}
-
-// Verify that interference is recorded correctly when a task becomes ready
-// while another task is running.
-TEST_F(AgentInterferenceRecorderTest, ReadyDuringRun) {
-  SCOPED_TRACE(NowTicks());
-
-  OnTaskReady(frame_agent_a_.get(), EnqueueOrder(1));
-  FastForwardBy(kDelay);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_a_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_frame_agent_a_.get(), EnqueueOrder(1),
-                              start);
-    }
-
-    FastForwardBy(kDelay);
-    // Post task 2 in the middle of running task 1.
-    OnTaskReady(frame_agent_b_.get(), EnqueueOrder(2));
-    FastForwardBy(kDelay);
-
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_a_.get(), end);
-  }
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_b_.get(),
-                                       kDelay);
-      recorder_.OnTaskStarted(queue_frame_agent_b_.get(), EnqueueOrder(2),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_b_.get(), end);
-  }
-}
-
-// Verify that OnFrameSchedulerDestroyed doesn't clear data associated to an
-// agent that is referred to by other frames.
-TEST_F(AgentInterferenceRecorderTest, OnFrameSchedulerDestroyed) {
-  SCOPED_TRACE(NowTicks());
-
-  OnTaskReady(frame_agent_c_.get(), EnqueueOrder(1));
-  FastForwardBy(kDelay);
-  OnTaskReady(other_frame_agent_c_.get(), EnqueueOrder(2));
-  FastForwardBy(kDelay);
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_frame_agent_c_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_frame_agent_c_.get(), EnqueueOrder(1),
-                              start);
-    }
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_frame_agent_c_.get(), end);
-  }
-
-  {
-    const base::TimeTicks start = NowTicks();
-    {
-      ScopedExpectSample expect_sample(this, queue_other_frame_agent_c_.get(),
-                                       base::TimeDelta());
-      recorder_.OnTaskStarted(queue_other_frame_agent_c_.get(), EnqueueOrder(2),
-                              start);
-    }
-    // This should not clear data associated with |agent_c_|.
-    recorder_.OnFrameSchedulerDestroyed(frame_agent_c_.get());
-
-    FastForwardBy(kDelay);
-    const base::TimeTicks end = NowTicks();
-    recorder_.OnTaskCompleted(queue_other_frame_agent_c_.get(), end);
-  }
-}
-
-}  // namespace agent_interference_recorder_test
-}  // namespace scheduler
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index 5583a10..159492c 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -247,10 +247,6 @@
       parent_page_scheduler_->OnThrottlingStatusUpdated();
     }
   }
-
-  // Can be null in tests.
-  if (main_thread_scheduler_)
-    main_thread_scheduler_->OnFrameSchedulerDestroyed(this);
 }
 
 void FrameSchedulerImpl::DetachFromPageScheduler() {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index efb5aa2..66d79f9 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -2499,21 +2499,11 @@
     page_scheduler->ReportIntervention(message);
 }
 
-void MainThreadSchedulerImpl::OnTaskReady(
-    const void* frame_scheduler,
-    const base::sequence_manager::Task& task,
-    base::sequence_manager::LazyNow* lazy_now) {
-  agent_interference_recorder_.OnTaskReady(frame_scheduler,
-                                           task.enqueue_order(), lazy_now);
-}
-
 void MainThreadSchedulerImpl::OnTaskStarted(
     MainThreadTaskQueue* queue,
     const base::sequence_manager::Task& task,
     const TaskQueue::TaskTiming& task_timing) {
   main_thread_only().running_queues.push(queue);
-  agent_interference_recorder_.OnTaskStarted(queue, task.enqueue_order(),
-                                             task_timing.start_time());
   if (main_thread_only().nested_runloop)
     return;
 
@@ -2547,8 +2537,6 @@
   if (task_timing->has_wall_time() && queue && queue->GetFrameScheduler())
     queue->GetFrameScheduler()->AddTaskTime(task_timing->wall_duration());
   main_thread_only().running_queues.pop();
-  agent_interference_recorder_.OnTaskCompleted(queue.get(),
-                                               task_timing->end_time());
   if (main_thread_only().nested_runloop)
     return;
 
@@ -2695,23 +2683,12 @@
 
 void MainThreadSchedulerImpl::OnBeginNestedRunLoop() {
   DCHECK(!main_thread_only().running_queues.empty());
-  const base::TimeTicks now = real_time_domain()->Now();
-  // When a nested loop is entered, simulate completing the current task. It
-  // will be resumed when the run loop is exited.
-  agent_interference_recorder_.OnTaskCompleted(
-      main_thread_only().running_queues.top().get(), now);
   main_thread_only().nested_runloop = true;
   ApplyVirtualTimePolicy();
 }
 
 void MainThreadSchedulerImpl::OnExitNestedRunLoop() {
   DCHECK(!main_thread_only().running_queues.empty());
-  base::TimeTicks now = real_time_domain()->Now();
-  // When a nested loop is exited, resume the task that was running when the
-  // nested loop was entered.
-  agent_interference_recorder_.OnTaskStarted(
-      main_thread_only().running_queues.top().get(),
-      base::sequence_manager::EnqueueOrder::none(), now);
   main_thread_only().nested_runloop = false;
   ApplyVirtualTimePolicy();
 }
@@ -2852,11 +2829,6 @@
       std::move(on_completion_task));
 }
 
-void MainThreadSchedulerImpl::OnFrameSchedulerDestroyed(
-    FrameSchedulerImpl* frame_scheduler) {
-  agent_interference_recorder_.OnFrameSchedulerDestroyed(frame_scheduler);
-}
-
 void MainThreadSchedulerImpl::DispatchOnTaskCompletionCallbacks() {
   for (auto& closure : main_thread_only().on_task_completion_callbacks) {
     std::move(closure).Run();
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index dd9c1ca4..3ac056b0 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -29,7 +29,6 @@
 #include "third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.h"
 #include "third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
-#include "third_party/blink/renderer/platform/scheduler/main_thread/agent_interference_recorder.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/agent_scheduling_strategy.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/compositor_priority_experiments.h"
@@ -370,10 +369,6 @@
 
   void OnShutdownTaskQueue(const scoped_refptr<MainThreadTaskQueue>& queue);
 
-  void OnTaskReady(const void* frame_scheduler,
-                   const base::sequence_manager::Task& task,
-                   base::sequence_manager::LazyNow* lazy_now);
-
   void OnTaskStarted(
       MainThreadTaskQueue* queue,
       const base::sequence_manager::Task& task,
@@ -405,8 +400,6 @@
   // only once per task.
   void ExecuteAfterCurrentTask(base::OnceClosure on_completion_task);
 
-  void OnFrameSchedulerDestroyed(FrameSchedulerImpl* frame_scheduler);
-
   base::WeakPtr<MainThreadSchedulerImpl> GetWeakPtr();
 
   base::sequence_manager::TaskQueue::QueuePriority compositor_priority() const {
@@ -867,8 +860,6 @@
   base::RepeatingCallback<void(base::WeakPtr<const FrameSchedulerImpl>)>
       agent_strategy_delay_callback_;
 
-  AgentInterferenceRecorder agent_interference_recorder_;
-
   std::unique_ptr<AgentSchedulingStrategy> agent_scheduling_strategy_ =
       AgentSchedulingStrategy::Create(*this);
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
index 0d54d31..f6848e6 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
@@ -163,9 +163,6 @@
     // MainThreadSchedulerImpl::OnTaskStarted/Completed. At the moment this
     // is not possible due to task queue being created inside
     // MainThreadScheduler's constructor.
-    GetTaskQueueImpl()->SetOnTaskReadyHandler(
-        base::BindRepeating(&MainThreadTaskQueue::OnTaskReady,
-                            base::Unretained(this), frame_scheduler_));
     GetTaskQueueImpl()->SetOnTaskStartedHandler(base::BindRepeating(
         &MainThreadTaskQueue::OnTaskStarted, base::Unretained(this)));
     GetTaskQueueImpl()->SetOnTaskCompletedHandler(base::BindRepeating(
@@ -175,14 +172,6 @@
 
 MainThreadTaskQueue::~MainThreadTaskQueue() = default;
 
-void MainThreadTaskQueue::OnTaskReady(
-    const void* frame_scheduler,
-    const base::sequence_manager::Task& task,
-    base::sequence_manager::LazyNow* lazy_now) {
-  if (main_thread_scheduler_)
-    main_thread_scheduler_->OnTaskReady(frame_scheduler, task, lazy_now);
-}
-
 void MainThreadTaskQueue::OnTaskStarted(
     const base::sequence_manager::Task& task,
     const TaskQueue::TaskTiming& task_timing) {
@@ -208,11 +197,6 @@
     return;
 
   if (GetTaskQueueImpl()) {
-    // Since the OnTaskReadyHandler can be invoked from any thread, it is not
-    // possible to bind it to a WeakPtr. Simply stop invoking it once the
-    // MainThreadScheduler is detached. This is not a problem since it is only
-    // used to record histograms.
-    GetTaskQueueImpl()->SetOnTaskReadyHandler({});
     GetTaskQueueImpl()->SetOnTaskStartedHandler(
         base::BindRepeating(&MainThreadSchedulerImpl::OnTaskStarted,
                             main_thread_scheduler_->GetWeakPtr(), nullptr));
diff --git a/third_party/blink/renderer/platform/wtf/text/atomic_string_table.h b/third_party/blink/renderer/platform/wtf/text/atomic_string_table.h
index e479295..6ea8903 100644
--- a/third_party/blink/renderer/platform/wtf/text/atomic_string_table.h
+++ b/third_party/blink/renderer/platform/wtf/text/atomic_string_table.h
@@ -61,11 +61,6 @@
 
    private:
     friend bool operator==(const WeakResult& lhs, const WeakResult& rhs);
-    friend bool operator==(const WeakResult& lhs, const String& rhs);
-    friend bool operator==(const String& rhs, const WeakResult& lhs);
-    friend bool operator==(const WeakResult& lhs, const AtomicString& rhs);
-    friend bool operator==(const AtomicString& rhs, const WeakResult& lhs);
-    friend bool operator==(const WeakResult& lhs, const StringImpl* rhs);
     friend bool operator==(const StringImpl* lhs, const WeakResult& rhs);
 
     // Contains the pointer a string in a non-deferenceable form. Do NOT cast
@@ -143,6 +138,16 @@
 }
 
 inline bool operator==(const AtomicStringTable::WeakResult& lhs,
+                       const StringImpl* rhs) {
+  return rhs == lhs;
+}
+
+inline bool operator==(const StringImpl* lhs,
+                       const AtomicStringTable::WeakResult& rhs) {
+  return reinterpret_cast<uintptr_t>(lhs) == rhs.ptr_value_;
+}
+
+inline bool operator==(const AtomicStringTable::WeakResult& lhs,
                        const String& rhs) {
   return lhs == rhs.Impl();
 }
@@ -162,16 +167,6 @@
   return lhs.Impl() == rhs;
 }
 
-inline bool operator==(const AtomicStringTable::WeakResult& lhs,
-                       const StringImpl* rhs) {
-  return rhs == lhs;
-}
-
-inline bool operator==(const StringImpl* lhs,
-                       const AtomicStringTable::WeakResult& rhs) {
-  return reinterpret_cast<uintptr_t>(lhs) == rhs.ptr_value_;
-}
-
 }  // namespace WTF
 
 using WTF::AtomicStringTable;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 0419f45..0b12c5f 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1038,8 +1038,13 @@
 crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/composited-with-overflow-in-next-column.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/doubly-nested-with-top-padding-crossing-row-boundaries.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/dynamic/change-second-row-height.html [ Failure ]
+crbug.com/1105758 virtual/layout_ng_block_frag/fast/multicol/dynamic/insert-spanner-before-content.html [ Crash ]
 crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/dynamic/insert-spanner-into-stf-constrained-width.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/dynamic/insert-spanner-into-stf-unconstrained-width.html [ Failure ]
+crbug.com/1105758 virtual/layout_ng_block_frag/fast/multicol/dynamic/insert-spanner-pseudo-after-then-content.html [ Crash ]
+crbug.com/1105758 virtual/layout_ng_block_frag/fast/multicol/dynamic/insert-spanner-pseudo-before-after-in-content.html [ Crash ]
+crbug.com/1105758 virtual/layout_ng_block_frag/fast/multicol/dynamic/insert-spanner-pseudo-before-following-content.html [ Crash ]
+crbug.com/1105758 virtual/layout_ng_block_frag/fast/multicol/dynamic/insert-spanner-pseudo-before.html [ Crash ]
 crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/dynamic/relpos-becomes-static-has-abspos.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/dynamic/remove-column-content-next-to-abspos-between-spanners.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/dynamic/static-becomes-relpos-has-abspos.html [ Failure ]
@@ -6330,7 +6335,6 @@
 crbug.com/1046784 http/tests/devtools/elements/styles-3/styles-add-invalid-property.js [ Pass Timeout ]
 crbug.com/1046784 http/tests/devtools/elements/resolve-node-blocked.js [ Pass Timeout ]
 crbug.com/1046784 http/tests/devtools/editor/text-editor-selection-to-search.js [ Pass Timeout ]
-crbug.com/1046784 http/tests/devtools/elements/shadow/breadcrumb-shadow-roots.js [ Pass Timeout ]
 crbug.com/1046784 http/tests/devtools/animation/animation-KeyframeEffect-crash.js [ Pass Timeout ]
 crbug.com/1046784 http/tests/devtools/animation/animation-group-matching-transitions.js [ Pass Timeout ]
 crbug.com/1046784 http/tests/devtools/storage-panel-dom-storage.js [ Pass Timeout ]
@@ -6355,7 +6359,7 @@
 crbug.com/1046784 http/tests/devtools/file-system-project.js [ Pass Timeout ]
 crbug.com/1046784 http/tests/devtools/bindings/navigator-frame-attach-detach.js [ Pass Timeout ]
 crbug.com/1046784 http/tests/devtools/forced-layout-in-microtask.js [ Pass Timeout ]
-crbug.com/1046784 http/tests/devtools/application-panel/resources-panel-iframe-idb.js [ Pass Timeout ]
+crbug.com/1046784 http/tests/devtools/application-panel/resources-panel-iframe-idb.js [ Pass Failure Timeout ]
 crbug.com/1046784 http/tests/devtools/a11y-axe-core/sources/scope-pane-a11y-test.js [ Pass Timeout ]
 crbug.com/1046784 http/tests/inspector-protocol/service-worker/target-reloaded-after-crash.js [ Pass Timeout ]
 crbug.com/1046784 http/tests/inspector-protocol/network/navigate-iframe-out2in.js [ Pass Timeout ]
@@ -6850,17 +6854,12 @@
 
 crbug.com/1104186 [ Win ] fast/forms/color-scheme/suggestion-picker/time-suggestion-picker-appearance.html [ Pass Failure ]
 
-crbug.com/1104195 inspector-protocol/css/css-set-effective-property-value.js [ Pass Failure Crash ]
-crbug.com/1104333 http/tests/devtools/bindings/inline-styles-binding.js [ Pass Failure Crash ]
-
 # Sheriff 2020-07-13
 
 crbug.com/1104910 [ Mac ] external/wpt/webaudio/the-audio-api/the-oscillatornode-interface/osc-basic-waveform.html [ Pass Failure ]
 crbug.com/1104910 fast/dom/cssTarget-crash.html [ Pass Timeout Failure ]
 crbug.com/1104910 fast/peerconnection/RTCPeerConnection-reload-interesting-usage.html [ Pass Failure ]
-crbug.com/1104910 inspector-protocol/stylesheet-tracking-restart.js [ Pass Failure ]
 crbug.com/1104910 [ Win ] virtual/cache-storage-eager-reading/external/wpt/service-workers/service-worker/registration-updateviacache.https.html [ Pass Failure ]
-crbug.com/1104910 [ Win ] http/tests/devtools/elements/styles-1/dynamic-style-tag.js [ Pass Failure ]
 crbug.com/1104910 [ Mac10.15 ] editing/selection/selection-background.html [ Pass Failure ]
 crbug.com/1104910 [ Linux ] external/wpt/referrer-policy/gen/worker-module.http-rp/unsafe-url/worker-classic.http.html [ Pass Failure ]
 crbug.com/1104910 [ Linux ] external/wpt/referrer-policy/gen/worker-module.http-rp/unset/worker-module.http.html [ Pass Failure ]
@@ -6875,3 +6874,10 @@
 crbug.com/1105276 [ Mac ] virtual/threaded/fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html [ Pass Failure ]
 crbug.com/1105278 [ Mac ] external/wpt/clipboard-apis/feature-policy/clipboard-write/clipboard-write-enabled-on-self-origin-by-feature-policy.tentative.https.sub.html [ Pass Failure ]
 crbug.com/1105279 [ Mac ] virtual/threaded/fast/scroll-snap/snaps-for-different-key-granularity.html [ Pass Timeout Failure ]
+
+# Temporarily disable to land DevTools changes
+crbug.com/1101262 http/tests/devtools/application-panel/resources-panel-on-navigation.js [ Pass Failure ]
+crbug.com/1101262 http/tests/devtools/application-panel/resources-panel-resource-preview.js [ Pass Failure ]
+crbug.com/1101262 http/tests/devtools/application-panel/resources-panel-selection-on-reload.js [ Pass Failure ]
+crbug.com/1101262 http/tests/devtools/application-panel/resources-panel-websql.js [ Pass Failure ]
+crbug.com/1101262 http/tests/devtools/resource-tree/resource-tree-non-unique-url.js [ Pass Failure ]
diff --git a/third_party/blink/web_tests/android/ClankWPTOverrideExpectations b/third_party/blink/web_tests/android/ClankWPTOverrideExpectations
index bfe5985..15d7efe 100644
--- a/third_party/blink/web_tests/android/ClankWPTOverrideExpectations
+++ b/third_party/blink/web_tests/android/ClankWPTOverrideExpectations
@@ -2362,7 +2362,7 @@
 crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html [ Failure Timeout ]
 crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html [ Failure Timeout ]
 crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html [ Failure Timeout ]
-crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unafe-none-report-to.https.html [ Failure Timeout ]
+crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html [ Failure Timeout ]
 crbug.com/1050754 external/wpt/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace-xhtml.xhtml [ Failure ]
 crbug.com/1050754 external/wpt/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace.html [ Failure ]
 crbug.com/1050754 external/wpt/html/dom/documents/dom-tree-accessors/nameditem-names.html [ Failure ]
diff --git a/third_party/blink/web_tests/android/WeblayerWPTOverrideExpectations b/third_party/blink/web_tests/android/WeblayerWPTOverrideExpectations
index 5a8fd7a..73d8e7d 100644
--- a/third_party/blink/web_tests/android/WeblayerWPTOverrideExpectations
+++ b/third_party/blink/web_tests/android/WeblayerWPTOverrideExpectations
@@ -2255,7 +2255,7 @@
 crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html [ Failure Timeout ]
 crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html [ Failure Timeout ]
 crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html [ Failure Timeout ]
-crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unafe-none-report-to.https.html [ Failure Timeout ]
+crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html [ Failure Timeout ]
 crbug.com/1050754 external/wpt/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace-xhtml.xhtml [ Failure ]
 crbug.com/1050754 external/wpt/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace.html [ Failure ]
 crbug.com/1050754 external/wpt/html/dom/documents/dom-tree-accessors/nameditem-names.html [ Failure ]
diff --git a/third_party/blink/web_tests/android/WebviewWPTOverrideExpectations b/third_party/blink/web_tests/android/WebviewWPTOverrideExpectations
index 8611bb5..f01d43d 100644
--- a/third_party/blink/web_tests/android/WebviewWPTOverrideExpectations
+++ b/third_party/blink/web_tests/android/WebviewWPTOverrideExpectations
@@ -2433,7 +2433,7 @@
 crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html [ Failure ]
 crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html [ Failure ]
 crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html [ Failure ]
-crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unafe-none-report-to.https.html [ Failure ]
+crbug.com/1050754 external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html [ Failure ]
 crbug.com/1050754 external/wpt/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace-xhtml.xhtml [ Failure ]
 crbug.com/1050754 external/wpt/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace.html [ Failure ]
 crbug.com/1050754 external/wpt/html/dom/documents/dom-tree-accessors/nameditem-names.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unafe-none-report-to.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unafe-none-report-to.https.html
rename to third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unafe-none-report-to.https.html.sub.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html.sub.headers
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unafe-none-report-to.https.html.sub.headers
rename to third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html.sub.headers
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/animated-svg-background-offscreen-firstline-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/animated-svg-background-offscreen-firstline-expected.txt
new file mode 100644
index 0000000..fa695d2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/animated-svg-background-offscreen-firstline-expected.txt
@@ -0,0 +1,40 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [3012, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1500, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-currentColor-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-currentColor-repaint-expected.txt
new file mode 100644
index 0000000..8350b9e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-currentColor-repaint-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 162, 150, 150],
+        [12, 12, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-generated-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-generated-expected.txt
new file mode 100644
index 0000000..6ffc534
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-generated-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 450]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-image-paint-invalidation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-image-paint-invalidation-expected.txt
new file mode 100644
index 0000000..ed07c8c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-image-paint-invalidation-expected.txt
@@ -0,0 +1,31 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1212, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 1212, 3024]
+      ]
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-misaligned-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-misaligned-expected.txt
new file mode 100644
index 0000000..510d58f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-misaligned-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 407, 411]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-resize-height-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-resize-height-expected.txt
new file mode 100644
index 0000000..7b739152
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-resize-height-expected.txt
@@ -0,0 +1,408 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 60, 90, 6]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image size-cover'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image size-contain'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 3
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image fixed-height'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 60, 90, 6]
+      ],
+      "transform": 4
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image percent-height'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 5
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image top'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 60, 90, 6]
+      ],
+      "transform": 6
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image bottom'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 7
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image center'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 8
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image no-repeat'",
+      "bounds": [90, 66],
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 60, 90, 6]
+      ],
+      "transform": 9
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image repeat-space'",
+      "bounds": [90, 66],
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 10
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test image repeat-round'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 11
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test generated'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 12
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test generated size-cover'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 13
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test generated size-contain'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 14
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test generated percent-height'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 15
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test generated top'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 16
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test generated bottom'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 17
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test generated center'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 18
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test generated no-repeat'",
+      "bounds": [90, 66],
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 19
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test generated repeat-space'",
+      "bounds": [90, 66],
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 20
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='test generated repeat-round'",
+      "bounds": [90, 66],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [0, 0, 90, 66]
+      ],
+      "transform": 21
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [87, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [162, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [237, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 5,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [312, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 6,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [387, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 7,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [462, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 8,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [537, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 9,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [612, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 10,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [687, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 11,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [762, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 12,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 162, 0, 1]
+      ]
+    },
+    {
+      "id": 13,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [87, 162, 0, 1]
+      ]
+    },
+    {
+      "id": 14,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [162, 162, 0, 1]
+      ]
+    },
+    {
+      "id": 15,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [312, 162, 0, 1]
+      ]
+    },
+    {
+      "id": 16,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [387, 162, 0, 1]
+      ]
+    },
+    {
+      "id": 17,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [462, 162, 0, 1]
+      ]
+    },
+    {
+      "id": 18,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [537, 162, 0, 1]
+      ]
+    },
+    {
+      "id": 19,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [612, 162, 0, 1]
+      ]
+    },
+    {
+      "id": 20,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [687, 162, 0, 1]
+      ]
+    },
+    {
+      "id": 21,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [762, 162, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-shorthand-with-gradient-and-height-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-shorthand-with-gradient-and-height-changes-expected.txt
new file mode 100644
index 0000000..a0d9b82
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-shorthand-with-gradient-and-height-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 1176, 750]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-size-auto-with-gradient-and-height-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-size-auto-with-gradient-and-height-changes-expected.txt
new file mode 100644
index 0000000..a0d9b82
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/background-size-auto-with-gradient-and-height-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 1176, 750]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/backgroundSizeRepaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/backgroundSizeRepaint-expected.txt
new file mode 100644
index 0000000..9077ffc
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/backgroundSizeRepaint-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [28, 493, 301, 91],
+        [28, 253, 301, 91]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/body-background-image-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/body-background-image-expected.txt
new file mode 100644
index 0000000..95f0d43
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/body-background-image-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 360, 1176, 426]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/change-text-content-and-background-color-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/change-text-content-and-background-color-expected.txt
new file mode 100644
index 0000000..0246ded
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/change-text-content-and-background-color-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 366, 100]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/composited-background-on-both-layers-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/composited-background-on-both-layers-expected.txt
new file mode 100644
index 0000000..c147e24
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/composited-background-on-both-layers-expected.txt
@@ -0,0 +1,61 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='target'",
+      "bounds": [360, 360],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 360, 360]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [30, 30],
+      "bounds": [278, 4500],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 278, 4500]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [30, 308],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [308, 30],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [308, 308],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/full-viewport-repaint-for-background-attachment-fixed-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/full-viewport-repaint-for-background-attachment-fixed-expected.txt
new file mode 100644
index 0000000..4d7051bd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/full-viewport-repaint-for-background-attachment-fixed-expected.txt
@@ -0,0 +1,31 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 7524],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 1200, 7524]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [1200, 0],
+      "bounds": [0, 900]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1500, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/multiple-backgrounds-style-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/multiple-backgrounds-style-change-expected.txt
new file mode 100644
index 0000000..4de5b30
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/multiple-backgrounds-style-change-expected.txt
@@ -0,0 +1,37 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='test' class='composited box changed'",
+      "bounds": [303, 303],
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [75, 75, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/no-repaint-for-composited-background-attachment-fixed-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/no-repaint-for-composited-background-attachment-fixed-expected.txt
new file mode 100644
index 0000000..0f15c239
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/no-repaint-for-composited-background-attachment-fixed-expected.txt
@@ -0,0 +1,32 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 7524],
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [1200, 0],
+      "bounds": [0, 900]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1500, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.txt
new file mode 100644
index 0000000..133f179
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/no-repaint-for-solid-color-background-attachment-fixed-expected.txt
@@ -0,0 +1,28 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 7524],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [1200, 0],
+      "bounds": [0, 900]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1500, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/obscured-background-no-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/obscured-background-no-repaint-expected.txt
new file mode 100644
index 0000000..22e19dd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/obscured-background-no-repaint-expected.txt
@@ -0,0 +1,40 @@
+FAIL: Unexpected paint invalidations: {"LayoutNGBlockFlow (relative positioned) DIV id='target2' class='parent'":true,"LayoutImage IMG id='imgForAdvanceImageAnimation'":true}
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 1008],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        {
+          "rect": [12, 162, 150, 150],
+          "object": "LayoutNGBlockFlow (relative positioned) DIV id='target2' class='parent'",
+          "reason": "background"
+        },
+        {
+          "rect": [12, 162, 150, 150],
+          "object": "LayoutNGBlockFlow (relative positioned) DIV id='target2' class='parent'",
+          "reason": "background"
+        },
+        {
+          "rect": [12, 810, 75, 75],
+          "object": "LayoutImage IMG id='imgForAdvanceImageAnimation'",
+          "reason": "uncacheable"
+        },
+        {
+          "rect": [12, 810, 75, 75],
+          "object": "LayoutImage IMG id='imgForAdvanceImageAnimation'",
+          "reason": "uncacheable"
+        }
+      ]
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/viewport-gradient-background-html-move-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/viewport-gradient-background-html-move-overflow-expected.txt
new file mode 100644
index 0000000..f29b2b9d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/viewport-gradient-background-html-move-overflow-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 1200, 900]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/viewport-gradient-background-html-resize-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/viewport-gradient-background-html-resize-expected.txt
new file mode 100644
index 0000000..f29b2b9d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/viewport-gradient-background-html-resize-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 1200, 900]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/viewport-gradient-background-html-resize-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/viewport-gradient-background-html-resize-overflow-expected.txt
new file mode 100644
index 0000000..f29b2b9d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/background/viewport-gradient-background-html-resize-overflow-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 1200, 900]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/block-layout-inline-children-replaced-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/block-layout-inline-children-replaced-expected.txt
new file mode 100644
index 0000000..95d54fa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/block-layout-inline-children-replaced-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 174, 603, 228]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/block-no-inflow-children-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/block-no-inflow-children-expected.txt
new file mode 100644
index 0000000..3db9a1a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/block-no-inflow-children-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 98, 26]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/block-shift-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/block-shift-repaint-expected.txt
new file mode 100644
index 0000000..5e4a4ac0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/block-shift-repaint-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 529, 90, 58],
+        [12, 507, 90, 57],
+        [12, 372, 90, 45],
+        [12, 327, 90, 45],
+        [12, 282, 90, 45],
+        [12, 237, 90, 45],
+        [12, 192, 90, 45],
+        [12, 147, 90, 45],
+        [12, 102, 90, 45],
+        [12, 57, 90, 45],
+        [12, 12, 90, 45]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-current-color-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-current-color-expected.txt
new file mode 100644
index 0000000..377143a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-current-color-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [87, 330, 180, 180]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-image-outset-add-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-image-outset-add-repaint-expected.txt
new file mode 100644
index 0000000..ecd24f2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-image-outset-add-repaint-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 113, 113]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-image-outset-change-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-image-outset-change-repaint-expected.txt
new file mode 100644
index 0000000..ecd24f2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-image-outset-change-repaint-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 113, 113]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-radius-repaint-2-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-radius-repaint-2-expected.txt
new file mode 100644
index 0000000..2d66efa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-radius-repaint-2-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1310, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#3F3F3F",
+      "invalidations": [
+        [12, 12, 1298, 888]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-radius-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-radius-repaint-expected.txt
new file mode 100644
index 0000000..5379af2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-radius-repaint-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [28, 358, 301, 133],
+        [28, 118, 301, 133]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-radius-without-border-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-radius-without-border-expected.txt
new file mode 100644
index 0000000..bc033a6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-radius-without-border-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 300, 150],
+        [0, 300, 150, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-repaint-glitch-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-repaint-glitch-expected.txt
new file mode 100644
index 0000000..3fd1d523
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/border-repaint-glitch-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [28, 505, 301, 133],
+        [28, 265, 301, 133]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-inline-resize-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-inline-resize-expected.txt
new file mode 100644
index 0000000..84e2d3b5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-inline-resize-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [60, 155, 169, 42],
+        [12, 155, 169, 42],
+        [12, 126, 48, 48]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-add-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-add-repaint-expected.txt
new file mode 100644
index 0000000..2a55eb31
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-add-repaint-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [6, 6, 177, 177]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-change-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-change-repaint-expected.txt
new file mode 100644
index 0000000..68c4fca5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-change-repaint-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [3, 3, 198, 198]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-dynamic-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-dynamic-expected.txt
new file mode 100644
index 0000000..4aead1c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-dynamic-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [26, 104, 85, 115],
+        [26, 284, 85, 85]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-inset-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-inset-repaint-expected.txt
new file mode 100644
index 0000000..dc45869
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-shadow-inset-repaint-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 345, 195]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-sizing-border-keeping-size-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-sizing-border-keeping-size-expected.txt
new file mode 100644
index 0000000..7528f4a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-sizing-border-keeping-size-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 300, 150, 150],
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-sizing-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-sizing-expected.txt
new file mode 100644
index 0000000..1cfdbe8e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-sizing-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 300, 660, 210],
+        [0, 0, 660, 210]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-sizing-padding-keeping-size-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-sizing-padding-keeping-size-expected.txt
new file mode 100644
index 0000000..7528f4a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/box-sizing-padding-keeping-size-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 300, 150, 150],
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/hover-pseudo-borders-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/hover-pseudo-borders-expected.txt
new file mode 100644
index 0000000..12406c0e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/hover-pseudo-borders-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [207, 12, 150, 150],
+        [12, 12, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/hover-pseudo-borders-whitespace-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/hover-pseudo-borders-whitespace-expected.txt
new file mode 100644
index 0000000..f26af52
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/hover-pseudo-borders-whitespace-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 207, 180, 180],
+        [12, 12, 180, 180]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/invalidate-box-shadow-currentColor-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/invalidate-box-shadow-currentColor-expected.txt
new file mode 100644
index 0000000..17743d0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/invalidate-box-shadow-currentColor-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 43, 34]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/margin-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/margin-expected.txt
new file mode 100644
index 0000000..6cdec37
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/margin-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [30, 30, 150, 150],
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/negative-shadow-box-expand-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/negative-shadow-box-expand-expected.txt
new file mode 100644
index 0000000..c46b301
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/negative-shadow-box-expand-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 90, 960, 360]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/negative-shadow-box-shrink-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/negative-shadow-box-shrink-expected.txt
new file mode 100644
index 0000000..c46b301
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/negative-shadow-box-shrink-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 90, 960, 360]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/padding-border-keeping-border-box-and-content-box-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/padding-border-keeping-border-box-and-content-box-expected.txt
new file mode 100644
index 0000000..eea4f80
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/padding-border-keeping-border-box-and-content-box-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 270, 270]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/padding-keeping-content-size-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/padding-keeping-content-size-expected.txt
new file mode 100644
index 0000000..f1dc2fd1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/padding-keeping-content-size-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 300, 210, 210],
+        [0, 0, 210, 210]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/padding-keeping-visual-size-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/padding-keeping-visual-size-expected.txt
new file mode 100644
index 0000000..7528f4a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/padding-keeping-visual-size-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 300, 150, 150],
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/resize-with-border-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/resize-with-border-expected.txt
new file mode 100644
index 0000000..16d0803
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/resize-with-border-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 150, 630, 330]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/shadow-box-resize-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/shadow-box-resize-expected.txt
new file mode 100644
index 0000000..de09a4e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/shadow-box-resize-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 150, 285, 180],
+        [150, 450, 210, 255],
+        [450, 450, 210, 180],
+        [450, 150, 210, 180]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/shadow-box-resize-writing-mode-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/shadow-box-resize-writing-mode-expected.txt
new file mode 100644
index 0000000..de09a4e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/box/shadow-box-resize-writing-mode-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 150, 285, 180],
+        [150, 450, 210, 255],
+        [450, 450, 210, 180],
+        [450, 150, 210, 180]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-3509-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-3509-expected.txt
new file mode 100644
index 0000000..82e65ed5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-3509-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [16, 187, 151, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-5699-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-5699-expected.txt
new file mode 100644
index 0000000..8aad1b5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-5699-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 267, 54, 26],
+        [12, 222, 54, 26],
+        [12, 218, 6, 26],
+        [12, 195, 6, 26]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-6278-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-6278-expected.txt
new file mode 100644
index 0000000..b91d9aa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-6278-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [15, 198, 438, 299],
+        [15, 198, 363, 353]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-6388-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-6388-expected.txt
new file mode 100644
index 0000000..6738aea0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-6388-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 195, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-6473-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-6473-expected.txt
new file mode 100644
index 0000000..4f6f194
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-6473-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 219, 1176, 27],
+        [12, 195, 1176, 27]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-7235-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-7235-expected.txt
new file mode 100644
index 0000000..e500598c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/bugzilla-7235-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 249, 150, 150],
+        [12, 222, 6, 26]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/button-inner-no-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/button-inner-no-repaint-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/button-inner-no-repaint-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/button-spurious-layout-hint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/button-spurious-layout-hint-expected.txt
new file mode 100644
index 0000000..d9f3e56d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/button-spurious-layout-hint-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/canvas-putImageData-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/canvas-putImageData-expected.txt
new file mode 100644
index 0000000..485f49b1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/canvas-putImageData-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 136, 136]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/canvas-resize-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/canvas-resize-expected.txt
new file mode 100644
index 0000000..02f5b1c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/canvas-resize-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [75, 75, 750, 750],
+        [825, 75, 150, 750]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/canvas-resize-no-full-invalidation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/canvas-resize-no-full-invalidation-expected.txt
new file mode 100644
index 0000000..aa2f6666
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/canvas-resize-no-full-invalidation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [825, 75, 150, 750]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/caret-outside-block-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/caret-outside-block-expected.txt
new file mode 100644
index 0000000..8014c1d5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/caret-outside-block-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [1186, 12, 1, 26]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/caret-subpixel-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/caret-subpixel-expected.txt
new file mode 100644
index 0000000..baa3ffd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/caret-subpixel-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 339, 32]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/change-clip-composited-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/change-clip-composited-layer-expected.txt
new file mode 100644
index 0000000..6755332
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/change-clip-composited-layer-expected.txt
@@ -0,0 +1,30 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='target'",
+      "bounds": [150, 15],
+      "invalidations": [
+        [0, 0, 75, 15]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/caret-ancestor-clip-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/caret-ancestor-clip-change-expected.txt
new file mode 100644
index 0000000..dbdb6b6d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/caret-ancestor-clip-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 87, 164, 94]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-path-constant-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-path-constant-repaint-expected.txt
new file mode 100644
index 0000000..40bb4cc3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-path-constant-repaint-expected.txt
@@ -0,0 +1,43 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='clip'",
+      "bounds": [1200, 450],
+      "backgroundColor": "#FF0000E6",
+      "transform": 2
+    },
+    {
+      "name": "Mask Layer",
+      "bounds": [1200, 450],
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt
new file mode 100644
index 0000000..d030a67
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt
@@ -0,0 +1,39 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [300, 300],
+      "backgroundColor": "#0000FF",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "Mask Layer",
+      "bounds": [300, 300],
+      "invalidations": [
+        [0, 0, 300, 300]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-path-resize-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-path-resize-expected.txt
new file mode 100644
index 0000000..8b2970679
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-path-resize-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 300, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-unclip-and-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-unclip-and-change-expected.txt
new file mode 100644
index 0000000..a4206ba
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-unclip-and-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 180, 150, 450]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-with-layout-delta-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-with-layout-delta-expected.txt
new file mode 100644
index 0000000..92e63c9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clip-with-layout-delta-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [162, 12, 150, 150],
+        [12, 12, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clipped-relative-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clipped-relative-expected.txt
new file mode 100644
index 0000000..834f000
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/clipped-relative-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 105, 306, 348]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/control-clip-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/control-clip-expected.txt
new file mode 100644
index 0000000..d72db56
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/control-clip-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [13, 124, 95, 24],
+        [115, 169, 94, 24]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/css-clip-change-stacking-child-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/css-clip-change-stacking-child-expected.txt
new file mode 100644
index 0000000..bd97c49
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/css-clip-change-stacking-child-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 312, 450, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/intermediate-layout-position-clip-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/intermediate-layout-position-clip-expected.txt
new file mode 100644
index 0000000..410469d9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/intermediate-layout-position-clip-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 60, 30]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/mask-clip-change-stacking-child-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/mask-clip-change-stacking-child-expected.txt
new file mode 100644
index 0000000..23e8992
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/mask-clip-change-stacking-child-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 450, 450]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/outline-clip-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/outline-clip-change-expected.txt
new file mode 100644
index 0000000..c003050
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/outline-clip-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [72, 126, 138, 34]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/replaced-clipped-positioned-not-wrong-incremental-repainting-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/replaced-clipped-positioned-not-wrong-incremental-repainting-expected.txt
new file mode 100644
index 0000000..d35c8ea
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/replaced-clipped-positioned-not-wrong-incremental-repainting-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 291, 348]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/resize-with-border-clipped-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/resize-with-border-clipped-expected.txt
new file mode 100644
index 0000000..00fbcb18
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/resize-with-border-clipped-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 150, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/subtree-root-clip-2-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/subtree-root-clip-2-expected.txt
new file mode 100644
index 0000000..d9f3e56d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/subtree-root-clip-2-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/subtree-root-clip-3-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/subtree-root-clip-3-expected.txt
new file mode 100644
index 0000000..062faca6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/subtree-root-clip-3-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [22, 90, 151, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/subtree-root-clip-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/subtree-root-clip-expected.txt
new file mode 100644
index 0000000..d9f3e56d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/clip/subtree-root-clip-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/background-attachment-local-composited-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/background-attachment-local-composited-expected.txt
new file mode 100644
index 0000000..4d3d622
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/background-attachment-local-composited-expected.txt
@@ -0,0 +1,59 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='container'",
+      "bounds": [600, 600],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [600, 3000],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "invalidations": [
+        [0, 750, 600, 2250]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [0, 600],
+      "bounds": [600, 0],
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [600, 0],
+      "bounds": [0, 600],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -2400, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt
new file mode 100644
index 0000000..4d3d622
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/background-attachment-local-equivalent-expected.txt
@@ -0,0 +1,59 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='container'",
+      "bounds": [600, 600],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [600, 3000],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "invalidations": [
+        [0, 750, 600, 2250]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [0, 600],
+      "bounds": [600, 0],
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [600, 0],
+      "bounds": [0, 600],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -2400, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/child-of-sub-pixel-offset-composited-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/child-of-sub-pixel-offset-composited-layer-expected.txt
new file mode 100644
index 0000000..5b01897
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/child-of-sub-pixel-offset-composited-layer-expected.txt
@@ -0,0 +1,31 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='container'",
+      "bounds": [21, 21],
+      "backgroundColor": "#FF0000",
+      "invalidations": [
+        [0, 0, 21, 21]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [151, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/chunk-reorder-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/chunk-reorder-expected.txt
new file mode 100644
index 0000000..add67c2e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/chunk-reorder-expected.txt
@@ -0,0 +1,31 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [1176, 825],
+      "invalidations": [
+        [600, 600, 150, 150],
+        [0, 0, 2, 2]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/clipping-should-not-repaint-composited-descendants-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/clipping-should-not-repaint-composited-descendants-expected.txt
new file mode 100644
index 0000000..8ed9833
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/clipping-should-not-repaint-composited-descendants-expected.txt
@@ -0,0 +1,65 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 924],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='clipping-container'",
+      "position": [150, 150],
+      "bounds": [150, 150],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='clipped-composited-child'",
+      "bounds": [378, 378],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFF00",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='clipping-container with-initial-clipping'",
+      "position": [150, 150],
+      "bounds": [150, 150],
+      "drawsContent": false,
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='clipped-composited-child'",
+      "bounds": [378, 378],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFF00",
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 462, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/column-span-under-composited-column-child-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/column-span-under-composited-column-child-expected.txt
new file mode 100644
index 0000000..de5c18db
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/column-span-under-composited-column-child-expected.txt
@@ -0,0 +1,31 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 150]
+      ]
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "contentsOpaque": true,
+      "drawsContent": false,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt
new file mode 100644
index 0000000..21784f1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-float-under-composited-inline-expected.txt
@@ -0,0 +1,37 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutInline (relative positioned) SPAN",
+      "position": [162, 162],
+      "drawsContent": false
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) (floating) DIV id='float'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [237, 237, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt
new file mode 100644
index 0000000..21784f1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-float-under-composited-inline-individual-expected.txt
@@ -0,0 +1,37 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutInline (relative positioned) SPAN",
+      "position": [162, 162],
+      "drawsContent": false
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) (floating) DIV id='float'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [237, 237, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-layer-move-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-layer-move-expected.txt
new file mode 100644
index 0000000..91d7b12
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-layer-move-expected.txt
@@ -0,0 +1,29 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='target'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [312, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-layers-move-in-subpixels-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-layers-move-in-subpixels-expected.txt
new file mode 100644
index 0000000..8a87818
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/composited-layers-move-in-subpixels-expected.txt
@@ -0,0 +1,61 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='first'",
+      "bounds": [1176, 78],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFF00",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [1176, 78],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [1176, 78],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 3
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 165, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 243, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 321, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/compositing-reason-removed-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/compositing-reason-removed-expected.txt
new file mode 100644
index 0000000..cef701bd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/compositing-reason-removed-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 45, 45]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-added-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-added-expected.txt
new file mode 100644
index 0000000..a56119e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-added-expected.txt
@@ -0,0 +1,35 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [75, 75, 113, 113]
+      ]
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='container'",
+      "bounds": [188, 188],
+      "backgroundColor": "#0000FF",
+      "invalidations": [
+        [0, 0, 150, 150],
+        [75, 75, 113, 113]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [300, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-added-individual-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-added-individual-expected.txt
new file mode 100644
index 0000000..a56119e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-added-individual-expected.txt
@@ -0,0 +1,35 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [75, 75, 113, 113]
+      ]
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='container'",
+      "bounds": [188, 188],
+      "backgroundColor": "#0000FF",
+      "invalidations": [
+        [0, 0, 150, 150],
+        [75, 75, 113, 113]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [300, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-removed-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-removed-expected.txt
new file mode 100644
index 0000000..0c27edc
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-removed-expected.txt
@@ -0,0 +1,36 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [75, 75, 113, 113]
+      ]
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='container'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "invalidations": [
+        [0, 0, 150, 150],
+        [75, 75, 113, 113]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [300, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-removed-individual-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-removed-individual-expected.txt
new file mode 100644
index 0000000..3e0eae2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/containing-block-removed-individual-expected.txt
@@ -0,0 +1,37 @@
+CONSOLE MESSAGE: line 30: debug
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [75, 75, 113, 113]
+      ]
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='container'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "invalidations": [
+        [0, 0, 150, 150],
+        [75, 75, 113, 113]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [300, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/dont-invalidate-root-layer-when-composited-layer-becomes-visible-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/dont-invalidate-root-layer-when-composited-layer-becomes-visible-expected.txt
new file mode 100644
index 0000000..ed58541
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/dont-invalidate-root-layer-when-composited-layer-becomes-visible-expected.txt
@@ -0,0 +1,28 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='target'",
+      "bounds": [300, 300],
+      "drawsContent": false,
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [300, 300, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt
new file mode 100644
index 0000000..3047b7e0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/fixed-pos-inside-composited-intermediate-layer-expected.txt
@@ -0,0 +1,68 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 45030],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='compositedBehind'",
+      "bounds": [750, 750],
+      "contentsOpaque": true,
+      "backgroundColor": "#00FFFF",
+      "transform": 2
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV class='containerOverlapsComposited')",
+      "position": [18, 18],
+      "bounds": [150, 45000],
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
+      "bounds": [75, 75],
+      "contentsOpaque": true,
+      "backgroundColor": "#00FF00",
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -150, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [68, 68, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/fixed-pos-with-abs-pos-child-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/fixed-pos-with-abs-pos-child-scroll-expected.txt
new file mode 100644
index 0000000..36c2867
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/fixed-pos-with-abs-pos-child-scroll-expected.txt
@@ -0,0 +1,36 @@
+Hi!
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 6032],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='fixed'",
+      "position": [-540, -135],
+      "bounds": [540, 135],
+      "contentsOpaque": true,
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [1178, 855, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt
new file mode 100644
index 0000000..aa9a68d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/fixed-scroll-in-empty-root-layer-expected.txt
@@ -0,0 +1,66 @@
+{
+  "layers": [
+    {
+      "name": "LayoutNGBlockFlow HTML",
+      "bounds": [1178, 3024],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "backgroundColor": "#FF0000",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow HTML (foreground) Layer",
+      "bounds": [1178, 3024],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -300, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 375, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 75, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/float-under-composited-inline-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/float-under-composited-inline-expected.txt
new file mode 100644
index 0000000..81cc8135
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/float-under-composited-inline-expected.txt
@@ -0,0 +1,19 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutInline (relative positioned) SPAN",
+      "position": [162, 162],
+      "bounds": [150, 150],
+      "invalidations": [
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
new file mode 100644
index 0000000..b4341833
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -0,0 +1,69 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 1524],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='foo'",
+      "bounds": [300, 1500],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV)",
+      "position": [0, -12],
+      "bounds": [450, 981],
+      "invalidations": [
+        [12, 762, 46, 26]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutIFrame IFRAME id='subframe'",
+      "bounds": [450, 225],
+      "transform": 2
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [428, 324],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [428, 0],
+      "bounds": [22, 225],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 750, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidate-paint-in-iframe-in-composited-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidate-paint-in-iframe-in-composited-layer-expected.txt
new file mode 100644
index 0000000..8aab166
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidate-paint-in-iframe-in-composited-layer-expected.txt
@@ -0,0 +1,36 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 924],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [456, 300],
+      "invalidations": [
+        [15, 15, 75, 75]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 612, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt
new file mode 100644
index 0000000..ef7d2b9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidate-when-leaving-squashed-layer-expected.txt
@@ -0,0 +1,57 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [300, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV)",
+      "position": [63, 63],
+      "bounds": [300, 300],
+      "invalidations": [
+        [0, 0, 300, 300]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='target'",
+      "bounds": [300, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#ADD8E6",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ],
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [75, 75, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
new file mode 100644
index 0000000..6dc13c3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidation-for-subpixel-offset-of-squashed-layer-expected.txt
@@ -0,0 +1,38 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [300, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV)",
+      "position": [63, 63],
+      "bounds": [376, 376],
+      "invalidations": [
+        [75, 75, 301, 301]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidations-on-composited-layers-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidations-on-composited-layers-expected.txt
new file mode 100644
index 0000000..f8b3538
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidations-on-composited-layers-expected.txt
@@ -0,0 +1,52 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='parent'",
+      "bounds": [600, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 600, 600]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='child'",
+      "bounds": [113, 113],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "invalidations": [
+        [0, 0, 113, 113]
+      ],
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [75, 75, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidations-with-large-negative-margin-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidations-with-large-negative-margin-expected.txt
new file mode 100644
index 0000000..a6d9592
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/invalidations-with-large-negative-margin-expected.txt
@@ -0,0 +1,54 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [900, 300],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [878, 600],
+      "invalidations": [
+        [600, 0, 75, 75],
+        [0, 0, 75, 75]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 278],
+      "bounds": [878, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [878, 0],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [878, 278],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/new-stacking-context-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/new-stacking-context-expected.txt
new file mode 100644
index 0000000..9ff1f973
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/new-stacking-context-expected.txt
@@ -0,0 +1,47 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [150, 150],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [300, 300],
+      "invalidations": [
+        [0, 0, 300, 300]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [0, 150],
+      "bounds": [150, 0],
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [150, 0],
+      "bounds": [0, 150],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited-expected.txt
new file mode 100644
index 0000000..3da0f260
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/opacity-from-zero-to-non-zero-composited-expected.txt
@@ -0,0 +1,29 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='target'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/overlap-test-with-filter-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
new file mode 100644
index 0000000..6054663
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/overlap-test-with-filter-expected.txt
@@ -0,0 +1,54 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutIFrame IFRAME",
+      "bounds": [450, 150]
+    },
+    {
+      "name": "LayoutView #document",
+      "bounds": [450, 150],
+      "contentsOpaqueForText": true,
+      "backgroundColor": "#FFFF00"
+    },
+    {
+      "name": "LayoutNGBlockFlow BODY",
+      "bounds": [426, 126],
+      "backgroundColor": "#FFFF00",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [450, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [226.5, 0, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/pointer-events-composited-scrolling-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/pointer-events-composited-scrolling-expected.txt
new file mode 100644
index 0000000..a30b4038
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/pointer-events-composited-scrolling-expected.txt
@@ -0,0 +1,42 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='target'",
+      "bounds": [150, 150],
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [0, 150],
+      "bounds": [150, 0],
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [150, 0],
+      "bounds": [0, 150],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt
new file mode 100644
index 0000000..f3764966
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/remove-squashed-layer-plus-move-expected.txt
@@ -0,0 +1,54 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [2127, 1512],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [1500, 1500],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (relative positioned) DIV class='mv-tile')",
+      "bounds": [1500, 156],
+      "invalidations": [
+        [0, 81, 150, 75],
+        [0, 0, 150, 75]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/repaint-overflow-scrolled-squashed-content-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/repaint-overflow-scrolled-squashed-content-expected.txt
new file mode 100644
index 0000000..fdff55bf
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/repaint-overflow-scrolled-squashed-content-expected.txt
@@ -0,0 +1,60 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [300, 300],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 278],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [278, 0],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [278, 278],
+      "bounds": [22, 22],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='foo2'",
+      "bounds": [225, 1500],
+      "contentsOpaque": true,
+      "backgroundColor": "#ADD8E6",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV id='foo')",
+      "bounds": [150, 1500],
+      "invalidations": [
+        [0, 0, 150, 1500]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/repaint-squashed-layer-in-rect-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/repaint-squashed-layer-in-rect-expected.txt
new file mode 100644
index 0000000..474abe6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/repaint-squashed-layer-in-rect-expected.txt
@@ -0,0 +1,55 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1212, 1224],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [1200, 1200],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV)",
+      "position": [0, -12],
+      "bounds": [888, 900],
+      "invalidations": [
+        [588, 600, 300, 300]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/repaint-via-layout-offset-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/repaint-via-layout-offset-expected.txt
new file mode 100644
index 0000000..0ab1cd8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/repaint-via-layout-offset-expected.txt
@@ -0,0 +1,38 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [300, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#ADD8E6",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) SPAN class='child')",
+      "position": [63, 63],
+      "bounds": [75, 75],
+      "invalidations": [
+        [0, 0, 75, 75]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/resize-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/resize-repaint-expected.txt
new file mode 100644
index 0000000..28cd59d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/resize-repaint-expected.txt
@@ -0,0 +1,30 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='resizing'",
+      "bounds": [603, 311],
+      "invalidations": [
+        [0, 0, 603, 311]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/resize-squashing-layer-that-needs-full-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/resize-squashing-layer-that-needs-full-repaint-expected.txt
new file mode 100644
index 0000000..694174c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/resize-squashing-layer-that-needs-full-repaint-expected.txt
@@ -0,0 +1,37 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [750, 750],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV)",
+      "position": [70, 70],
+      "bounds": [751, 751],
+      "invalidations": [
+        [0, 0, 751, 751]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scroll-fixed-layer-no-content-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scroll-fixed-layer-no-content-expected.txt
new file mode 100644
index 0000000..6ef0352d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scroll-fixed-layer-no-content-expected.txt
@@ -0,0 +1,44 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [300, 300],
+      "drawsContent": false,
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -150, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scroll-fixed-layer-out-of-view-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scroll-fixed-layer-out-of-view-expected.txt
new file mode 100644
index 0000000..0a419f0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scroll-fixed-layer-out-of-view-expected.txt
@@ -0,0 +1,61 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [132, 132],
+      "contentsOpaque": true,
+      "backgroundColor": "#C0C0C0",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [149, 149],
+      "contentsOpaque": true,
+      "backgroundColor": "#C0C0C0",
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -150, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, -450, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 1500, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scroll-fixed-squahed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scroll-fixed-squahed-layer-expected.txt
new file mode 100644
index 0000000..0e0e308f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scroll-fixed-squahed-layer-expected.txt
@@ -0,0 +1,61 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='main'",
+      "bounds": [300, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#ADD8E6",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='squahed'",
+      "bounds": [300, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#90EE90",
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -150, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 150, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 225, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scrolling-neg-z-index-descendants-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scrolling-neg-z-index-descendants-expected.txt
new file mode 100644
index 0000000..3c4079a8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scrolling-neg-z-index-descendants-expected.txt
@@ -0,0 +1,61 @@
+{
+  "layers": [
+    {
+      "name": "LayoutNGBlockFlow HTML",
+      "bounds": [1200, 477]
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='neg-z'",
+      "position": [2, 17],
+      "bounds": [150, 615],
+      "backfaceVisibility": "hidden",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow HTML (foreground) Layer",
+      "bounds": [1200, 477]
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='container'",
+      "bounds": [153, 453],
+      "backfaceVisibility": "hidden",
+      "transform": 1
+    },
+    {
+      "name": "Horizontal Scrollbar Layer",
+      "position": [1, 452],
+      "bounds": [150, 0],
+      "backfaceVisibility": "hidden",
+      "transform": 1
+    },
+    {
+      "name": "Vertical Scrollbar Layer",
+      "position": [152, 1],
+      "bounds": [0, 450],
+      "backfaceVisibility": "hidden",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scrolling-without-painting-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scrolling-without-painting-expected.txt
new file mode 100644
index 0000000..46fb183a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/scrolling-without-painting-expected.txt
@@ -0,0 +1,61 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='scroller'",
+      "bounds": [303, 303],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [2, 2],
+      "bounds": [278, 1538],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [1, 280],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [280, 1],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [279, 279],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -37, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-invoke-deferred-compositing-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-invoke-deferred-compositing-expected.txt
new file mode 100644
index 0000000..961c178
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-invoke-deferred-compositing-expected.txt
@@ -0,0 +1,27 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='container' class='composited box'",
+      "bounds": [450, 450],
+      "drawsContent": false
+    },
+    {
+      "name": "LayoutHTMLCanvas (positioned) CANVAS",
+      "bounds": [300, 300],
+      "invalidations": [
+        [0, 0, 300, 300]
+      ]
+    },
+    {
+      "name": "ContentsLayer for LayoutHTMLCanvas (positioned) CANVAS",
+      "bounds": [300, 300]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt
new file mode 100644
index 0000000..36050af3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -0,0 +1,63 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='container'",
+      "bounds": [600, 450],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1500, 1500],
+      "invalidations": [
+        [0, 0, 1500, 1500]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 428],
+      "bounds": [578, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [578, 0],
+      "bounds": [22, 428],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [578, 428],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-750, -600, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-clip-composited-viewport-scrolling-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-clip-composited-viewport-scrolling-layer-expected.txt
new file mode 100644
index 0000000..a7c271c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-clip-composited-viewport-scrolling-layer-expected.txt
@@ -0,0 +1,43 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [3012, 2274],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 3000, 2250]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-1350, -1050, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-paint-outline-on-foreground-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-paint-outline-on-foreground-layer-expected.txt
new file mode 100644
index 0000000..528b241
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-paint-outline-on-foreground-layer-expected.txt
@@ -0,0 +1,73 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='container'",
+      "position": [-15, -15],
+      "bounds": [480, 480],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [4500, 4500],
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#FF0000",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='container' (foreground) Layer",
+      "bounds": [4500, 4500],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 428],
+      "bounds": [428, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [428, 0],
+      "bounds": [22, 428],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [428, 428],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -600, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt
new file mode 100644
index 0000000..537aa29
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-descendants-expected.txt
@@ -0,0 +1,50 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='composited-box'",
+      "position": [45, 45],
+      "bounds": [30, 105],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 30, 105]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='composited child'",
+      "bounds": [75, 75],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 75, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-descendants-on-overflow-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-descendants-on-overflow-change-expected.txt
new file mode 100644
index 0000000..75461cc
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-descendants-on-overflow-change-expected.txt
@@ -0,0 +1,67 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='composited-child'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000"
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV class='composited-child overflow-child'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='composited-child'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV class='composited-child overflow-child'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 3
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [225, 225, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 300, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [225, 525, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-filter-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-filter-expected.txt
new file mode 100644
index 0000000..00f08b1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-filter-expected.txt
@@ -0,0 +1,29 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='composited-box'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-opacity-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-opacity-expected.txt
new file mode 100644
index 0000000..00f08b1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-opacity-expected.txt
@@ -0,0 +1,29 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='composited-box'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt
new file mode 100644
index 0000000..2d3dd9d3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-transform-expected.txt
@@ -0,0 +1,37 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='composited-box'",
+      "bounds": [153, 153],
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-z-index-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-z-index-expected.txt
new file mode 100644
index 0000000..734076da
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-composited-z-index-expected.txt
@@ -0,0 +1,30 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='composited-box'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-move-backface-hidden-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-move-backface-hidden-expected.txt
new file mode 100644
index 0000000..c2cd5cb2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-move-backface-hidden-expected.txt
@@ -0,0 +1,30 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='target'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 300, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-scrolling-contents-outline-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-scrolling-contents-outline-change-expected.txt
new file mode 100644
index 0000000..a132562ff
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/should-not-repaint-scrolling-contents-outline-change-expected.txt
@@ -0,0 +1,56 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='target'",
+      "position": [-15, -15],
+      "bounds": [330, 330],
+      "invalidations": [
+        [0, 0, 330, 330]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [278, 3000],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 278],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [278, 0],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [278, 278],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/squash-partial-repaint-inside-squashed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/squash-partial-repaint-inside-squashed-layer-expected.txt
new file mode 100644
index 0000000..4d7603d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/squash-partial-repaint-inside-squashed-layer-expected.txt
@@ -0,0 +1,38 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='composited box behind'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV class='box middle')",
+      "position": [120, 120],
+      "bounds": [393, 300],
+      "invalidations": [
+        [120, 120, 273, 44]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt
new file mode 100644
index 0000000..5125e06
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/squashing-inside-preserve-3d-element-expected.txt
@@ -0,0 +1,51 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 3
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV id='target')",
+      "position": [30, 30],
+      "bounds": [150, 150],
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "renderingContext": 1
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ],
+      "flattenInheritedTransform": false,
+      "renderingContext": 1
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "flattenInheritedTransform": false,
+      "renderingContext": 1
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt
new file mode 100644
index 0000000..e55499e1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/stacked-float-under-composited-inline-expected.txt
@@ -0,0 +1,20 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutInline (relative positioned) SPAN",
+      "position": [237, 237],
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "invalidations": [
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/text-color-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/text-color-change-expected.txt
new file mode 100644
index 0000000..083390e4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/text-color-change-expected.txt
@@ -0,0 +1,53 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow PRE id='scroller'",
+      "bounds": [300, 300],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [278, 902],
+      "invalidations": [
+        [0, 0, 72, 902]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 278],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [278, 0],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [278, 278],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 86, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/text-match-highlight-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/text-match-highlight-expected.txt
new file mode 100644
index 0000000..8a4aeb57
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/text-match-highlight-expected.txt
@@ -0,0 +1,62 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [428, 54, 69, 26]
+      ]
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [1200, 750],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 2010],
+      "invalidations": [
+        [15, 108, 345, 27],
+        [32, 243, 266, 105],
+        [15, 192, 207, 18],
+        [410, 0, 69, 26],
+        [341, 0, 69, 26],
+        [137, 0, 69, 26],
+        [80, 27, 69, 26]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 728],
+      "bounds": [1178, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 728],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 728],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 81, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/tricky-element-removal-crash-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/tricky-element-removal-crash-expected.txt
new file mode 100644
index 0000000..7ca62a1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/tricky-element-removal-crash-expected.txt
@@ -0,0 +1,34 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [300, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#FA8072",
+      "transform": 1
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (positioned) DIV)",
+      "bounds": [150, 150],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/updating-scrolling-container-and-content-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/updating-scrolling-container-and-content-expected.txt
new file mode 100644
index 0000000..3fc72e3f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/updating-scrolling-container-and-content-expected.txt
@@ -0,0 +1,75 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='container'",
+      "bounds": [300, 300],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [278, 351],
+      "invalidations": [
+        [0, 324, 112, 26],
+        [0, 297, 112, 26],
+        [0, 270, 112, 26],
+        [0, 243, 112, 26],
+        [0, 216, 112, 26],
+        [0, 189, 112, 26],
+        [0, 162, 112, 26],
+        [0, 135, 112, 26],
+        [0, 108, 112, 26],
+        [0, 81, 112, 26],
+        [0, 54, 112, 26],
+        [0, 27, 112, 26],
+        [0, 0, 112, 26]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 278],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [278, 0],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [278, 278],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 162, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -73, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/updating-scrolling-container-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/updating-scrolling-container-expected.txt
new file mode 100644
index 0000000..53ba77bd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/updating-scrolling-container-expected.txt
@@ -0,0 +1,54 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='container'",
+      "bounds": [315, 315],
+      "invalidations": [
+        [0, 0, 315, 315]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [8, 8],
+      "bounds": [600, 600],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [7, 286],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [286, 7],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [285, 285],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 162, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/updating-scrolling-content-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/updating-scrolling-content-expected.txt
new file mode 100644
index 0000000..29ee1b1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/compositing/updating-scrolling-content-expected.txt
@@ -0,0 +1,53 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='scroller'",
+      "bounds": [300, 300],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [278, 1800],
+      "invalidations": [
+        [0, 0, 278, 300]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 278],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [278, 0],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [278, 278],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-2-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-2-expected.txt
new file mode 100644
index 0000000..8d75bb2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-2-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [522, 126, 150, 150],
+        [132, 126, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-3-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-3-expected.txt
new file mode 100644
index 0000000..6c563bd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-3-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [762, 306, 150, 150],
+        [762, 126, 150, 150],
+        [612, 306, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-4-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-4-expected.txt
new file mode 100644
index 0000000..9d3effa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-4-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [612, 126, 150, 150],
+        [312, 126, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-expected.txt
new file mode 100644
index 0000000..8d75bb2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/crbug-371640-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [522, 126, 150, 150],
+        [132, 126, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/create-layer-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/create-layer-repaint-expected.txt
new file mode 100644
index 0000000..7217587
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/create-layer-repaint-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [42, 81, 750, 75]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/cull-rect-change-crash-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/cull-rect-change-crash-expected.txt
new file mode 100644
index 0000000..1d599367
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/cull-rect-change-crash-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 12, 1, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/delete-into-nested-block-expected.txt
new file mode 100644
index 0000000..aaa7fd2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/delete-into-nested-block-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 231, 49, 29],
+        [12, 177, 49, 29],
+        [12, 204, 36, 29]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/details-open-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/details-open-repaint-expected.txt
new file mode 100644
index 0000000..fd970df
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/details-open-repaint-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 102, 258, 32],
+        [12, 80, 16, 16]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/empty-object-move-and-resize-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/empty-object-move-and-resize-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/empty-object-move-and-resize-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-1-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-1-expected.txt
new file mode 100644
index 0000000..03cd957b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-1-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [192, 180, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-2-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-2-expected.txt
new file mode 100644
index 0000000..f38753b9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-2-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [192, 180, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-3-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-3-expected.txt
new file mode 100644
index 0000000..0d64f73
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-3-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 492, 480]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-4-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-4-expected.txt
new file mode 100644
index 0000000..f38753b9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-4-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [192, 180, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-5-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-5-expected.txt
new file mode 100644
index 0000000..03cd957b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-5-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [192, 180, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-6-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-6-expected.txt
new file mode 100644
index 0000000..0ce7279d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-composite-6-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [42, 30, 450, 450]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-displacement-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-displacement-expected.txt
new file mode 100644
index 0000000..94eb48e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-displacement-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 0, 360, 360]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-gaussianblur-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-gaussianblur-expected.txt
new file mode 100644
index 0000000..e61c0dd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-gaussianblur-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 477, 465]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-gaussianblur-xonly-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-gaussianblur-xonly-expected.txt
new file mode 100644
index 0000000..00f3beeb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-gaussianblur-xonly-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 75, 477, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-gaussianblur-yonly-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-gaussianblur-yonly-expected.txt
new file mode 100644
index 0000000..4edac5d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-gaussianblur-yonly-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [87, 0, 300, 465]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-lighting-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-lighting-expected.txt
new file mode 100644
index 0000000..85789946
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-lighting-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [117, 105, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-merge-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-merge-expected.txt
new file mode 100644
index 0000000..0ce7279d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-merge-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [42, 30, 450, 450]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-morphology-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-morphology-expected.txt
new file mode 100644
index 0000000..bf443c8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-morphology-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [49, 37, 376, 376]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-morphology-xonly-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-morphology-xonly-expected.txt
new file mode 100644
index 0000000..a6dfacdc
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-morphology-xonly-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [49, 75, 376, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-morphology-yonly-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-morphology-yonly-expected.txt
new file mode 100644
index 0000000..16e9519
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-morphology-yonly-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [87, 37, 300, 376]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-offset-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-offset-expected.txt
new file mode 100644
index 0000000..255b4a7e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-offset-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [297, 297, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-primitive-attr-mutation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-primitive-attr-mutation-expected.txt
new file mode 100644
index 0000000..d9f3e56d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-primitive-attr-mutation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-primitive-attr-removal-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-primitive-attr-removal-expected.txt
new file mode 100644
index 0000000..d9f3e56d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-primitive-attr-removal-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-primitive-removed-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-primitive-removed-expected.txt
new file mode 100644
index 0000000..d9f3e56d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/effect-reference-repaint-primitive-removed-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-invalidation-after-display-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-invalidation-after-display-expected.txt
new file mode 100644
index 0000000..e9cceb6c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-invalidation-after-display-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [450, 12, 495, 495]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-invalidation-positioned-child-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-invalidation-positioned-child-expected.txt
new file mode 100644
index 0000000..43592123
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-invalidation-positioned-child-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 645, 345],
+        [612, 612, 570, 270]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-invalidation-with-composited-container-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-invalidation-with-composited-container-change-expected.txt
new file mode 100644
index 0000000..811a09d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-invalidation-with-composited-container-change-expected.txt
@@ -0,0 +1,35 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 495, 495]
+      ]
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='box' class='green box blurry'",
+      "bounds": [300, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-on-html-element-with-fixed-position-child-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-on-html-element-with-fixed-position-child-expected.txt
new file mode 100644
index 0000000..2ef60b1d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-on-html-element-with-fixed-position-child-expected.txt
@@ -0,0 +1,59 @@
+{
+  "layers": [
+    {
+      "name": "LayoutNGBlockFlow HTML",
+      "bounds": [1178, 15024],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -15, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child-expected.txt
new file mode 100644
index 0000000..a786d33
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child-expected.txt
@@ -0,0 +1,36 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='blur'",
+      "bounds": [300, 300],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='accelerated'",
+      "position": [-18, -18],
+      "bounds": [318, 384],
+      "invalidations": [
+        [0, 0, 318, 384]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-repaint-accelerated-on-accelerated-filter-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-repaint-accelerated-on-accelerated-filter-expected.txt
new file mode 100644
index 0000000..95b5863
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-repaint-accelerated-on-accelerated-filter-expected.txt
@@ -0,0 +1,37 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='blur accelerated'",
+      "bounds": [300, 300],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='resize' class='drop-shadow accelerated'",
+      "bounds": [150, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 150, 300]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-repaint-on-accelerated-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-repaint-on-accelerated-layer-expected.txt
new file mode 100644
index 0000000..b5e3e0f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/filters/filter-repaint-on-accelerated-layer-expected.txt
@@ -0,0 +1,34 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='blur'",
+      "bounds": [300, 300],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='resize' class='accelerated'",
+      "bounds": [150, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-change-expected.txt
new file mode 100644
index 0000000..4665805
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-change-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 303, 300, 225],
+        [0, 78, 300, 225]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-change-keeping-geometry-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-change-keeping-geometry-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-change-keeping-geometry-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-change-no-flex-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-change-no-flex-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-change-no-flex-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-distribution-change-grid-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-distribution-change-grid-expected.txt
new file mode 100644
index 0000000..feefff3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-content-distribution-change-grid-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 378, 300, 150],
+        [0, 228, 300, 150],
+        [0, 78, 300, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-items-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-items-change-expected.txt
new file mode 100644
index 0000000..0e7bcc2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-items-change-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 78, 150, 450],
+        [0, 78, 150, 450]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-expected.txt
new file mode 100644
index 0000000..0e7bcc2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 78, 150, 450],
+        [0, 78, 150, 450]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-grid-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-grid-expected.txt
new file mode 100644
index 0000000..5d4de31
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-grid-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 78, 150, 450],
+        [150, 190, 150, 226],
+        [150, 303, 150, 225],
+        [150, 78, 150, 225]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-keeping-geometry-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-keeping-geometry-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-keeping-geometry-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-keeping-geometry-grid-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-keeping-geometry-grid-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-keeping-geometry-grid-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-no-flex-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-no-flex-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/align-self-change-no-flex-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-content-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-content-change-expected.txt
new file mode 100644
index 0000000..e996960
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-content-change-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [222, 78, 78, 450],
+        [186, 78, 78, 450],
+        [36, 78, 78, 450],
+        [0, 78, 78, 450]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-content-distribution-change-grid-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-content-distribution-change-grid-expected.txt
new file mode 100644
index 0000000..e1fcaadfe
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-content-distribution-change-grid-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [300, 78, 150, 300],
+        [150, 78, 150, 300],
+        [0, 78, 150, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-items-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-items-change-expected.txt
new file mode 100644
index 0000000..7233e3a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-items-change-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [225, 78, 75, 450],
+        [0, 78, 75, 450]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-items-legacy-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-items-legacy-change-expected.txt
new file mode 100644
index 0000000..546640b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-items-legacy-change-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [186, 78, 78, 225],
+        [150, 78, 78, 225],
+        [36, 78, 78, 225],
+        [0, 78, 78, 225]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-self-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-self-change-expected.txt
new file mode 100644
index 0000000..0ee55946
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-self-change-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 78, 150, 450],
+        [187, 78, 76, 450],
+        [225, 78, 75, 450],
+        [150, 78, 75, 450]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-self-change-keeping-geometry-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-self-change-keeping-geometry-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/justify-self-change-keeping-geometry-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt
new file mode 100644
index 0000000..b104ff7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 300, 150, 150],
+        [0, 150, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-column-reverse-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-column-reverse-expected.txt
new file mode 100644
index 0000000..11e0c688a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-column-reverse-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 102, 300, 45],
+        [13, 103, 298, 46]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-during-resize-no-flex-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-during-resize-no-flex-expected.txt
new file mode 100644
index 0000000..2036e37
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-during-resize-no-flex-expected.txt
@@ -0,0 +1,18 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [45, 30, 60, 75],
+        [240, 30, 15, 75],
+        [180, 30, 15, 75],
+        [165, 30, 15, 75],
+        [105, 30, 15, 75]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-expected.txt
new file mode 100644
index 0000000..0a0737a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [208, 174, 980, 162],
+        [600, 174, 588, 243],
+        [12, 336, 588, 81],
+        [222, 174, 378, 243]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-on-layout-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-on-layout-expected.txt
new file mode 100644
index 0000000..2eb9333
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-on-layout-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [1068, 12, 120, 30]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-on-margin-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-on-margin-change-expected.txt
new file mode 100644
index 0000000..8f3ab05a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/flexbox/repaint-on-margin-change-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [72, 42, 30, 30],
+        [12, 42, 30, 30]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/destroy-overlay-scrollbar-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/destroy-overlay-scrollbar-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/destroy-overlay-scrollbar-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/destroy-scrollbar-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/destroy-scrollbar-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/destroy-scrollbar-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/document-flipped-blocks-writing-mode-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/document-flipped-blocks-writing-mode-scroll-expected.txt
new file mode 100644
index 0000000..c82c71f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/document-flipped-blocks-writing-mode-scroll-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [2274, 878],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000"
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1200, 22],
+      "contentsOpaque": true
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-after-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-after-scroll-expected.txt
new file mode 100644
index 0000000..289528f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-after-scroll-expected.txt
@@ -0,0 +1,67 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 300, 150, 150]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='red fixed'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#FF0000",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='t' class='green absolute'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -750, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 300, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 300, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-and-absolute-position-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-and-absolute-position-scrolled-expected.txt
new file mode 100644
index 0000000..40e8088
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-and-absolute-position-scrolled-expected.txt
@@ -0,0 +1,56 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='fixed red'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#FF0000",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='absoluteDiv' class='absolute green'",
+      "position": [150, 1050],
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -750, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 300, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-move-after-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-move-after-scroll-expected.txt
new file mode 100644
index 0000000..628007c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-move-after-scroll-expected.txt
@@ -0,0 +1,48 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 4524],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='toMove'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -300, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [225, 105, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-of-fixed-move-after-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-of-fixed-move-after-scroll-expected.txt
new file mode 100644
index 0000000..628007c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-of-fixed-move-after-scroll-expected.txt
@@ -0,0 +1,48 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 4524],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='toMove'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -300, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [225, 105, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-of-transformed-move-after-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-of-transformed-move-after-scroll-expected.txt
new file mode 100644
index 0000000..7dba556
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-of-transformed-move-after-scroll-expected.txt
@@ -0,0 +1,33 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 4524],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [237, 417, 150, 150],
+        [27, 417, 150, 150]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -300, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-of-transformed-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-of-transformed-scrolled-expected.txt
new file mode 100644
index 0000000..7be6fb83
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-child-of-transformed-scrolled-expected.txt
@@ -0,0 +1,63 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='transformed'",
+      "bounds": [450, 450],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1500, 1500],
+      "invalidations": [
+        [150, 225, 150, 150]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 428],
+      "bounds": [428, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [428, 0],
+      "bounds": [22, 428],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [428, 428],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 75, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -75, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-descendant-of-transformed-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-descendant-of-transformed-scrolled-expected.txt
new file mode 100644
index 0000000..bad99e7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-descendant-of-transformed-scrolled-expected.txt
@@ -0,0 +1,63 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='transformed'",
+      "bounds": [450, 450],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1575, 1575],
+      "invalidations": [
+        [150, 225, 150, 150]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 428],
+      "bounds": [428, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [428, 0],
+      "bounds": [22, 428],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [428, 428],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 75, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -75, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-move-after-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-move-after-scroll-expected.txt
new file mode 100644
index 0000000..628007c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-move-after-scroll-expected.txt
@@ -0,0 +1,48 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 4524],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='toMove'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -300, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [225, 105, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-scroll-simple-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-scroll-simple-expected.txt
new file mode 100644
index 0000000..244fefe
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-scroll-simple-expected.txt
@@ -0,0 +1,45 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='green'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -150, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-scroll-viewport-scroll-hidden-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-scroll-viewport-scroll-hidden-expected.txt
new file mode 100644
index 0000000..8991490
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-scroll-viewport-scroll-hidden-expected.txt
@@ -0,0 +1,27 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 300, 150, 150],
+        [12, 150, 150, 150]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-under-composited-absolute-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-under-composited-absolute-scrolled-expected.txt
new file mode 100644
index 0000000..db57a14
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-under-composited-absolute-scrolled-expected.txt
@@ -0,0 +1,56 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3002],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='absolute'",
+      "bounds": [2, 2],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "backgroundColor": "#FF0000",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='fixed'",
+      "bounds": [150, 300],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 150, 150, 150]
+      ]
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -600, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 3000, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-with-border-under-composited-absolute-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-with-border-under-composited-absolute-scrolled-expected.txt
new file mode 100644
index 0000000..f2cae312
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/fixed-with-border-under-composited-absolute-scrolled-expected.txt
@@ -0,0 +1,56 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3002],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='absolute'",
+      "bounds": [2, 2],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "backgroundColor": "#FF0000",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='fixed'",
+      "bounds": [180, 330],
+      "contentsOpaque": true,
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 180, 330]
+      ]
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -600, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 3000, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/flipped-blocks-writing-mode-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/flipped-blocks-writing-mode-scroll-expected.txt
new file mode 100644
index 0000000..9335943
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/flipped-blocks-writing-mode-scroll-expected.txt
@@ -0,0 +1,41 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='scroller'",
+      "bounds": [600, 600],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [15000, 578],
+      "invalidations": [
+        [0, 0, 15000, 300]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 578],
+      "bounds": [600, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/iframe-gradient-background-scroll-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/iframe-gradient-background-scroll-repaint-expected.txt
new file mode 100644
index 0000000..31a07b6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/iframe-gradient-background-scroll-repaint-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [15, 15, 450, 225]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/iframe-scroll-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/iframe-scroll-repaint-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/iframe-scroll-repaint-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/iframe-scrollbar-hover-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/iframe-scrollbar-hover-expected.txt
new file mode 100644
index 0000000..49c38e9c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/iframe-scrollbar-hover-expected.txt
@@ -0,0 +1,48 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutIFrame (positioned) IFRAME id='iframe'",
+      "bounds": [306, 306],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [278, 474],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [278, 0],
+      "bounds": [22, 300],
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 150, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [3, 3, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/inline-style-change-in-scrolled-view-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/inline-style-change-in-scrolled-view-expected.txt
new file mode 100644
index 0000000..c83c8be
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/inline-style-change-in-scrolled-view-expected.txt
@@ -0,0 +1,43 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [3000, 3000],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 432, 631, 26]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-300, -300, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-after-composited-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-after-composited-scroll-expected.txt
new file mode 100644
index 0000000..0143ffb2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-after-composited-scroll-expected.txt
@@ -0,0 +1,51 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='scroller'",
+      "bounds": [300, 300],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [278, 7350],
+      "invalidations": [
+        [0, 3600, 150, 150]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [278, 0],
+      "bounds": [22, 300],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [450, 450, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -3525, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-after-composited-scroll-of-window-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-after-composited-scroll-of-window-expected.txt
new file mode 100644
index 0000000..5e9e11cd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-after-composited-scroll-of-window-expected.txt
@@ -0,0 +1,33 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 7401],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 7362, 843, 27],
+        [12, 3612, 150, 150]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -3525, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt
new file mode 100644
index 0000000..4307730
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -0,0 +1,32 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutTextControl INPUT id='root'",
+      "position": [-2, -2],
+      "bounds": [97, 36],
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 97, 36]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt
new file mode 100644
index 0000000..4307730
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -0,0 +1,32 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutTextControl INPUT id='root'",
+      "position": [-2, -2],
+      "bounds": [97, 36],
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 97, 36]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt
new file mode 100644
index 0000000..47b59577
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 177, 62, 26]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt
new file mode 100644
index 0000000..b9d1d4f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [153, 180, 63, 27]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt
new file mode 100644
index 0000000..be31e97
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 177, 51, 26]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt
new file mode 100644
index 0000000..a42c3b6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 26]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/nested-fixed-iframe-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/nested-fixed-iframe-scrolled-expected.txt
new file mode 100644
index 0000000..1b8db76
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/nested-fixed-iframe-scrolled-expected.txt
@@ -0,0 +1,32 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [33, 783, 150, 150]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -600, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/outline-change-in-scrollers-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/outline-change-in-scrollers-expected.txt
new file mode 100644
index 0000000..2c4622f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/outline-change-in-scrollers-expected.txt
@@ -0,0 +1,221 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [258, 258, 113, 113]
+      ]
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV class='scroll'",
+      "bounds": [195, 195],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [15, 15],
+      "bounds": [225, 225],
+      "invalidations": [
+        [0, 0, 113, 113]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [15, 158],
+      "bounds": [143, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [158, 15],
+      "bounds": [22, 143],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [158, 158],
+      "bounds": [22, 22],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV class='scroll'",
+      "bounds": [195, 195],
+      "transform": 2
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [15, 15],
+      "bounds": [143, 225],
+      "invalidations": [
+        [30, 0, 113, 113]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [15, 158],
+      "bounds": [143, 22],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [158, 15],
+      "bounds": [22, 143],
+      "transform": 2
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [158, 158],
+      "bounds": [22, 22],
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV class='scroll'",
+      "bounds": [195, 195],
+      "transform": 3
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [15, 15],
+      "bounds": [225, 225],
+      "invalidations": [
+        [0, 0, 113, 113]
+      ],
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [15, 158],
+      "bounds": [143, 22],
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [158, 15],
+      "bounds": [22, 143],
+      "transform": 3
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [158, 158],
+      "bounds": [22, 22],
+      "transform": 3
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV class='scroll'",
+      "bounds": [195, 195],
+      "transform": 4
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [37, 15],
+      "bounds": [143, 225],
+      "invalidations": [
+        [30, 0, 113, 113]
+      ],
+      "transform": 4
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [37, 158],
+      "bounds": [143, 22],
+      "transform": 4
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [15, 15],
+      "bounds": [22, 143],
+      "transform": 4
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [15, 158],
+      "bounds": [22, 22],
+      "transform": 4
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV class='scroll'",
+      "bounds": [195, 195],
+      "transform": 5
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [15, 15],
+      "bounds": [225, 143],
+      "invalidations": [
+        [0, 30, 113, 113]
+      ],
+      "transform": 5
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [15, 158],
+      "bounds": [143, 22],
+      "transform": 5
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [158, 15],
+      "bounds": [22, 143],
+      "transform": 5
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [158, 158],
+      "bounds": [22, 22],
+      "transform": 5
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [213, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [414, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 213, 0, 1]
+      ]
+    },
+    {
+      "id": 5,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [414, 213, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/outline-change-scrollable-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/outline-change-scrollable-expected.txt
new file mode 100644
index 0000000..00781a3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/outline-change-scrollable-expected.txt
@@ -0,0 +1,20 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1512, 878],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 1512, 192]
+      ]
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1200, 22],
+      "contentsOpaque": true
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-auto-in-overflow-auto-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-auto-in-overflow-auto-scrolled-expected.txt
new file mode 100644
index 0000000..ed2333f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-auto-in-overflow-auto-scrolled-expected.txt
@@ -0,0 +1,84 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='outerDiv'",
+      "bounds": [1176, 450],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1154, 1050],
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='innerDiv'",
+      "bounds": [1154, 600],
+      "transform": 3
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1132, 1200],
+      "transform": 4
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1132, 0],
+      "bounds": [22, 600],
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1154, 0],
+      "bounds": [22, 450],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -480, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 450, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -600, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-hidden-in-overflow-hidden-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-hidden-in-overflow-hidden-scrolled-expected.txt
new file mode 100644
index 0000000..254b02a6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-hidden-in-overflow-hidden-scrolled-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 27, 150, 285]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-hidden-yet-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-hidden-yet-scrolled-expected.txt
new file mode 100644
index 0000000..dfd873d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-hidden-yet-scrolled-expected.txt
@@ -0,0 +1,31 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='scroller'",
+      "bounds": [453, 453],
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [1, 301, 151, 151]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar-expected.txt
new file mode 100644
index 0000000..dfd873d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-hidden-yet-scrolled-with-custom-scrollbar-expected.txt
@@ -0,0 +1,31 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='scroller'",
+      "bounds": [453, 453],
+      "backfaceVisibility": "hidden",
+      "invalidations": [
+        [1, 301, 151, 151]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-move-after-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-move-after-scroll-expected.txt
new file mode 100644
index 0000000..945968c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-move-after-scroll-expected.txt
@@ -0,0 +1,64 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='scroller' class='scroller'",
+      "bounds": [1050, 600],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1028, 900],
+      "invalidations": [
+        [450, 300, 180, 75],
+        [75, 300, 180, 75]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 578],
+      "bounds": [1028, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1028, 0],
+      "bounds": [22, 578],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1028, 578],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [15, 90, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -150, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-after-move-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-after-move-expected.txt
new file mode 100644
index 0000000..b861fae
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-after-move-expected.txt
@@ -0,0 +1,64 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='scroller'",
+      "bounds": [450, 600],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [428, 1350],
+      "invalidations": [
+        [75, 465, 300, 75],
+        [75, 300, 300, 75]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 578],
+      "bounds": [428, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [428, 0],
+      "bounds": [22, 578],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [428, 578],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [15, 90, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -225, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt
new file mode 100644
index 0000000..551888c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt
@@ -0,0 +1,34 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [3012, 3138],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 3012, 3138]
+      ]
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22],
+      "invalidations": [
+        [0, 0, 22, 22]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-composited-non-stacking-child-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-composited-non-stacking-child-expected.txt
new file mode 100644
index 0000000..173b488
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-composited-non-stacking-child-expected.txt
@@ -0,0 +1,94 @@
+{
+  "layers": [
+    {
+      "name": "LayoutNGBlockFlow HTML",
+      "bounds": [1200, 402]
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='back'",
+      "position": [113, 98],
+      "bounds": [270, 150],
+      "contentsOpaque": true,
+      "backgroundColor": "#CCDDCC",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow HTML (foreground) Layer",
+      "bounds": [1200, 402]
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV class='scroller'",
+      "bounds": [465, 300],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [7, 271],
+      "bounds": [428, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [436, 7],
+      "bounds": [22, 263],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [435, 270],
+      "bounds": [22, 22],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV class='icon'",
+      "bounds": [60, 60],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFDDBB",
+      "transform": 3
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV class='list'",
+      "position": [38, 38],
+      "bounds": [270, 375],
+      "drawsContent": false,
+      "transform": 2
+    },
+    {
+      "name": "Squashing Layer (first squashed layer: LayoutNGBlockFlow (relative positioned) DIV class='commit')",
+      "position": [37, 37],
+      "bounds": [271, 376],
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [27, 90, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -75, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [300, 15, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-delete-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-delete-expected.txt
new file mode 100644
index 0000000..f0bbc30c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-delete-expected.txt
@@ -0,0 +1,51 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='t'",
+      "bounds": [120, 104],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [98, 297],
+      "invalidations": [
+        [0, 243, 65, 53]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [98, 0],
+      "bounds": [22, 104],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 117, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -192, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.png
new file mode 100644
index 0000000..735bbbdd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.txt
new file mode 100644
index 0000000..ed2333f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.txt
@@ -0,0 +1,84 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='outerDiv'",
+      "bounds": [1176, 450],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1154, 1050],
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='innerDiv'",
+      "bounds": [1154, 600],
+      "transform": 3
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1132, 1200],
+      "transform": 4
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1132, 0],
+      "bounds": [22, 600],
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1154, 0],
+      "bounds": [22, 450],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -480, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 450, 0, 1]
+      ]
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -600, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-local-background-text-color-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-local-background-text-color-change-expected.txt
new file mode 100644
index 0000000..c15e53e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/overflow-scroll-local-background-text-color-change-expected.txt
@@ -0,0 +1,65 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='scroller'",
+      "bounds": [300, 300],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [278, 825],
+      "contentsOpaque": true,
+      "backgroundColor": "#0000FF",
+      "invalidations": [
+        [0, 0, 278, 825]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 278],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [278, 0],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [278, 278],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -547, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/repaint-composited-child-in-scrolled-container-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/repaint-composited-child-in-scrolled-container-expected.txt
new file mode 100644
index 0000000..af49a982
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/repaint-composited-child-in-scrolled-container-expected.txt
@@ -0,0 +1,81 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='outer'",
+      "bounds": [450, 450],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [975, 900],
+      "backgroundColor": "#0000FF80",
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 428],
+      "bounds": [428, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [428, 0],
+      "bounds": [22, 428],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [428, 428],
+      "bounds": [22, 22],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='container'",
+      "bounds": [900, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FF0000",
+      "invalidations": [
+        [0, 0, 900, 900]
+      ],
+      "transform": 3
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-547, 0, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [75, 0, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/repaint-during-scroll-with-zoom-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/repaint-during-scroll-with-zoom-expected.txt
new file mode 100644
index 0000000..9c543a23
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/repaint-during-scroll-with-zoom-expected.txt
@@ -0,0 +1,72 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#C0C0C0"
+    },
+    {
+      "name": "LayoutIFrame (positioned) IFRAME",
+      "bounds": [383, 382],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [3012, 3024],
+      "contentsOpaqueForText": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 353],
+      "bounds": [353, 22],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [353, 0],
+      "bounds": [22, 353],
+      "transform": 2
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [353, 353],
+      "bounds": [22, 22],
+      "transform": 2
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 94, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [4, 4, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [-15, -15, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/resize-scrollable-div-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/resize-scrollable-div-expected.txt
new file mode 100644
index 0000000..c5df3e3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/resize-scrollable-div-expected.txt
@@ -0,0 +1,19 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 590, 428, 22],
+        [12, 290, 128, 22],
+        [440, 162, 22, 428],
+        [140, 162, 22, 128],
+        [440, 590, 22, 22],
+        [140, 290, 22, 22]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/resize-scrollable-iframe-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/resize-scrollable-iframe-expected.txt
new file mode 100644
index 0000000..a7c3601
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/resize-scrollable-iframe-expected.txt
@@ -0,0 +1,50 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutIFrame IFRAME id='iframe'",
+      "bounds": [450, 450],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1512, 1524],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 428],
+      "bounds": [428, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [428, 0],
+      "bounds": [22, 428],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [428, 428],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 162, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.txt
new file mode 100644
index 0000000..ed8058e8d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-descendant-with-cached-cliprects-expected.txt
@@ -0,0 +1,49 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 2840],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [1016, 75, 150, 150]
+      ],
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='scrollpanel'",
+      "bounds": [150, 150],
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -300, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [1016, 75, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-fixed-layer-with-no-visible-content-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-fixed-layer-with-no-visible-content-expected.txt
new file mode 100644
index 0000000..3128361
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-fixed-layer-with-no-visible-content-expected.txt
@@ -0,0 +1,46 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='moveMe' class='fixed clipped'",
+      "bounds": [150, 150],
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1500, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 225, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-fixed-layer-with-transformed-parent-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-fixed-layer-with-transformed-parent-layer-expected.txt
new file mode 100644
index 0000000..da968aed
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-fixed-layer-with-transformed-parent-layer-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [140, 352, 213, 213]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-in-clipped-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-in-clipped-layer-expected.txt
new file mode 100644
index 0000000..ae4a3ce
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-in-clipped-layer-expected.txt
@@ -0,0 +1,20 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 225, 150, 150]
+      ]
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-in-fixed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-in-fixed-layer-expected.txt
new file mode 100644
index 0000000..3128361
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-in-fixed-layer-expected.txt
@@ -0,0 +1,46 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='moveMe' class='fixed clipped'",
+      "bounds": [150, 150],
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1500, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [150, 225, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-in-transformed-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-in-transformed-layer-expected.txt
new file mode 100644
index 0000000..31b3123
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-in-transformed-layer-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [118, 193, 214, 214]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
new file mode 100644
index 0000000..2cdc149
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces-expected.txt
@@ -0,0 +1,60 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 7581],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) HEADER",
+      "bounds": [1154, 30],
+      "drawsContent": false,
+      "backfaceVisibility": "hidden",
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (positioned) DIV id='searchbar'",
+      "bounds": [225, 225],
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -2100, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 39, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [27, 675, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-with-transformed-parent-layer-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-with-transformed-parent-layer-expected.txt
new file mode 100644
index 0000000..31b3123
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scroll-with-transformed-parent-layer-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [118, 193, 214, 214]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-ancestor-clip-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-ancestor-clip-change-expected.txt
new file mode 100644
index 0000000..ad4b5058
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-ancestor-clip-change-expected.txt
@@ -0,0 +1,50 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='target'",
+      "bounds": [150, 300],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [600, 600],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 278],
+      "bounds": [128, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [128, 0],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [128, 278],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-damage-and-full-viewport-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-damage-and-full-viewport-repaint-expected.txt
new file mode 100644
index 0000000..9e7a7b04
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-damage-and-full-viewport-repaint-expected.txt
@@ -0,0 +1,55 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [1500, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1500, 900]
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='container'",
+      "bounds": [303, 303],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "position": [2, 2],
+      "bounds": [3000, 3000],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [1, 280],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [280, 1],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [279, 279],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 75, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-invalidation-on-resize-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-invalidation-on-resize-expected.txt
new file mode 100644
index 0000000..fed8e5b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-invalidation-on-resize-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 203, 428, 22],
+        [440, 75, 22, 128],
+        [140, 75, 22, 128],
+        [440, 203, 22, 22]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-invalidation-on-resize-with-border-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-invalidation-on-resize-with-border-expected.txt
new file mode 100644
index 0000000..64ae0f8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-invalidation-on-resize-with-border-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 75, 480, 180]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-parts-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-parts-expected.txt
new file mode 100644
index 0000000..5159c7d5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrollbar-parts-expected.txt
@@ -0,0 +1,50 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV",
+      "bounds": [150, 150],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [225, 450],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 128],
+      "bounds": [128, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [128, 0],
+      "bounds": [22, 128],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [128, 128],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrolled-iframe-scrollbar-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrolled-iframe-scrollbar-change-expected.txt
new file mode 100644
index 0000000..4a748f26
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/scrolled-iframe-scrollbar-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1206, 906],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 1206, 906]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt
new file mode 100644
index 0000000..455e605
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt
@@ -0,0 +1,83 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1178, 984],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow MAT id='scroller'",
+      "bounds": [540, 960],
+      "transform": 2
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [518, 3027],
+      "transform": 3
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [518, 0],
+      "bounds": [22, 960],
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow (sticky positioned) DIV id='sticky'",
+      "bounds": [518, 27],
+      "transform": 4
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 900],
+      "contentsOpaque": true
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, -0.0666666666666667],
+        [0, 0, 0, 1]
+      ],
+      "origin": [282, 492]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -52, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    },
+    {
+      "id": 4,
+      "parent": 3,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, 52, 0, 1]
+      ],
+      "flattenInheritedTransform": false
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/search-field-cancel-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/search-field-cancel-expected.txt
new file mode 100644
index 0000000..8e6df90
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/search-field-cancel-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [18, 66, 88, 25]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-expected.txt
new file mode 100644
index 0000000..345d04e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 72, 48]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-for-rtl-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-for-rtl-expected.txt
new file mode 100644
index 0000000..c706e0a4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-for-rtl-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 12, 60, 48]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt
new file mode 100644
index 0000000..d674d43
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-lr-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 48, 72]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-rl-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-rl-expected.txt
new file mode 100644
index 0000000..d674d43
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-includes-newline-for-vertical-rl-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 48, 72]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-with-br-includes-newline-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-with-br-includes-newline-expected.txt
new file mode 100644
index 0000000..0bc35be
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/invalidation-rect-with-br-includes-newline-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [36, 12, 24, 24],
+        [12, 36, 24, 24],
+        [12, 12, 24, 24]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/japanese-rl-selection-clear-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/japanese-rl-selection-clear-expected.txt
new file mode 100644
index 0000000..b6d14d2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/japanese-rl-selection-clear-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [465, 184, 701, 593]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/repaint-rect-for-vertical-writing-mode-with-positioned-root-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/repaint-rect-for-vertical-writing-mode-with-positioned-root-expected.txt
new file mode 100644
index 0000000..139b4a6f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/repaint-rect-for-vertical-writing-mode-with-positioned-root-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [278, 301, 27, 264]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selected-replaced-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selected-replaced-expected.txt
new file mode 100644
index 0000000..a67fcf7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selected-replaced-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 222, 321, 348],
+        [12, 102, 321, 348]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-after-delete-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-after-delete-expected.txt
new file mode 100644
index 0000000..db7551fd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-after-delete-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [57, 111, 228, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-after-remove-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-after-remove-expected.txt
new file mode 100644
index 0000000..db7551fd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-after-remove-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [57, 111, 228, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-change-in-iframe-with-relative-parent-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-change-in-iframe-with-relative-parent-expected.txt
new file mode 100644
index 0000000..8e19583
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-change-in-iframe-with-relative-parent-expected.txt
@@ -0,0 +1,21 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [27, 357, 60, 15],
+        [27, 327, 45, 15],
+        [27, 297, 45, 15],
+        [87, 357, 15, 15],
+        [72, 327, 15, 15],
+        [72, 297, 15, 15],
+        [27, 342, 15, 15],
+        [27, 312, 15, 15]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-clear-after-move-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-clear-after-move-expected.txt
new file mode 100644
index 0000000..02cabce8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-clear-after-move-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [150, 450, 75, 76]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-clear-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-clear-expected.txt
new file mode 100644
index 0000000..1ac3c26
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-clear-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
new file mode 100644
index 0000000..af322fc
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [10, 10, 97, 36]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
new file mode 100644
index 0000000..af322fc
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [10, 10, 97, 36]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-partial-invalidation-between-blocks-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-partial-invalidation-between-blocks-expected.txt
new file mode 100644
index 0000000..bddc481
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-partial-invalidation-between-blocks-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [16, 48, 114, 27],
+        [16, 16, 93, 27]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-rl-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-rl-expected.txt
new file mode 100644
index 0000000..de76860a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-rl-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [1161, 59, 27, 118]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-within-composited-scroller-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
new file mode 100644
index 0000000..74d8ff3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/selection-within-composited-scroller-expected.txt
@@ -0,0 +1,65 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='scroller'",
+      "bounds": [300, 300],
+      "transform": 1
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [300, 2430],
+      "contentsOpaque": true,
+      "backgroundColor": "#D3D3D3",
+      "invalidations": [
+        [0, 915, 34, 27]
+      ],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 278],
+      "bounds": [278, 22],
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [278, 0],
+      "bounds": [22, 278],
+      "transform": 1
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [278, 278],
+      "bounds": [22, 22],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -675, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/text-selection-rect-in-overflow-2-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/text-selection-rect-in-overflow-2-expected.txt
new file mode 100644
index 0000000..a8f9f10e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/text-selection-rect-in-overflow-2-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [27, 42, 358, 27]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/text-selection-rect-in-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/text-selection-rect-in-overflow-expected.txt
new file mode 100644
index 0000000..1661635
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/selection/text-selection-rect-in-overflow-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 27, 300, 27]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/set-text-content-same-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/set-text-content-same-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/set-text-content-same-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/stacked-diacritics-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/stacked-diacritics-expected.txt
new file mode 100644
index 0000000..c3a589e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/stacked-diacritics-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [28, 239, 196, 61]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/stacking-context-lost-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/stacking-context-lost-expected.txt
new file mode 100644
index 0000000..34a7a034
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/stacking-context-lost-expected.txt
@@ -0,0 +1,33 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow (relative positioned) DIV id='outer'",
+      "bounds": [150, 150],
+      "contentsOpaque": true,
+      "backfaceVisibility": "hidden",
+      "backgroundColor": "#008000",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ],
+      "transform": 1
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [417, 417, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/subtree-root-skipped-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/subtree-root-skipped-expected.txt
new file mode 100644
index 0000000..d39b866
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/subtree-root-skipped-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [18, 15, 51, 25],
+        [12, 432, 15, 30]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt
new file mode 100644
index 0000000..f1a89f70
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 102, 603, 603]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/absolute-sized-document-no-scrollbars-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/absolute-sized-document-no-scrollbars-expected.txt
new file mode 100644
index 0000000..f29b2b9d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/absolute-sized-document-no-scrollbars-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 1200, 900]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/add-background-property-on-root-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/add-background-property-on-root-expected.txt
new file mode 100644
index 0000000..d9f3e56d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/add-background-property-on-root-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/add-border-property-on-root-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/add-border-property-on-root-expected.txt
new file mode 100644
index 0000000..991b5bd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/add-border-property-on-root-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 180, 180]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/add-outline-property-on-root-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/add-outline-property-on-root-expected.txt
new file mode 100644
index 0000000..5dc7779
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/add-outline-property-on-root-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 177, 177]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-fill-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-fill-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-fill-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-target-id-changed-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-target-id-changed-expected.txt
new file mode 100644
index 0000000..fd4e3be05
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-target-id-changed-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-viewport-overflow-2-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-viewport-overflow-2-expected.txt
new file mode 100644
index 0000000..d068ec96
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-viewport-overflow-2-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 312, 150, 150],
+        [12, 237, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-viewport-overflow-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-viewport-overflow-expected.txt
new file mode 100644
index 0000000..24e8c55
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animate-viewport-overflow-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 312, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
new file mode 100644
index 0000000..669d528
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
@@ -0,0 +1,19 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [370, 132, 182, 65],
+        [305, 501, 182, 65],
+        [533, 185, 155, 156],
+        [164, 125, 155, 151],
+        [529, 594, 147, 147],
+        [135, 309, 147, 147]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-svg-as-image-background-offscreen-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-svg-as-image-background-offscreen-expected.txt
new file mode 100644
index 0000000..fa695d2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-svg-as-image-background-offscreen-expected.txt
@@ -0,0 +1,40 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [3012, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1500, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-svg-as-image-offscreen-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-svg-as-image-offscreen-expected.txt
new file mode 100644
index 0000000..fa695d2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-svg-as-image-offscreen-expected.txt
@@ -0,0 +1,40 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [3012, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "transform": 1
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1500, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt
new file mode 100644
index 0000000..f4697ded
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/animated-svg-as-image-transformed-offscreen-expected.txt
@@ -0,0 +1,54 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [3012, 3024],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='targetDiv'",
+      "bounds": [3000, 3000],
+      "transform": 2
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [12, 12, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -1500, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/append-text-node-to-tspan-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/append-text-node-to-tspan-expected.txt
new file mode 100644
index 0000000..783b79d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/append-text-node-to-tspan-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [15, 90, 465, 570]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/change-background-color-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/change-background-color-expected.txt
new file mode 100644
index 0000000..8b2970679
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/change-background-color-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 300, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/circle-move-invalidation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/circle-move-invalidation-expected.txt
new file mode 100644
index 0000000..be17073
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/circle-move-invalidation-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [294, 294, 114, 114],
+        [69, 69, 114, 114]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-child-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-child-changes-expected.txt
new file mode 100644
index 0000000..5998e8c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-child-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-href-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-href-changes-expected.txt
new file mode 100644
index 0000000..5998e8c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-href-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-id-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-id-changes-expected.txt
new file mode 100644
index 0000000..5998e8c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-id-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-units-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-units-changes-expected.txt
new file mode 100644
index 0000000..5998e8c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/clip-path-units-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/color-fill-currentColor-and-css-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/color-fill-currentColor-and-css-expected.txt
new file mode 100644
index 0000000..cdcdea3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/color-fill-currentColor-and-css-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 120, 120]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/color-stop-properties-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/color-stop-properties-expected.txt
new file mode 100644
index 0000000..8550f11
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/color-stop-properties-expected.txt
@@ -0,0 +1,54 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1212, 930],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [912, 552, 150, 150],
+        [912, 372, 150, 150],
+        [912, 192, 150, 150],
+        [912, 12, 150, 150],
+        [732, 552, 150, 150],
+        [732, 372, 150, 150],
+        [732, 192, 150, 150],
+        [732, 12, 150, 150],
+        [552, 552, 150, 150],
+        [552, 372, 150, 150],
+        [552, 192, 150, 150],
+        [552, 12, 150, 150],
+        [372, 552, 150, 150],
+        [372, 372, 150, 150],
+        [372, 192, 150, 150],
+        [372, 12, 150, 150],
+        [192, 552, 150, 150],
+        [192, 372, 150, 150],
+        [192, 192, 150, 150],
+        [192, 12, 150, 150],
+        [12, 552, 150, 150],
+        [12, 372, 150, 150],
+        [12, 192, 150, 150],
+        [12, 12, 150, 150]
+      ]
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/container-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/container-repaint-expected.txt
new file mode 100644
index 0000000..674bcc9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/container-repaint-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 150, 150, 75],
+        [0, 75, 150, 75]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/deep-dynamic-updates-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/deep-dynamic-updates-expected.txt
new file mode 100644
index 0000000..924f361
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/deep-dynamic-updates-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [37, 37, 601, 601]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
new file mode 100644
index 0000000..9d81e94
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 606, 306]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
new file mode 100644
index 0000000..9d81e94
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 606, 306]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/embedded-svg-size-changes-no-layout-triggers-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/embedded-svg-size-changes-no-layout-triggers-expected.txt
new file mode 100644
index 0000000..1608d334
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/embedded-svg-size-changes-no-layout-triggers-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 603, 303]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/ems-display-none-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/ems-display-none-expected.txt
new file mode 100644
index 0000000..32f25fb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/ems-display-none-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [75, 81, 860, 128]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/exs-display-none-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/exs-display-none-expected.txt
new file mode 100644
index 0000000..171f592
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/exs-display-none-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [75, 78, 860, 125]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-change-target-id-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-change-target-id-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-change-target-id-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-multiple-targets-id-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-multiple-targets-id-change-expected.txt
new file mode 100644
index 0000000..34131d64
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-multiple-targets-id-change-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [67, 0, 91, 165],
+        [0, 0, 83, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-reference-invalidation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-reference-invalidation-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-reference-invalidation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-remove-target-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-remove-target-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-remove-target-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-add-to-document-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-add-to-document-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-add-to-document-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-attribute-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-attribute-change-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-attribute-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-attribute-change-with-use-indirection-2-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-attribute-change-with-use-indirection-2-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-attribute-change-with-use-indirection-2-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-attribute-change-with-use-indirection-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-attribute-change-with-use-indirection-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-attribute-change-with-use-indirection-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-changes-id-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-changes-id-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-changes-id-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-id-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-id-change-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-id-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-inline-style-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-inline-style-change-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-inline-style-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-property-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-property-change-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-property-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-reappend-to-document-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-reappend-to-document-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-reappend-to-document-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-remove-from-document-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-remove-from-document-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-remove-from-document-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-style-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-style-change-expected.txt
new file mode 100644
index 0000000..5c4ce87
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/feImage-target-style-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/fecomponenttransfer-in1-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/fecomponenttransfer-in1-change-expected.txt
new file mode 100644
index 0000000..fd4e3be05
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/fecomponenttransfer-in1-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/fill-opacity-update-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/fill-opacity-update-expected.txt
new file mode 100644
index 0000000..5998e8c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/fill-opacity-update-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-child-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-child-repaint-expected.txt
new file mode 100644
index 0000000..829214b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-child-repaint-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 159, 159]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-reference-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-reference-change-expected.txt
new file mode 100644
index 0000000..b99e49a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-reference-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-refresh-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-refresh-expected.txt
new file mode 100644
index 0000000..366e38cdd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-refresh-expected.txt
@@ -0,0 +1,24 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [15, 255, 198, 54],
+        [15, 195, 198, 54],
+        [210, 210, 54, 54],
+        [210, 150, 54, 54],
+        [210, 90, 54, 54],
+        [135, 135, 54, 54],
+        [135, 75, 54, 54],
+        [75, 135, 54, 54],
+        [75, 75, 54, 54],
+        [15, 135, 54, 54],
+        [15, 75, 54, 54]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-width-update-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-width-update-expected.txt
new file mode 100644
index 0000000..7ad44cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/filter-width-update-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 210, 210]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/focus-element-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/focus-element-expected.txt
new file mode 100644
index 0000000..3e0f8f2c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/focus-element-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [84, 84, 81, 81]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/foreign-object-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/foreign-object-repaint-expected.txt
new file mode 100644
index 0000000..065837e2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/foreign-object-repaint-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [193, 300, 214, 213],
+        [75, 75, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/foreignObject-crash-on-hover-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/foreignObject-crash-on-hover-expected.txt
new file mode 100644
index 0000000..7f87abd0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/foreignObject-crash-on-hover-expected.txt
@@ -0,0 +1,11 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/gradient-add-stops-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/gradient-add-stops-expected.txt
new file mode 100644
index 0000000..fd4e3be05
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/gradient-add-stops-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/gradient-stop-style-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/gradient-stop-style-change-expected.txt
new file mode 100644
index 0000000..fd4e3be05
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/gradient-stop-style-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/hairline-stroke-squarecap-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/hairline-stroke-squarecap-expected.txt
new file mode 100644
index 0000000..a78f0b3d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/hairline-stroke-squarecap-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [296, 296, 159, 159],
+        [146, 146, 158, 158]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/image-href-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/image-href-change-expected.txt
new file mode 100644
index 0000000..5998e8c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/image-href-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/image-with-clip-path-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/image-with-clip-path-expected.txt
new file mode 100644
index 0000000..f1393b18
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/image-with-clip-path-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [30, 30, 90, 90],
+        [262, 37, 76, 76]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt
new file mode 100644
index 0000000..5998e8c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/inner-svg-change-viewBox-contract-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt
new file mode 100644
index 0000000..fd4e3be05
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/inner-svg-change-viewBox-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
new file mode 100644
index 0000000..5998e8c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/inner-svg-change-viewPort-relative-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/invalidate-on-child-layout-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/invalidate-on-child-layout-expected.txt
new file mode 100644
index 0000000..b66251a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/invalidate-on-child-layout-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [60, 60, 180, 180],
+        [0, 0, 165, 165]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt
new file mode 100644
index 0000000..e375c67
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [25, 60, 1175, 252]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-clipPath-creation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-clipPath-creation-expected.txt
new file mode 100644
index 0000000..e375c67
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-clipPath-creation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [25, 60, 1175, 252]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt
new file mode 100644
index 0000000..1fd0812
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 22, 1138, 543]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-gradient-creation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-gradient-creation-expected.txt
new file mode 100644
index 0000000..a1be04ff
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-gradient-creation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [50, 33, 1045, 286]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
new file mode 100644
index 0000000..8f1ab15
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [284, 297, 207, 206]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-marker-creation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-marker-creation-expected.txt
new file mode 100644
index 0000000..8f1ab15
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-marker-creation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [284, 297, 207, 206]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt
new file mode 100644
index 0000000..95b5e15
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 150, 1200, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-mask-creation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-mask-creation-expected.txt
new file mode 100644
index 0000000..95b5e15
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-mask-creation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 150, 1200, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt
new file mode 100644
index 0000000..40c6319
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 22, 1025, 543]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-pattern-creation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-pattern-creation-expected.txt
new file mode 100644
index 0000000..144427f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-late-pattern-creation-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [50, 33, 935, 286]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-repaint-rect-on-path-with-stroke-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-repaint-rect-on-path-with-stroke-expected.txt
new file mode 100644
index 0000000..6a7237e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-repaint-rect-on-path-with-stroke-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [44, 44, 212, 137],
+        [269, 44, 182, 137]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-bounce-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-bounce-expected.txt
new file mode 100644
index 0000000..10c9fa3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-bounce-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [152, 152, 101, 101],
+        [2, 2, 101, 101]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-container-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-container-expected.txt
new file mode 100644
index 0000000..300b2d9a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-container-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 113, 113]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-gradient-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-gradient-expected.txt
new file mode 100644
index 0000000..8935eb1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-gradient-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [15, 150, 645, 120],
+        [15, 15, 645, 120]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-image-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-image-expected.txt
new file mode 100644
index 0000000..300b2d9a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-image-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 113, 113]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-pattern-child-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-pattern-child-expected.txt
new file mode 100644
index 0000000..8935eb1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-pattern-child-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [15, 150, 645, 120],
+        [15, 15, 645, 120]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-pattern-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-pattern-expected.txt
new file mode 100644
index 0000000..8935eb1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-pattern-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [15, 150, 645, 120],
+        [15, 15, 645, 120]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-polygon-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-polygon-changes-expected.txt
new file mode 100644
index 0000000..01381e4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-polygon-changes-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [380, 313, 275, 192],
+        [380, 298, 275, 192]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-polygon-removal-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-polygon-removal-expected.txt
new file mode 100644
index 0000000..0d6ccda8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-polygon-removal-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [380, 313, 275, 192]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-stop-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-stop-expected.txt
new file mode 100644
index 0000000..8935eb1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-stop-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [15, 150, 645, 120],
+        [15, 15, 645, 120]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-stop-linked-gradient-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-stop-linked-gradient-expected.txt
new file mode 100644
index 0000000..0d976028
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-stop-linked-gradient-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [15, 315, 645, 120],
+        [15, 165, 645, 120],
+        [15, 15, 645, 120]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-style-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-style-expected.txt
new file mode 100644
index 0000000..46f599b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-style-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [9, 279, 237, 87],
+        [9, 189, 237, 87],
+        [9, 99, 237, 87],
+        [9, 9, 237, 87]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-transform-addition-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-transform-addition-expected.txt
new file mode 100644
index 0000000..0d6ccda8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-transform-addition-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [380, 313, 275, 192]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-transform-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-transform-changes-expected.txt
new file mode 100644
index 0000000..0d6ccda8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/js-update-transform-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [380, 313, 275, 192]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-child-changes-css-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-child-changes-css-expected.txt
new file mode 100644
index 0000000..080974d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-child-changes-css-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [170, 178, 125, 124]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-child-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-child-changes-expected.txt
new file mode 100644
index 0000000..080974d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-child-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [170, 178, 125, 124]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-strokeWidth-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-strokeWidth-changes-expected.txt
new file mode 100644
index 0000000..080974d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-strokeWidth-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [170, 178, 125, 124]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-text-decoration-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-text-decoration-change-expected.txt
new file mode 100644
index 0000000..484b2b5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-text-decoration-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 21, 222, 27]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-viewBox-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-viewBox-changes-expected.txt
new file mode 100644
index 0000000..b25930b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/marker-viewBox-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [134, 142, 161, 160]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/mask-child-changes-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/mask-child-changes-expected.txt
new file mode 100644
index 0000000..95b5e15
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/mask-child-changes-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 150, 1200, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/mask-clip-target-transform-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/mask-clip-target-transform-expected.txt
new file mode 100644
index 0000000..8066a5cf
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/mask-clip-target-transform-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [225, 75, 150, 150],
+        [75, 225, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/mask-invalidation-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/mask-invalidation-expected.txt
new file mode 100644
index 0000000..88ea541e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/mask-invalidation-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [75, 75, 680, 449],
+        [300, 150, 605, 374]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-inserted-listitem-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-inserted-listitem-expected.txt
new file mode 100644
index 0000000..06f01e21
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-inserted-listitem-expected.txt
@@ -0,0 +1,16 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [42, 57, 15, 15],
+        [42, 27, 15, 15],
+        [27, 27, 15, 15]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-text-node-in-tspan-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-text-node-in-tspan-expected.txt
new file mode 100644
index 0000000..783b79d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-text-node-in-tspan-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [15, 90, 465, 570]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt
new file mode 100644
index 0000000..4957c8f5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [34, 12, 128, 36],
+        [87, 67, 75, 41]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-transferred-listitem-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-transferred-listitem-expected.txt
new file mode 100644
index 0000000..f3582b5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/modify-transferred-listitem-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [27, 27, 45, 30]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
new file mode 100644
index 0000000..1608d334
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 603, 303]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
new file mode 100644
index 0000000..1608d334
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 603, 303]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt
new file mode 100644
index 0000000..49b47b7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 12, 603, 603]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/outline-offset-shape-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/outline-offset-shape-expected.txt
new file mode 100644
index 0000000..78a585c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/outline-offset-shape-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [16, 16, 217, 217],
+        [189, 16, 216, 217]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/outline-offset-text-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/outline-offset-text-expected.txt
new file mode 100644
index 0000000..6cff288
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/outline-offset-text-expected.txt
@@ -0,0 +1,15 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [144, 27, 261, 192],
+        [84, 27, 261, 192]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/overflow-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/overflow-repaint-expected.txt
new file mode 100644
index 0000000..9f783e51
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/overflow-repaint-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 162, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/paintorder-filtered-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/paintorder-filtered-expected.txt
new file mode 100644
index 0000000..82619be0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/paintorder-filtered-expected.txt
@@ -0,0 +1,17 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [677, 241, 210, 209],
+        [268, 241, 210, 209],
+        [64, 241, 209, 209],
+        [477, 245, 205, 205]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/path-pathlength-change-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/path-pathlength-change-expected.txt
new file mode 100644
index 0000000..5039607
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/path-pathlength-change-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [101, 101, 272, 272]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/pending-resource-after-removal-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/pending-resource-after-removal-expected.txt
new file mode 100644
index 0000000..5998e8c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/pending-resource-after-removal-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 300, 300]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/rect-modify-rx-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/rect-modify-rx-expected.txt
new file mode 100644
index 0000000..fd4e3be05
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/rect-modify-rx-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 150, 150]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-content-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-content-expected.txt
new file mode 100644
index 0000000..f1a89f70
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-content-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 102, 603, 603]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
new file mode 100644
index 0000000..f1a89f70
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 102, 603, 603]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt
new file mode 100644
index 0000000..f1a89f70
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 102, 603, 603]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-document-scrollbars-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-document-scrollbars-expected.txt
new file mode 100644
index 0000000..9214399
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-document-scrollbars-expected.txt
@@ -0,0 +1,34 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [2036, 1517],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [0, 0, 2036, 1517]
+      ]
+    },
+    {
+      "name": "ContentsLayer for Horizontal Scrollbar Layer",
+      "position": [0, 878],
+      "bounds": [1178, 22],
+      "contentsOpaque": true
+    },
+    {
+      "name": "ContentsLayer for Vertical Scrollbar Layer",
+      "position": [1178, 0],
+      "bounds": [22, 878],
+      "contentsOpaque": true
+    },
+    {
+      "name": "Scroll Corner Layer",
+      "position": [1178, 878],
+      "bounds": [22, 22],
+      "invalidations": [
+        [0, 0, 22, 22]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-image-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-image-expected.txt
new file mode 100644
index 0000000..f1a89f70
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-image-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 102, 603, 603]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-inner-svg-expected.txt b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-inner-svg-expected.txt
new file mode 100644
index 0000000..04e7243
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/paint/invalidation/svg/relative-sized-inner-svg-expected.txt
@@ -0,0 +1,14 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [1200, 900],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "invalidations": [
+        [12, 75, 603, 603]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/inline-styles-binding-expected.txt b/third_party/blink/web_tests/http/tests/devtools/bindings/inline-styles-binding-expected.txt
index 8b7664a..00f2fbc3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/inline-styles-binding-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/inline-styles-binding-expected.txt
@@ -5,11 +5,11 @@
 LiveLocation 'style0' was updated 7:11
 LiveLocation 'style1' was updated 17:11
 Adding rule0
-LiveLocation 'style0' was updated 9:1
-LiveLocation 'style1' was updated 19:11
 LiveLocation 'script0' was updated 15:12
 LiveLocation 'script1' was updated 19:48
+LiveLocation 'style0' was updated 9:1
+LiveLocation 'style1' was updated 19:11
 Adding rule1
-LiveLocation 'style1' was updated 21:1
 LiveLocation 'script1' was updated 21:38
+LiveLocation 'style1' was updated 21:1
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/inline-styles-binding.js b/third_party/blink/web_tests/http/tests/devtools/bindings/inline-styles-binding.js
index 803ea36..50348d5 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/inline-styles-binding.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/inline-styles-binding.js
@@ -7,43 +7,58 @@
   await TestRunner.loadModule('bindings_test_runner');
 
   await TestRunner.navigatePromise('./resources/inline-style.html');
-  var uiSourceCode = await TestRunner.waitForUISourceCode('inline-style.html', Workspace.projectTypes.Network);
+  const uiSourceCode = await TestRunner.waitForUISourceCode('inline-style.html', Workspace.projectTypes.Network);
 
   await uiSourceCode.requestContent(); // prefetch content to fix flakiness
-  var styleSheets = TestRunner.cssModel.styleSheetIdsForURL(uiSourceCode.url());
-  var scripts = TestRunner.debuggerModel.scriptsForSourceURL(uiSourceCode.url());
-  var locationPool = new Bindings.LiveLocationPool();
-  var i = 0;
-  for (var script of scripts) {
-    var rawLocation = TestRunner.debuggerModel.createRawLocation(script, script.lineOffset, script.columnOffset);
+  const headers = TestRunner.cssModel.headersForSourceURL(uiSourceCode.url());
+  // Sort headers in the order they appear in the file to avoid flakiness.
+  headers.sort((a, b) => a.startLine - b.startLine);
+  const styleSheets = headers.map(header => header.id);
+  const scripts = TestRunner.debuggerModel.scriptsForSourceURL(uiSourceCode.url());
+  const locationPool = new Bindings.LiveLocationPool();
+  let i = 0;
+  const locationUpdates = new Map();
+  for (const script of scripts) {
+    const rawLocation = TestRunner.debuggerModel.createRawLocation(script, script.lineOffset, script.columnOffset);
     await Bindings.debuggerWorkspaceBinding.createLiveLocation(
       rawLocation, updateDelegate.bind(null, 'script' + i), locationPool);
     i++;
   }
 
   i = 0;
-  for (var styleSheetId of styleSheets) {
-    var header = TestRunner.cssModel.styleSheetHeaderForId(styleSheetId);
-    var rawLocation = new SDK.CSSLocation(header, header.startLine, header.startColumn);
+  for (const styleSheetId of styleSheets) {
+    const header = TestRunner.cssModel.styleSheetHeaderForId(styleSheetId);
+    const rawLocation = new SDK.CSSLocation(header, header.startLine, header.startColumn);
     await Bindings.cssWorkspaceBinding.createLiveLocation(
       rawLocation, updateDelegate.bind(null, 'style' + i), locationPool);
     i++;
   }
 
+  await TestRunner.waitForPendingLiveLocationUpdates();
+  printLocationUpdates();
+
   i = 0;
-  for (var styleSheetId of styleSheets) {
+  for (const styleSheetId of styleSheets) {
     TestRunner.addResult('Adding rule' + i)
     await TestRunner.cssModel.addRule(styleSheetId, `.new-rule {
   --new: true;
 }`, TextUtils.TextRange.createFromLocation(0, 0));
     await TestRunner.waitForPendingLiveLocationUpdates();
+    printLocationUpdates();
     i++;
   }
 
-
   async function updateDelegate(name, location) {
-    var uiLocation = await location.uiLocation();
-    TestRunner.addResult(`LiveLocation '${name}' was updated ${uiLocation.lineNumber}:${uiLocation.columnNumber}`);
+    const uiLocation = await location.uiLocation();
+    locationUpdates.set(name, `LiveLocation '${name}' was updated ${uiLocation.lineNumber}:${uiLocation.columnNumber}`);
+  }
+
+  function printLocationUpdates() {
+    const keys = [...locationUpdates.keys()].sort();
+    for (const key of keys) {
+      TestRunner.addResult(locationUpdates.get(key));
+    }
+    locationUpdates.clear();
   }
 
   TestRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/breadcrumb-updates-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/breadcrumb-updates-expected.txt
deleted file mode 100644
index 595d684..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/elements/breadcrumb-updates-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests that breadcrumbs are updated upon involved element's attribute changes in the Elements panel.
-
-Original breadcrumb:
-html > body > div.firstClass > div#target
-After class change:
-html > body > div.anotherClass > div#target
-After class removal:
-html > body > div > div#target
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/breadcrumb-updates.js b/third_party/blink/web_tests/http/tests/devtools/elements/breadcrumb-updates.js
deleted file mode 100644
index f386a3a..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/elements/breadcrumb-updates.js
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(
-      `Tests that breadcrumbs are updated upon involved element's attribute changes in the Elements panel.\n`);
-  await TestRunner.loadModule('elements_test_runner');
-  await TestRunner.showPanel('elements');
-  await TestRunner.loadHTML(`
-      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-      <div class="firstClass">
-          <div id="target"></div>
-      </div>
-    `);
-  await TestRunner.evaluateInPagePromise(`
-      function changeClass()
-      {
-          document.getElementsByClassName("firstClass")[0].className = "anotherClass";
-      }
-
-      function deleteClass()
-      {
-          document.getElementsByClassName("anotherClass")[0].className = "";
-      }
-  `);
-
-  ElementsTestRunner.expandElementsTree(step0);
-
-  function step0() {
-    TestRunner.addSniffer(Elements.ElementsBreadcrumbs.prototype, 'update', step1);
-    ElementsTestRunner.selectNodeWithId('target');
-  }
-
-  function step1() {
-    ElementsTestRunner.dumpBreadcrumb('Original breadcrumb');
-    TestRunner.addSniffer(Elements.ElementsBreadcrumbs.prototype, 'update', step2);
-    TestRunner.evaluateInPage('changeClass()');
-  }
-
-  function step2() {
-    ElementsTestRunner.dumpBreadcrumb('After class change');
-    TestRunner.addSniffer(Elements.ElementsBreadcrumbs.prototype, 'update', step3);
-    TestRunner.evaluateInPage('deleteClass()');
-  }
-
-  function step3() {
-    ElementsTestRunner.dumpBreadcrumb('After class removal');
-    TestRunner.completeTest();
-  }
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/breadcrumb-shadow-roots-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/shadow/breadcrumb-shadow-roots-expected.txt
deleted file mode 100644
index 4103e917..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/breadcrumb-shadow-roots-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests that shadow roots are displayed correctly in breadcrumbs.
-
-User-agent shadow root breadcrumb:
-html > body > input > #shadow-root
-Open shadow root breadcrumb:
-html > body > div#host > #shadow-root
-Closed shadow root breadcrumb:
-html > body > div#hostClosed > #shadow-root
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/breadcrumb-shadow-roots.js b/third_party/blink/web_tests/http/tests/devtools/elements/shadow/breadcrumb-shadow-roots.js
deleted file mode 100644
index b18192b..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/elements/shadow/breadcrumb-shadow-roots.js
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Tests that shadow roots are displayed correctly in breadcrumbs.\n`);
-  await TestRunner.loadModule('elements_test_runner');
-  await TestRunner.showPanel('elements');
-  await TestRunner.loadHTML(`
-      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-      <input type="text">
-      <div id="host"></div>
-      <div id="hostClosed"></div>
-      <template id="tmpl">
-          <style>.red { color: red; }</style>
-          <div id="inner" class="red">inner</div>
-      </template>
-    `);
-  await TestRunner.evaluateInPagePromise(`
-      var template = document.querySelector("#tmpl");
-      var root = document.querySelector("#host").attachShadow({mode: 'open'});
-      root.appendChild(template.content.cloneNode(true));
-      var rootClosed = document.querySelector("#hostClosed").attachShadow({mode: 'closed'});
-      rootClosed.appendChild(template.content.cloneNode(true));
-  `);
-
-  Common.settingForTest('showUAShadowDOM').set(true);
-  ElementsTestRunner.expandElementsTree(step0);
-
-  function step0() {
-    selectNode(matchUserAgentShadowRoot, step1);
-  }
-
-  function step1() {
-    ElementsTestRunner.dumpBreadcrumb('User-agent shadow root breadcrumb');
-    selectNode(matchOpenShadowRoot, step2);
-  }
-
-  function step2() {
-    ElementsTestRunner.dumpBreadcrumb('Open shadow root breadcrumb');
-    selectNode(matchClosedShadowRoot, step3);
-  }
-
-  function step3() {
-    ElementsTestRunner.dumpBreadcrumb('Closed shadow root breadcrumb');
-    TestRunner.completeTest();
-  }
-
-  function selectNode(matchFunction, next) {
-    ElementsTestRunner.findNode(matchFunction, callback);
-    function callback(node) {
-      TestRunner.addSniffer(Elements.ElementsBreadcrumbs.prototype, 'update', next);
-      Common.Revealer.reveal(node);
-    }
-  }
-
-  function matchUserAgentShadowRoot(node) {
-    return node.shadowRootType() === SDK.DOMNode.ShadowRootTypes.UserAgent;
-  }
-
-  function matchOpenShadowRoot(node) {
-    return node.shadowRootType() === SDK.DOMNode.ShadowRootTypes.Open;
-  }
-
-  function matchClosedShadowRoot(node) {
-    return node.shadowRootType() === SDK.DOMNode.ShadowRootTypes.Closed;
-  }
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag-expected.txt
index 3128b20..c6e3750 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag-expected.txt
@@ -2,31 +2,6 @@
 
 Stylesheet added:
   - isInline: false
-  - sourceURL: 
-  - hasSourceURL: false
-  - contents: 
-.inline-style-added-by-parser-in-document-write {
-   color: blue;
-}
-
-Stylesheet added:
-  - isInline: false
-  - sourceURL: 
-  - hasSourceURL: false
-  - contents: .inline-style-created-by-script {
-   color: orange;
-}
-Stylesheet added:
-  - isInline: true
-  - sourceURL: dynamic-style-tag.html
-  - hasSourceURL: false
-  - contents: 
-/* comment */.inline-style-added-by-parser {
-    color: red;
-}
-
-Stylesheet added:
-  - isInline: false
   - sourceURL: inlineStyleAddedByDocumentWrite.css
   - hasSourceURL: true
   - contents: 
@@ -36,6 +11,15 @@
 /*# sourceURL=inlineStyleAddedByDocumentWrite.css*/
 
 Stylesheet added:
+  - isInline: false
+  - sourceURL: 
+  - hasSourceURL: false
+  - contents: 
+.inline-style-added-by-parser-in-document-write {
+   color: blue;
+}
+
+Stylesheet added:
   - isInline: true
   - sourceURL: inlineStyleAddedByParser.css
   - hasSourceURL: true
@@ -46,6 +30,22 @@
 /*# sourceURL=inlineStyleAddedByParser.css*/
 
 Stylesheet added:
+  - isInline: true
+  - sourceURL: dynamic-style-tag.html
+  - hasSourceURL: false
+  - contents: 
+/* comment */.inline-style-added-by-parser {
+    color: red;
+}
+
+Stylesheet added:
+  - isInline: false
+  - sourceURL: 
+  - hasSourceURL: false
+  - contents: .inline-style-created-by-script {
+   color: orange;
+}
+Stylesheet added:
   - isInline: false
   - sourceURL: inlineStyleCreatedByScript.css
   - hasSourceURL: true
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag.js b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag.js
index 0e3cd22..d3b7488 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/dynamic-style-tag.js
@@ -12,11 +12,16 @@
   ElementsTestRunner.selectNodeAndWaitForStyles('inspected', step1);
 
   async function step1() {
-    var styleSheets = TestRunner.cssModel.allStyleSheets();
-    styleSheets.sort();
-    for (var header of styleSheets) {
-      var content = await TestRunner.CSSAgent.getStyleSheetText(header.id);
-
+    const styleSheets = TestRunner.cssModel.allStyleSheets();
+    const styleSheetsWithContent = [];
+    for (const header of styleSheets) {
+      styleSheetsWithContent.push({
+        header,
+        content: await TestRunner.CSSAgent.getStyleSheetText(header.id),
+      });
+    }
+    styleSheetsWithContent.sort((a, b) => a.content.localeCompare(b.content));
+    for (const {header, content} of styleSheetsWithContent) {
       TestRunner.addResult('Stylesheet added:');
       TestRunner.addResult('  - isInline: ' + header.isInline);
       TestRunner.addResult('  - sourceURL: ' + header.sourceURL.substring(header.sourceURL.lastIndexOf('/') + 1));
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-creation-img-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-creation-img-expected.txt
index ae2dd86..a55c037 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-creation-img-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-creation-img-expected.txt
@@ -7,7 +7,7 @@
             contentSecurityPolicyIssueDetails : {
                 blockedURL : https://thirdparty.test/network/resources/to-be-blocked.jpg
                 contentSecurityPolicyViolationType : kURLViolation
-                violatedDirective : img-src 'self'
+                violatedDirective : img-src
             }
         }
     }
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-src-location-added-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-src-location-added-expected.txt
new file mode 100644
index 0000000..db63936
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-src-location-added-expected.txt
@@ -0,0 +1,20 @@
+Verifies that CSP issue contains source location.
+
+Inspector issue: {
+    issue : {
+        code : ContentSecurityPolicyIssue
+        details : {
+            contentSecurityPolicyIssueDetails : {
+                blockedURL : https://devtools.test:8443/inspector-protocol/resources/style.css
+                contentSecurityPolicyViolationType : kURLViolation
+                sourceCodeLocation : {
+                    columnNumber : 0
+                    lineNumber : 3
+                    url : https://devtools.test:8443/inspector-protocol/resources/content-security-policy-issue-with-src-location.html
+                }
+                violatedDirective : style-src-elem
+            }
+        }
+    }
+}
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-src-location-added.js b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-src-location-added.js
new file mode 100644
index 0000000..bcbd224af
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-src-location-added.js
@@ -0,0 +1,12 @@
+(async function(testRunner) {
+    const {page, session, dp} = await testRunner.startBlank(
+      `Verifies that CSP issue contains source location.\n`);
+
+    await dp.Network.enable();
+    await dp.Audits.enable();
+    page.navigate('https://devtools.test:8443/inspector-protocol/resources/content-security-policy-issue-with-src-location.html');
+    const issue = await dp.Audits.onceIssueAdded();
+
+    testRunner.log(issue.params, "Inspector issue: ");
+    testRunner.completeTest();
+  })
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/content-security-policy-issue-with-src-location.html b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/content-security-policy-issue-with-src-location.html
new file mode 100644
index 0000000..39c0dff
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/content-security-policy-issue-with-src-location.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta http-equiv="Content-Security-Policy" content="style-src 'https://thirdparty.test/network/resources/';">
+
+<link rel="stylesheet" type="text/css" href="style.css">
+
+<html>
+    <body>
+    </body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/xmlhttprequest/workers/resources/access-control-basic-get-fail-non-simple.js b/third_party/blink/web_tests/http/tests/xmlhttprequest/workers/resources/access-control-basic-get-fail-non-simple.js
index 1fc6a13..96a877f7 100644
--- a/third_party/blink/web_tests/http/tests/xmlhttprequest/workers/resources/access-control-basic-get-fail-non-simple.js
+++ b/third_party/blink/web_tests/http/tests/xmlhttprequest/workers/resources/access-control-basic-get-fail-non-simple.js
@@ -32,7 +32,7 @@
     try {
 	var xhr = new XMLHttpRequest;
 	xhr.open("GET", "http://localhost:8000/xmlhttprequest/resources/access-control-basic-get-fail-non-simple.cgi", false);
-	// Non-whitelisted method
+	// Non-CORS-saflisted method
 	xhr.setRequestHeader("x-webkit", "foobar");
         xhr.send();
     } catch(e) {
diff --git a/third_party/blink/web_tests/inspector-protocol/stylesheet-tracking-restart-expected.txt b/third_party/blink/web_tests/inspector-protocol/stylesheet-tracking-restart-expected.txt
index 9d9a311..5765823f 100644
--- a/third_party/blink/web_tests/inspector-protocol/stylesheet-tracking-restart-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/stylesheet-tracking-restart-expected.txt
@@ -3,8 +3,8 @@
 Running test
 Opening front-end for the first time
 Enabling CSS domain.
- - style sheet added: foo.css
  - style sheet added: bar.css
+ - style sheet added: foo.css
 Closing inspector.
 
 Removing style sheet.
diff --git a/third_party/blink/web_tests/inspector-protocol/stylesheet-tracking-restart.js b/third_party/blink/web_tests/inspector-protocol/stylesheet-tracking-restart.js
index d2ed8c2..7b0f12e 100644
--- a/third_party/blink/web_tests/inspector-protocol/stylesheet-tracking-restart.js
+++ b/third_party/blink/web_tests/inspector-protocol/stylesheet-tracking-restart.js
@@ -36,7 +36,7 @@
     session.protocol.DOM.enable();
     await session.protocol.CSS.enable();
     var headers = {};
-    headersAdded.sort((a, b) => a.styleSheetId - b.styleSheetId);
+    headersAdded.sort((a, b) => a.sourceURL.localeCompare(b.sourceURL));
     for (var header of headersAdded) {
       headers[header.styleSheetId] = header.sourceURL;
       testRunner.log(' - style sheet added: ' + header.sourceURL);
diff --git a/third_party/blink/web_tests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.html b/third_party/blink/web_tests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.html
deleted file mode 100644
index afba406..0000000
--- a/third_party/blink/web_tests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<script>
-onload = () => {
-    outerDiv.scrollTop = 300;
-    innerDiv.scrollTop = 400;
-}
-</script>
-<div style="height: 300px; overflow-y: scroll;" id="outerDiv">
-    <div style="height: 300px;"></div>
-    <div style="height: 400px; overflow-y: scroll;" id="innerDiv">
-        <div style="height: 800px; width: 300px; background: green"></div>
-    </div>
-</div>
diff --git a/third_party/blink/web_tests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled.html b/third_party/blink/web_tests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled.html
index 1ff3b9b..2ea53712 100644
--- a/third_party/blink/web_tests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled.html
+++ b/third_party/blink/web_tests/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled.html
@@ -1,18 +1,18 @@
 <!DOCTYPE html>
-<script src="../resources/text-based-repaint.js"></script>
-<script>
-onload = () => {
-  // Scroll the outerDiv until we reach innerDiv.
-  outerDiv.scrollTop = 300;
-  runRepaintAndPixelTest();
-};
-
-function repaintTest() {
-    // Now scroll the innerDiv once to the green area.
-    innerDiv.scrollTop = 400;
-}
-</script>
-<!-- https://bugs.webkit.org/show_bug.cgi?id=71550 -->
+<html>
+<head>
+    <script src="../resources/text-based-repaint.js" type="text/javascript"></script>
+    <script>
+    function repaintTest() {
+        // Now scroll once in the #innerDiv to the green area.
+        if (window.eventSender)
+            eventSender.mouseScrollBy(0, -10);
+    }
+    window.addEventListener("load", runRepaintAndPixelTest, false);
+    </script>
+</head>
+<body>
+<!-- Bug 71550 - REGRESSION (r93614): Content remains despite parent element being scrolled off page using javascript. -->
 <!-- For the test to pass you should not see any RED or PURPLE, only green -->
 <div style="height: 300px; overflow-y: scroll;" id="outerDiv">
     <div style="height: 300px; background: purple;"></div>
@@ -21,3 +21,17 @@
         <div style="height: 400px; width: 300px; background: green"></div>
     </div>
 </div>
+<script>
+if (window.eventSender) {
+    if (window.internals)
+        internals.settings.setScrollAnimatorEnabled(false);
+
+    // Scroll the #outerDiv until we reach the #innerDiv.
+    eventSender.mouseMoveTo(50, 50);
+    eventSender.mouseScrollBy(0, -8);
+} else {
+    document.write("This test is better run under DumpRenderTree. To manually test it, continuously scroll down on the top-most element. There should be no repaint issue.");
+}
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.png b/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.png
new file mode 100644
index 0000000..a16ab6fd
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.png b/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.png
new file mode 100644
index 0000000..decc654
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/overflow-scroll-in-overflow-scroll-scrolled-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/webshare/share-error.html b/third_party/blink/web_tests/webshare/share-error.html
index 00a48434..2020346 100644
--- a/third_party/blink/web_tests/webshare/share-error.html
+++ b/third_party/blink/web_tests/webshare/share-error.html
@@ -39,4 +39,18 @@
       'AbortError'));
 }, 'share with invalid url template');
 
+share_test(mock => {
+  return callWithKeyDown(async () => {
+    await assertRejectsWithError(
+      navigator.share({
+      }),
+      'TypeError');
+
+    return assertRejectsWithError(
+      navigator.share({
+      }),
+      'NotAllowedError');
+  });
+}, 'share consumes user activation');
+
 </script>
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 50a7e4a..91b159b 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-2-39-g5fe7c044c
-Revision: 5fe7c044c25bba9dfae315ef56bacfc83976ddd0
+Version: VER-2-10-2-40-gb7c467b6e
+Revision: b7c467b6efa5a91945854de81632be45d6f360ff
 CPEPrefix: cpe:/a:freetype:freetype:2.10.1
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/tools/android/errorprone_plugin/BUILD.gn b/tools/android/errorprone_plugin/BUILD.gn
index 0c13ec0..58e2582 100644
--- a/tools/android/errorprone_plugin/BUILD.gn
+++ b/tools/android/errorprone_plugin/BUILD.gn
@@ -12,11 +12,15 @@
   sources = [
     # Turned off because of existing code which fails the check
     # "src/org/chromium/tools/errorprone/plugin/NoContextGetApplicationContext.java",
-    "src/org/chromium/tools/errorprone/plugin/AndroidNullableCheck.java",
+    # TODO(crbug.com/1104558): Fix.
+    #"src/org/chromium/tools/errorprone/plugin/AndroidNullableCheck.java",
     "src/org/chromium/tools/errorprone/plugin/NoAndroidAsyncTaskCheck.java",
     "src/org/chromium/tools/errorprone/plugin/NoDynamicStringsInTraceEventCheck.java",
-    "src/org/chromium/tools/errorprone/plugin/NoRedundantFieldInitCheck.java",
-    "src/org/chromium/tools/errorprone/plugin/NoSynchronizedMethodCheck.java",
+
+    # TODO(crbug.com/1104558): Fix.
+    #"src/org/chromium/tools/errorprone/plugin/NoRedundantFieldInitCheck.java",
+    # TODO(crbug.com/1104558): Fix.
+    #"src/org/chromium/tools/errorprone/plugin/NoSynchronizedMethodCheck.java",
     "src/org/chromium/tools/errorprone/plugin/NoSynchronizedThisCheck.java",
     "src/org/chromium/tools/errorprone/plugin/TestClassNameCheck.java",
   ]
@@ -35,3 +39,20 @@
     "//third_party/android_deps:com_google_errorprone_javac_java",
   ]
 }
+
+android_library("test_class_name_check_test_java") {
+  testonly = true
+  enable_errorprone = true
+  errorprone_expected_warning_regex = "TestClassNameCheck"
+  sources = [ "test/src/org/chromium/tools/errorprone/plugin/TestClassNameCheckTesting.java" ]
+  deps = [
+    "//base:base_java_test_support",
+    "//third_party/android_support_test_runner:runner_java",
+    "//third_party/junit:junit",
+  ]
+}
+
+group("tests") {
+  testonly = true
+  deps = [ ":test_class_name_check_test_java" ]
+}
diff --git a/tools/android/errorprone_plugin/test/src/org/chromium/tools/errorprone/plugin/TestClassNameCheckTesting.java b/tools/android/errorprone_plugin/test/src/org/chromium/tools/errorprone/plugin/TestClassNameCheckTesting.java
new file mode 100644
index 0000000..8e3760f
--- /dev/null
+++ b/tools/android/errorprone_plugin/test/src/org/chromium/tools/errorprone/plugin/TestClassNameCheckTesting.java
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.tools.errorprone.plugin;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
+
+/**
+ * Should cause 'TestClassNameCheck' errorprone warning.
+ */
+@RunWith(BaseJUnit4ClassRunner.class)
+public class TestClassNameCheckTesting {
+    @Test
+    public void testRandom() {}
+}
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index 8d44d69..48f116e1 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -407,6 +407,15 @@
                       default=sys.platform in ('linux2', 'darwin'))
   args = parser.parse_args()
 
+  # TODO(crbug.com/1105518): Remove in the next Clang roll.
+  if args.llvm_force_head_revision:
+    global RELEASE_VERSION
+    RELEASE_VERSION = '12.0.0'
+    old_lib_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', '11.0.0')
+    if (os.path.isdir(old_lib_dir)):
+      print('Removing old lib dir: ' + old_lib_dir)
+      RmTree(old_lib_dir)
+
   if args.pgo and not args.bootstrap:
     print('--pgo requires --bootstrap')
     return 1
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index e9cbb39c..210c6ca 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -43,6 +43,7 @@
 
 PACKAGE_VERSION = '%s-%s-%s' % (CLANG_SVN_REVISION, CLANG_REVISION[:8],
                                 CLANG_SUB_REVISION)
+# TODO(crbug.com/1105518): Bump to 12.0.0 in the next Clang roll.
 RELEASE_VERSION = '11.0.0'
 
 
@@ -299,6 +300,11 @@
                       help='Verify that clang has the passed-in version.')
   args = parser.parse_args()
 
+  # TODO(crbug.com/1042192): Remove in the next Clang roll.
+  if args.llvm_force_head_revision:
+    global RELEASE_VERSION
+    RELEASE_VERSION = '12.0.0'
+
   if args.force_local_build:
     print(('update.py --force-local-build is no longer used to build clang; '
            'use build.py instead.'))
diff --git a/tools/git/move_source_file.py b/tools/git/move_source_file.py
index 90ade78a..f7a2a20 100755
--- a/tools/git/move_source_file.py
+++ b/tools/git/move_source_file.py
@@ -130,8 +130,11 @@
   if extension in ['.h', '.hh', '.mojom']:
     UpdateIncludes(from_path, to_path, in_blink)
     if extension == '.mojom':
-      # For mojom files, update includes of the generated header.
+      # For mojom files, update includes of generated headers.
       UpdateIncludes(from_path + '.h', to_path + '.h', in_blink)
+      UpdateIncludes(from_path + '-blink.h', to_path + '-blink.h', in_blink)
+      UpdateIncludes(from_path + '-shared.h', to_path + '-shared.h', in_blink)
+      UpdateIncludes(from_path + '-forward.h', to_path + '-forward.h', in_blink)
     else:
       UpdateIncludeGuard(from_path, to_path)
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 3f3863d..345e367 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -44212,6 +44212,13 @@
   <int value="3" label="Fetch failed because the document origin is opaque"/>
 </enum>
 
+<enum name="ManifestInvalidAppStatusError">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="Error unknown application"/>
+  <int value="2" label="Error invalid app id"/>
+  <int value="3" label="Error restricted"/>
+</enum>
+
 <enum name="ManifestInvalidError">
   <int value="0" label="XML Parsing failed"/>
   <int value="1" label="Invalid xlmns on gupdate tag"/>
@@ -44226,6 +44233,7 @@
   <int value="10" label="Missing version for update check"/>
   <int value="11" label="Invalid version"/>
   <int value="12" label="Bad Update specification"/>
+  <int value="13" label="Bad App Status"/>
 </enum>
 
 <enum name="MappedAndResidentPagesDumpState">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 9c5c8424..f3e012d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -17862,7 +17862,7 @@
 </histogram>
 
 <histogram name="BackgroundSync.LaunchTask.PlayServicesAvailable"
-    enum="Boolean" expires_after="M86">
+    enum="Boolean" expires_after="2021-07-21">
   <owner>nator@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
   <summary>
@@ -49615,7 +49615,7 @@
 </histogram>
 
 <histogram name="EphemeralTab.BottomSheet.CloseReason"
-    enum="BottomSheet.StateChangeReason" expires_after="M86">
+    enum="BottomSheet.StateChangeReason" expires_after="M88">
   <owner>donnd@chromium.org</owner>
   <owner>jinsukkim@chromium.org</owner>
   <summary>
@@ -49625,7 +49625,7 @@
 </histogram>
 
 <histogram name="EphemeralTab.CloseReason"
-    enum="OverlayPanel.StateChangeReason" expires_after="M86">
+    enum="OverlayPanel.StateChangeReason" expires_after="M88">
   <owner>donnd@chromium.org</owner>
   <owner>jinsukkim@chromium.org</owner>
   <summary>
@@ -49634,7 +49634,7 @@
   </summary>
 </histogram>
 
-<histogram name="EphemeralTab.Ctr" enum="BooleanOpened" expires_after="M86">
+<histogram name="EphemeralTab.Ctr" enum="BooleanOpened" expires_after="M88">
   <owner>donnd@chromium.org</owner>
   <owner>jinsukkim@chromium.org</owner>
   <summary>
@@ -49643,7 +49643,7 @@
   </summary>
 </histogram>
 
-<histogram name="EphemeralTab.DurationOpened" units="ms" expires_after="M86">
+<histogram name="EphemeralTab.DurationOpened" units="ms" expires_after="M88">
   <owner>donnd@chromium.org</owner>
   <owner>jinsukkim@chromium.org</owner>
   <summary>
@@ -49652,7 +49652,7 @@
   </summary>
 </histogram>
 
-<histogram name="EphemeralTab.DurationPeeked" units="ms" expires_after="M86">
+<histogram name="EphemeralTab.DurationPeeked" units="ms" expires_after="M88">
   <owner>donnd@chromium.org</owner>
   <owner>jinsukkim@chromium.org</owner>
   <summary>
@@ -56960,8 +56960,27 @@
   </summary>
 </histogram>
 
+<histogram name="Extensions.ForceInstalledFailureManifestInvalidAppStatusError"
+    enum="ManifestInvalidAppStatusError" expires_after="2020-11-01">
+  <owner>swapnilgupta@google.com</owner>
+  <owner>burunduk@chromium.org</owner>
+  <owner>managed-devices@google.com</owner>
+  <summary>
+    The detailed reason why enterprise policy forced extensions had failed to
+    install because fetched update manifest was invalid due to app status error.
+    Recorded for each forced extension that failed to install after 5 minutes
+    with Extensions.ForceInstalledFailureReason2 equal to MANIFEST_INVALID and
+    Extensions.ForceInstalledFailureManifestInvalidErrorDetail2 equal to
+    BAD_APP_STATUS.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.ForceInstalledFailureManifestInvalidErrorDetail"
     enum="ManifestInvalidError" expires_after="2020-09-01">
+  <obsolete>
+    Removed 07/2020, replaced by
+    Extensions.ForceInstalledFailureManifestInvalidErrorDetail2.
+  </obsolete>
   <owner>swapnilgupta@google.com</owner>
   <owner>burunduk@chromium.org</owner>
   <owner>managed-devices@google.com</owner>
@@ -56973,6 +56992,23 @@
   </summary>
 </histogram>
 
+<histogram name="Extensions.ForceInstalledFailureManifestInvalidErrorDetail2"
+    enum="ManifestInvalidError" expires_after="2020-11-01">
+  <owner>swapnilgupta@google.com</owner>
+  <owner>burunduk@chromium.org</owner>
+  <owner>managed-devices@google.com</owner>
+  <summary>
+    The detailed reason why enterprise policy forced extensions had failed to
+    install because fetched update manifest was invalid. Recorded for each
+    forced extension that failed to install after 5 minutes with
+    Extensions.ForceInstalledFailureReason2 equal to MANIFEST_INVALID.
+
+    Replaced Extensions.ForceInstalledFailureManifestInvalidErrorDetail due to
+    addition of new error BAD_APP_STATUS, and some of the errors that were
+    MISSING_UPDATE_CHECK_TAG would now be reported as BAD_APP_STATUS.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.ForceInstalledFailureNoUpdatesInfo"
     enum="ExtensionNoUpdatesInfo" expires_after="2020-11-01">
   <owner>snijhara@google.com</owner>
@@ -62663,7 +62699,7 @@
 </histogram>
 
 <histogram name="GCM.Crypto.GCMDatabaseUpgradeResult" enum="Boolean"
-    expires_after="M86">
+    expires_after="2021-07-21">
   <owner>nator@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
@@ -62922,7 +62958,7 @@
 </histogram>
 
 <histogram name="GCM.RegistrationCacheStatus" enum="GCMRegistrationCacheStatus"
-    expires_after="M86">
+    expires_after="2021-07-31">
   <owner>nator@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <owner>rayankans@chromium.org</owner>
@@ -69127,6 +69163,9 @@
 
 <histogram name="Import.NumberOfImportedPasswords.Firefox" units="units"
     expires_after="M86">
+  <obsolete>
+    Removed 07/2020.
+  </obsolete>
   <owner>vasilii@chromium.org</owner>
   <owner>hurims@gmail.com</owner>
   <summary>
@@ -124174,6 +124213,9 @@
 <histogram
     name="PasswordManager.BubbleSuppression.AccountsWithSuppressedBubble"
     units="accounts" expires_after="M86">
+  <obsolete>
+    Removed as of 07/2020.
+  </obsolete>
   <owner>battre@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -124186,6 +124228,9 @@
 
 <histogram name="PasswordManager.BubbleSuppression.DomainsWithSuppressedBubble"
     units="accounts" expires_after="M86">
+  <obsolete>
+    Removed as of 07/2020.
+  </obsolete>
   <owner>battre@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -124437,7 +124482,7 @@
 </histogram>
 
 <histogram name="PasswordManager.DeleteUndecryptableLoginsReturnValue"
-    enum="DeleteCorruptedPasswordsResult" expires_after="M86">
+    enum="DeleteCorruptedPasswordsResult" expires_after="M89">
   <owner>vasilii@chromium.org</owner>
   <owner>jdoerrie@chromium.org</owner>
   <summary>
@@ -124482,7 +124527,7 @@
 </histogram>
 
 <histogram name="PasswordManager.EmptyUsernames.CountInDatabase" units="units"
-    expires_after="M86">
+    expires_after="M89">
   <owner>vasilii@chromium.org</owner>
   <owner>jdoerrie@chromium.org</owner>
   <summary>
@@ -124883,7 +124928,7 @@
 </histogram>
 
 <histogram name="PasswordManager.InaccessiblePasswords" units="saved passwords"
-    expires_after="M86">
+    expires_after="M89">
   <owner>vasilii@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
@@ -125281,7 +125326,7 @@
 </histogram>
 
 <histogram name="PasswordManager.LoginDatabaseInit"
-    enum="LoginDatabaseInitError" expires_after="M86">
+    enum="LoginDatabaseInitError" expires_after="M89">
   <owner>vasilii@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <summary>An error on LoginDatabase initialization.</summary>
@@ -136384,6 +136429,9 @@
 
 <histogram name="Previews.Offline.CommittedErrorPage" enum="BooleanError"
     expires_after="M90">
+  <obsolete>
+    Offline Previews functionality removed in M86.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
   <summary>
@@ -136394,6 +136442,9 @@
 
 <histogram name="Previews.Offline.FalsePositivePrevention.Allowed"
     enum="BooleanAllowed" expires_after="M85">
+  <obsolete>
+    Offline Previews functionality removed in M86.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>ryansturm@chromium.org</owner>
   <summary>
@@ -136407,6 +136458,9 @@
 
 <histogram name="Previews.Offline.FalsePositivePrevention.PrefSize"
     units="count of entries" expires_after="M85">
+  <obsolete>
+    Offline Previews functionality removed in M86.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>ryansturm@chromium.org</owner>
   <summary>
@@ -136615,7 +136669,10 @@
 </histogram>
 
 <histogram name="Previews.ServerLitePage.HostBlacklistedOnBypass"
-    enum="Boolean" expires_after="2020-12-25">
+    enum="Boolean" expires_after="2020-07-10">
+  <obsolete>
+    Removed in M84.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <owner>tombergan@chromium.org</owner>
   <owner>src/components/data_reduction_proxy/OWNERS</owner>
@@ -136838,7 +136895,10 @@
 </histogram>
 
 <histogram name="Previews.StalePreviewTimestampShown"
-    enum="PreviewsStalePreviewTimestamp" expires_after="2020-12-31">
+    enum="PreviewsStalePreviewTimestamp" expires_after="2020-07-10">
+  <obsolete>
+    Stale timestamp functionality removed in M86.
+  </obsolete>
   <owner>robertogden@chromium.org</owner>
   <summary>
     Whether the timestamp for a stale preview was shown on the UI. If the
@@ -142890,6 +142950,9 @@
 <histogram base="true"
     name="RendererScheduler.TimeRunningOtherAgentsWhileTaskReady"
     units="microseconds" expires_after="M80">
+  <obsolete>
+    Removed 07/2020. Summary of collected data: https://crbug.com/1019856#c6.
+  </obsolete>
   <owner>fdoray@chromium.org</owner>
   <owner>etiennep@chromium.org</owner>
   <summary>
@@ -194674,7 +194737,7 @@
   </summary>
 </histogram>
 
-<histogram name="WebUITabStrip.TabActivation" units="ms" expires_after="M86">
+<histogram name="WebUITabStrip.TabActivation" units="ms" expires_after="M90">
   <owner>robliao@chromium.org</owner>
   <owner>johntlee@chromium.org</owner>
   <summary>
@@ -194683,7 +194746,7 @@
   </summary>
 </histogram>
 
-<histogram name="WebUITabStrip.TabCreation" units="ms" expires_after="M86">
+<histogram name="WebUITabStrip.TabCreation" units="ms" expires_after="M90">
   <owner>robliao@chromium.org</owner>
   <owner>johntlee@chromium.org</owner>
   <summary>
@@ -194691,7 +194754,7 @@
   </summary>
 </histogram>
 
-<histogram name="WebUITabStrip.TabDataReceived" units="ms" expires_after="M86">
+<histogram name="WebUITabStrip.TabDataReceived" units="ms" expires_after="M90">
   <owner>robliao@chromium.org</owner>
   <owner>johntlee@chromium.org</owner>
   <summary>
@@ -207500,6 +207563,7 @@
   <suffix name="Auto-enrollment-check.Next" label=""/>
   <suffix name="Autolaunch.Canceled" label=""/>
   <suffix name="Autolaunch.Completed" label=""/>
+  <suffix name="Connect.EnableDebugging" label=""/>
   <suffix name="Connect.Next" label=""/>
   <suffix name="Connect.SetupDemo" label=""/>
   <suffix name="Connect.StartDemo" label=""/>
@@ -208249,7 +208313,11 @@
   <suffix name="Clients.Previews.OfflinePages"
       label="PageLoadMetrics that are a result of a navigation that shows
              users an offline page preview. Offline page previews are shown
-             when a user's effective connection type is prohibitively slow."/>
+             when a user's effective connection type is prohibitively slow.">
+    <obsolete>
+      Functionality removed in M86.
+    </obsolete>
+  </suffix>
   <affected-histogram
       name="PageLoad.DocumentTiming.NavigationToDOMContentLoadedEventFired"/>
   <affected-histogram name="PageLoad.DocumentTiming.NavigationToFirstLayout"/>
@@ -209933,9 +210001,17 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="Previews.Types" separator=".">
-  <suffix name="AMPRedirection" label="AMP Redirection previews"/>
+  <suffix name="AMPRedirection" label="AMP Redirection previews">
+    <obsolete>
+      Functionality removed in 2018.
+    </obsolete>
+  </suffix>
   <suffix name="DeferAllScript" label="Defers execution of script"/>
-  <suffix name="LitePage" label="Lite page previews"/>
+  <suffix name="LitePage" label="Lite page previews">
+    <obsolete>
+      Functionality removed in M86.
+    </obsolete>
+  </suffix>
   <suffix name="LitePageRedirect" label="Lite page redirection previews">
     <obsolete>
       Removed in M84.
@@ -209948,7 +210024,11 @@
   </suffix>
   <suffix name="None" label="No preview was served"/>
   <suffix name="NoScript" label="NoScript previews"/>
-  <suffix name="Offline" label="Offline previews"/>
+  <suffix name="Offline" label="Offline previews">
+    <obsolete>
+      Functionality removed in M86.
+    </obsolete>
+  </suffix>
   <suffix name="ResourceLoadingHints"
       label="Resource loading hints based previews"/>
   <affected-histogram name="Previews.EligibilityReason"/>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index a47d92c..dcca10e 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,15 +6,15 @@
         },
         "mac": {
             "hash": "a2b0896e1d305a1b1fed14f2e745fe6d0398092d",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/55ef680dab933301b0a9aec7d3021714dcde26cd/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/a0a8e1d6457f8013d96e3508f0800cae5b4d769c/trace_processor_shell"
         },
         "linux": {
             "hash": "4a91142dbaa04283f5443eda976d03572ed5f859",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/55ef680dab933301b0a9aec7d3021714dcde26cd/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/a0a8e1d6457f8013d96e3508f0800cae5b4d769c/trace_processor_shell"
         }
     },
     "power_profile.sql": {
-        "hash": "89b27409972ed4ed5a1125d6c837273d404cb0d3",
-        "remote_path": "perfetto_data/power_profile.sql/20200610T163057/power_profile.sql"
+        "hash": "5bc5eae952c72d04403409a56838f66da13394d6",
+        "remote_path": "perfetto_data/power_profile.sql/20200713T171147/power_profile.sql"
     }
 }
\ No newline at end of file
diff --git a/ui/android/java/res/values/one_off_colors.xml b/ui/android/java/res/values/one_off_colors.xml
index c949c23..54a3fd5 100644
--- a/ui/android/java/res/values/one_off_colors.xml
+++ b/ui/android/java/res/values/one_off_colors.xml
@@ -9,8 +9,8 @@
          Ask for a UX approval before adding a new one.
     -->
 
-    <!-- Illustration colors -->
-    <color name="signin_header_animation_bg_dark" tools:ignore="UnusedResources">#28282B</color>
+    <!-- Background color for dark mode animations and images-->
+    <color name="header_background_dark" tools:ignore="UnusedResources">#28282B</color>
 
     <!-- TODO(https://crbug.com/1020436): Update the highlight colors to meet accessibility
          contrast ratio. -->
diff --git a/ui/base/clipboard/BUILD.gn b/ui/base/clipboard/BUILD.gn
index 090a77f5..8645b5c 100644
--- a/ui/base/clipboard/BUILD.gn
+++ b/ui/base/clipboard/BUILD.gn
@@ -67,6 +67,7 @@
     "clipboard.h",
     "clipboard_data_endpoint.cc",
     "clipboard_data_endpoint.h",
+    "clipboard_dlp_controller.h",
     "clipboard_metrics.cc",
     "clipboard_metrics.h",
     "clipboard_monitor.cc",
diff --git a/ui/base/clipboard/clipboard.h b/ui/base/clipboard/clipboard.h
index e3289fe..165e7049 100644
--- a/ui/base/clipboard/clipboard.h
+++ b/ui/base/clipboard/clipboard.h
@@ -27,6 +27,7 @@
 #include "build/build_config.h"
 #include "mojo/public/cpp/base/big_buffer.h"
 #include "ui/base/clipboard/clipboard_buffer.h"
+#include "ui/base/clipboard/clipboard_dlp_controller.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
 
 class SkBitmap;
@@ -107,6 +108,11 @@
   // whether it has changed.
   virtual uint64_t GetSequenceNumber(ClipboardBuffer buffer) const = 0;
 
+  // Sets the data leak prevention controller for the clipboard. This function
+  // will be used only on Chrome OS.
+  virtual void SetClipboardDlpController(
+      std::unique_ptr<ClipboardDlpController> dlp_controller) = 0;
+
   // Tests whether the clipboard contains a certain format.
   // TODO(crbug.com/1103614): Update |data_dst| in all references to its
   // appropriate ClipboardDataEndpoint for web-originates uses.
diff --git a/ui/base/clipboard/clipboard_android.cc b/ui/base/clipboard/clipboard_android.cc
index 4a2949b..8fac1b6 100644
--- a/ui/base/clipboard/clipboard_android.cc
+++ b/ui/base/clipboard/clipboard_android.cc
@@ -366,6 +366,11 @@
   return g_map.Get().GetSequenceNumber();
 }
 
+void ClipboardAndroid::SetClipboardDlpController(
+    std::unique_ptr<ClipboardDlpController> dlp_controller) {
+  NOTIMPLEMENTED();
+}
+
 // |data_dst| is not used. It's only passed to be consistent with other
 // platforms.
 bool ClipboardAndroid::IsFormatAvailable(
diff --git a/ui/base/clipboard/clipboard_android.h b/ui/base/clipboard/clipboard_android.h
index 2d5c127..09258ce4 100644
--- a/ui/base/clipboard/clipboard_android.h
+++ b/ui/base/clipboard/clipboard_android.h
@@ -59,6 +59,8 @@
   // Clipboard overrides:
   void OnPreShutdown() override;
   uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  void SetClipboardDlpController(
+      std::unique_ptr<ClipboardDlpController> dlp_controller) override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const ClipboardDataEndpoint* data_dst) const override;
diff --git a/ui/base/clipboard/clipboard_dlp_controller.h b/ui/base/clipboard/clipboard_dlp_controller.h
new file mode 100644
index 0000000..bf4447b
--- /dev/null
+++ b/ui/base/clipboard/clipboard_dlp_controller.h
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_DLP_CONTROLLER_H_
+#define UI_BASE_CLIPBOARD_CLIPBOARD_DLP_CONTROLLER_H_
+
+#include "ui/base/clipboard/clipboard_data_endpoint.h"
+
+namespace ui {
+
+// The Clipboard Data Leak Prevention controller is used to control clipboard
+// read operations. It should allow/disallow clipboard data read given the
+// source of the data and the destination trying to access the data and a set of
+// rules controlling these source and destination.
+class ClipboardDlpController {
+ public:
+  ClipboardDlpController() = default;
+  virtual ~ClipboardDlpController() = default;
+
+  virtual bool IsDataReadAllowed(
+      const ClipboardDataEndpoint* const data_src,
+      const ClipboardDataEndpoint* const data_dst) const = 0;
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_CLIPBOARD_CLIPBOARD_DLP_CONTROLLER_H_
diff --git a/ui/base/clipboard/clipboard_mac.h b/ui/base/clipboard/clipboard_mac.h
index 849c3b8..1189e052 100644
--- a/ui/base/clipboard/clipboard_mac.h
+++ b/ui/base/clipboard/clipboard_mac.h
@@ -31,6 +31,8 @@
   // Clipboard overrides:
   void OnPreShutdown() override;
   uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  void SetClipboardDlpController(
+      std::unique_ptr<ClipboardDlpController> dlp_controller) override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const ClipboardDataEndpoint* data_dst) const override;
diff --git a/ui/base/clipboard/clipboard_mac.mm b/ui/base/clipboard/clipboard_mac.mm
index 8e71324..3faea41c 100644
--- a/ui/base/clipboard/clipboard_mac.mm
+++ b/ui/base/clipboard/clipboard_mac.mm
@@ -70,6 +70,11 @@
   return [pb changeCount];
 }
 
+void ClipboardMac::SetClipboardDlpController(
+    std::unique_ptr<ClipboardDlpController> dlp_controller) {
+  NOTIMPLEMENTED();
+}
+
 // |data_dst| is not used. It's only passed to be consistent with other
 // platforms.
 bool ClipboardMac::IsFormatAvailable(
diff --git a/ui/base/clipboard/clipboard_non_backed.cc b/ui/base/clipboard/clipboard_non_backed.cc
index 2eddf5f..f2a1922 100644
--- a/ui/base/clipboard/clipboard_non_backed.cc
+++ b/ui/base/clipboard/clipboard_non_backed.cc
@@ -23,6 +23,7 @@
 #include "ui/base/clipboard/clipboard_constants.h"
 #include "ui/base/clipboard/clipboard_data.h"
 #include "ui/base/clipboard/clipboard_data_endpoint.h"
+#include "ui/base/clipboard/clipboard_dlp_controller.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
 #include "ui/base/clipboard/clipboard_metrics.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
@@ -188,6 +189,17 @@
     ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();
   }
 
+  void SetDlpController(
+      std::unique_ptr<ClipboardDlpController> dlp_controller) {
+    dlp_controller_ = std::move(dlp_controller);
+  }
+
+  bool IsReadAllowed(const ClipboardDataEndpoint* data_dst) const {
+    if (!dlp_controller_)
+      return true;
+    return dlp_controller_->IsDataReadAllowed(GetData()->source(), data_dst);
+  }
+
  private:
   // True if the data on top of the clipboard stack has format |format|.
   bool HasFormat(ClipboardInternalFormat format) const {
@@ -213,6 +225,9 @@
   // Sequence number uniquely identifying clipboard state.
   uint64_t sequence_number_ = 0;
 
+  // Data-leak prevention controller controlling clipboard read operations.
+  std::unique_ptr<ClipboardDlpController> dlp_controller_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(ClipboardInternal);
 };
 
@@ -314,6 +329,11 @@
 
 void ClipboardNonBacked::OnPreShutdown() {}
 
+void ClipboardNonBacked::SetClipboardDlpController(
+    std::unique_ptr<ClipboardDlpController> dlp_controller) {
+  clipboard_internal_->SetDlpController(std::move(dlp_controller));
+}
+
 uint64_t ClipboardNonBacked::GetSequenceNumber(ClipboardBuffer buffer) const {
   DCHECK(CalledOnValidThread());
   return clipboard_internal_->sequence_number();
@@ -325,6 +345,10 @@
     const ClipboardDataEndpoint* data_dst) const {
   DCHECK(CalledOnValidThread());
   DCHECK(IsSupportedClipboardBuffer(buffer));
+
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return false;
+
   if (ClipboardFormatType::GetPlainTextType().Equals(format) ||
       ClipboardFormatType::GetUrlType().Equals(format))
     return clipboard_internal_->IsFormatAvailable(
@@ -358,6 +382,9 @@
   DCHECK(CalledOnValidThread());
   DCHECK(types);
 
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return;
+
   types->clear();
   if (IsFormatAvailable(ClipboardFormatType::GetPlainTextType(), buffer,
                         data_dst))
@@ -389,6 +416,9 @@
 
   std::vector<base::string16> types;
 
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return types;
+
   // Includes all non-pickled AvailableTypes.
   if (IsFormatAvailable(ClipboardFormatType::GetPlainTextType(), buffer,
                         data_dst)) {
@@ -415,6 +445,10 @@
                                   const ClipboardDataEndpoint* data_dst,
                                   base::string16* result) const {
   DCHECK(CalledOnValidThread());
+
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return;
+
   RecordRead(ClipboardFormatMetric::kText);
   clipboard_internal_->ReadText(result);
 }
@@ -423,6 +457,10 @@
                                        const ClipboardDataEndpoint* data_dst,
                                        std::string* result) const {
   DCHECK(CalledOnValidThread());
+
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return;
+
   RecordRead(ClipboardFormatMetric::kText);
   clipboard_internal_->ReadAsciiText(result);
 }
@@ -434,6 +472,10 @@
                                   uint32_t* fragment_start,
                                   uint32_t* fragment_end) const {
   DCHECK(CalledOnValidThread());
+
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return;
+
   RecordRead(ClipboardFormatMetric::kHtml);
   clipboard_internal_->ReadHTML(markup, src_url, fragment_start, fragment_end);
 }
@@ -442,6 +484,10 @@
                                  const ClipboardDataEndpoint* data_dst,
                                  std::string* result) const {
   DCHECK(CalledOnValidThread());
+
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return;
+
   RecordRead(ClipboardFormatMetric::kRtf);
   clipboard_internal_->ReadRTF(result);
 }
@@ -450,6 +496,10 @@
                                    const ClipboardDataEndpoint* data_dst,
                                    ReadImageCallback callback) const {
   DCHECK(CalledOnValidThread());
+
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return;
+
   RecordRead(ClipboardFormatMetric::kImage);
   std::move(callback).Run(clipboard_internal_->ReadImage());
 }
@@ -459,6 +509,10 @@
                                         const ClipboardDataEndpoint* data_dst,
                                         base::string16* result) const {
   DCHECK(CalledOnValidThread());
+
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return;
+
   RecordRead(ClipboardFormatMetric::kCustomData);
   clipboard_internal_->ReadCustomData(type, result);
 }
@@ -467,6 +521,10 @@
                                       base::string16* title,
                                       std::string* url) const {
   DCHECK(CalledOnValidThread());
+
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return;
+
   RecordRead(ClipboardFormatMetric::kBookmark);
   clipboard_internal_->ReadBookmark(title, url);
 }
@@ -475,6 +533,10 @@
                                   const ClipboardDataEndpoint* data_dst,
                                   std::string* result) const {
   DCHECK(CalledOnValidThread());
+
+  if (!clipboard_internal_->IsReadAllowed(data_dst))
+    return;
+
   RecordRead(ClipboardFormatMetric::kData);
   clipboard_internal_->ReadData(format.GetName(), result);
 }
diff --git a/ui/base/clipboard/clipboard_non_backed.h b/ui/base/clipboard/clipboard_non_backed.h
index 5b35665..3c9099d 100644
--- a/ui/base/clipboard/clipboard_non_backed.h
+++ b/ui/base/clipboard/clipboard_non_backed.h
@@ -29,6 +29,8 @@
 
   // Clipboard overrides:
   void OnPreShutdown() override;
+  void SetClipboardDlpController(
+      std::unique_ptr<ClipboardDlpController> dlp_controller) override;
   uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
diff --git a/ui/base/clipboard/clipboard_ozone.cc b/ui/base/clipboard/clipboard_ozone.cc
index 2d79025..b65e17e 100644
--- a/ui/base/clipboard/clipboard_ozone.cc
+++ b/ui/base/clipboard/clipboard_ozone.cc
@@ -337,6 +337,12 @@
   return async_clipboard_ozone_->GetSequenceNumber(buffer);
 }
 
+// TODO(crbug.com/1103194): Setting |dlp_controller| should be supported.
+void ClipboardOzone::SetClipboardDlpController(
+    std::unique_ptr<ClipboardDlpController> dlp_controller) {
+  NOTIMPLEMENTED();
+}
+
 // TODO(crbug.com/1103194): |data_dst| should be supported.
 bool ClipboardOzone::IsFormatAvailable(
     const ClipboardFormatType& format,
diff --git a/ui/base/clipboard/clipboard_ozone.h b/ui/base/clipboard/clipboard_ozone.h
index ca77c5f..65b3ac19 100644
--- a/ui/base/clipboard/clipboard_ozone.h
+++ b/ui/base/clipboard/clipboard_ozone.h
@@ -26,6 +26,8 @@
   // Clipboard overrides:
   void OnPreShutdown() override;
   uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  void SetClipboardDlpController(
+      std::unique_ptr<ClipboardDlpController> dlp_controller) override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const ClipboardDataEndpoint* data_dst) const override;
diff --git a/ui/base/clipboard/clipboard_win.cc b/ui/base/clipboard/clipboard_win.cc
index 403670c2..d21aa94b 100644
--- a/ui/base/clipboard/clipboard_win.cc
+++ b/ui/base/clipboard/clipboard_win.cc
@@ -246,6 +246,11 @@
   return ::GetClipboardSequenceNumber();
 }
 
+void ClipboardWin::SetClipboardDlpController(
+    std::unique_ptr<ClipboardDlpController> dlp_controller) {
+  NOTIMPLEMENTED();
+}
+
 // |data_dst| is not used. It's only passed to be consistent with other
 // platforms.
 bool ClipboardWin::IsFormatAvailable(
diff --git a/ui/base/clipboard/clipboard_win.h b/ui/base/clipboard/clipboard_win.h
index 7843b1e..32e85b0 100644
--- a/ui/base/clipboard/clipboard_win.h
+++ b/ui/base/clipboard/clipboard_win.h
@@ -36,6 +36,8 @@
   // Clipboard overrides:
   void OnPreShutdown() override;
   uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  void SetClipboardDlpController(
+      std::unique_ptr<ClipboardDlpController> dlp_controller) override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const ClipboardDataEndpoint* data_dst) const override;
diff --git a/ui/base/clipboard/clipboard_x11.cc b/ui/base/clipboard/clipboard_x11.cc
index 898660f..1430878 100644
--- a/ui/base/clipboard/clipboard_x11.cc
+++ b/ui/base/clipboard/clipboard_x11.cc
@@ -498,6 +498,11 @@
     return SelectionChangeObserver::GetInstance()->primary_sequence_number();
 }
 
+void ClipboardX11::SetClipboardDlpController(
+    std::unique_ptr<ClipboardDlpController> dlp_controller) {
+  NOTIMPLEMENTED();
+}
+
 // |data_dst| is not used. It's only passed to be consistent with other
 // platforms.
 bool ClipboardX11::IsFormatAvailable(
diff --git a/ui/base/clipboard/clipboard_x11.h b/ui/base/clipboard/clipboard_x11.h
index c0f5146..d7b429e 100644
--- a/ui/base/clipboard/clipboard_x11.h
+++ b/ui/base/clipboard/clipboard_x11.h
@@ -25,6 +25,8 @@
   // Clipboard overrides:
   void OnPreShutdown() override;
   uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  void SetClipboardDlpController(
+      std::unique_ptr<ClipboardDlpController> dlp_controller) override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const ClipboardDataEndpoint* data_dst) const override;
diff --git a/ui/base/clipboard/test/test_clipboard.cc b/ui/base/clipboard/test/test_clipboard.cc
index ef56ff195..ac467227 100644
--- a/ui/base/clipboard/test/test_clipboard.cc
+++ b/ui/base/clipboard/test/test_clipboard.cc
@@ -39,6 +39,10 @@
   return GetStore(buffer).sequence_number;
 }
 
+// TODO(crbug.com/1103215): Setting |dlp_controller| should be supported.
+void TestClipboard::SetClipboardDlpController(
+    std::unique_ptr<ClipboardDlpController> dlp_controller) {}
+
 // TODO(crbug.com/1103215): |data_dst| should be supported.
 bool TestClipboard::IsFormatAvailable(
     const ClipboardFormatType& format,
diff --git a/ui/base/clipboard/test/test_clipboard.h b/ui/base/clipboard/test/test_clipboard.h
index 95a3430..a90d1846 100644
--- a/ui/base/clipboard/test/test_clipboard.h
+++ b/ui/base/clipboard/test/test_clipboard.h
@@ -35,6 +35,8 @@
   // Clipboard overrides.
   void OnPreShutdown() override;
   uint64_t GetSequenceNumber(ClipboardBuffer buffer) const override;
+  void SetClipboardDlpController(
+      std::unique_ptr<ClipboardDlpController> dlp_controller) override;
   bool IsFormatAvailable(const ClipboardFormatType& format,
                          ClipboardBuffer buffer,
                          const ClipboardDataEndpoint* data_dst) const override;
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index bd4310e7..2d6061b7 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -788,6 +788,11 @@
 
 .dialog-header.files-ng #share-menu-button > .icon {
   -webkit-mask-image: url(../images/files/ui/share_ng.svg);
+  height: 48px;
+  margin-inline-start: -7px;
+  margin-top: -7px;
+  position: absolute;
+  width: 48px;
 }
 
 body.check-select .dialog-header #share-menu-button > .icon {
@@ -888,6 +893,11 @@
 
 .dialog-header.files-ng #selection-menu-button > .icon {
   -webkit-mask-image: url(../images/files/ui/menu_ng.svg);
+  height: 48px;
+  margin-inline-start: -7px;
+  margin-top: -7px;
+  position: absolute;
+  width: 48px;
 }
 
 body:not(.check-select) #selection-menu-button {
@@ -3382,6 +3392,13 @@
   margin-top: 2px;
 }
 
+body.files-ng #gear-menu,
+body.files-ng #share-menu,
+body.files-ng #sort-menu,
+body.files-ng #tasks-menu {
+  margin-top: 8px;
+}
+
 #gear-menu > cr-menu-item:not(.menuitem-button),
 #sort-menu > cr-menu-item {
   margin-inline-end: 50px;
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index af6423f..91c134b 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -47,7 +47,6 @@
  * Must be kept in sync with webui_accelerator_mapping.cc.
  */
 /** @const */ var ACCELERATOR_CANCEL = 'cancel';
-/** @const */ var ACCELERATOR_ENABLE_DEBBUGING = 'debugging';
 /** @const */ var ACCELERATOR_ENROLLMENT = 'enrollment';
 /** @const */ var ACCELERATOR_KIOSK_ENABLE = 'kiosk_enable';
 /** @const */ var ACCELERATOR_VERSION = 'version';
@@ -113,19 +112,6 @@
   ];
 
   /**
-   * Group of screens (screen IDs) where enable debuggingscreen invocation is
-   * available. Newer screens using Polymer use the attribute
-   * `enableDebuggingAllowed` in their `ready()` method.
-   * @type Array<string>
-   * @const
-   */
-  var ENABLE_DEBUGGING_AVAILABLE_SCREEN_GROUP = [
-    SCREEN_OOBE_NETWORK,
-    SCREEN_OOBE_EULA,
-    SCREEN_OOBE_UPDATE
-  ];
-
-  /**
    * As Polymer behaviors do not provide true inheritance, when two behaviors
    * would declare same method one of them will be hidden. Also, if element
    * re-declares the method it needs explicitly iterate over behaviors and call
@@ -394,12 +380,6 @@
         if (this.currentScreen && this.currentScreen.cancel) {
           this.currentScreen.cancel();
         }
-      } else if (name == ACCELERATOR_ENABLE_DEBBUGING) {
-        if (attributes.enableDebuggingAllowed ||
-            ENABLE_DEBUGGING_AVAILABLE_SCREEN_GROUP.indexOf(currentStepId) !=
-            -1) {
-          chrome.send('toggleEnableDebuggingScreen');
-        }
       } else if (name == ACCELERATOR_ENROLLMENT) {
         if (attributes.startEnrollmentAllowed ||
             currentStepId == SCREEN_GAIA_SIGNIN ||
diff --git a/ui/login/display_manager_types.js b/ui/login/display_manager_types.js
index f353849..22d382d7 100644
--- a/ui/login/display_manager_types.js
+++ b/ui/login/display_manager_types.js
@@ -9,7 +9,6 @@
 
 /**
  * @typedef {{
- *   enableDebuggingAllowed: (boolean|undefined),
  *   resetAllowed: (boolean|undefined),
  *   startEnrollmentAllowed: (boolean|undefined),
  *   toggleKioskAllowed: (boolean|undefined),
@@ -19,12 +18,6 @@
 var DisplayManagerScreenAttributes = {};
 
 /**
- * True if showing "enable debugging" is allowed for the screen.
- * @type {boolean|undefined}
- */
-DisplayManagerScreenAttributes.enableDebuggingAllowed;
-
-/**
  * True if device reset is allowed on the screen.
  * @type {boolean|undefined}
  */
diff --git a/ui/message_center/views/notification_header_view.cc b/ui/message_center/views/notification_header_view.cc
index a9f6984e..a9d2c14 100644
--- a/ui/message_center/views/notification_header_view.cc
+++ b/ui/message_center/views/notification_header_view.cc
@@ -351,8 +351,8 @@
   NotifyAccessibilityEvent(ax::mojom::Event::kStateChanged, true);
 }
 
-void NotificationHeaderView::SetAccentColor(SkColor color) {
-  accent_color_ = color;
+void NotificationHeaderView::SetAccentColor(base::Optional<SkColor> color) {
+  accent_color_ = std::move(color);
   UpdateColors();
 }
 
diff --git a/ui/message_center/views/notification_header_view.h b/ui/message_center/views/notification_header_view.h
index f328556..bc391f1 100644
--- a/ui/message_center/views/notification_header_view.h
+++ b/ui/message_center/views/notification_header_view.h
@@ -41,9 +41,10 @@
   void SetExpandButtonEnabled(bool enabled);
   void SetExpanded(bool expanded);
 
-  // Calls UpdateColors() to set the unified theme color used among the
-  // app icon, app name, and expand button.
-  void SetAccentColor(SkColor color);
+  // Calls UpdateColors() to set the unified theme color used among the app
+  // icon, app name, and expand button. If set to base::nullopt it will use the
+  // NotificationDefaultAccentColor from the native theme.
+  void SetAccentColor(base::Optional<SkColor> color);
 
   // Sets the background color of the notification. This is used to ensure that
   // the accent color has enough contrast against the background.
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index b26d75c5..efce9410 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -68,7 +68,6 @@
 constexpr gfx::Insets kContentRowPadding(0, 12, 16, 12);
 constexpr gfx::Insets kActionsRowPadding(8, 8, 8, 8);
 constexpr int kActionsRowHorizontalSpacing = 8;
-constexpr gfx::Insets kActionButtonPadding(0, 12, 0, 12);
 constexpr gfx::Insets kStatusTextPadding(4, 0, 0, 0);
 constexpr gfx::Size kActionButtonMinSize(0, 32);
 // TODO(tetsui): Move |kIconViewSize| to public/cpp/message_center_constants.h
@@ -317,7 +316,6 @@
     : views::MdTextButton(listener, views::style::CONTEXT_BUTTON_MD),
       placeholder_(placeholder) {
   SetText(label);
-  SetBorder(views::CreateEmptyBorder(kActionButtonPadding));
   SetMinSize(kActionButtonMinSize);
   views::InstallRectHighlightPathGenerator(this);
   SetTextSubpixelRenderingEnabled(false);
@@ -325,12 +323,10 @@
 
 NotificationMdTextButton::~NotificationMdTextButton() = default;
 
-void NotificationMdTextButton::SetText(const base::string16& text) {
-  views::LabelButton::SetText(base::i18n::ToUpper(text));
+void NotificationMdTextButton::UpdateBackgroundColor() {
+  // Overridden as no-op so we don't draw any background or border.
 }
 
-void NotificationMdTextButton::UpdateColors() {}
-
 BEGIN_METADATA(NotificationMdTextButton)
 METADATA_PARENT_CLASS(views::MdTextButton)
 END_METADATA()
@@ -414,7 +410,7 @@
   textfield_->SetTextColor(SK_ColorWHITE);
   textfield_->SetBackgroundColor(SK_ColorTRANSPARENT);
   textfield_->set_placeholder_text_color(theme->GetSystemColor(
-      ui::NativeTheme::kColorId_TextfieldPlaceholderColor));
+      ui::NativeTheme::kColorId_NotificationEmptyPlaceholderTextColor));
   SetButtonImage();
 }
 
@@ -839,8 +835,7 @@
 
 void NotificationViewMD::CreateOrUpdateContextTitleView(
     const Notification& notification) {
-  header_row_->SetAccentColor(notification.accent_color().value_or(
-      ui::NativeTheme::kColorId_NotificationDefaultAccentColor));
+  header_row_->SetAccentColor(notification.accent_color());
   header_row_->SetTimestamp(notification.timestamp());
   header_row_->SetAppNameElideBehavior(gfx::ELIDE_TAIL);
   header_row_->SetSummaryText(base::string16());
@@ -1064,8 +1059,8 @@
   // cache images if so. (crbug.com/768748)
   gfx::Image masked_small_icon = notification.GenerateMaskedSmallIcon(
       kSmallImageSizeMD,
-      notification.accent_color().value_or(
-          ui::NativeTheme::kColorId_NotificationDefaultAccentColor));
+      notification.accent_color().value_or(GetNativeTheme()->GetSystemColor(
+          ui::NativeTheme::kColorId_NotificationDefaultAccentColor)));
 
   if (masked_small_icon.IsEmpty()) {
     header_row_->ClearAppIcon();
@@ -1125,25 +1120,23 @@
     }
   }
 
-  SkColor accent_color =
-      notification.accent_color().value_or(views::style::GetColor(
-          *this, views::style::CONTEXT_BUTTON_MD, views::style::STYLE_PRIMARY));
   for (size_t i = 0; i < buttons.size(); ++i) {
     ButtonInfo button_info = buttons[i];
+    base::string16 label = base::i18n::ToUpper(button_info.title);
     if (new_buttons) {
       action_buttons_.push_back(action_buttons_row_->AddChildView(
-          std::make_unique<NotificationMdTextButton>(this, button_info.title,
+          std::make_unique<NotificationMdTextButton>(this, label,
                                                      button_info.placeholder)));
       // TODO(pkasting): BoxLayout should invalidate automatically when a child
       // is added, at which point we can remove this call.
       action_buttons_row_->InvalidateLayout();
     } else {
-      action_buttons_[i]->SetText(button_info.title);
+      action_buttons_[i]->SetText(label);
       action_buttons_[i]->set_placeholder(button_info.placeholder);
     }
 
     // Change action button color to the accent color.
-    action_buttons_[i]->SetEnabledTextColors(accent_color);
+    action_buttons_[i]->SetEnabledTextColors(notification.accent_color());
   }
 
   // Inherit mouse hover state when action button views reset.
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h
index c55dc84..5c38030b 100644
--- a/ui/message_center/views/notification_view_md.h
+++ b/ui/message_center/views/notification_view_md.h
@@ -46,9 +46,8 @@
                            const base::Optional<base::string16>& placeholder);
   ~NotificationMdTextButton() override;
 
-  // Overridden from MdTextButton
-  void UpdateColors() override;
-  void SetText(const base::string16& text) override;
+  // views::MdTextButton:
+  void UpdateBackgroundColor() override;
 
   const base::Optional<base::string16>& placeholder() const {
     return placeholder_;
diff --git a/ui/message_center/views/notification_view_md_unittest.cc b/ui/message_center/views/notification_view_md_unittest.cc
index d26a472..a43a4cb 100644
--- a/ui/message_center/views/notification_view_md_unittest.cc
+++ b/ui/message_center/views/notification_view_md_unittest.cc
@@ -15,6 +15,7 @@
 #include "ui/events/event_utils.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/image/image_unittest_util.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/message_center_observer.h"
 #include "ui/message_center/public/cpp/message_center_constants.h"
@@ -988,16 +989,30 @@
     notification_view()->ToggleExpanded();
   EXPECT_TRUE(notification_view()->actions_row_->GetVisible());
 
+  auto app_icon_color_matches = [&](SkColor color) {
+    SkBitmap expected =
+        notification->GenerateMaskedSmallIcon(kSmallImageSizeMD, color)
+            .AsBitmap();
+    SkBitmap actual = *notification_view()
+                           ->header_row_->app_icon_view_for_testing()
+                           ->GetImage()
+                           .bitmap();
+    return gfx::test::AreBitmapsEqual(expected, actual);
+  };
+
   // By default, header does not have accent color (default grey), and
   // buttons have default accent color.
-  EXPECT_EQ(ui::NativeTheme::kColorId_NotificationDefaultAccentColor,
-            notification_view()->header_row_->accent_color_for_testing());
+  EXPECT_FALSE(
+      notification_view()->header_row_->accent_color_for_testing().has_value());
   EXPECT_EQ(
       kActionButtonTextColor,
       notification_view()->action_buttons_[0]->enabled_color_for_testing());
   EXPECT_EQ(
       kActionButtonTextColor,
       notification_view()->action_buttons_[1]->enabled_color_for_testing());
+  EXPECT_TRUE(app_icon_color_matches(
+      notification_view()->GetNativeTheme()->GetSystemColor(
+          ui::NativeTheme::kColorId_NotificationDefaultAccentColor)));
 
   // If custom accent color is set, the header and the buttons should have the
   // same accent color.
@@ -1013,6 +1028,7 @@
   EXPECT_EQ(
       kCustomAccentColor,
       notification_view()->action_buttons_[1]->enabled_color_for_testing());
+  EXPECT_TRUE(app_icon_color_matches(kCustomAccentColor));
 }
 
 TEST_F(NotificationViewMDTest, UseImageAsIcon) {
diff --git a/ui/native_theme/common_theme.cc b/ui/native_theme/common_theme.cc
index f8b36be4..c0c37674 100644
--- a/ui/native_theme/common_theme.cc
+++ b/ui/native_theme/common_theme.cc
@@ -429,6 +429,8 @@
       return SkColorSetRGB(0xf5, 0xf5, 0xf5);
     case NativeTheme::kColorId_NotificationEmptyPlaceholderIconColor:
       return SkColorSetA(SK_ColorWHITE, 0x60);
+    case NativeTheme::kColorId_NotificationEmptyPlaceholderTextColor:
+      return SkColorSetA(SK_ColorWHITE, gfx::kDisabledControlAlpha);
     case NativeTheme::kColorId_NotificationInkDropBase:
       return gfx::kGoogleBlue600;
 #if defined(OS_CHROMEOS)
diff --git a/ui/native_theme/native_theme_color_id.h b/ui/native_theme/native_theme_color_id.h
index 739c28d..dde0f97 100644
--- a/ui/native_theme/native_theme_color_id.h
+++ b/ui/native_theme/native_theme_color_id.h
@@ -92,6 +92,7 @@
   OP(kColorId_NotificationLargeImageBackground),                               \
   OP(kColorId_NotificationPlaceholderIconColor),                               \
   OP(kColorId_NotificationEmptyPlaceholderIconColor),                          \
+  OP(kColorId_NotificationEmptyPlaceholderTextColor),                          \
   OP(kColorId_NotificationDefaultAccentColor),                                 \
   OP(kColorId_NotificationInkDropBase),                                        \
   /* Slider */                                                                 \
diff --git a/ui/views/controls/button/image_button.cc b/ui/views/controls/button/image_button.cc
index 8a25c40..eae1949 100644
--- a/ui/views/controls/button/image_button.cc
+++ b/ui/views/controls/button/image_button.cc
@@ -244,6 +244,10 @@
   toggled_tooltip_text_ = tooltip;
 }
 
+void ToggleImageButton::SetToggledAccessibleName(const base::string16& name) {
+  toggled_accessible_name_ = name;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // ToggleImageButton, ImageButton overrides:
 
@@ -277,7 +281,13 @@
 
 void ToggleImageButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
   ImageButton::GetAccessibleNodeData(node_data);
-  node_data->SetName(GetTooltipText(gfx::Point()));
+  if (!toggled_)
+    return;
+
+  if (!toggled_accessible_name_.empty())
+    node_data->SetName(toggled_accessible_name_);
+  else if (!toggled_tooltip_text_.empty())
+    node_data->SetName(toggled_tooltip_text_);
 
   // Use the visual pressed image as a cue for making this control into an
   // accessible toggle button.
diff --git a/ui/views/controls/button/image_button.h b/ui/views/controls/button/image_button.h
index 81ad539..0ee3e8ff9 100644
--- a/ui/views/controls/button/image_button.h
+++ b/ui/views/controls/button/image_button.h
@@ -133,6 +133,9 @@
   // Set the tooltip text displayed when the button is toggled.
   void SetToggledTooltipText(const base::string16& tooltip);
 
+  // Set the accessible text used when the button is toggled.
+  void SetToggledAccessibleName(const base::string16& name);
+
   // Overridden from ImageButton:
   const gfx::ImageSkia& GetImage(ButtonState state) const override;
   void SetImage(ButtonState state, const gfx::ImageSkia& image) override;
@@ -156,6 +159,10 @@
   // this one is shown when toggled.
   base::string16 toggled_tooltip_text_;
 
+  // The parent class's accessibility data is used when not toggled, and this
+  // one is used when toggled.
+  base::string16 toggled_accessible_name_;
+
   DISALLOW_COPY_AND_ASSIGN(ToggleImageButton);
 };
 
diff --git a/ui/views/controls/button/md_text_button.cc b/ui/views/controls/button/md_text_button.cc
index 5f66ba1..8f2b304 100644
--- a/ui/views/controls/button/md_text_button.cc
+++ b/ui/views/controls/button/md_text_button.cc
@@ -227,27 +227,31 @@
                      horizontal_padding);
 }
 
-void MdTextButton::UpdateColors() {
-  bool is_disabled = GetState() == STATE_DISABLED;
+void MdTextButton::UpdateTextColor() {
+  if (explicitly_set_normal_color())
+    return;
+
   SkColor enabled_text_color =
       style::GetColor(*this, label()->GetTextContext(),
                       is_prominent_ ? style::STYLE_DIALOG_BUTTON_DEFAULT
                                     : style::STYLE_PRIMARY);
-  if (!explicitly_set_normal_color()) {
-    const auto colors = explicitly_set_colors();
-    LabelButton::SetEnabledTextColors(enabled_text_color);
-    // Disabled buttons need the disabled color explicitly set.
-    // This ensures that label()->GetEnabledColor() returns the correct color as
-    // the basis for calculating the stroke color. enabled_text_color isn't used
-    // since a descendant could have overridden the label enabled color.
-    if (is_disabled) {
-      LabelButton::SetTextColor(
-          STATE_DISABLED, style::GetColor(*this, label()->GetTextContext(),
-                                          style::STYLE_DISABLED));
-    }
-    set_explicitly_set_colors(colors);
-  }
 
+  const auto colors = explicitly_set_colors();
+  LabelButton::SetEnabledTextColors(enabled_text_color);
+  // Disabled buttons need the disabled color explicitly set.
+  // This ensures that label()->GetEnabledColor() returns the correct color as
+  // the basis for calculating the stroke color. enabled_text_color isn't used
+  // since a descendant could have overridden the label enabled color.
+  if (GetState() == STATE_DISABLED) {
+    LabelButton::SetTextColor(STATE_DISABLED,
+                              style::GetColor(*this, label()->GetTextContext(),
+                                              style::STYLE_DISABLED));
+  }
+  set_explicitly_set_colors(colors);
+}
+
+void MdTextButton::UpdateBackgroundColor() {
+  bool is_disabled = GetState() == STATE_DISABLED;
   ui::NativeTheme* theme = GetNativeTheme();
   SkColor bg_color =
       theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonColor);
@@ -280,6 +284,11 @@
   SetBackground(
       CreateBackgroundFromPainter(Painter::CreateRoundRectWith1PxBorderPainter(
           bg_color, stroke_color, corner_radius_)));
+}
+
+void MdTextButton::UpdateColors() {
+  UpdateTextColor();
+  UpdateBackgroundColor();
   SchedulePaint();
 }
 
diff --git a/ui/views/controls/button/md_text_button.h b/ui/views/controls/button/md_text_button.h
index 4a968cd..6688bc4 100644
--- a/ui/views/controls/button/md_text_button.h
+++ b/ui/views/controls/button/md_text_button.h
@@ -61,9 +61,12 @@
 
  private:
   void UpdatePadding();
-  virtual void UpdateColors();
   gfx::Insets CalculateDefaultPadding() const;
 
+  void UpdateTextColor();
+  virtual void UpdateBackgroundColor();
+  void UpdateColors();
+
   // True if this button uses prominent styling (blue fill, etc.).
   bool is_prominent_ = false;
 
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 0479effb..61df9d38 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -595,6 +595,26 @@
   return model_->GetCursorPosition();
 }
 
+void Textfield::SetTextAndScrollAndSelectRange(
+    const base::string16& text,
+    const size_t cursor_position,
+    const std::vector<size_t>& positions,
+    const gfx::Range range) {
+  // Pass cursor_position to SetText to ensure edit history works as expected.
+  model_->SetText(text, cursor_position);
+  NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
+  for (auto position : positions) {
+    model_->MoveCursorTo(position);
+    GetRenderText()->GetUpdatedCursorBounds();
+  }
+  model_->SelectRange(range);
+  OnPropertyChanged(&model_ + kTextfieldSelectedRange, kPropertyEffectsPaint);
+  // We don't set the |text_changed| param to true because that would notify
+  // the TextfieldController::ContentsChanged(), which should only occur when
+  // the user changes the text.
+  UpdateAfterChange(false, true);
+}
+
 void Textfield::SetColor(SkColor value) {
   GetRenderText()->SetColor(value);
   cursor_view_->layer()->SetColor(value);
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index 16043316..57da7deb 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -122,6 +122,23 @@
   void SetText(const base::string16& new_text);
   void SetText(const base::string16& new_text, size_t cursor_position);
 
+  // Similar to calling SetText followed by SetSelectedRange calls, but will
+  // dedupe some calls. Notably, this prevents OnCaretBoundsChanged from being
+  // called multiple times for a single change which can cause issues for
+  // accessibility tools.
+  // - |text| and |cursor_position| see SetText() comment above.
+  // - |scroll_positions| a vector of positions to scroll into view. This can
+  // contain multiple positions which can be useful to e.g. ensure multiple
+  // positions are in view (if possible). Scrolls are applied in the order of
+  // |scroll_positions|; i.e., later positions will have priority over earlier
+  // positions.
+  // - |range| is used to invoke SetSelectedRange and will also be scrolled to.
+  void SetTextAndScrollAndSelectRange(
+      const base::string16& text,
+      const size_t cursor_position,
+      const std::vector<size_t>& scroll_positions,
+      const gfx::Range range);
+
   // Appends the given string to the previously-existing text in the field.
   void AppendText(const base::string16& new_text);
 
diff --git a/ui/views/controls/textfield/textfield_test_api.cc b/ui/views/controls/textfield/textfield_test_api.cc
index 40176fa3..e939a31 100644
--- a/ui/views/controls/textfield/textfield_test_api.cc
+++ b/ui/views/controls/textfield/textfield_test_api.cc
@@ -37,4 +37,12 @@
   return textfield_->ShouldShowCursor();
 }
 
+int TextfieldTestApi::GetDisplayOffsetX() const {
+  return GetRenderText()->GetUpdatedDisplayOffset().x();
+}
+
+void TextfieldTestApi::SetDisplayOffsetX(int x) const {
+  return GetRenderText()->SetDisplayOffset(x);
+}
+
 }  // namespace views
diff --git a/ui/views/controls/textfield/textfield_test_api.h b/ui/views/controls/textfield/textfield_test_api.h
index 78436bc..9afc9ba3 100644
--- a/ui/views/controls/textfield/textfield_test_api.h
+++ b/ui/views/controls/textfield/textfield_test_api.h
@@ -56,6 +56,9 @@
 
   bool ShouldShowCursor() const;
 
+  int GetDisplayOffsetX() const;
+  void SetDisplayOffsetX(int x) const;
+
  private:
   Textfield* textfield_;
 };
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index f76f8bc..59054b0 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -19,7 +19,6 @@
 #include "base/pickle.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
-#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "ui/accessibility/ax_enums.mojom.h"
@@ -45,6 +44,7 @@
 #include "ui/events/test/event_generator.h"
 #include "ui/events/test/keyboard_layout.h"
 #include "ui/gfx/render_text.h"
+#include "ui/gfx/render_text_test_api.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/controls/textfield/textfield_model.h"
@@ -830,7 +830,6 @@
   // text programmatically.
   last_contents_.clear();
   textfield_->SetText(ASCIIToUTF16("this is"));
-
   EXPECT_STR_EQ("this is", model_->text());
   EXPECT_STR_EQ("this is", textfield_->GetText());
   EXPECT_TRUE(last_contents_.empty());
@@ -844,6 +843,123 @@
   textfield_->SelectAll(false);
   EXPECT_STR_EQ("this is a test", textfield_->GetSelectedText());
   EXPECT_TRUE(last_contents_.empty());
+
+  textfield_->SetTextAndScrollAndSelectRange(ASCIIToUTF16("another test"), 3,
+                                             {}, {4, 5});
+  EXPECT_STR_EQ("another test", model_->text());
+  EXPECT_STR_EQ("another test", textfield_->GetText());
+  EXPECT_STR_EQ("h", textfield_->GetSelectedText());
+  EXPECT_TRUE(last_contents_.empty());
+}
+
+TEST_F(TextfieldTest, SetTextAndScrollAndSelectRange_Scrolling) {
+  InitTextfield();
+
+  // Size the textfield wide enough to hold 10 characters.
+  gfx::test::RenderTextTestApi render_text_test_api(test_api_->GetRenderText());
+  render_text_test_api.SetGlyphWidth(10);
+  // 10px/char * 10chars + 1px for cursor width
+  test_api_->GetRenderText()->SetDisplayRect(gfx::Rect(0, 0, 101, 20));
+
+  // Should scroll cursor into view.
+  test_api_->SetDisplayOffsetX(0);
+  textfield_->SetTextAndScrollAndSelectRange(
+      ASCIIToUTF16("0123456789_123456789_123456789"), 0, {}, {0, 20});
+  EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(0, 20));
+
+  // Cursor position should not affect scroll.
+  test_api_->SetDisplayOffsetX(0);
+  textfield_->SetTextAndScrollAndSelectRange(
+      ASCIIToUTF16("0123456789_123456789_123456789"), 30, {}, {20, 20});
+  EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(20));
+
+  // Scroll positions should affect scroll.
+  test_api_->SetDisplayOffsetX(0);
+  textfield_->SetTextAndScrollAndSelectRange(
+      ASCIIToUTF16("0123456789_123456789_123456789"), 0, {30}, {20, 20});
+  EXPECT_EQ(test_api_->GetDisplayOffsetX(), -200);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(20));
+
+  // Should scroll no more than necessary; e.g., scrolling right should put the
+  // cursor at the right edge.
+  test_api_->SetDisplayOffsetX(0);
+  textfield_->SetTextAndScrollAndSelectRange(
+      ASCIIToUTF16("0123456789_123456789_123456789"), 0, {}, {15, 15});
+  EXPECT_EQ(test_api_->GetDisplayOffsetX(), -50);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(15));
+
+  // Should scroll no more than necessary; e.g., scrolling left should put the
+  // cursor at the left edge.
+  test_api_->SetDisplayOffsetX(-200);  // Scroll all the way right.
+  textfield_->SetTextAndScrollAndSelectRange(
+      ASCIIToUTF16("0123456789_123456789_123456789"), 0, {}, {15, 15});
+  EXPECT_EQ(test_api_->GetDisplayOffsetX(), -150);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(15));
+
+  // Should scroll no more than necessary; e.g., scrolling to a position already
+  // in view should not change the offset.
+  test_api_->SetDisplayOffsetX(-100);  // Scroll the middle 10 chars into view.
+  textfield_->SetTextAndScrollAndSelectRange(
+      ASCIIToUTF16("0123456789_123456789_123456789"), 0, {}, {15, 15});
+  EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(15));
+
+  // With multiple scroll positions, the Last scroll position should be scrolled
+  // to after previous scroll positions.
+  test_api_->SetDisplayOffsetX(0);
+  textfield_->SetTextAndScrollAndSelectRange(
+      ASCIIToUTF16("0123456789_123456789_123456789"), 0, {30, 0}, {20, 20});
+  EXPECT_EQ(test_api_->GetDisplayOffsetX(), -100);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(20));
+
+  // With multiple scroll positions, the previous scroll positions should be
+  // scrolled to anyways.
+  test_api_->SetDisplayOffsetX(0);
+  textfield_->SetTextAndScrollAndSelectRange(
+      ASCIIToUTF16("0123456789_123456789_123456789"), 0, {30, 20}, {20, 20});
+  EXPECT_EQ(test_api_->GetDisplayOffsetX(), -200);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(20));
+
+  // With a non empty selection, only the selection end should affect scrolling.
+  test_api_->SetDisplayOffsetX(0);
+  textfield_->SetTextAndScrollAndSelectRange(
+      ASCIIToUTF16("0123456789_123456789_123456789"), 0, {0}, {30, 0});
+  EXPECT_EQ(test_api_->GetDisplayOffsetX(), 0);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(30, 0));
+}
+
+TEST_F(TextfieldTest, SetTextAndScrollAndSelectRange_ModelEditHistory) {
+  InitTextfield();
+
+  // The cursor and selected range should reflect the |range| parameter.
+  textfield_->SetTextAndScrollAndSelectRange(
+      ASCIIToUTF16("0123456789_123456789_123456789"), 20, {}, {10, 15});
+  EXPECT_EQ(textfield_->GetCursorPosition(), 15u);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(10, 15));
+
+  // After undo, the cursor and selected range should reflect the state prior to
+  // the edit.
+  textfield_->InsertOrReplaceText(ASCIIToUTF16("xyz"));  // 2nd edit
+  SendKeyEvent(ui::VKEY_Z, false, true);                 // Undo 2nd edit
+  EXPECT_EQ(textfield_->GetCursorPosition(), 15u);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(10, 15));
+
+  // After redo, the cursor and selected range should reflect the
+  // |cursor_position| parameter.
+  SendKeyEvent(ui::VKEY_Z, false, true);  // Undo 2nd edit
+  SendKeyEvent(ui::VKEY_Z, false, true);  // Undo 1st edit
+  SendKeyEvent(ui::VKEY_Z, true, true);   // Redo 1st edit
+  EXPECT_EQ(textfield_->GetCursorPosition(), 20u);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(20, 20));
+
+  // After undo, the cursor and selected range should reflect the state prior to
+  // the edit, even if that differs than the state after the current (1st) edit.
+  textfield_->InsertOrReplaceText(ASCIIToUTF16("xyz"));  // (2')nd edit
+  SendKeyEvent(ui::VKEY_Z, false, true);                 // Undo (2')nd edit
+  EXPECT_EQ(textfield_->GetCursorPosition(), 20u);
+  EXPECT_EQ(textfield_->GetSelectedRange(), gfx::Range(20, 20));
 }
 
 TEST_F(TextfieldTest, KeyTest) {
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java b/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java
index 20b67a5..e627c844 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/TranslateCompactInfoBar.java
@@ -549,9 +549,8 @@
         return mParent != null ? mParent.getWidth() : 0;
     }
 
-    @CalledByNative
     // Selects the tab corresponding to |actionType| to simulate the user pressing on this tab.
-    private void selectTabForTesting(int actionType) {
+    void selectTabForTesting(int actionType) {
         if (actionType == ActionType.TRANSLATE) {
             mTabLayout.getTabAt(TARGET_TAB_INDEX).select();
         } else if (actionType == ActionType.TRANSLATE_SHOW_ORIGINAL) {
@@ -561,18 +560,6 @@
         }
     }
 
-    @CalledByNative
-    // Simulates a click of the overflow menu item for "never translate this language."
-    private void clickNeverTranslateLanguageMenuItemForTesting() {
-        onOverflowMenuItemClicked(TranslateMenu.ID_OVERFLOW_NEVER_LANGUAGE);
-    }
-
-    @CalledByNative
-    // Simulates a click of the overflow menu item for "never translate this site."
-    private void clickNeverTranslateSiteMenuItemForTesting() {
-        onOverflowMenuItemClicked(TranslateMenu.ID_OVERFLOW_NEVER_SITE);
-    }
-
     @NativeMethods
     interface Natives {
         void applyStringTranslateOption(long nativeTranslateCompactInfoBar,
diff --git a/weblayer/browser/translate_browsertest.cc b/weblayer/browser/translate_browsertest.cc
index 17f7a517..5f2a2bd1 100644
--- a/weblayer/browser/translate_browsertest.cc
+++ b/weblayer/browser/translate_browsertest.cc
@@ -27,6 +27,7 @@
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "weblayer/browser/infobar_service.h"
 #include "weblayer/browser/translate_compact_infobar.h"
+#include "weblayer/shell/android/browsertests_apk/translate_test_bridge.h"
 #endif
 
 namespace weblayer {
@@ -520,8 +521,8 @@
   // occurs.
   auto* infobar =
       static_cast<TranslateCompactInfoBar*>(infobar_service->infobar_at(0));
-  infobar->SelectButtonForTesting(
-      infobars::InfoBarAndroid::ActionType::ACTION_TRANSLATE);
+  TranslateTestBridge::SelectButton(
+      infobar, infobars::InfoBarAndroid::ActionType::ACTION_TRANSLATE);
 
   WaitUntilPageTranslated(shell());
 
@@ -539,7 +540,8 @@
 
   // Revert to the source language via the Java infobar and ensure that the
   // translation is undone.
-  infobar->SelectButtonForTesting(
+  TranslateTestBridge::SelectButton(
+      infobar,
       infobars::InfoBarAndroid::ActionType::ACTION_TRANSLATE_SHOW_ORIGINAL);
 
   translate_reversion_waiter->Wait();
@@ -588,8 +590,9 @@
 
   auto* infobar =
       static_cast<TranslateCompactInfoBar*>(infobar_service->infobar_at(0));
-  infobar->ClickOverflowMenuItemForTesting(
-      TranslateCompactInfoBar::OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE);
+  TranslateTestBridge::ClickOverflowMenuItem(
+      infobar,
+      TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE);
 
   // The translate infobar should still be present.
   EXPECT_EQ(1u, infobar_service->infobar_count());
@@ -658,8 +661,8 @@
 
   auto* infobar =
       static_cast<TranslateCompactInfoBar*>(infobar_service->infobar_at(0));
-  infobar->ClickOverflowMenuItemForTesting(
-      TranslateCompactInfoBar::OverflowMenuItemId::NEVER_TRANSLATE_SITE);
+  TranslateTestBridge::ClickOverflowMenuItem(
+      infobar, TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_SITE);
 
   // The translate infobar should still be present.
   EXPECT_EQ(1u, infobar_service->infobar_count());
@@ -690,7 +693,7 @@
 class NeverTranslateMenuItemTranslateBrowserTest
     : public TranslateBrowserTest,
       public testing::WithParamInterface<
-          TranslateCompactInfoBar::OverflowMenuItemId> {};
+          TranslateTestBridge::OverflowMenuItemId> {};
 
 // Test that clicking and unclicking a never translate item ends up being a
 // no-op.
@@ -726,12 +729,12 @@
 
     auto* infobar =
         static_cast<TranslateCompactInfoBar*>(infobar_service->infobar_at(0));
-    infobar->ClickOverflowMenuItemForTesting(GetParam());
+    TranslateTestBridge::ClickOverflowMenuItem(infobar, GetParam());
 
     // The translate infobar should still be present.
     EXPECT_EQ(1u, infobar_service->infobar_count());
 
-    infobar->ClickOverflowMenuItemForTesting(GetParam());
+    TranslateTestBridge::ClickOverflowMenuItem(infobar, GetParam());
   }
 
   // The infobar should be shown on a new navigation to a page in the same
@@ -769,8 +772,8 @@
     All,
     NeverTranslateMenuItemTranslateBrowserTest,
     ::testing::Values(
-        TranslateCompactInfoBar::OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE,
-        TranslateCompactInfoBar::OverflowMenuItemId::NEVER_TRANSLATE_SITE));
+        TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE,
+        TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_SITE));
 
 #endif  // #if defined(OS_ANDROID)
 
diff --git a/weblayer/browser/translate_compact_infobar.cc b/weblayer/browser/translate_compact_infobar.cc
index 31d1c36b..63b18f4 100644
--- a/weblayer/browser/translate_compact_infobar.cc
+++ b/weblayer/browser/translate_compact_infobar.cc
@@ -227,25 +227,4 @@
   GetDelegate()->RemoveObserver(this);
 }
 
-void TranslateCompactInfoBar::SelectButtonForTesting(ActionType action_type) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_TranslateCompactInfoBar_selectTabForTesting(env, GetJavaInfoBar(),
-                                                   action_type);
-}
-
-void TranslateCompactInfoBar::ClickOverflowMenuItemForTesting(
-    OverflowMenuItemId item_id) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  switch (item_id) {
-    case OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE:
-      Java_TranslateCompactInfoBar_clickNeverTranslateLanguageMenuItemForTesting(
-          env, GetJavaInfoBar());
-      return;
-    case OverflowMenuItemId::NEVER_TRANSLATE_SITE:
-      Java_TranslateCompactInfoBar_clickNeverTranslateSiteMenuItemForTesting(
-          env, GetJavaInfoBar());
-      return;
-  }
-}
-
 }  // namespace weblayer
diff --git a/weblayer/browser/translate_compact_infobar.h b/weblayer/browser/translate_compact_infobar.h
index ed4d9c2..2e85f5ba 100644
--- a/weblayer/browser/translate_compact_infobar.h
+++ b/weblayer/browser/translate_compact_infobar.h
@@ -26,11 +26,6 @@
       std::unique_ptr<translate::TranslateInfoBarDelegate> delegate);
   ~TranslateCompactInfoBar() override;
 
-  enum class OverflowMenuItemId {
-    NEVER_TRANSLATE_LANGUAGE = 0,
-    NEVER_TRANSLATE_SITE = 1,
-  };
-
   // JNI method specific to string settings in translate.
   void ApplyStringTranslateOption(
       JNIEnv* env,
@@ -65,13 +60,6 @@
   void OnTranslateInfoBarDelegateDestroyed(
       translate::TranslateInfoBarDelegate* delegate) override;
 
-  // Instructs the Java infobar to select the button corresponding to
-  // |action_type|.
-  void SelectButtonForTesting(ActionType action_type);
-
-  // Instructs the Java infobar to click the specified overflow menu item.
-  void ClickOverflowMenuItemForTesting(OverflowMenuItemId item_id);
-
  private:
   // infobars::InfoBarAndroid:
   base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
diff --git a/weblayer/shell/android/browsertests_apk/DEPS b/weblayer/shell/android/browsertests_apk/DEPS
index 79cf7b1..24d5411 100644
--- a/weblayer/shell/android/browsertests_apk/DEPS
+++ b/weblayer/shell/android/browsertests_apk/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+components/embedder_support",
   "+components/metrics",
+  "+components/translate/content/android",
   "+content/public/android",
   "+content/public/app",
   "+content/public/test",
diff --git a/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_private/TranslateTestBridge.java b/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_private/TranslateTestBridge.java
new file mode 100644
index 0000000..5197d4d
--- /dev/null
+++ b/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_private/TranslateTestBridge.java
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.weblayer_private;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.components.translate.TranslateMenu;
+
+/**
+ * Bridge for TranslateCompactInfoBar test methods invoked from native.
+ */
+@JNINamespace("weblayer")
+public class TranslateTestBridge {
+    TranslateTestBridge() {}
+
+    // Selects the tab corresponding to |actionType| to simulate the user pressing on this tab.
+    @CalledByNative
+    private static void selectTab(TranslateCompactInfoBar infobar, int actionType) {
+        infobar.selectTabForTesting(actionType);
+    }
+
+    @CalledByNative
+    // Simulates a click of the overflow menu item for "never translate this language."
+    private static void clickNeverTranslateLanguageMenuItem(TranslateCompactInfoBar infobar) {
+        infobar.onOverflowMenuItemClicked(TranslateMenu.ID_OVERFLOW_NEVER_LANGUAGE);
+    }
+
+    @CalledByNative
+    // Simulates a click of the overflow menu item for "never translate this site."
+    private static void clickNeverTranslateSiteMenuItem(TranslateCompactInfoBar infobar) {
+        infobar.onOverflowMenuItemClicked(TranslateMenu.ID_OVERFLOW_NEVER_SITE);
+    }
+}
diff --git a/weblayer/shell/android/browsertests_apk/translate_test_bridge.cc b/weblayer/shell/android/browsertests_apk/translate_test_bridge.cc
new file mode 100644
index 0000000..638d5ac67
--- /dev/null
+++ b/weblayer/shell/android/browsertests_apk/translate_test_bridge.cc
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "weblayer/shell/android/browsertests_apk/translate_test_bridge.h"
+
+#include "base/android/jni_android.h"
+#include "weblayer/test/weblayer_browsertests_jni/TranslateTestBridge_jni.h"
+
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
+namespace weblayer {
+
+// static
+void TranslateTestBridge::SelectButton(
+    TranslateCompactInfoBar* infobar,
+    TranslateCompactInfoBar::ActionType action_type) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_TranslateTestBridge_selectTab(env, infobar->GetJavaInfoBar(),
+                                     action_type);
+}
+
+// static
+void TranslateTestBridge::ClickOverflowMenuItem(
+    TranslateCompactInfoBar* infobar,
+    OverflowMenuItemId item_id) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  switch (item_id) {
+    case OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE:
+      Java_TranslateTestBridge_clickNeverTranslateLanguageMenuItem(
+          env, infobar->GetJavaInfoBar());
+      return;
+    case OverflowMenuItemId::NEVER_TRANSLATE_SITE:
+      Java_TranslateTestBridge_clickNeverTranslateSiteMenuItem(
+          env, infobar->GetJavaInfoBar());
+      return;
+  }
+}
+
+}  // namespace weblayer
diff --git a/weblayer/shell/android/browsertests_apk/translate_test_bridge.h b/weblayer/shell/android/browsertests_apk/translate_test_bridge.h
new file mode 100644
index 0000000..cbc4615
--- /dev/null
+++ b/weblayer/shell/android/browsertests_apk/translate_test_bridge.h
@@ -0,0 +1,38 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBLAYER_SHELL_ANDROID_BROWSERTESTS_APK_TRANSLATE_TEST_BRIDGE_H_
+#define WEBLAYER_SHELL_ANDROID_BROWSERTESTS_APK_TRANSLATE_TEST_BRIDGE_H_
+
+#include "weblayer/browser/translate_compact_infobar.h"
+
+namespace weblayer {
+
+// Bridge to support translate_browsertest.cc to calling into Java.
+class TranslateTestBridge {
+ public:
+  TranslateTestBridge();
+  ~TranslateTestBridge();
+
+  TranslateTestBridge(const TranslateTestBridge&) = delete;
+  TranslateTestBridge& operator=(const TranslateTestBridge&) = delete;
+
+  enum class OverflowMenuItemId {
+    NEVER_TRANSLATE_LANGUAGE = 0,
+    NEVER_TRANSLATE_SITE = 1,
+  };
+
+  // Instructs the Java infobar to select the button corresponding to
+  // |action_type|.
+  static void SelectButton(TranslateCompactInfoBar* infobar,
+                           TranslateCompactInfoBar::ActionType action_type);
+
+  // Instructs the Java infobar to click the specified overflow menu item.
+  static void ClickOverflowMenuItem(TranslateCompactInfoBar* infobar,
+                                    OverflowMenuItemId item_id);
+};
+
+}  // namespace weblayer
+
+#endif  // WEBLAYER_SHELL_ANDROID_BROWSERTESTS_APK_TRANSLATE_TEST_BRIDGE_H_
diff --git a/weblayer/test/BUILD.gn b/weblayer/test/BUILD.gn
index 2801d630..66d84cf 100644
--- a/weblayer/test/BUILD.gn
+++ b/weblayer/test/BUILD.gn
@@ -27,6 +27,7 @@
       "../shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java",
       "../shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsApplication.java",
       "../shell/android/browsertests_apk/src/org/chromium/weblayer_private/MetricsTestHelper.java",
+      "../shell/android/browsertests_apk/src/org/chromium/weblayer_private/TranslateTestBridge.java",
     ]
     deps = [
       ":weblayer_browsertests_jni",
@@ -36,6 +37,7 @@
       "//base:jni_java",
       "//components/embedder_support/android:application_java",
       "//components/safe_browsing/android:safe_browsing_java",
+      "//components/translate/content/android:java",
       "//content/public/android:content_java",
       "//content/public/test/android:content_java_test_support",
       "//testing/android/native_test:native_test_java",
@@ -51,7 +53,10 @@
   }
 
   generate_jni("weblayer_browsertests_jni") {
-    sources = [ "../shell/android/browsertests_apk/src/org/chromium/weblayer_private/MetricsTestHelper.java" ]
+    sources = [
+      "../shell/android/browsertests_apk/src/org/chromium/weblayer_private/MetricsTestHelper.java",
+      "../shell/android/browsertests_apk/src/org/chromium/weblayer_private/TranslateTestBridge.java",
+    ]
   }
 
   android_assets("weblayer_test_assets") {
@@ -159,6 +164,8 @@
       "../shell/android/browsertests_apk/metrics_browsertest.cc",
       "../shell/android/browsertests_apk/metrics_test_helper.cc",
       "../shell/android/browsertests_apk/metrics_test_helper.h",
+      "../shell/android/browsertests_apk/translate_test_bridge.cc",
+      "../shell/android/browsertests_apk/translate_test_bridge.h",
       "../shell/android/browsertests_apk/weblayer_browser_tests_jni_onload.cc",
     ]
     deps += [