diff --git a/DEPS b/DEPS
index 73e06bf..ee1ef0a 100644
--- a/DEPS
+++ b/DEPS
@@ -79,11 +79,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': 'e168c3e8f9a13472983a567ecd679226c9d0d186',
+  'skia_revision': '3ba3fa72ae2fd4102cff22b947d124f72ce0f880',
   # 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': '4918c096158e63a0d264b0a2b0fcbebae44a2207',
+  'v8_revision': '030cf69a95f91d45843ea7ad2f2a1139f15ac68a',
   # 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.
@@ -91,7 +91,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': '3c424b489c25552878a52c0fcb5305618221708e',
+  'angle_revision': '0e99b7a3bc8b474cba091ef65bb53264e6384ce2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -103,7 +103,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': '5ca283f376816522065c0ea35644fcb684f9572f',
+  'pdfium_revision': '1fa1b1f771dd077b0fb4056c7b84f701ba733a8c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -135,7 +135,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': 'c4b36e2d9b77e6ae89274fa33a982f8efea1b948',
+  'catapult_revision': '0a20f3ce6c4d6802892cbaa7489cde394eaa6fac',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -649,7 +649,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd458ada06171a85af00367251a4ed55db7fe2018',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '58daf40bad33535ea1e931c9fc6ed409aee3e865', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + '393e2664703351833948a30802e50d4ce101662a', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java
index cea82bc..ab0f33e 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java
@@ -4,14 +4,13 @@
 
 package org.chromium.android_webview.shell;
 
+import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.CommandLine;
-import org.chromium.content.app.ContentApplication;
 
 /**
  * The android_webview shell Application subclass.
  */
-public class AwShellApplication extends ContentApplication {
-
+public class AwShellApplication extends BaseChromiumApplication {
     public void initCommandLine() {
         if (!CommandLine.isInitialized()) {
             CommandLine.initFromFile("/data/local/tmp/android-webview-command-line");
diff --git a/base/allocator/partition_allocator/spin_lock.cc b/base/allocator/partition_allocator/spin_lock.cc
index c30d6cd..fd062c3 100644
--- a/base/allocator/partition_allocator/spin_lock.cc
+++ b/base/allocator/partition_allocator/spin_lock.cc
@@ -10,6 +10,8 @@
 #include <sched.h>
 #endif
 
+#include "base/threading/platform_thread.h"
+
 // The YIELD_PROCESSOR macro wraps an architecture specific-instruction that
 // informs the processor we're in a busy wait, so it can handle the branch more
 // intelligently and e.g. reduce power to our core or give more resources to the
@@ -67,6 +69,9 @@
   // critical section defaults, and various other recommendations.
   // TODO(jschuh): Further tuning may be warranted.
   static const int kYieldProcessorTries = 1000;
+  // The value of |kYieldThreadTries| is completely made up.
+  static const int kYieldThreadTries = 10;
+  int yield_thread_count = 0;
   do {
     do {
       for (int count = 0; count < kYieldProcessorTries; ++count) {
@@ -77,8 +82,17 @@
           return;
       }
 
-      // Give the OS a chance to schedule something on this core.
-      YIELD_THREAD;
+      if (yield_thread_count < kYieldThreadTries) {
+        ++yield_thread_count;
+        // Give the OS a chance to schedule something on this core.
+        YIELD_THREAD;
+      } else {
+        // At this point, it's likely that the lock is held by a lower priority
+        // thread that is unavailable to finish its work because of higher
+        // priority threads spinning here. Sleeping should ensure that they make
+        // progress.
+        PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
+      }
     } while (lock_.load(std::memory_order_relaxed));
   } while (UNLIKELY(lock_.exchange(true, std::memory_order_acquire)));
 }
diff --git a/base/debug/activity_tracker.cc b/base/debug/activity_tracker.cc
index 1b3aaeec..99dcdb8 100644
--- a/base/debug/activity_tracker.cc
+++ b/base/debug/activity_tracker.cc
@@ -1457,12 +1457,12 @@
     ProcessId process_id,
     const FilePath::StringType& exe,
     const FilePath::StringType& args) {
-  const int64_t pid = process_id;
   if (exe.find(FILE_PATH_LITERAL(" "))) {
-    RecordProcessLaunch(pid, FilePath::StringType(FILE_PATH_LITERAL("\"")) +
-                                 exe + FILE_PATH_LITERAL("\" ") + args);
+    RecordProcessLaunch(process_id,
+                        FilePath::StringType(FILE_PATH_LITERAL("\"")) + exe +
+                            FILE_PATH_LITERAL("\" ") + args);
   } else {
-    RecordProcessLaunch(pid, exe + FILE_PATH_LITERAL(' ') + args);
+    RecordProcessLaunch(process_id, exe + FILE_PATH_LITERAL(' ') + args);
   }
 }
 
diff --git a/base/strings/pattern.cc b/base/strings/pattern.cc
index 5a0a055..c1abf5d 100644
--- a/base/strings/pattern.cc
+++ b/base/strings/pattern.cc
@@ -10,126 +10,114 @@
 
 namespace {
 
-static bool IsWildcard(base_icu::UChar32 character) {
+bool IsWildcard(base_icu::UChar32 character) {
   return character == '*' || character == '?';
 }
 
-// Move the strings pointers to the point where they start to differ.
+// Searches for the next subpattern of |pattern| in |string|, up to the given
+// |maximum_distance|. The subpattern extends from the start of |pattern| up to
+// the first wildcard character (or the end of the string). If the value of
+// |maximum_distance| is negative, the maximum distance is considered infinite.
 template <typename CHAR, typename NEXT>
-static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end,
-                         const CHAR** string, const CHAR* string_end,
-                         NEXT next) {
-  const CHAR* escape = nullptr;
-  while (*pattern != pattern_end && *string != string_end) {
-    if (!escape && IsWildcard(**pattern)) {
-      // We don't want to match wildcard here, except if it's escaped.
-      return;
-    }
-
-    // Check if the escapement char is found. If so, skip it and move to the
-    // next character.
-    if (!escape && **pattern == '\\') {
-      escape = *pattern;
-      next(pattern, pattern_end);
-      continue;
-    }
-
-    // Check if the chars match, if so, increment the ptrs.
-    const CHAR* pattern_next = *pattern;
-    const CHAR* string_next = *string;
-    base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
-    if (pattern_char == next(&string_next, string_end) &&
-        pattern_char != CBU_SENTINEL) {
-      *pattern = pattern_next;
-      *string = string_next;
+bool SearchForChars(const CHAR** pattern,
+                    const CHAR* pattern_end,
+                    const CHAR** string,
+                    const CHAR* string_end,
+                    int maximum_distance,
+                    NEXT next) {
+  const CHAR* pattern_start = *pattern;
+  const CHAR* string_start = *string;
+  bool escape = false;
+  while (true) {
+    if (*pattern == pattern_end) {
+      // If this is the end of the pattern, only accept the end of the string;
+      // anything else falls through to the mismatch case.
+      if (*string == string_end)
+        return true;
     } else {
-      // Uh oh, it did not match, we are done. If the last char was an
-      // escapement, that means that it was an error to advance the ptr here,
-      // let's put it back where it was. This also mean that the MatchPattern
-      // function will return false because if we can't match an escape char
-      // here, then no one will.
-      if (escape) {
-        *pattern = escape;
+      // If we have found a wildcard, we're done.
+      if (!escape && IsWildcard(**pattern))
+        return true;
+
+      // Check if the escape character is found. If so, skip it and move to the
+      // next character.
+      if (!escape && **pattern == '\\') {
+        escape = true;
+        next(pattern, pattern_end);
+        continue;
       }
-      return;
+
+      escape = false;
+
+      if (*string == string_end)
+        return false;
+
+      // Check if the chars match, if so, increment the ptrs.
+      const CHAR* pattern_next = *pattern;
+      const CHAR* string_next = *string;
+      base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
+      if (pattern_char == next(&string_next, string_end) &&
+          pattern_char != CBU_SENTINEL) {
+        *pattern = pattern_next;
+        *string = string_next;
+        continue;
+      }
     }
 
-    escape = nullptr;
+    // Mismatch. If we have reached the maximum distance, return false,
+    // otherwise restart at the beginning of the pattern with the next character
+    // in the string.
+    // TODO(bauerb): This is a naive implementation of substring search, which
+    // could be implemented with a more efficient algorithm, e.g.
+    // Knuth-Morris-Pratt (at the expense of requiring preprocessing).
+    if (maximum_distance == 0)
+      return false;
+
+    // Because unlimited distance is represented as -1, this will never reach 0
+    // and therefore fail the match above.
+    maximum_distance--;
+    *pattern = pattern_start;
+    next(&string_start, string_end);
+    *string = string_start;
   }
 }
 
+// Consumes consecutive wildcard characters (? or *). Returns the maximum number
+// of characters matched by the sequence of wildcards, or -1 if the wildcards
+// match an arbitrary number of characters (which is the case if it contains at
+// least one *).
 template <typename CHAR, typename NEXT>
-static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
+int EatWildcards(const CHAR** pattern, const CHAR* end, NEXT next) {
+  int num_question_marks = 0;
+  bool has_asterisk = false;
   while (*pattern != end) {
-    if (!IsWildcard(**pattern))
-      return;
+    if (**pattern == '?') {
+      num_question_marks++;
+    } else if (**pattern == '*') {
+      has_asterisk = true;
+    } else {
+      break;
+    }
+
     next(pattern, end);
   }
+  return has_asterisk ? -1 : num_question_marks;
 }
 
 template <typename CHAR, typename NEXT>
-static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end,
-                          const CHAR* pattern, const CHAR* pattern_end,
-                          int depth,
-                          NEXT next) {
-  const int kMaxDepth = 16;
-  if (depth > kMaxDepth)
-    return false;
-
-  // Eat all the matching chars.
-  EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
-
-  // If the string is empty, then the pattern must be empty too, or contains
-  // only wildcards.
-  if (eval == eval_end) {
-    EatWildcard(&pattern, pattern_end, next);
-    return pattern == pattern_end;
-  }
-
-  // Pattern is empty but not string, this is not a match.
-  if (pattern == pattern_end)
-    return false;
-
-  // If this is a question mark, then we need to compare the rest with
-  // the current string or the string with one character eaten.
-  const CHAR* next_pattern = pattern;
-  next(&next_pattern, pattern_end);
-  if (pattern[0] == '?') {
-    if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
-                      depth + 1, next))
-      return true;
-    const CHAR* next_eval = eval;
-    next(&next_eval, eval_end);
-    if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end,
-                      depth + 1, next))
-      return true;
-  }
-
-  // This is a *, try to match all the possible substrings with the remainder
-  // of the pattern.
-  if (pattern[0] == '*') {
-    // Collapse duplicate wild cards (********** into *) so that the
-    // method does not recurse unnecessarily. http://crbug.com/52839
-    EatWildcard(&next_pattern, pattern_end, next);
-
-    while (eval != eval_end) {
-      if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
-                        depth + 1, next))
-        return true;
-      eval++;
+bool MatchPatternT(const CHAR* eval,
+                   const CHAR* eval_end,
+                   const CHAR* pattern,
+                   const CHAR* pattern_end,
+                   NEXT next) {
+  do {
+    int maximum_wildcard_length = EatWildcards(&pattern, pattern_end, next);
+    if (!SearchForChars(&pattern, pattern_end, &eval, eval_end,
+                        maximum_wildcard_length, next)) {
+      return false;
     }
-
-    // We reached the end of the string, let see if the pattern contains only
-    // wildcards.
-    if (eval == eval_end) {
-      EatWildcard(&pattern, pattern_end, next);
-      if (pattern != pattern_end)
-        return false;
-      return true;
-    }
-  }
-
-  return false;
+  } while (pattern != pattern_end);
+  return true;
 }
 
 struct NextCharUTF8 {
@@ -155,15 +143,13 @@
 }  // namespace
 
 bool MatchPattern(StringPiece eval, StringPiece pattern) {
-  return MatchPatternT(eval.data(), eval.data() + eval.size(),
-                       pattern.data(), pattern.data() + pattern.size(),
-                       0, NextCharUTF8());
+  return MatchPatternT(eval.data(), eval.data() + eval.size(), pattern.data(),
+                       pattern.data() + pattern.size(), NextCharUTF8());
 }
 
 bool MatchPattern(StringPiece16 eval, StringPiece16 pattern) {
-  return MatchPatternT(eval.data(), eval.data() + eval.size(),
-                       pattern.data(), pattern.data() + pattern.size(),
-                       0, NextCharUTF16());
+  return MatchPatternT(eval.data(), eval.data() + eval.size(), pattern.data(),
+                       pattern.data() + pattern.size(), NextCharUTF16());
 }
 
 }  // namespace base
diff --git a/base/strings/pattern.h b/base/strings/pattern.h
index 15f96e2..b5172ab 100644
--- a/base/strings/pattern.h
+++ b/base/strings/pattern.h
@@ -10,11 +10,10 @@
 
 namespace base {
 
-// Returns true if the string passed in matches the pattern. The pattern
-// string can contain wildcards like * and ?
+// Returns true if the |string| passed in matches the |pattern|. The pattern
+// string can contain wildcards like * and ?.
 //
-// The backslash character (\) is an escape character for * and ?
-// We limit the patterns to having a max of 16 * or ? characters.
+// The backslash character (\) is an escape character for * and ?.
 // ? matches 0 or 1 character, while * matches 0 or more characters.
 BASE_EXPORT bool MatchPattern(StringPiece string, StringPiece pattern);
 BASE_EXPORT bool MatchPattern(StringPiece16 string, StringPiece16 pattern);
diff --git a/base/strings/pattern_unittest.cc b/base/strings/pattern_unittest.cc
index 9e82b3cb..8ec54954 100644
--- a/base/strings/pattern_unittest.cc
+++ b/base/strings/pattern_unittest.cc
@@ -22,8 +22,10 @@
   EXPECT_TRUE(MatchPattern("", ""));
   EXPECT_FALSE(MatchPattern("Hello", ""));
   EXPECT_TRUE(MatchPattern("Hello*", "Hello*"));
-  // Stop after a certain recursion depth.
-  EXPECT_FALSE(MatchPattern("123456789012345678", "?????????????????*"));
+  EXPECT_TRUE(MatchPattern("abcd", "*???"));
+  EXPECT_FALSE(MatchPattern("abcd", "???"));
+  EXPECT_TRUE(MatchPattern("abcb", "a*b"));
+  EXPECT_FALSE(MatchPattern("abcb", "a?b"));
 
   // Test UTF8 matching.
   EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0", "*\xe2\x99\xa0"));
@@ -40,11 +42,11 @@
   EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello*1234"),
                            UTF8ToUTF16("He??o\\*1*")));
 
-  // This test verifies that consecutive wild cards are collapsed into 1
-  // wildcard (when this doesn't occur, MatchPattern reaches it's maximum
-  // recursion depth).
-  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello"),
-                           UTF8ToUTF16("He********************************o")));
+  // Some test cases that might cause naive implementations to exhibit
+  // exponential run time or fail.
+  EXPECT_TRUE(MatchPattern("Hello", "He********************************o"));
+  EXPECT_TRUE(MatchPattern("123456789012345678", "?????????????????*"));
+  EXPECT_TRUE(MatchPattern("aaaaaaaaaaab", "a*a*a*a*a*a*a*a*a*a*a*b"));
 }
 
 }  // namespace base
diff --git a/base/win/windows_types.h b/base/win/windows_types.h
index 091e47f..8060f03 100644
--- a/base/win/windows_types.h
+++ b/base/win/windows_types.h
@@ -78,6 +78,7 @@
 CHROME_DECLARE_HANDLE(HICON);
 CHROME_DECLARE_HANDLE(HINSTANCE);
 CHROME_DECLARE_HANDLE(HKEY);
+CHROME_DECLARE_HANDLE(HKL);
 CHROME_DECLARE_HANDLE(HMENU);
 CHROME_DECLARE_HANDLE(HWND);
 typedef HINSTANCE HMODULE;
@@ -102,6 +103,7 @@
 
 typedef struct tagMENUITEMINFOW MENUITEMINFOW, MENUITEMINFO;
 
+typedef struct tagNMHDR NMHDR;
 
 // Declare Chrome versions of some Windows structures. These are needed for
 // when we need a concrete type but don't want to pull in Windows.h. We can't
diff --git a/build/android/gyp/dist_aar.py b/build/android/gyp/dist_aar.py
index 51515fa..6dc38c4 100755
--- a/build/android/gyp/dist_aar.py
+++ b/build/android/gyp/dist_aar.py
@@ -72,13 +72,23 @@
       '--android-manifest',
       help='Path to AndroidManifest.xml to include.',
       default=os.path.join(_ANDROID_BUILD_DIR, 'AndroidManifest.xml'))
+  parser.add_argument('--native-libraries', default='',
+                      help='GN list of native libraries. If non-empty then '
+                      'ABI must be specified.')
+  parser.add_argument('--abi',
+                      help='ABI (e.g. armeabi-v7a) for native libraries.')
 
   options = parser.parse_args(args)
+
+  if options.native_libraries and not options.abi:
+    parser.error('You must provide --abi if you have native libs')
+
   options.jars = build_utils.ParseGnList(options.jars)
   options.dependencies_res_zips = build_utils.ParseGnList(
       options.dependencies_res_zips)
   options.r_text_files = build_utils.ParseGnList(options.r_text_files)
   options.proguard_configs = build_utils.ParseGnList(options.proguard_configs)
+  options.native_libraries = build_utils.ParseGnList(options.native_libraries)
 
   with tempfile.NamedTemporaryFile(delete=False) as staging_file:
     try:
@@ -100,6 +110,12 @@
               data=_MergeProguardConfigs(options.proguard_configs))
 
         _AddResources(z, options.dependencies_res_zips)
+
+        for native_library in options.native_libraries:
+          libname = os.path.basename(native_library)
+          build_utils.AddToZipHermetic(
+              z, os.path.join('jni', options.abi, libname),
+              src_path=native_library)
     except:
       os.unlink(staging_file.name)
       raise
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
index 79815a83..79e47e1 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -35,8 +35,22 @@
   'NarrowingCompoundAssignment',
   # TODO(crbug.com/802073): Follow steps in bug.
   'TypeParameterUnusedInFormals',
-  # TODO(crbug.com/802075): Follow steps in bug
+  # TODO(crbug.com/802075): Follow steps in bug.
   'ReferenceEquality',
+  # TODO(crbug.com/803482): Follow steps in bug.
+  'UseCorrectAssertInTests',
+  # TODO(crbug.com/803484): Follow steps in bug.
+  'CatchFail',
+  # TODO(crbug.com/803485): Follow steps in bug.
+  'JUnitAmbiguousTestClass',
+  # TODO(crbug.com/803486): Follow steps in bug.
+  'AssertionFailureIgnored',
+  # TODO(crbug.com/803587): Follow steps in bug.
+  'MissingOverride',
+  # TODO(crbug.com/803589): Follow steps in bug.
+  'MissingFail',
+  # TODO(crbug.com/803625): Follow steps in bug.
+  'StaticGuardedByInstance',
   # Android platform default is always UTF-8.
   # https://developer.android.com/reference/java/nio/charset/Charset.html#defaultCharset()
   'DefaultCharset',
@@ -78,6 +92,14 @@
   'TypeParameterShadowing',
   # Good to have immutable enums, also low priority.
   'ImmutableEnumChecker',
+  # False positives for testing.
+  'InputStreamSlowMultibyteRead',
+  # Nice to have better primitives.
+  'BoxedPrimitiveConstructor',
+  # Not necessary for tests.
+  'OverrideThrowableToString',
+  # Nice to have better type safety.
+  'CollectionToArraySafeParameter',
 ]
 
 ERRORPRONE_WARNINGS_TO_ERROR = [
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 33ea74a..06b0968 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1480,6 +1480,7 @@
   # Currently supports:
   #   * AndroidManifest.xml
   #   * classes.jar
+  #   * jni/
   #   * res/
   #   * R.txt
   #   * proguard.txt
@@ -1487,13 +1488,13 @@
   #   * public.txt
   #   * annotations.zip
   #   * assets/
-  #   * jni/
   # See: https://developer.android.com/studio/projects/android-library.html#aar-contents
   #
   # Variables:
   #   output: Path to the output .aar.
   #   proguard_configs: List of proguard configs (optional).
   #   android_manifest: Path to AndroidManifest.xml (optional).
+  #   native_libraries: list of native libraries (optional).
   #
   # Example
   #   dist_aar("my_aar") {
@@ -1554,6 +1555,16 @@
           rebase_path(invoker.android_manifest, root_build_dir),
         ]
       }
+      if (defined(invoker.native_libraries) && invoker.native_libraries != []) {
+        inputs += invoker.native_libraries
+        _rebased_native_libraries =
+            rebase_path(invoker.native_libraries, root_build_dir)
+
+        args += [
+          "--native-libraries=$_rebased_native_libraries",
+          "--abi=$android_app_abi",
+        ]
+      }
     }
   }
 
diff --git a/cc/ipc/cc_param_traits_macros.h b/cc/ipc/cc_param_traits_macros.h
index ae5ae805..afc513e 100644
--- a/cc/ipc/cc_param_traits_macros.h
+++ b/cc/ipc/cc_param_traits_macros.h
@@ -24,7 +24,6 @@
 #include "components/viz/common/resources/transferable_resource.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "ui/gfx/ipc/buffer_types/gfx_param_traits.h"
 #include "ui/gfx/ipc/color/gfx_param_traits.h"
 #include "ui/gfx/ipc/gfx_param_traits.h"
@@ -45,11 +44,6 @@
 // TODO(fsamuel): This trait belongs with skia code.
 IPC_ENUM_TRAITS_MAX_VALUE(SkBlendMode, SkBlendMode::kLastMode)
 
-IPC_STRUCT_TRAITS_BEGIN(viz::SurfaceSequence)
-  IPC_STRUCT_TRAITS_MEMBER(frame_sink_id)
-  IPC_STRUCT_TRAITS_MEMBER(sequence)
-IPC_STRUCT_TRAITS_END()
-
 IPC_STRUCT_TRAITS_BEGIN(viz::DrawQuad)
   IPC_STRUCT_TRAITS_MEMBER(material)
   IPC_STRUCT_TRAITS_MEMBER(rect)
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc
index 018af160..2b7b759 100644
--- a/cc/layers/surface_layer.cc
+++ b/cc/layers/surface_layer.cc
@@ -8,58 +8,17 @@
 
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/layers/surface_layer_impl.h"
 #include "cc/trees/layer_tree_host.h"
-#include "cc/trees/swap_promise.h"
-#include "cc/trees/swap_promise_manager.h"
-#include "cc/trees/task_runner_provider.h"
-#include "components/viz/common/surfaces/surface_sequence_generator.h"
 
 namespace cc {
 
-class SatisfySwapPromise : public SwapPromise {
- public:
-  SatisfySwapPromise(
-      base::Closure reference_returner,
-      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
-      : reference_returner_(reference_returner),
-        main_task_runner_(std::move(main_task_runner)) {}
-
-  ~SatisfySwapPromise() override = default;
-
- private:
-  void DidActivate() override {}
-
-  void WillSwap(viz::CompositorFrameMetadata* compositor_frame_metadata,
-                RenderFrameMetadata* render_frame_metadata) override {}
-
-  void DidSwap() override {
-    main_task_runner_->PostTask(FROM_HERE, reference_returner_);
-  }
-
-  DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
-    main_task_runner_->PostTask(FROM_HERE, reference_returner_);
-    return DidNotSwapAction::BREAK_PROMISE;
-  }
-
-  int64_t TraceId() const override { return 0; }
-
-  base::Closure reference_returner_;
-  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(SatisfySwapPromise);
-};
-
-scoped_refptr<SurfaceLayer> SurfaceLayer::Create(
-    scoped_refptr<viz::SurfaceReferenceFactory> ref_factory) {
-  return base::WrapRefCounted(new SurfaceLayer(std::move(ref_factory)));
+scoped_refptr<SurfaceLayer> SurfaceLayer::Create() {
+  return base::WrapRefCounted(new SurfaceLayer());
 }
 
-SurfaceLayer::SurfaceLayer(
-    scoped_refptr<viz::SurfaceReferenceFactory> ref_factory)
-    : ref_factory_(std::move(ref_factory)) {}
+SurfaceLayer::SurfaceLayer() = default;
 
 SurfaceLayer::~SurfaceLayer() {
   DCHECK(!layer_tree_host());
@@ -82,17 +41,14 @@
   if (fallback_surface_id_ == surface_id)
     return;
 
-  RemoveReference(std::move(fallback_reference_returner_));
   if (layer_tree_host())
     layer_tree_host()->RemoveSurfaceLayerId(fallback_surface_id_);
 
   fallback_surface_id_ = surface_id;
 
-  if (layer_tree_host() && fallback_surface_id_.is_valid()) {
-    fallback_reference_returner_ =
-        ref_factory_->CreateReference(layer_tree_host(), fallback_surface_id_);
+  if (layer_tree_host() && fallback_surface_id_.is_valid())
     layer_tree_host()->AddSurfaceLayerId(fallback_surface_id_);
-  }
+
   SetNeedsCommit();
 }
 
@@ -121,14 +77,10 @@
   if (layer_tree_host() && fallback_surface_id_.is_valid())
     layer_tree_host()->RemoveSurfaceLayerId(fallback_surface_id_);
 
-  RemoveReference(std::move(fallback_reference_returner_));
   Layer::SetLayerTreeHost(host);
 
-  if (layer_tree_host() && fallback_surface_id_.is_valid()) {
-    fallback_reference_returner_ =
-        ref_factory_->CreateReference(layer_tree_host(), fallback_surface_id_);
+  if (layer_tree_host() && fallback_surface_id_.is_valid())
     layer_tree_host()->AddSurfaceLayerId(fallback_surface_id_);
-  }
 }
 
 void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) {
@@ -142,14 +94,4 @@
   layer_impl->SetStretchContentToFillBounds(stretch_content_to_fill_bounds_);
 }
 
-void SurfaceLayer::RemoveReference(base::Closure reference_returner) {
-  if (!reference_returner)
-    return;
-  auto swap_promise = std::make_unique<SatisfySwapPromise>(
-      std::move(reference_returner),
-      layer_tree_host()->GetTaskRunnerProvider()->MainThreadTaskRunner());
-  layer_tree_host()->GetSwapPromiseManager()->QueueSwapPromise(
-      std::move(swap_promise));
-}
-
 }  // namespace cc
diff --git a/cc/layers/surface_layer.h b/cc/layers/surface_layer.h
index 0e084dd..a627a94 100644
--- a/cc/layers/surface_layer.h
+++ b/cc/layers/surface_layer.h
@@ -9,7 +9,6 @@
 #include "cc/cc_export.h"
 #include "cc/layers/layer.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/common/surfaces/surface_reference_factory.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -19,8 +18,7 @@
 // instance or client.
 class CC_EXPORT SurfaceLayer : public Layer {
  public:
-  static scoped_refptr<SurfaceLayer> Create(
-      scoped_refptr<viz::SurfaceReferenceFactory> ref_factory);
+  static scoped_refptr<SurfaceLayer> Create();
 
   void SetPrimarySurfaceId(const viz::SurfaceId& surface_id,
                            base::Optional<uint32_t> deadline_in_frames);
@@ -35,11 +33,6 @@
   void SetLayerTreeHost(LayerTreeHost* host) override;
   void PushPropertiesTo(LayerImpl* layer) override;
 
-  scoped_refptr<viz::SurfaceReferenceFactory> surface_reference_factory()
-      const {
-    return ref_factory_;
-  }
-
   const viz::SurfaceId& primary_surface_id() const {
     return primary_surface_id_;
   }
@@ -49,20 +42,16 @@
   }
 
  protected:
-  explicit SurfaceLayer(
-      scoped_refptr<viz::SurfaceReferenceFactory> ref_factory);
+  SurfaceLayer();
   bool HasDrawableContent() const override;
 
  private:
   ~SurfaceLayer() override;
-  void RemoveReference(base::Closure reference_returner);
 
   viz::SurfaceId primary_surface_id_;
   viz::SurfaceId fallback_surface_id_;
-  base::Closure fallback_reference_returner_;
   base::Optional<uint32_t> deadline_in_frames_;
 
-  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory_;
   bool stretch_content_to_fill_bounds_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(SurfaceLayer);
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc
index d32696cb..e5aacb6 100644
--- a/cc/layers/surface_layer_unittest.cc
+++ b/cc/layers/surface_layer_unittest.cc
@@ -24,7 +24,6 @@
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_host.h"
 #include "components/viz/common/quads/compositor_frame.h"
-#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_info.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -75,95 +74,10 @@
   FakeLayerTreeHostImpl host_impl_;
 };
 
-class MockSurfaceReferenceFactory
-    : public viz::SequenceSurfaceReferenceFactory {
- public:
-  MockSurfaceReferenceFactory() = default;
-
-  // SequenceSurfaceReferenceFactory implementation.
-  MOCK_CONST_METHOD1(SatisfySequence, void(const viz::SurfaceSequence&));
-  MOCK_CONST_METHOD2(RequireSequence,
-                     void(const viz::SurfaceId&, const viz::SurfaceSequence&));
-
- protected:
-  ~MockSurfaceReferenceFactory() override = default;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockSurfaceReferenceFactory);
-};
-
-// Check that one surface can be referenced by multiple LayerTreeHosts, and
-// each will create its own viz::SurfaceSequence that's satisfied on
-// destruction.
-TEST_F(SurfaceLayerTest, MultipleFramesOneSurface) {
-  const base::UnguessableToken kArbitraryToken =
-      base::UnguessableToken::Create();
-  const viz::SurfaceId surface_id(kArbitraryFrameSinkId,
-                                  viz::LocalSurfaceId(1, kArbitraryToken));
-  const viz::SurfaceSequence expected_seq1(viz::FrameSinkId(1, 1), 1u);
-  const viz::SurfaceSequence expected_seq2(viz::FrameSinkId(2, 2), 1u);
-  const viz::SurfaceId expected_id(kArbitraryFrameSinkId,
-                                   viz::LocalSurfaceId(1, kArbitraryToken));
-
-  scoped_refptr<MockSurfaceReferenceFactory> ref_factory =
-      new testing::StrictMock<MockSurfaceReferenceFactory>();
-
-  // We are going to set up the SurfaceLayers and LayerTreeHosts. Each layer
-  // will require a sequence and no sequence should be satisfied for now.
-  EXPECT_CALL(*ref_factory, RequireSequence(Eq(expected_id), Eq(expected_seq1)))
-      .Times(1);
-  EXPECT_CALL(*ref_factory, RequireSequence(Eq(expected_id), Eq(expected_seq2)))
-      .Times(1);
-  EXPECT_CALL(*ref_factory, SatisfySequence(_)).Times(0);
-
-  auto layer = SurfaceLayer::Create(ref_factory);
-  layer->SetPrimarySurfaceId(surface_id, base::nullopt);
-  layer->SetFallbackSurfaceId(surface_id);
-  layer_tree_host_->GetSurfaceSequenceGenerator()->set_frame_sink_id(
-      viz::FrameSinkId(1, 1));
-  layer_tree_host_->SetRootLayer(layer);
-
-  auto animation_host2 = AnimationHost::CreateForTesting(ThreadInstance::MAIN);
-  std::unique_ptr<FakeLayerTreeHost> layer_tree_host2 =
-      FakeLayerTreeHost::Create(&fake_client_, &task_graph_runner_,
-                                animation_host2.get());
-  auto layer2 = SurfaceLayer::Create(ref_factory);
-  layer2->SetPrimarySurfaceId(surface_id, base::nullopt);
-  layer2->SetFallbackSurfaceId(surface_id);
-  layer_tree_host2->GetSurfaceSequenceGenerator()->set_frame_sink_id(
-      viz::FrameSinkId(2, 2));
-  layer_tree_host2->SetRootLayer(layer2);
-
-  testing::Mock::VerifyAndClearExpectations(ref_factory.get());
-
-  // Destroy the second LayerTreeHost. The sequence generated by its
-  // SurfaceLayer must be satisfied and no new sequences must be required.
-  EXPECT_CALL(*ref_factory, SatisfySequence(Eq(expected_seq2))).Times(1);
-  layer_tree_host2->SetRootLayer(nullptr);
-  layer_tree_host2.reset();
-  animation_host2 = nullptr;
-  base::RunLoop().RunUntilIdle();
-  testing::Mock::VerifyAndClearExpectations(ref_factory.get());
-
-  // Destroy the first LayerTreeHost. The sequence generated by its
-  // SurfaceLayer must be satisfied and no new sequences must be required.
-  EXPECT_CALL(*ref_factory, SatisfySequence(expected_seq1)).Times(1);
-  EXPECT_CALL(*ref_factory, RequireSequence(_, _)).Times(0);
-  layer_tree_host_->SetRootLayer(nullptr);
-  layer_tree_host_.reset();
-  base::RunLoop().RunUntilIdle();
-  testing::Mock::VerifyAndClearExpectations(ref_factory.get());
-}
-
 // This test verifies that SurfaceLayer properties are pushed across to
 // SurfaceLayerImpl.
 TEST_F(SurfaceLayerTest, PushProperties) {
-  // We use a nice mock here because we are not really interested in calls to
-  // MockSurfaceReferenceFactory and we don't want warnings printed.
-  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory =
-      new testing::NiceMock<MockSurfaceReferenceFactory>();
-
-  scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create(ref_factory);
+  scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create();
   layer_tree_host_->SetRootLayer(layer);
   viz::SurfaceId primary_id(
       kArbitraryFrameSinkId,
@@ -229,25 +143,20 @@
 // surface layers. This emulates the flow of maximize and minimize animations on
 // Chrome OS.
 TEST_F(SurfaceLayerTest, CheckSurfaceReferencesForClonedLayer) {
-  // We use a nice mock here because we are not really interested in calls to
-  // MockSurfaceReferenceFactory and we don't want warnings printed.
-  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory =
-      new testing::NiceMock<MockSurfaceReferenceFactory>();
-
   const viz::SurfaceId old_surface_id(
       kArbitraryFrameSinkId,
       viz::LocalSurfaceId(1, base::UnguessableToken::Create()));
 
   // This layer will always contain the old surface id and will be deleted when
   // animation is done.
-  scoped_refptr<SurfaceLayer> layer1 = SurfaceLayer::Create(ref_factory);
+  scoped_refptr<SurfaceLayer> layer1 = SurfaceLayer::Create();
   layer1->SetLayerTreeHost(layer_tree_host_.get());
   layer1->SetPrimarySurfaceId(old_surface_id, base::nullopt);
   layer1->SetFallbackSurfaceId(old_surface_id);
 
   // This layer will eventually be switched be switched to show the new surface
   // id and will be retained when animation is done.
-  scoped_refptr<SurfaceLayer> layer2 = SurfaceLayer::Create(ref_factory);
+  scoped_refptr<SurfaceLayer> layer2 = SurfaceLayer::Create();
   layer2->SetLayerTreeHost(layer_tree_host_.get());
   layer2->SetPrimarySurfaceId(old_surface_id, base::nullopt);
   layer2->SetFallbackSurfaceId(old_surface_id);
@@ -297,16 +206,11 @@
 // This test verifies LayerTreeHost::needs_surface_ids_sync() is correct when
 // there are cloned surface layers.
 TEST_F(SurfaceLayerTest, CheckNeedsSurfaceIdsSyncForClonedLayers) {
-  // We use a nice mock here because we are not really interested in calls to
-  // MockSurfaceReferenceFactory and we don't want warnings printed.
-  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory =
-      new testing::NiceMock<MockSurfaceReferenceFactory>();
-
   const viz::SurfaceId surface_id(
       kArbitraryFrameSinkId,
       viz::LocalSurfaceId(1, base::UnguessableToken::Create()));
 
-  scoped_refptr<SurfaceLayer> layer1 = SurfaceLayer::Create(ref_factory);
+  scoped_refptr<SurfaceLayer> layer1 = SurfaceLayer::Create();
   layer1->SetLayerTreeHost(layer_tree_host_.get());
   layer1->SetPrimarySurfaceId(surface_id, base::nullopt);
   layer1->SetFallbackSurfaceId(surface_id);
@@ -324,7 +228,7 @@
   EXPECT_FALSE(layer_tree_host_->needs_surface_ids_sync());
 
   // Create the second layer that is a clone of the first.
-  scoped_refptr<SurfaceLayer> layer2 = SurfaceLayer::Create(ref_factory);
+  scoped_refptr<SurfaceLayer> layer2 = SurfaceLayer::Create();
   layer2->SetLayerTreeHost(layer_tree_host_.get());
   layer2->SetPrimarySurfaceId(surface_id, base::nullopt);
   layer2->SetFallbackSurfaceId(surface_id);
@@ -355,127 +259,5 @@
   EXPECT_THAT(layer_tree_host_->SurfaceLayerIds(), SizeIs(0));
 }
 
-// Check that viz::SurfaceSequence is sent through swap promise.
-class SurfaceLayerSwapPromise : public LayerTreeTest {
- public:
-  SurfaceLayerSwapPromise()
-      : commit_count_(0), sequence_was_satisfied_(false) {}
-
-  void BeginTest() override {
-    layer_tree_host()->GetSurfaceSequenceGenerator()->set_frame_sink_id(
-        viz::FrameSinkId(1, 1));
-    ref_factory_ = new testing::StrictMock<MockSurfaceReferenceFactory>();
-
-    // Create a SurfaceLayer but don't add it to the tree yet. No sequence
-    // should be required / satisfied.
-    EXPECT_CALL(*ref_factory_, SatisfySequence(_)).Times(0);
-    EXPECT_CALL(*ref_factory_, RequireSequence(_, _)).Times(0);
-    layer_ = SurfaceLayer::Create(ref_factory_);
-    viz::SurfaceId surface_id(kArbitraryFrameSinkId,
-                              viz::LocalSurfaceId(1, kArbitraryToken));
-    layer_->SetPrimarySurfaceId(surface_id, base::nullopt);
-    layer_->SetFallbackSurfaceId(surface_id);
-    testing::Mock::VerifyAndClearExpectations(ref_factory_.get());
-
-    // Add the layer to the tree. A sequence must be required.
-    viz::SurfaceSequence expected_seq(kArbitraryFrameSinkId, 1u);
-    viz::SurfaceId expected_id(kArbitraryFrameSinkId,
-                               viz::LocalSurfaceId(1, kArbitraryToken));
-    EXPECT_CALL(*ref_factory_, SatisfySequence(_)).Times(0);
-    EXPECT_CALL(*ref_factory_,
-                RequireSequence(Eq(expected_id), Eq(expected_seq)))
-        .Times(1);
-    layer_tree_host()->SetRootLayer(layer_);
-    testing::Mock::VerifyAndClearExpectations(ref_factory_.get());
-
-    // By the end of the test, the required sequence must be satisfied and no
-    // more sequence must be required.
-    EXPECT_CALL(*ref_factory_, SatisfySequence(Eq(expected_seq))).Times(1);
-    EXPECT_CALL(*ref_factory_, RequireSequence(_, _)).Times(0);
-
-    gfx::Size bounds(100, 100);
-    layer_tree_host()->SetViewportSize(bounds);
-
-    blank_layer_ = SolidColorLayer::Create();
-    blank_layer_->SetIsDrawable(true);
-    blank_layer_->SetBounds(gfx::Size(10, 10));
-
-    PostSetNeedsCommitToMainThread();
-  }
-
-  virtual void ChangeTree() = 0;
-
-  void DidCommitAndDrawFrame() override {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(&SurfaceLayerSwapPromise::ChangeTree,
-                                  base::Unretained(this)));
-  }
-
-  void AfterTest() override {}
-
- protected:
-  int commit_count_;
-  bool sequence_was_satisfied_;
-  scoped_refptr<SurfaceLayer> layer_;
-  scoped_refptr<Layer> blank_layer_;
-  scoped_refptr<MockSurfaceReferenceFactory> ref_factory_;
-
-  const base::UnguessableToken kArbitraryToken =
-      base::UnguessableToken::Create();
-};
-
-// Check that viz::SurfaceSequence is sent through swap promise.
-class SurfaceLayerSwapPromiseWithDraw : public SurfaceLayerSwapPromise {
- public:
-  void ChangeTree() override {
-    ++commit_count_;
-    switch (commit_count_) {
-      case 1:
-        // Remove SurfaceLayer from tree to cause SwapPromise to be created.
-        layer_tree_host()->SetRootLayer(blank_layer_);
-        break;
-      case 2:
-        EndTest();
-        break;
-      default:
-        NOTREACHED();
-        break;
-    }
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithDraw);
-
-// Check that viz::SurfaceSequence is sent through swap promise and resolved
-// when swap fails.
-class SurfaceLayerSwapPromiseWithoutDraw : public SurfaceLayerSwapPromise {
- public:
-  SurfaceLayerSwapPromiseWithoutDraw() : SurfaceLayerSwapPromise() {}
-
-  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-                                   LayerTreeHostImpl::FrameData* frame,
-                                   DrawResult draw_result) override {
-    return DRAW_ABORTED_MISSING_HIGH_RES_CONTENT;
-  }
-
-  void ChangeTree() override {
-    ++commit_count_;
-    switch (commit_count_) {
-      case 1:
-        // Remove SurfaceLayer from tree to cause SwapPromise to be created.
-        layer_tree_host()->SetRootLayer(blank_layer_);
-        break;
-      case 2:
-        layer_tree_host()->SetNeedsCommit();
-        break;
-      default:
-        EndTest();
-        break;
-    }
-  }
-};
-
-MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithoutDraw);
-
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 85872e62..ecab8f5 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -226,10 +226,6 @@
   return settings_;
 }
 
-void LayerTreeHost::SetFrameSinkId(const viz::FrameSinkId& frame_sink_id) {
-  surface_sequence_generator_.set_frame_sink_id(frame_sink_id);
-}
-
 void LayerTreeHost::QueueSwapPromise(
     std::unique_ptr<SwapPromise> swap_promise) {
   swap_promise_manager_.QueueSwapPromise(std::move(swap_promise));
@@ -243,10 +239,6 @@
     SetNeedsAnimate();
 }
 
-viz::SurfaceSequenceGenerator* LayerTreeHost::GetSurfaceSequenceGenerator() {
-  return &surface_sequence_generator_;
-}
-
 void LayerTreeHost::WillBeginMainFrame() {
   inside_main_frame_ = true;
   devtools_instrumentation::WillBeginMainThreadFrame(GetId(),
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 600ac2b..77be794 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -44,8 +44,6 @@
 #include "cc/trees/swap_promise_manager.h"
 #include "cc/trees/target_property.h"
 #include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/surfaces/surface_reference_owner.h"
-#include "components/viz/common/surfaces/surface_sequence_generator.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/rect.h"
@@ -69,8 +67,7 @@
 struct RenderingStats;
 struct ScrollAndScaleSet;
 
-class CC_EXPORT LayerTreeHost : public viz::SurfaceReferenceOwner,
-                                public MutatorHostClient {
+class CC_EXPORT LayerTreeHost : public MutatorHostClient {
  public:
   struct CC_EXPORT InitParams {
     LayerTreeHostClient* client = nullptr;
@@ -98,7 +95,7 @@
       LayerTreeHostSingleThreadClient* single_thread_client,
       InitParams* params);
 
-  ~LayerTreeHost() override;
+  virtual ~LayerTreeHost();
 
   // Returns the process global unique identifier for this LayerTreeHost.
   int GetId() const;
@@ -118,10 +115,6 @@
   // Returns the settings used by this host.
   const LayerTreeSettings& GetSettings() const;
 
-  // Sets the client id used to generate the viz::SurfaceId that uniquely
-  // identifies the Surfaces produced by this compositor.
-  void SetFrameSinkId(const viz::FrameSinkId& frame_sink_id);
-
   // Sets the LayerTreeMutator interface used to directly mutate the compositor
   // state on the compositor thread. (Compositor-Worker)
   void SetLayerTreeMutator(std::unique_ptr<LayerTreeMutator> mutator);
@@ -481,9 +474,6 @@
   // are always already built and so cc doesn't have to build them.
   bool IsUsingLayerLists() const;
 
-  // viz::SurfaceReferenceOwner implementation.
-  viz::SurfaceSequenceGenerator* GetSurfaceSequenceGenerator() override;
-
   // MutatorHostClient implementation.
   bool IsElementInList(ElementId element_id,
                        ElementListType list_type) const override;
@@ -615,7 +605,6 @@
 
   TaskGraphRunner* task_graph_runner_;
 
-  viz::SurfaceSequenceGenerator surface_sequence_generator_;
   uint32_t num_consecutive_frames_without_slow_paths_ = 0;
 
   scoped_refptr<Layer> root_layer_;
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS
index 12478ec..44a304f 100644
--- a/chrome/android/java/DEPS
+++ b/chrome/android/java/DEPS
@@ -18,7 +18,6 @@
 
   "-content/public/android",
   "+content/public/android/java/src/org/chromium/content_public",
-  "!content/public/android/java/src/org/chromium/content/app/ContentApplication.java",
   "!content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java",
   "!content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibility.java",
   "!content/public/android/java/src/org/chromium/content/browser/ActivityContentVideoViewEmbedder.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
index 8105a3a..3f9e13b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -9,6 +9,7 @@
 
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
+import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.CommandLineInitUtil;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.DiscardableReferencePool;
@@ -29,14 +30,13 @@
 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModelSelector;
 import org.chromium.chrome.browser.tabmodel.document.StorageDelegate;
 import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
-import org.chromium.content.app.ContentApplication;
 
 /**
  * Basic application functionality that should be shared among all browser applications that use
  * chrome layer.
  */
 @MainDex
-public class ChromeApplication extends ContentApplication {
+public class ChromeApplication extends BaseChromiumApplication {
     public static final String COMMAND_LINE_FILE = "chrome-command-line";
     private static final String TAG = "ChromiumApplication";
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
index 8e62617..b305cd2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
@@ -33,8 +33,6 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.PasswordManagerHandler.PasswordListObserver;
-import org.chromium.chrome.browser.PasswordUIView;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.components.sync.AndroidSyncSettings;
@@ -207,7 +205,8 @@
 
     // Delete was clicked.
     private void removeItem() {
-        final PasswordListObserver passwordDeleter = new PasswordListObserver() {
+        final PasswordManagerHandler.PasswordListObserver
+                passwordDeleter = new PasswordManagerHandler.PasswordListObserver() {
             @Override
             public void passwordListAvailable(int count) {
                 if (!mException) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/PasswordManagerHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java
similarity index 80%
rename from chrome/android/java/src/org/chromium/chrome/browser/PasswordManagerHandler.java
rename to chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java
index 2860dd3..abbdbba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/PasswordManagerHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java
@@ -2,7 +2,7 @@
 // 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;
+package org.chromium.chrome.browser.preferences.password;
 
 import org.chromium.base.Callback;
 
@@ -15,7 +15,7 @@
      * An interface which a client can use to listen to changes to password and password exception
      * lists.
      */
-    public interface PasswordListObserver {
+    interface PasswordListObserver {
         /**
          * Called when passwords list is updated.
          * @param count Number of entries in the password list.
@@ -32,7 +32,7 @@
     /**
      * Called to start fetching password and exception lists.
      */
-    public void updatePasswordLists();
+    void updatePasswordLists();
 
     /**
      * Get the saved password entry at index.
@@ -40,7 +40,7 @@
      * @param index Index of Password.
      * @return SavedPasswordEntry at index.
      */
-    public SavedPasswordEntry getSavedPasswordEntry(int index);
+    SavedPasswordEntry getSavedPasswordEntry(int index);
 
     /**
      * Get saved password exception at index.
@@ -48,26 +48,26 @@
      * @param index of exception
      * @return Origin of password exception.
      */
-    public String getSavedPasswordException(int index);
+    String getSavedPasswordException(int index);
 
     /**
      * Remove saved password entry at index.
      *
      * @param index of password entry to remove.
      */
-    public void removeSavedPasswordEntry(int index);
+    void removeSavedPasswordEntry(int index);
 
     /**
      * Remove saved exception entry at index.
      *
      * @param index of exception entry.
      */
-    public void removeSavedPasswordException(int index);
+    void removeSavedPasswordException(int index);
 
     /**
      * Trigger serializing the saved passwords in the background.
      *
      * @param callback is called on completion, with the serialized passwords as argument.
      */
-    public void serializePasswords(Callback<String> callback);
+    void serializePasswords(Callback<String> callback);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandlerProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandlerProvider.java
index 52341247..0e2da16 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandlerProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandlerProvider.java
@@ -7,8 +7,6 @@
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.browser.PasswordManagerHandler;
-import org.chromium.chrome.browser.PasswordUIView;
 
 /**
  * A provider for PasswordManagerHandler implementations, handling the choice of the proper one
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java
similarity index 92%
rename from chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java
rename to chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java
index 57972ed..76fa6a1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/PasswordUIView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java
@@ -2,7 +2,7 @@
 // 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;
+package org.chromium.chrome.browser.preferences.password;
 
 import org.chromium.base.Callback;
 import org.chromium.base.annotations.CalledByNative;
@@ -102,16 +102,14 @@
     private native SavedPasswordEntry nativeGetSavedPasswordEntry(
             long nativePasswordUIViewAndroid, int index);
 
-    private native String nativeGetSavedPasswordException(long nativePasswordUIViewAndroid,
-            int index);
+    private native String nativeGetSavedPasswordException(
+            long nativePasswordUIViewAndroid, int index);
 
     private native void nativeHandleRemoveSavedPasswordEntry(
-            long nativePasswordUIViewAndroid,
-            int index);
+            long nativePasswordUIViewAndroid, int index);
 
     private native void nativeHandleRemoveSavedPasswordException(
-            long nativePasswordUIViewAndroid,
-            int index);
+            long nativePasswordUIViewAndroid, int index);
 
     private static native String nativeGetAccountDashboardURL();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
index 8811486..3699689 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java
@@ -24,9 +24,6 @@
 import org.chromium.base.Callback;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.PasswordManagerHandler;
-import org.chromium.chrome.browser.PasswordUIView;
-import org.chromium.chrome.browser.SavedPasswordEntry;
 import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
 import org.chromium.chrome.browser.preferences.ChromeBasePreference;
 import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SavedPasswordEntry.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavedPasswordEntry.java
similarity index 95%
rename from chrome/android/java/src/org/chromium/chrome/browser/SavedPasswordEntry.java
rename to chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavedPasswordEntry.java
index 032ba7d..932359f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/SavedPasswordEntry.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/SavedPasswordEntry.java
@@ -2,7 +2,7 @@
 // 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;
+package org.chromium.chrome.browser.preferences.password;
 
 /**
  * A class representing information about a saved password entry in Chrome's settngs.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
index 45ad652..7d86fae8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
@@ -404,7 +404,7 @@
         if (MultiWindowUtils.isActivityVisible(getActivity())
                 && getSelectedOptions().contains(DialogOption.CLEAR_HISTORY)
                 && mIsDialogAboutOtherFormsOfBrowsingHistoryEnabled
-                && !OtherFormsOfHistoryDialogFragment.wasDialogShown(getActivity())) {
+                && !OtherFormsOfHistoryDialogFragment.wasDialogShown()) {
             mDialogAboutOtherFormsOfBrowsingHistory = new OtherFormsOfHistoryDialogFragment();
             mDialogAboutOtherFormsOfBrowsingHistory.show(getActivity());
             dismissProgressDialog();
@@ -500,7 +500,8 @@
 
         mDialogOpened = SystemClock.elapsedRealtime();
         mMaxImportantSites = BrowsingDataBridge.getMaxImportantSites();
-        BrowsingDataBridge.getInstance().requestInfoAboutOtherFormsOfBrowsingHistory(this);
+        if (!OtherFormsOfHistoryDialogFragment.wasDialogShown())
+            BrowsingDataBridge.getInstance().requestInfoAboutOtherFormsOfBrowsingHistory(this);
         getActivity().setTitle(R.string.clear_browsing_data_title);
         PreferenceUtils.addPreferencesFromResource(this, getPreferenceXmlId());
         DialogOption[] options = getDialogOptions();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/OtherFormsOfHistoryDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/OtherFormsOfHistoryDialogFragment.java
index e419f431..1424678 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/OtherFormsOfHistoryDialogFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/OtherFormsOfHistoryDialogFragment.java
@@ -7,7 +7,6 @@
 import android.app.Activity;
 import android.app.Dialog;
 import android.app.DialogFragment;
-import android.content.Context;
 import android.content.DialogInterface;
 import android.content.SharedPreferences;
 import android.os.Bundle;
@@ -109,7 +108,7 @@
     /**
      * @return Whether the dialog has already been shown to the user before.
      */
-    static boolean wasDialogShown(Context context) {
+    static boolean wasDialogShown() {
         return ContextUtils.getAppSharedPreferences().getBoolean(
                 PREF_OTHER_FORMS_OF_HISTORY_DIALOG_SHOWN, false);
     }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 6fbc269c..447b586 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -55,11 +55,8 @@
   "java/src/org/chromium/chrome/browser/NativePageHost.java",
   "java/src/org/chromium/chrome/browser/NavigationPopup.java",
   "java/src/org/chromium/chrome/browser/NearOomMonitor.java",
-  "java/src/org/chromium/chrome/browser/PasswordManagerHandler.java",
-  "java/src/org/chromium/chrome/browser/PasswordUIView.java",
   "java/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java",
   "java/src/org/chromium/chrome/browser/RepostFormWarningDialog.java",
-  "java/src/org/chromium/chrome/browser/SavedPasswordEntry.java",
   "java/src/org/chromium/chrome/browser/SearchGeolocationDisclosureTabHelper.java",
   "java/src/org/chromium/chrome/browser/ServiceTabLauncher.java",
   "java/src/org/chromium/chrome/browser/SingleTabActivity.java",
@@ -984,9 +981,12 @@
   "java/src/org/chromium/chrome/browser/preferences/languages/LanguageListPreference.java",
   "java/src/org/chromium/chrome/browser/preferences/password/ExportWarningDialogFragment.java",
   "java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java",
+  "java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java",
   "java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandlerProvider.java",
   "java/src/org/chromium/chrome/browser/preferences/password/PasswordReauthenticationFragment.java",
+  "java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java",
   "java/src/org/chromium/chrome/browser/preferences/password/ReauthenticationManager.java",
+  "java/src/org/chromium/chrome/browser/preferences/password/SavedPasswordEntry.java",
   "java/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferences.java",
   "java/src/org/chromium/chrome/browser/preferences/privacy/BandwidthType.java",
   "java/src/org/chromium/chrome/browser/preferences/privacy/BrowsingDataBridge.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
index f00ff8c8..ead6545 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
@@ -22,7 +22,6 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.test.ChromeActivityTestRule;
-import org.chromium.content.browser.test.util.ApplicationUtils;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -212,7 +211,6 @@
 
         cleanUpAllDownloads();
 
-        ApplicationUtils.waitForLibraryDependencies(InstrumentationRegistry.getInstrumentation());
         final Context context = InstrumentationRegistry.getTargetContext().getApplicationContext();
 
         ThreadUtils.runOnUiThreadBlocking(() -> {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
index 8d056bc..10bd6a8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
@@ -35,8 +35,6 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.PasswordManagerHandler;
-import org.chromium.chrome.browser.SavedPasswordEntry;
 import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
 import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/UndoTabModelTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/UndoTabModelTest.java
index 290e532..f4d53d9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/UndoTabModelTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/UndoTabModelTest.java
@@ -116,9 +116,8 @@
         });
     }
 
-    private void closeTabOnUiThread(
-            final TabModel model, final Tab tab, final boolean undoable)
-            throws InterruptedException {
+    private void closeTabOnUiThread(final TabModel model, final Tab tab, final boolean undoable)
+            throws InterruptedException, TimeoutException {
         // Check preconditions.
         Assert.assertFalse(tab.isClosing());
         Assert.assertTrue(tab.isInitialized());
@@ -144,13 +143,7 @@
         boolean didUndo = undoable && model.supportsPendingClosures();
 
         // Make sure the TabModel throws a tabPendingClosure callback if necessary.
-        if (didUndo) {
-            try {
-                didReceivePendingClosureHelper.waitForCallback(0);
-            } catch (TimeoutException e) {
-                Assert.fail();
-            }
-        }
+        if (didUndo) didReceivePendingClosureHelper.waitForCallback(0);
 
         // Check post conditions
         Assert.assertEquals(didUndo, model.isClosurePending(tab.getId()));
@@ -178,7 +171,7 @@
     }
 
     private void cancelTabClosureOnUiThread(final TabModel model, final Tab tab)
-            throws InterruptedException {
+            throws InterruptedException, TimeoutException {
         // Check preconditions.
         Assert.assertTrue(tab.isClosing());
         Assert.assertTrue(tab.isInitialized());
@@ -202,11 +195,7 @@
         });
 
         // Make sure the TabModel throws a tabClosureUndone.
-        try {
-            didReceiveClosureCancelledHelper.waitForCallback(0);
-        } catch (TimeoutException e) {
-            Assert.fail();
-        }
+        didReceiveClosureCancelledHelper.waitForCallback(0);
 
         // Check post conditions.
         Assert.assertFalse(model.isClosurePending(tab.getId()));
@@ -216,7 +205,7 @@
     }
 
     private void cancelAllTabClosuresOnUiThread(final TabModel model, final Tab[] expectedToClose)
-            throws InterruptedException {
+            throws InterruptedException, TimeoutException {
         final CallbackHelper tabClosureUndoneHelper = new CallbackHelper();
 
         for (int i = 0; i < expectedToClose.length; i++) {
@@ -245,11 +234,7 @@
             }
         });
 
-        try {
-            tabClosureUndoneHelper.waitForCallback(0, expectedToClose.length);
-        } catch (TimeoutException e) {
-            Assert.fail();
-        }
+        tabClosureUndoneHelper.waitForCallback(0, expectedToClose.length);
 
         for (int i = 0; i < expectedToClose.length; i++) {
             final Tab tab = expectedToClose[i];
@@ -261,7 +246,7 @@
     }
 
     private void commitTabClosureOnUiThread(final TabModel model, final Tab tab)
-            throws InterruptedException {
+            throws InterruptedException, TimeoutException {
         // Check preconditions.
         Assert.assertTrue(tab.isClosing());
         Assert.assertTrue(tab.isInitialized());
@@ -285,11 +270,7 @@
         });
 
         // Make sure the TabModel throws a tabClosureCommitted.
-        try {
-            didReceiveClosureCommittedHelper.waitForCallback(0);
-        } catch (TimeoutException e) {
-            Assert.fail();
-        }
+        didReceiveClosureCommittedHelper.waitForCallback(0);
 
         // Check post conditions
         Assert.assertFalse(model.isClosurePending(tab.getId()));
@@ -299,7 +280,7 @@
     }
 
     private void commitAllTabClosuresOnUiThread(final TabModel model, Tab[] expectedToClose)
-            throws InterruptedException {
+            throws InterruptedException, TimeoutException {
         final CallbackHelper tabClosureCommittedHelper = new CallbackHelper();
 
         for (int i = 0; i < expectedToClose.length; i++) {
@@ -324,11 +305,7 @@
             }
         });
 
-        try {
-            tabClosureCommittedHelper.waitForCallback(0, expectedToClose.length);
-        } catch (TimeoutException e) {
-            Assert.fail();
-        }
+        tabClosureCommittedHelper.waitForCallback(0, expectedToClose.length);
         for (int i = 0; i < expectedToClose.length; i++) {
             final Tab tab = expectedToClose[i];
             Assert.assertTrue(tab.isClosing());
@@ -396,7 +373,7 @@
     @Test
     @MediumTest
     @RetryOnFailure
-    public void testSingleTab() throws InterruptedException {
+    public void testSingleTab() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
 
@@ -490,7 +467,7 @@
     // Flaky on tablets, crbug.com/620014.
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
     @RetryOnFailure
-    public void testTwoTabs() throws InterruptedException {
+    public void testTwoTabs() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
         createTabOnUiThread(tabCreator);
@@ -639,7 +616,7 @@
     @Test
     @MediumTest
     @RetryOnFailure
-    public void testInOrderRestore() throws InterruptedException {
+    public void testInOrderRestore() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
         createTabOnUiThread(tabCreator);
@@ -800,7 +777,7 @@
     @Test
     @MediumTest
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) // See crbug.com/633607
-    public void testReverseOrderRestore() throws InterruptedException {
+    public void testReverseOrderRestore() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
         createTabOnUiThread(tabCreator);
@@ -953,7 +930,7 @@
     @Test
     @MediumTest
     @RetryOnFailure
-    public void testOutOfOrder1() throws InterruptedException {
+    public void testOutOfOrder1() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
         createTabOnUiThread(tabCreator);
@@ -1070,7 +1047,7 @@
     @Test
     @MediumTest
     @FlakyTest(message = "crbug.com/592969")
-    public void testOutOfOrder2() throws InterruptedException {
+    public void testOutOfOrder2() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
         createTabOnUiThread(tabCreator);
@@ -1168,7 +1145,7 @@
     @Test
     @MediumTest
     @DisabledTest(message = "crbug.com/633607")
-    public void testCloseAll() throws InterruptedException {
+    public void testCloseAll() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
         createTabOnUiThread(tabCreator);
@@ -1243,7 +1220,7 @@
      */
     @Test
     @MediumTest
-    public void testCloseTab() throws InterruptedException {
+    public void testCloseTab() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
         createTabOnUiThread(tabCreator);
@@ -1291,7 +1268,7 @@
     @Test
     @MediumTest
     @RetryOnFailure
-    public void testMoveTab() throws InterruptedException {
+    public void testMoveTab() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
         createTabOnUiThread(tabCreator);
@@ -1344,7 +1321,7 @@
     // Disabled due to flakiness on linux_android_rel_ng (crbug.com/661429)
     @Test
     @DisabledTest
-    public void testAddTab() throws InterruptedException {
+    public void testAddTab() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
         createTabOnUiThread(tabCreator);
@@ -1418,7 +1395,7 @@
     @Test
     @MediumTest
     @RetryOnFailure
-    public void testUndoNotSupported() throws InterruptedException {
+    public void testUndoNotSupported() throws InterruptedException, TimeoutException {
         TabModel model = mActivityTestRule.getActivity().getTabModelSelector().getModel(true);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(true);
         createTabOnUiThread(tabCreator);
@@ -1465,7 +1442,7 @@
     @Test
     @MediumTest
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) // See crbug.com/633607
-    public void testSaveStateCommitsUndos() throws InterruptedException {
+    public void testSaveStateCommitsUndos() throws InterruptedException, TimeoutException {
         TabModelSelector selector = mActivityTestRule.getActivity().getTabModelSelector();
         TabModel model = selector.getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
@@ -1498,7 +1475,7 @@
     @Test
     @MediumTest
     @RetryOnFailure
-    public void testOpenRecentlyClosedTab() throws InterruptedException {
+    public void testOpenRecentlyClosedTab() throws InterruptedException, TimeoutException {
         TabModelSelector selector = mActivityTestRule.getActivity().getTabModelSelector();
         TabModel model = selector.getModel(false);
         ChromeTabCreator tabCreator = mActivityTestRule.getActivity().getTabCreator(false);
@@ -1523,7 +1500,7 @@
      */
     @Test
     @MediumTest
-    public void testOpenRecentlyClosedTabNative() throws InterruptedException {
+    public void testOpenRecentlyClosedTabNative() throws InterruptedException, TimeoutException {
         final TabModelSelector selector = mActivityTestRule.getActivity().getTabModelSelector();
         final TabModel model = selector.getModel(false);
 
@@ -1569,7 +1546,8 @@
     @MinAndroidSdkLevel(24)
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     @CommandLineFlags.Add(ChromeSwitches.DISABLE_TAB_MERGING_FOR_TESTING)
-    public void testOpenRecentlyClosedTabMultiWindow() throws InterruptedException {
+    public void testOpenRecentlyClosedTabMultiWindow()
+            throws InterruptedException, TimeoutException {
         final ChromeTabbedActivity2 secondActivity =
                 MultiWindowTestHelper.createSecondChromeTabbedActivity(
                         mActivityTestRule.getActivity());
@@ -1650,7 +1628,8 @@
     @MinAndroidSdkLevel(24)
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     @CommandLineFlags.Add(ChromeSwitches.DISABLE_TAB_MERGING_FOR_TESTING)
-    public void testOpenRecentlyClosedTabMultiWindowFallback() throws InterruptedException {
+    public void testOpenRecentlyClosedTabMultiWindowFallback()
+            throws InterruptedException, TimeoutException {
         final ChromeTabbedActivity2 secondActivity =
                 MultiWindowTestHelper.createSecondChromeTabbedActivity(
                         mActivityTestRule.getActivity());
@@ -1683,7 +1662,7 @@
         try {
             closedCallback.waitForCallback(0);
         } catch (TimeoutException | InterruptedException e) {
-            Assert.fail("Failed to close the tab on the second window.");
+            throw new AssertionError("Failed to close the tab on the second window.", e);
         }
 
         Assert.assertEquals("Window 2 should have 1 tab.", 1, secondModel.getCount());
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 8fbc3229..59cc684 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -11068,9 +11068,12 @@
       <message name="IDS_VR_BUTTON_TRACKPAD" desc="The label for the trackpad on the VR controller.">
         Scroll / Click
       </message>
-      <message name="IDS_VR_BUTTON_EXIT" desc="The label for the exit button on the VR controller.">
+      <message name="IDS_VR_BUTTON_EXIT" desc="The label for the exit button on the VR controller -- shown when in fullscreen mode.">
         Exit Fullscreen
       </message>
+      <message name="IDS_VR_BUTTON_BACK" desc="The label for the back button on the VR controller -- shown when the keyboard is visible.">
+        Back
+      </message>
     </if>
   </messages>
  </release>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index d9b6063..d2bac0e2 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4182,7 +4182,6 @@
       "../android/java/src/org/chromium/chrome/browser/IntentHelper.java",
       "../android/java/src/org/chromium/chrome/browser/JavascriptAppModalDialog.java",
       "../android/java/src/org/chromium/chrome/browser/NearOomMonitor.java",
-      "../android/java/src/org/chromium/chrome/browser/PasswordUIView.java",
       "../android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java",
       "../android/java/src/org/chromium/chrome/browser/SearchGeolocationDisclosureTabHelper.java",
       "../android/java/src/org/chromium/chrome/browser/ServiceTabLauncher.java",
@@ -4351,6 +4350,7 @@
       "../android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java",
       "../android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java",
       "../android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileBridge.java",
+      "../android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java",
       "../android/java/src/org/chromium/chrome/browser/preferences/privacy/BrowsingDataBridge.java",
       "../android/java/src/org/chromium/chrome/browser/preferences/privacy/BrowsingDataCounterBridge.java",
       "../android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreferenceBridge.java",
diff --git a/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc b/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc
index a71ca51..ffd081e 100644
--- a/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc
@@ -24,9 +24,9 @@
       content::BrowserContext* browser_context);
 
   // BrowsingDataFlashLSOHelper implementation:
-  void StartFetching(const GetSitesWithFlashDataCallback& callback) override;
+  void StartFetching(GetSitesWithFlashDataCallback callback) override;
   void DeleteFlashLSOsForSite(const std::string& site,
-                              const base::Closure& callback) override;
+                              base::OnceClosure callback) override;
 
   // PepperFlashSettingsManager::Client overrides:
   void OnGetSitesWithDataCompleted(
@@ -37,11 +37,11 @@
  private:
   struct DeleteFlashLSOTask {
     DeleteFlashLSOTask() {}
-    DeleteFlashLSOTask(const std::string& site, const base::Closure& callback)
-        : site(site), callback(callback) {}
+    DeleteFlashLSOTask(const std::string& site, base::OnceClosure callback)
+        : site(site), callback(std::move(callback)) {}
 
     std::string site;
-    base::Closure callback;
+    base::OnceClosure callback;
   };
 
   ~BrowsingDataFlashLSOHelperImpl() override;
@@ -73,26 +73,26 @@
 }
 
 void BrowsingDataFlashLSOHelperImpl::StartFetching(
-    const GetSitesWithFlashDataCallback& callback) {
+    GetSitesWithFlashDataCallback callback) {
   DCHECK(callback_.is_null());
-  callback_ = callback;
+  callback_ = std::move(callback);
   get_sites_with_data_request_id_ = settings_manager_.GetSitesWithData();
 }
 
 void BrowsingDataFlashLSOHelperImpl::DeleteFlashLSOsForSite(
-    const std::string& site, const base::Closure& callback) {
+    const std::string& site,
+    base::OnceClosure callback) {
   const uint64_t kClearAllData = 0;
   uint32_t id = settings_manager_.ClearSiteData(
       site, kClearAllData, std::numeric_limits<uint64_t>::max());
-  clear_site_data_ids_[id] = DeleteFlashLSOTask(site, callback);
+  clear_site_data_ids_[id] = DeleteFlashLSOTask(site, std::move(callback));
 }
 
 void BrowsingDataFlashLSOHelperImpl::OnGetSitesWithDataCompleted(
     uint32_t request_id,
     const std::vector<std::string>& sites) {
   DCHECK_EQ(get_sites_with_data_request_id_, request_id);
-  callback_.Run(sites);
-  callback_ = GetSitesWithFlashDataCallback();
+  std::move(callback_).Run(sites);
 }
 
 void BrowsingDataFlashLSOHelperImpl::OnClearSiteDataCompleted(
@@ -104,7 +104,7 @@
   LOG_IF(ERROR, !success) << "Couldn't clear Flash LSO data for "
                           << entry->second.site;
   if (!entry->second.callback.is_null())
-    entry->second.callback.Run();
+    std::move(entry->second.callback).Run();
   clear_site_data_ids_.erase(entry);
 }
 
diff --git a/chrome/browser/browsing_data/browsing_data_flash_lso_helper.h b/chrome/browser/browsing_data/browsing_data_flash_lso_helper.h
index 3922c44b..40ba100d 100644
--- a/chrome/browser/browsing_data/browsing_data_flash_lso_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_flash_lso_helper.h
@@ -20,15 +20,15 @@
 class BrowsingDataFlashLSOHelper
     : public base::RefCounted<BrowsingDataFlashLSOHelper> {
  public:
-  typedef base::Callback<void(const std::vector<std::string>&)>
+  typedef base::OnceCallback<void(const std::vector<std::string>&)>
       GetSitesWithFlashDataCallback;
 
   static BrowsingDataFlashLSOHelper* Create(
       content::BrowserContext* browser_context);
 
-  virtual void StartFetching(const GetSitesWithFlashDataCallback& callback) = 0;
+  virtual void StartFetching(GetSitesWithFlashDataCallback callback) = 0;
   virtual void DeleteFlashLSOsForSite(const std::string& site,
-                                      const base::Closure& callback) = 0;
+                                      base::OnceClosure callback) = 0;
 
  protected:
   friend class base::RefCounted<BrowsingDataFlashLSOHelper>;
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 763af68..2da8e1f 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -11,7 +11,9 @@
 #include <utility>
 #include <vector>
 
+#include "base/barrier_closure.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/metrics/user_metrics.h"
 #include "base/task_scheduler/post_task.h"
 #include "build/build_config.h"
@@ -136,33 +138,33 @@
 
 namespace {
 
-void UIThreadTrampolineHelper(const base::Closure& callback) {
-  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
+void UIThreadTrampolineHelper(base::OnceClosure callback) {
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, std::move(callback));
 }
 
 // Convenience method to create a callback that can be run on any thread and
 // will post the given |callback| back to the UI thread.
-base::Closure UIThreadTrampoline(const base::Closure& callback) {
+base::OnceClosure UIThreadTrampoline(base::OnceClosure callback) {
   // We could directly bind &BrowserThread::PostTask, but that would require
   // evaluating FROM_HERE when this method is called, as opposed to when the
   // task is actually posted.
-  return base::Bind(&UIThreadTrampolineHelper, callback);
+  return base::BindOnce(&UIThreadTrampolineHelper, std::move(callback));
 }
 
 template <typename T>
-void IgnoreArgumentHelper(const base::Closure& callback, T unused_argument) {
-  callback.Run();
+void IgnoreArgumentHelper(base::OnceClosure callback, T unused_argument) {
+  std::move(callback).Run();
 }
 
 // Another convenience method to turn a callback without arguments into one that
 // accepts (and ignores) a single argument.
 template <typename T>
-base::Callback<void(T)> IgnoreArgument(const base::Closure& callback) {
-  return base::Bind(&IgnoreArgumentHelper<T>, callback);
+base::OnceCallback<void(T)> IgnoreArgument(base::OnceClosure callback) {
+  return base::BindOnce(&IgnoreArgumentHelper<T>, std::move(callback));
 }
 
 bool WebsiteSettingsFilterAdapter(
-    const base::Callback<bool(const GURL&)> predicate,
+    const base::RepeatingCallback<bool(const GURL&)> predicate,
     const ContentSettingsPattern& primary_pattern,
     const ContentSettingsPattern& secondary_pattern) {
   // Ignore the default setting.
@@ -198,12 +200,14 @@
 void ClearCookiesOnIOThread(base::Time delete_begin,
                             base::Time delete_end,
                             net::URLRequestContextGetter* rq_context,
-                            const base::Closure& callback) {
+                            base::OnceClosure callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   net::CookieStore* cookie_store =
       rq_context->GetURLRequestContext()->cookie_store();
   cookie_store->DeleteAllCreatedBetweenAsync(
-      delete_begin, delete_end, IgnoreArgument<uint32_t>(callback));
+      delete_begin, delete_end,
+      base::AdaptCallbackForRepeating(
+          IgnoreArgument<uint32_t>(std::move(callback))));
 }
 
 void ClearCookiesWithPredicateOnIOThread(
@@ -211,12 +215,14 @@
     base::Time delete_end,
     net::CookieStore::CookiePredicate predicate,
     net::URLRequestContextGetter* rq_context,
-    const base::Closure& callback) {
+    base::OnceClosure callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   net::CookieStore* cookie_store =
       rq_context->GetURLRequestContext()->cookie_store();
   cookie_store->DeleteAllCreatedBetweenWithPredicateAsync(
-      delete_begin, delete_end, predicate, IgnoreArgument<uint32_t>(callback));
+      delete_begin, delete_end, predicate,
+      base::AdaptCallbackForRepeating(
+          IgnoreArgument<uint32_t>(std::move(callback))));
 }
 
 void ClearNetworkPredictorOnIOThread(chrome_browser_net::Predictor* predictor) {
@@ -229,7 +235,7 @@
 
 void ClearHostnameResolutionCacheOnIOThread(
     IOThread* io_thread,
-    base::Callback<bool(const std::string&)> host_filter) {
+    base::RepeatingCallback<bool(const std::string&)> host_filter) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   io_thread->ClearHostCache(host_filter);
@@ -252,7 +258,7 @@
 void ClearReportingCacheOnIOThread(
     net::URLRequestContextGetter* context,
     int data_type_mask,
-    const base::Callback<bool(const GURL&)>& origin_filter) {
+    const base::RepeatingCallback<bool(const GURL&)>& origin_filter) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   net::ReportingService* service =
@@ -311,70 +317,9 @@
 
 }  // namespace
 
-ChromeBrowsingDataRemoverDelegate::SubTask::SubTask(
-    const base::Closure& forward_callback)
-    : is_pending_(false),
-      forward_callback_(forward_callback),
-      weak_ptr_factory_(this) {
-  DCHECK(!forward_callback_.is_null());
-}
-
-ChromeBrowsingDataRemoverDelegate::SubTask::~SubTask() {}
-
-void ChromeBrowsingDataRemoverDelegate::SubTask::Start() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(!is_pending_);
-  is_pending_ = true;
-}
-
-base::Closure
-ChromeBrowsingDataRemoverDelegate::SubTask::GetCompletionCallback() {
-  return base::Bind(&SubTask::CompletionCallback,
-                    weak_ptr_factory_.GetWeakPtr());
-}
-
-void ChromeBrowsingDataRemoverDelegate::SubTask::CompletionCallback() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(is_pending_);
-  is_pending_ = false;
-  forward_callback_.Run();
-}
-
 ChromeBrowsingDataRemoverDelegate::ChromeBrowsingDataRemoverDelegate(
     BrowserContext* browser_context)
     : profile_(Profile::FromBrowserContext(browser_context)),
-      sub_task_forward_callback_(
-          base::Bind(&ChromeBrowsingDataRemoverDelegate::NotifyIfDone,
-                     base::Unretained(this))),
-      synchronous_clear_operations_(sub_task_forward_callback_),
-      clear_autofill_origin_urls_(sub_task_forward_callback_),
-      clear_flash_content_licenses_(sub_task_forward_callback_),
-      clear_media_drm_licenses_(sub_task_forward_callback_),
-      clear_domain_reliability_monitor_(sub_task_forward_callback_),
-      clear_form_(sub_task_forward_callback_),
-      clear_history_(sub_task_forward_callback_),
-      clear_keyword_data_(sub_task_forward_callback_),
-#if BUILDFLAG(ENABLE_NACL)
-      clear_nacl_cache_(sub_task_forward_callback_),
-      clear_pnacl_cache_(sub_task_forward_callback_),
-#endif
-      clear_hostname_resolution_cache_(sub_task_forward_callback_),
-      clear_network_predictor_(sub_task_forward_callback_),
-      clear_passwords_(sub_task_forward_callback_),
-      clear_passwords_stats_(sub_task_forward_callback_),
-      clear_http_auth_cache_(sub_task_forward_callback_),
-      clear_platform_keys_(sub_task_forward_callback_),
-#if defined(OS_ANDROID)
-      clear_precache_history_(sub_task_forward_callback_),
-      clear_offline_page_data_(sub_task_forward_callback_),
-#endif
-#if BUILDFLAG(ENABLE_WEBRTC)
-      clear_webrtc_logs_(sub_task_forward_callback_),
-#endif
-      clear_auto_sign_in_(sub_task_forward_callback_),
-      clear_reporting_cache_(sub_task_forward_callback_),
-      clear_network_error_logging_(sub_task_forward_callback_),
-      clear_video_perf_history_(sub_task_forward_callback_),
 #if BUILDFLAG(ENABLE_PLUGINS)
       flash_lso_helper_(BrowsingDataFlashLSOHelper::Create(browser_context)),
 #endif
@@ -392,7 +337,7 @@
 
 content::BrowsingDataRemoverDelegate::EmbedderOriginTypeMatcher
 ChromeBrowsingDataRemoverDelegate::GetOriginTypeMatcher() const {
-  return base::Bind(&DoesOriginMatchEmbedderMask);
+  return base::BindRepeating(&DoesOriginMatchEmbedderMask);
 }
 
 bool ChromeBrowsingDataRemoverDelegate::MayRemoveDownloadHistory() const {
@@ -447,20 +392,22 @@
 
   //////////////////////////////////////////////////////////////////////////////
   // INITIALIZATION
-  synchronous_clear_operations_.Start();
+  base::ScopedClosureRunner synchronous_clear_operations(
+      CreatePendingTaskCompletionClosure());
   callback_ = std::move(callback);
 
   delete_begin_ = delete_begin;
   delete_end_ = delete_end;
 
-  base::Callback<bool(const GURL& url)> filter =
+  base::RepeatingCallback<bool(const GURL& url)> filter =
       filter_builder.BuildGeneralFilter();
 
   // Some backends support a filter that |is_null()| to make complete deletion
   // more efficient.
-  base::Callback<bool(const GURL&)> nullable_filter =
-      filter_builder.IsEmptyBlacklist() ? base::Callback<bool(const GURL&)>()
-                                        : filter;
+  base::RepeatingCallback<bool(const GURL&)> nullable_filter =
+      filter_builder.IsEmptyBlacklist()
+          ? base::RepeatingCallback<bool(const GURL&)>()
+          : filter;
 
   // Managed devices and supervised users can have restrictions on history
   // deletion.
@@ -487,11 +434,10 @@
     if (history_service) {
       // TODO(dmurph): Support all backends with filter (crbug.com/113621).
       base::RecordAction(UserMetricsAction("ClearBrowsingData_History"));
-      clear_history_.Start();
       history_service->ExpireLocalAndRemoteHistoryBetween(
           WebHistoryServiceFactory::GetForProfile(profile_), std::set<GURL>(),
           delete_begin_, delete_end_,
-          clear_history_.GetCompletionCallback(),
+          base::AdaptCallbackForRepeating(CreatePendingTaskCompletionClosure()),
           &history_task_tracker_);
     }
     if (ClipboardRecentContent::GetInstance())
@@ -546,22 +492,20 @@
     // as the hostname resolution cache, key their entries by hostname. Rename
     // BuildPluginFilter() to something more general to reflect this use.
     if (g_browser_process->io_thread()) {
-      clear_hostname_resolution_cache_.Start();
       BrowserThread::PostTaskAndReply(
           BrowserThread::IO, FROM_HERE,
           base::BindOnce(&ClearHostnameResolutionCacheOnIOThread,
                          g_browser_process->io_thread(),
                          filter_builder.BuildPluginFilter()),
-          clear_hostname_resolution_cache_.GetCompletionCallback());
+          CreatePendingTaskCompletionClosure());
     }
     if (profile_->GetNetworkPredictor()) {
       // TODO(dmurph): Support all backends with filter (crbug.com/113621).
-      clear_network_predictor_.Start();
       BrowserThread::PostTaskAndReply(
           BrowserThread::IO, FROM_HERE,
           base::BindOnce(&ClearNetworkPredictorOnIOThread,
                          profile_->GetNetworkPredictor()),
-          clear_network_predictor_.GetCompletionCallback());
+          CreatePendingTaskCompletionClosure());
       profile_->GetNetworkPredictor()->ClearPrefsOnUIThread();
     }
 
@@ -573,10 +517,11 @@
       // TODO(msramek): Store filters from the currently executed task on the
       // object to avoid having to copy them to callback methods.
       template_url_sub_ = keywords_model->RegisterOnLoadedCallback(
-          base::Bind(&ChromeBrowsingDataRemoverDelegate::OnKeywordsLoaded,
-                     weak_ptr_factory_.GetWeakPtr(), filter));
+          base::AdaptCallbackForRepeating(base::BindOnce(
+              &ChromeBrowsingDataRemoverDelegate::OnKeywordsLoaded,
+              weak_ptr_factory_.GetWeakPtr(), filter,
+              CreatePendingTaskCompletionClosure())));
       keywords_model->Load();
-      clear_keyword_data_.Start();
     } else if (keywords_model) {
       keywords_model->RemoveAutoGeneratedForUrlsBetween(filter, delete_begin_,
                                                         delete_end_);
@@ -624,13 +569,12 @@
         WebDataServiceFactory::GetAutofillWebDataForProfile(
             profile_, ServiceAccessType::EXPLICIT_ACCESS);
     if (web_data_service.get()) {
-      clear_autofill_origin_urls_.Start();
       web_data_service->RemoveOriginURLsModifiedBetween(
           delete_begin_, delete_end_);
       // Ask for a call back when the above call is finished.
       web_data_service->GetDBTaskRunner()->PostTaskAndReply(
           FROM_HERE, base::BindOnce(&base::DoNothing),
-          clear_autofill_origin_urls_.GetCompletionCallback());
+          CreatePendingTaskCompletionClosure());
 
       autofill::PersonalDataManager* data_manager =
           autofill::PersonalDataManagerFactory::GetForProfile(profile_);
@@ -639,7 +583,6 @@
     }
 
 #if BUILDFLAG(ENABLE_WEBRTC)
-    clear_webrtc_logs_.Start();
     base::PostTaskWithTraitsAndReply(
         FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
         base::BindOnce(
@@ -647,15 +590,14 @@
             webrtc_logging::LogList::GetWebRtcLogDirectoryForBrowserContextPath(
                 profile_->GetPath()),
             delete_begin_),
-        clear_webrtc_logs_.GetCompletionCallback());
+        CreatePendingTaskCompletionClosure());
 #endif
 
 #if defined(OS_ANDROID)
-    clear_precache_history_.Start();
     base::PostTaskWithTraitsAndReply(
         FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
         base::BindOnce(&ClearPrecacheInBackground, profile_),
-        clear_precache_history_.GetCompletionCallback());
+        CreatePendingTaskCompletionClosure());
 
     // Clear the history information (last launch time and origin URL) of any
     // registered webapps.
@@ -700,7 +642,7 @@
     if (profile_->GetSSLHostStateDelegate()) {
       profile_->GetSSLHostStateDelegate()->Clear(
           filter_builder.IsEmptyBlacklist()
-              ? base::Callback<bool(const std::string&)>()
+              ? base::RepeatingCallback<bool(const std::string&)>()
               : filter_builder.BuildPluginFilter());
     }
 
@@ -713,9 +655,8 @@
       media::VideoDecodePerfHistory* video_decode_perf_history =
           profile_->GetVideoDecodePerfHistory();
       if (video_decode_perf_history) {
-        clear_video_perf_history_.Start();
         video_decode_perf_history->ClearHistory(
-            clear_video_perf_history_.GetCompletionCallback());
+            CreatePendingTaskCompletionClosure());
       }
     }
   }
@@ -743,7 +684,7 @@
 
     host_content_settings_map_->ClearSettingsForOneTypeWithPredicate(
         CONTENT_SETTINGS_TYPE_CLIENT_HINTS, base::Time(),
-        base::Bind(&WebsiteSettingsFilterAdapter, filter));
+        base::BindRepeating(&WebsiteSettingsFilterAdapter, filter));
 
     // Clear the safebrowsing cookies only if time period is for "all time".  It
     // doesn't make sense to apply the time period of deleting in the last X
@@ -755,16 +696,17 @@
       if (sb_service) {
         scoped_refptr<net::URLRequestContextGetter> sb_context =
             sb_service->url_request_context();
-        ++clear_cookies_count_;
+
         if (filter_builder.IsEmptyBlacklist()) {
           BrowserThread::PostTask(
               BrowserThread::IO, FROM_HERE,
               base::BindOnce(
                   &ClearCookiesOnIOThread, delete_begin_, delete_end_,
                   base::RetainedRef(std::move(sb_context)),
-                  UIThreadTrampoline(base::Bind(
+                  UIThreadTrampoline(base::BindOnce(
                       &ChromeBrowsingDataRemoverDelegate::OnClearedCookies,
-                      weak_ptr_factory_.GetWeakPtr()))));
+                      weak_ptr_factory_.GetWeakPtr(),
+                      CreatePendingTaskCompletionClosure()))));
         } else {
           BrowserThread::PostTask(
               BrowserThread::IO, FROM_HERE,
@@ -772,9 +714,10 @@
                   &ClearCookiesWithPredicateOnIOThread, delete_begin_,
                   delete_end_, filter_builder.BuildCookieFilter(),
                   base::RetainedRef(std::move(sb_context)),
-                  UIThreadTrampoline(base::Bind(
+                  UIThreadTrampoline(base::BindOnce(
                       &ChromeBrowsingDataRemoverDelegate::OnClearedCookies,
-                      weak_ptr_factory_.GetWeakPtr()))));
+                      weak_ptr_factory_.GetWeakPtr(),
+                      CreatePendingTaskCompletionClosure()))));
         }
       }
     }
@@ -810,7 +753,7 @@
   if (remove_mask & DATA_TYPE_DURABLE_PERMISSION) {
     host_content_settings_map_->ClearSettingsForOneTypeWithPredicate(
         CONTENT_SETTINGS_TYPE_DURABLE_STORAGE, base::Time(),
-        base::Bind(&WebsiteSettingsFilterAdapter, filter));
+        base::BindRepeating(&WebsiteSettingsFilterAdapter, filter));
   }
 
   //////////////////////////////////////////////////////////////////////////////
@@ -820,7 +763,7 @@
 
     host_content_settings_map_->ClearSettingsForOneTypeWithPredicate(
         CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, base::Time(),
-        base::Bind(&WebsiteSettingsFilterAdapter, filter));
+        base::BindRepeating(&WebsiteSettingsFilterAdapter, filter));
 
     if (MediaEngagementService::IsEnabled()) {
       MediaEngagementService::Get(profile_)->ClearDataBetweenTime(delete_begin_,
@@ -832,7 +775,7 @@
       (remove_mask & DATA_TYPE_HISTORY)) {
     host_content_settings_map_->ClearSettingsForOneTypeWithPredicate(
         CONTENT_SETTINGS_TYPE_APP_BANNER, base::Time(),
-        base::Bind(&WebsiteSettingsFilterAdapter, filter));
+        base::BindRepeating(&WebsiteSettingsFilterAdapter, filter));
 
     PermissionDecisionAutoBlocker::GetForProfile(profile_)->RemoveCountsByUrl(
         filter);
@@ -847,21 +790,20 @@
             profile_, ServiceAccessType::EXPLICIT_ACCESS).get();
 
     if (password_store) {
-      clear_passwords_.Start();
       password_store->RemoveLoginsByURLAndTime(
           filter, delete_begin_, delete_end_,
-          clear_passwords_.GetCompletionCallback());
+          base::AdaptCallbackForRepeating(
+              CreatePendingTaskCompletionClosure()));
     }
 
     scoped_refptr<net::URLRequestContextGetter> request_context =
         BrowserContext::GetDefaultStoragePartition(profile_)
             ->GetURLRequestContext();
-    clear_http_auth_cache_.Start();
     BrowserThread::PostTaskAndReply(
         BrowserThread::IO, FROM_HERE,
         base::BindOnce(&ClearHttpAuthCacheOnIOThread,
                        std::move(request_context), delete_begin_),
-        clear_http_auth_cache_.GetCompletionCallback());
+        CreatePendingTaskCompletionClosure());
   }
 
   if (remove_mask & content::BrowsingDataRemover::DATA_TYPE_COOKIES) {
@@ -871,9 +813,9 @@
             .get();
 
     if (password_store) {
-      clear_auto_sign_in_.Start();
       password_store->DisableAutoSignInForOrigins(
-          filter, clear_auto_sign_in_.GetCompletionCallback());
+          filter, base::AdaptCallbackForRepeating(
+                      CreatePendingTaskCompletionClosure()));
     }
   }
 
@@ -883,10 +825,10 @@
             profile_, ServiceAccessType::EXPLICIT_ACCESS).get();
 
     if (password_store) {
-      clear_passwords_stats_.Start();
       password_store->RemoveStatisticsByOriginAndTime(
           nullable_filter, delete_begin_, delete_end_,
-          clear_passwords_stats_.GetCompletionCallback());
+          base::AdaptCallbackForRepeating(
+              CreatePendingTaskCompletionClosure()));
     }
   }
 
@@ -900,7 +842,6 @@
             profile_, ServiceAccessType::EXPLICIT_ACCESS);
 
     if (web_data_service.get()) {
-      clear_form_.Start();
       web_data_service->RemoveFormElementsAddedBetween(delete_begin_,
           delete_end_);
       web_data_service->RemoveAutofillDataModifiedBetween(
@@ -908,7 +849,7 @@
       // Ask for a call back when the above calls are finished.
       web_data_service->GetDBTaskRunner()->PostTaskAndReply(
           FROM_HERE, base::BindOnce(&base::DoNothing),
-          clear_form_.GetCompletionCallback());
+          CreatePendingTaskCompletionClosure());
 
       autofill::PersonalDataManager* data_manager =
           autofill::PersonalDataManagerFactory::GetForProfile(profile_);
@@ -929,20 +870,16 @@
     web_cache::WebCacheManager::GetInstance()->ClearCache();
 
 #if BUILDFLAG(ENABLE_NACL)
-    clear_nacl_cache_.Start();
-
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
-        base::BindOnce(
-            &ClearNaClCacheOnIOThread,
-            UIThreadTrampoline(clear_nacl_cache_.GetCompletionCallback())));
-
-    clear_pnacl_cache_.Start();
+        base::BindOnce(&ClearNaClCacheOnIOThread,
+                       base::AdaptCallbackForRepeating(UIThreadTrampoline(
+                           CreatePendingTaskCompletionClosure()))));
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
-        base::BindOnce(
-            &ClearPnaclCacheOnIOThread, delete_begin_, delete_end_,
-            UIThreadTrampoline(clear_pnacl_cache_.GetCompletionCallback())));
+        base::BindOnce(&ClearPnaclCacheOnIOThread, delete_begin_, delete_end_,
+                       base::AdaptCallbackForRepeating(UIThreadTrampoline(
+                           CreatePendingTaskCompletionClosure()))));
 #endif
 
     // The PrerenderManager may have a page actively being prerendered, which
@@ -977,12 +914,13 @@
     // For now we're considering offline pages as cache, so if we're removing
     // cache we should remove offline pages as well.
     if ((remove_mask & content::BrowsingDataRemover::DATA_TYPE_CACHE)) {
-      clear_offline_page_data_.Start();
       offline_pages::OfflinePageModelFactory::GetForBrowserContext(profile_)
           ->DeleteCachedPagesByURLPredicate(
               filter,
-              IgnoreArgument<offline_pages::OfflinePageModel::DeletePageResult>(
-                  clear_offline_page_data_.GetCompletionCallback()));
+              base::AdaptCallbackForRepeating(
+                  IgnoreArgument<
+                      offline_pages::OfflinePageModel::DeletePageResult>(
+                      CreatePendingTaskCompletionClosure())));
     }
 #endif
   }
@@ -1004,7 +942,6 @@
       (origin_type_mask &
        content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB)) {
     base::RecordAction(UserMetricsAction("ClearBrowsingData_LSOData"));
-    clear_plugin_data_count_ = 1;
 
     if (filter_builder.IsEmptyBlacklist()) {
       DCHECK(!plugin_data_remover_);
@@ -1016,16 +953,19 @@
       base::WaitableEventWatcher::EventCallback watcher_callback =
           base::BindOnce(
               &ChromeBrowsingDataRemoverDelegate::OnWaitableEventSignaled,
-              weak_ptr_factory_.GetWeakPtr());
+              weak_ptr_factory_.GetWeakPtr(),
+              CreatePendingTaskCompletionClosure());
       watcher_.StartWatching(event, std::move(watcher_callback),
                              base::SequencedTaskRunnerHandle::Get());
     } else {
       // TODO(msramek): Store filters from the currently executed task on the
       // object to avoid having to copy them to callback methods.
-      flash_lso_helper_->StartFetching(base::Bind(
-          &ChromeBrowsingDataRemoverDelegate::OnSitesWithFlashDataFetched,
-          weak_ptr_factory_.GetWeakPtr(),
-          filter_builder.BuildPluginFilter()));
+      flash_lso_helper_->StartFetching(
+          base::AdaptCallbackForRepeating(base::BindOnce(
+              &ChromeBrowsingDataRemoverDelegate::OnSitesWithFlashDataFetched,
+              weak_ptr_factory_.GetWeakPtr(),
+              filter_builder.BuildPluginFilter(),
+              CreatePendingTaskCompletionClosure())));
     }
   }
 #endif
@@ -1038,7 +978,8 @@
     base::RecordAction(UserMetricsAction("ClearBrowsingData_ContentLicenses"));
 
 #if BUILDFLAG(ENABLE_PLUGINS)
-    clear_flash_content_licenses_.Start();
+    // Will be completed in OnDeauthorizeFlashContentLicensesCompleted()
+    num_pending_tasks_ += 1;
     if (!pepper_flash_settings_manager_.get()) {
       pepper_flash_settings_manager_.reset(
           new PepperFlashSettingsManager(this, profile_));
@@ -1054,7 +995,6 @@
     if (!user) {
       LOG(WARNING) << "Failed to find user for current profile.";
     } else {
-      clear_platform_keys_.Start();
       chromeos::DBusThreadManager::Get()
           ->GetCryptohomeClient()
           ->TpmAttestationDeleteKeys(
@@ -1063,14 +1003,14 @@
               chromeos::attestation::kContentProtectionKeyPrefix,
               base::BindOnce(
                   &ChromeBrowsingDataRemoverDelegate::OnClearPlatformKeys,
-                  weak_ptr_factory_.GetWeakPtr()));
+                  weak_ptr_factory_.GetWeakPtr(),
+                  CreatePendingTaskCompletionClosure()));
     }
 #endif  // defined(OS_CHROMEOS)
 
 #if defined(OS_ANDROID)
-    clear_media_drm_licenses_.Start();
     ClearMediaDrmLicenses(prefs, delete_begin_, delete_end, filter,
-                          clear_media_drm_licenses_.GetCompletionCallback());
+                          CreatePendingTaskCompletionClosure());
 #endif  // defined(OS_ANDROID);
   }
 
@@ -1098,11 +1038,9 @@
       else
         mode = domain_reliability::CLEAR_BEACONS;
 
-      clear_domain_reliability_monitor_.Start();
-      service->ClearBrowsingData(
-          mode,
-          filter,
-          clear_domain_reliability_monitor_.GetCompletionCallback());
+      service->ClearBrowsingData(mode, filter,
+                                 base::AdaptCallbackForRepeating(
+                                     CreatePendingTaskCompletionClosure()));
     }
   }
 
@@ -1117,13 +1055,12 @@
     if (remove_mask & content::BrowsingDataRemover::DATA_TYPE_COOKIES)
       data_type_mask |= net::ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS;
 
-    clear_reporting_cache_.Start();
     BrowserThread::PostTaskAndReply(
         BrowserThread::IO, FROM_HERE,
         base::BindOnce(&ClearReportingCacheOnIOThread,
                        base::RetainedRef(std::move(context)), data_type_mask,
                        filter),
-        UIThreadTrampoline(clear_reporting_cache_.GetCompletionCallback()));
+        UIThreadTrampoline(CreatePendingTaskCompletionClosure()));
   }
 
   if ((remove_mask & content::BrowsingDataRemover::DATA_TYPE_COOKIES) ||
@@ -1131,13 +1068,11 @@
     scoped_refptr<net::URLRequestContextGetter> context =
         profile_->GetRequestContext();
 
-    clear_network_error_logging_.Start();
     BrowserThread::PostTaskAndReply(
         BrowserThread::IO, FROM_HERE,
         base::BindOnce(&ClearNetworkErrorLoggingOnIOThread,
                        base::RetainedRef(std::move(context)), filter),
-        UIThreadTrampoline(
-            clear_network_error_logging_.GetCompletionCallback()));
+        UIThreadTrampoline(CreatePendingTaskCompletionClosure()));
   }
 //////////////////////////////////////////////////////////////////////////////
 // DATA_TYPE_WEB_APP_DATA
@@ -1151,46 +1086,26 @@
   // Remove external protocol data.
   if (remove_mask & DATA_TYPE_EXTERNAL_PROTOCOL_DATA)
     ExternalProtocolHandler::ClearData(profile_);
-
-  synchronous_clear_operations_.GetCompletionCallback().Run();
 }
 
-void ChromeBrowsingDataRemoverDelegate::NotifyIfDone() {
-  if (!AllDone())
+void ChromeBrowsingDataRemoverDelegate::OnTaskComplete() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_GT(num_pending_tasks_, 0);
+  num_pending_tasks_--;
+
+  if (num_pending_tasks_)
     return;
 
   DCHECK(!callback_.is_null());
   std::move(callback_).Run();
 }
 
-bool ChromeBrowsingDataRemoverDelegate::AllDone() {
-  return !clear_cookies_count_ && !synchronous_clear_operations_.is_pending() &&
-         !clear_autofill_origin_urls_.is_pending() &&
-         !clear_flash_content_licenses_.is_pending() &&
-         !clear_media_drm_licenses_.is_pending() &&
-         !clear_domain_reliability_monitor_.is_pending() &&
-         !clear_form_.is_pending() && !clear_history_.is_pending() &&
-         !clear_hostname_resolution_cache_.is_pending() &&
-         !clear_keyword_data_.is_pending() &&
-#if BUILDFLAG(ENABLE_NACL)
-         !clear_nacl_cache_.is_pending() && !clear_pnacl_cache_.is_pending() &&
-#endif
-         !clear_network_predictor_.is_pending() &&
-         !clear_passwords_.is_pending() &&
-         !clear_passwords_stats_.is_pending() &&
-         !clear_http_auth_cache_.is_pending() &&
-         !clear_platform_keys_.is_pending() &&
-#if defined(OS_ANDROID)
-         !clear_precache_history_.is_pending() &&
-         !clear_offline_page_data_.is_pending() &&
-#endif
-#if BUILDFLAG(ENABLE_WEBRTC)
-         !clear_webrtc_logs_.is_pending() &&
-#endif
-         !clear_auto_sign_in_.is_pending() &&
-         !clear_reporting_cache_.is_pending() &&
-         !clear_network_error_logging_.is_pending() &&
-         !clear_video_perf_history_.is_pending() && !clear_plugin_data_count_;
+base::OnceClosure
+ChromeBrowsingDataRemoverDelegate::CreatePendingTaskCompletionClosure() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  num_pending_tasks_++;
+  return base::BindOnce(&ChromeBrowsingDataRemoverDelegate::OnTaskComplete,
+                        weak_ptr_factory_.GetWeakPtr());
 }
 
 #if defined(OS_ANDROID)
@@ -1208,80 +1123,65 @@
 #endif
 
 void ChromeBrowsingDataRemoverDelegate::OnKeywordsLoaded(
-    base::Callback<bool(const GURL&)> url_filter) {
+    base::RepeatingCallback<bool(const GURL&)> url_filter,
+    base::OnceClosure done) {
   // Deletes the entries from the model.
   TemplateURLService* model =
       TemplateURLServiceFactory::GetForProfile(profile_);
   model->RemoveAutoGeneratedForUrlsBetween(url_filter, delete_begin_,
                                            delete_end_);
   template_url_sub_.reset();
-  clear_keyword_data_.GetCompletionCallback().Run();
+  std::move(done).Run();
 }
 
-void ChromeBrowsingDataRemoverDelegate::OnClearedCookies() {
+void ChromeBrowsingDataRemoverDelegate::OnClearedCookies(
+    base::OnceClosure done) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  DCHECK_GT(clear_cookies_count_, 0);
-  --clear_cookies_count_;
-  NotifyIfDone();
+  std::move(done).Run();
 }
 
 #if defined(OS_CHROMEOS)
 void ChromeBrowsingDataRemoverDelegate::OnClearPlatformKeys(
+    base::OnceClosure done,
     base::Optional<bool> result) {
   LOG_IF(ERROR, !result.has_value() || !result.value())
       << "Failed to clear platform keys.";
-  clear_platform_keys_.GetCompletionCallback().Run();
+  std::move(done).Run();
 }
 #endif
 
 #if BUILDFLAG(ENABLE_PLUGINS)
 void ChromeBrowsingDataRemoverDelegate::OnWaitableEventSignaled(
+    base::OnceClosure done,
     base::WaitableEvent* waitable_event) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  DCHECK_EQ(1, clear_plugin_data_count_);
-  clear_plugin_data_count_ = 0;
-
   plugin_data_remover_.reset();
   watcher_.StopWatching();
-  NotifyIfDone();
+  std::move(done).Run();
 }
 
 void ChromeBrowsingDataRemoverDelegate::OnSitesWithFlashDataFetched(
-    base::Callback<bool(const std::string&)> plugin_filter,
+    base::RepeatingCallback<bool(const std::string&)> plugin_filter,
+    base::OnceClosure done,
     const std::vector<std::string>& sites) {
-  DCHECK_EQ(1, clear_plugin_data_count_);
-  clear_plugin_data_count_ = 0;
-
   std::vector<std::string> sites_to_delete;
   for (const std::string& site : sites) {
     if (plugin_filter.Run(site))
       sites_to_delete.push_back(site);
   }
 
-  clear_plugin_data_count_ = sites_to_delete.size();
+  base::RepeatingClosure barrier =
+      base::BarrierClosure(sites_to_delete.size(), std::move(done));
 
   for (const std::string& site : sites_to_delete) {
-    flash_lso_helper_->DeleteFlashLSOsForSite(
-        site,
-        base::Bind(&ChromeBrowsingDataRemoverDelegate::OnFlashDataDeleted,
-                   weak_ptr_factory_.GetWeakPtr()));
+    flash_lso_helper_->DeleteFlashLSOsForSite(site, barrier);
   }
-
-  NotifyIfDone();
-}
-
-void ChromeBrowsingDataRemoverDelegate::OnFlashDataDeleted() {
-  clear_plugin_data_count_--;
-  NotifyIfDone();
 }
 
 void ChromeBrowsingDataRemoverDelegate::
-OnDeauthorizeFlashContentLicensesCompleted(
-    uint32_t request_id,
-    bool /* success */) {
+    OnDeauthorizeFlashContentLicensesCompleted(uint32_t request_id,
+                                               bool /* success */) {
   DCHECK_EQ(request_id, deauthorize_flash_content_licenses_request_id_);
-  clear_flash_content_licenses_.GetCompletionCallback().Run();
+  OnTaskComplete();
 }
 #endif
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
index 57f7227..617b2f93 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
@@ -147,32 +147,6 @@
   static_assert((IMPORTANT_SITES_DATA_TYPES & ~FILTERABLE_DATA_TYPES) == 0,
                 "All important sites datatypes must be filterable.");
 
-  // Used to track the deletion of a single data storage backend.
-  class SubTask {
-   public:
-    // Creates a SubTask that calls |forward_callback| when completed.
-    // |forward_callback| is only kept as a reference and must outlive SubTask.
-    explicit SubTask(const base::Closure& forward_callback);
-    ~SubTask();
-
-    // Indicate that the task is in progress and we're waiting.
-    void Start();
-
-    // Returns a callback that should be called to indicate that the task
-    // has been finished.
-    base::Closure GetCompletionCallback();
-
-    // Whether the task is still in progress.
-    bool is_pending() const { return is_pending_; }
-
-   private:
-    void CompletionCallback();
-
-    bool is_pending_;
-    const base::Closure& forward_callback_;
-    base::WeakPtrFactory<SubTask> weak_ptr_factory_;
-  };
-
   ChromeBrowsingDataRemoverDelegate(content::BrowserContext* browser_context);
   ~ChromeBrowsingDataRemoverDelegate() override;
 
@@ -203,30 +177,36 @@
 #endif
 
  private:
-  // If AllDone(), calls the callback provided in RemoveEmbedderData().
-  void NotifyIfDone();
+  // Called by the closures returned by CreatePendingTaskCompletionClosure().
+  // Checks if all tasks have completed, and if so, calls callback_.
+  void OnTaskComplete();
 
-  // Whether there are no running deletion tasks.
-  bool AllDone();
+  // Increments the number of pending tasks by one, and returns a OnceClosure
+  // that calls OnTaskComplete(). The Remover is complete once all the closures
+  // created by this method have been invoked.
+  base::OnceClosure CreatePendingTaskCompletionClosure();
 
   // Callback for when TemplateURLService has finished loading. Clears the data,
   // clears the respective waiting flag, and invokes NotifyIfDone.
-  void OnKeywordsLoaded(base::Callback<bool(const GURL&)> url_filter);
+  void OnKeywordsLoaded(base::RepeatingCallback<bool(const GURL&)> url_filter,
+                        base::OnceClosure done);
 
 #if defined (OS_CHROMEOS)
-  void OnClearPlatformKeys(base::Optional<bool> result);
+  void OnClearPlatformKeys(base::OnceClosure done, base::Optional<bool> result);
 #endif
 
   // Callback for when cookies have been deleted. Invokes NotifyIfDone.
-  void OnClearedCookies();
+  void OnClearedCookies(base::OnceClosure done);
 
 #if BUILDFLAG(ENABLE_PLUGINS)
   // Called when plugin data has been cleared. Invokes NotifyIfDone.
-  void OnWaitableEventSignaled(base::WaitableEvent* waitable_event);
+  void OnWaitableEventSignaled(base::OnceClosure done,
+                               base::WaitableEvent* waitable_event);
 
   // Called when the list of |sites| storing Flash LSO cookies is fetched.
   void OnSitesWithFlashDataFetched(
-      base::Callback<bool(const std::string&)> plugin_filter,
+      base::RepeatingCallback<bool(const std::string&)> plugin_filter,
+      base::OnceClosure done,
       const std::vector<std::string>& sites);
 
   // Indicates that LSO cookies for one website have been deleted.
@@ -249,44 +229,8 @@
   // Completion callback to call when all data are deleted.
   base::OnceClosure callback_;
 
-  // A callback to NotifyIfDone() used by SubTasks instances.
-  const base::Closure sub_task_forward_callback_;
-
-  // Keeping track of various subtasks to be completed.
-  // Non-zero if waiting for SafeBrowsing cookies to be cleared.
-  int clear_cookies_count_ = 0;
-  SubTask synchronous_clear_operations_;
-  SubTask clear_autofill_origin_urls_;
-  SubTask clear_flash_content_licenses_;
-  SubTask clear_media_drm_licenses_;
-  SubTask clear_domain_reliability_monitor_;
-  SubTask clear_form_;
-  SubTask clear_history_;
-  SubTask clear_keyword_data_;
-#if BUILDFLAG(ENABLE_NACL)
-  SubTask clear_nacl_cache_;
-  SubTask clear_pnacl_cache_;
-#endif
-  SubTask clear_hostname_resolution_cache_;
-  SubTask clear_network_predictor_;
-  SubTask clear_passwords_;
-  SubTask clear_passwords_stats_;
-  SubTask clear_http_auth_cache_;
-  SubTask clear_platform_keys_;
-#if defined(OS_ANDROID)
-  SubTask clear_precache_history_;
-  SubTask clear_offline_page_data_;
-#endif
-#if BUILDFLAG(ENABLE_WEBRTC)
-  SubTask clear_webrtc_logs_;
-#endif
-  SubTask clear_auto_sign_in_;
-  SubTask clear_reporting_cache_;
-  SubTask clear_network_error_logging_;
-  SubTask clear_video_perf_history_;
-  // Counts the number of plugin data tasks. Should be the number of LSO cookies
-  // to be deleted, or 1 while we're fetching LSO cookies or deleting in bulk.
-  int clear_plugin_data_count_ = 0;
+  // Keeps track of number of tasks to be completed.
+  int num_pending_tasks_ = 0;
 
 #if BUILDFLAG(ENABLE_PLUGINS)
   // Used to delete plugin data.
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 06e1787..d4b6bcc 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -82,7 +82,6 @@
 #include "net/cookies/cookie_store.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/reporting/reporting_browsing_data_remover.h"
-#include "net/reporting/reporting_policy.h"
 #include "net/reporting/reporting_service.h"
 #include "net/url_request/network_error_logging_delegate.h"
 #include "net/url_request/url_request_context.h"
@@ -693,8 +692,8 @@
   explicit TestBrowsingDataFlashLSOHelper(TestingProfile* profile)
       : MockBrowsingDataFlashLSOHelper(profile) {}
 
-  void StartFetching(const GetSitesWithFlashDataCallback& callback) override {
-    MockBrowsingDataFlashLSOHelper::StartFetching(callback);
+  void StartFetching(GetSitesWithFlashDataCallback callback) override {
+    MockBrowsingDataFlashLSOHelper::StartFetching(std::move(callback));
     Notify();
   }
 
@@ -951,12 +950,6 @@
     return true;
   }
 
-  const net::ReportingPolicy& GetPolicy() const override {
-    static net::ReportingPolicy dummy_policy_;
-    NOTREACHED();
-    return dummy_policy_;
-  }
-
   int remove_calls() const { return remove_calls_; }
   int last_data_type_mask() const { return last_data_type_mask_; }
   const base::RepeatingCallback<bool(const GURL&)>& last_origin_filter() const {
diff --git a/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc b/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc
index 8bf64f1..0d88320 100644
--- a/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc
+++ b/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc
@@ -12,20 +12,21 @@
     content::BrowserContext* browser_context) {
 }
 void MockBrowsingDataFlashLSOHelper::StartFetching(
-    const GetSitesWithFlashDataCallback& callback) {
+    GetSitesWithFlashDataCallback callback) {
   ASSERT_FALSE(callback.is_null());
   ASSERT_TRUE(callback_.is_null());
-  callback_ = callback;
+  callback_ = std::move(callback);
 }
 
 void MockBrowsingDataFlashLSOHelper::DeleteFlashLSOsForSite(
-    const std::string& site, const base::Closure& callback) {
+    const std::string& site,
+    base::OnceClosure callback) {
   std::vector<std::string>::iterator entry =
       std::find(domains_.begin(), domains_.end(), site);
   ASSERT_TRUE(entry != domains_.end());
   domains_.erase(entry);
   if (!callback.is_null())
-    callback.Run();
+    std::move(callback).Run();
 }
 
 void MockBrowsingDataFlashLSOHelper::AddFlashLSODomain(
@@ -34,7 +35,7 @@
 }
 
 void MockBrowsingDataFlashLSOHelper::Notify() {
-  callback_.Run(domains_);
+  std::move(callback_).Run(domains_);
   callback_ = GetSitesWithFlashDataCallback();
 }
 
diff --git a/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h b/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h
index 2257e20..5a533a29 100644
--- a/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h
+++ b/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h
@@ -18,9 +18,9 @@
       content::BrowserContext* browser_context);
 
   // BrowsingDataFlashLSOHelper implementation:
-  void StartFetching(const GetSitesWithFlashDataCallback& callback) override;
+  void StartFetching(GetSitesWithFlashDataCallback callback) override;
   void DeleteFlashLSOsForSite(const std::string& site,
-                              const base::Closure& callback) override;
+                              base::OnceClosure callback) override;
 
   // Adds a domain sample.
   void AddFlashLSODomain(const std::string& domain);
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index b03f9b6..e52ed15b 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -425,6 +425,8 @@
     "arc/process/arc_process.h",
     "arc/process/arc_process_service.cc",
     "arc/process/arc_process_service.h",
+    "arc/screen_capture/arc_screen_capture_bridge.cc",
+    "arc/screen_capture/arc_screen_capture_bridge.h",
     "arc/tracing/arc_tracing_bridge.cc",
     "arc/tracing/arc_tracing_bridge.h",
     "arc/tts/arc_tts_service.cc",
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc
index b18e4139..ec96a75 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
 #include "chrome/browser/chromeos/arc/print/arc_print_service.h"
 #include "chrome/browser/chromeos/arc/process/arc_process_service.h"
+#include "chrome/browser/chromeos/arc/screen_capture/arc_screen_capture_bridge.h"
 #include "chrome/browser/chromeos/arc/tracing/arc_tracing_bridge.h"
 #include "chrome/browser/chromeos/arc/tts/arc_tts_service.h"
 #include "chrome/browser/chromeos/arc/user_session/arc_user_session_service.h"
@@ -161,6 +162,7 @@
   ArcProcessService::GetForBrowserContext(profile);
   ArcProvisionNotificationService::GetForBrowserContext(profile);
   ArcRotationLockBridge::GetForBrowserContext(profile);
+  ArcScreenCaptureBridge::GetForBrowserContext(profile);
   ArcSettingsService::GetForBrowserContext(profile);
   ArcTracingBridge::GetForBrowserContext(profile);
   ArcTtsService::GetForBrowserContext(profile);
diff --git a/chrome/browser/chromeos/arc/screen_capture/arc_screen_capture_bridge.cc b/chrome/browser/chromeos/arc/screen_capture/arc_screen_capture_bridge.cc
new file mode 100644
index 0000000..12478bd9
--- /dev/null
+++ b/chrome/browser/chromeos/arc/screen_capture/arc_screen_capture_bridge.cc
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/arc/screen_capture/arc_screen_capture_bridge.h"
+
+#include "base/memory/singleton.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+
+namespace arc {
+namespace {
+
+// Singleton factory for ArcScreenCaptureBridge
+class ArcScreenCaptureBridgeFactory
+    : public internal::ArcBrowserContextKeyedServiceFactoryBase<
+          ArcScreenCaptureBridge,
+          ArcScreenCaptureBridgeFactory> {
+ public:
+  // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
+  static constexpr const char* kName = "ArcScreenCaptureBridgeFactory";
+
+  static ArcScreenCaptureBridgeFactory* GetInstance() {
+    return base::Singleton<ArcScreenCaptureBridgeFactory>::get();
+  }
+
+ private:
+  friend base::DefaultSingletonTraits<ArcScreenCaptureBridgeFactory>;
+  ArcScreenCaptureBridgeFactory() = default;
+  ~ArcScreenCaptureBridgeFactory() override = default;
+};
+
+}  // namespace
+
+// static
+ArcScreenCaptureBridge* ArcScreenCaptureBridge::GetForBrowserContext(
+    content::BrowserContext* context) {
+  return ArcScreenCaptureBridgeFactory::GetForBrowserContext(context);
+}
+
+ArcScreenCaptureBridge::ArcScreenCaptureBridge(content::BrowserContext* context,
+                                               ArcBridgeService* bridge_service)
+    : arc_bridge_service_(bridge_service), weak_factory_(this) {
+  arc_bridge_service_->screen_capture()->SetHost(this);
+}
+
+ArcScreenCaptureBridge::~ArcScreenCaptureBridge() {
+  arc_bridge_service_->screen_capture()->SetHost(nullptr);
+}
+
+void ArcScreenCaptureBridge::RequestPermission(
+    const std::string& display_name,
+    const std::string& package_name,
+    RequestPermissionCallback callback) {
+  NOTREACHED();
+}
+
+void ArcScreenCaptureBridge::OpenSession(
+    mojom::ScreenCaptureSessionNotifierPtr notifier,
+    const std::string& package_name,
+    const gfx::Size& size,
+    OpenSessionCallback callback) {
+  NOTREACHED();
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/screen_capture/arc_screen_capture_bridge.h b/chrome/browser/chromeos/arc/screen_capture/arc_screen_capture_bridge.h
new file mode 100644
index 0000000..617467b8
--- /dev/null
+++ b/chrome/browser/chromeos/arc/screen_capture/arc_screen_capture_bridge.h
@@ -0,0 +1,52 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ARC_SCREEN_CAPTURE_ARC_SCREEN_CAPTURE_BRIDGE_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_SCREEN_CAPTURE_ARC_SCREEN_CAPTURE_BRIDGE_H_
+
+#include "base/macros.h"
+#include "components/arc/common/screen_capture.mojom.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace arc {
+
+class ArcBridgeService;
+
+class ArcScreenCaptureBridge : public KeyedService,
+                               public mojom::ScreenCaptureHost {
+ public:
+  // Returns singleton instance for the given BrowserContext,
+  // or nullptr if the browser |context| is not allowed to use ARC.
+  static ArcScreenCaptureBridge* GetForBrowserContext(
+      content::BrowserContext* context);
+
+  ArcScreenCaptureBridge(content::BrowserContext* context,
+                         ArcBridgeService* bridge_service);
+  ~ArcScreenCaptureBridge() override;
+
+  // mojom::ScreenCaptureHost overrides:
+  void OpenSession(mojom::ScreenCaptureSessionNotifierPtr notifier,
+                   const std::string& package_name,
+                   const gfx::Size& size,
+                   OpenSessionCallback callback) override;
+  void RequestPermission(const std::string& display_name,
+                         const std::string& package_name,
+                         RequestPermissionCallback callback) override;
+
+ private:
+  ArcBridgeService* const arc_bridge_service_;  // Owned by ArcServiceManager.
+
+  // WeakPtrFactory to use for callbacks.
+  base::WeakPtrFactory<ArcScreenCaptureBridge> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcScreenCaptureBridge);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_SCREEN_CAPTURE_ARC_SCREEN_CAPTURE_BRIDGE_H_
diff --git a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
index 0c7ee32..bffa077 100644
--- a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
@@ -150,7 +150,15 @@
   StartTest();
 }
 
-IN_PROC_BROWSER_TEST_F(GalleryBrowserTest, TraverseSlideThumbnailsOnDrive) {
+// http://crbug.com/804364 : Flaky due to crash on linux-chromeos-dbg
+#if !defined(NDEBUG)
+#define MAYBE_TraverseSlideThumbnailsOnDrive \
+  DISABLED_TraverseSlideThumbnailsOnDrive
+#else
+#define MAYBE_TraverseSlideThumbnailsOnDrive TraverseSlideThumbnailsOnDrive
+#endif
+IN_PROC_BROWSER_TEST_F(GalleryBrowserTest,
+                       MAYBE_TraverseSlideThumbnailsOnDrive) {
   set_test_case_name("traverseSlideThumbnailsOnDrive");
   StartTest();
 }
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 0771dc9..6d0b180 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -55,7 +55,6 @@
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/net/url_request_mock_util.h"
-#include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/permissions/permission_request_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h"
@@ -2087,9 +2086,6 @@
 
   DownloadAndWait(browser(), download_url);
 
-  // Close the notifications as they would prevent the browser from quitting.
-  g_browser_process->notification_ui_manager()->CancelAll();
-
   content::WindowedNotificationObserver signal(
       chrome::NOTIFICATION_BROWSER_CLOSED,
       content::Source<Browser>(browser()));
@@ -3075,7 +3071,6 @@
       DownloadItem::COMPLETE));
 
   browser()->tab_strip_model()->GetActiveWebContents()->Close();
-  g_browser_process->notification_ui_manager()->CancelAll();
 }
 
 IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadTest_Renaming) {
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
index a2883146..a8348d7 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
@@ -69,8 +69,8 @@
            << " sinks to CastMediaSinkService";
 
   if (dial_sink_added_cb_) {
-    for (const auto& sink : current_sinks_)
-      dial_sink_added_cb_.Run(sink);
+    for (const auto& sink_it : current_sinks_)
+      dial_sink_added_cb_.Run(sink_it.second);
   }
 }
 
@@ -126,7 +126,8 @@
   }
 
   MediaSinkInternal dial_sink(sink, extra_data);
-  current_sinks_.insert(dial_sink);
+  std::string sink_id = dial_sink.sink().id();
+  current_sinks_.insert_or_assign(sink_id, dial_sink);
   if (dial_sink_added_cb_)
     dial_sink_added_cb_.Run(dial_sink);
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
index ff0ca5e..831d917c 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
@@ -71,6 +71,8 @@
   FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest, TestTimer);
   FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                            TestOnDeviceDescriptionAvailable);
+  FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
+                           TestOnDeviceDescriptionAvailableIPAddressChanged);
   FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest, TestRestartAfterStop);
   FRIEND_TEST_ALL_PREFIXES(DialMediaSinkServiceImplTest,
                            OnDialSinkAddedCallback);
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc
index 9e014ba..d191ce49 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc
@@ -107,6 +107,7 @@
   EXPECT_CALL(*mock_description_service_,
               GetDeviceDescriptions(device_list, _));
 
+  EXPECT_CALL(dial_sink_added_cb_, Run(_));
   media_sink_service_->OnDialDeviceEvent(device_list);
   media_sink_service_->OnDeviceDescriptionAvailable(device_data,
                                                     device_description);
@@ -114,6 +115,38 @@
   EXPECT_EQ(1u, media_sink_service_->current_sinks_.size());
 }
 
+TEST_F(DialMediaSinkServiceImplTest,
+       TestOnDeviceDescriptionAvailableIPAddressChanged) {
+  DialDeviceData device_data("first", GURL("http://127.0.0.1/dd.xml"),
+                             base::Time::Now());
+  ParsedDialDeviceDescription device_description;
+  device_description.model_name = "model name";
+  device_description.friendly_name = "friendly name";
+  device_description.app_url = GURL("http://192.168.1.1/apps");
+  device_description.unique_id = "unique id";
+
+  std::vector<DialDeviceData> device_list = {device_data};
+  EXPECT_CALL(*mock_description_service_,
+              GetDeviceDescriptions(device_list, _));
+  media_sink_service_->OnDialDeviceEvent(device_list);
+
+  EXPECT_CALL(dial_sink_added_cb_, Run(_));
+  media_sink_service_->OnDeviceDescriptionAvailable(device_data,
+                                                    device_description);
+  EXPECT_EQ(1u, media_sink_service_->current_sinks_.size());
+
+  EXPECT_CALL(dial_sink_added_cb_, Run(_));
+  device_description.app_url = GURL("http://192.168.1.100/apps");
+  media_sink_service_->OnDeviceDescriptionAvailable(device_data,
+                                                    device_description);
+
+  EXPECT_EQ(1u, media_sink_service_->current_sinks_.size());
+  for (const auto& dial_sink_it : media_sink_service_->current_sinks_) {
+    EXPECT_EQ(device_description.app_url,
+              dial_sink_it.second.dial_data().app_url);
+  }
+}
+
 TEST_F(DialMediaSinkServiceImplTest, TestTimer) {
   DialDeviceData device_data("first", GURL("http://127.0.0.1/dd.xml"),
                              base::Time::Now());
@@ -128,6 +161,7 @@
               GetDeviceDescriptions(device_list, _));
 
   EXPECT_FALSE(mock_timer_->IsRunning());
+  EXPECT_CALL(dial_sink_added_cb_, Run(_));
   media_sink_service_->OnDialDeviceEvent(device_list);
   media_sink_service_->OnDeviceDescriptionAvailable(device_data,
                                                     device_description);
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
index 679ac7d..b3ff166 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
@@ -256,7 +256,8 @@
              << " [name]: " << sink_it.second.sink().name()
              << " [ip_endpoint]: "
              << sink_it.second.cast_data().ip_endpoint.ToString();
-    current_sinks_.insert(sink_it.second);
+    std::string sink_id = sink_it.second.sink().id();
+    current_sinks_.emplace(sink_id, sink_it.second);
   }
 
   MediaSinkServiceBase::OnDiscoveryComplete();
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc
index 904266f6..6521e76 100644
--- a/chrome/browser/metrics/thread_watcher.cc
+++ b/chrome/browser/metrics/thread_watcher.cc
@@ -334,8 +334,9 @@
 const int ThreadWatcherList::kUnresponsiveSeconds = 2;
 // static
 const int ThreadWatcherList::kUnresponsiveCount = 9;
-// static
-const int ThreadWatcherList::kLiveThreadsThreshold = 2;
+// static, configured high to catch single thread hangs
+// TODO(gab): Clean this up, https://crbug.com/804345
+const int ThreadWatcherList::kLiveThreadsThreshold = BrowserThread::ID_COUNT;
 // static, non-const for tests.
 int ThreadWatcherList::g_initialize_delay_seconds = 120;
 
diff --git a/chrome/browser/metrics/ukm_browsertest.cc b/chrome/browser/metrics/ukm_browsertest.cc
index 3cd34e8..63c0c46 100644
--- a/chrome/browser/metrics/ukm_browsertest.cc
+++ b/chrome/browser/metrics/ukm_browsertest.cc
@@ -249,7 +249,7 @@
 }
 
 // Make sure that UKM is disabled while an non-sync profile's window is open.
-IN_PROC_BROWSER_TEST_F(UkmBrowserTest, NonSyncCheck) {
+IN_PROC_BROWSER_TEST_F(UkmBrowserTest, OpenNonSyncCheck) {
   MetricsConsentOverride metrics_consent(true);
 
   Profile* profile = ProfileManager::GetActiveUserProfile();
@@ -491,8 +491,6 @@
   CloseBrowserSynchronously(sync_browser);
 }
 
-// TODO(crbug/745939): Add a tests for disable w/ multiprofiles.
-
 // TODO(crbug/745939): Add a tests for guest profile.
 
 // Make sure that pending data is deleted when user deletes history.
diff --git a/chrome/browser/notifications/notification_display_service_impl.cc b/chrome/browser/notifications/notification_display_service_impl.cc
index cf8fb8b..7d77fd5a 100644
--- a/chrome/browser/notifications/notification_display_service_impl.cc
+++ b/chrome/browser/notifications/notification_display_service_impl.cc
@@ -271,6 +271,31 @@
                         callback);
 }
 
+// Callback to run once the profile has been loaded in order to perform a
+// given |operation| in a notification.
+void NotificationDisplayServiceImpl::ProfileLoadedCallback(
+    NotificationCommon::Operation operation,
+    NotificationHandler::Type notification_type,
+    const GURL& origin,
+    const std::string& notification_id,
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply,
+    const base::Optional<bool>& by_user,
+    Profile* profile) {
+  if (!profile) {
+    // TODO(miguelg): Add UMA for this condition.
+    // Perhaps propagate this through PersistentNotificationStatus.
+    LOG(WARNING) << "Profile not loaded correctly";
+    return;
+  }
+
+  NotificationDisplayServiceImpl* display_service =
+      NotificationDisplayServiceImpl::GetForProfile(profile);
+  display_service->ProcessNotificationOperation(operation, notification_type,
+                                                origin, notification_id,
+                                                action_index, reply, by_user);
+}
+
 void NotificationDisplayServiceImpl::OnNotificationPlatformBridgeReady(
     bool success) {
   if (base::FeatureList::IsEnabled(features::kNativeNotifications)) {
diff --git a/chrome/browser/notifications/notification_display_service_impl.h b/chrome/browser/notifications/notification_display_service_impl.h
index 8a8fc6c..c13a7238 100644
--- a/chrome/browser/notifications/notification_display_service_impl.h
+++ b/chrome/browser/notifications/notification_display_service_impl.h
@@ -70,6 +70,15 @@
              const std::string& notification_id) override;
   void GetDisplayed(const DisplayedNotificationsCallback& callback) override;
 
+  static void ProfileLoadedCallback(NotificationCommon::Operation operation,
+                                    NotificationHandler::Type notification_type,
+                                    const GURL& origin,
+                                    const std::string& notification_id,
+                                    const base::Optional<int>& action_index,
+                                    const base::Optional<base::string16>& reply,
+                                    const base::Optional<bool>& by_user,
+                                    Profile* profile);
+
  private:
   // Called when the NotificationPlatformBridge may have been initialized.
   void OnNotificationPlatformBridgeReady(bool success);
diff --git a/chrome/browser/notifications/notification_platform_bridge_android.cc b/chrome/browser/notifications/notification_platform_bridge_android.cc
index 981bebd..a933acf3 100644
--- a/chrome/browser/notifications/notification_platform_bridge_android.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_android.cc
@@ -108,31 +108,6 @@
   return ScopedJavaLocalRef<jobjectArray>(env, actions);
 }
 
-// Callback to run once the profile has been loaded in order to perform a
-// given |operation| in a notification.
-// TODO(miguelg) move it to notification_common?
-void ProfileLoadedCallback(NotificationCommon::Operation operation,
-                           NotificationHandler::Type notification_type,
-                           const GURL& origin,
-                           const std::string& notification_id,
-                           const base::Optional<int>& action_index,
-                           const base::Optional<base::string16>& reply,
-                           const base::Optional<bool>& by_user,
-                           Profile* profile) {
-  if (!profile) {
-    // TODO(miguelg): Add UMA for this condition.
-    // Perhaps propagate this through PersistentNotificationStatus.
-    LOG(WARNING) << "Profile not loaded correctly";
-    return;
-  }
-
-  NotificationDisplayServiceImpl* display_service =
-      NotificationDisplayServiceImpl::GetForProfile(profile);
-  display_service->ProcessNotificationOperation(operation, notification_type,
-                                                origin, notification_id,
-                                                action_index, reply, by_user);
-}
-
 }  // namespace
 
 // Called by the Java side when a notification event has been received, but the
@@ -201,7 +176,8 @@
 
   profile_manager->LoadProfile(
       profile_id, incognito,
-      base::Bind(&ProfileLoadedCallback, NotificationCommon::CLICK,
+      base::Bind(&NotificationDisplayServiceImpl::ProfileLoadedCallback,
+                 NotificationCommon::CLICK,
                  NotificationHandler::Type::WEB_PERSISTENT, origin,
                  notification_id, std::move(action_index), std::move(reply),
                  base::nullopt /* by_user */));
@@ -247,7 +223,8 @@
 
   profile_manager->LoadProfile(
       profile_id, incognito,
-      base::Bind(&ProfileLoadedCallback, NotificationCommon::CLOSE,
+      base::Bind(&NotificationDisplayServiceImpl::ProfileLoadedCallback,
+                 NotificationCommon::CLOSE,
                  NotificationHandler::Type::WEB_PERSISTENT,
                  GURL(ConvertJavaStringToUTF8(env, java_origin)),
                  notification_id, base::nullopt /* action index */,
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux.cc b/chrome/browser/notifications/notification_platform_bridge_linux.cc
index e879670..57f933f 100644
--- a/chrome/browser/notifications/notification_platform_bridge_linux.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc
@@ -170,26 +170,6 @@
           height)));
 }
 
-// Runs once the profile has been loaded in order to perform a given
-// |operation| on a notification.
-void ProfileLoadedCallback(NotificationCommon::Operation operation,
-                           NotificationHandler::Type notification_type,
-                           const GURL& origin,
-                           const std::string& notification_id,
-                           const base::Optional<int>& action_index,
-                           const base::Optional<base::string16>& reply,
-                           const base::Optional<bool>& by_user,
-                           Profile* profile) {
-  if (!profile)
-    return;
-
-  NotificationDisplayServiceImpl* display_service =
-      NotificationDisplayServiceImpl::GetForProfile(profile);
-  display_service->ProcessNotificationOperation(operation, notification_type,
-                                                origin, notification_id,
-                                                action_index, reply, by_user);
-}
-
 void ForwardNotificationOperationOnUiThread(
     NotificationCommon::Operation operation,
     NotificationHandler::Type notification_type,
@@ -202,9 +182,9 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   g_browser_process->profile_manager()->LoadProfile(
       profile_id, is_incognito,
-      base::Bind(&ProfileLoadedCallback, operation, notification_type, origin,
-                 notification_id, action_index, base::nullopt /* reply */,
-                 by_user));
+      base::Bind(&NotificationDisplayServiceImpl::ProfileLoadedCallback,
+                 operation, notification_type, origin, notification_id,
+                 action_index, base::nullopt /* reply */, by_user));
 }
 
 class ResourceFile {
diff --git a/chrome/browser/notifications/notification_platform_bridge_mac.mm b/chrome/browser/notifications/notification_platform_bridge_mac.mm
index 27424ff..1d4b274c 100644
--- a/chrome/browser/notifications/notification_platform_bridge_mac.mm
+++ b/chrome/browser/notifications/notification_platform_bridge_mac.mm
@@ -64,30 +64,6 @@
 
 namespace {
 
-// Callback to run once the profile has been loaded in order to perform a
-// given |operation| in a notification.
-void ProfileLoadedCallback(NotificationCommon::Operation operation,
-                           NotificationHandler::Type notification_type,
-                           const GURL& origin,
-                           const std::string& notification_id,
-                           const base::Optional<int>& action_index,
-                           const base::Optional<base::string16>& reply,
-                           const base::Optional<bool>& by_user,
-                           Profile* profile) {
-  if (!profile) {
-    // TODO(miguelg): Add UMA for this condition.
-    // Perhaps propagate this through PersistentNotificationStatus.
-    LOG(WARNING) << "Profile not loaded correctly";
-    return;
-  }
-
-  NotificationDisplayServiceImpl* display_service =
-      NotificationDisplayServiceImpl::GetForProfile(profile);
-  display_service->ProcessNotificationOperation(operation, notification_type,
-                                                origin, notification_id,
-                                                action_index, reply, by_user);
-}
-
 // Loads the profile and process the Notification response
 void DoProcessNotificationResponse(NotificationCommon::Operation operation,
                                    NotificationHandler::Type type,
@@ -105,8 +81,9 @@
 
   profileManager->LoadProfile(
       profile_id, incognito,
-      base::Bind(&ProfileLoadedCallback, operation, type, origin,
-                 notification_id, action_index, reply, by_user));
+      base::Bind(&NotificationDisplayServiceImpl::ProfileLoadedCallback,
+                 operation, type, origin, notification_id, action_index, reply,
+                 by_user));
 }
 
 // This enum backs an UMA histogram, so it should be treated as append-only.
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc
index 38c0a73..99d286b 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win.cc
@@ -76,25 +76,6 @@
                                            IID_PPV_ARGS(object));
 }
 
-// Perform |operation| on a notification once the profile has been loaded.
-void ProfileLoadedCallback(NotificationCommon::Operation operation,
-                           NotificationHandler::Type notification_type,
-                           const GURL& origin,
-                           const std::string& notification_id,
-                           const base::Optional<int>& action_index,
-                           const base::Optional<base::string16>& reply,
-                           const base::Optional<bool>& by_user,
-                           Profile* profile) {
-  if (!profile)
-    return;
-
-  NotificationDisplayServiceImpl* display_service =
-      NotificationDisplayServiceImpl::GetForProfile(profile);
-  display_service->ProcessNotificationOperation(operation, notification_type,
-                                                origin, notification_id,
-                                                action_index, reply, by_user);
-}
-
 void ForwardNotificationOperationOnUiThread(
     NotificationCommon::Operation operation,
     NotificationHandler::Type notification_type,
@@ -110,9 +91,9 @@
 
   g_browser_process->profile_manager()->LoadProfile(
       profile_id, incognito,
-      base::Bind(&ProfileLoadedCallback, operation, notification_type, origin,
-                 notification_id, action_index, base::nullopt /*reply*/,
-                 by_user));
+      base::Bind(&NotificationDisplayServiceImpl::ProfileLoadedCallback,
+                 operation, notification_type, origin, notification_id,
+                 action_index, base::nullopt /*reply*/, by_user));
 }
 
 }  // namespace
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 8ef430e2..fe2dd393 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -2955,8 +2955,17 @@
                       "mypassword");
 }
 
+
+// Flaky on Linux. http://crbug.com/804398
+#if defined(OS_LINUX)
+#define MAYBE_InternalsPage_Renderer DISABLED_InternalsPage_Renderer
+#else
+#define MAYBE_InternalsPage_Renderer InternalsPage_Renderer
+#endif
+
 // Check that the internals page contains logs from the renderer.
-IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase, InternalsPage_Renderer) {
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
+    MAYBE_InternalsPage_Renderer) {
   // Open the internals page.
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), GURL("chrome://password-manager-internals"),
diff --git a/chrome/browser/permissions/chooser_context_base.cc b/chrome/browser/permissions/chooser_context_base.cc
index f3a3f47..de73a30 100644
--- a/chrome/browser/permissions/chooser_context_base.cc
+++ b/chrome/browser/permissions/chooser_context_base.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "base/memory/ptr_util.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 
@@ -92,7 +91,7 @@
         continue;
       }
 
-      results.push_back(base::MakeUnique<Object>(
+      results.push_back(std::make_unique<Object>(
           requesting_origin, embedding_origin, object_dict,
           content_setting.source, content_setting.incognito));
     }
@@ -114,7 +113,7 @@
   base::ListValue* object_list;
   if (!setting->GetList(kObjectListKey, &object_list)) {
     object_list =
-        setting->SetList(kObjectListKey, base::MakeUnique<base::ListValue>());
+        setting->SetList(kObjectListKey, std::make_unique<base::ListValue>());
   }
   object_list->AppendIfNotPresent(std::move(object));
   SetWebsiteSetting(requesting_origin, embedding_origin, std::move(setting));
diff --git a/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
index 7986f083..f9a2158 100644
--- a/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
+++ b/chrome/browser/permissions/grouped_permission_infobar_delegate_android.cc
@@ -24,7 +24,7 @@
     const base::WeakPtr<PermissionPromptAndroid>& permission_prompt,
     InfoBarService* infobar_service) {
   return infobar_service->AddInfoBar(
-      base::MakeUnique<GroupedPermissionInfoBar>(base::WrapUnique(
+      std::make_unique<GroupedPermissionInfoBar>(base::WrapUnique(
           new GroupedPermissionInfoBarDelegate(permission_prompt))));
 }
 
diff --git a/chrome/browser/permissions/permission_blacklist_client.cc b/chrome/browser/permissions/permission_blacklist_client.cc
index 8fbaea43..dca26d8 100644
--- a/chrome/browser/permissions/permission_blacklist_client.cc
+++ b/chrome/browser/permissions/permission_blacklist_client.cc
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "base/timer/elapsed_timer.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/permissions/permission_uma_util.h"
@@ -60,7 +59,7 @@
   // Start the timer to interrupt into the client callback method with an
   // empty response if Safe Browsing times out.
   safe_browsing::ThreatMetadata empty_metadata;
-  timer_ = base::MakeUnique<base::OneShotTimer>();
+  timer_ = std::make_unique<base::OneShotTimer>();
   elapsed_timer_.reset(new base::ElapsedTimer());
   timer_->Start(
       FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_),
diff --git a/chrome/browser/permissions/permission_context_base.cc b/chrome/browser/permissions/permission_context_base.cc
index 79f09f5..4fb90ece 100644
--- a/chrome/browser/permissions/permission_context_base.cc
+++ b/chrome/browser/permissions/permission_context_base.cc
@@ -11,7 +11,6 @@
 
 #include "base/callback.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -334,7 +333,7 @@
     return;
 
   std::unique_ptr<PermissionRequest> request_ptr =
-      base::MakeUnique<PermissionRequestImpl>(
+      std::make_unique<PermissionRequestImpl>(
           requesting_origin, content_settings_type_, user_gesture,
           base::Bind(&PermissionContextBase::PermissionDecided,
                      weak_factory_.GetWeakPtr(), id, requesting_origin,
diff --git a/chrome/browser/permissions/permission_context_base_unittest.cc b/chrome/browser/permissions/permission_context_base_unittest.cc
index a8dccba..72a91e06 100644
--- a/chrome/browser/permissions/permission_context_base_unittest.cc
+++ b/chrome/browser/permissions/permission_context_base_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/run_loop.h"
 #include "base/test/histogram_tester.h"
@@ -195,15 +194,15 @@
       Profile* profile,
       const ContentSettingsType content_settings_type)
       : TestPermissionContext(profile, content_settings_type),
-        field_trial_list_(base::MakeUnique<base::FieldTrialList>(
-            base::MakeUnique<base::MockEntropyProvider>())) {}
+        field_trial_list_(std::make_unique<base::FieldTrialList>(
+            std::make_unique<base::MockEntropyProvider>())) {}
 
   void ResetFieldTrialList() {
     // Destroy the existing FieldTrialList before creating a new one to avoid
     // a DCHECK.
     field_trial_list_.reset();
-    field_trial_list_ = base::MakeUnique<base::FieldTrialList>(
-        base::MakeUnique<base::MockEntropyProvider>());
+    field_trial_list_ = std::make_unique<base::FieldTrialList>(
+        std::make_unique<base::MockEntropyProvider>());
     variations::testing::ClearAllVariationParams();
   }
 
@@ -448,7 +447,7 @@
                                                      kPromptGroupName, params));
 
     std::unique_ptr<base::FeatureList> feature_list =
-        base::MakeUnique<base::FeatureList>();
+        std::make_unique<base::FeatureList>();
     feature_list->RegisterFieldTrialOverride(
         features::kBlockPromptsIfDismissedOften.name,
         base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
diff --git a/chrome/browser/permissions/permission_decision_auto_blocker.cc b/chrome/browser/permissions/permission_decision_auto_blocker.cc
index 40916655..8df324d 100644
--- a/chrome/browser/permissions/permission_decision_auto_blocker.cc
+++ b/chrome/browser/permissions/permission_decision_auto_blocker.cc
@@ -9,7 +9,6 @@
 #include <utility>
 
 #include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
@@ -66,7 +65,7 @@
           origin_url, GURL(), CONTENT_SETTINGS_TYPE_PERMISSION_AUTOBLOCKER_DATA,
           std::string(), nullptr));
   if (!dict)
-    return base::MakeUnique<base::DictionaryValue>();
+    return std::make_unique<base::DictionaryValue>();
 
   return dict;
 }
diff --git a/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc b/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc
index 66cdf001..b875400 100644
--- a/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc
+++ b/chrome/browser/permissions/permission_decision_auto_blocker_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/permissions/permission_decision_auto_blocker.h"
 
 #include <map>
+#include <memory>
 
 #include "base/bind.h"
 #include "base/run_loop.h"
@@ -93,7 +94,7 @@
                                    {});
     last_embargoed_status_ = false;
     std::unique_ptr<base::SimpleTestClock> clock =
-        base::MakeUnique<base::SimpleTestClock>();
+        std::make_unique<base::SimpleTestClock>();
     clock_ = clock.get();
     autoblocker_->SetClockForTesting(std::move(clock));
     callback_was_run_ = false;
diff --git a/chrome/browser/permissions/permission_manager.cc b/chrome/browser/permissions/permission_manager.cc
index 4ac3f55..f8d4ed82 100644
--- a/chrome/browser/permissions/permission_manager.cc
+++ b/chrome/browser/permissions/permission_manager.cc
@@ -8,7 +8,6 @@
 #include <utility>
 
 #include "base/callback.h"
-#include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 #include "chrome/browser/accessibility/accessibility_permission_context.h"
 #include "chrome/browser/background_sync/background_sync_permission_context.h"
@@ -259,44 +258,44 @@
 
 PermissionManager::PermissionManager(Profile* profile) : profile_(profile) {
   permission_contexts_[CONTENT_SETTINGS_TYPE_MIDI_SYSEX] =
-      base::MakeUnique<MidiSysexPermissionContext>(profile);
+      std::make_unique<MidiSysexPermissionContext>(profile);
   permission_contexts_[CONTENT_SETTINGS_TYPE_MIDI] =
-      base::MakeUnique<MidiPermissionContext>(profile);
+      std::make_unique<MidiPermissionContext>(profile);
   permission_contexts_[CONTENT_SETTINGS_TYPE_NOTIFICATIONS] =
-      base::MakeUnique<NotificationPermissionContext>(profile);
+      std::make_unique<NotificationPermissionContext>(profile);
 #if !defined(OS_ANDROID)
   permission_contexts_[CONTENT_SETTINGS_TYPE_GEOLOCATION] =
-      base::MakeUnique<GeolocationPermissionContext>(profile);
+      std::make_unique<GeolocationPermissionContext>(profile);
 #else
   permission_contexts_[CONTENT_SETTINGS_TYPE_GEOLOCATION] =
-      base::MakeUnique<GeolocationPermissionContextAndroid>(profile);
+      std::make_unique<GeolocationPermissionContextAndroid>(profile);
 #endif
 #if defined(OS_CHROMEOS) || defined(OS_ANDROID)
   permission_contexts_[CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER] =
-      base::MakeUnique<ProtectedMediaIdentifierPermissionContext>(profile);
+      std::make_unique<ProtectedMediaIdentifierPermissionContext>(profile);
 #endif
   permission_contexts_[CONTENT_SETTINGS_TYPE_DURABLE_STORAGE] =
-      base::MakeUnique<DurableStoragePermissionContext>(profile);
+      std::make_unique<DurableStoragePermissionContext>(profile);
   permission_contexts_[CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC] =
-      base::MakeUnique<MediaStreamDevicePermissionContext>(
+      std::make_unique<MediaStreamDevicePermissionContext>(
           profile, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
   permission_contexts_[CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA] =
-      base::MakeUnique<MediaStreamDevicePermissionContext>(
+      std::make_unique<MediaStreamDevicePermissionContext>(
           profile, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
   permission_contexts_[CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC] =
-      base::MakeUnique<BackgroundSyncPermissionContext>(profile);
+      std::make_unique<BackgroundSyncPermissionContext>(profile);
 #if BUILDFLAG(ENABLE_PLUGINS)
   permission_contexts_[CONTENT_SETTINGS_TYPE_PLUGINS] =
-      base::MakeUnique<FlashPermissionContext>(profile);
+      std::make_unique<FlashPermissionContext>(profile);
 #endif
   permission_contexts_[CONTENT_SETTINGS_TYPE_SENSORS] =
-      base::MakeUnique<SensorPermissionContext>(profile);
+      std::make_unique<SensorPermissionContext>(profile);
   permission_contexts_[CONTENT_SETTINGS_TYPE_ACCESSIBILITY_EVENTS] =
-      base::MakeUnique<AccessibilityPermissionContext>(profile);
+      std::make_unique<AccessibilityPermissionContext>(profile);
   permission_contexts_[CONTENT_SETTINGS_TYPE_CLIPBOARD_READ] =
-      base::MakeUnique<ClipboardReadPermissionContext>(profile);
+      std::make_unique<ClipboardReadPermissionContext>(profile);
   permission_contexts_[CONTENT_SETTINGS_TYPE_CLIPBOARD_WRITE] =
-      base::MakeUnique<ClipboardWritePermissionContext>(profile);
+      std::make_unique<ClipboardWritePermissionContext>(profile);
 }
 
 PermissionManager::~PermissionManager() {
@@ -356,7 +355,7 @@
   GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
   GURL canonical_requesting_origin = GetCanonicalOrigin(requesting_origin);
 
-  int request_id = pending_requests_.Add(base::MakeUnique<PendingRequest>(
+  int request_id = pending_requests_.Add(std::make_unique<PendingRequest>(
       render_frame_host, permissions, callback));
 
   const PermissionRequestID request(render_frame_host, request_id);
@@ -367,7 +366,7 @@
     PermissionContextBase* context = GetPermissionContext(permission);
     DCHECK(context);
     auto callback =
-        base::MakeUnique<PermissionResponseCallback>(this, request_id, i);
+        std::make_unique<PermissionResponseCallback>(this, request_id, i);
     context->RequestPermission(
         web_contents, request, canonical_requesting_origin, user_gesture,
         base::Bind(
@@ -525,7 +524,7 @@
     HostContentSettingsMapFactory::GetForProfile(profile_)->AddObserver(this);
 
   ContentSettingsType content_type = PermissionTypeToContentSetting(permission);
-  auto subscription = base::MakeUnique<Subscription>();
+  auto subscription = std::make_unique<Subscription>();
   subscription->permission = content_type;
   subscription->requesting_origin = GetCanonicalOrigin(requesting_origin);
   subscription->embedding_origin = embedding_origin;
diff --git a/chrome/browser/permissions/permission_manager_unittest.cc b/chrome/browser/permissions/permission_manager_unittest.cc
index f8e284dd5..6937b0e 100644
--- a/chrome/browser/permissions/permission_manager_unittest.cc
+++ b/chrome/browser/permissions/permission_manager_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/permissions/permission_manager.h"
 
+#include <memory>
+
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -452,7 +454,7 @@
   PermissionRequestManager::CreateForWebContents(contents);
   PermissionRequestManager* manager =
       PermissionRequestManager::FromWebContents(contents);
-  auto prompt_factory = base::MakeUnique<MockPermissionPromptFactory>(manager);
+  auto prompt_factory = std::make_unique<MockPermissionPromptFactory>(manager);
 
   NavigateAndCommit(url());
 
diff --git a/chrome/browser/permissions/permission_prompt_android.cc b/chrome/browser/permissions/permission_prompt_android.cc
index e2563aca..8342231 100644
--- a/chrome/browser/permissions/permission_prompt_android.cc
+++ b/chrome/browser/permissions/permission_prompt_android.cc
@@ -4,7 +4,8 @@
 
 #include "chrome/browser/permissions/permission_prompt_android.h"
 
-#include "base/memory/ptr_util.h"
+#include <memory>
+
 #include "chrome/browser/android/android_theme_resources.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/permissions/grouped_permission_infobar_delegate_android.h"
@@ -115,5 +116,5 @@
 std::unique_ptr<PermissionPrompt> PermissionPrompt::Create(
     content::WebContents* web_contents,
     Delegate* delegate) {
-  return base::MakeUnique<PermissionPromptAndroid>(web_contents, delegate);
+  return std::make_unique<PermissionPromptAndroid>(web_contents, delegate);
 }
diff --git a/chrome/browser/permissions/permission_request_manager_browsertest.cc b/chrome/browser/permissions/permission_request_manager_browsertest.cc
index 6db3857..aafcd66 100644
--- a/chrome/browser/permissions/permission_request_manager_browsertest.cc
+++ b/chrome/browser/permissions/permission_request_manager_browsertest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/permissions/permission_request_manager.h"
 
+#include <memory>
+
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/run_loop.h"
@@ -137,7 +139,7 @@
   bool user_gesture = true;
   auto decided = [](ContentSetting) {};
   auto cleanup = [] {};  // Leave cleanup to test harness destructor.
-  owned_requests_.push_back(base::MakeUnique<PermissionRequestImpl>(
+  owned_requests_.push_back(std::make_unique<PermissionRequestImpl>(
       GetUrl(), permission, user_gesture, base::Bind(decided),
       base::Bind(cleanup)));
   return owned_requests_.back().get();
@@ -333,7 +335,7 @@
   // SetUp() only creates a mock prompt factory for the first tab.
   MockPermissionPromptFactory* bubble_factory_0 = bubble_factory();
   std::unique_ptr<MockPermissionPromptFactory> bubble_factory_1(
-      base::MakeUnique<MockPermissionPromptFactory>(
+      std::make_unique<MockPermissionPromptFactory>(
           GetPermissionRequestManager()));
 
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
diff --git a/chrome/browser/permissions/permission_request_manager_test_api.cc b/chrome/browser/permissions/permission_request_manager_test_api.cc
index c8e4171c..3f36862 100644
--- a/chrome/browser/permissions/permission_request_manager_test_api.cc
+++ b/chrome/browser/permissions/permission_request_manager_test_api.cc
@@ -21,7 +21,7 @@
   explicit TestPermisisonRequestOwner(ContentSettingsType type) {
     bool user_gesture = true;
     auto decided = [](ContentSetting) {};
-    request_ = base::MakeUnique<PermissionRequestImpl>(
+    request_ = std::make_unique<PermissionRequestImpl>(
         GURL("https://example.com"), type, user_gesture, base::Bind(decided),
         base::Bind(&TestPermisisonRequestOwner::DeleteThis,
                    base::Unretained(this)));
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 7470c14..c8826a9 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -265,9 +265,6 @@
   { key::kEnableSha1ForLocalAnchors,
     ssl_config::prefs::kCertEnableSha1LocalAnchors,
     base::Value::Type::BOOLEAN },
-  { key::kEnableCommonNameFallbackForLocalAnchors,
-    ssl_config::prefs::kCertEnableCommonNameFallbackLocalAnchors,
-    base::Value::Type::BOOLEAN },
   { key::kAuthSchemes,
     prefs::kAuthSchemes,
     base::Value::Type::STRING },
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 872e0ae..a7aa16a9 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -1415,6 +1415,79 @@
   EXPECT_FALSE(is_toggle_dev_mode_checkbox_enabled);
 }
 
+// TODO(dpapad): Remove the "_MD" suffix once the non-MD test is deleted.
+IN_PROC_BROWSER_TEST_F(PolicyTest, DeveloperToolsDisabledExtensionsDevMode_MD) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {features::kMaterialDesignExtensions} /* enabled */, {} /* disabled */);
+
+  // Verifies that when DeveloperToolsDisabled policy is set, the "dev mode"
+  // in chrome://extensions is actively turned off and the checkbox
+  // is disabled.
+  // Note: We don't test the indicator as it is tested in the policy pref test
+  // for kDeveloperToolsDisabled.
+
+  // This test depends on the following helper methods to locate the DOM elemens
+  // to be tested.
+  const char define_helpers_js[] =
+      R"(function getToolbar() {
+           const manager = document.querySelector('extensions-manager');
+           return manager.$$('extensions-toolbar');
+         }
+
+         function getToggle() {
+           return getToolbar().$$('#dev-mode');
+         }
+
+         function getControls() {
+           return getToolbar().$$('#devDrawer');
+         }
+        )";
+
+  const char toggle_dev_mode_accessor_js[] = "getToggle()";
+  const char dev_controls_accessor_js[] = "getControls()";
+  const char dev_controls_visibility_check_js[] =
+      "getControls().hasAttribute('expanded')";
+
+  // Navigate to the extensions frame and enabled "Developer mode"
+  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIExtensionsURL));
+
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_TRUE(
+      content::ExecuteScript(contents, base::StringPrintf(define_helpers_js)));
+
+  EXPECT_TRUE(content::ExecuteScript(
+      contents, base::StringPrintf("domAutomationController.send(%s.click());",
+                                   toggle_dev_mode_accessor_js)));
+
+  WaitForExtensionsDevModeControlsVisibility(contents, dev_controls_accessor_js,
+                                             dev_controls_visibility_check_js,
+                                             true);
+
+  // Disable devtools via policy.
+  PolicyMap policies;
+  policies.Set(key::kDeveloperToolsDisabled, POLICY_LEVEL_MANDATORY,
+               POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+               std::make_unique<base::Value>(true), nullptr);
+  UpdateProviderPolicy(policies);
+
+  // Expect devcontrols to be hidden now...
+  WaitForExtensionsDevModeControlsVisibility(contents, dev_controls_accessor_js,
+                                             dev_controls_visibility_check_js,
+                                             false);
+
+  // ... and checkbox is disabled
+  bool is_toggle_dev_mode_checkbox_disabled = false;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      contents,
+      base::StringPrintf(
+          "domAutomationController.send(%s.hasAttribute('disabled'))",
+          toggle_dev_mode_accessor_js),
+      &is_toggle_dev_mode_checkbox_disabled));
+  EXPECT_TRUE(is_toggle_dev_mode_checkbox_disabled);
+}
+
 // TODO(samarth): remove along with rest of NTP4 code.
 IN_PROC_BROWSER_TEST_F(PolicyTest, DISABLED_WebStoreIconHidden) {
   // Verifies that the web store icons can be hidden from the new tab page.
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc
index 06bf157b..ae9ed60 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.cc
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -1,3 +1,4 @@
+
 // Copyright (c) 2012 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.
@@ -33,9 +34,6 @@
 #include "net/http/http_cache.h"
 #include "net/http/http_network_session.h"
 #include "net/http/http_server_properties_impl.h"
-#include "net/network_error_logging/network_error_logging_service.h"
-#include "net/reporting/reporting_policy.h"
-#include "net/reporting/reporting_service.h"
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/default_channel_id_store.h"
 #include "net/url_request/url_request_context.h"
@@ -280,16 +278,6 @@
       std::move(protocol_handler_interceptor), context->network_delegate(),
       context->host_resolver());
   context->SetJobFactory(std::move(top_job_factory));
-  if (context->reporting_service()) {
-    context->SetReportingService(net::ReportingService::Create(
-        context->reporting_service()->GetPolicy(), context));
-  }
-  if (context->network_error_logging_delegate()) {
-    context->SetNetworkErrorLoggingDelegate(
-        net::NetworkErrorLoggingService::Create());
-    context->network_error_logging_delegate()->SetReportingService(
-        context->reporting_service());
-  }
   return context;
 }
 
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index 7ce7a49..a9afe2e2 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -50,6 +50,7 @@
 #include "extensions/common/value_builder.h"
 #include "net/base/net_errors.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/reporting/reporting_feature.h"
 #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"
@@ -59,7 +60,6 @@
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
-#include "services/network/public/cpp/network_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -560,10 +560,6 @@
     EXPECT_NE(extension_context->reporting_service(),
               main_context->reporting_service());
   }
-  if (extension_context->network_error_logging_delegate()) {
-    EXPECT_NE(extension_context->network_error_logging_delegate(),
-              main_context->network_error_logging_delegate());
-  }
 
   // Check that the ChannelIDService in the HttpNetworkSession is the same as
   // the one directly on the URLRequestContext.
@@ -587,8 +583,7 @@
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      {features::kReporting, features::kNetworkErrorLogging}, {});
+  feature_list.InitAndEnableFeature(features::kReporting);
 
   MockProfileDelegate delegate;
   EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
@@ -628,8 +623,7 @@
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      {features::kReporting, features::kNetworkErrorLogging}, {});
+  feature_list.InitAndEnableFeature(features::kReporting);
 
   MockProfileDelegate delegate;
   EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index e3a3ff4..558f516 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -68,7 +68,7 @@
 #include "net/http/http_network_session.h"
 #include "net/http/http_server_properties.h"
 #include "net/http/http_server_properties_manager.h"
-#include "net/network_error_logging/network_error_logging_service.h"
+#include "net/reporting/reporting_feature.h"
 #include "net/reporting/reporting_policy.h"
 #include "net/reporting/reporting_service.h"
 #include "net/ssl/channel_id_service.h"
@@ -479,6 +479,8 @@
   SetUpJobFactoryDefaultsForBuilder(
       builder, std::move(request_interceptors),
       std::move(profile_params->protocol_handler_interceptor));
+
+  builder->set_reporting_policy(MaybeCreateReportingPolicy());
 }
 
 void ProfileImplIOData::OnMainRequestContextCreated(
@@ -576,7 +578,7 @@
 
   // Build a new HttpNetworkSession that uses the new ChannelIDService.
   // TODO(mmenke):  It's weird to combine state from
-  // main_request_context_storage() objects and the argument to this method,
+  // main_request_context_storage() objects and the argumet to this method,
   // |main_context|.  Remove |main_context| as an argument, and just use
   // main_context() instead.
   net::HttpNetworkSession* network_session =
@@ -613,17 +615,7 @@
           context->host_resolver()));
   context->SetJobFactory(std::move(top_job_factory));
 
-  if (context->reporting_service()) {
-    context->SetReportingService(net::ReportingService::Create(
-        context->reporting_service()->GetPolicy(), context));
-  }
-
-  if (context->network_error_logging_delegate()) {
-    context->SetNetworkErrorLoggingDelegate(
-        net::NetworkErrorLoggingService::Create());
-    context->network_error_logging_delegate()->SetReportingService(
-        context->reporting_service());
-  }
+  context->SetReportingService(MaybeCreateReportingService(context));
 
   return context;
 }
@@ -712,3 +704,22 @@
 chrome_browser_net::Predictor* ProfileImplIOData::GetPredictor() {
   return predictor_.get();
 }
+
+std::unique_ptr<net::ReportingService>
+ProfileImplIOData::MaybeCreateReportingService(
+    net::URLRequestContext* url_request_context) const {
+  std::unique_ptr<net::ReportingPolicy> reporting_policy(
+      MaybeCreateReportingPolicy());
+  if (!reporting_policy)
+    return std::unique_ptr<net::ReportingService>();
+
+  return net::ReportingService::Create(*reporting_policy, url_request_context);
+}
+
+std::unique_ptr<net::ReportingPolicy>
+ProfileImplIOData::MaybeCreateReportingPolicy() {
+  if (!base::FeatureList::IsEnabled(features::kReporting))
+    return std::unique_ptr<net::ReportingPolicy>();
+
+  return base::MakeUnique<net::ReportingPolicy>();
+}
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 85f02a3c..47f10c48 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -105,7 +105,6 @@
 #include "net/url_request/data_protocol_handler.h"
 #include "net/url_request/file_protocol_handler.h"
 #include "net/url_request/ftp_protocol_handler.h"
-#include "net/url_request/network_error_logging_delegate.h"
 #include "net/url_request/report_sender.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
@@ -629,16 +628,8 @@
   set_reporting_service(reporting_service_.get());
 }
 
-void ProfileIOData::AppRequestContext::SetNetworkErrorLoggingDelegate(
-    std::unique_ptr<net::NetworkErrorLoggingDelegate>
-        network_error_logging_delegate) {
-  network_error_logging_delegate_ = std::move(network_error_logging_delegate);
-  set_network_error_logging_delegate(network_error_logging_delegate_.get());
-}
-
 ProfileIOData::AppRequestContext::~AppRequestContext() {
-  SetNetworkErrorLoggingDelegate(nullptr);
-  SetReportingService(nullptr);
+  SetReportingService(std::unique_ptr<net::ReportingService>());
   AssertNoURLRequests();
 }
 
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 934d1db..cdd85d6 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -81,7 +81,6 @@
 class ClientCertStore;
 class CookieStore;
 class HttpTransactionFactory;
-class NetworkErrorLoggingDelegate;
 class ReportingService;
 class ReportSender;
 class SSLConfigService;
@@ -301,9 +300,6 @@
     void SetJobFactory(std::unique_ptr<net::URLRequestJobFactory> job_factory);
     void SetReportingService(
         std::unique_ptr<net::ReportingService> reporting_service);
-    void SetNetworkErrorLoggingDelegate(
-        std::unique_ptr<net::NetworkErrorLoggingDelegate>
-            network_error_logging_delegate);
 
    private:
     ~AppRequestContext() override;
@@ -314,8 +310,6 @@
     std::unique_ptr<net::HttpTransactionFactory> http_factory_;
     std::unique_ptr<net::URLRequestJobFactory> job_factory_;
     std::unique_ptr<net::ReportingService> reporting_service_;
-    std::unique_ptr<net::NetworkErrorLoggingDelegate>
-        network_error_logging_delegate_;
   };
 
   // Created on the UI thread, read on the IO thread during ProfileIOData lazy
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index c4c0bfe..9bdd106 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -27,35 +27,6 @@
 
 
 /**
- * The different sources where an NTP tile's title can originate from.
- * Note: Keep in sync with components/ntp_tiles/tile_title_source.h
- * @enum {number}
- * @const
- */
-var TileTitleSource = {
-  UNKNOWN: 0,
-  MANIFEST: 1,
-  META_TAG: 2,
-  TITLE: 3,
-  INFERRED: 4
-};
-
-
-/**
- * The different sources that an NTP tile can have.
- * Note: Keep in sync with components/ntp_tiles/tile_source.h
- * @enum {number}
- * @const
- */
-var TileSource = {
-  TOP_SITES: 0,
-  SUGGESTIONS_SERVICE: 1,
-  POPULAR: 3,
-  WHITELIST: 4,
-};
-
-
-/**
  * The different (visual) types that an NTP tile can have.
  * Note: Keep in sync with components/ntp_tiles/tile_visual_type.h
  * @enum {number}
@@ -128,9 +99,11 @@
 /**
  * Log impression of an NTP tile.
  * @param {number} tileIndex Position of the tile, >= 0 and < NUMBER_OF_TILES.
- * @param {number} tileTitleSource The title's source from TileTitleSource.
- * @param {number} tileSource The source from TileSource.
- * @param {number} tileType The type from TileVisualType.
+ * @param {number} tileTitleSource The source of the tile's title as received
+ *                 from getMostVisitedItemData.
+ * @param {number} tileSource The tile's source as received from
+ *                 getMostVisitedItemData.
+ * @param {number} tileType The tile's visual type from TileVisualType.
  * @param {Date} dataGenerationTime Timestamp representing when the tile was
  *               produced by a ranking algorithm.
  */
@@ -143,9 +116,11 @@
 /**
  * Log click on an NTP tile.
  * @param {number} tileIndex Position of the tile, >= 0 and < NUMBER_OF_TILES.
- * @param {number} tileTitleSource The title's source from TileTitleSource.
- * @param {number} tileSource The source from TileSource.
- * @param {number} tileType The type from TileVisualType.
+ * @param {number} tileTitleSource The source of the tile's title as received
+ *                 from getMostVisitedItemData.
+ * @param {number} tileSource The tile's source as received from
+ *                 getMostVisitedItemData.
+ * @param {number} tileType The tile's visual type from TileVisualType.
  * @param {Date} dataGenerationTime Timestamp representing when the tile was
  *               produced by a ranking algorithm.
  */
diff --git a/chrome/browser/signin/account_consistency_mode_manager.cc b/chrome/browser/signin/account_consistency_mode_manager.cc
index f7d38fcd..3702c70b 100644
--- a/chrome/browser/signin/account_consistency_mode_manager.cc
+++ b/chrome/browser/signin/account_consistency_mode_manager.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_thread.h"
 
 namespace {
 
@@ -76,6 +77,9 @@
 // static
 bool AccountConsistencyModeManager::IsDiceEnabledForProfile(
     const Profile* profile) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(profile);
+
   return profile->GetProfileType() == Profile::ProfileType::REGULAR_PROFILE &&
          signin::IsDiceEnabledForProfile(profile->GetPrefs());
 }
@@ -93,3 +97,16 @@
          profile_->GetPrefs()->GetBoolean(kDiceMigrationOnStartupPref);
 }
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+
+// static
+bool AccountConsistencyModeManager::IsMirrorEnabledForProfile(
+    const Profile* profile) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(profile);
+
+#if defined(OS_CHROMEOS)
+  return profile->IsChild();
+#else
+  return signin::IsAccountConsistencyMirrorEnabled();
+#endif
+}
diff --git a/chrome/browser/signin/account_consistency_mode_manager.h b/chrome/browser/signin/account_consistency_mode_manager.h
index 19390de..182361a 100644
--- a/chrome/browser/signin/account_consistency_mode_manager.h
+++ b/chrome/browser/signin/account_consistency_mode_manager.h
@@ -33,8 +33,16 @@
   // If true, then account management is done through Gaia webpages.
   // Can only be used on the UI thread.
   // Returns false if |profile| is in Guest or Incognito mode.
+  // A given |profile| will have only one of Mirror or Dice consistency
+  // behaviour enabled.
   static bool IsDiceEnabledForProfile(const Profile* profile);
 
+  // Returns |true| if Mirror account consistency is enabled for |profile|.
+  // Can only be used on the UI thread.
+  // A given |profile| will have only one of Mirror or Dice consistency
+  // behaviour enabled.
+  static bool IsMirrorEnabledForProfile(const Profile* profile);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(AccountConsistencyModeManagerTest,
                            MigrateAtCreation);
diff --git a/chrome/browser/signin/account_consistency_mode_manager_unittest.cc b/chrome/browser/signin/account_consistency_mode_manager_unittest.cc
index 49486e73..137c424c 100644
--- a/chrome/browser/signin/account_consistency_mode_manager_unittest.cc
+++ b/chrome/browser/signin/account_consistency_mode_manager_unittest.cc
@@ -5,10 +5,12 @@
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/test/scoped_feature_list.h"
 #include "build/buildflag.h"
 #include "chrome/browser/prefs/browser_prefs.h"
+#include "chrome/browser/supervised_user/supervised_user_constants.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/prefs/pref_notifier_impl.h"
 #include "components/prefs/testing_pref_store.h"
@@ -91,3 +93,41 @@
   EXPECT_TRUE(signin::IsDiceEnabledForProfile(profile->GetPrefs()));
 }
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+
+#if defined(OS_CHROMEOS)
+TEST(AccountConsistencyModeManagerTest, MirrorDisabledForNonUnicorn) {
+  // Creation of this object sets the current thread's id as UI thread.
+  content::TestBrowserThreadBundle test_thread_bundle;
+
+  TestingProfile profile;
+  EXPECT_FALSE(
+      AccountConsistencyModeManager::IsMirrorEnabledForProfile(&profile));
+}
+
+TEST(AccountConsistencyModeManagerTest, MirrorEnabledForUnicorn) {
+  // Creation of this object sets the current thread's id as UI thread.
+  content::TestBrowserThreadBundle test_thread_bundle;
+
+  TestingProfile profile;
+  profile.SetSupervisedUserId(supervised_users::kChildAccountSUID);
+  EXPECT_TRUE(
+      AccountConsistencyModeManager::IsMirrorEnabledForProfile(&profile));
+}
+#endif
+
+#if BUILDFLAG(ENABLE_MIRROR)
+TEST(AccountConsistencyModeManagerTest, MirrorEnabled) {
+  // Creation of this object sets the current thread's id as UI thread.
+  content::TestBrowserThreadBundle test_thread_bundle;
+
+  // Test that Mirror is enabled for regular accounts.
+  TestingProfile profile;
+  EXPECT_TRUE(
+      AccountConsistencyModeManager::IsMirrorEnabledForProfile(&profile));
+
+  // Test that Mirror is enabled for child accounts.
+  profile.SetSupervisedUserId(supervised_users::kChildAccountSUID);
+  EXPECT_TRUE(
+      AccountConsistencyModeManager::IsMirrorEnabledForProfile(&profile));
+}
+#endif
diff --git a/chrome/browser/signin/account_fetcher_service_factory.cc b/chrome/browser/signin/account_fetcher_service_factory.cc
index f009533..0bf902d 100644
--- a/chrome/browser/signin/account_fetcher_service_factory.cc
+++ b/chrome/browser/signin/account_fetcher_service_factory.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/suggestions/image_decoder_impl.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -48,6 +49,7 @@
   AccountFetcherService* service = new AccountFetcherService();
   service->Initialize(ChromeSigninClientFactory::GetForProfile(profile),
                       ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-                      AccountTrackerServiceFactory::GetForProfile(profile));
+                      AccountTrackerServiceFactory::GetForProfile(profile),
+                      std::make_unique<suggestions::ImageDecoderImpl>());
   return service;
 }
diff --git a/chrome/browser/signin/account_reconcilor_factory.cc b/chrome/browser/signin/account_reconcilor_factory.cc
index e7b6195..f1a2858 100644
--- a/chrome/browser/signin/account_reconcilor_factory.cc
+++ b/chrome/browser/signin/account_reconcilor_factory.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -63,6 +64,12 @@
 // static
 std::unique_ptr<signin::AccountReconcilorDelegate>
 AccountReconcilorFactory::CreateAccountReconcilorDelegate(Profile* profile) {
+  if (AccountConsistencyModeManager::IsMirrorEnabledForProfile(profile)) {
+    return std::make_unique<signin::MirrorAccountReconcilorDelegate>(
+        SigninManagerFactory::GetForProfile(profile));
+  }
+  // TODO(droger): Remove this switch case. |AccountConsistencyModeManager| is
+  // the source of truth.
   switch (signin::GetAccountConsistencyMethod()) {
     case signin::AccountConsistencyMethod::kMirror:
       return std::make_unique<signin::MirrorAccountReconcilorDelegate>(
diff --git a/chrome/browser/signin/fake_account_fetcher_service_builder.cc b/chrome/browser/signin/fake_account_fetcher_service_builder.cc
index 36605c8..4823cf4 100644
--- a/chrome/browser/signin/fake_account_fetcher_service_builder.cc
+++ b/chrome/browser/signin/fake_account_fetcher_service_builder.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/signin/fake_account_fetcher_service_builder.h"
 
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/suggestions/image_decoder_impl.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -18,6 +19,7 @@
   Profile* profile = Profile::FromBrowserContext(context);
   service->Initialize(ChromeSigninClientFactory::GetForProfile(profile),
                       ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-                      AccountTrackerServiceFactory::GetForProfile(profile));
+                      AccountTrackerServiceFactory::GetForProfile(profile),
+                      std::make_unique<suggestions ::ImageDecoderImpl>());
   return std::unique_ptr<KeyedService>(service);
 }
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc
index fe74ea3..dae322b 100644
--- a/chrome/browser/signin/signin_ui_util.cc
+++ b/chrome/browser/signin/signin_ui_util.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/signin/signin_global_error_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/common/pref_names.h"
@@ -31,6 +32,11 @@
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/text_elider.h"
 
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+#include "chrome/browser/signin/account_consistency_mode_manager.h"
+#include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h"
+#endif
+
 namespace signin_ui_util {
 
 base::string16 GetAuthenticatedUsername(const SigninManagerBase* signin) {
@@ -81,6 +87,7 @@
   return email;
 }
 
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
 // TODO(tangltom): Add a unit test for this function.
 std::vector<AccountInfo> GetAccountsForDicePromos(Profile* profile) {
   // Fetch account ids for accounts that have a token.
@@ -113,4 +120,40 @@
   return accounts;
 }
 
+void EnableSync(Browser* browser,
+                const AccountInfo& account,
+                signin_metrics::AccessPoint access_point) {
+  DCHECK(browser);
+  DCHECK(!account.account_id.empty());
+  DCHECK(!account.email.empty());
+  DCHECK_NE(signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN, access_point);
+
+  Profile* profile = browser->profile();
+  DCHECK(AccountConsistencyModeManager::IsDiceEnabledForProfile(profile));
+  if (SigninManagerFactory::GetForProfile(profile)->IsAuthenticated()) {
+    DVLOG(1) << "There is already a primary account.";
+    return;
+  }
+
+  ProfileOAuth2TokenService* token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
+  bool needs_reauth_before_enable_sync =
+      !token_service->RefreshTokenIsAvailable(account.account_id) ||
+      token_service->RefreshTokenHasError(account.account_id);
+  if (needs_reauth_before_enable_sync) {
+    browser->signin_view_controller()->ShowDiceSigninTab(
+        profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, browser, access_point,
+        account.email);
+    return;
+  }
+
+  // DiceTurnSyncOnHelper is suicidal (it will delete itself once it finishes
+  // enabling sync).
+  new DiceTurnSyncOnHelper(
+      profile, browser, access_point,
+      signin_metrics::Reason::REASON_UNKNOWN_REASON, account.account_id,
+      DiceTurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT);
+}
+#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+
 }  // namespace signin_ui_util
diff --git a/chrome/browser/signin/signin_ui_util.h b/chrome/browser/signin/signin_ui_util.h
index d0ceb21..5eea8a1 100644
--- a/chrome/browser/signin/signin_ui_util.h
+++ b/chrome/browser/signin/signin_ui_util.h
@@ -9,9 +9,13 @@
 #include <vector>
 
 #include "base/strings/string16.h"
+#include "build/buildflag.h"
 #include "components/signin/core/browser/account_info.h"
+#include "components/signin/core/browser/signin_features.h"
+#include "components/signin/core/browser/signin_metrics.h"
 
 class Profile;
+class Browser;
 class SigninManagerBase;
 
 // Utility functions to gather status information from the various signed in
@@ -31,6 +35,7 @@
 // Shows a learn more page for signin errors.
 void ShowSigninErrorLearnMorePage(Profile* profile);
 
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
 // Returns the display email string for the given account.  If the profile
 // has not been migrated to use gaia ids, then its possible for the display
 // to not ne known yet.  In this case, use |account_id|, which is assumed to
@@ -41,6 +46,16 @@
 // the Gaia cookies will be the first account in the list.
 std::vector<AccountInfo> GetAccountsForDicePromos(Profile* profile);
 
+// Enables sync for |account| if the refresh token is valid or presents the
+// Chrome sign-in page with |account.email| prefilled if the token is missing
+// or invalid.
+//
+// Note: This function does nothing if the user is already signed in to Chrome.
+void EnableSync(Browser* browser,
+                const AccountInfo& account,
+                signin_metrics::AccessPoint access_point);
+#endif
+
 }  // namespace signin_ui_util
 
 #endif  // CHROME_BROWSER_SIGNIN_SIGNIN_UI_UTIL_H_
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 8c5895bd..4fc7638 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -1920,24 +1920,6 @@
       net::CERT_STATUS_COMMON_NAME_INVALID, AuthState::SHOWING_INTERSTITIAL);
 }
 
-IN_PROC_BROWSER_TEST_P(SSLUITest, CommonNamePrefsCanEnable) {
-  bool net::SSLConfig::*member =
-      &net::SSLConfig::common_name_fallback_local_anchors_enabled;
-
-  ASSERT_NO_FATAL_FAILURE(EnablePolicy(
-      policy::key::kEnableCommonNameFallbackForLocalAnchors,
-      ssl_config::prefs::kCertEnableCommonNameFallbackLocalAnchors));
-  ASSERT_NO_FATAL_FAILURE(
-      CheckSSLConfig(browser()->profile()->GetRequestContext(), member, true));
-
-  ASSERT_TRUE(https_server_common_name_only_.Start());
-  ui_test_utils::NavigateToURL(
-      browser(), https_server_common_name_only_.GetURL("/ssl/google.html"));
-
-  CheckAuthenticatedState(browser()->tab_strip_model()->GetActiveWebContents(),
-                          AuthState::NONE);
-}
-
 IN_PROC_BROWSER_TEST_P(SSLUITest, SymantecEnforcementIsNotDisabled) {
   bool net::SSLConfig::*member = &net::SSLConfig::symantec_enforcement_disabled;
   ASSERT_NO_FATAL_FAILURE(
diff --git a/chrome/browser/supervised_user/experimental/safe_search_url_reporter.cc b/chrome/browser/supervised_user/experimental/safe_search_url_reporter.cc
index a13d641f..d00389642 100644
--- a/chrome/browser/supervised_user/experimental/safe_search_url_reporter.cc
+++ b/chrome/browser/supervised_user/experimental/safe_search_url_reporter.cc
@@ -33,9 +33,6 @@
 
 const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s";
 
-// Request keys
-const char kUrlKey[] = "url";
-
 struct SafeSearchURLReporter::Report {
   Report(const GURL& url, const SuccessCallback& callback, int url_fetcher_id);
   ~Report();
@@ -149,7 +146,7 @@
       base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str()));
 
   base::DictionaryValue dict;
-  dict.SetKey(kUrlKey, base::Value((*it)->url.spec()));
+  dict.SetKey("url", base::Value((*it)->url.spec()));
 
   std::string body;
   base::JSONWriter::Write(dict, &body);
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
index b5e12b6..fc374060 100644
--- a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h"
 
 #include "build/buildflag.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -14,11 +13,10 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/signin/core/browser/signin_features.h"
-#include "components/signin/core/browser/signin_manager.h"
 
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
-#include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h"
+#include "chrome/browser/signin/signin_ui_util.h"
 #endif
 
 BookmarkBubbleSignInDelegate::BookmarkBubbleSignInDelegate(Browser* browser)
@@ -37,28 +35,17 @@
       browser_, signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE);
 }
 
-void BookmarkBubbleSignInDelegate::EnableSync(const AccountInfo& account) {
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
-  DCHECK(AccountConsistencyModeManager::IsDiceEnabledForProfile(profile_));
-
-  if (SigninManagerFactory::GetForProfile(profile_)->IsAuthenticated())
-    return;
-
+void BookmarkBubbleSignInDelegate::EnableSync(const AccountInfo& account) {
   EnsureBrowser();
-  // DiceTurnSyncOnHelper is suicidal (it will delete itself once it finishes
-  // enabling sync).
-  new DiceTurnSyncOnHelper(
-      profile_, browser_,
-      signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE,
-      signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT, account.account_id,
-      DiceTurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT);
+  signin_ui_util::EnableSync(
+      browser_, account,
+      signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE);
 
-// TODO(msarda): Close the bookmarks bubble once the enable sync flow has
-// started.
-#else
-  NOTREACHED();
-#endif
+  // TODO(msarda): Close the bookmarks bubble once the enable sync flow has
+  // started.
 }
+#endif
 
 void BookmarkBubbleSignInDelegate::OnBrowserRemoved(Browser* browser) {
   if (browser == browser_)
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h
index fafbf6c..65a1e19 100644
--- a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h
+++ b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h
@@ -25,7 +25,9 @@
 
   // BubbleSyncPromoDelegate:
   void ShowBrowserSignin() override;
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
   void EnableSync(const AccountInfo& account) override;
+#endif
 
   // BrowserListObserver:
   void OnBrowserRemoved(Browser* browser) override;
diff --git a/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm b/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm
index f2c956c..0514c62 100644
--- a/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm
+++ b/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_unittest.mm
@@ -131,7 +131,7 @@
   }
 
   void TearDown() override {
-    [browser_window_controller_ close];
+    [[browser_window_controller_ nsWindowController] close];
     CocoaProfileTest::TearDown();
   }
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
index 9fa797e..63259ffe 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
@@ -396,8 +396,9 @@
 }
 
 - (LocationBarDecoration*)decorationForBubble {
-  LocationBarViewMac* locationBar =
-      [[[self parentWindow] windowController] locationBarBridge];
+  BrowserWindowController* browserWindowController = [BrowserWindowController
+      browserWindowControllerForWindow:[self parentWindow]];
+  LocationBarViewMac* locationBar = [browserWindowController locationBarBridge];
   return locationBar ? locationBar->star_decoration() : nullptr;
 }
 
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm b/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
index 76a34bc0..ceac777 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa_unittest.mm
@@ -30,7 +30,7 @@
   }
 
   void TearDown() override {
-    [controller_ close];
+    [[controller_ nsWindowController] close];
     CocoaProfileTest::TearDown();
   }
 
diff --git a/chrome/browser/ui/cocoa/browser_window_command_handler.mm b/chrome/browser/ui/cocoa/browser_window_command_handler.mm
index e68b691..1a1ff7a 100644
--- a/chrome/browser/ui/cocoa/browser_window_command_handler.mm
+++ b/chrome/browser/ui/cocoa/browser_window_command_handler.mm
@@ -95,7 +95,9 @@
 // TODO(jackhou): Remove the dependency on BrowserWindowController(Private).
 NSString* GetTitleForFullscreenMenuItem(Browser* browser) {
   NSWindow* ns_window = browser->window()->GetNativeWindow();
-  if (BrowserWindowController* controller = [ns_window windowController]) {
+  BrowserWindowController* controller =
+      [BrowserWindowController browserWindowControllerForWindow:ns_window];
+  if (controller) {
     return l10n_util::GetNSString([controller isInAppKitFullscreen]
                                       ? IDS_EXIT_FULLSCREEN_MAC
                                       : IDS_ENTER_FULLSCREEN_MAC);
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index fb2ca36f..3974ee2 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -9,6 +9,9 @@
 // object. Handles interactions between Cocoa and the cross-platform
 // code. Each window has a single toolbar and, by virtue of being a
 // TabWindowController, a tab strip along the top.
+// Note that under the hood the BrowserWindowController is neither an
+// NSWindowController nor its window's delegate, though it receives all
+// NSWindowDelegate methods as if it were.
 
 #import <Cocoa/Cocoa.h>
 
@@ -638,5 +641,4 @@
 
 @end  // @interface BrowserWindowController (TestingAPI)
 
-
 #endif  // CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index c65db3c..0e5db8e 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -249,13 +249,8 @@
 @implementation BrowserWindowController
 
 + (BrowserWindowController*)browserWindowControllerForWindow:(NSWindow*)window {
-  while (window) {
-    id controller = [window windowController];
-    if ([controller isKindOfClass:[BrowserWindowController class]])
-      return (BrowserWindowController*)controller;
-    window = [window parentWindow];
-  }
-  return nil;
+  return base::mac::ObjCCast<BrowserWindowController>(
+      [TabWindowController tabWindowControllerForWindow:window]);
 }
 
 + (BrowserWindowController*)browserWindowControllerForView:(NSView*)view {
@@ -774,7 +769,7 @@
 }
 
 - (void)activate {
-  [BrowserWindowUtils activateWindowForController:self];
+  [BrowserWindowUtils activateWindowForController:[self nsWindowController]];
 }
 
 // Determine whether we should let a window zoom/unzoom to the given |newFrame|.
@@ -1286,9 +1281,8 @@
       CreateNewStripWithContents(contentses, browserRect, false);
 
   // Get the new controller by asking the new window for its delegate.
-  BrowserWindowController* controller =
-      reinterpret_cast<BrowserWindowController*>(
-          [newBrowser->window()->GetNativeWindow() delegate]);
+  BrowserWindowController* controller = [BrowserWindowController
+      browserWindowControllerForWindow:newBrowser->window()->GetNativeWindow()];
   DCHECK(controller && [controller isKindOfClass:[TabWindowController class]]);
 
   // Ensure that the window will appear on top of the source window in
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
index 4bae8d7..93e9020 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
@@ -636,7 +636,9 @@
   EXPECT_FALSE([popupController hasToolbar]);
 
   // Open sheet in an application window.
-  [popupController showWindow:nil];
+  NSWindowController* nsWindowController = [popupController nsWindowController];
+  EXPECT_TRUE(nsWindowController);
+  [nsWindowController showWindow:nil];
   sheetLocation = [popupController window:popupWindow
                         willPositionSheet:sheet
                                 usingRect:defaultLocation];
@@ -644,7 +646,7 @@
 
   // Close the application window.
   popup_browser->tab_strip_model()->CloseSelectedTabs();
-  [popupController close];
+  [nsWindowController close];
 }
 
 // Verify that the info bar tip is hidden when the toolbar is not visible.
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index f6b052ea..bedc4ae 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -360,7 +360,7 @@
   // Have to do this here, otherwise later calls can crash because the window
   // has no delegate.
   [sourceWindow setDelegate:nil];
-  [destWindow setDelegate:self];
+  [destWindow setDelegate:[self nsWindowController]];
 
   // With this call, valgrind complains that a "Conditional jump or move depends
   // on uninitialised value(s)".  The error happens in -[NSThemeFrame
@@ -389,7 +389,7 @@
 
   [sourceWindow setWindowController:nil];
   [self setWindow:destWindow];
-  [destWindow setWindowController:self];
+  [destWindow setWindowController:[self nsWindowController]];
 
   // Move the status bubble over, if we have one.
   if (statusBubble_)
@@ -608,9 +608,8 @@
 
       NSWindow* windowForToolbar = [window _windowForToolbar];
       if ([windowForToolbar isKindOfClass:[FramedBrowserWindow class]]) {
-        BrowserWindowController* bwc =
-            base::mac::ObjCCastStrict<BrowserWindowController>(
-                [windowForToolbar windowController]);
+        BrowserWindowController* bwc = [BrowserWindowController
+            browserWindowControllerForWindow:windowForToolbar];
         if ([bwc hasToolbar])
           [[window contentView] setHidden:YES];
       }
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
index 8f553ce..1a72305 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -84,7 +84,7 @@
   }
 
   void TearDown() override {
-    [controller_ close];
+    [[controller_ nsWindowController] close];
     CocoaProfileTest::TearDown();
   }
 
@@ -136,13 +136,13 @@
       new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile(), true)));
   NSWindow* cocoaWindow = popup_browser->window()->GetNativeWindow();
   BrowserWindowController* controller =
-      static_cast<BrowserWindowController*>([cocoaWindow windowController]);
+      [BrowserWindowController browserWindowControllerForWindow:cocoaWindow];
   ASSERT_TRUE([controller isKindOfClass:[BrowserWindowController class]]);
   EXPECT_FALSE([controller isTabbedWindow]);
   EXPECT_FALSE([controller hasTabStrip]);
   EXPECT_TRUE([controller hasTitleBar]);
   EXPECT_FALSE([controller isBookmarkBarVisible]);
-  [controller close];
+  [[controller nsWindowController] close];
 }
 
 TEST_F(BrowserWindowControllerTest, TestSetBounds) {
@@ -152,7 +152,7 @@
   Browser* browser = new Browser(params);
   NSWindow* cocoaWindow = browser->window()->GetNativeWindow();
   BrowserWindowController* controller =
-    static_cast<BrowserWindowController*>([cocoaWindow windowController]);
+      [BrowserWindowController browserWindowControllerForWindow:cocoaWindow];
 
   ASSERT_TRUE([controller isTabbedWindow]);
   BrowserWindow* browser_window = [controller browserWindow];
@@ -163,7 +163,7 @@
   browser_window->SetBounds(gfx::Rect(0, 0, 50, 50));
   EXPECT_EQ(browser_window->GetBounds().size(), kMinCocoaTabbedWindowSize);
 
-  [controller close];
+  [[controller nsWindowController] close];
 }
 
 // https://crbug.com/667698 - When Auto Layout is in use, adding the download
@@ -205,7 +205,7 @@
   Browser* browser = new Browser(params);
   NSWindow* cocoaWindow = browser->window()->GetNativeWindow();
   BrowserWindowController* controller =
-    static_cast<BrowserWindowController*>([cocoaWindow windowController]);
+      [BrowserWindowController browserWindowControllerForWindow:cocoaWindow];
 
   ASSERT_FALSE([controller isTabbedWindow]);
   BrowserWindow* browser_window = [controller browserWindow];
@@ -220,7 +220,7 @@
   EXPECT_EQ(100, bounds.width());
   EXPECT_EQ(122, bounds.height());
 
-  [controller close];
+  [[controller nsWindowController] close];
 }
 
 TEST_F(BrowserWindowControllerTest, TestTheme) {
@@ -245,7 +245,7 @@
   Browser* browser = new Browser(params);
   NSWindow* cocoaWindow = browser->window()->GetNativeWindow();
   BrowserWindowController* controller =
-   static_cast<BrowserWindowController*>([cocoaWindow windowController]);
+      [BrowserWindowController browserWindowControllerForWindow:cocoaWindow];
   BrowserWindow* browser_window = [controller browserWindow];
   gfx::Rect bounds = browser_window->GetBounds();
   EXPECT_EQ(280, bounds.height());
@@ -257,7 +257,7 @@
   bounds = browser_window->GetBounds();
   EXPECT_EQ(272, bounds.height());
 
-  [controller close];
+  [[controller nsWindowController] close];
 }
 
 #if 0
@@ -783,7 +783,7 @@
   }
 
   void TearDown() override {
-    [controller_ close];
+    [[controller_ nsWindowController] close];
     CocoaProfileTest::TearDown();
   }
 
@@ -809,7 +809,7 @@
 // http://crbug.com/53586
 TEST_F(BrowserWindowFullScreenControllerTest, TestFullscreen) {
   ui::test::ScopedFakeNSWindowFullscreen fake_fullscreen;
-  [controller_ showWindow:nil];
+  [[controller_ nsWindowController] showWindow:nil];
   EXPECT_FALSE([controller_ isInAnyFullscreenMode]);
 
   // The fix for http://crbug.com/447740 , where the omnibox would lose focus
@@ -844,7 +844,7 @@
 // http://crbug.com/53586
 TEST_F(BrowserWindowFullScreenControllerTest, TestActivate) {
   ui::test::ScopedFakeNSWindowFullscreen fake_fullscreen;
-  [controller_ showWindow:nil];
+  [[controller_ nsWindowController] showWindow:nil];
 
   EXPECT_FALSE([controller_ isInAnyFullscreenMode]);
 
diff --git a/chrome/browser/ui/cocoa/bubble_anchor_helper.mm b/chrome/browser/ui/cocoa/bubble_anchor_helper.mm
index bd3ac83..0c46a603 100644
--- a/chrome/browser/ui/cocoa/bubble_anchor_helper.mm
+++ b/chrome/browser/ui/cocoa/bubble_anchor_helper.mm
@@ -38,8 +38,10 @@
   NSPoint anchor;
   NSWindow* parentWindow = browser->window()->GetNativeWindow();
   if (has_location_bar) {
+    BrowserWindowController* browserWindowController =
+        [BrowserWindowController browserWindowControllerForWindow:parentWindow];
     LocationBarViewMac* location_bar =
-        [[parentWindow windowController] locationBarBridge];
+        [browserWindowController locationBarBridge];
     anchor = location_bar->GetPageInfoBubblePoint();
   } else {
     // Position the bubble on the left of the screen if there is no page info
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window.mm b/chrome/browser/ui/cocoa/chrome_browser_window.mm
index 6470d5c1..a644b43 100644
--- a/chrome/browser/ui/cocoa/chrome_browser_window.mm
+++ b/chrome/browser/ui/cocoa/chrome_browser_window.mm
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "chrome/browser/themes/theme_properties.h"
+#import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
 #import "chrome/browser/ui/cocoa/themed_window.h"
 #include "ui/base/theme_provider.h"
 
@@ -26,24 +27,28 @@
 @implementation ChromeBrowserWindow
 
 - (const ui::ThemeProvider*)themeProvider {
-  id delegate = [self delegate];
-  if (![delegate respondsToSelector:@selector(themeProvider)])
+  id tabWindowController =
+      [TabWindowController tabWindowControllerForWindow:self];
+  if (![tabWindowController respondsToSelector:@selector(themeProvider)])
     return NULL;
-  return [delegate themeProvider];
+  return [tabWindowController themeProvider];
 }
 
 - (ThemedWindowStyle)themedWindowStyle {
-  id delegate = [self delegate];
-  if (![delegate respondsToSelector:@selector(themedWindowStyle)])
+  id tabWindowController =
+      [TabWindowController tabWindowControllerForWindow:self];
+  if (![tabWindowController respondsToSelector:@selector(themedWindowStyle)])
     return THEMED_NORMAL;
-  return [delegate themedWindowStyle];
+  return [tabWindowController themedWindowStyle];
 }
 
 - (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
-  id delegate = [self delegate];
-  if (![delegate respondsToSelector:@selector(themeImagePositionForAlignment:)])
+  id tabWindowController =
+      [TabWindowController tabWindowControllerForWindow:self];
+  if (![tabWindowController
+          respondsToSelector:@selector(themeImagePositionForAlignment:)])
     return NSZeroPoint;
-  return [delegate themeImagePositionForAlignment:alignment];
+  return [tabWindowController themeImagePositionForAlignment:alignment];
 }
 
 - (BOOL)inIncognitoMode {
diff --git a/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm b/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm
index f36b4bd..f6e7eb96 100644
--- a/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm
+++ b/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm
@@ -89,7 +89,8 @@
   // let the extension system try to handle the event. In case this is a
   // redispatched event, [event window] gives the correct window.
   if ([event window]) {
-    BrowserWindowController* controller = [[event window] windowController];
+    BrowserWindowController* controller = [BrowserWindowController
+        browserWindowControllerForWindow:[event window]];
     // |controller| is only set in Cocoa. In toolkit-views extension commands
     // are handled by BrowserView.
     if ([controller respondsToSelector:@selector(handledByExtensionCommand:
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.mm b/chrome/browser/ui/cocoa/framed_browser_window.mm
index ac46eae5..c564b79 100644
--- a/chrome/browser/ui/cocoa/framed_browser_window.mm
+++ b/chrome/browser/ui/cocoa/framed_browser_window.mm
@@ -88,8 +88,7 @@
 
 - (BOOL)makeFirstResponder:(NSResponder*)responder {
   BrowserWindowController* bwc =
-      base::mac::ObjCCastStrict<BrowserWindowController>(
-          [self windowController]);
+      [BrowserWindowController browserWindowControllerForWindow:self];
   [bwc firstResponderUpdated:responder];
   return [super makeFirstResponder:responder];
 }
@@ -192,8 +191,7 @@
 - (NSTouchBar*)makeTouchBar {
   if (@available(macOS 10.12.2, *)) {
     BrowserWindowController* bwc =
-        base::mac::ObjCCastStrict<BrowserWindowController>(
-            [self windowController]);
+        [BrowserWindowController browserWindowControllerForWindow:self];
     return [[bwc browserWindowTouchBar] makeTouchBar];
   } else {
     return nil;
diff --git a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
index 38af117..dd8e013 100644
--- a/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/page_info/page_info_bubble_controller.mm
@@ -298,7 +298,8 @@
 }
 
 - (void)showWindow:(id)sender {
-  BrowserWindowController* controller = [[self parentWindow] windowController];
+  BrowserWindowController* controller = [BrowserWindowController
+      browserWindowControllerForWindow:[self parentWindow]];
   LocationBarViewMac* locationBar = [controller locationBarBridge];
   if (locationBar) {
     decoration_ = locationBar->page_info_decoration();
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
index 9a77b3d..6750f55 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
@@ -184,12 +184,11 @@
 
   DCHECK(chrome::IsCommandEnabled(browser_, IDC_SHOW_AVATAR_MENU));
 
-  NSWindowController* wc =
-      [browser_->window()->GetNativeWindow() windowController];
-  if ([wc isKindOfClass:[BrowserWindowController class]]) {
-    [static_cast<BrowserWindowController*>(wc)
-        lockToolbarVisibilityForOwner:self
-                        withAnimation:NO];
+  BrowserWindowController* bwc = [BrowserWindowController
+      browserWindowControllerForWindow:browser_->window()->GetNativeWindow()];
+
+  if (bwc) {
+    [bwc lockToolbarVisibilityForOwner:self withAnimation:NO];
   }
 
   // The new avatar bubble does not have an arrow, and it should be anchored
@@ -233,12 +232,10 @@
 }
 
 - (void)bubbleWillClose {
-  NSWindowController* wc =
-      [browser_->window()->GetNativeWindow() windowController];
-  if ([wc isKindOfClass:[BrowserWindowController class]]) {
-    [static_cast<BrowserWindowController*>(wc)
-        releaseToolbarVisibilityForOwner:self
-                           withAnimation:YES];
+  BrowserWindowController* bwc = [BrowserWindowController
+      browserWindowControllerForWindow:browser_->window()->GetNativeWindow()];
+  if (bwc) {
+    [bwc releaseToolbarVisibilityForOwner:self withAnimation:YES];
   }
   profileChooserViewObserverBridge_.reset();
   menuController_ = nil;
diff --git a/chrome/browser/ui/cocoa/share_menu_controller.mm b/chrome/browser/ui/cocoa/share_menu_controller.mm
index 31b0f39..dc36394 100644
--- a/chrome/browser/ui/cocoa/share_menu_controller.mm
+++ b/chrome/browser/ui/cocoa/share_menu_controller.mm
@@ -155,7 +155,9 @@
 - (void)saveTransitionDataFromBrowser:(Browser*)browser {
   windowForShare_ = browser->window()->GetNativeWindow();
 
-  NSView* contentsView = [[windowForShare_ windowController] tabContentArea];
+  TabWindowController* tabWindowController =
+      [TabWindowController tabWindowControllerForWindow:windowForShare_];
+  NSView* contentsView = [tabWindowController tabContentArea];
   NSRect rectInWindow =
       [[contentsView superview] convertRect:[contentsView frame] toView:nil];
   rectForShare_ = [windowForShare_ convertRectToScreen:rectInWindow];
diff --git a/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm b/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm
index 4531c02..d87aab9 100644
--- a/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm
+++ b/chrome/browser/ui/cocoa/tab_dialogs_views_mac.mm
@@ -64,7 +64,10 @@
   // earlier because the bubble is shown on mouse release (but dismissed on
   // mouse pressed). A Cocoa browser does both on mouse pressed, so a check
   // when showing is sufficient.
-  if (ManagePasswordsBubbleDelegateViewBase::manage_password_bubble())
+  if (ManagePasswordsBubbleDelegateViewBase::manage_password_bubble() &&
+      ManagePasswordsBubbleDelegateViewBase::manage_password_bubble()
+          ->GetWidget()
+          ->IsVisible())
     return;
 
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
diff --git a/chrome/browser/ui/cocoa/tabbed_browser_window.mm b/chrome/browser/ui/cocoa/tabbed_browser_window.mm
index ce42d44..864789d9 100644
--- a/chrome/browser/ui/cocoa/tabbed_browser_window.mm
+++ b/chrome/browser/ui/cocoa/tabbed_browser_window.mm
@@ -196,7 +196,8 @@
   // If there is a profile avatar icon present, shift the button over by its
   // width and some padding. The new avatar button is displayed to the right
   // of the fullscreen icon, so it doesn't need to be shifted.
-  auto* bwc = static_cast<BrowserWindowController*>([self windowController]);
+  BrowserWindowController* bwc =
+      [BrowserWindowController browserWindowControllerForWindow:self];
   if ([bwc shouldShowAvatar] && ![bwc shouldUseNewAvatarButton]) {
     NSView* avatarButton = [[bwc avatarButtonController] view];
     return NSWidth([avatarButton frame]) - 3;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
index a1a84a8..341afe1 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
@@ -71,7 +71,8 @@
 
   sourceWindowFrame_ = [sourceWindow_ frame];
   sourceTabFrame_ = [[tab view] frame];
-  sourceController_ = [sourceWindow_ windowController];
+  sourceController_ =
+      [TabWindowController tabWindowControllerForWindow:sourceWindow_];
   draggedTab_ = tab;
   tabWasDragged_ = NO;
   tearTime_ = 0.0;
@@ -473,7 +474,7 @@
     // Force redraw to avoid flashes of old content before returning to event
     // loop.
     [[targetController_ window] display];
-    [targetController_ showWindow:nil];
+    [[targetController_ nsWindowController] showWindow:nil];
     [draggedController_ removeOverlay];
   } else {
     // Only move the window around on screen. Make sure it's set back to
@@ -523,12 +524,11 @@
       return NO;
   }
 
-  NSWindowController* controller = [sourceWindow_ windowController];
-  if ([controller isKindOfClass:[TabWindowController class]]) {
-    TabWindowController* realController =
-        static_cast<TabWindowController*>(controller);
+  TabWindowController* controller =
+      [TabWindowController tabWindowControllerForWindow:sourceWindow_];
+  if (controller) {
     for (TabView* tabView in tabs) {
-      if (![realController isTabDraggable:tabView])
+      if (![controller isTabDraggable:tabView])
         return NO;
     }
   }
@@ -559,13 +559,10 @@
     // Skip windows on the wrong space.
     if (![window isOnActiveSpace])
       continue;
-    NSWindowController* controller = [window windowController];
-    if ([controller isKindOfClass:[TabWindowController class]]) {
-      TabWindowController* realController =
-          static_cast<TabWindowController*>(controller);
-      if ([realController canReceiveFrom:dragController])
-        [targets addObject:controller];
-    }
+    TabWindowController* controller =
+        [TabWindowController tabWindowControllerForWindow:window];
+    if ([controller canReceiveFrom:dragController])
+      [targets addObject:controller];
   }
   return targets;
 }
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
index a8c312a3b..523de75 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
@@ -11,6 +11,9 @@
 // know anything about the actual tab implementation or model, as that is fairly
 // application-specific. It only provides an API to be overridden by subclasses
 // to fill in the details.
+// Note that under the hood the TabWindowController is neither an
+// NSWindowController nor its window's delegate, though it receives all
+// NSWindowDelegate methods as if it were.
 
 #import <Cocoa/Cocoa.h>
 
@@ -23,7 +26,7 @@
 @class TabStripView;
 @class TabView;
 
-@interface TabWindowController : NSWindowController<NSWindowDelegate> {
+@interface TabWindowController : NSObject<NSWindowDelegate> {
  @private
   // Wrapper view around web content, and the developer tools view.
   base::scoped_nsobject<FastResizeView> tabContentArea_;
@@ -54,6 +57,14 @@
   BOOL closeDeferred_;  // If YES, call performClose: in removeOverlay:.
 }
 
+// Returns the NSWindowController that manages the TabWindowController's
+// NSWindow. In the past the TabWindowController was also the window's
+// NSWindowController but they are now separate objects. Use
+// +tabWindowControllerForWindow: to retrieve a TabWindowController from a
+// given NSWindow.
+@property(readonly, nonatomic)
+    NSWindowController<NSWindowDelegate>* nsWindowController;
+@property(retain, nonatomic) NSWindow* window;
 @property(readonly, nonatomic) API_AVAILABLE(macos(10.10))
     NSVisualEffectView* visualEffectView;
 @property(readonly, nonatomic) NSView* tabStripBackgroundView;
@@ -61,6 +72,10 @@
 @property(readonly, nonatomic) FastResizeView* tabContentArea;
 @property(readonly, nonatomic) NSView* chromeContentView;
 
+// A convenience class method which returns the |TabWindowController| for a
+// given window, or nil if no window in the chain has one.
++ (TabWindowController*)tabWindowControllerForWindow:(NSWindow*)window;
+
 // This is the designated initializer for this class.
 - (id)initTabWindowControllerWithTabStrip:(BOOL)hasTabStrip
                                  titleBar:(BOOL)hasTitleBar;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
index 8be82134..90a848c 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -4,7 +4,10 @@
 
 #import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
 
+#import <objc/runtime.h>
+
 #include "base/logging.h"
+#import "base/mac/foundation_util.h"
 #import "base/mac/sdk_forward_declarations.h"
 #import "chrome/browser/ui/cocoa/browser_window_layout.h"
 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
@@ -18,7 +21,63 @@
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/theme_provider.h"
 
-@interface TabWindowController ()
+// As of macOS 10.13 NSWindow lifetimes after closing are unpredictable. Chrome
+// frees resources on window close so this new behavior created problems such as
+// browser tests failing to complete (see https://crbug.com/749196 ). To work
+// around this new behavior TabWindowController no longer acts as the NSWindow's
+// NSWindowController or NSWindowDelegate but instead uses a
+// TabWindowControllerProxy instance. The TabWindowController and its subclasses
+// still expect to receive NSWindowDelegate messages, which the
+// TabWindowControllerProxy forwards along.
+@interface TabWindowControllerProxy : NSWindowController<NSWindowDelegate>
+@property(assign, nonatomic) TabWindowController* tabWindowController;
+@end
+
+@implementation TabWindowControllerProxy
+
+@synthesize tabWindowController = tabWindowController_;
+
+- (void)dealloc {
+  // The TabWindowControllerProxy should outlive the TabWindowController.
+  DCHECK(!tabWindowController_);
+  [super dealloc];
+}
+
+- (BOOL)respondsToSelector:(SEL)aSelector {
+  if ([super respondsToSelector:aSelector]) {
+    return YES;
+  }
+
+  // Only forward methods from the NSWindowDelegate protcol.
+  Protocol* nsWindowDelegateProtocol = objc_getProtocol("NSWindowDelegate");
+  struct objc_method_description methodDescription =
+      protocol_getMethodDescription(nsWindowDelegateProtocol, aSelector, NO,
+                                    YES);
+
+  return methodDescription.name
+             ? [self.tabWindowController respondsToSelector:aSelector]
+             : NO;
+}
+
+- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector {
+  NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
+
+  return signature
+             ? signature
+             : [self.tabWindowController methodSignatureForSelector:aSelector];
+}
+
+- (void)forwardInvocation:(NSInvocation*)anInvocation {
+  [anInvocation setTarget:self.tabWindowController];
+  [anInvocation invoke];
+}
+
+@end
+
+@interface TabWindowController () {
+  base::scoped_nsobject<TabWindowControllerProxy> nsWindowController_;
+}
+
 - (void)setUseOverlay:(BOOL)useOverlay;
 
 // The tab strip background view should always be inserted as the back-most
@@ -85,20 +144,39 @@
 
 @implementation TabWindowController
 
++ (TabWindowController*)tabWindowControllerForWindow:(NSWindow*)window {
+  while (window) {
+    TabWindowControllerProxy* nsWindowController =
+        base::mac::ObjCCast<TabWindowControllerProxy>(
+            [window windowController]);
+
+    if (nsWindowController) {
+      return [nsWindowController tabWindowController];
+    }
+    window = [window parentWindow];
+  }
+  return nil;
+}
+
 - (id)initTabWindowControllerWithTabStrip:(BOOL)hasTabStrip
                                  titleBar:(BOOL)hasTitleBar {
   const CGFloat kDefaultWidth = WindowSizer::kWindowMaxDefaultWidth;
   const CGFloat kDefaultHeight = 600;
 
-  NSRect contentRect = NSMakeRect(60, 229, kDefaultWidth, kDefaultHeight);
-  base::scoped_nsobject<FramedBrowserWindow> window(
-      [(hasTabStrip ? [TabbedBrowserWindow alloc] : [FramedBrowserWindow alloc])
-          initWithContentRect:contentRect]);
-  [window setReleasedWhenClosed:YES];
-  [window setAutorecalculatesKeyViewLoop:YES];
+  if (self = [self init]) {
+    NSRect contentRect = NSMakeRect(60, 229, kDefaultWidth, kDefaultHeight);
+    base::scoped_nsobject<FramedBrowserWindow> window(
+        [(hasTabStrip
+              ? [TabbedBrowserWindow alloc]
+              : [FramedBrowserWindow alloc]) initWithContentRect:contentRect]);
+    [window setReleasedWhenClosed:YES];
+    [window setAutorecalculatesKeyViewLoop:YES];
 
-  if ((self = [super initWithWindow:window])) {
-    [[self window] setDelegate:self];
+    nsWindowController_.reset(
+        [[TabWindowControllerProxy alloc] initWithWindow:window]);
+    [nsWindowController_ setTabWindowController:self];
+
+    [[self window] setDelegate:nsWindowController_];
 
     chromeContentView_.reset([[ChromeContentView alloc]
         initWithFrame:NSMakeRect(0, 0, kDefaultWidth, kDefaultHeight)]);
@@ -109,8 +187,8 @@
 
     tabContentArea_.reset(
         [[FastResizeView alloc] initWithFrame:[chromeContentView_ bounds]]);
-    [tabContentArea_ setAutoresizingMask:NSViewWidthSizable |
-                                         NSViewHeightSizable];
+    [tabContentArea_
+        setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
     [chromeContentView_ addSubview:tabContentArea_];
 
     // tabStripBackgroundView_ draws the theme image behind the tab strip area.
@@ -127,18 +205,18 @@
     [self insertTabStripBackgroundViewIntoWindow:window titleBar:hasTitleBar];
 
     tabStripView_.reset([[TabStripView alloc]
-        initWithFrame:NSMakeRect(
-                          0, 0, kDefaultWidth, chrome::kTabStripHeight)]);
-    [tabStripView_ setAutoresizingMask:NSViewWidthSizable |
-                                       NSViewMinYMargin];
+        initWithFrame:NSMakeRect(0, 0, kDefaultWidth,
+                                 chrome::kTabStripHeight)]);
+    [tabStripView_ setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
     if (hasTabStrip)
       [windowView addSubview:tabStripView_];
 
-    // |windowWillEnterFullScreen:| and |windowWillExitFullScreen:| are already
-    // called because self is a delegate for the window. However this class is
-    // designed for subclassing and can not implement NSWindowDelegate methods
-    // (because subclasses can do so as well and they should be able to).
-    // TODO(crbug.com/654656): Move |visualEffectView_| to subclass.
+    // |windowWillEnterFullScreen:| and |windowWillExitFullScreen:| are
+    // already called because self is a delegate for the window. However this
+    // class is designed for subclassing and can not implement
+    // NSWindowDelegate methods (because subclasses can do so as well and they
+    // should be able to). TODO(crbug.com/654656): Move |visualEffectView_| to
+    // subclass.
     [[NSNotificationCenter defaultCenter]
         addObserver:self
            selector:@selector(windowWillEnterFullScreenNotification:)
@@ -150,14 +228,30 @@
                name:NSWindowWillExitFullScreenNotification
              object:window];
   }
+
   return self;
 }
 
 - (void)dealloc {
   [[NSNotificationCenter defaultCenter] removeObserver:self];
+  [[self window] setDelegate:nil];
+  [nsWindowController_ setTabWindowController:nil];
+  [nsWindowController_ setWindow:nil];
   [super dealloc];
 }
 
+- (NSWindow*)window {
+  return [nsWindowController_ window];
+}
+
+- (void)setWindow:(NSWindow*)aWindow {
+  [nsWindowController_ setWindow:aWindow];
+}
+
+- (NSWindowController*)nsWindowController {
+  return nsWindowController_;
+}
+
 - (NSVisualEffectView*)visualEffectView {
   return visualEffectView_;
 }
diff --git a/chrome/browser/ui/cocoa/translate/translate_bubble_controller.mm b/chrome/browser/ui/cocoa/translate/translate_bubble_controller.mm
index 105f3d8..e73ed08 100644
--- a/chrome/browser/ui/cocoa/translate/translate_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/translate/translate_bubble_controller.mm
@@ -212,8 +212,9 @@
 }
 
 - (void)showWindow:(id)sender {
-  LocationBarViewMac* locationBar =
-      [[[self parentWindow] windowController] locationBarBridge];
+  BrowserWindowController* browserWindowController = [BrowserWindowController
+      browserWindowControllerForWindow:self.parentWindow];
+  LocationBarViewMac* locationBar = [browserWindowController locationBarBridge];
   if (locationBar) {
     NSPoint anchorPoint =
         locationBar->GetBubblePointForDecoration([self decorationForBubble]);
@@ -225,8 +226,9 @@
 }
 
 - (LocationBarDecoration*)decorationForBubble {
-  LocationBarViewMac* locationBar =
-      [[[self parentWindow] windowController] locationBarBridge];
+  BrowserWindowController* browserWindowController = [BrowserWindowController
+      browserWindowControllerForWindow:self.parentWindow];
+  LocationBarViewMac* locationBar = [browserWindowController locationBarBridge];
   return locationBar ? locationBar->translate_decoration() : nullptr;
 }
 
diff --git a/chrome/browser/ui/cocoa/view_id_util.mm b/chrome/browser/ui/cocoa/view_id_util.mm
index 95748cc..7859bad 100644
--- a/chrome/browser/ui/cocoa/view_id_util.mm
+++ b/chrome/browser/ui/cocoa/view_id_util.mm
@@ -63,7 +63,8 @@
   // As tabs can be created, destroyed or rearranged dynamically, we handle them
   // here specially.
   if (viewID >= VIEW_ID_TAB_0 && viewID <= VIEW_ID_TAB_LAST) {
-    BrowserWindowController* windowController = [window windowController];
+    BrowserWindowController* windowController =
+        [BrowserWindowController browserWindowControllerForWindow:window];
     DCHECK([windowController isKindOfClass:[BrowserWindowController class]]);
     TabStripController* tabStripController =
         [windowController tabStripController];
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model_browsertest.cc b/chrome/browser/ui/content_settings/content_setting_image_model_browsertest.cc
index 4d8e4a23..f9ca7ce 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model_browsertest.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model_browsertest.cc
@@ -4,13 +4,18 @@
 
 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
 
+#include <string>
+
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_request_limiter.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
+#include "content/public/test/test_navigation_observer.h"
 
 using content::WebContents;
 using ImageType = ContentSettingImageModel::ImageType;
@@ -101,3 +106,25 @@
   browser()->tab_strip_model()->AppendWebContents(other_web_contents, true);
   EXPECT_TRUE(model->ShouldRunAnimation(other_web_contents));
 }
+
+// Tests that we go to the correct link when learn more is clicked in Ads
+// bubble.
+IN_PROC_BROWSER_TEST_F(ContentSettingImageModelBrowserTest,
+                       AdsLearnMoreLinkClicked) {
+  WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  auto model = ContentSettingImageModel::CreateForContentType(ImageType::ADS);
+  Profile* profile = browser()->profile();
+  std::unique_ptr<ContentSettingBubbleModel> bubble(model->CreateBubbleModel(
+      browser()->content_setting_bubble_model_delegate(), web_contents,
+      profile));
+
+  content::TestNavigationObserver observer(nullptr);
+  observer.StartWatchingNewWebContents();
+  bubble->OnLearnMoreClicked();
+  observer.Wait();
+
+  std::string link_value(subresource_filter::kLearnMoreLink);
+  EXPECT_EQ(link_value, observer.last_navigation_url().spec());
+}
diff --git a/chrome/browser/ui/overlay/overlay_surface_embedder.cc b/chrome/browser/ui/overlay/overlay_surface_embedder.cc
index f0bf0c3..b7c0581 100644
--- a/chrome/browser/ui/overlay/overlay_surface_embedder.cc
+++ b/chrome/browser/ui/overlay/overlay_surface_embedder.cc
@@ -4,9 +4,6 @@
 
 #include "chrome/browser/ui/overlay/overlay_surface_embedder.h"
 
-#include <memory>
-
-#include "components/viz/common/surfaces/stub_surface_reference_factory.h"
 #include "ui/compositor/layer.h"
 
 OverlaySurfaceEmbedder::OverlaySurfaceEmbedder(OverlayWindow* window)
@@ -18,7 +15,6 @@
   // the surface layer.
   surface_layer_->SetFillsBoundsOpaquely(false);
   window_->GetLayer()->Add(surface_layer_.get());
-  ref_factory_ = new viz::StubSurfaceReferenceFactory();
 }
 
 OverlaySurfaceEmbedder::~OverlaySurfaceEmbedder() = default;
@@ -27,5 +23,5 @@
     const viz::SurfaceId& surface_id) {
   // SurfaceInfo has information about the embedded surface.
   surface_layer_->SetShowPrimarySurface(surface_id, window_->GetBounds().size(),
-                                        SK_ColorBLACK, ref_factory_);
+                                        SK_ColorBLACK);
 }
diff --git a/chrome/browser/ui/overlay/overlay_surface_embedder.h b/chrome/browser/ui/overlay/overlay_surface_embedder.h
index 841a037..a160f06 100644
--- a/chrome/browser/ui/overlay/overlay_surface_embedder.h
+++ b/chrome/browser/ui/overlay/overlay_surface_embedder.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_UI_OVERLAY_OVERLAY_SURFACE_EMBEDDER_H_
 
 #include "chrome/browser/ui/overlay/overlay_window.h"
-#include "components/viz/common/surfaces/surface_reference_factory.h"
 
 namespace viz {
 class SurfaceId;
@@ -29,8 +28,6 @@
   // Contains the client's content.
   std::unique_ptr<ui::Layer> surface_layer_;
 
-  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(OverlaySurfaceEmbedder);
 };
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
index 1d6f14d..66838e1 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
@@ -270,6 +270,7 @@
     DisplayReason display_reason)
     : password_overridden_(false),
       delegate_(std::move(delegate)),
+      interaction_reported_(false),
       metrics_recorder_(delegate_->GetPasswordFormMetricsRecorder()) {
   origin_ = delegate_->GetOrigin();
   state_ = delegate_->GetState();
@@ -392,9 +393,16 @@
 }
 
 ManagePasswordsBubbleModel::~ManagePasswordsBubbleModel() {
+  if (!interaction_reported_)
+    OnBubbleClosing();
+}
+
+void ManagePasswordsBubbleModel::OnBubbleClosing() {
   interaction_keeper_->ReportInteractions(this);
   if (delegate_)
     delegate_->OnBubbleHidden();
+  delegate_.reset();
+  interaction_reported_ = true;
 }
 
 void ManagePasswordsBubbleModel::OnNeverForThisSiteClicked() {
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.h b/chrome/browser/ui/passwords/manage_passwords_bubble_model.h
index b3d7aca..0969670 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.h
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.h
@@ -42,6 +42,10 @@
                              DisplayReason reason);
   ~ManagePasswordsBubbleModel();
 
+  // The method MAY BE called to record the statistics while the bubble is being
+  // closed. Otherwise, it is called later on when the model is destroyed.
+  void OnBubbleClosing();
+
   // Called by the view code when the "Nope" button in clicked by the user in
   // update bubble.
   void OnNopeUpdateClicked();
@@ -187,6 +191,10 @@
   // A bridge to ManagePasswordsUIController instance.
   base::WeakPtr<PasswordsModelDelegate> delegate_;
 
+  // True if the model has already recorded all the necessary statistics when
+  // the bubble is closing.
+  bool interaction_reported_;
+
   // True iff password revealing should require re-auth for privacy reasons.
   bool password_revealing_requires_reauth_;
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
index ad25612..4a778ff 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
@@ -223,8 +223,9 @@
 void ManagePasswordsBubbleModelTest::
     DestroyModelAndVerifyControllerExpectations() {
   EXPECT_CALL(*controller(), OnBubbleHidden());
-  model_.reset();
+  model_->OnBubbleClosing();
   ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(controller()));
+  model_.reset();
 }
 
 void ManagePasswordsBubbleModelTest::DestroyModelExpectReason(
diff --git a/chrome/browser/ui/sync/bubble_sync_promo_delegate.h b/chrome/browser/ui/sync/bubble_sync_promo_delegate.h
index a62f415a..22eb2986 100644
--- a/chrome/browser/ui/sync/bubble_sync_promo_delegate.h
+++ b/chrome/browser/ui/sync/bubble_sync_promo_delegate.h
@@ -7,6 +7,9 @@
 
 #include "components/signin/core/browser/account_info.h"
 
+#include "build/buildflag.h"
+#include "components/signin/core/browser/signin_features.h"
+
 class BubbleSyncPromoDelegate {
  public:
   virtual ~BubbleSyncPromoDelegate() {}
@@ -14,8 +17,10 @@
   // Shows the chrome sign-in page.
   virtual void ShowBrowserSignin() = 0;
 
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
   // Enables sync for |account|.
   virtual void EnableSync(const AccountInfo& account) = 0;
+#endif
 };
 
 #endif  // CHROME_BROWSER_UI_SYNC_BUBBLE_SYNC_PROMO_DELEGATE_H_
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
index ffdcf552..a5ccfaa 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/buildflag.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/browser.h"
@@ -29,6 +30,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/bubble/bubble_controller.h"
 #include "components/signin/core/browser/account_info.h"
+#include "components/signin/core/browser/signin_features.h"
 #include "extensions/common/extension.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/ui_features.h"
@@ -139,7 +141,9 @@
 
   // BubbleSyncPromoDelegate:
   void ShowBrowserSignin() override;
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
   void EnableSync(const AccountInfo& account_info) override;
+#endif
 
   // views::LinkListener:
   void LinkClicked(views::Link* source, int event_flags) override;
@@ -291,10 +295,12 @@
   CloseBubble(BUBBLE_CLOSE_NAVIGATED);
 }
 
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
 void ExtensionInstalledBubbleView::EnableSync(const AccountInfo& account) {
   NOTREACHED() << "Extension installl bubble does not display the DICE "
                << "personalized sign-in promo asking the user to enable sync.";
 }
+#endif
 
 void ExtensionInstalledBubbleView::LinkClicked(views::Link* source,
                                                int event_flags) {
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 246c871f..1bb3be2 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -751,6 +751,14 @@
   // we don't want any WebContents to be attached, so that we
   // avoid an unnecessary resize and re-layout of a WebContents.
   if (change_tab_contents) {
+    if (GetWidget() &&
+        (contents_web_view_->HasFocus() || devtools_web_view_->HasFocus())) {
+      // Manually clear focus before setting focus behavior so that the focus
+      // is not temporarily advanced to an arbitrary place in the UI via
+      // SetFocusBehavior(FocusBehavior::NEVER), confusing screen readers.
+      // The saved focus for new_contents is restored after it is attached.
+      GetWidget()->GetFocusManager()->ClearFocus();
+    }
     contents_web_view_->SetWebContents(nullptr);
     devtools_web_view_->SetWebContents(nullptr);
   }
diff --git a/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc b/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc
index 01138ff..afb9a71d 100644
--- a/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc
@@ -14,6 +14,8 @@
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/views/controls/webview/webview.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/view.h"
 #include "url/gurl.h"
@@ -91,3 +93,72 @@
   browser_view2->Close();
 #endif
 }
+
+// Helper class that tracks view classes receiving focus.
+class FocusedViewClassRecorder : public views::FocusChangeListener {
+ public:
+  explicit FocusedViewClassRecorder(views::FocusManager* focus_manager)
+      : focus_manager_(focus_manager) {
+    focus_manager_->AddFocusChangeListener(this);
+  }
+
+  ~FocusedViewClassRecorder() override {
+    focus_manager_->RemoveFocusChangeListener(this);
+  }
+
+  std::vector<std::string>& GetFocusClasses() { return focus_classes_; }
+
+ private:
+  // Inherited from views::FocusChangeListener
+  void OnWillChangeFocus(views::View* focused_before,
+                         views::View* focused_now) override {}
+  void OnDidChangeFocus(views::View* focused_before,
+                        views::View* focused_now) override {
+    std::string class_name;
+    if (focused_now)
+      class_name = focused_now->GetClassName();
+    focus_classes_.push_back(class_name);
+  }
+
+  views::FocusManager* focus_manager_;
+  std::vector<std::string> focus_classes_;
+
+  DISALLOW_COPY_AND_ASSIGN(FocusedViewClassRecorder);
+};
+
+// Switching tabs does not focus views unexpectedly.
+// (bug http://crbug.com/791757, bug http://crbug.com/777051)
+IN_PROC_BROWSER_TEST_F(BrowserViewFocusTest, TabChangesAvoidSpuriousFocus) {
+  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // First we navigate to our test page.
+  GURL url = embedded_test_server()->GetURL(kSimplePage);
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Create another tab.
+  AddTabAtIndex(1, url, ui::PAGE_TRANSITION_TYPED);
+
+  // Begin recording focus changes.
+  gfx::NativeWindow window = browser()->window()->GetNativeWindow();
+  views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window);
+  views::FocusManager* focus_manager = widget->GetFocusManager();
+  FocusedViewClassRecorder focus_change_recorder(focus_manager);
+
+  // Switch tabs using ctrl+tab.
+  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_TAB, true,
+                                              false, false, false));
+
+  std::vector<std::string>& focused_classes =
+      focus_change_recorder.GetFocusClasses();
+
+  // Everything before the last focus must be either "" (nothing) or a WebView.
+  for (size_t index = 0; index < focused_classes.size() - 1; index++) {
+    EXPECT_THAT(focused_classes[index],
+                testing::AnyOf("", views::WebView::kViewClassName));
+  }
+
+  // Must end up focused on a WebView.
+  ASSERT_FALSE(focused_classes.empty());
+  EXPECT_EQ(views::WebView::kViewClassName, focused_classes.back());
+}
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 69fbe08..f8ba00c 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -185,6 +185,7 @@
     // No matches or the IME is showing a popup window which may overlap
     // the omnibox popup window.  Close any existing popup.
     if (popup_) {
+      NotifyAccessibilityEvent(ui::AX_EVENT_EXPANDED_CHANGED, true);
       size_animation_.Stop();
 
       // NOTE: Do NOT use CloseNow() here, as we may be deep in a callstack
@@ -294,6 +295,11 @@
       return;
     }
     popup_->ShowInactive();
+
+    // Popup is now expanded and first item will be selected.
+    NotifyAccessibilityEvent(ui::AX_EVENT_EXPANDED_CHANGED, true);
+    if (result_view_at(0))
+      result_view_at(0)->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true);
   } else {
     // Animate the popup shrinking, but don't animate growing larger since that
     // would make the popup feel less responsive.
@@ -454,6 +460,12 @@
 void OmniboxPopupContentsView::GetAccessibleNodeData(
     ui::AXNodeData* node_data) {
   node_data->role = ui::AX_ROLE_LIST_BOX;
+  if (IsOpen()) {
+    node_data->AddState(ui::AX_STATE_EXPANDED);
+  } else {
+    node_data->AddState(ui::AX_STATE_COLLAPSED);
+    node_data->AddState(ui::AX_STATE_INVISIBLE);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc
index 1b6974c..957eae43 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view_unittest.cc
@@ -235,4 +235,7 @@
   ui::AXNodeData popup_node_data;
   popup_view()->GetAccessibleNodeData(&popup_node_data);
   EXPECT_EQ(popup_node_data.role, ui::AX_ROLE_LIST_BOX);
+  EXPECT_FALSE(popup_node_data.HasState(ui::AX_STATE_EXPANDED));
+  EXPECT_TRUE(popup_node_data.HasState(ui::AX_STATE_COLLAPSED));
+  EXPECT_TRUE(popup_node_data.HasState(ui::AX_STATE_INVISIBLE));
 }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
index a2f7aba9..3d402d0f 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -110,9 +110,16 @@
   void AddedToWidget() override;
   void RemovedFromWidget() override;
 
+ protected:
+  // For testing only.
+  OmniboxPopupContentsView* GetPopupContentsView() const {
+    return popup_view_.get();
+  }
+
  private:
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, CloseOmniboxPopupOnTextDrag);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, FriendlyAccessibleLabel);
+  FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, AccessiblePopup);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, MaintainCursorAfterFocusCycle);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, OnBlur);
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
index 3f1b10c..312e210 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -472,6 +473,10 @@
             base::UTF8ToUTF16("https://www.google.com/#\u2603"));
 }
 
+// Ensure that when the user navigates between suggestions, that the accessible
+// value of the Omnibox includes helpful information for human comprehension,
+// such as the document title. When the user begins to arrow left/right
+// within the label or edit it, the value is presented as the pure editable URL.
 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, FriendlyAccessibleLabel) {
   OmniboxView* omnibox_view = nullptr;
   ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
@@ -549,3 +554,53 @@
   EXPECT_EQ(base::ASCIIToUTF16("hxps://google.com"),
             node_data.GetString16Attribute(ui::AX_ATTR_VALUE));
 }
+
+// Ensure that the Omnibox popup exposes appropriate accessibility semantics,
+// given a current state of open or closed.
+IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, AccessiblePopup) {
+  OmniboxView* omnibox_view = nullptr;
+  ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
+  OmniboxViewViews* omnibox_view_views =
+      static_cast<OmniboxViewViews*>(omnibox_view);
+
+  base::string16 match_url = base::ASCIIToUTF16("https://google.com");
+  AutocompleteMatch match(nullptr, 500, false,
+                          AutocompleteMatchType::HISTORY_TITLE);
+  match.contents = match_url;
+  match.contents_class.push_back(
+      ACMatchClassification(0, ACMatchClassification::URL));
+  match.destination_url = GURL(match_url);
+  match.description = base::ASCIIToUTF16("Google");
+  match.allowed_to_be_default_match = true;
+
+  OmniboxPopupContentsView* popup_view =
+      omnibox_view_views->GetPopupContentsView();
+  ui::AXNodeData popup_node_data_1;
+  popup_view->GetAccessibleNodeData(&popup_node_data_1);
+  EXPECT_FALSE(popup_node_data_1.HasState(ui::AX_STATE_EXPANDED));
+  EXPECT_TRUE(popup_node_data_1.HasState(ui::AX_STATE_COLLAPSED));
+  EXPECT_TRUE(popup_node_data_1.HasState(ui::AX_STATE_INVISIBLE));
+
+  // Populate suggestions for the omnibox popup.
+  AutocompleteController* autocomplete_controller =
+      omnibox_view->model()->popup_model()->autocomplete_controller();
+  AutocompleteResult& results = autocomplete_controller->result_;
+  ACMatches matches;
+  matches.push_back(match);
+  AutocompleteInput input(base::ASCIIToUTF16("g"),
+                          metrics::OmniboxEventProto::OTHER,
+                          TestSchemeClassifier());
+  results.AppendMatches(input, matches);
+  results.SortAndCull(
+      input, TemplateURLServiceFactory::GetForProfile(browser()->profile()));
+
+  // The omnibox popup should open with suggestions displayed.
+  chrome::FocusLocationBar(browser());
+  omnibox_view->model()->popup_model()->OnResultChanged();
+  EXPECT_TRUE(omnibox_view->model()->popup_model()->IsOpen());
+  ui::AXNodeData popup_node_data_2;
+  popup_view->GetAccessibleNodeData(&popup_node_data_2);
+  EXPECT_TRUE(popup_node_data_2.HasState(ui::AX_STATE_EXPANDED));
+  EXPECT_FALSE(popup_node_data_2.HasState(ui::AX_STATE_COLLAPSED));
+  EXPECT_FALSE(popup_node_data_2.HasState(ui::AX_STATE_INVISIBLE));
+}
diff --git a/chrome/browser/ui/views/passwords/manage_password_update_pending_view.cc b/chrome/browser/ui/views/passwords/manage_password_update_pending_view.cc
index a1ab097..36fdb543 100644
--- a/chrome/browser/ui/views/passwords/manage_password_update_pending_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_password_update_pending_view.cc
@@ -4,33 +4,39 @@
 
 #include "chrome/browser/ui/views/passwords/manage_password_update_pending_view.h"
 
-#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/passwords/credentials_selection_view.h"
 #include "chrome/browser/ui/views/passwords/manage_password_items_view.h"
 #include "chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/styled_label.h"
 #include "ui/views/layout/grid_layout.h"
 
 ManagePasswordUpdatePendingView::ManagePasswordUpdatePendingView(
-    ManagePasswordsBubbleView* parent)
-    : parent_(parent), selection_view_(nullptr) {
-  ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get();
+    content::WebContents* web_contents,
+    views::View* anchor_view,
+    const gfx::Point& anchor_point,
+    DisplayReason reason)
+    : ManagePasswordsBubbleDelegateViewBase(web_contents,
+                                            anchor_view,
+                                            anchor_point,
+                                            reason),
+      selection_view_(nullptr) {
   views::GridLayout* layout =
       SetLayoutManager(std::make_unique<views::GridLayout>(this));
   layout->set_minimum_size(
       gfx::Size(ManagePasswordsBubbleView::kDesiredBubbleWidth, 0));
 
   // Credential row.
-  if (parent->model()->ShouldShowMultipleAccountUpdateUI()) {
+  if (model()->ShouldShowMultipleAccountUpdateUI()) {
     ManagePasswordsBubbleView::BuildColumnSet(
         layout, ManagePasswordsBubbleView::SINGLE_VIEW_COLUMN_SET);
     layout->StartRow(0, ManagePasswordsBubbleView::SINGLE_VIEW_COLUMN_SET);
-    layout->AddView(new CredentialsSelectionView(parent->model()));
+    layout->AddView(new CredentialsSelectionView(model()));
   } else {
-    const autofill::PasswordForm& password_form =
-        parent_->model()->pending_password();
+    const autofill::PasswordForm& password_form = model()->pending_password();
     ManagePasswordsBubbleView::BuildCredentialRows(
         layout, CreateUsernameLabel(password_form).release(),
         CreatePasswordLabel(password_form,
@@ -39,46 +45,64 @@
         nullptr, /* password_view_button */
         true /* show_password_label */);
   }
-  layout->AddPaddingRow(
-      0, layout_provider->GetDistanceMetric(
-             views::DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_CONTROL));
-
-  // Button row.
-  nope_button_ = views::MdTextButton::CreateSecondaryUiButton(
-      this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_CANCEL_BUTTON));
-
-  update_button_ = views::MdTextButton::CreateSecondaryUiBlueButton(
-      this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_UPDATE_BUTTON));
-  ManagePasswordsBubbleView::BuildColumnSet(
-      layout, ManagePasswordsBubbleView::DOUBLE_BUTTON_COLUMN_SET);
-  layout->StartRow(0, ManagePasswordsBubbleView::DOUBLE_BUTTON_COLUMN_SET);
-  layout->AddView(update_button_);
-  layout->AddView(nope_button_);
-
-  parent_->set_initially_focused_view(update_button_);
 }
 
 ManagePasswordUpdatePendingView::~ManagePasswordUpdatePendingView() = default;
 
-void ManagePasswordUpdatePendingView::ButtonPressed(views::Button* sender,
-                                                    const ui::Event& event) {
-  DCHECK(sender == update_button_ || sender == nope_button_);
-  if (sender == update_button_) {
-    if (selection_view_) {
-      // Multi account case.
-      parent_->model()->OnUpdateClicked(
-          *selection_view_->GetSelectedCredentials());
-    } else {
-      parent_->model()->OnUpdateClicked(parent_->model()->pending_password());
-    }
-  } else {
-    parent_->model()->OnNopeUpdateClicked();
-  }
-  parent_->CloseBubble();
-}
-
 gfx::Size ManagePasswordUpdatePendingView::CalculatePreferredSize() const {
   return gfx::Size(ManagePasswordsBubbleView::kDesiredBubbleWidth,
                    GetLayoutManager()->GetPreferredHeightForWidth(
                        this, ManagePasswordsBubbleView::kDesiredBubbleWidth));
 }
+
+base::string16 ManagePasswordUpdatePendingView::GetDialogButtonLabel(
+    ui::DialogButton button) const {
+  return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK
+                                       ? IDS_PASSWORD_MANAGER_UPDATE_BUTTON
+                                       : IDS_PASSWORD_MANAGER_CANCEL_BUTTON);
+}
+
+bool ManagePasswordUpdatePendingView::Accept() {
+  if (selection_view_) {
+    // Multi account case.
+    model()->OnUpdateClicked(*selection_view_->GetSelectedCredentials());
+  } else {
+    model()->OnUpdateClicked(model()->pending_password());
+  }
+  return true;
+}
+
+bool ManagePasswordUpdatePendingView::Cancel() {
+  model()->OnNopeUpdateClicked();
+  return true;
+}
+
+bool ManagePasswordUpdatePendingView::Close() {
+  return true;
+}
+
+void ManagePasswordUpdatePendingView::AddedToWidget() {
+  auto title_view =
+      base::MakeUnique<views::StyledLabel>(base::string16(), this);
+  title_view->SetTextContext(views::style::CONTEXT_DIALOG_TITLE);
+  UpdateTitleText(title_view.get());
+  GetBubbleFrameView()->SetTitleView(std::move(title_view));
+}
+
+void ManagePasswordUpdatePendingView::StyledLabelLinkClicked(
+    views::StyledLabel* label,
+    const gfx::Range& range,
+    int event_flags) {
+  DCHECK_EQ(model()->title_brand_link_range(), range);
+  model()->OnBrandLinkClicked();
+}
+
+void ManagePasswordUpdatePendingView::UpdateTitleText(
+    views::StyledLabel* title_view) {
+  title_view->SetText(GetWindowTitle());
+  if (!model()->title_brand_link_range().is_empty()) {
+    auto link_style = views::StyledLabel::RangeStyleInfo::CreateForLink();
+    link_style.disable_line_wrapping = false;
+    title_view->AddStyleRange(model()->title_brand_link_range(), link_style);
+  }
+}
diff --git a/chrome/browser/ui/views/passwords/manage_password_update_pending_view.h b/chrome/browser/ui/views/passwords/manage_password_update_pending_view.h
index d07410f..03420529 100644
--- a/chrome/browser/ui/views/passwords/manage_password_update_pending_view.h
+++ b/chrome/browser/ui/views/passwords/manage_password_update_pending_view.h
@@ -5,35 +5,47 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_PASSWORDS_MANAGE_PASSWORD_UPDATE_PENDING_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_PASSWORDS_MANAGE_PASSWORD_UPDATE_PENDING_VIEW_H_
 
-#include "ui/views/controls/button/button.h"
-#include "ui/views/view.h"
+#include "chrome/browser/ui/views/passwords/manage_passwords_bubble_delegate_view_base.h"
+#include "ui/views/controls/styled_label_listener.h"
+
+namespace views {
+class StyledLabel;
+}
 
 class CredentialsSelectionView;
-class ManagePasswordsBubbleView;
 
 // A view offering the user the ability to update credentials. Contains a
 // single credential row (in case of one credentials) or
 // CredentialsSelectionView otherwise, along with a "Update Passwords" button
 // and a rejection button.
-class ManagePasswordUpdatePendingView : public views::View,
-                                        public views::ButtonListener {
+class ManagePasswordUpdatePendingView
+    : public ManagePasswordsBubbleDelegateViewBase,
+      public views::StyledLabelListener {
  public:
-  explicit ManagePasswordUpdatePendingView(ManagePasswordsBubbleView* parent);
+  ManagePasswordUpdatePendingView(content::WebContents* web_contents,
+                                  views::View* anchor_view,
+                                  const gfx::Point& anchor_point,
+                                  DisplayReason reason);
   ~ManagePasswordUpdatePendingView() override;
 
  private:
-  // views::ButtonListener:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
-  // views::View:
+  // ManagePasswordsBubbleDelegateViewBase:
   gfx::Size CalculatePreferredSize() const override;
+  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
+  bool Accept() override;
+  bool Cancel() override;
+  bool Close() override;
+  void AddedToWidget() override;
 
-  ManagePasswordsBubbleView* parent_;
+  // views::StyledLabelListener:
+  void StyledLabelLinkClicked(views::StyledLabel* label,
+                              const gfx::Range& range,
+                              int event_flags) override;
+
+  void UpdateTitleText(views::StyledLabel* title_view);
 
   CredentialsSelectionView* selection_view_;
 
-  views::Button* update_button_;
-  views::Button* nope_button_;
-
   DISALLOW_COPY_AND_ASSIGN(ManagePasswordUpdatePendingView);
 };
 
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_delegate_view_base.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_delegate_view_base.cc
index 1e6594f..f9fdfd57 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_delegate_view_base.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_delegate_view_base.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/views/passwords/manage_password_auto_sign_in_view.h"
 #include "chrome/browser/ui/views/passwords/manage_password_items_view.h"
 #include "chrome/browser/ui/views/passwords/manage_password_save_confirmation_view.h"
+#include "chrome/browser/ui/views/passwords/manage_password_update_pending_view.h"
 #include "chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h"
 #include "chrome/browser/ui/views/passwords/manage_passwords_icon_views.h"
 #include "ui/base/material_design/material_design_controller.h"
@@ -94,6 +95,11 @@
   } else if (model_state == password_manager::ui::CONFIRMATION_STATE) {
     view = new ManagePasswordSaveConfirmationView(web_contents, anchor_view,
                                                   anchor_point, reason);
+  } else if (model_state ==
+             password_manager::ui::PENDING_PASSWORD_UPDATE_STATE) {
+    view = new ManagePasswordUpdatePendingView(web_contents, anchor_view,
+                                               anchor_point, reason);
+
   } else {
     // TODO(crbug.com/654115): Get rid of the one-bubble-for-everything
     // BubbleView.
@@ -118,6 +124,19 @@
   g_manage_passwords_bubble_->GetWidget()->Activate();
 }
 
+const content::WebContents*
+ManagePasswordsBubbleDelegateViewBase::GetWebContents() const {
+  return model_.GetWebContents();
+}
+
+base::string16 ManagePasswordsBubbleDelegateViewBase::GetWindowTitle() const {
+  return model_.title();
+}
+
+bool ManagePasswordsBubbleDelegateViewBase::ShouldShowWindowTitle() const {
+  return !model_.title().empty();
+}
+
 ManagePasswordsBubbleDelegateViewBase::ManagePasswordsBubbleDelegateViewBase(
     content::WebContents* web_contents,
     views::View* anchor_view,
@@ -128,8 +147,7 @@
              reason == AUTOMATIC ? ManagePasswordsBubbleModel::AUTOMATIC
                                  : ManagePasswordsBubbleModel::USER_ACTION),
       mouse_handler_(
-          std::make_unique<WebContentMouseHandler>(this,
-                                                   model_.GetWebContents())) {}
+          std::make_unique<WebContentMouseHandler>(this, web_contents)) {}
 
 ManagePasswordsBubbleDelegateViewBase::
     ~ManagePasswordsBubbleDelegateViewBase() {
@@ -137,20 +155,16 @@
     g_manage_passwords_bubble_ = nullptr;
 }
 
-const content::WebContents*
-ManagePasswordsBubbleDelegateViewBase::GetWebContents() const {
-  return model_.GetWebContents();
-}
-
-void ManagePasswordsBubbleDelegateViewBase::CloseBubble() {
+void ManagePasswordsBubbleDelegateViewBase::OnWidgetClosing(
+    views::Widget* widget) {
+  LocationBarBubbleDelegateView::OnWidgetClosing(widget);
+  if (widget != GetWidget())
+    return;
   mouse_handler_.reset();
-  LocationBarBubbleDelegateView::CloseBubble();
-}
-
-base::string16 ManagePasswordsBubbleDelegateViewBase::GetWindowTitle() const {
-  return model_.title();
-}
-
-bool ManagePasswordsBubbleDelegateViewBase::ShouldShowWindowTitle() const {
-  return !model_.title().empty();
+  // It can be the case that a password bubble is being closed while another
+  // password bubble is being opened. The metrics recorder can be shared between
+  // them and it doesn't understand the sequence [open1, open2, close1, close2].
+  // Therefore, we reset the model early (before the bubble destructor) to get
+  // the following sequence of events [open1, close1, open2, close2].
+  model_.OnBubbleClosing();
 }
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_delegate_view_base.h b/chrome/browser/ui/views/passwords/manage_passwords_bubble_delegate_view_base.h
index 3913ccb..0cda49d 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_delegate_view_base.h
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_delegate_view_base.h
@@ -70,10 +70,10 @@
 
   ~ManagePasswordsBubbleDelegateViewBase() override;
 
-  // LocationBarBubbleDelegateView:
-  void CloseBubble() override;
-
  private:
+  // WidgetObserver:
+  void OnWidgetClosing(views::Widget* widget) override;
+
   // Singleton instance of the Password bubble.The instance is owned by the
   // Bubble and will be deleted when the bubble closes.
   static ManagePasswordsBubbleDelegateViewBase* g_manage_passwords_bubble_;
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
index f475f37..0056f90 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/ui/views/passwords/manage_password_items_view.h"
 #include "chrome/browser/ui/views/passwords/manage_password_pending_view.h"
 #include "chrome/browser/ui/views/passwords/manage_password_sign_in_promo_view.h"
-#include "chrome/browser/ui/views/passwords/manage_password_update_pending_view.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/password_manager/core/common/password_manager_features.h"
@@ -301,9 +300,6 @@
 void ManagePasswordsBubbleView::CreateChild() {
   if (model()->state() == password_manager::ui::PENDING_PASSWORD_STATE) {
     AddChildView(new ManagePasswordPendingView(this));
-  } else if (model()->state() ==
-             password_manager::ui::PENDING_PASSWORD_UPDATE_STATE) {
-    AddChildView(new ManagePasswordUpdatePendingView(this));
   } else {
     // This model state should be handled by separate dialogs.
     NOTREACHED();
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index 67a0c5e..90c376e 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -48,7 +48,6 @@
 #include "chrome/browser/ui/views/profiles/badged_profile_photo.h"
 #include "chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h"
 #include "chrome/browser/ui/views/profiles/user_manager_view.h"
-#include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
 #include "chrome/common/pref_names.h"
@@ -653,13 +652,8 @@
   } else if (sender == signin_current_profile_button_) {
     ShowViewFromMode(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN);
   } else if (sender == signin_with_gaia_account_button_) {
-    // DiceTurnSyncOnHelper deletes itself once it's done.
-    new DiceTurnSyncOnHelper(
-        browser_->profile(), browser_, access_point_,
-        signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT,
-        signin_with_gaia_account_id_,
-        DiceTurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT);
-
+    signin_ui_util::EnableSync(browser_, dice_sync_promo_account_,
+                               access_point_);
   } else {
     // Either one of the "other profiles", or one of the profile accounts
     // buttons was pressed.
@@ -1063,11 +1057,13 @@
   }
 
   // Create a hover button to sign in the first account of |accounts|.
-  // TODO(http://crbug.com/794522): Use the account picture instead of the
-  // default avatar.
   gfx::Image account_icon =
-      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-          profiles::GetPlaceholderAvatarIconResourceID());
+      AccountTrackerServiceFactory::GetForProfile(browser_->profile())
+          ->GetAccountImage(accounts[0].account_id);
+  if (account_icon.IsEmpty()) {
+    account_icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+        profiles::GetPlaceholderAvatarIconResourceID());
+  }
   auto account_photo = std::make_unique<BadgedProfilePhoto>(
       BadgedProfilePhoto::BADGE_TYPE_NONE, account_icon);
   base::string16 first_account_button_title =
@@ -1086,7 +1082,7 @@
   promo_button_container->AddChildView(signin_button_view);
 
   signin_with_gaia_account_button_ = first_account_button;
-  signin_with_gaia_account_id_ = accounts[0].account_id;
+  dice_sync_promo_account_ = accounts[0];
 
   constexpr int kSmallMenuIconSize = 16;
   HoverButton* sync_to_another_account_button = new HoverButton(
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.h b/chrome/browser/ui/views/profiles/profile_chooser_view.h
index 56d2ec84..ced3e92 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.h
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.h
@@ -229,9 +229,8 @@
 
   CloseBubbleOnTabActivationHelper close_bubble_helper_;
 
-  // ID of the GAIA account that should be signed in when
-  // |signin_with_gaia_account_button_| is pressed.
-  std::string signin_with_gaia_account_id_;
+  // Account that is presented in the enable sync promo.
+  AccountInfo dice_sync_promo_account_;
 
   const bool dice_enabled_;
 
diff --git a/chrome/browser/ui/views/sync/bubble_sync_promo_view_unittest.cc b/chrome/browser/ui/views/sync/bubble_sync_promo_view_unittest.cc
index ea2ec3f..e3384bd 100644
--- a/chrome/browser/ui/views/sync/bubble_sync_promo_view_unittest.cc
+++ b/chrome/browser/ui/views/sync/bubble_sync_promo_view_unittest.cc
@@ -26,7 +26,10 @@
  protected:
   // BubbleSyncPromoDelegate:
   void ShowBrowserSignin() override { ++show_browser_signin_count_; }
+
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
   void EnableSync(const AccountInfo& account_info) override { NOTREACHED(); }
+#endif
 
   // Number of times that OnSignInLinkClicked has been called.
   int show_browser_signin_count_ = 0;
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index fcbea931..562b7df 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/auto_reset.h"
+#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/task_scheduler/post_task.h"
@@ -31,6 +32,7 @@
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/feature_engagement/features.h"
@@ -72,7 +74,8 @@
   *adjust_layout = true;
   return prefs->GetBoolean(prefs::kTabStripStackedLayout);
 #else
-  return false;
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kForceStackedTabStripLayout);
 #endif
 }
 
diff --git a/chrome/browser/ui/webui/discards/discards_ui.cc b/chrome/browser/ui/webui/discards/discards_ui.cc
index d237795..2d53a02 100644
--- a/chrome/browser/ui/webui/discards/discards_ui.cc
+++ b/chrome/browser/ui/webui/discards/discards_ui.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/ui/webui/discards/discards_ui.h"
 
-#include "base/memory/ptr_util.h"
+#include <utility>
+#include <vector>
+
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
@@ -23,15 +25,11 @@
 
 namespace {
 
-namespace {
-
 resource_coordinator::DiscardReason GetDiscardReason(bool urgent) {
   return urgent ? resource_coordinator::DiscardReason::kUrgent
                 : resource_coordinator::DiscardReason::kProactive;
 }
 
-}  // namespace
-
 class DiscardsDetailsProviderImpl : public mojom::DiscardsDetailsProvider {
  public:
   // This instance is deleted when the supplied pipe is destroyed.
@@ -129,5 +127,6 @@
 DiscardsUI::~DiscardsUI() {}
 
 void DiscardsUI::BindUIHandler(mojom::DiscardsDetailsProviderRequest request) {
-  ui_handler_.reset(new DiscardsDetailsProviderImpl(std::move(request)));
+  ui_handler_ =
+      std::make_unique<DiscardsDetailsProviderImpl>(std::move(request));
 }
diff --git a/chrome/browser/ui/webui/discards/discards_ui.h b/chrome/browser/ui/webui/discards/discards_ui.h
index 442fd98..212c664 100644
--- a/chrome/browser/ui/webui/discards/discards_ui.h
+++ b/chrome/browser/ui/webui/discards/discards_ui.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_DISCARDS_DISCARDS_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_DISCARDS_DISCARDS_UI_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "chrome/browser/ui/webui/discards/discards.mojom.h"
 #include "chrome/browser/ui/webui/mojo_web_ui_controller.h"
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
index 24fc3095..3ce482e 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -162,6 +162,8 @@
   if (net::GetValueForKeyInQuery(web_contents->GetURL(), "type", &type_param)) {
     if (type_param == "hpkp_failure") {
       cert_error = net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
+    } else if (type_param == "ct_failure") {
+      cert_error = net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
     }
   }
   net::SSLInfo ssl_info;
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui_browsertest.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui_browsertest.cc
index 8b82fe2..cfda310 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui_browsertest.cc
@@ -12,6 +12,7 @@
 #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_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 
 class InterstitialUITest : public InProcessBrowserTest {
@@ -76,6 +77,18 @@
                    "Privacy error");
 }
 
+IN_PROC_BROWSER_TEST_F(InterstitialUITest, CTInterstitial) {
+  TestInterstitial(GURL("chrome://interstitials/ssl?type=ct_failure"),
+                   "Privacy error");
+  bool found_ct_error = false;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      "window.domAutomationController.send(document.body.textContent.indexOf('"
+      "CERTIFICATE_TRANSPARENCY') != -1);",
+      &found_ct_error));
+  EXPECT_TRUE(found_ct_error);
+}
+
 IN_PROC_BROWSER_TEST_F(InterstitialUITest, MalwareInterstitial) {
   TestInterstitial(
       GURL("chrome://interstitials/safebrowsing?type=malware"),
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
index 6b171c72..9150faf 100644
--- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
@@ -377,9 +377,6 @@
   base::RecordAction(base::UserMetricsAction("Signin_Signin_Succeed"));
 
   // Show Sync confirmation.
-  browser_sync::ProfileSyncService* sync_service = GetProfileSyncService();
-  if (sync_service)
-    sync_blocker_ = sync_service->GetSetupInProgressHandle();
   scoped_login_ui_service_observer_.Add(
       LoginUIServiceFactory::GetForProfile(profile_));
   browser_ = EnsureBrowser(browser_, profile_);
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h
index d1ef87b..d83197f 100644
--- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h
@@ -26,10 +26,6 @@
 class ProfileSyncService;
 }
 
-namespace syncer {
-class SyncSetupInProgressHandle;
-}
-
 // Handles details of signing the user in with SigninManager and turning on
 // sync for an account that is already present in the token service.
 class DiceTurnSyncOnHelper : public BrowserListObserver,
@@ -144,9 +140,6 @@
   // Account information.
   const AccountInfo account_info_;
 
-  // Prevents Sync from running until configuration is complete.
-  std::unique_ptr<syncer::SyncSetupInProgressHandle> sync_blocker_;
-
   // Policy credentials we keep while determining whether to create
   // a new profile for an enterprise user or not.
   std::string dm_token_;
diff --git a/chrome/browser/vr/PRESUBMIT.py b/chrome/browser/vr/PRESUBMIT.py
index 4bb6e355..5e94690 100644
--- a/chrome/browser/vr/PRESUBMIT.py
+++ b/chrome/browser/vr/PRESUBMIT.py
@@ -49,6 +49,8 @@
   against all Chromium commits, but should be run against changes
   likely to affect these tests.
 
+  Also, it compiles the Linux VR tryserver to compile the UI testapp.
+
   When adding/removing tests here, ensure that both gpu/PRESUBMIT.py and
   ui/gl/PRESUBMIT.py are updated.
   """
@@ -59,5 +61,6 @@
       'master.tryserver.chromium.mac:mac_optional_gpu_tests_rel',
       'master.tryserver.chromium.win:win_optional_gpu_tests_rel',
       'master.tryserver.chromium.android:android_optional_gpu_tests_rel',
+      'master.tryserver.chromium.linux:linux_vr',
     ],
     'Automatically added optional GPU tests to run on CQ.')
diff --git a/chrome/browser/vr/elements/text.cc b/chrome/browser/vr/elements/text.cc
index 3c1cd1d..a892bdc 100644
--- a/chrome/browser/vr/elements/text.cc
+++ b/chrome/browser/vr/elements/text.cc
@@ -10,6 +10,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/gfx/render_text.h"
 
@@ -150,6 +151,7 @@
   void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override;
 
   gfx::SizeF size_;
+  gfx::Vector2d texture_offset_;
   base::string16 text_;
   float font_height_dmms_ = 0;
   float text_width_ = 0;
@@ -295,12 +297,17 @@
 
   // Note, there is no padding here whatsoever.
   size_ = gfx::SizeF(text_bounds.size());
+  if (parameters.shadows_enabled) {
+    texture_offset_ = gfx::Vector2d(gfx::ToFlooredInt(parameters.shadow_size),
+                                    gfx::ToFlooredInt(parameters.shadow_size));
+  }
 }
 
 void TextTexture::Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) {
   cc::SkiaPaintCanvas paint_canvas(sk_canvas);
   gfx::Canvas gfx_canvas(&paint_canvas, 1.0f);
   gfx::Canvas* canvas = &gfx_canvas;
+  canvas->Translate(texture_offset_);
 
   for (auto& render_text : lines_)
     render_text->Draw(canvas);
diff --git a/chrome/browser/vr/elements/ui_element_name.cc b/chrome/browser/vr/elements/ui_element_name.cc
index b2fad274..0a90f463 100644
--- a/chrome/browser/vr/elements/ui_element_name.cc
+++ b/chrome/browser/vr/elements/ui_element_name.cc
@@ -118,6 +118,7 @@
     "kDownloadedSnackbar",
     "kControllerTrackpadLabel",
     "kControllerExitButtonLabel",
+    "kControllerBackButtonLabel",
 };
 
 static_assert(
diff --git a/chrome/browser/vr/elements/ui_element_name.h b/chrome/browser/vr/elements/ui_element_name.h
index 9857f5d..dea3d3e 100644
--- a/chrome/browser/vr/elements/ui_element_name.h
+++ b/chrome/browser/vr/elements/ui_element_name.h
@@ -117,6 +117,7 @@
   kDownloadedSnackbar,
   kControllerTrackpadLabel,
   kControllerExitButtonLabel,
+  kControllerBackButtonLabel,
 
   // This must be last.
   kNumUiElementNames,
diff --git a/chrome/browser/vr/elements/ui_texture.cc b/chrome/browser/vr/elements/ui_texture.cc
index f3182db97..3fd1a47 100644
--- a/chrome/browser/vr/elements/ui_texture.cc
+++ b/chrome/browser/vr/elements/ui_texture.cc
@@ -126,7 +126,6 @@
     // Set calculated height.
     if (bounds->height() == 0)
       bounds->set_height(height);
-
   } else {
     std::unique_ptr<gfx::RenderText> render_text = CreateConfiguredRenderText(
         text, font_list, parameters.color, parameters.text_alignment,
@@ -147,6 +146,12 @@
     render_text->SetDisplayRect(*bounds);
     lines.push_back(std::move(render_text));
   }
+
+  if (parameters.shadows_enabled) {
+    bounds->Inset(-parameters.shadow_size, -parameters.shadow_size);
+    bounds->Offset(parameters.shadow_size, parameters.shadow_size);
+  }
+
   return lines;
 }
 
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc
index 2fbc2d0..9d227fd 100644
--- a/chrome/browser/vr/testapp/vr_test_context.cc
+++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -55,7 +55,7 @@
 constexpr float kViewScaleAdjustmentFactor = 0.2f;
 constexpr float kPageLoadTimeMilliseconds = 500;
 
-constexpr gfx::Point3F kDefaultLaserOrigin = {0.5f, -0.5f, 0.f};
+constexpr gfx::Point3F kDefaultLaserOrigin = {0.1f, -0.5f, 0.f};
 constexpr gfx::Vector3dF kLaserLocalOffset = {0.f, -0.0075f, -0.05f};
 constexpr float kControllerScaleFactor = 1.5f;
 
diff --git a/chrome/browser/vr/ui_scene_constants.h b/chrome/browser/vr/ui_scene_constants.h
index 5a64662..50c9fc76 100644
--- a/chrome/browser/vr/ui_scene_constants.h
+++ b/chrome/browser/vr/ui_scene_constants.h
@@ -260,9 +260,9 @@
 static constexpr float kSnackbarMoveInAngle = -base::kPiFloat / 10;
 static constexpr int kSnackbarTransitionDurationMs = 300;
 
-static constexpr float kControllerLabelSpacerSize = 0.003f;
-static constexpr float kControllerLabelLayoutMargin = 0.005f;
-static constexpr float kControllerLabelCalloutWidth = 0.025f;
+static constexpr float kControllerLabelSpacerSize = 0.025f;
+static constexpr float kControllerLabelLayoutMargin = -0.005f;
+static constexpr float kControllerLabelCalloutWidth = 0.02f;
 static constexpr float kControllerLabelCalloutHeight = 0.001f;
 static constexpr float kControllerLabelFontHeight = 0.05f;
 static constexpr float kControllerLabelScale = 0.2f;
@@ -270,6 +270,7 @@
 // TODO(vollick): these should be encoded in the controller mesh.
 static constexpr float kControllerTrackpadOffset = -0.035f;
 static constexpr float kControllerExitButtonOffset = -0.008f;
+static constexpr float kControllerBackButtonOffset = -0.008f;
 
 static constexpr int kControllerLabelTransitionDurationMs = 700;
 
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index 4ae0a3c..9c0fb8e2 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -1308,10 +1308,15 @@
   auto exit_button_label = CreateControllerLabel(
       kControllerExitButtonLabel, kControllerExitButtonOffset,
       l10n_util::GetStringUTF16(IDS_VR_BUTTON_EXIT), model_);
-
   VR_BIND_VISIBILITY(exit_button_label, model->fullscreen_enabled());
   callout_group->AddChild(std::move(exit_button_label));
 
+  auto back_button_label = CreateControllerLabel(
+      kControllerBackButtonLabel, kControllerBackButtonOffset,
+      l10n_util::GetStringUTF16(IDS_VR_BUTTON_BACK), model_);
+  VR_BIND_VISIBILITY(back_button_label, model->omnibox_editing_enabled());
+  callout_group->AddChild(std::move(back_button_label));
+
   controller->AddChild(std::move(callout_group));
 
   scene_->AddUiElement(kControllerGroup, std::move(controller));
diff --git a/chrome/browser/vr/ui_unittest.cc b/chrome/browser/vr/ui_unittest.cc
index 5f11028..e084d0b 100644
--- a/chrome/browser/vr/ui_unittest.cc
+++ b/chrome/browser/vr/ui_unittest.cc
@@ -1070,18 +1070,28 @@
 
   EXPECT_FALSE(IsVisible(kControllerTrackpadLabel));
   EXPECT_FALSE(IsVisible(kControllerExitButtonLabel));
+  EXPECT_FALSE(IsVisible(kControllerBackButtonLabel));
 
   model_->controller.resting_in_viewport = true;
   EXPECT_TRUE(IsVisible(kControllerTrackpadLabel));
   EXPECT_FALSE(IsVisible(kControllerExitButtonLabel));
+  EXPECT_FALSE(IsVisible(kControllerBackButtonLabel));
 
-  ui_->SetFullscreen(true);
+  model_->push_mode(kModeFullscreen);
   EXPECT_TRUE(IsVisible(kControllerTrackpadLabel));
   EXPECT_TRUE(IsVisible(kControllerExitButtonLabel));
+  EXPECT_FALSE(IsVisible(kControllerBackButtonLabel));
+
+  model_->pop_mode(kModeFullscreen);
+  model_->push_mode(kModeEditingOmnibox);
+  EXPECT_TRUE(IsVisible(kControllerTrackpadLabel));
+  EXPECT_FALSE(IsVisible(kControllerExitButtonLabel));
+  EXPECT_TRUE(IsVisible(kControllerBackButtonLabel));
 
   model_->controller.resting_in_viewport = false;
   EXPECT_FALSE(IsVisible(kControllerTrackpadLabel));
   EXPECT_FALSE(IsVisible(kControllerExitButtonLabel));
+  EXPECT_FALSE(IsVisible(kControllerBackButtonLabel));
 }
 
 }  // namespace vr
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 4a0f972..bc000f1 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -422,6 +422,9 @@
 // Forces Chrome to use localNTP instead of server (GWS) NTP.
 const char kForceLocalNtp[]                 = "force-local-ntp";
 
+// Forces Chrome to use a stacked tab strip layout.
+const char kForceStackedTabStripLayout[]    = "force-stacked-tab-strip-layout";
+
 // Specifies which page will be displayed in newly-opened tabs. We need this
 // for testing purposes so that the UI tests don't depend on what comes up for
 // http://google.com.
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 7f500f51..5adf77db 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -134,6 +134,7 @@
 extern const char kForceFirstRun[];
 extern const char kForceFirstRunDialog[];
 extern const char kForceLocalNtp[];
+extern const char kForceStackedTabStripLayout[];
 extern const char kHomePage[];
 extern const char kIgnoreUrlFetcherCertRequests[];
 extern const char kIncognito[];
diff --git a/chrome/common/media_router/discovery/media_sink_service_base.cc b/chrome/common/media_router/discovery/media_sink_service_base.cc
index 9374c4ff..f3f62c19 100644
--- a/chrome/common/media_router/discovery/media_sink_service_base.cc
+++ b/chrome/common/media_router/discovery/media_sink_service_base.cc
@@ -37,8 +37,12 @@
   }
 
   DVLOG(2) << "Send sinks to media router, [size]: " << current_sinks_.size();
-  on_sinks_discovered_cb_.Run(std::vector<MediaSinkInternal>(
-      current_sinks_.begin(), current_sinks_.end()));
+
+  std::vector<MediaSinkInternal> sinks;
+  for (const auto& sink_it : current_sinks_)
+    sinks.push_back(sink_it.second);
+
+  on_sinks_discovered_cb_.Run(std::move(sinks));
   mrp_sinks_ = current_sinks_;
   discovery_timer_->Stop();
   RecordDeviceCounts();
diff --git a/chrome/common/media_router/discovery/media_sink_service_base.h b/chrome/common/media_router/discovery/media_sink_service_base.h
index ea0b503..f8e323cd 100644
--- a/chrome/common/media_router/discovery/media_sink_service_base.h
+++ b/chrome/common/media_router/discovery/media_sink_service_base.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 
-#include "base/containers/flat_set.h"
+#include "base/containers/flat_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/sequence_checker.h"
 #include "base/timer/timer.h"
@@ -44,21 +44,24 @@
   // |StartTimer()| is called.
   void RestartTimer();
 
-  // Sorted sinks from current round of discovery.
-  base::flat_set<MediaSinkInternal> current_sinks_;
+  // Sorted sinks from current round of discovery, keyed by sink ID.
+  base::flat_map<std::string, MediaSinkInternal> current_sinks_;
 
  private:
   friend class MediaSinkServiceBaseTest;
   FRIEND_TEST_ALL_PREFIXES(MediaSinkServiceBaseTest,
                            TestOnDiscoveryComplete_SameSink);
+  FRIEND_TEST_ALL_PREFIXES(MediaSinkServiceBaseTest,
+                           TestOnDiscoveryComplete_SameSinkDifferentOrders);
 
   // Helper method to start |discovery_timer_|.
   void DoStart();
 
   OnSinksDiscoveredCallback on_sinks_discovered_cb_;
 
-  // Sorted sinks sent to Media Router Provider in last |OnDiscoveryComplete()|
-  base::flat_set<MediaSinkInternal> mrp_sinks_;
+  // Sorted sinks sent to Media Router Provider in last |OnDiscoveryComplete()|,
+  // keyed by sink ID.
+  base::flat_map<std::string, MediaSinkInternal> mrp_sinks_;
 
   // Timer for completing the current round of discovery.
   std::unique_ptr<base::Timer> discovery_timer_;
diff --git a/chrome/common/media_router/discovery/media_sink_service_base_unittest.cc b/chrome/common/media_router/discovery/media_sink_service_base_unittest.cc
index 8e7de8b9..953c8ba 100644
--- a/chrome/common/media_router/discovery/media_sink_service_base_unittest.cc
+++ b/chrome/common/media_router/discovery/media_sink_service_base_unittest.cc
@@ -58,13 +58,25 @@
     media_sink_service_.SetTimerForTest(base::WrapUnique(mock_timer_));
   }
 
+  void PopulateSinks(const std::vector<MediaSinkInternal>& old_sinks,
+                     const std::vector<MediaSinkInternal>& new_sinks) {
+    media_sink_service_.mrp_sinks_.clear();
+    for (const auto& old_sink : old_sinks) {
+      std::string sink_id = old_sink.sink().id();
+      media_sink_service_.mrp_sinks_[sink_id] = old_sink;
+    }
+
+    media_sink_service_.current_sinks_.clear();
+    for (const auto& new_sink : new_sinks) {
+      std::string sink_id = new_sink.sink().id();
+      media_sink_service_.current_sinks_[sink_id] = new_sink;
+    }
+  }
+
   void TestOnDiscoveryComplete(
       const std::vector<MediaSinkInternal>& old_sinks,
       const std::vector<MediaSinkInternal>& new_sinks) {
-    media_sink_service_.mrp_sinks_ =
-        base::flat_set<MediaSinkInternal>(old_sinks.begin(), old_sinks.end());
-    media_sink_service_.current_sinks_ =
-        base::flat_set<MediaSinkInternal>(new_sinks.begin(), new_sinks.end());
+    PopulateSinks(old_sinks, new_sinks);
     EXPECT_CALL(mock_sink_discovered_cb_, Run(new_sinks));
     media_sink_service_.OnDiscoveryComplete();
   }
@@ -88,6 +100,17 @@
   media_sink_service_.OnDiscoveryComplete();
 }
 
+TEST_F(MediaSinkServiceBaseTest,
+       TestOnDiscoveryComplete_SameSinkDifferentOrders) {
+  std::vector<MediaSinkInternal> old_sinks = CreateDialMediaSinks();
+  std::vector<MediaSinkInternal> new_sinks = CreateDialMediaSinks();
+  std::reverse(new_sinks.begin(), new_sinks.end());
+
+  PopulateSinks(old_sinks, new_sinks);
+  EXPECT_CALL(mock_sink_discovered_cb_, Run(new_sinks)).Times(0);
+  media_sink_service_.OnDiscoveryComplete();
+}
+
 TEST_F(MediaSinkServiceBaseTest, TestOnDiscoveryComplete_OneNewSink) {
   std::vector<MediaSinkInternal> old_sinks = CreateDialMediaSinks();
   std::vector<MediaSinkInternal> new_sinks = CreateDialMediaSinks();
diff --git a/chrome/installer/zucchini/image_utils.h b/chrome/installer/zucchini/image_utils.h
index c6dd4e8..599f9b1 100644
--- a/chrome/installer/zucchini/image_utils.h
+++ b/chrome/installer/zucchini/image_utils.h
@@ -195,6 +195,7 @@
 // A matched pair of Elements.
 struct ElementMatch {
   bool IsValid() const { return old_element.exe_type == new_element.exe_type; }
+  ExecutableType exe_type() const { return old_element.exe_type; }
 
   Element old_element;
   Element new_element;
diff --git a/chrome/installer/zucchini/patch_read_write_unittest.cc b/chrome/installer/zucchini/patch_read_write_unittest.cc
index e18761a0..580144d 100644
--- a/chrome/installer/zucchini/patch_read_write_unittest.cc
+++ b/chrome/installer/zucchini/patch_read_write_unittest.cc
@@ -63,22 +63,22 @@
 
 TEST(PatchTest, ParseSerializeElementMatch) {
   ByteVector data = {
-      1, 0, 0, 0,  // old_offset
-      3, 0, 0, 0,  // new_offset
-      2, 0, 0, 0,  // old_length
-      4, 0, 0, 0,  // new_length
-      7, 0, 0, 0,  // kExeTypeDex
+      0x01, 0, 0, 0,  // old_offset
+      0x03, 0, 0, 0,  // new_offset
+      0x02, 0, 0, 0,  // old_length
+      0x04, 0, 0, 0,  // new_length
+      7,    0, 0, 0,  // kExeTypeDex
   };
   BufferSource buffer_source(data.data(), data.size());
   ElementMatch element_match = {};
   EXPECT_TRUE(patch::ParseElementMatch(&buffer_source, &element_match));
-
+  EXPECT_EQ(kExeTypeDex, element_match.exe_type());
   EXPECT_EQ(kExeTypeDex, element_match.old_element.exe_type);
   EXPECT_EQ(kExeTypeDex, element_match.new_element.exe_type);
-  EXPECT_EQ(size_t(1), element_match.old_element.offset);
-  EXPECT_EQ(size_t(2), element_match.old_element.size);
-  EXPECT_EQ(size_t(3), element_match.new_element.offset);
-  EXPECT_EQ(size_t(4), element_match.new_element.size);
+  EXPECT_EQ(0x1U, element_match.old_element.offset);
+  EXPECT_EQ(0x2U, element_match.old_element.size);
+  EXPECT_EQ(0x3U, element_match.new_element.offset);
+  EXPECT_EQ(0x4U, element_match.new_element.size);
 
   size_t size = patch::SerializedElementMatchSize(element_match);
   EXPECT_EQ(data.size(), size);
@@ -429,12 +429,13 @@
       TestInitialize<PatchElementReader>(&data);
 
   ElementMatch element_match = patch_element_reader.element_match();
+  EXPECT_EQ(kExeTypeWin32X86, element_match.exe_type());
   EXPECT_EQ(kExeTypeWin32X86, element_match.old_element.exe_type);
-  EXPECT_EQ(0x01U, element_match.old_element.offset);
-  EXPECT_EQ(0x02U, element_match.old_element.size);
   EXPECT_EQ(kExeTypeWin32X86, element_match.new_element.exe_type);
-  EXPECT_EQ(0x03U, element_match.new_element.offset);
-  EXPECT_EQ(0x04U, element_match.new_element.size);
+  EXPECT_EQ(0x1U, element_match.old_element.offset);
+  EXPECT_EQ(0x2U, element_match.old_element.size);
+  EXPECT_EQ(0x3U, element_match.new_element.offset);
+  EXPECT_EQ(0x4U, element_match.new_element.size);
 
   EquivalenceSource equivalence_source =
       patch_element_reader.GetEquivalenceSource();
diff --git a/chrome/installer/zucchini/patch_writer.cc b/chrome/installer/zucchini/patch_writer.cc
index d4e37f8..13be44d0 100644
--- a/chrome/installer/zucchini/patch_writer.cc
+++ b/chrome/installer/zucchini/patch_writer.cc
@@ -29,7 +29,7 @@
       base::checked_cast<uint32_t>(element_match.old_element.size);
   element_header.new_length =
       base::checked_cast<uint32_t>(element_match.new_element.size);
-  element_header.exe_type = element_match.old_element.exe_type;
+  element_header.exe_type = element_match.exe_type();
 
   return sink->PutValue<PatchElementHeader>(element_header);
 }
diff --git a/chrome/installer/zucchini/zucchini_apply.cc b/chrome/installer/zucchini/zucchini_apply.cc
index 59477be..1f4cd00 100644
--- a/chrome/installer/zucchini/zucchini_apply.cc
+++ b/chrome/installer/zucchini/zucchini_apply.cc
@@ -242,9 +242,8 @@
 
   for (const auto& element_patch : patch_reader.elements()) {
     ElementMatch match = element_patch.element_match();
-    if (!ApplyElement(match.old_element.exe_type,
-                      old_image[match.old_element.region()], element_patch,
-                      new_image[match.new_element.region()]))
+    if (!ApplyElement(match.exe_type(), old_image[match.old_element.region()],
+                      element_patch, new_image[match.new_element.region()]))
       return status::kStatusFatal;
   }
 
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index ed745bd..b05df588 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -751,13 +751,7 @@
   },
 
   "EnableCommonNameFallbackForLocalAnchors": {
-    "os": ["win", "linux", "mac", "chromeos", "android"],
-    "test_policy": { "EnableCommonNameFallbackForLocalAnchors": true },
-    "pref_mappings": [
-      { "pref": "ssl.common_name_fallback_enabled_for_local_anchors",
-        "local_state": true
-      }
-    ]
+    "note": "This policy is deprecated and removed since Chrome 66."
   },
 
   "AuthSchemes": {
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java
index fec40f7..c4ae8edc 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java
@@ -7,10 +7,10 @@
 import android.content.Context;
 
 import org.chromium.base.ApplicationStatus;
+import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.CommandLineInitUtil;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
-import org.chromium.content.app.ContentApplication;
 
 /**
  * Entry point for the Android cast shell application.  Handles initialization of information that
@@ -20,7 +20,7 @@
  * processes don't need most of the full "setup" performed in CastBrowserHelper.java, but they do
  * require a few basic pieces (found here).
  */
-public class CastApplication extends ContentApplication {
+public class CastApplication extends BaseChromiumApplication {
     private static final String TAG = "CastApplication";
 
     private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "cast_shell";
diff --git a/chromecast/graphics/cast_window_manager_aura.cc b/chromecast/graphics/cast_window_manager_aura.cc
index 409fee669..34a4112 100644
--- a/chromecast/graphics/cast_window_manager_aura.cc
+++ b/chromecast/graphics/cast_window_manager_aura.cc
@@ -266,8 +266,8 @@
   wm::SetActivationClient(window_tree_host_->window(), nullptr);
   aura::client::SetFocusClient(window_tree_host_->window(), nullptr);
   focus_client_.reset();
-  window_tree_host_.reset();
   system_gesture_event_handler_.reset();
+  window_tree_host_.reset();
 }
 
 void CastWindowManagerAura::SetWindowId(gfx::NativeView window,
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 27e9a18..54d8d22 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10324.0.0
\ No newline at end of file
+10330.0.0
\ No newline at end of file
diff --git a/components/arc/arc_bridge_host_impl.cc b/components/arc/arc_bridge_host_impl.cc
index eb7aaae..0ba4d8a9 100644
--- a/components/arc/arc_bridge_host_impl.cc
+++ b/components/arc/arc_bridge_host_impl.cc
@@ -233,6 +233,12 @@
                   std::move(rotation_lock_ptr));
 }
 
+void ArcBridgeHostImpl::OnScreenCaptureInstanceReady(
+    mojom::ScreenCaptureInstancePtr screen_capture_ptr) {
+  OnInstanceReady(arc_bridge_service_->screen_capture(),
+                  std::move(screen_capture_ptr));
+}
+
 void ArcBridgeHostImpl::OnStorageManagerInstanceReady(
     mojom::StorageManagerInstancePtr storage_manager_ptr) {
   OnInstanceReady(arc_bridge_service_->storage_manager(),
diff --git a/components/arc/arc_bridge_host_impl.h b/components/arc/arc_bridge_host_impl.h
index 0a7374a..f4e86e28 100644
--- a/components/arc/arc_bridge_host_impl.h
+++ b/components/arc/arc_bridge_host_impl.h
@@ -82,6 +82,8 @@
   void OnProcessInstanceReady(mojom::ProcessInstancePtr process_ptr) override;
   void OnRotationLockInstanceReady(
       mojom::RotationLockInstancePtr rotation_lock_ptr) override;
+  void OnScreenCaptureInstanceReady(
+      mojom::ScreenCaptureInstancePtr screen_capture_ptr) override;
   void OnStorageManagerInstanceReady(
       mojom::StorageManagerInstancePtr storage_manager_ptr) override;
   void OnTracingInstanceReady(mojom::TracingInstancePtr trace_ptr) override;
diff --git a/components/arc/arc_bridge_service.h b/components/arc/arc_bridge_service.h
index 6cfd090..92916d6 100644
--- a/components/arc/arc_bridge_service.h
+++ b/components/arc/arc_bridge_service.h
@@ -65,6 +65,8 @@
 class PrintInstance;
 class ProcessInstance;
 class RotationLockInstance;
+class ScreenCaptureHost;
+class ScreenCaptureInstance;
 class StorageManagerInstance;
 class TracingInstance;
 class TtsHost;
@@ -181,6 +183,10 @@
   ConnectionHolder<mojom::RotationLockInstance>* rotation_lock() {
     return &rotation_lock_;
   }
+  ConnectionHolder<mojom::ScreenCaptureInstance, mojom::ScreenCaptureHost>*
+  screen_capture() {
+    return &screen_capture_;
+  }
   ConnectionHolder<mojom::StorageManagerInstance>* storage_manager() {
     return &storage_manager_;
   }
@@ -249,6 +255,8 @@
   ConnectionHolder<mojom::PrintInstance, mojom::PrintHost> print_;
   ConnectionHolder<mojom::ProcessInstance> process_;
   ConnectionHolder<mojom::RotationLockInstance> rotation_lock_;
+  ConnectionHolder<mojom::ScreenCaptureInstance, mojom::ScreenCaptureHost>
+      screen_capture_;
   ConnectionHolder<mojom::StorageManagerInstance> storage_manager_;
   ConnectionHolder<mojom::TracingInstance> tracing_;
   ConnectionHolder<mojom::TtsInstance, mojom::TtsHost> tts_;
diff --git a/components/arc/common/BUILD.gn b/components/arc/common/BUILD.gn
index 0ea2baf..c22a239c 100644
--- a/components/arc/common/BUILD.gn
+++ b/components/arc/common/BUILD.gn
@@ -43,6 +43,7 @@
       "process.mojom",
       "rotation_lock.mojom",
       "scale_factor.mojom",
+      "screen_capture.mojom",
       "storage_manager.mojom",
       "tracing.mojom",
       "tts.mojom",
diff --git a/components/arc/common/arc_bridge.mojom b/components/arc/common/arc_bridge.mojom
index c779b381..492c170 100644
--- a/components/arc/common/arc_bridge.mojom
+++ b/components/arc/common/arc_bridge.mojom
@@ -32,6 +32,7 @@
 import "print.mojom";
 import "process.mojom";
 import "rotation_lock.mojom";
+import "screen_capture.mojom";
 import "storage_manager.mojom";
 import "tracing.mojom";
 import "tts.mojom";
@@ -42,9 +43,9 @@
 import "volume_mounter.mojom";
 import "wallpaper.mojom";
 
-// Next MinVersion: 35
+// Next MinVersion: 36
 // Deprecated method IDs: 101, 105
-// Next method ID: 140
+// Next method ID: 141
 interface ArcBridgeHost {
   // Keep the entries alphabetical. In order to do so without breaking
   // compatibility with the ARC instance, explicitly assign each interface a
@@ -142,6 +143,9 @@
   // Notifies Chrome that the RotationLockInstance interface is ready.
   [MinVersion=32] OnRotationLockInstanceReady@137(RotationLockInstance instance_ptr);
 
+  // Notifies Chrome that the ScreenCaptureInstance interface is ready.
+  [MinVersion=35] OnScreenCaptureInstanceReady@140(ScreenCaptureInstance instance_ptr);
+
   // Notifies Chrome that the StorageManagerInstance interface is ready.
   [MinVersion=12] OnStorageManagerInstanceReady@118(StorageManagerInstance instance_ptr);
 
diff --git a/components/arc/common/screen_capture.mojom b/components/arc/common/screen_capture.mojom
new file mode 100644
index 0000000..d6c96b8
--- /dev/null
+++ b/components/arc/common/screen_capture.mojom
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Mojo interface for performing screen capture in ChromeOS at the request of
+// Android. Android does not have access to the full desktop for capture (it has
+// access only to its Windows), so via this IPC mechanism it can request
+// permissions to capture the entire desktop and then also perform that capture.
+
+// The original version of this file lives in the Chromium repository at:
+// src/components/arc/common/screen_capture.mojom
+
+module arc.mojom;
+
+// For gfx::Size.
+import "video_common.mojom";
+
+// Implemented by Chrome in order to allow requesting of permissions to perform
+// desktop capture as well as creating a session for it.
+interface ScreenCaptureHost {
+  // This will also show the desktop picker in case of multiple displays and
+  // will then link that desktop window to the granted permission.
+  // display_name is the string that should be used in the UI
+  // package_name is what should be used as the permission token
+  // returns true if the user accepts, false otherwise
+  RequestPermission@0(string display_name, string package_name) => (bool granted);
+
+  // Starts a new capture session, binding the session interface to the passed
+  // in session request.
+  // notifier interface passed in will be used to send messages back to Android
+  //     for when updates are needed by the Chrome rendering engine
+  // package_name should correspond to what was passed into the
+  //     RequestPermission call
+  // size should have the width/height of the buffers used
+  // returns null interface in the case the permission was not granted, a valid
+  //     interface pointer otherwise
+  OpenSession@1(ScreenCaptureSessionNotifier notifier,
+                string package_name, Size size) =>
+                (ScreenCaptureSession? session);
+};
+
+// Implemented by Chrome for handling a screen capture session.
+interface ScreenCaptureSession {
+  // Called to set the graphics buffer that the screen capture should be
+  // rendered to. This call does not return until the rendering is complete to
+  // the passed in buffer.
+  // graphics_buffer should be a handle to the buffer which corresponds to the
+  //     surface being rendered to
+  // stride is the stride in pixels for each row of the buffer
+  SetOutputBuffer@0(handle graphics_buffer, uint32 stride) => ();
+};
+
+// Implemented by Android.
+interface ScreenCaptureInstance {
+  // Establishes full-duplex communication with the host.
+  Init@0(ScreenCaptureHost host_ptr) => ();
+};
+
+// Implemented by Android as a callback mechanism.
+interface ScreenCaptureSessionNotifier {
+  // This is called when Chrome detects a compositor update but Android is not
+  // actively rendering. This will occur if the Android windows are minimized or
+  // not animating but Chrome windows are since Android’s rendering stack does
+  // not update if nothing in Android itself is changing.
+  ForceUpdate@0();
+};
diff --git a/components/arc/test/fake_arc_bridge_host.cc b/components/arc/test/fake_arc_bridge_host.cc
index 148f5c22..c4c567a7 100644
--- a/components/arc/test/fake_arc_bridge_host.cc
+++ b/components/arc/test/fake_arc_bridge_host.cc
@@ -90,6 +90,9 @@
 void FakeArcBridgeHost::OnRotationLockInstanceReady(
     mojom::RotationLockInstancePtr rotation_lock_ptr) {}
 
+void FakeArcBridgeHost::OnScreenCaptureInstanceReady(
+    mojom::ScreenCaptureInstancePtr screen_capture_ptr) {}
+
 void FakeArcBridgeHost::OnStorageManagerInstanceReady(
     mojom::StorageManagerInstancePtr storage_manager_ptr) {}
 
diff --git a/components/arc/test/fake_arc_bridge_host.h b/components/arc/test/fake_arc_bridge_host.h
index cce1ad2b..83036ea 100644
--- a/components/arc/test/fake_arc_bridge_host.h
+++ b/components/arc/test/fake_arc_bridge_host.h
@@ -60,6 +60,8 @@
   void OnProcessInstanceReady(mojom::ProcessInstancePtr process_ptr) override;
   void OnRotationLockInstanceReady(
       mojom::RotationLockInstancePtr rotation_lock_ptr) override;
+  void OnScreenCaptureInstanceReady(
+      mojom::ScreenCaptureInstancePtr screen_capture_ptr) override;
   void OnStorageManagerInstanceReady(
       mojom::StorageManagerInstancePtr storage_manager_ptr) override;
   void OnTracingInstanceReady(mojom::TracingInstancePtr trace_ptr) override;
diff --git a/components/browsing_data/core/counters/history_counter.cc b/components/browsing_data/core/counters/history_counter.cc
index 93d8e0e3..dfa5433 100644
--- a/components/browsing_data/core/counters/history_counter.cc
+++ b/components/browsing_data/core/counters/history_counter.cc
@@ -88,7 +88,7 @@
   history::QueryOptions options;
   options.max_count = 1;
   options.begin_time = GetPeriodStart();
-  options.end_time = base::Time::Max();
+  options.end_time = GetPeriodEnd();
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation("web_history_counter",
                                                  "web_history_service",
diff --git a/components/component_updater/component_installer.cc b/components/component_updater/component_installer.cc
index 499b32a..903ad21 100644
--- a/components/component_updater/component_installer.cc
+++ b/components/component_updater/component_installer.cc
@@ -22,6 +22,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "base/version.h"
+#include "build/build_config.h"
 #include "components/component_updater/component_updater_paths.h"
 #include "components/component_updater/component_updater_service.h"
 #include "components/update_client/component_unpacker.h"
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc
index 7dc920ad8..0a6ebfb 100644
--- a/components/cronet/url_request_context_config.cc
+++ b/components/cronet/url_request_context_config.cc
@@ -29,14 +29,9 @@
 #include "net/nqe/network_quality_estimator_params.h"
 #include "net/quic/chromium/quic_utils_chromium.h"
 #include "net/quic/core/quic_packets.h"
-#include "net/reporting/reporting_policy.h"
 #include "net/socket/ssl_client_socket.h"
 #include "net/url_request/url_request_context_builder.h"
 
-#if BUILDFLAG(ENABLE_REPORTING)
-#include "net/reporting/reporting_policy.h"
-#endif  // BUILDFLAG(ENABLE_REPORTING)
-
 namespace cronet {
 
 namespace {
@@ -110,11 +105,6 @@
 // NetworkQualityEstimator (NQE) experiment dictionary name.
 const char kNetworkQualityEstimatorFieldTrialName[] = "NetworkQualityEstimator";
 
-// Network Error Logging experiment dictionary name.
-const char kNetworkErrorLoggingFieldTrialName[] = "NetworkErrorLogging";
-// Name of boolean to enable Reporting API.
-const char kNetworkErrorLoggingEnable[] = "enable";
-
 // Disable IPv6 when on WiFi. This is a workaround for a known issue on certain
 // Android phones, and should not be necessary when not on one of those devices.
 // See https://crbug.com/696569 for details.
@@ -219,7 +209,6 @@
   bool stale_dns_enable = false;
   bool host_resolver_rules_enable = false;
   bool disable_ipv6_on_wifi = false;
-  bool nel_enable = false;
 
   effective_experimental_options = dict->CreateDeepCopy();
   StaleHostResolver::StaleOptions stale_dns_options;
@@ -423,15 +412,6 @@
       }
       host_resolver_rules_enable = host_resolver_rules_args->GetString(
           kHostResolverRules, &host_resolver_rules_string);
-    } else if (it.key() == kNetworkErrorLoggingFieldTrialName) {
-      const base::DictionaryValue* nel_args = nullptr;
-      if (!it.value().GetAsDictionary(&nel_args)) {
-        LOG(ERROR) << "\"" << it.key() << "\" config params \"" << it.value()
-                   << "\" is not a dictionary value";
-        effective_experimental_options->Remove(it.key(), nullptr);
-        continue;
-      }
-      nel_args->GetBoolean(kNetworkErrorLoggingEnable, &nel_enable);
     } else if (it.key() == kDisableIPv6OnWifi) {
       if (!it.value().GetAsBoolean(&disable_ipv6_on_wifi)) {
         LOG(ERROR) << "\"" << it.key() << "\" config params \"" << it.value()
@@ -503,23 +483,6 @@
     }
     context_builder->set_host_resolver(std::move(host_resolver));
   }
-
-#if BUILDFLAG(ENABLE_REPORTING)
-  if (nel_enable) {
-    auto policy = std::make_unique<net::ReportingPolicy>();
-
-    // Apps (like Cronet embedders) are generally allowed to run in the
-    // background, even across network changes, so use more relaxed privacy
-    // settings than when Reporting is running in the browser.
-    policy->persist_reports_across_restarts = true;
-    policy->persist_clients_across_restarts = true;
-    policy->clear_reports_on_network_changes = false;
-    policy->clear_clients_on_network_changes = false;
-
-    context_builder->set_reporting_policy(std::move(policy));
-    context_builder->set_network_error_logging_enabled(true);
-  }
-#endif  // BUILDFLAG(ENABLE_REPORTING)
 }
 
 void URLRequestContextConfig::ConfigureURLRequestContextBuilder(
diff --git a/components/cronet/url_request_context_config_unittest.cc b/components/cronet/url_request_context_config_unittest.cc
index 39666e862..20f938c 100644
--- a/components/cronet/url_request_context_config_unittest.cc
+++ b/components/cronet/url_request_context_config_unittest.cc
@@ -52,7 +52,6 @@
       "\"race_cert_verification\":true,"
       "\"connection_options\":\"TIME,TBBR,REJ\"},"
       "\"AsyncDNS\":{\"enable\":true},"
-      "\"NetworkErrorLogging\":{\"enable\":true},"
       "\"UnknownOption\":{\"foo\":true},"
       "\"HostResolverRules\":{\"host_resolver_rules\":"
       "\"MAP * 127.0.0.1\"},"
@@ -107,13 +106,6 @@
   EXPECT_TRUE(context->host_resolver()->GetDnsConfigAsValue());
 #endif  // defined(ENABLE_BUILT_IN_DNS)
 
-#if BUILDFLAG(ENABLE_REPORTING)
-  // Check Reporting and Network Error Logging are enabled (can be disabled at
-  // build time).
-  EXPECT_TRUE(context->reporting_service());
-  EXPECT_TRUE(context->network_error_logging_delegate());
-#endif  // BUILDFLAG(ENABLE_REPORTING)
-
   // Check IPv6 is disabled when on wifi.
   EXPECT_TRUE(context->host_resolver()->GetNoIPv6OnWifi());
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
index f13d6f99..7d4257c 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -493,20 +493,37 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(IsFetchInFlight());
 
-  // Check the proxy server used, or disable all data saver proxies?
-  if (!IsDataReductionProxy(proxy_server, nullptr)) {
-    // No need to do anything here.
+  // If the probe times out, then proxy server information may not have been
+  // set by the URL fetcher.
+  bool timed_out_with_no_proxy_data =
+      (success_response == WarmupURLFetcher::FetchResult::kTimedOut &&
+       !proxy_server.is_valid());
+
+  // Check the proxy server used.
+  if (!timed_out_with_no_proxy_data &&
+      !IsDataReductionProxy(proxy_server, nullptr)) {
+    // No need to do anything here since the warmup fetch did not go through
+    // the data saver proxy.
     return;
   }
 
-  bool is_secure_proxy = proxy_server.is_https() || proxy_server.is_quic();
-  bool is_core_proxy = IsDataReductionProxyServerCore(proxy_server);
+  bool is_secure_proxy = false;
+  bool is_core_proxy = false;
 
-  // The proxy server through which the warmup URL was fetched should match
-  // the proxy server for which the warmup URL is in-flight.
-  DCHECK(GetInFlightWarmupProxyDetails());
-  DCHECK_EQ(is_secure_proxy, GetInFlightWarmupProxyDetails()->first);
-  DCHECK_EQ(is_core_proxy, GetInFlightWarmupProxyDetails()->second);
+  if (!timed_out_with_no_proxy_data) {
+    is_secure_proxy = proxy_server.is_https() || proxy_server.is_quic();
+    is_core_proxy = IsDataReductionProxyServerCore(proxy_server);
+    // The proxy server through which the warmup URL was fetched should match
+    // the proxy server for which the warmup URL is in-flight.
+    DCHECK(GetInFlightWarmupProxyDetails());
+    DCHECK_EQ(is_secure_proxy, GetInFlightWarmupProxyDetails()->first);
+    DCHECK_EQ(is_core_proxy, GetInFlightWarmupProxyDetails()->second);
+  } else {
+    // When the probe times out, the proxy information may not be set. Fill-in
+    // the missing data using the proxy that was being probed.
+    is_secure_proxy = warmup_url_fetch_in_flight_secure_proxy_;
+    is_core_proxy = warmup_url_fetch_in_flight_core_proxy_;
+  }
 
   if (is_secure_proxy && is_core_proxy) {
     UMA_HISTOGRAM_BOOLEAN(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index 541f676..3e40a19 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -1298,6 +1298,62 @@
   test_config()->SetInFlightWarmupProxyDetails(base::nullopt);
 }
 
+// Tests the behavior when warmup URL fetcher times out.
+TEST_F(DataReductionProxyConfigTest, HandleWarmupFetcherTimeout) {
+  base::HistogramTester histogram_tester;
+  const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
+  const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
+      "https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
+  const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
+      "fallback.net:80", net::ProxyServer::SCHEME_HTTP);
+
+  SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
+  ResetSettings();
+
+  // Enable the proxy.
+  test_config()->SetWarmupURLFetchAttemptCounts(0);
+  test_config()->UpdateConfigForTesting(true, true, true);
+
+  test_config()->SetIsFetchInFlight(true);
+
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.WarmupURL.FetchInitiated", 0);
+  test_config()->OnNewClientConfigFetched();
+  EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
+            GetConfiguredProxiesForHttp());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
+            GetConfiguredProxiesForHttp());
+
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
+      "InsecureProxy.NonCore",
+      0);
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
+      "SecureProxy.NonCore",
+      0);
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.WarmupURL.FetchInitiated", 1);
+
+  // The first probe should go through the HTTPS data saver proxy. On fetch
+  // timeout, the HTTPS proxy must be disabled even though the callback did
+  // not specify a proxy.
+  test_config()->HandleWarmupFetcherResponse(
+      net::ProxyServer(), WarmupURLFetcher::FetchResult::kTimedOut);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
+            GetConfiguredProxiesForHttp());
+  histogram_tester.ExpectUniqueSample(
+      "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch."
+      "SecureProxy.NonCore",
+      0, 1);
+
+  // Warmup URL should be fetched from the next proxy.
+  histogram_tester.ExpectTotalCount(
+      "DataReductionProxy.WarmupURL.FetchInitiated", 2);
+}
+
 TEST_F(DataReductionProxyConfigTest,
        HandleWarmupFetcherRetryWithConnectionChange) {
   constexpr size_t kMaxWarmupURLFetchAttempts = 3;
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
index f11bb1c..7c1a58cd 100644
--- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
+++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
@@ -29,9 +29,9 @@
     const scoped_refptr<net::URLRequestContextGetter>&
         url_request_context_getter,
     WarmupURLFetcherCallback callback)
-    : previous_attempt_counts_(0),
+    : is_fetch_in_flight_(false),
+      previous_attempt_counts_(0),
       url_request_context_getter_(url_request_context_getter),
-      is_fetch_in_flight_(false),
       callback_(callback) {
   DCHECK(url_request_context_getter_);
   DCHECK(url_request_context_getter_->GetURLRequestContext()
@@ -41,6 +41,8 @@
 WarmupURLFetcher::~WarmupURLFetcher() {}
 
 void WarmupURLFetcher::FetchWarmupURL(size_t previous_attempt_counts) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   previous_attempt_counts_ = previous_attempt_counts;
 
   DCHECK_LE(0u, previous_attempt_counts_);
@@ -58,6 +60,7 @@
 }
 
 base::TimeDelta WarmupURLFetcher::GetFetchWaitTime() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_LT(0u, previous_attempt_counts_);
   DCHECK_GE(2u, previous_attempt_counts_);
 
@@ -68,6 +71,8 @@
 }
 
 void WarmupURLFetcher::FetchWarmupURLNow() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   UMA_HISTOGRAM_EXACT_LINEAR("DataReductionProxy.WarmupURL.FetchInitiated", 1,
                              2);
   net::NetworkTrafficAnnotationTag traffic_annotation =
@@ -96,6 +101,7 @@
   GetWarmupURLWithQueryParam(&warmup_url_with_query_params);
 
   fetcher_.reset();
+  fetch_timeout_timer_.Stop();
   is_fetch_in_flight_ = true;
 
   fetcher_ =
@@ -114,11 +120,15 @@
   static const int kMaxRetries = 5;
   fetcher_->SetAutomaticallyRetryOn5xx(false);
   fetcher_->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
+  fetch_timeout_timer_.Start(FROM_HERE, GetFetchTimeout(), this,
+                             &WarmupURLFetcher::OnFetchTimeout);
   fetcher_->Start();
 }
 
 void WarmupURLFetcher::GetWarmupURLWithQueryParam(
     GURL* warmup_url_with_query_params) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   // Set the query param to a random string to prevent intermediate middleboxes
   // from returning cached content.
   const std::string query = "q=" + base::GenerateGUID();
@@ -133,6 +143,7 @@
 }
 
 void WarmupURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(source, fetcher_.get());
   DCHECK(is_fetch_in_flight_);
 
@@ -161,8 +172,7 @@
   if (!GetFieldTrialParamByFeatureAsBool(
           features::kDataReductionProxyRobustConnection,
           "warmup_fetch_callback_enabled", false)) {
-    // Running the callback is not enabled.
-    is_fetch_in_flight_ = false;
+    CleanupAfterFetch();
     return;
   }
 
@@ -171,7 +181,7 @@
     // Fetching failed due to Internet unavailability, and not due to some
     // error. Set the proxy server to unknown.
     callback_.Run(net::ProxyServer(), FetchResult::kSuccessful);
-    is_fetch_in_flight_ = false;
+    CleanupAfterFetch();
     return;
   }
 
@@ -184,11 +194,84 @@
   callback_.Run(source->ProxyServerUsed(), success_response
                                                ? FetchResult::kSuccessful
                                                : FetchResult::kFailed);
-  is_fetch_in_flight_ = false;
+  CleanupAfterFetch();
 }
 
 bool WarmupURLFetcher::IsFetchInFlight() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   return is_fetch_in_flight_;
 }
 
+base::TimeDelta WarmupURLFetcher::GetFetchTimeout() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_LE(0u, previous_attempt_counts_);
+  DCHECK_GE(2u, previous_attempt_counts_);
+
+  // The timeout value should always be between kMinTimeout and kMaxTimeout
+  // (both inclusive).
+  constexpr base::TimeDelta kMinTimeout = base::TimeDelta::FromSeconds(8);
+  constexpr base::TimeDelta kMaxTimeout = base::TimeDelta::FromSeconds(60);
+
+  // Set the timeout based on how many times the fetching of the warmup URL
+  // has been tried.
+  size_t http_rtt_multiplier = 5;
+  if (previous_attempt_counts_ == 1) {
+    http_rtt_multiplier = 10;
+  } else if (previous_attempt_counts_ == 2) {
+    http_rtt_multiplier = 20;
+  }
+
+  const net::NetworkQualityEstimator* network_quality_estimator =
+      url_request_context_getter_->GetURLRequestContext()
+          ->network_quality_estimator();
+
+  base::Optional<base::TimeDelta> http_rtt_estimate =
+      network_quality_estimator->GetHttpRTT();
+  if (!http_rtt_estimate)
+    return kMaxTimeout;
+
+  base::TimeDelta timeout = http_rtt_multiplier * http_rtt_estimate.value();
+  if (timeout > kMaxTimeout)
+    return kMaxTimeout;
+
+  if (timeout < kMinTimeout)
+    return kMinTimeout;
+
+  return timeout;
+}
+
+void WarmupURLFetcher::OnFetchTimeout() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(is_fetch_in_flight_);
+  DCHECK(fetcher_);
+
+  const net::ProxyServer proxy_server = fetcher_->ProxyServerUsed();
+  DCHECK_LE(1, proxy_server.scheme());
+
+  UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.WarmupURL.FetchSuccessful", false);
+  base::UmaHistogramSparse("DataReductionProxy.WarmupURL.NetError",
+                           net::ERR_ABORTED);
+  base::UmaHistogramSparse("DataReductionProxy.WarmupURL.HttpResponseCode",
+                           std::abs(net::URLFetcher::RESPONSE_CODE_INVALID));
+
+  if (!GetFieldTrialParamByFeatureAsBool(
+          features::kDataReductionProxyRobustConnection,
+          "warmup_fetch_callback_enabled", false)) {
+    // Running the callback is not enabled.
+    CleanupAfterFetch();
+    return;
+  }
+
+  callback_.Run(proxy_server, FetchResult::kTimedOut);
+  CleanupAfterFetch();
+}
+
+void WarmupURLFetcher::CleanupAfterFetch() {
+  is_fetch_in_flight_ = false;
+  fetcher_.reset();
+  fetch_timeout_timer_.Stop();
+  fetch_delay_timer_.Stop();
+}
+
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.h b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.h
index 9a50275..41cd9d47 100644
--- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.h
+++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
 #include "base/timer/timer.h"
 #include "net/url_request/url_fetcher_delegate.h"
 
@@ -59,30 +60,48 @@
   // delayed.
   virtual base::TimeDelta GetFetchWaitTime() const;
 
+  // Returns the timeout value for fetching the secure proxy URL. Virtualized
+  // for testing.
+  virtual base::TimeDelta GetFetchTimeout() const;
+
+  // Called when the fetch timeouts.
+  void OnFetchTimeout();
+
+  void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+  // The URLFetcher being used for fetching the warmup URL. Protected for
+  // testing.
+  std::unique_ptr<net::URLFetcher> fetcher_;
+
+  // Timer used to delay the fetching of the warmup probe URL.
+  base::OneShotTimer fetch_delay_timer_;
+
+  // Timer to enforce timeout of fetching the warmup URL.
+  base::OneShotTimer fetch_timeout_timer_;
+
+  // True if the fetcher for warmup URL is in-flight.
+  bool is_fetch_in_flight_;
+
  private:
   // Creates and immediately starts a URLFetcher that fetches the warmup URL.
   void FetchWarmupURLNow();
 
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
+  // Resets the variable after the fetching of the warmup URL has completed or
+  // timed out. Must be called after |callback_| has been run.
+  void CleanupAfterFetch();
 
   // Count of fetch attempts that have been made to the proxy which is being
   // probed.
   size_t previous_attempt_counts_;
 
-  // Timer used to delay the fetching of the warmup probe URL.
-  base::OneShotTimer fetch_delay_timer_;
-
   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
 
-  // The URLFetcher being used for fetching the warmup URL.
-  std::unique_ptr<net::URLFetcher> fetcher_;
-
-  bool is_fetch_in_flight_;
-
   // Callback that should be executed when the fetching of the warmup URL is
   // completed.
   WarmupURLFetcherCallback callback_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(WarmupURLFetcher);
 };
 
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc b/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
index 817ec07..ec8d654 100644
--- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/gtest_util.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/platform_thread.h"
@@ -24,6 +25,7 @@
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace data_reduction_proxy {
@@ -66,8 +68,29 @@
     fetch_wait_time_ = fetch_wait_time;
   }
 
+  void SetFetchTimeout(base::Optional<base::TimeDelta> fetch_timeout) {
+    fetch_timeout_ = fetch_timeout;
+  }
+
   using WarmupURLFetcher::FetchWarmupURL;
   using WarmupURLFetcher::GetWarmupURLWithQueryParam;
+  using WarmupURLFetcher::OnFetchTimeout;
+  using WarmupURLFetcher::OnURLFetchComplete;
+
+  base::TimeDelta GetFetchTimeout() const override {
+    if (!fetch_timeout_)
+      return WarmupURLFetcher::GetFetchTimeout();
+    return fetch_timeout_.value();
+  }
+
+  void VerifyStateCleanedUp() const {
+    DCHECK(!fetcher_);
+    DCHECK(!fetch_delay_timer_.IsRunning());
+    DCHECK(!fetch_timeout_timer_.IsRunning());
+    DCHECK(!is_fetch_in_flight_);
+  }
+
+  net::URLFetcher* fetcher() const { return fetcher_.get(); }
 
  private:
   void HandleWarmupFetcherResponse(const net::ProxyServer& proxy_server,
@@ -81,6 +104,7 @@
   size_t callback_received_count_ = 0;
   net::ProxyServer proxy_server_last_;
   FetchResult success_response_last_ = FetchResult::kFailed;
+  base::Optional<base::TimeDelta> fetch_timeout_;
   DISALLOW_COPY_AND_ASSIGN(WarmupURLFetcherTest);
 };
 
@@ -118,6 +142,7 @@
       query_param_different = true;
   }
   EXPECT_TRUE(query_param_different);
+  warmup_url_fetcher.VerifyStateCleanedUp();
 }
 
 TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLNoViaHeader) {
@@ -180,6 +205,7 @@
   // the via header.
   EXPECT_EQ(WarmupURLFetcher::FetchResult::kFailed,
             warmup_url_fetcher.success_response_last());
+  warmup_url_fetcher.VerifyStateCleanedUp();
 }
 
 TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLWithViaHeader) {
@@ -242,6 +268,10 @@
   // The last response contained the via header.
   EXPECT_EQ(WarmupURLFetcher::FetchResult::kSuccessful,
             warmup_url_fetcher.success_response_last());
+  warmup_url_fetcher.VerifyStateCleanedUp();
+
+  // If the fetch times out, it should cause DCHECK to trigger.
+  EXPECT_DCHECK_DEATH(warmup_url_fetcher.OnFetchTimeout());
 }
 
 TEST(WarmupURLFetcherTest,
@@ -295,6 +325,7 @@
 
   // The callback should not be run.
   EXPECT_EQ(0u, warmup_url_fetcher.callback_received_count());
+  warmup_url_fetcher.VerifyStateCleanedUp();
 }
 
 TEST(WarmupURLFetcherTest, TestConnectionResetFetchWarmupURL) {
@@ -351,6 +382,67 @@
             warmup_url_fetcher.proxy_server_last().scheme());
   EXPECT_EQ(WarmupURLFetcher::FetchResult::kFailed,
             warmup_url_fetcher.success_response_last());
+  warmup_url_fetcher.VerifyStateCleanedUp();
+}
+
+TEST(WarmupURLFetcherTest, TestFetchTimesout) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  WarmupURLFetcherTest::InitExperiment(&scoped_feature_list);
+
+  base::HistogramTester histogram_tester;
+  base::MessageLoopForIO message_loop;
+  const std::string config = "foobarbaz";
+  std::vector<std::unique_ptr<net::SocketDataProvider>> socket_data_providers;
+  net::MockClientSocketFactory mock_socket_factory;
+  net::MockRead success_reads[3];
+  success_reads[0] = net::MockRead(
+      "HTTP/1.1 204 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n");
+  success_reads[1] = net::MockRead(net::ASYNC, config.c_str(), config.length());
+  success_reads[2] = net::MockRead(net::SYNCHRONOUS, net::OK);
+
+  socket_data_providers.push_back(
+      (base::MakeUnique<net::StaticSocketDataProvider>(
+          success_reads, arraysize(success_reads), nullptr, 0)));
+  mock_socket_factory.AddSocketDataProvider(socket_data_providers.back().get());
+
+  std::unique_ptr<net::TestURLRequestContext> test_request_context(
+      new net::TestURLRequestContext(true));
+
+  test_request_context->set_client_socket_factory(&mock_socket_factory);
+  test_request_context->Init();
+  scoped_refptr<net::URLRequestContextGetter> request_context_getter =
+      new net::TestURLRequestContextGetter(message_loop.task_runner(),
+                                           std::move(test_request_context));
+  net::TestNetworkQualityEstimator estimator;
+  request_context_getter->GetURLRequestContext()->set_network_quality_estimator(
+      &estimator);
+
+  WarmupURLFetcherTest warmup_url_fetcher(request_context_getter);
+  // Set the timeout to a very low value. This should cause warmup URL fetcher
+  // to run the callback with appropriate error code.
+  warmup_url_fetcher.SetFetchTimeout(base::TimeDelta::FromSeconds(0));
+  EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
+  warmup_url_fetcher.FetchWarmupURL(0);
+  EXPECT_TRUE(warmup_url_fetcher.IsFetchInFlight());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
+
+  histogram_tester.ExpectUniqueSample(
+      "DataReductionProxy.WarmupURL.FetchInitiated", 1, 1);
+  histogram_tester.ExpectUniqueSample(
+      "DataReductionProxy.WarmupURL.FetchSuccessful", 0, 1);
+  histogram_tester.ExpectUniqueSample("DataReductionProxy.WarmupURL.NetError",
+                                      net::ERR_ABORTED, 1);
+
+  EXPECT_EQ(1u, warmup_url_fetcher.callback_received_count());
+  // The last response should have timedout.
+  EXPECT_EQ(WarmupURLFetcher::FetchResult::kTimedOut,
+            warmup_url_fetcher.success_response_last());
+  warmup_url_fetcher.VerifyStateCleanedUp();
+
+  // If the URL fetch completes, it should cause DCHECK to trigger.
+  EXPECT_DCHECK_DEATH(
+      warmup_url_fetcher.OnURLFetchComplete(warmup_url_fetcher.fetcher()));
 }
 
 TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLWithDelay) {
@@ -416,6 +508,49 @@
   // header.
   EXPECT_EQ(WarmupURLFetcher::FetchResult::kSuccessful,
             warmup_url_fetcher.success_response_last());
+  warmup_url_fetcher.VerifyStateCleanedUp();
+}
+
+TEST(WarmupURLFetcherTest, TestFetchTimeoutIncreasing) {
+  // Must remain in sync with warmup_url_fetcher.cc.
+  constexpr base::TimeDelta kMinTimeout = base::TimeDelta::FromSeconds(8);
+  constexpr base::TimeDelta kMaxTimeout = base::TimeDelta::FromSeconds(60);
+
+  base::HistogramTester histogram_tester;
+  base::MessageLoopForIO message_loop;
+
+  std::unique_ptr<net::TestURLRequestContext> test_request_context(
+      new net::TestURLRequestContext(true));
+
+  test_request_context->Init();
+  scoped_refptr<net::URLRequestContextGetter> request_context_getter =
+      new net::TestURLRequestContextGetter(message_loop.task_runner(),
+                                           std::move(test_request_context));
+  net::TestNetworkQualityEstimator estimator;
+  request_context_getter->GetURLRequestContext()->set_network_quality_estimator(
+      &estimator);
+
+  WarmupURLFetcherTest warmup_url_fetcher(request_context_getter);
+  EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
+
+  EXPECT_EQ(kMinTimeout, warmup_url_fetcher.GetFetchTimeout());
+
+  base::TimeDelta http_rtt = base::TimeDelta::FromSeconds(2);
+  estimator.SetStartTimeNullHttpRtt(http_rtt);
+  EXPECT_EQ(http_rtt * 5, warmup_url_fetcher.GetFetchTimeout());
+
+  warmup_url_fetcher.FetchWarmupURL(1);
+  EXPECT_EQ(http_rtt * 10, warmup_url_fetcher.GetFetchTimeout());
+
+  warmup_url_fetcher.FetchWarmupURL(2);
+  EXPECT_EQ(http_rtt * 20, warmup_url_fetcher.GetFetchTimeout());
+
+  http_rtt = base::TimeDelta::FromSeconds(5);
+  estimator.SetStartTimeNullHttpRtt(http_rtt);
+  EXPECT_EQ(kMaxTimeout, warmup_url_fetcher.GetFetchTimeout());
+
+  warmup_url_fetcher.FetchWarmupURL(0);
+  EXPECT_EQ(http_rtt * 5, warmup_url_fetcher.GetFetchTimeout());
 }
 
 }  // namespace
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 6b9d48a..d636360 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -23,7 +23,6 @@
 #include "components/viz/common/quads/solid_color_draw_quad.h"
 #include "components/viz/common/quads/texture_draw_quad.h"
 #include "components/viz/common/resources/single_release_callback.h"
-#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "components/viz/service/surfaces/surface.h"
 #include "components/viz/service/surfaces/surface_manager.h"
 #include "services/ui/public/interfaces/window_tree_constants.mojom.h"
diff --git a/components/image_fetcher/core/image_fetcher_impl.cc b/components/image_fetcher/core/image_fetcher_impl.cc
index ccbc25c..0cf6c10 100644
--- a/components/image_fetcher/core/image_fetcher_impl.cc
+++ b/components/image_fetcher/core/image_fetcher_impl.cc
@@ -101,7 +101,8 @@
 
   // Run all callbacks
   for (const auto& callback : request->callbacks) {
-    callback.Run(request->id, image, metadata);
+    if (callback)
+      callback.Run(request->id, image, metadata);
   }
 
   // Inform the ImageFetcherDelegate.
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc
index 2722ce9..1fcfc627 100644
--- a/components/ntp_tiles/most_visited_sites.cc
+++ b/components/ntp_tiles/most_visited_sites.cc
@@ -563,8 +563,10 @@
 
   int num_personal_tiles = 0;
   for (const auto& tile : *current_tiles_) {
-    if (tile.source != TileSource::POPULAR)
+    if (tile.source != TileSource::POPULAR &&
+        tile.source != TileSource::POPULAR_BAKED_IN) {
       num_personal_tiles++;
+    }
   }
   prefs_->SetInteger(prefs::kNumPersonalTiles, num_personal_tiles);
   if (!observer_)
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h
index b6a6d550..a059b81 100644
--- a/components/omnibox/browser/autocomplete_controller.h
+++ b/components/omnibox/browser/autocomplete_controller.h
@@ -147,6 +147,7 @@
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewTest, DoesNotUpdateAutocompleteOnBlur);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, CloseOmniboxPopupOnTextDrag);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, FriendlyAccessibleLabel);
+  FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, AccessiblePopup);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, MaintainCursorAfterFocusCycle);
   FRIEND_TEST_ALL_PREFIXES(OmniboxPopupModelTest, SetSelectedLine);
 
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index d685b56..a652098 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -5265,11 +5265,12 @@
       'name': 'EnableCommonNameFallbackForLocalAnchors',
       'type': 'main',
       'schema': { 'type': 'boolean' },
-      'supported_on': ['chrome.*:58-66', 'chrome_os:58-66', 'android:58-66'],
+      'supported_on': ['chrome.*:58-65', 'chrome_os:58-65', 'android:58-65'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': False,
       },
+      'deprecated': True,
       'example_value': False,
       'id': 366,
       'caption': '''Whether to allow certificates issued by local trust anchors that are missing the subjectAlternativeName extension''',
diff --git a/components/security_interstitials/core/browser/resources/list_of_interstitials.html b/components/security_interstitials/core/browser/resources/list_of_interstitials.html
index 639d6769..6da45f27 100644
--- a/components/security_interstitials/core/browser/resources/list_of_interstitials.html
+++ b/components/security_interstitials/core/browser/resources/list_of_interstitials.html
@@ -44,6 +44,9 @@
       <a href="ssl?type=hpkp_failure">Pinned certificate error</a>
     </li>
     <li>
+      <a href="ssl?type=ct_failure&overridable=1">Certificate Transparency error</a>
+    </li>
+    <li>
       <a href="superfish-ssl">Superfish</a>
     </li>
     <li>
diff --git a/components/signin/core/browser/BUILD.gn b/components/signin/core/browser/BUILD.gn
index 9bbfc29..951cf3e 100644
--- a/components/signin/core/browser/BUILD.gn
+++ b/components/signin/core/browser/BUILD.gn
@@ -118,17 +118,20 @@
     "//components/signin/core/browser:signin_features",
     "//google_apis",
     "//net",
+    "//ui/gfx",
     "//url",
   ]
   deps = [
     "//base:i18n",
     "//components/data_use_measurement/core",
     "//components/google/core/browser",
+    "//components/image_fetcher/core",
     "//components/metrics",
     "//components/os_crypt",
     "//components/pref_registry",
     "//components/webdata/common",
     "//crypto",
+    "//skia",
     "//sql",
     "//third_party/icu",
     "//third_party/re2",
@@ -186,6 +189,7 @@
   public_deps = [
     ":browser",
     "//base",
+    "//components/image_fetcher/core/",
     "//components/prefs:test_support",
     "//components/webdata/common",
     "//google_apis:test_support",
diff --git a/components/signin/core/browser/DEPS b/components/signin/core/browser/DEPS
index 1daccb8f..8808770 100644
--- a/components/signin/core/browser/DEPS
+++ b/components/signin/core/browser/DEPS
@@ -1,8 +1,10 @@
 include_rules = [
   "+components/data_use_measurement/core",
+  "+components/image_fetcher/core",
   "+components/invalidation/public",
   "+components/metrics",
   "+google/cacheinvalidation",
   "+jni",
   "+third_party/re2",
+  "+ui/gfx",
 ]
diff --git a/components/signin/core/browser/account_fetcher_service.cc b/components/signin/core/browser/account_fetcher_service.cc
index ce77941..7027fef 100644
--- a/components/signin/core/browser/account_fetcher_service.cc
+++ b/components/signin/core/browser/account_fetcher_service.cc
@@ -10,10 +10,13 @@
 #include "base/metrics/field_trial.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "components/image_fetcher/core/image_decoder.h"
+#include "components/image_fetcher/core/image_fetcher_impl.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/account_info_fetcher.h"
 #include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/avatar_icon_util.h"
 #include "components/signin/core/browser/child_account_info_fetcher.h"
 #include "components/signin/core/browser/signin_client.h"
 #include "components/signin/core/browser/signin_switches.h"
@@ -24,6 +27,8 @@
 const base::TimeDelta kRefreshFromTokenServiceDelay =
     base::TimeDelta::FromHours(24);
 
+constexpr int kAccountImageDownloadSize = 64;
+
 bool AccountSupportsUserInfo(const std::string& account_id) {
   // Supervised users use a specially scoped token which when used for general
   // purposes causes the token service to raise spurious auth errors.
@@ -32,7 +37,7 @@
   return account_id != "managed_user@localhost";
 }
 
-}
+}  // namespace
 
 // This pref used to be in the AccountTrackerService, hence its string value.
 const char AccountFetcherService::kLastUpdatePref[] =
@@ -65,7 +70,8 @@
 void AccountFetcherService::Initialize(
     SigninClient* signin_client,
     OAuth2TokenService* token_service,
-    AccountTrackerService* account_tracker_service) {
+    AccountTrackerService* account_tracker_service,
+    std::unique_ptr<image_fetcher::ImageDecoder> image_decoder) {
   DCHECK(signin_client);
   DCHECK(!signin_client_);
   signin_client_ = signin_client;
@@ -76,6 +82,9 @@
   DCHECK(!token_service_);
   token_service_ = token_service;
   token_service_->AddObserver(this);
+  DCHECK(image_decoder);
+  DCHECK(!image_decoder_);
+  image_decoder_ = std::move(image_decoder);
 
   last_updated_ = base::Time::FromInternalValue(
       signin_client_->GetPrefs()->GetInt64(kLastUpdatePref));
@@ -247,9 +256,60 @@
     std::unique_ptr<base::DictionaryValue> user_info) {
   account_tracker_service_->SetAccountStateFromUserInfo(account_id,
                                                         user_info.get());
+  FetchAccountImage(account_id);
   user_info_requests_.erase(account_id);
 }
 
+image_fetcher::ImageFetcherImpl*
+AccountFetcherService::GetOrCreateImageFetcher() {
+  // Lazy initialization of |image_fetcher_| because the request context might
+  // not be available yet when |Initialize| is called.
+  if (!image_fetcher_) {
+    image_fetcher_ = std::make_unique<image_fetcher::ImageFetcherImpl>(
+        std::move(image_decoder_), signin_client_->GetURLRequestContext());
+    image_fetcher_->SetImageFetcherDelegate(this);
+  }
+  return image_fetcher_.get();
+}
+
+void AccountFetcherService::FetchAccountImage(const std::string& account_id) {
+  DCHECK(signin_client_);
+  std::string picture_url_string =
+      account_tracker_service_->GetAccountInfo(account_id).picture_url;
+  GURL picture_url(picture_url_string);
+  if (!picture_url.is_valid()) {
+    DVLOG(1) << "Invalid avatar picture URL: \"" + picture_url_string + "\"";
+    return;
+  }
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("accounts_image_fetcher", R"(
+        semantics {
+          sender: "Image fetcher for GAIA accounts"
+          description:
+            "To use a GAIA web account to log into Chrome in the user menu, the"
+            "account images of the signed-in GAIA accounts are displayed."
+          trigger: "At startup."
+          data: "Account picture URL of signed-in GAIA accounts."
+          destination: GOOGLE_OWNED_SERVICE
+        }
+        policy {
+          cookies_allowed: YES
+          cookies_store: "user"
+          setting: "This feature cannot be disabled by settings, "
+                   "however, it will only be requested if the user "
+                   "has signed into the web."
+          policy_exception_justification:
+            "Not implemented, considered not useful as no content is being "
+            "uploaded or saved; this request merely downloads the web account"
+            "profile image."
+        })");
+  GURL image_url_with_size(signin::GetAvatarImageURLWithOptions(
+      picture_url, kAccountImageDownloadSize, true /* no_silhouette */));
+  GetOrCreateImageFetcher()->StartOrQueueNetworkRequest(
+      account_id, image_url_with_size,
+      image_fetcher::ImageFetcher::ImageFetcherCallback(), traffic_annotation);
+}
+
 void AccountFetcherService::SetIsChildAccount(const std::string& account_id,
                                               bool is_child_account) {
   if (child_request_account_id_ == account_id)
@@ -306,3 +366,8 @@
   refresh_tokens_loaded_ = true;
   MaybeEnableNetworkFetches();
 }
+
+void AccountFetcherService::OnImageFetched(const std::string& id,
+                                           const gfx::Image& image) {
+  account_tracker_service_->SetAccountImage(id, image);
+}
diff --git a/components/signin/core/browser/account_fetcher_service.h b/components/signin/core/browser/account_fetcher_service.h
index d8abc50..6e86435 100644
--- a/components/signin/core/browser/account_fetcher_service.h
+++ b/components/signin/core/browser/account_fetcher_service.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/sequence_checker.h"
 #include "base/timer/timer.h"
+#include "components/image_fetcher/core/image_fetcher_delegate.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 
@@ -22,6 +23,11 @@
 class OAuth2TokenService;
 class SigninClient;
 
+namespace image_fetcher {
+class ImageDecoder;
+class ImageFetcherImpl;
+}  // namespace image_fetcher
+
 namespace invalidation {
 class InvalidationService;
 }
@@ -34,7 +40,8 @@
 // to child account info fetching.
 
 class AccountFetcherService : public KeyedService,
-                              public OAuth2TokenService::Observer {
+                              public OAuth2TokenService::Observer,
+                              public image_fetcher::ImageFetcherDelegate {
  public:
   // Name of the preference that tracks the int64_t representation of the last
   // time the AccountTrackerService was updated.
@@ -48,7 +55,8 @@
 
   void Initialize(SigninClient* signin_client,
                   OAuth2TokenService* token_service,
-                  AccountTrackerService* account_tracker_service);
+                  AccountTrackerService* account_tracker_service,
+                  std::unique_ptr<image_fetcher::ImageDecoder> image_decoder);
 
   // KeyedService implementation
   void Shutdown() override;
@@ -112,6 +120,14 @@
                               std::unique_ptr<base::DictionaryValue> user_info);
   void OnUserInfoFetchFailure(const std::string& account_id);
 
+  image_fetcher::ImageFetcherImpl* GetOrCreateImageFetcher();
+
+  // Called in |OnUserInfoFetchSuccess| after the account info has been fetched.
+  void FetchAccountImage(const std::string& account_id);
+
+  // image_fetcher::ImageFetcherDelegate:
+  void OnImageFetched(const std::string& id, const gfx::Image& image) override;
+
   AccountTrackerService* account_tracker_service_;  // Not owned.
   OAuth2TokenService* token_service_;  // Not owned.
   SigninClient* signin_client_;  // Not owned.
@@ -132,6 +148,10 @@
   std::unordered_map<std::string, std::unique_ptr<AccountInfoFetcher>>
       user_info_requests_;
 
+  // Used for fetching the account images.
+  std::unique_ptr<image_fetcher::ImageFetcherImpl> image_fetcher_;
+  std::unique_ptr<image_fetcher::ImageDecoder> image_decoder_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(AccountFetcherService);
diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc
index 2b0173c4..9b49e2a3 100644
--- a/components/signin/core/browser/account_tracker_service.cc
+++ b/components/signin/core/browser/account_tracker_service.cc
@@ -145,6 +145,12 @@
   return AccountInfo();
 }
 
+gfx::Image AccountTrackerService::GetAccountImage(
+    const std::string& account_id) {
+  return base::ContainsKey(accounts_, account_id) ? accounts_[account_id].image
+                                                  : gfx::Image();
+}
+
 AccountTrackerService::AccountIdMigrationState
 AccountTrackerService::GetMigrationState() const {
   return GetMigrationState(signin_client_->GetPrefs());
@@ -243,6 +249,12 @@
   SaveToPrefs(state);
 }
 
+void AccountTrackerService::SetAccountImage(const std::string& account_id,
+                                            const gfx::Image& image) {
+  DCHECK(base::ContainsKey(accounts_, account_id));
+  accounts_[account_id].image = image;
+}
+
 void AccountTrackerService::SetIsChildAccount(const std::string& account_id,
                                               const bool& is_child_account) {
   DCHECK(base::ContainsKey(accounts_, account_id));
diff --git a/components/signin/core/browser/account_tracker_service.h b/components/signin/core/browser/account_tracker_service.h
index 128dc73..65396fa 100644
--- a/components/signin/core/browser/account_tracker_service.h
+++ b/components/signin/core/browser/account_tracker_service.h
@@ -18,6 +18,7 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/signin/core/browser/account_info.h"
 #include "google_apis/gaia/gaia_auth_util.h"
+#include "ui/gfx/image/image.h"
 
 class PrefService;
 class SigninClient;
@@ -94,6 +95,10 @@
   AccountInfo FindAccountInfoByGaiaId(const std::string& gaia_id) const;
   AccountInfo FindAccountInfoByEmail(const std::string& email) const;
 
+  // Returns the account image associated to the account id |account_id|.
+  // If the account id is not known an empty image is returned.
+  gfx::Image GetAccountImage(const std::string& account_id);
+
   // Picks the correct account_id for the specified account depending on the
   // migration state.
   std::string PickAccountIdForAccount(const std::string& gaia,
@@ -129,11 +134,16 @@
   void SetAccountStateFromUserInfo(const std::string& account_id,
                                    const base::DictionaryValue* user_info);
 
+  // Assumes that there already exists an account with |account_id| in
+  // |accounts_|.
+  void SetAccountImage(const std::string& account_id, const gfx::Image& image);
+
  private:
   friend class AccountFetcherService;
   friend class FakeAccountFetcherService;
   struct AccountState {
     AccountInfo info;
+    gfx::Image image;
   };
 
   void NotifyAccountUpdated(const AccountState& state);
diff --git a/components/signin/core/browser/account_tracker_service_unittest.cc b/components/signin/core/browser/account_tracker_service_unittest.cc
index 8b5cb75..56f20df 100644
--- a/components/signin/core/browser/account_tracker_service_unittest.cc
+++ b/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -74,7 +74,8 @@
 }
 
 std::string AccountIdToPictureURL(const std::string& account_id) {
-  return "picture_url-" + account_id;
+  return "https://example.com/-" + account_id +
+         "/AAAAAAAAAAI/AAAAAAAAACQ/Efg/photo.jpg";
 }
 
 void CheckAccountDetails(const std::string& account_id,
@@ -276,9 +277,9 @@
     account_tracker_->Initialize(signin_client_.get());
 
     account_fetcher_.reset(new AccountFetcherService());
-    account_fetcher_->Initialize(signin_client_.get(),
-                                 fake_oauth2_token_service_.get(),
-                                 account_tracker_.get());
+    account_fetcher_->Initialize(
+        signin_client_.get(), fake_oauth2_token_service_.get(),
+        account_tracker_.get(), std::make_unique<TestImageDecoder>());
 
     account_fetcher_->EnableNetworkFetchesForTest();
   }
@@ -460,7 +461,8 @@
   tracker.AddObserver(&observer);
   tracker.Initialize(signin_client());
 
-  fetcher.Initialize(signin_client(), token_service(), &tracker);
+  fetcher.Initialize(signin_client(), token_service(), &tracker,
+                     std::make_unique<TestImageDecoder>());
   fetcher.EnableNetworkFetchesForTest();
   ASSERT_FALSE(fetcher.IsAllUserInfoFetched());
   ASSERT_TRUE(observer.CheckEvents());
@@ -542,7 +544,8 @@
   tracker.Initialize(signin_client());
 
   AccountFetcherService fetcher_service;
-  fetcher_service.Initialize(signin_client(), token_service(), &tracker);
+  fetcher_service.Initialize(signin_client(), token_service(), &tracker,
+                             std::make_unique<TestImageDecoder>());
 
   SimulateTokenAvailable("alpha");
   IssueAccessToken("alpha");
@@ -629,7 +632,8 @@
     CheckAccountDetails("beta", infos[1]);
 
     FakeAccountFetcherService fetcher;
-    fetcher.Initialize(signin_client(), token_service(), &tracker);
+    fetcher.Initialize(signin_client(), token_service(), &tracker,
+                       std::make_unique<TestImageDecoder>());
     fetcher.EnableNetworkFetchesForTest();
     // Remove an account.
     // This will allow testing removal as well as child accounts which is only
@@ -727,7 +731,8 @@
     AccountTrackerService tracker;
     tracker.Initialize(signin_client());
     AccountFetcherService fetcher;
-    fetcher.Initialize(signin_client(), token_service(), &tracker);
+    fetcher.Initialize(signin_client(), token_service(), &tracker,
+                       std::make_unique<TestImageDecoder>());
     fetcher.EnableNetworkFetchesForTest();
     SimulateTokenAvailable("incomplete");
     ReturnOAuthUrlFetchSuccessIncomplete("incomplete");
@@ -739,7 +744,8 @@
     AccountTrackerService tracker;
     tracker.Initialize(signin_client());
     AccountFetcherService fetcher;
-    fetcher.Initialize(signin_client(), token_service(), &tracker);
+    fetcher.Initialize(signin_client(), token_service(), &tracker,
+                       std::make_unique<TestImageDecoder>());
     fetcher.EnableNetworkFetchesForTest();
     // Validate that the loaded AccountInfo from prefs is considered invalid.
     std::vector<AccountInfo> infos = tracker.GetAccounts();
@@ -767,7 +773,8 @@
     tracker.AddObserver(&observer);
     tracker.Initialize(signin_client());
     AccountFetcherService fetcher;
-    fetcher.Initialize(signin_client(), token_service(), &tracker);
+    fetcher.Initialize(signin_client(), token_service(), &tracker,
+                       std::make_unique<TestImageDecoder>());
 
     ASSERT_TRUE(observer.CheckEvents(TrackingEvent(UPDATED, "incomplete")));
     // Enabling network fetches shouldn't cause any actual fetch since the
@@ -793,7 +800,8 @@
     AccountTrackerService tracker;
     tracker.Initialize(signin_client());
     AccountFetcherService fetcher;
-    fetcher.Initialize(signin_client(), token_service(), &tracker);
+    fetcher.Initialize(signin_client(), token_service(), &tracker,
+                       std::make_unique<TestImageDecoder>());
     fetcher.EnableNetworkFetchesForTest();
     SimulateTokenAvailable("alpha");
     ReturnOAuthUrlFetchSuccess("alpha");
@@ -816,7 +824,8 @@
     AccountTrackerService tracker;
     tracker.Initialize(signin_client());
     AccountFetcherService fetcher;
-    fetcher.Initialize(signin_client(), token_service(), &tracker);
+    fetcher.Initialize(signin_client(), token_service(), &tracker,
+                       std::make_unique<TestImageDecoder>());
 
     ASSERT_TRUE(fetcher.IsAllUserInfoFetched());
     std::vector<AccountInfo> infos = tracker.GetAccounts();
@@ -842,7 +851,8 @@
     AccountTrackerService tracker;
     tracker.Initialize(signin_client());
     AccountFetcherService fetcher;
-    fetcher.Initialize(signin_client(), token_service(), &tracker);
+    fetcher.Initialize(signin_client(), token_service(), &tracker,
+                       std::make_unique<TestImageDecoder>());
 
     ASSERT_TRUE(fetcher.IsAllUserInfoFetched());
     std::vector<AccountInfo> infos = tracker.GetAccounts();
@@ -865,7 +875,8 @@
     AccountTrackerService tracker;
     tracker.Initialize(signin_client());
     AccountFetcherService fetcher;
-    fetcher.Initialize(signin_client(), token_service(), &tracker);
+    fetcher.Initialize(signin_client(), token_service(), &tracker,
+                       std::make_unique<TestImageDecoder>());
     fetcher.EnableNetworkFetchesForTest();
     SimulateTokenAvailable("foo.bar@gmail.com");
     SimulateTokenAvailable("foobar@gmail.com");
@@ -885,7 +896,8 @@
     AccountTrackerService tracker;
     tracker.Initialize(signin_client());
     AccountFetcherService fetcher;
-    fetcher.Initialize(signin_client(), token_service(), &tracker);
+    fetcher.Initialize(signin_client(), token_service(), &tracker,
+                       std::make_unique<TestImageDecoder>());
 
     ASSERT_TRUE(fetcher.IsAllUserInfoFetched());
     std::vector<AccountInfo> infos = tracker.GetAccounts();
@@ -1085,7 +1097,8 @@
   AccountTrackerService tracker;
   tracker.Initialize(signin_client());
   FakeAccountFetcherService fetcher;
-  fetcher.Initialize(signin_client(), token_service(), &tracker);
+  fetcher.Initialize(signin_client(), token_service(), &tracker,
+                     std::make_unique<TestImageDecoder>());
   fetcher.EnableNetworkFetchesForTest();
   AccountTrackerObserver observer;
   tracker.AddObserver(&observer);
@@ -1114,7 +1127,8 @@
   AccountTrackerService tracker;
   tracker.Initialize(signin_client());
   FakeAccountFetcherService fetcher;
-  fetcher.Initialize(signin_client(), token_service(), &tracker);
+  fetcher.Initialize(signin_client(), token_service(), &tracker,
+                     std::make_unique<TestImageDecoder>());
   fetcher.EnableNetworkFetchesForTest();
   AccountTrackerObserver observer;
   tracker.AddObserver(&observer);
@@ -1143,7 +1157,8 @@
   AccountTrackerService tracker;
   tracker.Initialize(signin_client());
   FakeAccountFetcherService fetcher;
-  fetcher.Initialize(signin_client(), token_service(), &tracker);
+  fetcher.Initialize(signin_client(), token_service(), &tracker,
+                     std::make_unique<TestImageDecoder>());
   fetcher.EnableNetworkFetchesForTest();
   AccountTrackerObserver observer;
   tracker.AddObserver(&observer);
@@ -1178,7 +1193,8 @@
   AccountTrackerService tracker;
   tracker.Initialize(signin_client());
   FakeAccountFetcherService fetcher;
-  fetcher.Initialize(signin_client(), token_service(), &tracker);
+  fetcher.Initialize(signin_client(), token_service(), &tracker,
+                     std::make_unique<TestImageDecoder>());
   fetcher.EnableNetworkFetchesForTest();
   AccountTrackerObserver observer;
   tracker.AddObserver(&observer);
@@ -1215,7 +1231,8 @@
   AccountTrackerService tracker;
   tracker.Initialize(signin_client());
   FakeAccountFetcherService fetcher;
-  fetcher.Initialize(signin_client(), token_service(), &tracker);
+  fetcher.Initialize(signin_client(), token_service(), &tracker,
+                     std::make_unique<TestImageDecoder>());
   fetcher.EnableNetworkFetchesForTest();
   AccountTrackerObserver observer;
   tracker.AddObserver(&observer);
diff --git a/components/signin/core/browser/fake_account_fetcher_service.cc b/components/signin/core/browser/fake_account_fetcher_service.cc
index 21eb31b6..ce60c6f9 100644
--- a/components/signin/core/browser/fake_account_fetcher_service.cc
+++ b/components/signin/core/browser/fake_account_fetcher_service.cc
@@ -46,3 +46,14 @@
     const std::string& account_id) {
   // In tests, don't do actual network fetch.
 }
+
+TestImageDecoder::TestImageDecoder() = default;
+
+TestImageDecoder::~TestImageDecoder() = default;
+
+void TestImageDecoder::DecodeImage(
+    const std::string& image_data,
+    const gfx::Size& desired_image_frame_size,
+    const image_fetcher::ImageDecodedCallback& callback) {
+  callback.Run(gfx::Image());
+}
diff --git a/components/signin/core/browser/fake_account_fetcher_service.h b/components/signin/core/browser/fake_account_fetcher_service.h
index 84d6713..948121c3 100644
--- a/components/signin/core/browser/fake_account_fetcher_service.h
+++ b/components/signin/core/browser/fake_account_fetcher_service.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "components/image_fetcher/core/image_decoder.h"
 #include "components/signin/core/browser/account_fetcher_service.h"
 
 class KeyedService;
@@ -44,4 +45,23 @@
   DISALLOW_COPY_AND_ASSIGN(FakeAccountFetcherService);
 };
 
+// This dummy class implements |image_fetcher::ImageDecoder|, and is passed
+// as an argument to |AccountFetcherService::Initialize|.
+class TestImageDecoder : public image_fetcher::ImageDecoder {
+ public:
+  TestImageDecoder();
+  ~TestImageDecoder() override;
+
+  // image_fetcher::Decoder implementation:
+
+  // Passes an empty image to callback.
+  void DecodeImage(
+      const std::string& image_data,
+      const gfx::Size& desired_image_frame_size,
+      const image_fetcher::ImageDecodedCallback& callback) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestImageDecoder);
+};
+
 #endif  // COMPONENTS_SIGNIN_CORE_BROWSER_FAKE_ACCOUNT_FETCHER_SERVICE_H_
diff --git a/components/signin/core/browser/signin_manager_unittest.cc b/components/signin/core/browser/signin_manager_unittest.cc
index 90eb20b..c69565a 100644
--- a/components/signin/core/browser/signin_manager_unittest.cc
+++ b/components/signin/core/browser/signin_manager_unittest.cc
@@ -97,7 +97,8 @@
     SigninManagerBase::RegisterPrefs(local_state_.registry());
     account_tracker_.Initialize(&test_signin_client_);
     account_fetcher_.Initialize(&test_signin_client_, &token_service_,
-                                &account_tracker_);
+                                &account_tracker_,
+                                std::make_unique<TestImageDecoder>());
   }
 
   ~SigninManagerTest() override {
diff --git a/components/ssl_config/ssl_config_service_manager_pref.cc b/components/ssl_config/ssl_config_service_manager_pref.cc
index f924fe26..0d5c299 100644
--- a/components/ssl_config/ssl_config_service_manager_pref.cc
+++ b/components/ssl_config/ssl_config_service_manager_pref.cc
@@ -196,27 +196,27 @@
   const std::string tls13_variant =
       base::GetFieldTrialParamValue(kTLS13VariantExperimentName, "variant");
   const char* tls13_value = nullptr;
-  const char* experiment_value = nullptr;
+  const char* version_value = nullptr;
   if (tls13_variant == "disabled") {
     tls13_value = switches::kTLS13VariantDisabled;
   } else if (tls13_variant == "draft22") {
     tls13_value = switches::kTLS13VariantDraft22;
-    experiment_value = switches::kSSLVersionTLSv13;
+    version_value = switches::kSSLVersionTLSv13;
   } else if (tls13_variant == "draft23") {
     tls13_value = switches::kTLS13VariantDraft23;
-    experiment_value = switches::kSSLVersionTLSv13;
+    version_value = switches::kSSLVersionTLSv13;
   } else if (tls13_variant == "experiment2") {
     tls13_value = switches::kTLS13VariantExperiment2;
-    experiment_value = switches::kSSLVersionTLSv13;
+    version_value = switches::kSSLVersionTLSv13;
   }
 
   if (tls13_value) {
     local_state->SetDefaultPrefValue(ssl_config::prefs::kTLS13Variant,
                                      base::Value(tls13_value));
   }
-  if (experiment_value) {
+  if (version_value) {
     local_state->SetDefaultPrefValue(ssl_config::prefs::kSSLVersionMax,
-                                     base::Value(experiment_value));
+                                     base::Value(version_value));
   }
 
   PrefChangeRegistrar::NamedChangeCallback local_state_callback =
diff --git a/components/update_client/action_runner.cc b/components/update_client/action_runner.cc
index e357a11..be8706c4 100644
--- a/components/update_client/action_runner.cc
+++ b/components/update_client/action_runner.cc
@@ -14,6 +14,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/task_scheduler/post_task.h"
+#include "build/build_config.h"
 #include "components/update_client/component.h"
 #include "components/update_client/configurator.h"
 #include "components/update_client/task_traits.h"
diff --git a/components/update_client/update_client_unittest.cc b/components/update_client/update_client_unittest.cc
index f0a6278..e3e8846 100644
--- a/components/update_client/update_client_unittest.cc
+++ b/components/update_client/update_client_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "base/version.h"
+#include "build/build_config.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/update_client/component_unpacker.h"
 #include "components/update_client/crx_update_item.h"
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index b1f1c51..51b18d6 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -126,18 +126,9 @@
     "surfaces/local_surface_id.h",
     "surfaces/parent_local_surface_id_allocator.cc",
     "surfaces/parent_local_surface_id_allocator.h",
-    "surfaces/sequence_surface_reference_factory.cc",
-    "surfaces/sequence_surface_reference_factory.h",
-    "surfaces/stub_surface_reference_factory.cc",
-    "surfaces/stub_surface_reference_factory.h",
     "surfaces/surface_id.cc",
     "surfaces/surface_id.h",
     "surfaces/surface_info.h",
-    "surfaces/surface_reference_factory.h",
-    "surfaces/surface_reference_owner.h",
-    "surfaces/surface_sequence.h",
-    "surfaces/surface_sequence_generator.cc",
-    "surfaces/surface_sequence_generator.h",
     "switches.cc",
     "switches.h",
     "traced_value.cc",
@@ -194,7 +185,6 @@
     "quads/draw_quad_unittest.cc",
     "quads/render_pass_unittest.cc",
     "resources/platform_color_unittest.cc",
-    "surfaces/surface_sequence_generator_unittest.cc",
     "yuv_readback_unittest.cc",
   ]
 
diff --git a/components/viz/common/DEPS b/components/viz/common/DEPS
index 04cd092..10c073f 100644
--- a/components/viz/common/DEPS
+++ b/components/viz/common/DEPS
@@ -14,6 +14,7 @@
     "+components/viz/test",
     "+gpu/ipc/gl_in_process_context.h",
     "+media/base",
+    "+third_party/skia/include/core",
     "+ui/gl",
   ],
   ".*_benchmark\.cc": [
diff --git a/components/viz/common/gpu/context_cache_controller.cc b/components/viz/common/gpu/context_cache_controller.cc
index d49abb7..572955cd 100644
--- a/components/viz/common/gpu/context_cache_controller.cc
+++ b/components/viz/common/gpu/context_cache_controller.cc
@@ -159,8 +159,11 @@
     return;
   }
 
-  if (gr_context_)
-    gr_context_->freeGpuResources();
+  if (gr_context_) {
+    // Avoid the more complete GrContext::freeGpuResources, as that evicts
+    // harder to re-generate Skia caches.
+    gr_context_->performDeferredCleanup(std::chrono::milliseconds(0));
+  }
 
   // Toggle SetAggressivelyFreeResources to drop command buffer data.
   context_support_->SetAggressivelyFreeResources(true);
diff --git a/components/viz/common/gpu/context_cache_controller_unittest.cc b/components/viz/common/gpu/context_cache_controller_unittest.cc
index d6eb828e..f91475b 100644
--- a/components/viz/common/gpu/context_cache_controller_unittest.cc
+++ b/components/viz/common/gpu/context_cache_controller_unittest.cc
@@ -11,6 +11,9 @@
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkPixmap.h"
+#include "third_party/skia/include/gpu/GrContext.h"
 
 using ::testing::Mock;
 using ::testing::StrictMock;
@@ -112,5 +115,51 @@
   cache_controller.ClientBecameNotVisible(std::move(visible));
 }
 
+// Confirms that the Skia performDeferredCleanup API used by the cache
+// controller behaves as expected.
+TEST(ContextCacheControllerTest, CheckSkiaResourcePurgeAPI) {
+  StrictMock<MockContextSupport> context_support;
+  auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+  ContextCacheController cache_controller(&context_support, task_runner);
+  auto context_provider = cc::TestContextProvider::Create();
+  context_provider->BindToCurrentThread();
+  auto* gr_context = context_provider->GrContext();
+  cache_controller.SetGrContext(gr_context);
+
+  // Make us visible.
+  EXPECT_CALL(context_support, SetAggressivelyFreeResources(false));
+  auto visibility = cache_controller.ClientBecameVisible();
+  Mock::VerifyAndClearExpectations(&context_support);
+
+  // Now that we're visible, become busy, create and release a skia resource.
+  auto busy = cache_controller.ClientBecameBusy();
+  {
+    auto image_info = SkImageInfo::MakeN32Premul(200, 200);
+    std::vector<uint8_t> image_data(image_info.computeMinByteSize());
+    SkPixmap pixmap(image_info, image_data.data(), image_info.minRowBytes());
+    auto image = SkImage::MakeRasterCopy(pixmap);
+    auto image_gpu = image->makeTextureImage(gr_context, nullptr);
+    gr_context->flush();
+  }
+
+  // Ensure we see size taken up for the image (now released, but cached for
+  // re-use).
+  EXPECT_GT(gr_context->getResourceCachePurgeableBytes(), 0u);
+
+  // Make the client idle and wait for the idle callback to trigger.
+  cache_controller.ClientBecameNotBusy(std::move(busy));
+  EXPECT_CALL(context_support, SetAggressivelyFreeResources(true));
+  EXPECT_CALL(context_support, SetAggressivelyFreeResources(false));
+  task_runner->FastForwardBy(base::TimeDelta::FromSeconds(5));
+  Mock::VerifyAndClearExpectations(&context_support);
+
+  // The Skia resource cache should now be empty.
+  EXPECT_EQ(gr_context->getResourceCachePurgeableBytes(), 0u);
+
+  // Set not-visible.
+  EXPECT_CALL(context_support, SetAggressivelyFreeResources(true));
+  cache_controller.ClientBecameNotVisible(std::move(visibility));
+}
+
 }  // namespace
 }  // namespace viz
diff --git a/components/viz/common/surfaces/sequence_surface_reference_factory.cc b/components/viz/common/surfaces/sequence_surface_reference_factory.cc
deleted file mode 100644
index 7faf30e..0000000
--- a/components/viz/common/surfaces/sequence_surface_reference_factory.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-
-#include "components/viz/common/surfaces/surface_sequence.h"
-
-namespace viz {
-
-base::Closure SequenceSurfaceReferenceFactory::CreateReference(
-    SurfaceReferenceOwner* owner,
-    const SurfaceId& surface_id) const {
-  auto seq = owner->GetSurfaceSequenceGenerator()->CreateSurfaceSequence();
-  RequireSequence(surface_id, seq);
-  return base::Bind(&SequenceSurfaceReferenceFactory::SatisfySequence, this,
-                    seq);
-}
-
-}  // namespace viz
diff --git a/components/viz/common/surfaces/sequence_surface_reference_factory.h b/components/viz/common/surfaces/sequence_surface_reference_factory.h
deleted file mode 100644
index c3cbde9..0000000
--- a/components/viz/common/surfaces/sequence_surface_reference_factory.h
+++ /dev/null
@@ -1,37 +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 COMPONENTS_VIZ_COMMON_SURFACES_SEQUENCE_SURFACE_REFERENCE_FACTORY_H_
-#define COMPONENTS_VIZ_COMMON_SURFACES_SEQUENCE_SURFACE_REFERENCE_FACTORY_H_
-
-#include "components/viz/common/surfaces/surface_reference_factory.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
-#include "components/viz/common/viz_common_export.h"
-
-namespace viz {
-
-// A surface reference factory that uses SurfaceSequence.
-class VIZ_COMMON_EXPORT SequenceSurfaceReferenceFactory
-    : public SurfaceReferenceFactory {
- public:
-  SequenceSurfaceReferenceFactory() = default;
-
-  // SurfaceReferenceFactory implementation:
-  base::Closure CreateReference(SurfaceReferenceOwner* owner,
-                                const SurfaceId& surface_id) const override;
-
- protected:
-  ~SequenceSurfaceReferenceFactory() override = default;
-
- private:
-  virtual void RequireSequence(const SurfaceId& surface_id,
-                               const SurfaceSequence& sequence) const = 0;
-  virtual void SatisfySequence(const SurfaceSequence& sequence) const = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(SequenceSurfaceReferenceFactory);
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_COMMON_SURFACES_SEQUENCE_SURFACE_REFERENCE_FACTORY_H_
diff --git a/components/viz/common/surfaces/stub_surface_reference_factory.cc b/components/viz/common/surfaces/stub_surface_reference_factory.cc
deleted file mode 100644
index e5d2ce50..0000000
--- a/components/viz/common/surfaces/stub_surface_reference_factory.cc
+++ /dev/null
@@ -1,17 +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.
-
-#include "components/viz/common/surfaces/stub_surface_reference_factory.h"
-
-#include "base/callback.h"
-
-namespace viz {
-
-base::Closure StubSurfaceReferenceFactory::CreateReference(
-    SurfaceReferenceOwner* owner,
-    const SurfaceId& surface_id) const {
-  return base::Closure();
-}
-
-}  // namespace viz
diff --git a/components/viz/common/surfaces/stub_surface_reference_factory.h b/components/viz/common/surfaces/stub_surface_reference_factory.h
deleted file mode 100644
index 156809c..0000000
--- a/components/viz/common/surfaces/stub_surface_reference_factory.h
+++ /dev/null
@@ -1,34 +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.
-
-#ifndef COMPONENTS_VIZ_COMMON_SURFACES_STUB_SURFACE_REFERENCE_FACTORY_H_
-#define COMPONENTS_VIZ_COMMON_SURFACES_STUB_SURFACE_REFERENCE_FACTORY_H_
-
-#include "base/compiler_specific.h"
-#include "components/viz/common/surfaces/surface_reference_factory.h"
-#include "components/viz/common/viz_common_export.h"
-
-namespace viz {
-
-// A stub implementation that creates a closure which does nothing.
-// TODO(kylechar): Delete this class and all usage of
-// SurfaceReferenceFactory when surface references are enabled by default.
-class VIZ_COMMON_EXPORT StubSurfaceReferenceFactory
-    : public SurfaceReferenceFactory {
- public:
-  StubSurfaceReferenceFactory() = default;
-
-  // SurfaceReferenceFactory:
-  base::Closure CreateReference(SurfaceReferenceOwner* owner,
-                                const SurfaceId& surface_id) const override;
-
- protected:
-  ~StubSurfaceReferenceFactory() override = default;
-
-  DISALLOW_COPY_AND_ASSIGN(StubSurfaceReferenceFactory);
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_COMMON_SURFACES_STUB_SURFACE_REFERENCE_FACTORY_H_
diff --git a/components/viz/common/surfaces/surface_reference_factory.h b/components/viz/common/surfaces/surface_reference_factory.h
deleted file mode 100644
index 03e5808..0000000
--- a/components/viz/common/surfaces/surface_reference_factory.h
+++ /dev/null
@@ -1,39 +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 COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_FACTORY_H_
-#define COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_FACTORY_H_
-
-#include "base/callback_forward.h"
-#include "base/memory/ref_counted.h"
-#include "components/viz/common/surfaces/surface_id.h"
-#include "components/viz/common/surfaces/surface_reference_owner.h"
-
-namespace viz {
-
-// Confusingly, SurfaceReferenceFactory is only used to create SurfaceSequences.
-// TODO(kylechar): Delete all usage of SurfaceReferenceFactory when surface
-// references are enabled by default.
-class SurfaceReferenceFactory
-    : public base::RefCountedThreadSafe<SurfaceReferenceFactory> {
- public:
-  // Creates a reference to the surface with the given surface id and returns
-  // a closure that must be called exactly once to remove the reference.
-  virtual base::Closure CreateReference(SurfaceReferenceOwner* owner,
-                                        const SurfaceId& surface_id) const = 0;
-
-  SurfaceReferenceFactory() = default;
-
- protected:
-  virtual ~SurfaceReferenceFactory() = default;
-
- private:
-  friend class base::RefCountedThreadSafe<SurfaceReferenceFactory>;
-
-  DISALLOW_COPY_AND_ASSIGN(SurfaceReferenceFactory);
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_FACTORY_H_
diff --git a/components/viz/common/surfaces/surface_reference_owner.h b/components/viz/common/surfaces/surface_reference_owner.h
deleted file mode 100644
index c966fb9..0000000
--- a/components/viz/common/surfaces/surface_reference_owner.h
+++ /dev/null
@@ -1,23 +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 COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_OWNER_H_
-#define COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_OWNER_H_
-
-#include "components/viz/common/surfaces/surface_sequence_generator.h"
-
-namespace viz {
-
-// Implementations of this interface can be passed to
-// SurfaceReferenceFactory::CreateReference as the reference owner.
-class SurfaceReferenceOwner {
- public:
-  virtual ~SurfaceReferenceOwner() {}
-
-  virtual SurfaceSequenceGenerator* GetSurfaceSequenceGenerator() = 0;
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_REFERENCE_OWNER_H_
diff --git a/components/viz/common/surfaces/surface_sequence.h b/components/viz/common/surfaces/surface_sequence.h
deleted file mode 100644
index 1b5bda9..0000000
--- a/components/viz/common/surfaces/surface_sequence.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_H_
-#define COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <tuple>
-
-#include "base/hash.h"
-#include "components/viz/common/surfaces/frame_sink_id.h"
-
-namespace viz {
-
-// A per-surface-namespace sequence number that's used to coordinate
-// dependencies between frames. A sequence number may be satisfied once, and
-// may be depended on once.
-struct SurfaceSequence {
-  SurfaceSequence() : sequence(0u) {}
-  SurfaceSequence(const FrameSinkId& frame_sink_id, uint32_t sequence)
-      : frame_sink_id(frame_sink_id), sequence(sequence) {}
-  bool is_valid() const { return frame_sink_id.is_valid() && sequence > 0u; }
-
-  FrameSinkId frame_sink_id;
-  uint32_t sequence;
-};
-
-inline bool operator==(const SurfaceSequence& a, const SurfaceSequence& b) {
-  return a.frame_sink_id == b.frame_sink_id && a.sequence == b.sequence;
-}
-
-inline bool operator!=(const SurfaceSequence& a, const SurfaceSequence& b) {
-  return !(a == b);
-}
-
-inline bool operator<(const SurfaceSequence& a, const SurfaceSequence& b) {
-  return std::tie(a.frame_sink_id, a.sequence) <
-         std::tie(b.frame_sink_id, b.sequence);
-}
-
-struct SurfaceSequenceHash {
-  size_t operator()(SurfaceSequence key) const {
-    return base::HashInts(static_cast<uint64_t>(key.frame_sink_id.hash()),
-                          key.sequence);
-  }
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_H_
diff --git a/components/viz/common/surfaces/surface_sequence_generator.cc b/components/viz/common/surfaces/surface_sequence_generator.cc
deleted file mode 100644
index f3c351e..0000000
--- a/components/viz/common/surfaces/surface_sequence_generator.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/surfaces/surface_sequence_generator.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
-
-namespace viz {
-
-SurfaceSequenceGenerator::SurfaceSequenceGenerator()
-    : next_surface_sequence_(1u) {}
-
-SurfaceSequenceGenerator::~SurfaceSequenceGenerator() = default;
-
-SurfaceSequence SurfaceSequenceGenerator::CreateSurfaceSequence() {
-  return SurfaceSequence(frame_sink_id_, next_surface_sequence_++);
-}
-
-}  // namespace viz
diff --git a/components/viz/common/surfaces/surface_sequence_generator.h b/components/viz/common/surfaces/surface_sequence_generator.h
deleted file mode 100644
index 1bed7d5..0000000
--- a/components/viz/common/surfaces/surface_sequence_generator.h
+++ /dev/null
@@ -1,41 +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 COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_GENERATOR_H_
-#define COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_GENERATOR_H_
-
-#include <stdint.h>
-
-#include <tuple>
-
-#include "base/macros.h"
-
-#include "components/viz/common/surfaces/frame_sink_id.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
-#include "components/viz/common/viz_common_export.h"
-
-namespace viz {
-
-// Generates unique surface sequences for a surface client id.
-class VIZ_COMMON_EXPORT SurfaceSequenceGenerator {
- public:
-  SurfaceSequenceGenerator();
-  ~SurfaceSequenceGenerator();
-
-  void set_frame_sink_id(const FrameSinkId& frame_sink_id) {
-    frame_sink_id_ = frame_sink_id;
-  }
-
-  SurfaceSequence CreateSurfaceSequence();
-
- private:
-  FrameSinkId frame_sink_id_;
-  uint32_t next_surface_sequence_;
-
-  DISALLOW_COPY_AND_ASSIGN(SurfaceSequenceGenerator);
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_SEQUENCE_GENERATOR_H_
diff --git a/components/viz/common/surfaces/surface_sequence_generator_unittest.cc b/components/viz/common/surfaces/surface_sequence_generator_unittest.cc
deleted file mode 100644
index 5d1913cc..0000000
--- a/components/viz/common/surfaces/surface_sequence_generator_unittest.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/surfaces/surface_sequence_generator.h"
-
-#include "components/viz/common/surfaces/surface_sequence.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace viz {
-namespace {
-
-static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
-
-TEST(SurfaceSequenceGeneratorTest, Basic) {
-  SurfaceSequenceGenerator generator;
-  generator.set_frame_sink_id(kArbitraryFrameSinkId);
-  SurfaceSequence sequence1 = generator.CreateSurfaceSequence();
-  SurfaceSequence sequence2 = generator.CreateSurfaceSequence();
-  EXPECT_NE(sequence1, sequence2);
-}
-
-}  // namespace
-}  // namespace viz
diff --git a/components/viz/common/switches.cc b/components/viz/common/switches.cc
index 8eaf1ca6..5f911d8 100644
--- a/components/viz/common/switches.cc
+++ b/components/viz/common/switches.cc
@@ -19,12 +19,6 @@
 const char kDeadlineToSynchronizeSurfaces[] =
     "deadline-to-synchronize-surfaces";
 
-// Disable surface lifetime management using surface references. This enables
-// adding surface sequences and disables adding temporary references. This flag
-// is only checked on Android, other platforms always have surface references
-// enabled.
-const char kDisableSurfaceReferences[] = "disable-surface-references";
-
 // Enables multi-client Surface synchronization. In practice, this indicates
 // that LayerTreeHost expects to be given a valid viz::LocalSurfaceId provided
 // by the parent compositor.
diff --git a/components/viz/common/switches.h b/components/viz/common/switches.h
index 6752c34..508d753 100644
--- a/components/viz/common/switches.h
+++ b/components/viz/common/switches.h
@@ -14,7 +14,6 @@
 
 // Keep list in alphabetical order.
 VIZ_COMMON_EXPORT extern const char kDeadlineToSynchronizeSurfaces[];
-VIZ_COMMON_EXPORT extern const char kDisableSurfaceReferences[];
 VIZ_COMMON_EXPORT extern const char kEnableSurfaceSynchronization[];
 
 VIZ_COMMON_EXPORT uint32_t GetDeadlineToSynchronizeSurfaces();
diff --git a/components/viz/host/host_frame_sink_manager.cc b/components/viz/host/host_frame_sink_manager.cc
index 1719ae8d..6df9d7f 100644
--- a/components/viz/host/host_frame_sink_manager.cc
+++ b/components/viz/host/host_frame_sink_manager.cc
@@ -26,10 +26,6 @@
   frame_sink_manager_impl_ = frame_sink_manager_impl;
 
   frame_sink_manager_ = frame_sink_manager_impl;
-
-  // Assign temporary references if FrameSinkManagerImpl is using them.
-  assign_temporary_references_ =
-      frame_sink_manager_impl_->surface_manager()->using_surface_references();
 }
 
 void HostFrameSinkManager::BindAndSetManager(
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index a2c5598..dc49222 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -137,8 +137,6 @@
     "hit_test/hit_test_aggregator_delegate.h",
     "hit_test/hit_test_manager.cc",
     "hit_test/hit_test_manager.h",
-    "surfaces/direct_surface_reference_factory.cc",
-    "surfaces/direct_surface_reference_factory.h",
     "surfaces/surface.cc",
     "surfaces/surface.h",
     "surfaces/surface_client.h",
diff --git a/components/viz/service/display/display_scheduler_unittest.cc b/components/viz/service/display/display_scheduler_unittest.cc
index 7211752..335f33a 100644
--- a/components/viz/service/display/display_scheduler_unittest.cc
+++ b/components/viz/service/display/display_scheduler_unittest.cc
@@ -123,7 +123,7 @@
   explicit DisplaySchedulerTest(bool wait_for_all_surfaces_before_draw = false)
       : fake_begin_frame_source_(0.f, false),
         task_runner_(new base::NullTaskRunner),
-        surface_manager_(SurfaceManager::LifetimeType::REFERENCES, 4u),
+        surface_manager_(4u),
         scheduler_(&fake_begin_frame_source_,
                    &surface_manager_,
                    task_runner_.get(),
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 4f94a0e35..8aa3917 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -72,12 +72,6 @@
 #if BUILDFLAG(ENABLE_VULKAN)
   return;
 #endif
-  gpu::gles2::GLES2Interface* gl =
-      output_surface_->context_provider()->ContextGL();
-  for (auto& pair : render_pass_backings_) {
-    RenderPassBacking& backing = pair.second;
-    gl->DeleteTextures(1, &backing.gl_id);
-  }
 }
 
 bool SkiaRenderer::CanPartialSwap() {
@@ -250,22 +244,12 @@
   return;
 #endif
 
-  RenderPassBacking& backing = render_pass_backings_[render_pass_id];
-  DCHECK(backing.gl_id);
-
-  GrGLTextureInfo texture_info;
-  texture_info.fID = backing.gl_id;
-  texture_info.fTarget = GL_TEXTURE_2D;
-  GrBackendTexture backend_texture(backing.size.width(), backing.size.height(),
-                                   ToGrPixelConfig(backing.format),
-                                   texture_info);
-  constexpr uint32_t flags = 0;
-  // LegacyFontHost will get LCD text and skia figures out what type to use.
-  SkSurfaceProps surface_props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
-  int msaa_sample_count = 0;
-  non_root_surface_ = SkSurface::MakeFromBackendTextureAsRenderTarget(
-      output_surface_->context_provider()->GrContext(), backend_texture,
-      kTopLeft_GrSurfaceOrigin, msaa_sample_count, nullptr, &surface_props);
+  auto iter = render_pass_backings_.find(render_pass_id);
+  DCHECK(render_pass_backings_.end() != iter);
+  // This function is called after AllocateRenderPassResourceIfNeeded, so there
+  // should be backing ready.
+  RenderPassBacking& backing = iter->second;
+  non_root_surface_ = backing.render_pass_surface;
   current_canvas_ = non_root_surface_->getCanvas();
 }
 
@@ -593,19 +577,14 @@
   NOTIMPLEMENTED();
   return;
 #endif
-  RenderPassBacking& content_texture =
-      render_pass_backings_[quad->render_pass_id];
-  DCHECK(content_texture.gl_id);
+  auto iter = render_pass_backings_.find(quad->render_pass_id);
+  DCHECK(render_pass_backings_.end() != iter);
+  // This function is called after AllocateRenderPassResourceIfNeeded, so there
+  // should be backing ready.
+  RenderPassBacking& content_texture = iter->second;
 
-  GrGLTextureInfo texture_info;
-  texture_info.fID = content_texture.gl_id;
-  texture_info.fTarget = GL_TEXTURE_2D;
-  GrBackendTexture backend_texture(
-      content_texture.size.width(), content_texture.size.height(),
-      ToGrPixelConfig(content_texture.format), texture_info);
-  sk_sp<SkImage> content = SkImage::MakeFromTexture(
-      output_surface_->context_provider()->GrContext(), backend_texture,
-      kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, nullptr);
+  sk_sp<SkImage> content =
+      content_texture.render_pass_surface->makeImageSnapshot();
 
   SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect());
   SkRect dest_visible_rect =
@@ -770,15 +749,10 @@
       passes_to_delete.push_back(pair.first);
   }
 
-  gpu::gles2::GLES2Interface* gl =
-      output_surface_->context_provider()->ContextGL();
-
   // Delete RenderPass backings from the previous frame that will not be used
   // again.
   for (size_t i = 0; i < passes_to_delete.size(); ++i) {
     auto it = render_pass_backings_.find(passes_to_delete[i]);
-    RenderPassBacking& backing = it->second;
-    gl->DeleteTextures(1, &backing.gl_id);
     render_pass_backings_.erase(it);
   }
 }
@@ -795,65 +769,62 @@
     return;
 
   ContextProvider* context_provider = output_surface_->context_provider();
-  gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
-  const gpu::Capabilities& caps = context_provider->ContextCapabilities();
+  bool capability_bgra8888 =
+      context_provider->ContextCapabilities().texture_format_bgra8888;
+  render_pass_backings_.insert(std::pair<RenderPassId, RenderPassBacking>(
+      render_pass_id,
+      RenderPassBacking(context_provider->GrContext(), requirements.size,
+                        requirements.mipmap, capability_bgra8888,
+                        current_frame()->current_render_pass->color_space)));
+}
 
-  uint32_t texture_id;
-  gl->GenTextures(1, &texture_id);
-  gl->BindTexture(GL_TEXTURE_2D, texture_id);
-
-  gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-  gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-  gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-  gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-  // This texture will be bound as a framebuffer, so optimize for that.
-  if (caps.texture_usage) {
-    gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE,
-                      GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
-  }
-
-  ResourceFormat backbuffer_format;
-  if (current_frame()->current_render_pass->color_space.IsHDR()) {
+SkiaRenderer::RenderPassBacking::RenderPassBacking(
+    GrContext* gr_context,
+    const gfx::Size& size,
+    bool mipmap,
+    bool capability_bgra8888,
+    const gfx::ColorSpace& color_space)
+    : size(size), mipmap(mipmap), color_space(color_space) {
+  ResourceFormat format;
+  if (color_space.IsHDR()) {
     // If a platform does not support half-float renderbuffers then it should
     // not should request HDR rendering.
-    DCHECK(caps.texture_half_float_linear);
-    DCHECK(caps.color_buffer_half_float_rgba);
-    backbuffer_format = RGBA_F16;
+    // DCHECK(caps.texture_half_float_linear);
+    // DCHECK(caps.color_buffer_half_float_rgba);
+    format = RGBA_F16;
   } else {
-    backbuffer_format =
-        PlatformColor::BestSupportedTextureFormat(caps.texture_format_bgra8888);
+    format = PlatformColor::BestSupportedTextureFormat(capability_bgra8888);
   }
+  SkColorType color_type = ResourceFormatToClosestSkColorType(format);
 
-  // If |texture_storage| is available, then we can use TexStorage2DEXT to make
-  // an immutable texture backing, which allows for optimized usage. Otherwise
-  // we must use the traditional TexImage2D to generate the texture backing.
-  if (caps.texture_storage) {
-    GLint levels = 1;
-    // If |texture_npot| is availble, and mipmaps are desired, we generate a
-    // mipmap for each power of 2 size. This is only done when using
-    // TexStorage2DEXT.
-    if (caps.texture_npot && requirements.mipmap) {
-      levels += base::bits::Log2Floor(
-          std::max(requirements.size.width(), requirements.size.height()));
-    }
-    gl->TexStorage2DEXT(GL_TEXTURE_2D, levels,
-                        TextureStorageFormat(backbuffer_format),
-                        requirements.size.width(), requirements.size.height());
-  } else {
-    gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(backbuffer_format),
-                   requirements.size.width(), requirements.size.height(), 0,
-                   GLDataFormat(backbuffer_format),
-                   GLDataType(backbuffer_format), nullptr);
-  }
+  constexpr uint32_t flags = 0;
+  // LegacyFontHost will get LCD text and skia figures out what type to use.
+  SkSurfaceProps surface_props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
+  int msaa_sample_count = 0;
+  SkImageInfo image_info = SkImageInfo::Make(
+      size.width(), size.height(), color_type, kPremul_SkAlphaType, nullptr);
+  render_pass_surface = SkSurface::MakeRenderTarget(
+      gr_context, SkBudgeted::kNo, image_info, msaa_sample_count,
+      kTopLeft_GrSurfaceOrigin, &surface_props, mipmap);
+}
 
-  RenderPassBacking& backing = render_pass_backings_[render_pass_id];
-  backing.gl_id = texture_id;
-  backing.size = requirements.size;
-  backing.mipmap = requirements.mipmap;
-  backing.format = backbuffer_format;
-  backing.color_space = current_frame()->current_render_pass->color_space;
-  gl->BindTexture(GL_TEXTURE_2D, 0);
+SkiaRenderer::RenderPassBacking::~RenderPassBacking() {}
+
+SkiaRenderer::RenderPassBacking::RenderPassBacking(
+    SkiaRenderer::RenderPassBacking&& other)
+    : size(other.size), mipmap(other.mipmap), color_space(other.color_space) {
+  render_pass_surface = other.render_pass_surface;
+  other.render_pass_surface = nullptr;
+}
+
+SkiaRenderer::RenderPassBacking& SkiaRenderer::RenderPassBacking::operator=(
+    SkiaRenderer::RenderPassBacking&& other) {
+  size = other.size;
+  mipmap = other.mipmap;
+  color_space = other.color_space;
+  render_pass_surface = other.render_pass_surface;
+  other.render_pass_surface = nullptr;
+  return *this;
 }
 
 bool SkiaRenderer::IsRenderPassResourceAllocated(
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index 18358d4..32aa19d 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -101,11 +101,18 @@
 
   // A map from RenderPass id to the texture used to draw the RenderPass from.
   struct RenderPassBacking {
-    uint32_t gl_id;
+    sk_sp<SkSurface> render_pass_surface;
     gfx::Size size;
     bool mipmap;
-    ResourceFormat format;
     gfx::ColorSpace color_space;
+    RenderPassBacking(GrContext* gr_context,
+                      const gfx::Size& size,
+                      bool mipmap,
+                      bool capability_bgra8888,
+                      const gfx::ColorSpace& color_space);
+    ~RenderPassBacking();
+    RenderPassBacking(RenderPassBacking&&);
+    RenderPassBacking& operator=(RenderPassBacking&&);
   };
   base::flat_map<RenderPassId, RenderPassBacking> render_pass_backings_;
 
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index 8617ed49..5c67eb7 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -24,35 +24,21 @@
 
 namespace viz {
 
-FrameSinkManagerImpl::FrameSinkSourceMapping::FrameSinkSourceMapping() =
+FrameSinkManagerImpl::FrameSinkData::FrameSinkData() = default;
+
+FrameSinkManagerImpl::FrameSinkData::FrameSinkData(FrameSinkData&& other) =
     default;
 
-FrameSinkManagerImpl::FrameSinkSourceMapping::FrameSinkSourceMapping(
-    FrameSinkSourceMapping&& other) = default;
+FrameSinkManagerImpl::FrameSinkData::~FrameSinkData() = default;
 
-FrameSinkManagerImpl::FrameSinkSourceMapping::~FrameSinkSourceMapping() =
-    default;
-
-FrameSinkManagerImpl::FrameSinkSourceMapping&
-FrameSinkManagerImpl::FrameSinkSourceMapping::operator=(
-    FrameSinkSourceMapping&& other) = default;
-
-FrameSinkManagerImpl::SinkAndSupport::SinkAndSupport() = default;
-
-FrameSinkManagerImpl::SinkAndSupport::SinkAndSupport(SinkAndSupport&& other) =
-    default;
-
-FrameSinkManagerImpl::SinkAndSupport::~SinkAndSupport() = default;
-
-FrameSinkManagerImpl::SinkAndSupport& FrameSinkManagerImpl::SinkAndSupport::
-operator=(SinkAndSupport&& other) = default;
+FrameSinkManagerImpl::FrameSinkData& FrameSinkManagerImpl::FrameSinkData::
+operator=(FrameSinkData&& other) = default;
 
 FrameSinkManagerImpl::FrameSinkManagerImpl(
-    SurfaceManager::LifetimeType lifetime_type,
     uint32_t number_of_frames_to_activation_deadline,
     DisplayProvider* display_provider)
     : display_provider_(display_provider),
-      surface_manager_(lifetime_type, number_of_frames_to_activation_deadline),
+      surface_manager_(number_of_frames_to_activation_deadline),
       hit_test_manager_(this),
       binding_(this) {
   surface_manager_.AddObserver(&hit_test_manager_);
@@ -61,11 +47,13 @@
 
 FrameSinkManagerImpl::~FrameSinkManagerImpl() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  // All CompositorFrameSinkSupports and BeginFrameSources should be deleted
+  // before FrameSinkManagerImpl destruction.
+  DCHECK(support_map_.empty());
+  DCHECK(registered_sources_.empty());
+
   video_capturers_.clear();
-  // All FrameSinks should be unregistered prior to FrameSinkManager
-  // destruction.
-  compositor_frame_sinks_.clear();
-  DCHECK_EQ(registered_sources_.size(), 0u);
   surface_manager_.RemoveObserver(this);
   surface_manager_.RemoveObserver(&hit_test_manager_);
 }
@@ -105,11 +93,13 @@
     video_detector_->OnFrameSinkIdInvalidated(frame_sink_id);
 
   // Destroy the [Root]CompositorFrameSinkImpl if there is one. This will result
-  // in UnregisterCompositorFrameSinkSupport() being called and |iter| will be
-  // invalidated afterwards
-  auto iter = compositor_frame_sinks_.find(frame_sink_id);
-  if (iter != compositor_frame_sinks_.end())
+  // in UnregisterCompositorFrameSinkSupport() being called.
+  auto iter = frame_sink_data_map_.find(frame_sink_id);
+  if (iter != frame_sink_data_map_.end()) {
     iter->second.sink.reset();
+    if (iter->second.empty())
+      frame_sink_data_map_.erase(iter);
+  }
 }
 
 void FrameSinkManagerImpl::SetFrameSinkDebugLabel(
@@ -121,7 +111,7 @@
 void FrameSinkManagerImpl::CreateRootCompositorFrameSink(
     mojom::RootCompositorFrameSinkParamsPtr params) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK_EQ(0u, compositor_frame_sinks_.count(params->frame_sink_id));
+  DCHECK(!frame_sink_data_map_[params->frame_sink_id].sink);
   DCHECK(display_provider_);
 
   std::unique_ptr<ExternalBeginFrameControllerImpl>
@@ -141,17 +131,16 @@
       external_begin_frame_controller.get(), params->renderer_settings,
       &begin_frame_source);
 
-  auto frame_sink = std::make_unique<RootCompositorFrameSinkImpl>(
-      this, params->frame_sink_id, std::move(display),
-      std::move(begin_frame_source), std::move(external_begin_frame_controller),
-      std::move(params->compositor_frame_sink),
-      mojom::CompositorFrameSinkClientPtr(
-          std::move(params->compositor_frame_sink_client)),
-      std::move(params->display_private),
-      mojom::DisplayClientPtr(std::move(params->display_client)));
-  SinkAndSupport& entry = compositor_frame_sinks_[params->frame_sink_id];
-  DCHECK(entry.support);  // |entry| was created by RootCompositorFrameSinkImpl.
-  entry.sink = std::move(frame_sink);
+  frame_sink_data_map_[params->frame_sink_id].sink =
+      std::make_unique<RootCompositorFrameSinkImpl>(
+          this, params->frame_sink_id, std::move(display),
+          std::move(begin_frame_source),
+          std::move(external_begin_frame_controller),
+          std::move(params->compositor_frame_sink),
+          mojom::CompositorFrameSinkClientPtr(
+              std::move(params->compositor_frame_sink_client)),
+          std::move(params->display_private),
+          mojom::DisplayClientPtr(std::move(params->display_client)));
 }
 
 void FrameSinkManagerImpl::CreateCompositorFrameSink(
@@ -159,13 +148,11 @@
     mojom::CompositorFrameSinkRequest request,
     mojom::CompositorFrameSinkClientPtr client) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK_EQ(0u, compositor_frame_sinks_.count(frame_sink_id));
+  DCHECK(!frame_sink_data_map_[frame_sink_id].sink);
 
-  auto frame_sink = std::make_unique<CompositorFrameSinkImpl>(
-      this, frame_sink_id, std::move(request), std::move(client));
-  SinkAndSupport& entry = compositor_frame_sinks_[frame_sink_id];
-  DCHECK(entry.support);  // |entry| was created by CompositorFrameSinkImpl.
-  entry.sink = std::move(frame_sink);
+  frame_sink_data_map_[frame_sink_id].sink =
+      std::make_unique<CompositorFrameSinkImpl>(
+          this, frame_sink_id, std::move(request), std::move(client));
 }
 
 void FrameSinkManagerImpl::RegisterFrameSinkHierarchy(
@@ -175,14 +162,14 @@
   // then this will create an infinite loop.  Might as well just crash here.
   CHECK(!ChildContains(child_frame_sink_id, parent_frame_sink_id));
 
-  auto& children = frame_sink_source_map_[parent_frame_sink_id].children;
+  auto& children = frame_sink_data_map_[parent_frame_sink_id].children;
   DCHECK(!base::ContainsKey(children, child_frame_sink_id));
   children.insert(child_frame_sink_id);
 
   // If the parent has no source, then attaching it to this child will
   // not change any downstream sources.
   BeginFrameSource* parent_source =
-      frame_sink_source_map_[parent_frame_sink_id].source;
+      frame_sink_data_map_[parent_frame_sink_id].source;
   if (!parent_source)
     return;
 
@@ -198,30 +185,26 @@
   // in time. This makes it possible to invalidate parent and child FrameSinkIds
   // independently of each other and not have an ordering dependency of
   // unregistering the hierarchy first before either of them.
-  auto iter = frame_sink_source_map_.find(parent_frame_sink_id);
-  DCHECK(iter != frame_sink_source_map_.end());
+  auto iter = frame_sink_data_map_.find(parent_frame_sink_id);
+  DCHECK(iter != frame_sink_data_map_.end());
 
   // Remove |child_frame_sink_id| from parents list of children.
-  auto& mapping = iter->second;
-  DCHECK(base::ContainsKey(mapping.children, child_frame_sink_id));
-  mapping.children.erase(child_frame_sink_id);
-
-  // Delete the FrameSinkSourceMapping for |parent_frame_sink_id| if empty.
-  if (!mapping.has_children() && !mapping.source) {
-    frame_sink_source_map_.erase(iter);
-    return;
-  }
+  auto& data = iter->second;
+  DCHECK(base::ContainsKey(data.children, child_frame_sink_id));
+  data.children.erase(child_frame_sink_id);
 
   // If the parent does not have a begin frame source, then disconnecting it
   // will not change any of its children.
-  BeginFrameSource* parent_source = iter->second.source;
-  if (!parent_source)
+  if (!data.source) {
+    if (data.empty())
+      frame_sink_data_map_.erase(iter);
     return;
+  }
 
   // TODO(enne): these walks could be done in one step.
-  RecursivelyDetachBeginFrameSource(child_frame_sink_id, parent_source);
-  for (auto& source_iter : registered_sources_)
-    RecursivelyAttachBeginFrameSource(source_iter.second, source_iter.first);
+  RecursivelyDetachBeginFrameSource(child_frame_sink_id, data.source);
+  for (auto& map_entry : registered_sources_)
+    RecursivelyAttachBeginFrameSource(map_entry.second, map_entry.first);
 }
 
 void FrameSinkManagerImpl::AssignTemporaryReference(const SurfaceId& surface_id,
@@ -250,31 +233,30 @@
     const FrameSinkId& frame_sink_id,
     CompositorFrameSinkSupport* support) {
   DCHECK(support);
+  DCHECK(!base::ContainsKey(support_map_, frame_sink_id));
 
-  SinkAndSupport& entry = compositor_frame_sinks_[frame_sink_id];
-  DCHECK(!entry.support);
-  entry.support = support;
+  support_map_[frame_sink_id] = support;
 
   for (auto& capturer : video_capturers_) {
     if (capturer->requested_target() == frame_sink_id)
-      capturer->SetResolvedTarget(entry.support);
+      capturer->SetResolvedTarget(support);
   }
 
-  auto it = frame_sink_source_map_.find(frame_sink_id);
-  if (it != frame_sink_source_map_.end() && it->second.source)
+  auto it = frame_sink_data_map_.find(frame_sink_id);
+  if (it != frame_sink_data_map_.end() && it->second.source)
     support->SetBeginFrameSource(it->second.source);
 }
 
 void FrameSinkManagerImpl::UnregisterCompositorFrameSinkSupport(
     const FrameSinkId& frame_sink_id) {
-  DCHECK_EQ(compositor_frame_sinks_.count(frame_sink_id), 1u);
+  DCHECK(base::ContainsKey(support_map_, frame_sink_id));
 
   for (auto& capturer : video_capturers_) {
     if (capturer->requested_target() == frame_sink_id)
       capturer->OnTargetWillGoAway();
   }
 
-  compositor_frame_sinks_.erase(frame_sink_id);
+  support_map_.erase(frame_sink_id);
 }
 
 void FrameSinkManagerImpl::RegisterBeginFrameSource(
@@ -299,7 +281,7 @@
 
   primary_source_.OnBeginFrameSourceRemoved(source);
 
-  if (frame_sink_source_map_.count(frame_sink_id) == 0u)
+  if (frame_sink_data_map_.count(frame_sink_id) == 0u)
     return;
 
   // TODO(enne): these walks could be done in one step.
@@ -318,17 +300,17 @@
 void FrameSinkManagerImpl::RecursivelyAttachBeginFrameSource(
     const FrameSinkId& frame_sink_id,
     BeginFrameSource* source) {
-  FrameSinkSourceMapping& mapping = frame_sink_source_map_[frame_sink_id];
-  if (!mapping.source) {
-    mapping.source = source;
-    auto iter = compositor_frame_sinks_.find(frame_sink_id);
-    if (iter != compositor_frame_sinks_.end())
-      iter->second.support->SetBeginFrameSource(source);
+  FrameSinkData& data = frame_sink_data_map_[frame_sink_id];
+  if (!data.source) {
+    data.source = source;
+    auto iter = support_map_.find(frame_sink_id);
+    if (iter != support_map_.end())
+      iter->second->SetBeginFrameSource(source);
   }
 
   // Copy the list of children because RecursivelyAttachBeginFrameSource() can
-  // modify |frame_sink_source_map_| and invalidate iterators.
-  base::flat_set<FrameSinkId> children = mapping.children;
+  // modify |frame_sink_data_map_| and invalidate iterators.
+  base::flat_set<FrameSinkId> children = data.children;
   for (const FrameSinkId& child : children)
     RecursivelyAttachBeginFrameSource(child, source);
 }
@@ -336,37 +318,37 @@
 void FrameSinkManagerImpl::RecursivelyDetachBeginFrameSource(
     const FrameSinkId& frame_sink_id,
     BeginFrameSource* source) {
-  auto iter = frame_sink_source_map_.find(frame_sink_id);
-  if (iter == frame_sink_source_map_.end())
+  auto iter = frame_sink_data_map_.find(frame_sink_id);
+  if (iter == frame_sink_data_map_.end())
     return;
 
-  auto& mapping = iter->second;
-  if (mapping.source == source) {
-    mapping.source = nullptr;
-    auto client_iter = compositor_frame_sinks_.find(frame_sink_id);
-    if (client_iter != compositor_frame_sinks_.end())
-      client_iter->second.support->SetBeginFrameSource(nullptr);
+  auto& data = iter->second;
+  if (data.source == source) {
+    data.source = nullptr;
+    auto client_iter = support_map_.find(frame_sink_id);
+    if (client_iter != support_map_.end())
+      client_iter->second->SetBeginFrameSource(nullptr);
   }
 
-  // Delete the FrameSinkSourceMapping for |frame_sink_id| if empty.
-  if (!mapping.has_children()) {
-    frame_sink_source_map_.erase(iter);
+  // Delete the FrameSinkData for |frame_sink_id| if empty.
+  if (data.empty()) {
+    frame_sink_data_map_.erase(iter);
     return;
   }
 
   // Copy the list of children because RecursivelyDetachBeginFrameSource() can
-  // modify |frame_sink_source_map_| and invalidate iterators.
-  base::flat_set<FrameSinkId> children = mapping.children;
+  // modify |frame_sink_data_map_| and invalidate iterators.
+  base::flat_set<FrameSinkId> children = data.children;
   for (const FrameSinkId& child : children)
     RecursivelyDetachBeginFrameSource(child, source);
 }
 
 CapturableFrameSink* FrameSinkManagerImpl::FindCapturableFrameSink(
     const FrameSinkId& frame_sink_id) {
-  const auto it = compositor_frame_sinks_.find(frame_sink_id);
-  if (it == compositor_frame_sinks_.end())
+  const auto it = support_map_.find(frame_sink_id);
+  if (it == support_map_.end())
     return nullptr;
-  return it->second.support;
+  return it->second;
 }
 
 void FrameSinkManagerImpl::OnCapturerConnectionLost(
@@ -377,8 +359,8 @@
 bool FrameSinkManagerImpl::ChildContains(
     const FrameSinkId& child_frame_sink_id,
     const FrameSinkId& search_frame_sink_id) const {
-  auto iter = frame_sink_source_map_.find(child_frame_sink_id);
-  if (iter == frame_sink_source_map_.end())
+  auto iter = frame_sink_data_map_.find(child_frame_sink_id);
+  if (iter == frame_sink_data_map_.end())
     return false;
 
   for (const FrameSinkId& child : iter->second.children) {
@@ -398,8 +380,7 @@
   } else {
     // There is no client to assign an owner for the temporary reference, so we
     // can drop the temporary reference safely.
-    if (surface_manager_.using_surface_references())
-      surface_manager_.DropTemporaryReference(surface_id);
+    surface_manager_.DropTemporaryReference(surface_id);
   }
 }
 
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index 58798be2..d919f550 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -43,9 +43,7 @@
       public FrameSinkVideoCapturerManager,
       public mojom::FrameSinkManager {
  public:
-  FrameSinkManagerImpl(SurfaceManager::LifetimeType lifetime_type =
-                           SurfaceManager::LifetimeType::REFERENCES,
-                       uint32_t number_of_frames_to_activation_deadline = 4u,
+  FrameSinkManagerImpl(uint32_t number_of_frames_to_activation_deadline = 4u,
                        DisplayProvider* display_provider = nullptr);
   ~FrameSinkManagerImpl() override;
 
@@ -164,37 +162,25 @@
   friend class FrameSinkManagerTest;
 
   // BeginFrameSource routing information for a FrameSinkId.
-  struct FrameSinkSourceMapping {
-    FrameSinkSourceMapping();
-    FrameSinkSourceMapping(FrameSinkSourceMapping&& other);
-    ~FrameSinkSourceMapping();
-    FrameSinkSourceMapping& operator=(FrameSinkSourceMapping&& other);
+  struct FrameSinkData {
+    FrameSinkData();
+    FrameSinkData(FrameSinkData&& other);
+    ~FrameSinkData();
+    FrameSinkData& operator=(FrameSinkData&& other);
 
-    bool has_children() const { return !children.empty(); }
+    bool empty() const { return !source && children.empty() && !sink; }
+
     // The currently assigned begin frame source for this client.
     BeginFrameSource* source = nullptr;
     // This represents a dag of parent -> children mapping.
     base::flat_set<FrameSinkId> children;
 
-   private:
-    DISALLOW_COPY_AND_ASSIGN(FrameSinkSourceMapping);
-  };
-
-  struct SinkAndSupport {
-    SinkAndSupport();
-    SinkAndSupport(SinkAndSupport&& other);
-    ~SinkAndSupport();
-    SinkAndSupport& operator=(SinkAndSupport&& other);
-
     // CompositorFrameSinks owned here. This will be null if a
     // CompositorFrameSinkSupport is owned externally.
     std::unique_ptr<mojom::CompositorFrameSink> sink;
 
-    // This can be owned by |sink| or owned externally.
-    CompositorFrameSinkSupport* support = nullptr;
-
    private:
-    DISALLOW_COPY_AND_ASSIGN(SinkAndSupport);
+    DISALLOW_COPY_AND_ASSIGN(FrameSinkData);
   };
 
   void RecursivelyAttachBeginFrameSource(const FrameSinkId& frame_sink_id,
@@ -220,11 +206,13 @@
   // parent in the dag.
   base::flat_map<BeginFrameSource*, FrameSinkId> registered_sources_;
 
-  // Contains FrameSinkId hierarchy and BeginFrameSource mapping.
-  base::flat_map<FrameSinkId, FrameSinkSourceMapping> frame_sink_source_map_;
+  // Contains FrameSinkId hierarchy, BeginFrameSource mapping and maybe a
+  // [Root]CompositorFrameSinkImpl.
+  base::flat_map<FrameSinkId, FrameSinkData> frame_sink_data_map_;
 
-  // Contains (and maybe owns) the CompositorFrameSinkSupport.
-  base::flat_map<FrameSinkId, SinkAndSupport> compositor_frame_sinks_;
+  // CompositorFrameSinkSupports get added to this map on creation and removed
+  // on destruction.
+  base::flat_map<FrameSinkId, CompositorFrameSinkSupport*> support_map_;
 
   PrimaryBeginFrameSource primary_source_;
 
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc b/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
index 9b5a2a6d..4491baf 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
@@ -36,8 +36,8 @@
 
   // testing::Test implementation.
   void TearDown() override {
-    // Make sure that all FrameSinkSourceMappings have been deleted.
-    EXPECT_TRUE(manager_.frame_sink_source_map_.empty());
+    // Make sure that all FrameSinkData has been deleted.
+    EXPECT_TRUE(manager_.frame_sink_data_map_.empty());
   }
 
  protected:
diff --git a/components/viz/service/main/viz_main_impl.cc b/components/viz/service/main/viz_main_impl.cc
index 9066f83..fb8f37b 100644
--- a/components/viz/service/main/viz_main_impl.cc
+++ b/components/viz/service/main/viz_main_impl.cc
@@ -277,7 +277,6 @@
   mojom::FrameSinkManagerClientPtr client(
       std::move(params->frame_sink_manager_client));
   frame_sink_manager_ = std::make_unique<FrameSinkManagerImpl>(
-      SurfaceManager::LifetimeType::REFERENCES,
       params->number_of_frames_to_activation_deadline, display_provider_.get());
   frame_sink_manager_->BindAndSetClient(std::move(params->frame_sink_manager),
                                         nullptr, std::move(client));
diff --git a/components/viz/service/surfaces/direct_surface_reference_factory.cc b/components/viz/service/surfaces/direct_surface_reference_factory.cc
deleted file mode 100644
index 1cde4a6..0000000
--- a/components/viz/service/surfaces/direct_surface_reference_factory.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/surfaces/direct_surface_reference_factory.h"
-
-#include <vector>
-
-#include "components/viz/service/surfaces/surface.h"
-
-namespace viz {
-
-DirectSurfaceReferenceFactory::DirectSurfaceReferenceFactory(
-    base::WeakPtr<SurfaceManager> manager)
-    : manager_(manager) {}
-
-DirectSurfaceReferenceFactory::~DirectSurfaceReferenceFactory() = default;
-void DirectSurfaceReferenceFactory::SatisfySequence(
-    const SurfaceSequence& sequence) const {
-  if (!manager_)
-    return;
-  manager_->SatisfySequence(sequence);
-}
-
-void DirectSurfaceReferenceFactory::RequireSequence(
-    const SurfaceId& surface_id,
-    const SurfaceSequence& sequence) const {
-  manager_->RequireSequence(surface_id, sequence);
-}
-
-}  // namespace viz
diff --git a/components/viz/service/surfaces/direct_surface_reference_factory.h b/components/viz/service/surfaces/direct_surface_reference_factory.h
deleted file mode 100644
index 1348578..0000000
--- a/components/viz/service/surfaces/direct_surface_reference_factory.h
+++ /dev/null
@@ -1,42 +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 COMPONENTS_VIZ_SERVICE_SURFACES_DIRECT_SURFACE_REFERENCE_FACTORY_H_
-#define COMPONENTS_VIZ_SERVICE_SURFACES_DIRECT_SURFACE_REFERENCE_FACTORY_H_
-
-#include "base/compiler_specific.h"
-#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
-#include "components/viz/common/surfaces/surface_id.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
-#include "components/viz/service/surfaces/surface_manager.h"
-#include "components/viz/service/viz_service_export.h"
-
-namespace viz {
-
-class SurfaceManager;
-
-// The surface reference factory that interacts directly with SurfaceManager.
-// You probably don't need to instantiate this class directly.
-// Use SurfaceManager::reference_factory() instead.
-class VIZ_SERVICE_EXPORT DirectSurfaceReferenceFactory final
-    : public SequenceSurfaceReferenceFactory {
- public:
-  explicit DirectSurfaceReferenceFactory(base::WeakPtr<SurfaceManager> manager);
-
- private:
-  ~DirectSurfaceReferenceFactory() override;
-
-  // SequenceSurfaceReferenceFactory implementation:
-  void SatisfySequence(const SurfaceSequence& sequence) const override;
-  void RequireSequence(const SurfaceId& surface_id,
-                       const SurfaceSequence& sequence) const override;
-
-  base::WeakPtr<SurfaceManager> manager_;
-
-  DISALLOW_COPY_AND_ASSIGN(DirectSurfaceReferenceFactory);
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_SERVICE_SURFACES_DIRECT_SURFACE_REFERENCE_FACTORY_H_
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc
index beccc68..494938d 100644
--- a/components/viz/service/surfaces/surface.cc
+++ b/components/viz/service/surfaces/surface.cc
@@ -436,20 +436,6 @@
       surface_id().local_surface_id(), damage_rect, active_frame_data_->frame);
 }
 
-void Surface::AddDestructionDependency(SurfaceSequence sequence) {
-  destruction_dependencies_.push_back(sequence);
-}
-
-void Surface::SatisfyDestructionDependencies(
-    base::flat_set<SurfaceSequence>* sequences,
-    base::flat_map<FrameSinkId, std::string>* valid_frame_sink_ids) {
-  base::EraseIf(destruction_dependencies_,
-                [sequences, valid_frame_sink_ids](SurfaceSequence seq) {
-                  return (!!sequences->erase(seq) ||
-                          !valid_frame_sink_ids->count(seq.frame_sink_id));
-                });
-}
-
 void Surface::OnDeadline() {
   TRACE_EVENT1("viz", "Surface::OnDeadline", "FrameSinkId",
                surface_id().frame_sink_id().ToString());
diff --git a/components/viz/service/surfaces/surface.h b/components/viz/service/surfaces/surface.h
index 637aa8624..9938cde 100644
--- a/components/viz/service/surfaces/surface.h
+++ b/components/viz/service/surfaces/surface.h
@@ -22,7 +22,6 @@
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "components/viz/service/surfaces/surface_dependency_deadline.h"
 #include "components/viz/service/viz_service_export.h"
 #include "ui/gfx/geometry/size.h"
@@ -168,19 +167,6 @@
   void RunDrawCallback();
   void NotifyAggregatedDamage(const gfx::Rect& damage_rect);
 
-  // Add a SurfaceSequence that must be satisfied before the Surface is
-  // destroyed.
-  void AddDestructionDependency(SurfaceSequence sequence);
-
-  // Satisfy all destruction dependencies that are contained in sequences, and
-  // remove them from sequences.
-  void SatisfyDestructionDependencies(
-      base::flat_set<SurfaceSequence>* sequences,
-      base::flat_map<FrameSinkId, std::string>* valid_id_namespaces);
-  size_t GetDestructionDependencyCount() const {
-    return destruction_dependencies_.size();
-  }
-
   const std::vector<SurfaceId>* active_referenced_surfaces() const {
     return active_frame_data_
                ? &active_frame_data_->frame.metadata.referenced_surfaces
@@ -267,7 +253,6 @@
   bool closed_ = false;
   bool seen_first_frame_activation_ = false;
   const bool needs_sync_tokens_;
-  std::vector<SurfaceSequence> destruction_dependencies_;
 
   base::flat_set<SurfaceId> activation_dependencies_;
   base::flat_set<SurfaceId> late_activation_dependencies_;
diff --git a/components/viz/service/surfaces/surface_manager.cc b/components/viz/service/surfaces/surface_manager.cc
index f8f667e..a8fd6a8 100644
--- a/components/viz/service/surfaces/surface_manager.cc
+++ b/components/viz/service/surfaces/surface_manager.cc
@@ -16,9 +16,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
-#include "components/viz/common/surfaces/stub_surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/service/surfaces/direct_surface_reference_factory.h"
 #include "components/viz/service/surfaces/surface.h"
 #include "components/viz/service/surfaces/surface_client.h"
 
@@ -45,16 +43,12 @@
 
 SurfaceManager::TemporaryReferenceData::~TemporaryReferenceData() = default;
 
-SurfaceManager::SurfaceManager(LifetimeType lifetime_type,
-                               uint32_t number_of_frames_to_activation_deadline)
-    : lifetime_type_(lifetime_type),
-      dependency_tracker_(this, number_of_frames_to_activation_deadline),
+SurfaceManager::SurfaceManager(uint32_t number_of_frames_to_activation_deadline)
+    : dependency_tracker_(this, number_of_frames_to_activation_deadline),
       root_surface_id_(FrameSinkId(0u, 0u),
                        LocalSurfaceId(1u, base::UnguessableToken::Create())),
       weak_factory_(this) {
   thread_checker_.DetachFromThread();
-  if (using_surface_references()) {
-    reference_factory_ = new StubSurfaceReferenceFactory();
 
     // Android WebView doesn't have a task runner and doesn't need the timer.
     if (base::SequencedTaskRunnerHandle::IsSet()) {
@@ -65,10 +59,6 @@
     // TODO(kylechar): After collecting UMA stats on the number of old temporary
     // references, we may want to turn the timer off when there are no temporary
     // references to avoid waking the thread unnecessarily.
-  } else {
-    reference_factory_ =
-        new DirectSurfaceReferenceFactory(weak_factory_.GetWeakPtr());
-  }
 }
 
 SurfaceManager::~SurfaceManager() {
@@ -124,15 +114,14 @@
     surface_map_[surface_info.id()] =
         std::make_unique<Surface>(surface_info, this, surface_client,
                                   begin_frame_source, needs_sync_tokens);
-    if (lifetime_type_ == LifetimeType::REFERENCES) {
-      // We can get into a situation where multiple CompositorFrames arrive for
-      // a FrameSink before the client can add any references for the frame.
-      // When the second frame with a new size arrives, the first will be
-      // destroyed in SurfaceFactory and then if there are no references it will
-      // be deleted during surface GC. A temporary reference, removed when a
-      // real reference is received, is added to prevent this from happening.
-      AddTemporaryReference(surface_info.id());
-    }
+    // We can get into a situation where multiple CompositorFrames arrive for a
+    // FrameSink before the client can add any references for the frame. When
+    // the second frame with a new size arrives, the first will be destroyed in
+    // SurfaceFactory and then if there are no references it will be deleted
+    // during surface GC. A temporary reference, removed when a real reference
+    // is received, is added to prevent this from happening.
+    AddTemporaryReference(surface_info.id());
+
     for (auto& observer : observer_list_)
       observer.OnSurfaceCreated(surface_info.id());
     return surface_map_[surface_info.id()].get();
@@ -161,23 +150,6 @@
   surfaces_to_destroy_.insert(surface_id);
 }
 
-void SurfaceManager::RequireSequence(const SurfaceId& surface_id,
-                                     const SurfaceSequence& sequence) {
-  DCHECK_EQ(lifetime_type_, LifetimeType::SEQUENCES);
-  auto* surface = GetSurfaceForId(surface_id);
-  if (!surface) {
-    DLOG(ERROR) << "Attempting to require callback on nonexistent surface";
-    return;
-  }
-  surface->AddDestructionDependency(sequence);
-}
-
-void SurfaceManager::SatisfySequence(const SurfaceSequence& sequence) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK_EQ(lifetime_type_, LifetimeType::SEQUENCES);
-  satisfied_sequences_.insert(sequence);
-}
-
 void SurfaceManager::RegisterFrameSinkId(const FrameSinkId& frame_sink_id) {
   bool inserted = valid_frame_sink_labels_.emplace(frame_sink_id, "").second;
   DCHECK(inserted);
@@ -238,7 +210,6 @@
 void SurfaceManager::AssignTemporaryReference(const SurfaceId& surface_id,
                                               const FrameSinkId& owner) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK_EQ(lifetime_type_, LifetimeType::REFERENCES);
 
   if (!HasTemporaryReference(surface_id))
     return;
@@ -249,10 +220,8 @@
 void SurfaceManager::DropTemporaryReference(const SurfaceId& surface_id) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  if (lifetime_type_ != LifetimeType::REFERENCES ||
-      !HasTemporaryReference(surface_id)) {
+  if (!HasTemporaryReference(surface_id))
     return;
-  }
 
   RemoveTemporaryReference(surface_id, false);
 }
@@ -262,9 +231,7 @@
   if (surfaces_to_destroy_.empty())
     return;
 
-  SurfaceIdSet reachable_surfaces = using_surface_references()
-                                        ? GetLiveSurfacesForReferences()
-                                        : GetLiveSurfacesForSequences();
+  SurfaceIdSet reachable_surfaces = GetLiveSurfacesForReferences();
 
   std::vector<SurfaceId> surfaces_to_delete;
 
@@ -301,8 +268,6 @@
 }
 
 SurfaceManager::SurfaceIdSet SurfaceManager::GetLiveSurfacesForReferences() {
-  DCHECK(using_surface_references());
-
   SurfaceIdSet reachable_surfaces;
 
   // Walk down from the root and mark each SurfaceId we encounter as
@@ -339,52 +304,6 @@
   return reachable_surfaces;
 }
 
-SurfaceManager::SurfaceIdSet SurfaceManager::GetLiveSurfacesForSequences() {
-  DCHECK_EQ(lifetime_type_, LifetimeType::SEQUENCES);
-
-  // Simple mark and sweep GC.
-  // TODO(jbauman): Reduce the amount of work when nothing needs to be
-  // destroyed.
-  std::vector<SurfaceId> live_surfaces;
-  std::unordered_set<SurfaceId, SurfaceIdHash> live_surfaces_set;
-
-  // GC roots are surfaces that have not been destroyed, or have not had all
-  // their destruction dependencies satisfied.
-  for (auto& map_entry : surface_map_) {
-    const SurfaceId& surface_id = map_entry.first;
-    Surface* surface = map_entry.second.get();
-    surface->SatisfyDestructionDependencies(&satisfied_sequences_,
-                                            &valid_frame_sink_labels_);
-
-    if (!IsMarkedForDestruction(surface_id) ||
-        surface->GetDestructionDependencyCount() > 0) {
-      live_surfaces_set.insert(surface_id);
-      live_surfaces.push_back(surface_id);
-    }
-  }
-
-  // Mark all surfaces reachable from live surfaces by adding them to
-  // live_surfaces and live_surfaces_set.
-  for (size_t i = 0; i < live_surfaces.size(); i++) {
-    Surface* surf = surface_map_[live_surfaces[i]].get();
-    DCHECK(surf);
-
-    const auto& children = GetSurfacesReferencedByParent(surf->surface_id());
-    for (const SurfaceId& id : children) {
-      if (live_surfaces_set.count(id))
-        continue;
-
-      Surface* surf2 = GetSurfaceForId(id);
-      if (surf2) {
-        live_surfaces.push_back(id);
-        live_surfaces_set.insert(id);
-      }
-    }
-  }
-
-  return live_surfaces_set;
-}
-
 void SurfaceManager::AddSurfaceReferenceImpl(const SurfaceId& parent_id,
                                              const SurfaceId& child_id) {
   if (parent_id.frame_sink_id() == child_id.frame_sink_id()) {
@@ -482,9 +401,6 @@
 Surface* SurfaceManager::GetLatestInFlightSurface(
     const SurfaceId& primary_surface_id,
     const SurfaceId& fallback_surface_id) {
-  if (!using_surface_references())
-    return nullptr;
-
   // The fallback surface must exist before we begin looking for more recent
   // surfaces. This guarantees that the |parent| is allowed to embed the
   // |fallback_surface_id| and is not guessing surface IDs.
diff --git a/components/viz/service/surfaces/surface_manager.h b/components/viz/service/surfaces/surface_manager.h
index b555701..c8093532 100644
--- a/components/viz/service/surfaces/surface_manager.h
+++ b/components/viz/service/surfaces/surface_manager.h
@@ -22,8 +22,6 @@
 #include "base/timer/timer.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/surface_id.h"
-#include "components/viz/common/surfaces/surface_reference_factory.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "components/viz/service/surfaces/surface_dependency_tracker.h"
 #include "components/viz/service/surfaces/surface_observer.h"
 #include "components/viz/service/surfaces/surface_reference.h"
@@ -45,13 +43,7 @@
 
 class VIZ_SERVICE_EXPORT SurfaceManager {
  public:
-  enum class LifetimeType {
-    REFERENCES,
-    SEQUENCES,
-  };
-
-  SurfaceManager(LifetimeType lifetime_type,
-                 uint32_t number_of_frames_to_activation_deadline);
+  explicit SurfaceManager(uint32_t number_of_frames_to_activation_deadline);
   ~SurfaceManager();
 
 #if DCHECK_IS_ON()
@@ -64,8 +56,7 @@
   // Creates a Surface for the given SurfaceClient. The surface will be
   // destroyed when DestroySurface is called, all of its destruction
   // dependencies are satisfied, and it is not reachable from the root surface.
-  // If LifetimeType=REFERENCES, then a temporary reference will be added to
-  // the new Surface.
+  // A temporary reference will be added to the new Surface.
   Surface* CreateSurface(base::WeakPtr<SurfaceClient> surface_client,
                          const SurfaceInfo& surface_info,
                          BeginFrameSource* begin_frame_source,
@@ -110,15 +101,6 @@
   void SurfaceDamageExpected(const SurfaceId& surface_id,
                              const BeginFrameArgs& args);
 
-  // Require that the given sequence number must be satisfied (using
-  // SatisfySequence) before the given surface can be destroyed.
-  void RequireSequence(const SurfaceId& surface_id,
-                       const SurfaceSequence& sequence);
-
-  // Satisfies the given sequence number. Once all sequence numbers that
-  // a surface depends on are satisfied, the surface can be destroyed.
-  void SatisfySequence(const SurfaceSequence& sequence);
-
   void RegisterFrameSinkId(const FrameSinkId& frame_sink_id);
 
   // Invalidate a frame_sink_id that might still have associated sequences,
@@ -186,14 +168,6 @@
   const base::flat_set<SurfaceId>& GetSurfacesThatReferenceChild(
       const SurfaceId& surface_id) const;
 
-  const scoped_refptr<SurfaceReferenceFactory>& reference_factory() {
-    return reference_factory_;
-  }
-
-  bool using_surface_references() const {
-    return lifetime_type_ == LifetimeType::REFERENCES;
-  }
-
   // Returns the most recent surface associated with the |fallback_surface_id|'s
   // FrameSinkId that was created prior to the current primary surface and
   // verified by the viz host to be owned by the fallback surface's parent. If
@@ -290,9 +264,6 @@
       const base::flat_set<SurfaceId>& fallback_parents,
       const base::Optional<FrameSinkId>& owner) const;
 
-  // Use reference or sequence based lifetime management.
-  LifetimeType lifetime_type_;
-
   // SurfaceDependencyTracker needs to be destroyed after Surfaces are destroyed
   // because they will call back into the dependency tracker.
   SurfaceDependencyTracker dependency_tracker_;
@@ -303,10 +274,6 @@
 
   base::flat_set<SurfaceId> surfaces_to_destroy_;
 
-  // Set of SurfaceSequences that have been satisfied by a frame but not yet
-  // waited on.
-  base::flat_set<SurfaceSequence> satisfied_sequences_;
-
   // Set of valid FrameSinkIds and their labels. When a FrameSinkId is removed
   // from this set, any remaining (surface) sequences with that FrameSinkId are
   // considered satisfied.
@@ -320,10 +287,6 @@
   // for a SurfaceId.
   const base::flat_set<SurfaceId> empty_surface_id_set_;
 
-  // The DirectSurfaceReferenceFactory that uses this manager to create surface
-  // references.
-  scoped_refptr<SurfaceReferenceFactory> reference_factory_;
-
   // Keeps track of surface references for a surface. The graph of references is
   // stored in both directions, so we know the parents and children for each
   // surface.
diff --git a/components/viz/service/surfaces/surface_unittest.cc b/components/viz/service/surfaces/surface_unittest.cc
index 1745dd6..c80ea0f6 100644
--- a/components/viz/service/surfaces/surface_unittest.cc
+++ b/components/viz/service/surfaces/surface_unittest.cc
@@ -86,25 +86,6 @@
   }
 }
 
-TEST(SurfaceTest, SurfaceLifetime) {
-  FrameSinkManagerImpl frame_sink_manager(
-      SurfaceManager::LifetimeType::SEQUENCES);
-  SurfaceManager* surface_manager = frame_sink_manager.surface_manager();
-  auto support = std::make_unique<CompositorFrameSinkSupport>(
-      nullptr, &frame_sink_manager, kArbitraryFrameSinkId, kIsRoot,
-      kNeedsSyncPoints);
-
-  LocalSurfaceId local_surface_id(6, base::UnguessableToken::Create());
-  SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
-  support->SubmitCompositorFrame(local_surface_id,
-                                 MakeDefaultCompositorFrame());
-  EXPECT_TRUE(surface_manager->GetSurfaceForId(surface_id));
-  support->EvictCurrentSurface();
-  frame_sink_manager.surface_manager()->GarbageCollectSurfaces();
-
-  EXPECT_EQ(nullptr, surface_manager->GetSurfaceForId(surface_id));
-}
-
 TEST(SurfaceTest, SurfaceIds) {
   for (size_t i = 0; i < 3; ++i) {
     ParentLocalSurfaceIdAllocator allocator;
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 8933f624..fc197cd5 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -162,7 +162,7 @@
   std::move(callback).Run(mojo::ConvertTo<ServiceWorkerStatusCode>(status));
 }
 
-void DidStartWorker(
+void DidStartWorkerForSyncEvent(
     base::OnceCallback<void(ServiceWorkerVersion::StatusCallback)> task,
     ServiceWorkerVersion::StatusCallback callback,
     ServiceWorkerStatusCode start_worker_status) {
@@ -775,7 +775,7 @@
   if (active_version->running_status() != EmbeddedWorkerStatus::RUNNING) {
     active_version->RunAfterStartWorker(
         ServiceWorkerMetrics::EventType::SYNC,
-        base::BindOnce(&DidStartWorker,
+        base::BindOnce(&DidStartWorkerForSyncEvent,
                        base::BindOnce(&BackgroundSyncManager::DispatchSyncEvent,
                                       weak_ptr_factory_.GetWeakPtr(), tag,
                                       std::move(active_version), last_chance),
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 9b1fbc4d..e65679a 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -147,6 +147,7 @@
 #endif
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
+#include "content/public/common/common_sandbox_support_linux.h"
 #include "content/public/common/zygote_handle.h"
 #include "media/base/media_switches.h"
 #endif
@@ -284,7 +285,15 @@
                              kForwardSwitches, arraysize(kForwardSwitches));
 
   GetContentClient()->browser()->AppendExtraCommandLineSwitches(cmd_line, -1);
-  return ZygoteHostImpl::GetInstance()->LaunchZygote(cmd_line, control_fd);
+
+  // Start up the sandbox host process and get the file descriptor for the
+  // sandboxed processes to talk to it.
+  base::FileHandleMappingVector additional_remapped_fds;
+  additional_remapped_fds.emplace_back(
+      SandboxHostLinux::GetInstance()->GetChildSocket(), GetSandboxFD());
+
+  return ZygoteHostImpl::GetInstance()->LaunchZygote(
+      cmd_line, control_fd, std::move(additional_remapped_fds));
 }
 
 void SetupSandbox(const base::CommandLine& parsed_command_line) {
@@ -1553,7 +1562,6 @@
       ImageTransportFactory::SetFactory(std::move(transport_factory));
     } else {
       frame_sink_manager_impl_ = std::make_unique<viz::FrameSinkManagerImpl>(
-          viz::SurfaceManager::LifetimeType::REFERENCES,
           switches::GetDeadlineToSynchronizeSurfaces());
 
       surface_utils::ConnectWithLocalFrameSinkManager(
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index c83e5ba..af60603 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -18,12 +18,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/surfaces/surface.h"
 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/compositor/surface_utils.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/frame_host/render_frame_proxy_host.h"
 #include "content/browser/frame_host/render_widget_host_view_guest.h"
@@ -312,8 +310,6 @@
     IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
     IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateResizeParams,
                         OnUpdateResizeParams)
-    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SatisfySequence, OnSatisfySequence)
-    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_RequireSequence, OnRequireSequence)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -433,29 +429,15 @@
 }
 
 void BrowserPluginGuest::SetChildFrameSurface(
-    const viz::SurfaceInfo& surface_info,
-    const viz::SurfaceSequence& sequence) {
+    const viz::SurfaceInfo& surface_info) {
   has_attached_since_surface_set_ = false;
   if (!switches::IsMusHostingViz()) {
     SendMessageToEmbedder(
         std::make_unique<BrowserPluginMsg_SetChildFrameSurface>(
-            browser_plugin_instance_id(), surface_info, sequence));
+            browser_plugin_instance_id(), surface_info));
   }
 }
 
-void BrowserPluginGuest::OnSatisfySequence(
-    int instance_id,
-    const viz::SurfaceSequence& sequence) {
-  GetFrameSinkManager()->surface_manager()->SatisfySequence(sequence);
-}
-
-void BrowserPluginGuest::OnRequireSequence(
-    int instance_id,
-    const viz::SurfaceId& id,
-    const viz::SurfaceSequence& sequence) {
-  GetFrameSinkManager()->surface_manager()->RequireSequence(id, sequence);
-}
-
 void BrowserPluginGuest::ResendEventToEmbedder(
     const blink::WebInputEvent& event) {
   if (!attached() || !owner_web_contents_)
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h
index f47d039..91dd79f 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -59,9 +59,7 @@
 
 namespace viz {
 class LocalSurfaceId;
-class SurfaceId;
 class SurfaceInfo;
-struct SurfaceSequence;
 }  // namespace viz
 
 namespace content {
@@ -260,8 +258,7 @@
   void PointerLockPermissionResponse(bool allow);
 
   // The next function is virtual for test purposes.
-  virtual void SetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                                    const viz::SurfaceSequence& sequence);
+  virtual void SetChildFrameSurface(const viz::SurfaceInfo& surface_info);
 
   void ResendEventToEmbedder(const blink::WebInputEvent& event);
 
@@ -300,10 +297,6 @@
   void InitInternal(const BrowserPluginHostMsg_Attach_Params& params,
                     WebContentsImpl* owner_web_contents);
 
-  void OnSatisfySequence(int instance_id, const viz::SurfaceSequence& sequence);
-  void OnRequireSequence(int instance_id,
-                         const viz::SurfaceId& id,
-                         const viz::SurfaceSequence& sequence);
   // Message handlers for messages from embedder.
   void OnDetach(int instance_id);
   // Handles drag events from the embedder.
diff --git a/content/browser/browsing_data/browsing_data_remover_impl.cc b/content/browser/browsing_data/browsing_data_remover_impl.cc
index b2bca5a..1c64aa5 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl.cc
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
@@ -288,7 +289,7 @@
   // 3. Do not support partial deletion, i.e. only delete your data if
   //    |filter_builder.IsEmptyBlacklist()|. Add a comment explaining why this
   //    is acceptable.
-  base::OnceClosure synchronous_clear_operations(
+  base::ScopedClosureRunner synchronous_clear_operations(
       CreatePendingTaskCompletionClosure());
 
   // crbug.com/140910: Many places were calling this with base::Time() as
@@ -485,9 +486,6 @@
         delete_begin_, delete_end_, remove_mask, filter_builder,
         origin_type_mask, CreatePendingTaskCompletionClosure());
   }
-
-  // Notify in case all actions taken were synchronous.
-  std::move(synchronous_clear_operations).Run();
 }
 
 void BrowsingDataRemoverImpl::AddObserver(Observer* observer) {
@@ -604,7 +602,7 @@
 BrowsingDataRemoverImpl::CreatePendingTaskCompletionClosure() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   num_pending_tasks_++;
-  return base::Bind(&BrowsingDataRemoverImpl::OnTaskComplete, GetWeakPtr());
+  return base::BindOnce(&BrowsingDataRemoverImpl::OnTaskComplete, GetWeakPtr());
 }
 
 base::WeakPtr<BrowsingDataRemoverImpl> BrowsingDataRemoverImpl::GetWeakPtr() {
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc
index 26e705e..0e77070 100644
--- a/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -53,8 +53,6 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_SetIsInert, OnSetIsInert)
     IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateRenderThrottlingStatus,
                         OnUpdateRenderThrottlingStatus)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_SatisfySequence, OnSatisfySequence)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_RequireSequence, OnRequireSequence)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -107,21 +105,9 @@
 }
 
 void CrossProcessFrameConnector::SetChildFrameSurface(
-    const viz::SurfaceInfo& surface_info,
-    const viz::SurfaceSequence& sequence) {
+    const viz::SurfaceInfo& surface_info) {
   frame_proxy_in_parent_renderer_->Send(new FrameMsg_SetChildFrameSurface(
-      frame_proxy_in_parent_renderer_->GetRoutingID(), surface_info, sequence));
-}
-
-void CrossProcessFrameConnector::OnSatisfySequence(
-    const viz::SurfaceSequence& sequence) {
-  GetFrameSinkManager()->surface_manager()->SatisfySequence(sequence);
-}
-
-void CrossProcessFrameConnector::OnRequireSequence(
-    const viz::SurfaceId& id,
-    const viz::SurfaceSequence& sequence) {
-  GetFrameSinkManager()->surface_manager()->RequireSequence(id, sequence);
+      frame_proxy_in_parent_renderer_->GetRoutingID(), surface_info));
 }
 
 void CrossProcessFrameConnector::UpdateCursor(const WebCursor& cursor) {
diff --git a/content/browser/frame_host/cross_process_frame_connector.h b/content/browser/frame_host/cross_process_frame_connector.h
index 9add9fc..b6108dd 100644
--- a/content/browser/frame_host/cross_process_frame_connector.h
+++ b/content/browser/frame_host/cross_process_frame_connector.h
@@ -76,8 +76,7 @@
   RenderWidgetHostViewBase* GetParentRenderWidgetHostView() override;
   RenderWidgetHostViewBase* GetRootRenderWidgetHostView() override;
   void RenderProcessGone() override;
-  void SetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                            const viz::SurfaceSequence& sequence) override;
+  void SetChildFrameSurface(const viz::SurfaceInfo& surface_info) override;
   void UpdateCursor(const WebCursor& cursor) override;
   gfx::PointF TransformPointToRootCoordSpace(
       const gfx::PointF& point,
@@ -137,9 +136,6 @@
   void OnSetIsInert(bool);
   void OnUpdateRenderThrottlingStatus(bool is_throttled,
                                       bool subtree_throttled);
-  void OnSatisfySequence(const viz::SurfaceSequence& sequence);
-  void OnRequireSequence(const viz::SurfaceId& id,
-                         const viz::SurfaceSequence& sequence);
 
   // The RenderFrameProxyHost that routes messages to the parent frame's
   // renderer process.
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
index 65d872e..f7c61cb 100644
--- a/content/browser/frame_host/frame_tree_node.cc
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -465,6 +465,13 @@
   return did_change_flags || did_change_container_policy;
 }
 
+void FrameTreeNode::TransferNavigationRequestOwnership(
+    RenderFrameHostImpl* render_frame_host) {
+  RenderFrameDevToolsAgentHost::OnResetNavigationRequest(
+      navigation_request_.get());
+  render_frame_host->SetNavigationRequest(std::move(navigation_request_));
+}
+
 void FrameTreeNode::CreatedNavigationRequest(
     std::unique_ptr<NavigationRequest> navigation_request) {
   CHECK(IsBrowserSideNavigationEnabled());
diff --git a/content/browser/frame_host/frame_tree_node.h b/content/browser/frame_host/frame_tree_node.h
index 4a2f5b8..e71b0b6 100644
--- a/content/browser/frame_host/frame_tree_node.h
+++ b/content/browser/frame_host/frame_tree_node.h
@@ -286,6 +286,12 @@
 
   NavigationRequest* navigation_request() { return navigation_request_.get(); }
 
+  // Transfers the ownership of the NavigationRequest to |render_frame_host|.
+  // From ReadyToCommit to DidCommit, the NavigationRequest is owned by the
+  // RenderFrameHost that is committing the navigation.
+  void TransferNavigationRequestOwnership(
+      RenderFrameHostImpl* render_frame_host);
+
   // PlzNavigate
   // Takes ownership of |navigation_request| and makes it the current
   // NavigationRequest of this frame. This corresponds to the start of a new
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index f820882..a925693a 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -7181,7 +7181,7 @@
   FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
                             ->GetFrameTree()
                             ->root();
-  EXPECT_FALSE(main_frame->navigation_handle());
+  EXPECT_FALSE(main_frame->GetNavigationHandle());
   EXPECT_FALSE(root->navigation_request());
 
   // Start navigating to the second page.
@@ -7193,7 +7193,7 @@
   EXPECT_TRUE(manager.WaitForRequestStart());
 
   // This should create a NavigationHandle.
-  NavigationHandleImpl* handle = main_frame->navigation_handle();
+  NavigationHandleImpl* handle = main_frame->GetNavigationHandle();
   NavigationRequest* request = root->navigation_request();
   if (IsBrowserSideNavigationEnabled()) {
     EXPECT_TRUE(request);
@@ -7221,8 +7221,8 @@
     EXPECT_TRUE(root->navigation_request());
     EXPECT_EQ(request, root->navigation_request());
   } else {
-    EXPECT_TRUE(main_frame->navigation_handle());
-    EXPECT_EQ(handle, main_frame->navigation_handle());
+    EXPECT_TRUE(main_frame->GetNavigationHandle());
+    EXPECT_EQ(handle, main_frame->GetNavigationHandle());
   }
 
   // Let the navigation finish. It should commit successfully.
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index ac20cab5b..f5e34d5b 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -578,9 +578,9 @@
   }
 }
 
-void NavigationRequest::TransferNavigationHandleOwnership(
-    RenderFrameHostImpl* render_frame_host) {
-  render_frame_host->SetNavigationHandle(std::move(navigation_handle_));
+std::unique_ptr<NavigationHandleImpl>
+NavigationRequest::TakeNavigationHandle() {
+  return std::move(navigation_handle_);
 }
 
 void NavigationRequest::OnRequestRedirected(
@@ -1240,9 +1240,8 @@
 void NavigationRequest::CommitErrorPage(
     RenderFrameHostImpl* render_frame_host,
     const base::Optional<std::string>& error_page_content) {
-  TransferNavigationHandleOwnership(render_frame_host);
-  render_frame_host->navigation_handle()->ReadyToCommitNavigation(
-      render_frame_host);
+  frame_tree_node_->TransferNavigationRequestOwnership(render_frame_host);
+  navigation_handle_->ReadyToCommitNavigation(render_frame_host);
   render_frame_host->FailedNavigation(common_params_, request_params_,
                                       has_stale_copy_in_cache_, net_error_,
                                       error_page_content);
@@ -1261,14 +1260,11 @@
          render_frame_host ==
              frame_tree_node_->render_manager()->speculative_frame_host());
 
-  TransferNavigationHandleOwnership(render_frame_host);
-
+  frame_tree_node_->TransferNavigationRequestOwnership(render_frame_host);
   render_frame_host->CommitNavigation(
       response_.get(), std::move(url_loader_client_endpoints_),
       std::move(body_), common_params_, request_params_, is_view_source_,
       std::move(subresource_loader_params_), devtools_navigation_token_);
-
-  frame_tree_node_->ResetNavigationRequest(true, true);
 }
 
 NavigationRequest::ContentSecurityPolicyCheckResult
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index f0a832b..925a71b8 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -171,13 +171,8 @@
   // NavigationRequest for the FrameTreeNode has been destroyed.
   void CreateNavigationHandle();
 
-  // Transfers the ownership of the NavigationHandle to |render_frame_host|.
-  // This should be called when the navigation is ready to commit, because the
-  // NavigationHandle outlives the NavigationRequest. The NavigationHandle's
-  // lifetime is the entire navigation, while the NavigationRequest is
-  // destroyed when a navigation is ready for commit.
-  void TransferNavigationHandleOwnership(
-      RenderFrameHostImpl* render_frame_host);
+  // Returns ownership of the navigation handle.
+  std::unique_ptr<NavigationHandleImpl> TakeNavigationHandle();
 
   void set_on_start_checks_complete_closure_for_testing(
       const base::Closure& closure) {
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index e327ed6..fe17841c 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -190,7 +190,7 @@
   if (is_main_frame && !is_error_page) {
     DidStartMainFrameNavigation(validated_url,
                                 render_frame_host->GetSiteInstance(),
-                                render_frame_host->navigation_handle());
+                                render_frame_host->GetNavigationHandle());
   }
 }
 
@@ -238,8 +238,8 @@
 
   // Discard the pending navigation entry if needed.
   int expected_pending_entry_id =
-      render_frame_host->navigation_handle()
-          ? render_frame_host->navigation_handle()->pending_nav_entry_id()
+      render_frame_host->GetNavigationHandle()
+          ? render_frame_host->GetNavigationHandle()->pending_nav_entry_id()
           : 0;
   DiscardPendingEntryIfNeeded(expected_pending_entry_id);
 }
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index fc3412c..c6ef1f6b 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -578,9 +578,9 @@
 }
 
 RenderFrameHostImpl::~RenderFrameHostImpl() {
-  // Destroying navigation handle may call into delegates/observers,
+  // Destroying |navigation_request_| may call into delegates/observers,
   // so we do it early while |this| object is still in a sane state.
-  navigation_handle_.reset();
+  navigation_request_.reset();
 
   // Release the WebUI instances before all else as the WebUI may accesses the
   // RenderFrameHost during cleanup.
@@ -1061,8 +1061,8 @@
   DCHECK_EQ(site_instance_.get(), site_instance);
 
   // The renderer process is gone, so this frame can no longer be loading.
-  if (navigation_handle_)
-    navigation_handle_->set_net_error_code(net::ERR_ABORTED);
+  if (GetNavigationHandle())
+    GetNavigationHandle()->set_net_error_code(net::ERR_ABORTED);
   ResetLoadingState();
 
   // The renderer process is gone, so the |stream_handle_| will no longer be
@@ -1496,8 +1496,8 @@
   // happening in practice. See https://crbug.com/605289.
 
   // Update the error code in the NavigationHandle of the navigation.
-  if (navigation_handle_) {
-    navigation_handle_->set_net_error_code(
+  if (GetNavigationHandle()) {
+    GetNavigationHandle()->set_net_error_code(
         static_cast<net::Error>(params.error_code));
   }
 
@@ -1678,7 +1678,7 @@
     return;
   }
 
-  if (!navigation_handle_) {
+  if (!navigation_request_) {
     // The browser has not been notified about the start of the load in this
     // renderer yet (e.g., for same-document navigations that start in the
     // renderer). Do it now.
@@ -1759,9 +1759,14 @@
   return GlobalFrameRoutingId(GetProcess()->GetID(), GetRoutingID());
 }
 
-void RenderFrameHostImpl::SetNavigationHandle(
-    std::unique_ptr<NavigationHandleImpl> navigation_handle) {
-  navigation_handle_ = std::move(navigation_handle);
+NavigationHandleImpl* RenderFrameHostImpl::GetNavigationHandle() {
+  return navigation_request() ? navigation_request()->navigation_handle()
+                              : nullptr;
+}
+
+void RenderFrameHostImpl::SetNavigationRequest(
+    std::unique_ptr<NavigationRequest> navigation_request) {
+  navigation_request_ = std::move(navigation_request);
 }
 
 void RenderFrameHostImpl::SwapOut(
@@ -2734,7 +2739,7 @@
   }
 
   is_loading_ = false;
-  navigation_handle_.reset();
+  navigation_request_.reset();
 
   // Only inform the FrameTreeNode of a change in load state if the load state
   // of this RenderFrameHost is being tracked.
@@ -3679,9 +3684,8 @@
 
   // An error page is expected to commit, hence why is_loading_ is set to true.
   is_loading_ = true;
-  if (navigation_handle_)
-    DCHECK_NE(net::OK, navigation_handle_->GetNetErrorCode());
-  frame_tree_node_->ResetNavigationRequest(true, true);
+  DCHECK(GetNavigationHandle() &&
+         GetNavigationHandle()->GetNetErrorCode() != net::OK);
 }
 
 void RenderFrameHostImpl::SetUpMojoIfNeeded() {
@@ -4368,14 +4372,19 @@
     const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
   bool is_browser_initiated = (params.nav_entry_id != 0);
 
+  NavigationHandleImpl* navigation_handle = GetNavigationHandle();
+
   if (params.was_within_same_document) {
     // A NavigationHandle is created for browser-initiated same-document
     // navigation. Try to take it if it's still available and matches the
     // current navigation.
-    if (is_browser_initiated && navigation_handle_ &&
-        navigation_handle_->IsSameDocument() &&
-        navigation_handle_->GetURL() == params.url) {
-      return std::move(navigation_handle_);
+    if (is_browser_initiated && navigation_handle &&
+        navigation_handle->IsSameDocument() &&
+        navigation_handle->GetURL() == params.url) {
+      std::unique_ptr<NavigationHandleImpl> result_navigation_handle =
+          navigation_request()->TakeNavigationHandle();
+      navigation_request_.reset();
+      return result_navigation_handle;
     }
 
     // No existing NavigationHandle has been found. Create a new one, but don't
@@ -4406,8 +4415,11 @@
   }
 
   // Determine if the current NavigationHandle can be used.
-  if (navigation_handle_ && navigation_handle_->GetURL() == params.url) {
-    return std::move(navigation_handle_);
+  if (navigation_handle && navigation_handle->GetURL() == params.url) {
+    std::unique_ptr<NavigationHandleImpl> result_navigation_handle =
+        navigation_request()->TakeNavigationHandle();
+    navigation_request_.reset();
+    return result_navigation_handle;
   }
 
   // If the URL does not match what the NavigationHandle expects, treat the
@@ -4426,26 +4438,22 @@
   // and that it matches this handle.  TODO(csharrison): The pending entry's
   // base url should equal |params.base_url|. This is not the case for loads
   // with invalid base urls.
-  if (navigation_handle_) {
+  if (navigation_handle) {
     NavigationEntryImpl* pending_entry =
         NavigationEntryImpl::FromNavigationEntry(
             frame_tree_node()->navigator()->GetController()->GetPendingEntry());
     bool pending_entry_matches_handle =
-        pending_entry &&
-        pending_entry->GetUniqueID() ==
-            navigation_handle_->pending_nav_entry_id();
+        pending_entry && pending_entry->GetUniqueID() ==
+                             navigation_handle->pending_nav_entry_id();
     // TODO(csharrison): The pending entry's base url should equal
     // |validated_params.base_url|. This is not the case for loads with invalid
     // base urls.
-    if (navigation_handle_->GetURL() == params.base_url &&
+    if (navigation_handle->GetURL() == params.base_url &&
         pending_entry_matches_handle &&
         !pending_entry->GetBaseURLForDataURL().is_empty()) {
-      entry_id_for_data_nav = navigation_handle_->pending_nav_entry_id();
+      entry_id_for_data_nav = navigation_handle->pending_nav_entry_id();
       is_renderer_initiated = pending_entry->is_renderer_initiated();
     }
-
-    // Reset any existing NavigationHandle.
-    navigation_handle_.reset();
   }
 
   // There is no pending NavigationEntry in these cases, so pass 0 as the
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index fee62ff..c994d60 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -118,6 +118,7 @@
 class KeepAliveHandleFactory;
 class MediaInterfaceProxy;
 class NavigationHandleImpl;
+class NavigationRequest;
 class PermissionServiceContext;
 class PresentationServiceImpl;
 class RenderFrameHostDelegate;
@@ -377,18 +378,19 @@
   int nav_entry_id() const { return nav_entry_id_; }
   void set_nav_entry_id(int nav_entry_id) { nav_entry_id_ = nav_entry_id; }
 
-  // A NavigationHandle for the pending navigation in this frame, if any. This
+  // A NavigationRequest for the pending navigation in this frame, if any. This
   // is cleared when the navigation commits.
-  NavigationHandleImpl* navigation_handle() const {
-    return navigation_handle_.get();
-  }
+  NavigationRequest* navigation_request() { return navigation_request_.get(); }
 
-  // Called when a new navigation starts in this RenderFrameHost. Ownership of
-  // |navigation_handle| is transferred.
-  // PlzNavigate: called when a navigation is ready to commit in this
-  // RenderFrameHost.
-  void SetNavigationHandle(
-      std::unique_ptr<NavigationHandleImpl> navigation_handle);
+  // Returns the NavigationHandleImpl stored in the NavigationRequest returned
+  // by GetNavigationRequest(), if any.
+  NavigationHandleImpl* GetNavigationHandle();
+
+  // Called when a navigation is ready to commit in this
+  // RenderFrameHost. Transfers ownership of the NavigationRequest associated
+  // with the navigation to this RenderFrameHost.
+  void SetNavigationRequest(
+      std::unique_ptr<NavigationRequest> navigation_request);
 
   // Tells the renderer that this RenderFrame is being swapped out for one in a
   // different renderer process.  It should run its unload handler and move to
@@ -1231,12 +1233,9 @@
   std::unique_ptr<resource_coordinator::FrameResourceCoordinator>
       frame_resource_coordinator_;
 
-  // Tracks a navigation happening in this frame. Note that while there can be
-  // two navigations in the same FrameTreeNode, there can only be one
-  // navigation per RenderFrameHost.
-  // Before the navigation is ready to be committed, the NavigationHandle for it
-  // is owned by the NavigationRequest.
-  std::unique_ptr<NavigationHandleImpl> navigation_handle_;
+  // Holds a NavigationRequest while waiting for the navigation it is tracking
+  // to commit.
+  std::unique_ptr<NavigationRequest> navigation_request_;
 
   // The associated WebUIImpl and its type. They will be set if the current
   // document is from WebUI source. Otherwise they will be null and
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 2a054e4..0faad5d 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -372,9 +372,9 @@
       CreateRenderFrameProxyHost(old_render_frame_host->GetSiteInstance(),
                                  old_render_frame_host->render_view_host());
 
-  // Reset any NavigationHandle in the RenderFrameHost. This will prevent any
-  // ongoing navigation from attempting to transfer.
-  old_render_frame_host->SetNavigationHandle(nullptr);
+  // Reset any NavigationRequest in the RenderFrameHost. A swapped out
+  // RenderFrameHost should not be trying to commit a navigation.
+  old_render_frame_host->SetNavigationRequest(nullptr);
 
   // Tell the old RenderFrameHost to swap out and be replaced by the proxy.
   old_render_frame_host->SwapOut(proxy, true);
@@ -505,10 +505,10 @@
       // navigation was started from BeginNavigation. If the navigation was
       // started through the NavigationController, the NavigationController has
       // already updated its state properly, and doesn't need to be notified.
-      if (speculative_render_frame_host_->navigation_handle() &&
+      if (speculative_render_frame_host_->GetNavigationHandle() &&
           request.from_begin_navigation()) {
         frame_tree_node_->navigator()->DiscardPendingEntryIfNeeded(
-            speculative_render_frame_host_->navigation_handle()
+            speculative_render_frame_host_->GetNavigationHandle()
                 ->pending_nav_entry_id());
       }
       DiscardUnusedFrame(UnsetSpeculativeRenderFrameHost());
@@ -544,10 +544,10 @@
       // has already updated its state properly, and doesn't need to be
       // notified.
       if (speculative_render_frame_host_ &&
-          speculative_render_frame_host_->navigation_handle() &&
+          speculative_render_frame_host_->GetNavigationHandle() &&
           request.from_begin_navigation()) {
         frame_tree_node_->navigator()->DiscardPendingEntryIfNeeded(
-            speculative_render_frame_host_->navigation_handle()
+            speculative_render_frame_host_->GetNavigationHandle()
                 ->pending_nav_entry_id());
       }
 
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc
index d637a49..a8a9262 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -12,7 +12,6 @@
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "build/build_config.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/surfaces/surface.h"
 #include "components/viz/service/surfaces/surface_hittest.h"
@@ -369,10 +368,9 @@
 }
 
 void RenderWidgetHostViewGuest::SendSurfaceInfoToEmbedderImpl(
-    const viz::SurfaceInfo& surface_info,
-    const viz::SurfaceSequence& sequence) {
+    const viz::SurfaceInfo& surface_info) {
   if (guest_ && !guest_->is_in_destruction())
-    guest_->SetChildFrameSurface(surface_info, sequence);
+    guest_->SetChildFrameSurface(surface_info);
 }
 
 void RenderWidgetHostViewGuest::SubmitCompositorFrame(
diff --git a/content/browser/frame_host/render_widget_host_view_guest.h b/content/browser/frame_host/render_widget_host_view_guest.h
index d07b130..3d095bf 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.h
+++ b/content/browser/frame_host/render_widget_host_view_guest.h
@@ -158,8 +158,7 @@
   friend class RenderWidgetHostView;
 
   void SendSurfaceInfoToEmbedderImpl(
-      const viz::SurfaceInfo& surface_info,
-      const viz::SurfaceSequence& sequence) override;
+      const viz::SurfaceInfo& surface_info) override;
 
   RenderWidgetHostViewGuest(
       RenderWidgetHost* widget,
diff --git a/content/browser/frame_host/render_widget_host_view_guest_unittest.cc b/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
index 02f0ff67..768cdfb 100644
--- a/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/surfaces/surface.h"
 #include "components/viz/service/surfaces/surface_manager.h"
@@ -124,8 +123,7 @@
     BrowserPluginGuest::set_attached_for_test(attached);
   }
 
-  void SetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                            const viz::SurfaceSequence& sequence) override {
+  void SetChildFrameSurface(const viz::SurfaceInfo& surface_info) override {
     last_surface_info_ = surface_info;
   }
 
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index ecab3580..a388a96 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -190,7 +190,13 @@
 };
 
 // Verifies that in-process network service works.
-IN_PROC_BROWSER_TEST_F(NetworkServiceInProcessBrowserTest, Basic) {
+// http://crbug.com/804204: failed on several dbg builders.
+#if !defined(NDEBUG)
+#define MAYBE_Basic DISABLED_Basic
+#else
+#define MAYBE_Basic Basic
+#endif
+IN_PROC_BROWSER_TEST_F(NetworkServiceInProcessBrowserTest, MAYBE_Basic) {
   GURL test_url = embedded_test_server()->GetURL("foo.com", "/echo");
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetDefaultStoragePartition(
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 3cdcc91..5adf3d1 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -40,7 +40,6 @@
 #include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/surfaces/frame_sink_id_allocator.h"
-#include "components/viz/common/switches.h"
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "components/viz/service/display/display.h"
 #include "components/viz/service/display/display_scheduler.h"
@@ -97,17 +96,9 @@
 
 struct CompositorDependencies {
   CompositorDependencies() : frame_sink_id_allocator(kDefaultClientId) {
-    // TODO(crbug.com/676384): Remove flag along with surface sequences.
-    auto surface_lifetime_type =
-        base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisableSurfaceReferences)
-            ? viz::SurfaceManager::LifetimeType::SEQUENCES
-            : viz::SurfaceManager::LifetimeType::REFERENCES;
-
     // TODO(danakj): Don't make a FrameSinkManagerImpl when display is in the
     // Gpu process, instead get the mojo pointer from the Gpu process.
-    frame_sink_manager_impl =
-        std::make_unique<viz::FrameSinkManagerImpl>(surface_lifetime_type);
+    frame_sink_manager_impl = std::make_unique<viz::FrameSinkManagerImpl>();
     surface_utils::ConnectWithLocalFrameSinkManager(
         &host_frame_sink_manager, frame_sink_manager_impl.get());
   }
@@ -632,7 +623,6 @@
   params.mutator_host = animation_host_.get();
   host_ = cc::LayerTreeHost::CreateSingleThreaded(this, &params);
   DCHECK(!host_->IsVisible());
-  host_->SetFrameSinkId(frame_sink_id_);
   host_->SetViewportSize(size_);
   host_->SetDeviceScaleFactor(1);
 
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index 653f3697..13e21d6 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -18,7 +18,6 @@
 #include "components/viz/common/gl_helper.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/resources/single_release_callback.h"
-#include "components/viz/common/surfaces/stub_surface_reference_factory.h"
 #include "components/viz/common/switches.h"
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
@@ -300,8 +299,7 @@
 
     viz::SurfaceId surface_id(frame_sink_id_, client_->GetLocalSurfaceId());
     client_->DelegatedFrameHostGetLayer()->SetShowPrimarySurface(
-        surface_id, current_frame_size_in_dip_, GetGutterColor(),
-        GetSurfaceReferenceFactory());
+        surface_id, current_frame_size_in_dip_, GetGutterColor());
     if (compositor_ && !base::CommandLine::ForCurrentProcess()->HasSwitch(
                            switches::kDisableResizeLock)) {
       compositor_->OnChildResizing();
@@ -572,8 +570,7 @@
     }
   } else {
     client_->DelegatedFrameHostGetLayer()->SetShowPrimarySurface(
-        surface_info.id(), frame_size_in_dip, GetGutterColor(),
-        GetSurfaceReferenceFactory());
+        surface_info.id(), frame_size_in_dip, GetGutterColor());
   }
 
   client_->DelegatedFrameHostGetLayer()->SetFallbackSurfaceId(
@@ -948,12 +945,4 @@
   support_.reset();
 }
 
-scoped_refptr<viz::SurfaceReferenceFactory>
-DelegatedFrameHost::GetSurfaceReferenceFactory() {
-  if (enable_viz_)
-    return base::MakeRefCounted<viz::StubSurfaceReferenceFactory>();
-
-  return GetFrameSinkManager()->surface_manager()->reference_factory();
-}
-
 }  // namespace content
diff --git a/content/browser/renderer_host/delegated_frame_host.h b/content/browser/renderer_host/delegated_frame_host.h
index dcaabf1..a79724c6 100644
--- a/content/browser/renderer_host/delegated_frame_host.h
+++ b/content/browser/renderer_host/delegated_frame_host.h
@@ -273,10 +273,6 @@
   void CreateCompositorFrameSinkSupport();
   void ResetCompositorFrameSinkSupport();
 
-  // Returns SurfaceReferenceFactory instance. If |enable_viz| is true then it
-  // will be a stub factory, otherwise it will be the real factory.
-  scoped_refptr<viz::SurfaceReferenceFactory> GetSurfaceReferenceFactory();
-
   const viz::FrameSinkId frame_sink_id_;
   viz::LocalSurfaceId local_surface_id_;
   DelegatedFrameHostClient* const client_;
diff --git a/content/browser/renderer_host/frame_connector_delegate.h b/content/browser/renderer_host/frame_connector_delegate.h
index 03562e8f..eeb8fa8 100644
--- a/content/browser/renderer_host/frame_connector_delegate.h
+++ b/content/browser/renderer_host/frame_connector_delegate.h
@@ -23,7 +23,6 @@
 namespace viz {
 class SurfaceId;
 class SurfaceInfo;
-struct SurfaceSequence;
 }  // namespace viz
 
 namespace content {
@@ -64,8 +63,7 @@
   // Provide the SurfaceInfo to the embedder, which becomes a reference to the
   // current view's Surface that is included in higher-level compositor
   // frames.
-  virtual void SetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                                    const viz::SurfaceSequence& sequence) {}
+  virtual void SetChildFrameSurface(const viz::SurfaceInfo& surface_info) {}
 
   // Return the rect in DIP that the RenderWidgetHostViewChildFrame's content
   // will render into.
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
index 3ec2fbb..3174275 100644
--- a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
+++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
@@ -10,7 +10,6 @@
 #include "base/memory/ptr_util.h"
 #include "components/viz/common/features.h"
 #include "components/viz/host/host_frame_sink_manager.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/surfaces/surface_manager.h"
 #include "content/browser/compositor/surface_utils.h"
 
@@ -77,29 +76,6 @@
   // canvas
 }
 
-void OffscreenCanvasSurfaceImpl::Require(const viz::SurfaceId& surface_id,
-                                         const viz::SurfaceSequence& sequence) {
-  // TODO(kylechar): This is a hacky workaround for https://crbug.com/796700
-  // to unblock video with surfaces work. Delete function M65 branch.
-  if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
-    return;
-
-  auto* surface_manager = GetFrameSinkManager()->surface_manager();
-  if (!surface_manager->using_surface_references())
-    surface_manager->RequireSequence(surface_id, sequence);
-}
-
-void OffscreenCanvasSurfaceImpl::Satisfy(const viz::SurfaceSequence& sequence) {
-  // TODO(kylechar): This is a hacky workaround for https://crbug.com/796700
-  // to unblock video with surfaces work. Delete function after M65 branch.
-  if (base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
-    return;
-
-  auto* surface_manager = GetFrameSinkManager()->surface_manager();
-  if (!surface_manager->using_surface_references())
-    surface_manager->SatisfySequence(sequence);
-}
-
 void OffscreenCanvasSurfaceImpl::OnSurfaceConnectionClosed() {
   std::move(destroy_callback_).Run();
 }
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.h b/content/browser/renderer_host/offscreen_canvas_surface_impl.h
index b906ed61..e64b95a 100644
--- a/content/browser/renderer_host/offscreen_canvas_surface_impl.h
+++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.h
@@ -56,11 +56,6 @@
   void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
   void OnFrameTokenChanged(uint32_t frame_token) override;
 
-  // blink::mojom::OffscreenCanvasSurface implementation.
-  void Require(const viz::SurfaceId& surface_id,
-               const viz::SurfaceSequence& sequence) override;
-  void Satisfy(const viz::SurfaceSequence& sequence) override;
-
  private:
   // Registered as a callback for when |binding_| is closed. Will call
   // |destroy_callback_|.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 22c72f3..5af75c5 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2648,7 +2648,6 @@
     cc::switches::kBrowserControlsHideThreshold,
     cc::switches::kBrowserControlsShowThreshold,
     cc::switches::kRunAllCompositorStagesBeforeDraw,
-    switches::kDisableSurfaceReferences,
     switches::kEnableSurfaceSynchronization,
 
 #if BUILDFLAG(ENABLE_PLUGINS)
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 9a8a5ec..a8a8e31 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -494,9 +494,8 @@
   if (using_browser_compositor_) {
     viz::FrameSinkId frame_sink_id =
         host_->AllocateFrameSinkId(false /* is_guest_view_hack */);
-    delegated_frame_host_.reset(new ui::DelegatedFrameHostAndroid(
-        &view_, CompositorImpl::GetHostFrameSinkManager(),
-        CompositorImpl::GetFrameSinkManager(), this, frame_sink_id));
+    delegated_frame_host_ = std::make_unique<ui::DelegatedFrameHostAndroid>(
+        &view_, CompositorImpl::GetHostFrameSinkManager(), this, frame_sink_id);
 
     // Let the page-level input event router know about our frame sink ID
     // for surface-based hit testing.
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index efab4c1..ad65cd9 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -19,7 +19,6 @@
 #include "components/viz/common/frame_sinks/copy_output_result.h"
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/surfaces/surface.h"
 #include "components/viz/service/surfaces/surface_manager.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
@@ -69,7 +68,6 @@
       frame_sink_id_(
           base::checked_cast<uint32_t>(widget_host->GetProcess()->GetID()),
           base::checked_cast<uint32_t>(widget_host->GetRoutingID())),
-      next_surface_sequence_(1u),
       current_surface_scale_factor_(1.f),
       frame_connector_(nullptr),
       enable_viz_(
@@ -586,26 +584,16 @@
 void RenderWidgetHostViewChildFrame::SendSurfaceInfoToEmbedder() {
   if (switches::IsMusHostingViz())
     return;
-  // TODO(kylechar): Remove sequence generation and only send surface info.
-  // See https://crbug.com/676384.
-  viz::SurfaceSequence sequence =
-      viz::SurfaceSequence(frame_sink_id_, next_surface_sequence_++);
-  viz::SurfaceManager* manager = GetFrameSinkManager()->surface_manager();
   viz::SurfaceId surface_id(frame_sink_id_, last_received_local_surface_id_);
-  // The renderer process will satisfy this dependency when it creates a
-  // SurfaceLayer.
-  if (!manager->using_surface_references())
-    manager->RequireSequence(surface_id, sequence);
   viz::SurfaceInfo surface_info(surface_id, current_surface_scale_factor_,
                                 current_surface_size_);
-  SendSurfaceInfoToEmbedderImpl(surface_info, sequence);
+  SendSurfaceInfoToEmbedderImpl(surface_info);
 }
 
 void RenderWidgetHostViewChildFrame::SendSurfaceInfoToEmbedderImpl(
-    const viz::SurfaceInfo& surface_info,
-    const viz::SurfaceSequence& sequence) {
+    const viz::SurfaceInfo& surface_info) {
   if (frame_connector_)
-    frame_connector_->SetChildFrameSurface(surface_info, sequence);
+    frame_connector_->SetChildFrameSurface(surface_info);
 }
 
 void RenderWidgetHostViewChildFrame::SubmitCompositorFrame(
@@ -906,8 +894,7 @@
 
 void RenderWidgetHostViewChildFrame::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
-  viz::SurfaceSequence sequence(frame_sink_id_, next_surface_sequence_++);
-  SendSurfaceInfoToEmbedderImpl(surface_info, sequence);
+  SendSurfaceInfoToEmbedderImpl(surface_info);
 }
 
 void RenderWidgetHostViewChildFrame::OnFrameTokenChanged(uint32_t frame_token) {
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h
index 98bd278..2ca8542 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -19,7 +19,6 @@
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/resources/returned_resource.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "components/viz/host/host_frame_sink_client.h"
 #include "content/browser/compositor/image_transport_factory.h"
 #include "content/browser/renderer_host/event_with_latency_info.h"
@@ -268,7 +267,6 @@
   // Surface-related state.
   std::unique_ptr<viz::CompositorFrameSinkSupport> support_;
   viz::LocalSurfaceId last_received_local_surface_id_;
-  uint32_t next_surface_sequence_;
   gfx::Size current_surface_size_;
   float current_surface_scale_factor_;
   gfx::Rect last_screen_rect_;
@@ -289,8 +287,7 @@
       HiddenOOPIFWillNotGenerateCompositorFramesAfterNavigation);
 
   virtual void SendSurfaceInfoToEmbedderImpl(
-      const viz::SurfaceInfo& surface_info,
-      const viz::SurfaceSequence& sequence);
+      const viz::SurfaceInfo& surface_info);
 
   void SubmitSurfaceCopyRequest(const gfx::Rect& src_subrect,
                                 const gfx::Size& dst_size,
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
index 802e4a6..865e049 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
@@ -5,7 +5,6 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "components/viz/common/surfaces/surface_id.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/mus_util.h"
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
@@ -188,94 +187,4 @@
                           base::Unretained(this)));
 }
 
-// A class to filter RequireSequence and SatisfySequence messages sent from
-// an embedding renderer for its child's Surfaces.
-class SurfaceRefMessageFilter : public BrowserMessageFilter {
- public:
-  SurfaceRefMessageFilter()
-      : BrowserMessageFilter(FrameMsgStart),
-        require_message_loop_runner_(new content::MessageLoopRunner),
-        satisfy_message_loop_runner_(new content::MessageLoopRunner),
-        satisfy_received_(false),
-        require_received_first_(false) {}
-
-  void WaitForRequire() { require_message_loop_runner_->Run(); }
-
-  void WaitForSatisfy() { satisfy_message_loop_runner_->Run(); }
-
-  bool require_received_first() { return require_received_first_; }
-
- protected:
-  ~SurfaceRefMessageFilter() override {}
-
- private:
-  // BrowserMessageFilter:
-  bool OnMessageReceived(const IPC::Message& message) override {
-    IPC_BEGIN_MESSAGE_MAP(SurfaceRefMessageFilter, message)
-      IPC_MESSAGE_HANDLER(FrameHostMsg_RequireSequence, OnRequire)
-      IPC_MESSAGE_HANDLER(FrameHostMsg_SatisfySequence, OnSatisfy)
-    IPC_END_MESSAGE_MAP()
-    return false;
-  }
-
-  void OnRequire(const viz::SurfaceId& id,
-                 const viz::SurfaceSequence sequence) {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::BindOnce(&SurfaceRefMessageFilter::OnRequireOnUI, this));
-  }
-
-  void OnRequireOnUI() {
-    if (!satisfy_received_)
-      require_received_first_ = true;
-    require_message_loop_runner_->Quit();
-  }
-
-  void OnSatisfy(const viz::SurfaceSequence sequence) {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::BindOnce(&SurfaceRefMessageFilter::OnSatisfyOnUI, this));
-  }
-
-  void OnSatisfyOnUI() {
-    satisfy_received_ = true;
-    satisfy_message_loop_runner_->Quit();
-  }
-
-  scoped_refptr<content::MessageLoopRunner> require_message_loop_runner_;
-  scoped_refptr<content::MessageLoopRunner> satisfy_message_loop_runner_;
-  bool satisfy_received_;
-  bool require_received_first_;
-
-  DISALLOW_COPY_AND_ASSIGN(SurfaceRefMessageFilter);
-};
-
-// Test that when a child frame submits its first compositor frame, the
-// embedding renderer process properly acquires and releases references to the
-// new Surface. See https://crbug.com/701175.
-// TODO(crbug.com/676384): Delete test with the rest of SurfaceSequence code.
-IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameTest,
-                       DISABLED_ChildFrameSurfaceReference) {
-  EXPECT_TRUE(NavigateToURL(
-      shell(), embedded_test_server()->GetURL(
-                   "a.com", "/cross_site_iframe_factory.html?a(a)")));
-
-  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
-                            ->GetFrameTree()
-                            ->root();
-  ASSERT_EQ(1U, root->child_count());
-
-  scoped_refptr<SurfaceRefMessageFilter> filter = new SurfaceRefMessageFilter();
-  root->current_frame_host()->GetProcess()->AddFilter(filter.get());
-
-  GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title1.html");
-  NavigateFrameToURL(root->child_at(0), foo_url);
-
-  // If one of these messages isn't received, this test times out.
-  filter->WaitForRequire();
-  filter->WaitForSatisfy();
-
-  EXPECT_TRUE(filter->require_received_first());
-}
-
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
index 4a48803..fe813324 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_unittest.cc
@@ -16,7 +16,6 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/surfaces/surface.h"
@@ -55,8 +54,7 @@
       : FrameConnectorDelegate(use_zoom_for_device_scale_factor) {}
   ~MockFrameConnectorDelegate() override {}
 
-  void SetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                            const viz::SurfaceSequence& sequence) override {
+  void SetChildFrameSurface(const viz::SurfaceInfo& surface_info) override {
     last_surface_info_ = surface_info;
   }
 
diff --git a/content/browser/resources/media/peer_connection_update_table.js b/content/browser/resources/media/peer_connection_update_table.js
index d6795d5..208d11f 100644
--- a/content/browser/resources/media/peer_connection_update_table.js
+++ b/content/browser/resources/media/peer_connection_update_table.js
@@ -122,6 +122,14 @@
           update.type === 'addIceCandidateFailed') {
         valueContainer.parentElement.classList.add('update-log-failure');
       }
+      // Highlight legacy streams API usage.
+      if (update.type === 'addStream' || update.type === 'removeStream') {
+        valueContainer.parentElement.classList.add(
+            'update-log-legacy-api-usage');
+        valueContainer.parentElement.title = update.type + ' is no longer ' +
+            'part of the WebRTC API and may be removed in future versions. ' +
+            'Use the addTrack/removeTrack APIs instead.'
+      }
 
       var value = update.value;
       // map internal names and values to names and events from the
diff --git a/content/browser/resources/media/webrtc_internals.css b/content/browser/resources/media/webrtc_internals.css
index b8111e19..349c8c2 100644
--- a/content/browser/resources/media/webrtc_internals.css
+++ b/content/browser/resources/media/webrtc_internals.css
@@ -18,6 +18,10 @@
   background-color: #be2026;
 }
 
+.update-log-legacy-api-usage {
+  background-color: #fed14b;
+}
+
 .ssrc-info-block {
   color: #999;
   font-size: 0.8em;
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index e1b72f8..706b9510 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -80,7 +80,7 @@
   registration->ActivateWaitingVersionWhenReady();
 }
 
-void DidStartWorker(
+void DidStartActiveWorker(
     scoped_refptr<ServiceWorkerVersion> version,
     ServiceWorkerContext::StartActiveWorkerCallback info_callback,
     base::OnceClosure error_callback,
@@ -101,14 +101,15 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (service_worker_status == SERVICE_WORKER_OK) {
     // Note: There might be a remote possibility that
-    // |service_worker_registration|'s active version might change between here
-    // and DidStartWorker, so bind |active_version| to RunAfterStartWorker.
+    // |service_worker_registration|'s active version might change
+    // between here and DidStartActiveWorker, so
+    // bind |active_version| to RunAfterStartWorker.
     scoped_refptr<ServiceWorkerVersion> active_version =
         service_worker_registration->active_version();
     DCHECK(active_version.get());
     active_version->RunAfterStartWorker(
         ServiceWorkerMetrics::EventType::EXTERNAL_REQUEST,
-        base::BindOnce(&DidStartWorker, active_version,
+        base::BindOnce(&DidStartActiveWorker, active_version,
                        std::move(info_callback), std::move(failure_callback)));
   } else {
     std::move(failure_callback).Run();
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index 75c486c..acaade25 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -167,10 +167,6 @@
     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker,
                         OnPostMessageToWorker)
     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_CountFeature, OnCountFeature)
-    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount,
-                        OnIncrementServiceWorkerRefCount)
-    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount,
-                        OnDecrementServiceWorkerRefCount)
     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_TerminateWorker, OnTerminateWorker)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
@@ -219,6 +215,10 @@
   return nullptr;
 }
 
+void ServiceWorkerDispatcherHost::UnregisterServiceWorkerHandle(int handle_id) {
+  handles_.Remove(handle_id);
+}
+
 base::WeakPtr<ServiceWorkerDispatcherHost>
 ServiceWorkerDispatcherHost::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
@@ -376,7 +376,6 @@
   // If not enough time is left to actually process the event don't even
   // bother starting the worker and sending the event.
   if (timeout && *timeout < base::TimeDelta::FromMilliseconds(100)) {
-    ReleaseSourceInfo(std::move(source_info));
     std::move(callback).Run(SERVICE_WORKER_ERROR_TIMEOUT);
     return;
   }
@@ -403,7 +402,6 @@
         ServiceWorkerStatusCode start_worker_status) {
   DCHECK(IsValidSourceInfo(source_info));
   if (start_worker_status != SERVICE_WORKER_OK) {
-    ReleaseSourceInfo(std::move(source_info));
     std::move(callback).Run(start_worker_status);
     return;
   }
@@ -428,21 +426,6 @@
       std::move(event), worker->CreateSimpleEventCallback(request_id));
 }
 
-void ServiceWorkerDispatcherHost::ReleaseSourceInfo(
-    blink::mojom::ServiceWorkerClientInfoPtr source_info) {
-  // ServiceWorkerClientInfo is just a snapshot of the client. There is no need
-  // to do anything for it.
-}
-
-void ServiceWorkerDispatcherHost::ReleaseSourceInfo(
-    blink::mojom::ServiceWorkerObjectInfoPtr source_info) {
-  ServiceWorkerHandle* handle = handles_.Lookup(source_info->handle_id);
-  DCHECK(handle);
-  handle->DecrementRefCount();
-  if (handle->HasNoRefCount())
-    handles_.Remove(source_info->handle_id);
-}
-
 void ServiceWorkerDispatcherHost::OnCountFeature(int64_t version_id,
                                                  uint32_t feature) {
   if (!GetContext())
@@ -461,34 +444,6 @@
   version->CountFeature(feature);
 }
 
-void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
-    int handle_id) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount");
-  ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
-  if (!handle) {
-    bad_message::ReceivedBadMessage(
-        this, bad_message::SWDH_INCREMENT_WORKER_BAD_HANDLE);
-    return;
-  }
-  handle->IncrementRefCount();
-}
-
-void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
-    int handle_id) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount");
-  ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
-  if (!handle) {
-    bad_message::ReceivedBadMessage(
-        this, bad_message::SWDH_DECREMENT_WORKER_BAD_HANDLE);
-    return;
-  }
-  handle->DecrementRefCount();
-  if (handle->HasNoRefCount())
-    handles_.Remove(handle_id);
-}
-
 ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() {
   // Temporary CHECK for debugging https://crbug.com/736203.
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index be37ba7..3bf52e4 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -98,9 +98,10 @@
   // be destroyed.
   bool Send(IPC::Message* message) override;
 
-  // This method is virtual only for testing.
+  // These methods are virtual only for testing.
   virtual void RegisterServiceWorkerHandle(
       std::unique_ptr<ServiceWorkerHandle> handle);
+  virtual void UnregisterServiceWorkerHandle(int handle_id);
 
   ServiceWorkerHandle* FindServiceWorkerHandle(int provider_id,
                                                int64_t version_id);
@@ -140,8 +141,6 @@
 
   // IPC Message handlers
   void OnCountFeature(int64_t version_id, uint32_t feature);
-  void OnIncrementServiceWorkerRefCount(int handle_id);
-  void OnDecrementServiceWorkerRefCount(int handle_id);
   void OnPostMessageToWorker(
       int handle_id,
       int provider_id,
@@ -177,8 +176,6 @@
       const base::Optional<base::TimeDelta>& timeout,
       StatusCallback callback,
       ServiceWorkerStatusCode status);
-  void ReleaseSourceInfo(blink::mojom::ServiceWorkerClientInfoPtr source_info);
-  void ReleaseSourceInfo(blink::mojom::ServiceWorkerObjectInfoPtr source_info);
 
   ServiceWorkerContextCore* GetContext();
 
diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index f91b99a..efe17a1c 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -392,12 +392,13 @@
   // worker object information for the source attribute of the message event.
   provider_host_->running_hosted_version_ = version_;
 
-  // Set aside the initial refcount of the worker handle.
-  provider_host_->GetOrCreateServiceWorkerHandle(version_.get());
+  // |info| keeps the 1st reference to |sender_worker_handle|.
+  blink::mojom::ServiceWorkerObjectInfoPtr info =
+      provider_host_->GetOrCreateServiceWorkerHandle(version_.get());
   ServiceWorkerHandle* sender_worker_handle =
       dispatcher_host_->FindServiceWorkerHandle(provider_host_->provider_id(),
                                                 version_->version_id());
-  const int ref_count = sender_worker_handle->ref_count();
+  EXPECT_EQ(1u, sender_worker_handle->bindings_.size());
 
   // Set mock clock on version_ to check timeout behavior.
   tick_clock_.SetNowTicks(base::TimeTicks::Now());
@@ -430,12 +431,17 @@
       version_, base::string16(),
       url::Origin::Create(version_->scope().GetOrigin()), ports, provider_host_,
       base::BindOnce(&SaveStatusCallback, &called, &status));
-  EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count());
+  // The 2nd reference to |sender_worker_handle| has been passed via the above
+  // dispatch of ExtendableMessageEvent.
+  EXPECT_EQ(2u, sender_worker_handle->bindings_.size());
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(called);
   EXPECT_EQ(SERVICE_WORKER_OK, status);
 
-  EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count());
+  // The remote handler of ExtendableMessageEvent has released the reference to
+  // |service_worker_handle|, please see impl of
+  // EmbeddedWorkerTestHelper::OnExtendableMessageEvent() for details.
+  EXPECT_EQ(1u, sender_worker_handle->bindings_.size());
 
   // Timeout of message event should not have extended life of service worker.
   EXPECT_EQ(remaining_time, version_->remaining_timeout());
diff --git a/content/browser/service_worker/service_worker_handle.cc b/content/browser/service_worker/service_worker_handle.cc
index 8be8695..40003a3 100644
--- a/content/browser/service_worker/service_worker_handle.cc
+++ b/content/browser/service_worker/service_worker_handle.cc
@@ -6,49 +6,49 @@
 
 #include "base/memory/ptr_util.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_dispatcher_host.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_type_converters.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/common/service_worker_modes.h"
 
 namespace content {
 
-std::unique_ptr<ServiceWorkerHandle> ServiceWorkerHandle::Create(
-    base::WeakPtr<ServiceWorkerContextCore> context,
-    base::WeakPtr<ServiceWorkerProviderHost> provider_host,
-    ServiceWorkerVersion* version) {
-  const int handle_id = context.get()
-                            ? context->GetNewServiceWorkerHandleId()
-                            : blink::mojom::kInvalidServiceWorkerHandleId;
-  return CreateWithID(context, provider_host, version, handle_id);
-}
-
-std::unique_ptr<ServiceWorkerHandle> ServiceWorkerHandle::CreateWithID(
+// static
+base::WeakPtr<ServiceWorkerHandle> ServiceWorkerHandle::Create(
+    ServiceWorkerDispatcherHost* dispatcher_host,
     base::WeakPtr<ServiceWorkerContextCore> context,
     base::WeakPtr<ServiceWorkerProviderHost> provider_host,
     ServiceWorkerVersion* version,
-    int handle_id) {
-  if (!context || !provider_host || !version)
-    return std::unique_ptr<ServiceWorkerHandle>();
-  DCHECK(context->GetLiveRegistration(version->registration_id()));
-  return base::WrapUnique(
-      new ServiceWorkerHandle(context, provider_host, version, handle_id));
+    blink::mojom::ServiceWorkerObjectInfoPtr* out_info) {
+  DCHECK(context && provider_host && version && out_info);
+  ServiceWorkerHandle* handle =
+      new ServiceWorkerHandle(dispatcher_host, context, provider_host, version);
+  *out_info = handle->CreateObjectInfo();
+  return handle->AsWeakPtr();
 }
 
 ServiceWorkerHandle::ServiceWorkerHandle(
+    ServiceWorkerDispatcherHost* dispatcher_host,
     base::WeakPtr<ServiceWorkerContextCore> context,
     base::WeakPtr<ServiceWorkerProviderHost> provider_host,
-    ServiceWorkerVersion* version,
-    int handle_id)
-    : context_(context),
+    ServiceWorkerVersion* version)
+    : dispatcher_host_(dispatcher_host),
+      context_(context),
       provider_host_(provider_host),
-      provider_id_(provider_host ? provider_host->provider_id()
-                                 : kInvalidServiceWorkerProviderId),
-      handle_id_(handle_id),
-      ref_count_(1),
-      version_(version) {
+      provider_id_(provider_host->provider_id()),
+      handle_id_(context->GetNewServiceWorkerHandleId()),
+      version_(version),
+      weak_ptr_factory_(this) {
+  DCHECK(context_ && provider_host_ && version_);
+  DCHECK(context_->GetLiveRegistration(version_->registration_id()));
   version_->AddListener(this);
+  bindings_.set_connection_error_handler(base::BindRepeating(
+      &ServiceWorkerHandle::OnConnectionError, base::Unretained(this)));
+  if (dispatcher_host_)
+    dispatcher_host_->RegisterServiceWorkerHandle(base::WrapUnique(this));
 }
 
 ServiceWorkerHandle::~ServiceWorkerHandle() {
@@ -72,17 +72,35 @@
   info->state =
       mojo::ConvertTo<blink::mojom::ServiceWorkerState>(version_->status());
   info->version_id = version_->version_id();
+  bindings_.AddBinding(this, mojo::MakeRequest(&info->host_ptr_info));
   return info;
 }
 
-void ServiceWorkerHandle::IncrementRefCount() {
-  DCHECK_GT(ref_count_, 0);
-  ++ref_count_;
+void ServiceWorkerHandle::RegisterIntoDispatcherHost(
+    ServiceWorkerDispatcherHost* dispatcher_host) {
+  DCHECK(ServiceWorkerUtils::IsServicificationEnabled());
+  DCHECK(!dispatcher_host_);
+  dispatcher_host_ = dispatcher_host;
+  dispatcher_host_->RegisterServiceWorkerHandle(base::WrapUnique(this));
 }
 
-void ServiceWorkerHandle::DecrementRefCount() {
-  DCHECK_GE(ref_count_, 0);
-  --ref_count_;
+base::WeakPtr<ServiceWorkerHandle> ServiceWorkerHandle::AsWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
+void ServiceWorkerHandle::OnConnectionError() {
+  // If there are still bindings, |this| is still being used.
+  if (!bindings_.empty())
+    return;
+  // S13nServiceWorker: This handle may have been precreated before registering
+  // to a dispatcher host. Just self-destruct since we're no longer needed.
+  if (!dispatcher_host_) {
+    DCHECK(ServiceWorkerUtils::IsServicificationEnabled());
+    delete this;
+    return;
+  }
+  // Will destroy |this|.
+  dispatcher_host_->UnregisterServiceWorkerHandle(handle_id_);
 }
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_handle.h b/content/browser/service_worker/service_worker_handle.h
index 015935df..8d7d809 100644
--- a/content/browser/service_worker/service_worker_handle.h
+++ b/content/browser/service_worker/service_worker_handle.h
@@ -13,63 +13,90 @@
 #include "content/browser/service_worker/service_worker_version.h"
 #include "content/common/content_export.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "mojo/public/cpp/bindings/associated_binding_set.h"
+#include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
 
 namespace content {
 
 class ServiceWorkerContextCore;
+class ServiceWorkerDispatcherHost;
+
+namespace service_worker_dispatcher_host_unittest {
+FORWARD_DECLARE_TEST(ServiceWorkerDispatcherHostTest,
+                     DispatchExtendableMessageEvent);
+}  // namespace service_worker_dispatcher_host_unittest
 
 // Roughly corresponds to one WebServiceWorker object in the renderer process.
 //
-// The renderer process maintains the reference count by owning a
-// ServiceWorkerHandleReference for each reference it has to the service worker
-// object. ServiceWorkerHandleReference creation and destruction sends an IPC to
-// the browser process, which adjusts the ServiceWorkerHandle refcount.
+// The WebServiceWorker object in the renderer process maintains a reference to
+// |this| by owning an associated interface pointer to
+// blink::mojom::ServiceWorkerObjectHost.
 //
 // Has references to the corresponding ServiceWorkerVersion in order to ensure
 // that the version is alive while this handle is around.
 class CONTENT_EXPORT ServiceWorkerHandle
-    : public ServiceWorkerVersion::Listener {
+    : public blink::mojom::ServiceWorkerObjectHost,
+      public ServiceWorkerVersion::Listener {
  public:
-  // Creates a handle for a live version. This may return nullptr if any of
-  // |context|, |provider_host| and |version| is nullptr.
-  static std::unique_ptr<ServiceWorkerHandle> Create(
-      base::WeakPtr<ServiceWorkerContextCore> context,
-      base::WeakPtr<ServiceWorkerProviderHost> provider_host,
-      ServiceWorkerVersion* version);
-  // Does the same, but with a specific |handle_id|.
-  static std::unique_ptr<ServiceWorkerHandle> CreateWithID(
+  // Creates a newly created instance for a live version. |out_info| holds the
+  // first ServiceWorkerObjectHost Mojo connection to this instance, which will
+  // delete itself once it detects that all the Mojo connections have gone
+  // away.
+  //
+  // This instance registers itself into |dispatcher_host| to be owned by the
+  // dispatcher host. S13nServiceWorker: |dispatcher_host| may be null.
+  // RegisterIntoDispatcherHost() should be called later to register the handle
+  // once the host is known.
+  static base::WeakPtr<ServiceWorkerHandle> Create(
+      ServiceWorkerDispatcherHost* dispatcher_host,
       base::WeakPtr<ServiceWorkerContextCore> context,
       base::WeakPtr<ServiceWorkerProviderHost> provider_host,
       ServiceWorkerVersion* version,
-      int handle_id);
+      blink::mojom::ServiceWorkerObjectInfoPtr* out_info);
 
-  ServiceWorkerHandle(base::WeakPtr<ServiceWorkerContextCore> context,
-                      base::WeakPtr<ServiceWorkerProviderHost> provider_host,
-                      ServiceWorkerVersion* version,
-                      int handle_id);
   ~ServiceWorkerHandle() override;
 
   // ServiceWorkerVersion::Listener overrides.
   void OnVersionStateChanged(ServiceWorkerVersion* version) override;
 
+  // Establishes a new mojo connection into |bindings_|.
   blink::mojom::ServiceWorkerObjectInfoPtr CreateObjectInfo();
 
+  // Should only be called on a ServiceWorkerHandle instance constructed with
+  // null |dispatcher_host| before.
+  void RegisterIntoDispatcherHost(ServiceWorkerDispatcherHost* dispatcher_host);
+
   int provider_id() const { return provider_id_; }
   int handle_id() const { return handle_id_; }
   ServiceWorkerVersion* version() { return version_.get(); }
 
-  int ref_count() const { return ref_count_; }
-  bool HasNoRefCount() const { return ref_count_ <= 0; }
-  void IncrementRefCount();
-  void DecrementRefCount();
-
  private:
+  FRIEND_TEST_ALL_PREFIXES(
+      service_worker_dispatcher_host_unittest::ServiceWorkerDispatcherHostTest,
+      DispatchExtendableMessageEvent);
+
+  ServiceWorkerHandle(ServiceWorkerDispatcherHost* dispatcher_host,
+                      base::WeakPtr<ServiceWorkerContextCore> context,
+                      base::WeakPtr<ServiceWorkerProviderHost> provider_host,
+                      ServiceWorkerVersion* version);
+
+  base::WeakPtr<ServiceWorkerHandle> AsWeakPtr();
+
+  void OnConnectionError();
+
+  // |dispatcher_host_| may get a valid value via ctor or
+  // RegisterIntoDispatcherHost() function, after that |dispatcher_host_| starts
+  // to own |this|, then, |dispatcher_host_| is valid throughout the lifetime of
+  // |this|.
+  ServiceWorkerDispatcherHost* dispatcher_host_;
   base::WeakPtr<ServiceWorkerContextCore> context_;
   base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
   const int provider_id_;
   const int handle_id_;
-  int ref_count_;  // Created with 1.
   scoped_refptr<ServiceWorkerVersion> version_;
+  mojo::AssociatedBindingSet<blink::mojom::ServiceWorkerObjectHost> bindings_;
+
+  base::WeakPtrFactory<ServiceWorkerHandle> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerHandle);
 };
diff --git a/content/browser/service_worker/service_worker_handle_unittest.cc b/content/browser/service_worker/service_worker_handle_unittest.cc
index 9e639a8..c984e62 100644
--- a/content/browser/service_worker/service_worker_handle_unittest.cc
+++ b/content/browser/service_worker/service_worker_handle_unittest.cc
@@ -138,9 +138,12 @@
 };
 
 TEST_F(ServiceWorkerHandleTest, OnVersionStateChanged) {
-  std::unique_ptr<ServiceWorkerHandle> handle =
-      ServiceWorkerHandle::Create(helper_->context()->AsWeakPtr(),
-                                  provider_host_->AsWeakPtr(), version_.get());
+  blink::mojom::ServiceWorkerObjectInfoPtr info;
+  // ServiceWorkerHandle lifetime is controlled by |info| and is also owned by
+  // |dispatcher_host_|.
+  auto handle = ServiceWorkerHandle::Create(
+      dispatcher_host_.get(), helper_->context()->AsWeakPtr(),
+      provider_host_->AsWeakPtr(), version_.get(), &info);
 
   // Start the worker, and then...
   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index d9b1d59..f2f57f4 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -63,6 +63,16 @@
     handles_.push_back(std::move(handle));
   }
 
+  void UnregisterServiceWorkerHandle(int handle_id) override {
+    auto iter = handles_.begin();
+    for (; iter != handles_.end(); ++iter) {
+      if ((*iter)->handle_id() == handle_id)
+        break;
+    }
+    ASSERT_NE(handles_.end(), iter);
+    handles_.erase(iter);
+  }
+
   void Clear() {
     handles_.clear();
   }
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 9e688a8..627c1cc 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -21,7 +21,6 @@
 #include "content/browser/service_worker/service_worker_context_request_handler.h"
 #include "content/browser/service_worker/service_worker_controllee_request_handler.h"
 #include "content/browser/service_worker/service_worker_dispatcher_host.h"
-#include "content/browser/service_worker/service_worker_handle.h"
 #include "content/browser/service_worker/service_worker_registration_object_host.h"
 #include "content/browser/service_worker/service_worker_script_url_loader_factory.h"
 #include "content/browser/service_worker/service_worker_type_converters.h"
@@ -510,28 +509,27 @@
   if (!context_ || !version)
     return blink::mojom::ServiceWorkerObjectInfo::New();
   if (!dispatcher_host_) {
+    DCHECK(ServiceWorkerUtils::IsServicificationEnabled());
+    blink::mojom::ServiceWorkerObjectInfoPtr info;
     // This is called before the dispatcher host is created.
-    auto info = blink::mojom::ServiceWorkerObjectInfo::New();
-    info->handle_id = context_->GetNewServiceWorkerHandleId();
-    info->url = version->script_url();
-    info->state =
-        mojo::ConvertTo<blink::mojom::ServiceWorkerState>(version->status());
-    info->version_id = version->version_id();
-    precreated_controller_handle_id_ = info->handle_id;
+    // |precreated_controller_handle_| instance's lifetime is controlled by its
+    // own internal Mojo connections via |info|.
+    precreated_controller_handle_ = ServiceWorkerHandle::Create(
+        nullptr, context_, AsWeakPtr(), version, &info);
     return info;
   }
   ServiceWorkerHandle* handle = dispatcher_host_->FindServiceWorkerHandle(
       provider_id(), version->version_id());
   if (handle) {
-    handle->IncrementRefCount();
     return handle->CreateObjectInfo();
   }
 
-  std::unique_ptr<ServiceWorkerHandle> new_handle(
-      ServiceWorkerHandle::Create(context_, AsWeakPtr(), version));
-  handle = new_handle.get();
-  dispatcher_host_->RegisterServiceWorkerHandle(std::move(new_handle));
-  return handle->CreateObjectInfo();
+  blink::mojom::ServiceWorkerObjectInfoPtr info;
+  // ServiceWorkerHandle lifetime is controlled by |info| and is also owned by
+  // |dispatcher_host_|.
+  ServiceWorkerHandle::Create(dispatcher_host_.get(), context_, AsWeakPtr(),
+                              version, &info);
+  return info;
 }
 
 bool ServiceWorkerProviderHost::CanAssociateRegistration(
@@ -613,16 +611,15 @@
   if (!controller_)
     return;
 
-  if (ServiceWorkerUtils::IsServicificationEnabled()) {
-    // S13nServiceWorker: register the controller service worker with the
-    // pre-created handle ID.
+  if (ServiceWorkerUtils::IsServicificationEnabled() &&
+      precreated_controller_handle_) {
+    // S13nServiceWorker: register the pre-created handle for the controller
+    // service worker with the dispatcher host, now that it exists.
     DCHECK_NE(blink::mojom::kInvalidServiceWorkerHandleId,
-              precreated_controller_handle_id_);
-    std::unique_ptr<ServiceWorkerHandle> new_handle(
-        ServiceWorkerHandle::CreateWithID(context_, AsWeakPtr(),
-                                          controller_.get(),
-                                          precreated_controller_handle_id_));
-    dispatcher_host_->RegisterServiceWorkerHandle(std::move(new_handle));
+              precreated_controller_handle_->handle_id());
+    precreated_controller_handle_->RegisterIntoDispatcherHost(
+        dispatcher_host_.get());
+    precreated_controller_handle_ = nullptr;
   }
 
   // In S13nServiceWorker case the controller is already sent in navigation
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index c976257..227f55b3 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -19,6 +19,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
+#include "content/browser/service_worker/service_worker_handle.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/common/content_export.h"
 #include "content/common/service_worker/service_worker_container.mojom.h"
@@ -275,11 +276,10 @@
       scoped_refptr<network::ResourceRequestBody> body,
       bool skip_service_worker);
 
-  // Used to get a ServiceWorkerObjectInfo to send to the renderer. Finds an
-  // existing ServiceWorkerHandle, and increments its reference count, or else
-  // creates a new one (initialized to ref count 1). Returns the
-  // ServiceWorkerObjectInfo from the handle. The renderer is expected to use
-  // ServiceWorkerHandleReference::Adopt to balance out the ref count.
+  // Used to get a ServiceWorkerObjectInfo to send to the renderer.
+  // The object info holds a Mojo connection to the ServiceWorkerHandle for the
+  // |version| to ensure the handle stays alive while the object info is alive.
+  // A new handle is created if one does not already exist.
   blink::mojom::ServiceWorkerObjectInfoPtr GetOrCreateServiceWorkerHandle(
       ServiceWorkerVersion* version);
 
@@ -584,11 +584,10 @@
   std::vector<base::Closure> queued_events_;
 
   // S13nServiceWorker:
-  // A service worker handle ID for the controller service worker that is
+  // A service worker handle for the controller service worker that is
   // pre-created before the renderer process (and therefore the dispatcher host)
   // is created.
-  int precreated_controller_handle_id_ =
-      blink::mojom::kInvalidServiceWorkerHandleId;
+  base::WeakPtr<ServiceWorkerHandle> precreated_controller_handle_;
 
   // For provider hosts that are hosting a running service worker.
   mojo::Binding<service_manager::mojom::InterfaceProvider>
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 3484edd..f66501cb 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -52,6 +52,7 @@
 #include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
+#include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/frame_host/navigator_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/frame_host/render_frame_proxy_host.h"
@@ -645,18 +646,15 @@
   RenderFrameHostManager* root = GetRenderManager();
 
   root->current_frame_host()->SetRenderFrameCreated(false);
-  root->current_frame_host()->SetNavigationHandle(
-      std::unique_ptr<NavigationHandleImpl>());
+  root->current_frame_host()->SetNavigationRequest(
+      std::unique_ptr<NavigationRequest>());
 
-  // PlzNavigate: clear up state specific to browser-side navigation.
-  if (IsBrowserSideNavigationEnabled()) {
-    // Do not update state as the WebContents is being destroyed.
-    frame_tree_.root()->ResetNavigationRequest(true, true);
-    if (root->speculative_frame_host()) {
-      root->speculative_frame_host()->SetRenderFrameCreated(false);
-      root->speculative_frame_host()->SetNavigationHandle(
-          std::unique_ptr<NavigationHandleImpl>());
-    }
+  // Do not update state as the WebContents is being destroyed.
+  frame_tree_.root()->ResetNavigationRequest(true, true);
+  if (root->speculative_frame_host()) {
+    root->speculative_frame_host()->SetRenderFrameCreated(false);
+    root->speculative_frame_host()->SetNavigationRequest(
+        std::unique_ptr<NavigationRequest>());
   }
 
 #if BUILDFLAG(ENABLE_PLUGINS)
diff --git a/content/browser/webrtc/webrtc_event_log_manager.cc b/content/browser/webrtc/webrtc_event_log_manager.cc
index fa424b99..023577f 100644
--- a/content/browser/webrtc/webrtc_event_log_manager.cc
+++ b/content/browser/webrtc/webrtc_event_log_manager.cc
@@ -11,6 +11,30 @@
 
 namespace content {
 
+namespace {
+class PeerConnectionTrackerProxyImpl
+    : public WebRtcEventLogManager::PeerConnectionTrackerProxy {
+ public:
+  ~PeerConnectionTrackerProxyImpl() override = default;
+
+  void StartEventLogOutput(WebRtcEventLogPeerConnectionKey key) override {
+    RenderProcessHost* host = RenderProcessHost::FromID(key.render_process_id);
+    if (!host) {
+      return;  // The host has been asynchronously removed; not a problem.
+    }
+    host->Send(new PeerConnectionTracker_StartEventLogOutput(key.lid));
+  }
+
+  void StopEventLogOutput(WebRtcEventLogPeerConnectionKey key) override {
+    RenderProcessHost* host = RenderProcessHost::FromID(key.render_process_id);
+    if (!host) {
+      return;  // The host has been asynchronously removed; not a problem.
+    }
+    host->Send(new PeerConnectionTracker_StopEventLog(key.lid));
+  }
+};
+}  // namespace
+
 const size_t kWebRtcEventLogManagerUnlimitedFileSize = 0;
 
 WebRtcEventLogManager* WebRtcEventLogManager::g_webrtc_event_log_manager =
@@ -29,6 +53,7 @@
 WebRtcEventLogManager::WebRtcEventLogManager()
     : local_logs_observer_(nullptr),
       local_logs_manager_(this),
+      pc_tracker_proxy_(new PeerConnectionTrackerProxyImpl),
       task_runner_(base::CreateSequencedTaskRunnerWithTraits(
           {base::MayBlock(), base::TaskPriority::BACKGROUND,
            base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {
@@ -245,26 +270,25 @@
 void WebRtcEventLogManager::UpdateWebRtcEventLoggingState(
     PeerConnectionKey peer_connection,
     bool enabled) {
-  // TODO(eladalon): Add unit tests that would make sure that we really
-  // instruct WebRTC to start/stop event logs. https://crbug.com/775415
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  RenderProcessHost* host =
-      RenderProcessHost::FromID(peer_connection.render_process_id);
-  if (!host) {
-    return;  // The host has been asynchronously removed; not a problem.
-  }
   if (enabled) {
-    host->Send(
-        new PeerConnectionTracker_StartEventLogOutput(peer_connection.lid));
+    pc_tracker_proxy_->StartEventLogOutput(peer_connection);
   } else {
-    host->Send(new PeerConnectionTracker_StopEventLog(peer_connection.lid));
+    pc_tracker_proxy_->StopEventLogOutput(peer_connection);
   }
 }
 
-void WebRtcEventLogManager::InjectClockForTesting(base::Clock* clock) {
+void WebRtcEventLogManager::SetClockForTesting(base::Clock* clock) {
   // Testing only; no need for threading guarantees (called before anything
   // could be put on the TQ).
-  local_logs_manager_.InjectClockForTesting(clock);
+  local_logs_manager_.SetClockForTesting(clock);
+}
+
+void WebRtcEventLogManager::SetPeerConnectionTrackerProxyForTesting(
+    std::unique_ptr<PeerConnectionTrackerProxy> pc_tracker_proxy) {
+  // Testing only; no need for threading guarantees (called before anything
+  // could be put on the TQ).
+  pc_tracker_proxy_ = std::move(pc_tracker_proxy);
 }
 
 }  // namespace content
diff --git a/content/browser/webrtc/webrtc_event_log_manager.h b/content/browser/webrtc/webrtc_event_log_manager.h
index 1b8e5d0..0449514 100644
--- a/content/browser/webrtc/webrtc_event_log_manager.h
+++ b/content/browser/webrtc/webrtc_event_log_manager.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_H_
 
 #include <map>
+#include <memory>
 #include <type_traits>
 
 #include "base/callback.h"
@@ -30,6 +31,18 @@
 class CONTENT_EXPORT WebRtcEventLogManager
     : protected WebRtcLocalEventLogsObserver {
  public:
+  // To turn WebRTC on and off, we go through PeerConnectionTrackerProxy. In
+  // order to make this toggling easily testable, PeerConnectionTrackerProxyImpl
+  // will send real messages to PeerConnectionTracker, whereas
+  // PeerConnectionTrackerProxyForTesting will be a mock that just makes sure
+  // the correct messages were attempted to be sent.
+  class PeerConnectionTrackerProxy {
+   public:
+    virtual ~PeerConnectionTrackerProxy() = default;
+    virtual void StartEventLogOutput(WebRtcEventLogPeerConnectionKey key) = 0;
+    virtual void StopEventLogOutput(WebRtcEventLogPeerConnectionKey key) = 0;
+  };
+
   // Ensures that no previous instantiation of the class was performed, then
   // instantiates the class and returns the object. Subsequent calls to
   // GetInstance() will return this object.
@@ -169,7 +182,10 @@
   void UpdateWebRtcEventLoggingState(PeerConnectionKey peer_connection,
                                      bool enabled);
 
-  void InjectClockForTesting(base::Clock* clock);
+  void SetClockForTesting(base::Clock* clock);
+
+  void SetPeerConnectionTrackerProxyForTesting(
+      std::unique_ptr<PeerConnectionTrackerProxy> pc_tracker_proxy);
 
   // Observer which will be informed whenever a local log file is started or
   // stopped. Its callbacks are called synchronously from |task_runner_|,
@@ -185,6 +201,11 @@
   std::map<PeerConnectionKey, LoggingTargetBitmap>
       peer_connections_with_event_logging_enabled_;
 
+  // In production, this holds a small object that just tells WebRTC (via
+  // PeerConnectionTracker) to start/stop producing event logs for a specific
+  // peer connection. In (relevant) unit tests, a mock will be injected.
+  std::unique_ptr<PeerConnectionTrackerProxy> pc_tracker_proxy_;
+
   // The main logic will run sequentially on this runner, on which blocking
   // tasks are allowed.
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
diff --git a/content/browser/webrtc/webrtc_event_log_manager_common.h b/content/browser/webrtc/webrtc_event_log_manager_common.h
index 17ed338..f95d3e9 100644
--- a/content/browser/webrtc/webrtc_event_log_manager_common.h
+++ b/content/browser/webrtc/webrtc_event_log_manager_common.h
@@ -43,9 +43,9 @@
 class WebRtcLocalEventLogsObserver {
  public:
   virtual ~WebRtcLocalEventLogsObserver() = default;
-  virtual void OnLocalLogStarted(WebRtcEventLogPeerConnectionKey pc_key,
+  virtual void OnLocalLogStarted(WebRtcEventLogPeerConnectionKey key,
                                  base::FilePath file_path) = 0;
-  virtual void OnLocalLogStopped(WebRtcEventLogPeerConnectionKey pc_key) = 0;
+  virtual void OnLocalLogStopped(WebRtcEventLogPeerConnectionKey key) = 0;
 };
 
 }  // namespace content
diff --git a/content/browser/webrtc/webrtc_event_log_manager_unittest.cc b/content/browser/webrtc/webrtc_event_log_manager_unittest.cc
index 068361f..8fa5db5 100644
--- a/content/browser/webrtc/webrtc_event_log_manager_unittest.cc
+++ b/content/browser/webrtc/webrtc_event_log_manager_unittest.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <memory>
 #include <numeric>
+#include <queue>
 #include <string>
 #include <vector>
 
@@ -62,10 +63,11 @@
 }  // namespace
 
 class WebRtcEventLogManagerTest : public ::testing::Test {
- protected:
+ public:
   WebRtcEventLogManagerTest()
       : run_loop_(std::make_unique<base::RunLoop>()),
-        manager_(new WebRtcEventLogManager) {
+        manager_(new WebRtcEventLogManager),
+        webrtc_state_change_run_loop_(std::make_unique<base::RunLoop>()) {
     EXPECT_TRUE(
         base::CreateNewTempDirectory(FILE_PATH_LITERAL(""), &base_dir_));
     if (base_dir_.empty()) {
@@ -80,6 +82,8 @@
     if (!base_dir_.empty()) {
       EXPECT_TRUE(base::DeleteFile(base_dir_, true));
     }
+    // Guard against unexpected state changes.
+    EXPECT_TRUE(webrtc_state_change_instructions_.empty());
   }
 
   void DestroyUnitUnderTest() {
@@ -170,7 +174,38 @@
     ASSERT_TRUE(
         base::Time::FromLocalExploded(frozen_time_exploded, &frozen_time));
     frozen_clock_.SetNow(frozen_time);
-    manager_->InjectClockForTesting(&frozen_clock_);
+    manager_->SetClockForTesting(&frozen_clock_);
+  }
+
+  void StartEventLogOutput(PeerConnectionKey key) {
+    webrtc_state_change_instructions_.emplace(key, true);
+    webrtc_state_change_run_loop_->QuitWhenIdle();
+  }
+
+  void StopEventLogOutput(PeerConnectionKey key) {
+    webrtc_state_change_instructions_.emplace(key, false);
+    webrtc_state_change_run_loop_->QuitWhenIdle();
+  }
+
+  void ExpectWebRtcStateChangeInstruction(int render_process_id,
+                                          int lid,
+                                          bool enabled) {
+    webrtc_state_change_run_loop_->Run();
+    webrtc_state_change_run_loop_.reset(new base::RunLoop);
+
+    ASSERT_FALSE(webrtc_state_change_instructions_.empty());
+    auto& instruction = webrtc_state_change_instructions_.front();
+    const PeerConnectionKey key(render_process_id, lid);
+    EXPECT_EQ(instruction.key, key);
+    EXPECT_EQ(instruction.enabled, enabled);
+    webrtc_state_change_instructions_.pop();
+  }
+
+  void SetPeerConnectionTrackerProxyForTesting(
+      std::unique_ptr<WebRtcEventLogManager::PeerConnectionTrackerProxy>
+          pc_tracker_proxy) {
+    manager_->SetPeerConnectionTrackerProxyForTesting(
+        std::move(pc_tracker_proxy));
   }
 
   // Common default values.
@@ -187,8 +222,44 @@
 
   base::FilePath base_dir_;   // The directory where we'll save log files.
   base::FilePath base_path_;  // base_dir_ +  log files' name prefix.
+
+  // WebRtcEventLogManager instructs WebRTC, via PeerConnectionTracker, to
+  // only send WebRTC messages for certain peer connections. Some tests make
+  // sure that this is done correctly, by waiting for these notifications, then
+  // testing them.
+  struct WebRtcStateChangeInstruction {
+    WebRtcStateChangeInstruction(PeerConnectionKey key, bool enabled)
+        : key(key), enabled(enabled) {}
+    PeerConnectionKey key;
+    bool enabled;
+  };
+  std::queue<WebRtcStateChangeInstruction> webrtc_state_change_instructions_;
+  std::unique_ptr<base::RunLoop> webrtc_state_change_run_loop_;
 };
 
+namespace {
+
+class PeerConnectionTrackerProxyForTesting
+    : public WebRtcEventLogManager::PeerConnectionTrackerProxy {
+ public:
+  explicit PeerConnectionTrackerProxyForTesting(WebRtcEventLogManagerTest* test)
+      : test_(test) {}
+  ~PeerConnectionTrackerProxyForTesting() override = default;
+
+  void StartEventLogOutput(WebRtcEventLogPeerConnectionKey key) override {
+    test_->StartEventLogOutput(key);
+  }
+
+  void StopEventLogOutput(WebRtcEventLogPeerConnectionKey key) override {
+    test_->StopEventLogOutput(key);
+  }
+
+ private:
+  WebRtcEventLogManagerTest* const test_;
+};
+
+}  // namespace
+
 TEST_F(WebRtcEventLogManagerTest, LocalLogPeerConnectionAddedReturnsTrue) {
   EXPECT_TRUE(PeerConnectionAdded(kRenderProcessId, kPeerConnectionId));
 }
@@ -940,4 +1011,68 @@
   ASSERT_EQ(file_path_2, expected_path_2);
 }
 
+TEST_F(WebRtcEventLogManagerTest,
+       NoStartWebRtcSendingEventLogsWhenLocalEnabledWithoutPeerConnection) {
+  SetPeerConnectionTrackerProxyForTesting(
+      std::make_unique<PeerConnectionTrackerProxyForTesting>(this));
+  ASSERT_TRUE(EnableLocalLogging());
+  EXPECT_TRUE(webrtc_state_change_instructions_.empty());
+}
+
+TEST_F(WebRtcEventLogManagerTest,
+       NoStartWebRtcSendingEventLogsWhenPeerConnectionButNoLoggingEnabled) {
+  SetPeerConnectionTrackerProxyForTesting(
+      std::make_unique<PeerConnectionTrackerProxyForTesting>(this));
+  ASSERT_TRUE(PeerConnectionAdded(kRenderProcessId, kPeerConnectionId));
+  EXPECT_TRUE(webrtc_state_change_instructions_.empty());
+}
+
+TEST_F(WebRtcEventLogManagerTest,
+       StartWebRtcSendingEventLogsWhenLocalEnabledThenPeerConnectionAdded) {
+  SetPeerConnectionTrackerProxyForTesting(
+      std::make_unique<PeerConnectionTrackerProxyForTesting>(this));
+  ASSERT_TRUE(EnableLocalLogging());
+  ASSERT_TRUE(PeerConnectionAdded(kRenderProcessId, kPeerConnectionId));
+  ExpectWebRtcStateChangeInstruction(kRenderProcessId, kPeerConnectionId, true);
+}
+
+TEST_F(WebRtcEventLogManagerTest,
+       StartWebRtcSendingEventLogsWhenPeerConnectionAddedThenLocalEnabled) {
+  SetPeerConnectionTrackerProxyForTesting(
+      std::make_unique<PeerConnectionTrackerProxyForTesting>(this));
+  ASSERT_TRUE(PeerConnectionAdded(kRenderProcessId, kPeerConnectionId));
+  ASSERT_TRUE(EnableLocalLogging());
+  ExpectWebRtcStateChangeInstruction(kRenderProcessId, kPeerConnectionId, true);
+}
+
+TEST_F(WebRtcEventLogManagerTest,
+       InstructWebRtcToStopSendingEventLogsWhenLocalLoggingStopped) {
+  // Setup
+  SetPeerConnectionTrackerProxyForTesting(
+      std::make_unique<PeerConnectionTrackerProxyForTesting>(this));
+  ASSERT_TRUE(PeerConnectionAdded(kRenderProcessId, kPeerConnectionId));
+  ASSERT_TRUE(EnableLocalLogging());
+  ExpectWebRtcStateChangeInstruction(kRenderProcessId, kPeerConnectionId, true);
+
+  // Test
+  ASSERT_TRUE(DisableLocalLogging());
+  ExpectWebRtcStateChangeInstruction(kRenderProcessId, kPeerConnectionId,
+                                     false);
+}
+
+TEST_F(WebRtcEventLogManagerTest,
+       InstructWebRtcToStopSendingEventLogsWhenPeerConnectionRemoved) {
+  // Setup
+  SetPeerConnectionTrackerProxyForTesting(
+      std::make_unique<PeerConnectionTrackerProxyForTesting>(this));
+  ASSERT_TRUE(PeerConnectionAdded(kRenderProcessId, kPeerConnectionId));
+  ASSERT_TRUE(EnableLocalLogging());
+  ExpectWebRtcStateChangeInstruction(kRenderProcessId, kPeerConnectionId, true);
+
+  // Test
+  ASSERT_TRUE(PeerConnectionRemoved(kRenderProcessId, kPeerConnectionId));
+  ExpectWebRtcStateChangeInstruction(kRenderProcessId, kPeerConnectionId,
+                                     false);
+}
+
 }  // namespace content
diff --git a/content/browser/webrtc/webrtc_local_event_log_manager.cc b/content/browser/webrtc/webrtc_local_event_log_manager.cc
index 31bbc5d..6b010b6f 100644
--- a/content/browser/webrtc/webrtc_local_event_log_manager.cc
+++ b/content/browser/webrtc/webrtc_local_event_log_manager.cc
@@ -157,7 +157,7 @@
   return (static_cast<size_t>(written) == output.length());
 }
 
-void WebRtcLocalEventLogManager::InjectClockForTesting(base::Clock* clock) {
+void WebRtcLocalEventLogManager::SetClockForTesting(base::Clock* clock) {
   clock_for_testing_ = clock;
 }
 
diff --git a/content/browser/webrtc/webrtc_local_event_log_manager.h b/content/browser/webrtc/webrtc_local_event_log_manager.h
index 7934e028..da6654c 100644
--- a/content/browser/webrtc/webrtc_local_event_log_manager.h
+++ b/content/browser/webrtc/webrtc_local_event_log_manager.h
@@ -31,8 +31,8 @@
 
   // This function is public, but this entire class is a protected
   // implementation detail of WebRtcEventLogManager, which hides this
-  // function from everybody except its own unit-tests.
-  void InjectClockForTesting(base::Clock* clock);
+  // function from everybody except its own unit tests.
+  void SetClockForTesting(base::Clock* clock);
 
  private:
   using PeerConnectionKey = WebRtcEventLogPeerConnectionKey;
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.cc b/content/browser/zygote_host/zygote_host_impl_linux.cc
index 680c08a8..900ef81 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -14,9 +14,7 @@
 #include "base/process/kill.h"
 #include "base/process/memory.h"
 #include "base/strings/string_number_conversions.h"
-#include "content/browser/sandbox_host_linux.h"
 #include "content/common/zygote_commands_linux.h"
-#include "content/public/common/common_sandbox_support_linux.h"
 #include "content/public/common/content_switches.h"
 #include "sandbox/linux/services/credentials.h"
 #include "sandbox/linux/services/namespace_sandbox.h"
@@ -152,19 +150,17 @@
   return renderer_sandbox_status_;
 }
 
-pid_t ZygoteHostImpl::LaunchZygote(base::CommandLine* cmd_line,
-                                   base::ScopedFD* control_fd) {
+pid_t ZygoteHostImpl::LaunchZygote(
+    base::CommandLine* cmd_line,
+    base::ScopedFD* control_fd,
+    base::FileHandleMappingVector additional_remapped_fds) {
   int fds[2];
   CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
   CHECK(base::UnixDomainSocket::EnableReceiveProcessId(fds[0]));
 
   base::LaunchOptions options;
-  options.fds_to_remap.push_back(std::make_pair(fds[1], kZygoteSocketPairFd));
-
-  // Start up the sandbox host process and get the file descriptor for the
-  // sandboxed processes to talk to it.
-  const int sfd = SandboxHostLinux::GetInstance()->GetChildSocket();
-  options.fds_to_remap.push_back(std::make_pair(sfd, GetSandboxFD()));
+  options.fds_to_remap = std::move(additional_remapped_fds);
+  options.fds_to_remap.emplace_back(fds[1], kZygoteSocketPairFd);
 
   base::ScopedFD dummy_fd;
   if (use_suid_sandbox_) {
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.h b/content/browser/zygote_host/zygote_host_impl_linux.h
index ee70bd6..c527996 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.h
+++ b/content/browser/zygote_host/zygote_host_impl_linux.h
@@ -12,6 +12,7 @@
 
 #include "base/command_line.h"
 #include "base/files/scoped_file.h"
+#include "base/process/launch.h"
 #include "base/process/process_handle.h"
 #include "base/synchronization/lock.h"
 #include "content/public/browser/zygote_host_linux.h"
@@ -36,7 +37,10 @@
   void SetRendererSandboxStatus(int status);
   int GetRendererSandboxStatus() const override;
 
-  pid_t LaunchZygote(base::CommandLine* cmd_line, base::ScopedFD* control_fd);
+  pid_t LaunchZygote(base::CommandLine* cmd_line,
+                     base::ScopedFD* control_fd,
+                     base::FileHandleMappingVector additional_remapped_fds);
+
   void AdjustRendererOOMScore(base::ProcessHandle process_handle,
                               int score) override;
 
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index 025d0cfb..17dbb02 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -369,10 +369,10 @@
 }
 
 std::unique_ptr<blink::WebThread> BlinkPlatformImpl::CreateThread(
-    const char* name) {
+    const blink::WebThreadCreationParams& params) {
   std::unique_ptr<blink::scheduler::WebThreadBase> thread =
       blink::scheduler::WebThreadBase::CreateWorkerThread(
-          name, base::Thread::Options());
+          params.name, base::Thread::Options());
   thread->Init();
   WaitUntilWebThreadTLSUpdate(thread.get());
   return std::move(thread);
diff --git a/content/child/blink_platform_impl.h b/content/child/blink_platform_impl.h
index 6515ffd..24be824 100644
--- a/content/child/blink_platform_impl.h
+++ b/content/child/blink_platform_impl.h
@@ -78,7 +78,8 @@
   bool IsLowEndDevice() override;
   uint32_t GetUniqueIdForProcess() override;
   blink::WebString UserAgent() override;
-  std::unique_ptr<blink::WebThread> CreateThread(const char* name) override;
+  std::unique_ptr<blink::WebThread> CreateThread(
+      const blink::WebThreadCreationParams& params) override;
   std::unique_ptr<blink::WebThread> CreateWebAudioThread() override;
   blink::WebThread* CurrentThread() override;
   void RecordAction(const blink::UserMetricsAction&) override;
diff --git a/content/common/browser_plugin/browser_plugin_messages.h b/content/common/browser_plugin/browser_plugin_messages.h
index 6d19348..101ccdbe 100644
--- a/content/common/browser_plugin/browser_plugin_messages.h
+++ b/content/common/browser_plugin/browser_plugin_messages.h
@@ -162,15 +162,6 @@
                      uint64_t /* sequence_number */,
                      viz::LocalSurfaceId /* local_surface_id */)
 
-IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_SatisfySequence,
-                    int /* browser_plugin_instance_id */,
-                    viz::SurfaceSequence /* sequence */)
-
-IPC_MESSAGE_ROUTED3(BrowserPluginHostMsg_RequireSequence,
-                    int /* browser_plugin_instance_id */,
-                    viz::SurfaceId /* surface_id */,
-                    viz::SurfaceSequence /* sequence */)
-
 // -----------------------------------------------------------------------------
 // These messages are from the browser process to the embedder.
 
@@ -206,10 +197,9 @@
                      int /* browser_plugin_instance_id */,
                      content::WebCursor /* cursor */)
 
-IPC_MESSAGE_CONTROL3(BrowserPluginMsg_SetChildFrameSurface,
+IPC_MESSAGE_CONTROL2(BrowserPluginMsg_SetChildFrameSurface,
                      int /* browser_plugin_instance_id */,
-                     viz::SurfaceInfo /* surface_info */,
-                     viz::SurfaceSequence /* sequence */)
+                     viz::SurfaceInfo /* surface_info */)
 
 // Forwards a PointerLock Unlock request to the BrowserPlugin.
 IPC_MESSAGE_CONTROL2(BrowserPluginMsg_SetMouseLock,
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 7bce348..565e406 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -19,7 +19,6 @@
 #include "build/build_config.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "content/common/content_export.h"
 #include "content/common/content_param_traits.h"
 #include "content/common/content_security_policy/csp_context.h"
@@ -759,9 +758,8 @@
 // -----------------------------------------------------------------------------
 // Messages sent from the browser to the renderer.
 
-IPC_MESSAGE_ROUTED2(FrameMsg_SetChildFrameSurface,
-                    viz::SurfaceInfo /* surface_info */,
-                    viz::SurfaceSequence /* sequence */)
+IPC_MESSAGE_ROUTED1(FrameMsg_SetChildFrameSurface,
+                    viz::SurfaceInfo /* surface_info */)
 
 // Notifies the embedding frame that the process rendering the child frame's
 // contents has terminated.
@@ -1439,16 +1437,6 @@
                      bool /* is_throttled */)
 #endif  // BUILDFLAG(ENABLE_PLUGINS)
 
-// Satisfies a Surface destruction dependency associated with |sequence|.
-IPC_MESSAGE_ROUTED1(FrameHostMsg_SatisfySequence,
-                    viz::SurfaceSequence /* sequence */)
-
-// Creates a destruction dependency for the Surface specified by the given
-// |surface_id|.
-IPC_MESSAGE_ROUTED2(FrameHostMsg_RequireSequence,
-                    viz::SurfaceId /* surface_id */,
-                    viz::SurfaceSequence /* sequence */)
-
 // Provides the result from handling BeforeUnload.  |proceed| matches the return
 // value of the frame's beforeunload handler: true if the user decided to
 // proceed with leaving the page.
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index 325c4900..24da92c 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -110,14 +110,6 @@
     url::Origin /* source_origin */,
     std::vector<blink::MessagePortChannel> /* sent_message_ports */)
 
-// Increments and decrements the ServiceWorker object's reference
-// counting in the browser side. The ServiceWorker object is created
-// with ref-count==1 initially.
-IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount,
-                     int /* handle_id */)
-IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount,
-                     int /* handle_id */)
-
 // Tells the browser to terminate a service worker. Used in layout tests to
 // verify behavior when a service worker isn't running.
 IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_TerminateWorker,
diff --git a/content/network/network_context.cc b/content/network/network_context.cc
index 4c65f2a..ddd2766 100644
--- a/content/network/network_context.cc
+++ b/content/network/network_context.cc
@@ -43,13 +43,11 @@
 #include "net/http/http_server_properties_manager.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/proxy/proxy_config.h"
-#include "net/reporting/reporting_policy.h"
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/default_channel_id_store.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
 #include "services/network/proxy_config_service_mojo.h"
-#include "services/network/public/cpp/network_features.h"
 #include "services/network/public/cpp/network_switches.h"
 
 namespace content {
@@ -381,16 +379,6 @@
   DCHECK(!network_context_params->enable_ftp_url_support);
 #endif
 
-#if BUILDFLAG(ENABLE_REPORTING)
-  if (base::FeatureList::IsEnabled(features::kReporting))
-    builder->set_reporting_policy(std::make_unique<net::ReportingPolicy>());
-  else
-    builder->set_reporting_policy(nullptr);
-
-  builder->set_network_error_logging_enabled(
-      base::FeatureList::IsEnabled(features::kNetworkErrorLogging));
-#endif  // BUILDFLAG(ENABLE_REPORTING)
-
   net::HttpNetworkSession::Params session_params;
   bool is_quic_force_disabled = false;
   if (quic_disabled)
diff --git a/content/network/network_context_unittest.cc b/content/network/network_context_unittest.cc
index 16bddd2..f3db848e 100644
--- a/content/network/network_context_unittest.cc
+++ b/content/network/network_context_unittest.cc
@@ -17,7 +17,6 @@
 #include "base/run_loop.h"
 #include "base/strings/string_split.h"
 #include "base/test/mock_entropy_provider.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -44,7 +43,6 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
 #include "net/url_request/url_request_job_factory.h"
-#include "services/network/public/cpp/network_features.h"
 #include "services/network/public/interfaces/network_service.mojom.h"
 #include "services/network/public/interfaces/proxy_config.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -262,46 +260,6 @@
 }
 #endif  // !BUILDFLAG(DISABLE_FTP_SUPPORT)
 
-#if BUILDFLAG(ENABLE_REPORTING)
-TEST_F(NetworkContextTest, DisableReporting) {
-  base::test::ScopedFeatureList scoped_feature_list_;
-  scoped_feature_list_.InitAndDisableFeature(features::kReporting);
-
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateContextParams());
-  EXPECT_FALSE(network_context->url_request_context()->reporting_service());
-}
-
-TEST_F(NetworkContextTest, EnableReporting) {
-  base::test::ScopedFeatureList scoped_feature_list_;
-  scoped_feature_list_.InitAndEnableFeature(features::kReporting);
-
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateContextParams());
-  EXPECT_TRUE(network_context->url_request_context()->reporting_service());
-}
-
-TEST_F(NetworkContextTest, DisableNetworkErrorLogging) {
-  base::test::ScopedFeatureList scoped_feature_list_;
-  scoped_feature_list_.InitAndDisableFeature(features::kNetworkErrorLogging);
-
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateContextParams());
-  EXPECT_FALSE(
-      network_context->url_request_context()->network_error_logging_delegate());
-}
-
-TEST_F(NetworkContextTest, EnableNetworkErrorLogging) {
-  base::test::ScopedFeatureList scoped_feature_list_;
-  scoped_feature_list_.InitAndEnableFeature(features::kNetworkErrorLogging);
-
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateContextParams());
-  EXPECT_TRUE(
-      network_context->url_request_context()->network_error_logging_delegate());
-}
-#endif  // BUILDFLAG(ENABLE_REPORTING)
-
 TEST_F(NetworkContextTest, Http09Disabled) {
   network::mojom::NetworkContextParamsPtr context_params =
       CreateContextParams();
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 8e3728a46..6873332c 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -76,7 +76,6 @@
 
   java_files = [
     "java/src/org/chromium/content/app/ChromiumLinkerParams.java",
-    "java/src/org/chromium/content/app/ContentApplication.java",
     "java/src/org/chromium/content/app/ContentChildProcessService.java",
     "java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java",
     "java/src/org/chromium/content/app/ContentMain.java",
diff --git a/content/public/android/java/src/org/chromium/content/app/ContentApplication.java b/content/public/android/java/src/org/chromium/content/app/ContentApplication.java
deleted file mode 100644
index f99526b..0000000
--- a/content/public/android/java/src/org/chromium/content/app/ContentApplication.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.content.app;
-
-import org.chromium.base.BaseChromiumApplication;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.base.annotations.MainDex;
-
-/**
- * Basic application functionality that should be shared among all browser applications
- * based on the content layer.
- */
-@MainDex
-public abstract class ContentApplication extends BaseChromiumApplication {
-    private boolean mLibraryDependenciesInitialized;
-
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mLibraryDependenciesInitialized = true;
-    }
-
-    /**
-     * @return Whether the library dependencies have been initialized and it is safe to issue
-     *         requests to load the native library.
-     */
-    @VisibleForTesting
-    public boolean areLibraryDependenciesInitialized() {
-        return mLibraryDependenciesInitialized;
-    }
-}
diff --git a/content/public/android/java/src/org/chromium/content/browser/SpeechRecognition.java b/content/public/android/java/src/org/chromium/content/browser/SpeechRecognition.java
index 90aeb60f..f2eb964 100644
--- a/content/public/android/java/src/org/chromium/content/browser/SpeechRecognition.java
+++ b/content/public/android/java/src/org/chromium/content/browser/SpeechRecognition.java
@@ -228,6 +228,7 @@
     // This function destroys everything when recognition is done, taking care to properly tear
     // down by calling On{Sound,Audio}End if corresponding On{Audio,Sound}Start were called.
     private void terminate(int error) {
+        if (mNativeSpeechRecognizerImplAndroid == 0) return;
 
         if (mState != STATE_IDLE) {
             if (mState == STATE_CAPTURING_SPEECH) {
diff --git a/content/public/test/android/BUILD.gn b/content/public/test/android/BUILD.gn
index ee6ce6c5..f0607ed 100644
--- a/content/public/test/android/BUILD.gn
+++ b/content/public/test/android/BUILD.gn
@@ -37,7 +37,6 @@
     "javatests/src/org/chromium/content/browser/test/NativeLibraryTestBase.java",
     "javatests/src/org/chromium/content/browser/test/NativeLibraryTestCommon.java",
     "javatests/src/org/chromium/content/browser/test/NativeLibraryTestRule.java",
-    "javatests/src/org/chromium/content/browser/test/util/ApplicationUtils.java",
     "javatests/src/org/chromium/content/browser/test/util/ClickUtils.java",
     "javatests/src/org/chromium/content/browser/test/util/Coordinates.java",
     "javatests/src/org/chromium/content/browser/test/util/Criteria.java",
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestCommon.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestCommon.java
index fbbdc539..51c0f9a 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestCommon.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/NativeLibraryTestCommon.java
@@ -15,7 +15,6 @@
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.content.browser.BrowserStartupController;
-import org.chromium.content.browser.test.util.ApplicationUtils;
 
 class NativeLibraryTestCommon {
     private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "content";
@@ -26,8 +25,6 @@
 
         PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
 
-        ApplicationUtils.waitForLibraryDependencies(instrumentation);
-
         // LibraryLoader is not in general multithreaded; as other InstrumentationTestCase code
         // (specifically, ChromeBrowserProvider) uses it from the main thread we must do
         // likewise.
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/ApplicationUtils.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/ApplicationUtils.java
deleted file mode 100644
index ba8182cf..0000000
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/ApplicationUtils.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.content.browser.test.util;
-
-import android.app.Instrumentation;
-import android.content.Context;
-
-import org.chromium.content.app.ContentApplication;
-
-/**
- * Test utilities for dealing with applications.
- */
-public class ApplicationUtils {
-
-    /**
-     * Wait for the library dependencies to be initialized for the application being
-     * instrumented.
-     *
-     * @param instrumentation The test instrumentation.
-     */
-    public static void waitForLibraryDependencies(final Instrumentation instrumentation) {
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                Context context = instrumentation.getTargetContext();
-                if (context == null) return false;
-                if (context.getApplicationContext() == null) return false;
-                ContentApplication application =
-                        (ContentApplication) context.getApplicationContext();
-                return application.areLibraryDependenciesInitialized();
-            }
-        });
-    }
-
-}
diff --git a/content/public/test/navigation_simulator.cc b/content/public/test/navigation_simulator.cc
index 38e7cbc..b5924b35 100644
--- a/content/public/test/navigation_simulator.cc
+++ b/content/public/test/navigation_simulator.cc
@@ -791,7 +791,7 @@
   request =
       web_contents_->GetMainFrame()->frame_tree_node()->navigation_request();
   if (!request) {
-    if (web_contents_->GetMainFrame()->navigation_handle() == handle_) {
+    if (web_contents_->GetMainFrame()->GetNavigationHandle() == handle_) {
       DCHECK(handle_->IsSameDocument() ||
              !IsURLHandledByNetworkStack(handle_->GetURL()));
       same_document_ = handle_->IsSameDocument();
@@ -800,7 +800,7 @@
       // There is no DidStartNavigation for renderer-debug URLs and the
       // NavigationHandle has already been passed to the main frame for commit.
       // Register it now.
-      handle_ = web_contents_->GetMainFrame()->navigation_handle();
+      handle_ = web_contents_->GetMainFrame()->GetNavigationHandle();
 
       // A navigation to a renderer-debug URL cannot commit. Simulate the
       // renderer process aborting it.
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index b8e28a1..cd18a5e 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -423,8 +423,6 @@
     "service_worker/service_worker_dispatcher.h",
     "service_worker/service_worker_fetch_context_impl.cc",
     "service_worker/service_worker_fetch_context_impl.h",
-    "service_worker/service_worker_handle_reference.cc",
-    "service_worker/service_worker_handle_reference.h",
     "service_worker/service_worker_message_filter.cc",
     "service_worker/service_worker_message_filter.h",
     "service_worker/service_worker_network_provider.cc",
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index 19e2c163..d1f0501a 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -141,8 +141,7 @@
 
 void BrowserPlugin::OnSetChildFrameSurface(
     int browser_plugin_instance_id,
-    const viz::SurfaceInfo& surface_info,
-    const viz::SurfaceSequence& sequence) {
+    const viz::SurfaceInfo& surface_info) {
   if (!attached() || switches::IsMusHostingViz())
     return;
 
@@ -151,12 +150,7 @@
                                              frame_rect().size());
   }
   compositing_helper_->SetFallbackSurfaceId(surface_info.id(),
-                                            frame_rect().size(), sequence);
-}
-
-void BrowserPlugin::SendSatisfySequence(const viz::SurfaceSequence& sequence) {
-  BrowserPluginManager::Get()->Send(new BrowserPluginHostMsg_SatisfySequence(
-      render_frame_routing_id_, browser_plugin_instance_id_, sequence));
+                                            frame_rect().size());
 }
 
 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
@@ -768,8 +762,8 @@
   if (!attached_)
     return;
 
-  compositing_helper_->SetFallbackSurfaceId(
-      surface_info.id(), frame_rect().size(), viz::SurfaceSequence());
+  compositing_helper_->SetFallbackSurfaceId(surface_info.id(),
+                                            frame_rect().size());
 }
 
 void BrowserPlugin::OnMusEmbeddedFrameSinkIdAllocated(
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
index 7480991..7df6d36 100644
--- a/content/renderer/browser_plugin/browser_plugin.h
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -34,7 +34,6 @@
 
 namespace viz {
 class SurfaceInfo;
-struct SurfaceSequence;
 }
 
 namespace content {
@@ -77,9 +76,6 @@
   // Indicates whether the guest should be focused.
   bool ShouldGuestBeFocused() const;
 
-  // Called by CompositingHelper to send current SurfaceSequence to browser.
-  void SendSatisfySequence(const viz::SurfaceSequence& sequence);
-
   // Provided that a guest instance ID has been allocated, this method attaches
   // this BrowserPlugin instance to that guest.
   void Attach();
@@ -190,8 +186,7 @@
   void OnResizeDueToAutoResize(int browser_plugin_instance_id,
                                uint64_t sequence_number);
   void OnSetChildFrameSurface(int instance_id,
-                              const viz::SurfaceInfo& surface_info,
-                              const viz::SurfaceSequence& sequence);
+                              const viz::SurfaceInfo& surface_info);
   void OnSetContentsOpaque(int instance_id, bool opaque);
   void OnSetCursor(int instance_id, const WebCursor& cursor);
   void OnSetMouseLock(int instance_id, bool enable);
diff --git a/content/renderer/child_frame_compositing_helper.cc b/content/renderer/child_frame_compositing_helper.cc
index 01080066..fcd6a40 100644
--- a/content/renderer/child_frame_compositing_helper.cc
+++ b/content/renderer/child_frame_compositing_helper.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "base/command_line.h"
 #include "build/build_config.h"
 #include "cc/blink/web_layer_impl.h"
 #include "cc/layers/picture_image_layer.h"
@@ -18,13 +17,7 @@
 #include "components/viz/common/frame_sinks/copy_output_result.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/resources/single_release_callback.h"
-#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
-#include "components/viz/common/surfaces/stub_surface_reference_factory.h"
-#include "components/viz/common/switches.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/common/browser_plugin/browser_plugin_messages.h"
 #include "content/common/content_switches_internal.h"
-#include "content/common/frame_messages.h"
 #include "content/public/common/content_client.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/renderer/browser_plugin/browser_plugin.h"
@@ -45,117 +38,6 @@
 
 namespace content {
 
-namespace {
-
-bool AreSurfaceReferencesEnabled() {
-#if defined(OS_ANDROID)
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kDisableSurfaceReferences);
-#else
-  // Surface references are always enabled for non-Android platforms.
-  return true;
-#endif
-}
-
-class IframeSurfaceReferenceFactory
-    : public viz::SequenceSurfaceReferenceFactory {
- public:
-  IframeSurfaceReferenceFactory(scoped_refptr<ThreadSafeSender> sender,
-                                int routing_id)
-      : sender_(std::move(sender)), routing_id_(routing_id) {}
-
-  void AddPendingSequence(const viz::SurfaceSequence& sequence) {
-    ReleasePendingSequenceIfNecessary();
-    pending_sequence_ = sequence;
-  }
-
- private:
-  ~IframeSurfaceReferenceFactory() override {
-    ReleasePendingSequenceIfNecessary();
-  }
-
-  void ReleasePendingSequenceIfNecessary() const {
-    if (pending_sequence_.is_valid()) {
-      sender_->Send(
-          new FrameHostMsg_SatisfySequence(routing_id_, pending_sequence_));
-      pending_sequence_ = viz::SurfaceSequence();
-    }
-  }
-
-  // cc::SequenceSurfaceReferenceFactory implementation:
-  void RequireSequence(const viz::SurfaceId& surface_id,
-                       const viz::SurfaceSequence& sequence) const override {
-    sender_->Send(
-        new FrameHostMsg_RequireSequence(routing_id_, surface_id, sequence));
-    // If there is a temporary reference that was waiting on a new one to be
-    // created, it is now safe to release it.
-    ReleasePendingSequenceIfNecessary();
-  }
-
-  void SatisfySequence(const viz::SurfaceSequence& sequence) const override {
-    sender_->Send(new FrameHostMsg_SatisfySequence(routing_id_, sequence));
-  }
-
-  const scoped_refptr<ThreadSafeSender> sender_;
-  mutable viz::SurfaceSequence pending_sequence_;
-  const int routing_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(IframeSurfaceReferenceFactory);
-};
-
-class BrowserPluginSurfaceReferenceFactory
-    : public viz::SequenceSurfaceReferenceFactory {
- public:
-  BrowserPluginSurfaceReferenceFactory(scoped_refptr<ThreadSafeSender> sender,
-                                       int routing_id,
-                                       int browser_plugin_instance_id)
-      : sender_(std::move(sender)),
-        routing_id_(routing_id),
-        browser_plugin_instance_id_(browser_plugin_instance_id) {}
-
-  void AddPendingSequence(const viz::SurfaceSequence& sequence) {
-    ReleasePendingSequenceIfNecessary();
-    pending_sequence_ = sequence;
-  }
-
- private:
-  ~BrowserPluginSurfaceReferenceFactory() override {
-    ReleasePendingSequenceIfNecessary();
-  }
-
-  void ReleasePendingSequenceIfNecessary() const {
-    if (pending_sequence_.is_valid()) {
-      sender_->Send(new BrowserPluginHostMsg_SatisfySequence(
-          routing_id_, browser_plugin_instance_id_, pending_sequence_));
-      pending_sequence_ = viz::SurfaceSequence();
-    }
-  }
-
-  // cc::SequenceSurfaceRefrenceFactory implementation:
-  void SatisfySequence(const viz::SurfaceSequence& seq) const override {
-    sender_->Send(new BrowserPluginHostMsg_SatisfySequence(
-        routing_id_, browser_plugin_instance_id_, seq));
-  }
-
-  void RequireSequence(const viz::SurfaceId& surface_id,
-                       const viz::SurfaceSequence& sequence) const override {
-    sender_->Send(new BrowserPluginHostMsg_RequireSequence(
-        routing_id_, browser_plugin_instance_id_, surface_id, sequence));
-    // If there is a temporary reference that was waiting on a new one to be
-    // created, it is now safe to release it.
-    ReleasePendingSequenceIfNecessary();
-  }
-
-  const scoped_refptr<ThreadSafeSender> sender_;
-  mutable viz::SurfaceSequence pending_sequence_;
-  const int routing_id_;
-  const int browser_plugin_instance_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserPluginSurfaceReferenceFactory);
-};
-
-}  // namespace
-
 ChildFrameCompositingHelper*
 ChildFrameCompositingHelper::CreateForBrowserPlugin(
     const base::WeakPtr<BrowserPlugin>& browser_plugin) {
@@ -180,24 +62,7 @@
     : host_routing_id_(host_routing_id),
       browser_plugin_(browser_plugin),
       render_frame_proxy_(render_frame_proxy),
-      frame_(frame),
-      enable_surface_references_(AreSurfaceReferencesEnabled()) {
-  // In some tests there is no RenderThreadImpl instance.
-  if (enable_surface_references_ || !RenderThreadImpl::current()) {
-    surface_reference_factory_ = new viz::StubSurfaceReferenceFactory();
-  } else {
-    scoped_refptr<ThreadSafeSender> sender(
-        RenderThreadImpl::current()->thread_safe_sender());
-    if (render_frame_proxy_) {
-      surface_reference_factory_ =
-          new IframeSurfaceReferenceFactory(sender, host_routing_id_);
-    } else {
-      surface_reference_factory_ = new BrowserPluginSurfaceReferenceFactory(
-          sender, host_routing_id_,
-          browser_plugin_->browser_plugin_instance_id());
-    }
-  }
-}
+      frame_(frame) {}
 
 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {
 }
@@ -264,7 +129,7 @@
 
   last_primary_surface_id_ = surface_id;
 
-  surface_layer_ = cc::SurfaceLayer::Create(surface_reference_factory_);
+  surface_layer_ = cc::SurfaceLayer::Create();
   surface_layer_->SetMasksToBounds(true);
   surface_layer_->SetBackgroundColor(SK_ColorTRANSPARENT);
 
@@ -288,26 +153,11 @@
 
 void ChildFrameCompositingHelper::SetFallbackSurfaceId(
     const viz::SurfaceId& surface_id,
-    const gfx::Size& frame_size_in_dip,
-    const viz::SurfaceSequence& sequence) {
+    const gfx::Size& frame_size_in_dip) {
   if (fallback_surface_id_ == surface_id)
     return;
 
   fallback_surface_id_ = surface_id;
-  // The RWHV creates a destruction dependency on the surface that needs to be
-  // satisfied. The reference factory will satisfy it when a new reference has
-  // been created.
-  if (!enable_surface_references_) {
-    if (render_frame_proxy_) {
-      static_cast<IframeSurfaceReferenceFactory*>(
-          surface_reference_factory_.get())
-          ->AddPendingSequence(sequence);
-    } else {
-      static_cast<BrowserPluginSurfaceReferenceFactory*>(
-          surface_reference_factory_.get())
-          ->AddPendingSequence(sequence);
-    }
-  }
 
   if (!surface_layer_) {
     SetPrimarySurfaceId(surface_id, frame_size_in_dip);
diff --git a/content/renderer/child_frame_compositing_helper.h b/content/renderer/child_frame_compositing_helper.h
index d67244a..9ef0a2cc 100644
--- a/content/renderer/child_frame_compositing_helper.h
+++ b/content/renderer/child_frame_compositing_helper.h
@@ -16,14 +16,9 @@
 #include "base/memory/weak_ptr.h"
 #include "cc/layers/surface_layer.h"
 #include "components/viz/common/surfaces/surface_id.h"
-#include "components/viz/common/surfaces/surface_reference_factory.h"
 #include "content/common/content_export.h"
 #include "ui/gfx/geometry/size.h"
 
-namespace cc {
-struct SurfaceSequence;
-}
-
 namespace blink {
 class WebLayer;
 class WebPluginContainer;
@@ -56,8 +51,7 @@
   void SetPrimarySurfaceId(const viz::SurfaceId& surface_id,
                            const gfx::Size& frame_size_in_dip);
   void SetFallbackSurfaceId(const viz::SurfaceId& surface_id,
-                            const gfx::Size& frame_size_in_dip,
-                            const viz::SurfaceSequence& sequence);
+                            const gfx::Size& frame_size_in_dip);
   void UpdateVisibility(bool);
   void ChildFrameGone();
 
@@ -94,13 +88,6 @@
   std::unique_ptr<blink::WebLayer> web_layer_;
   blink::WebRemoteFrame* frame_;
 
-  // If surface references are enabled use a stub reference factory.
-  // TODO(kylechar): Remove variable along with surface sequences.
-  // See https://crbug.com/676384.
-  bool enable_surface_references_;
-
-  scoped_refptr<viz::SurfaceReferenceFactory> surface_reference_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(ChildFrameCompositingHelper);
 };
 
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 69305da..77411b2a 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -1273,7 +1273,6 @@
 void RenderWidgetCompositor::SetFrameSinkId(
     const viz::FrameSinkId& frame_sink_id) {
   frame_sink_id_ = frame_sink_id;
-  layer_tree_host_->SetFrameSinkId(frame_sink_id);
 }
 
 void RenderWidgetCompositor::SetPaintedDeviceScaleFactor(float device_scale) {
diff --git a/content/renderer/mus/mus_embedded_frame.cc b/content/renderer/mus/mus_embedded_frame.cc
index 81aadcbe..f3a08923 100644
--- a/content/renderer/mus/mus_embedded_frame.cc
+++ b/content/renderer/mus/mus_embedded_frame.cc
@@ -12,7 +12,6 @@
 #include "components/viz/client/client_layer_tree_frame_sink.h"
 #include "components/viz/client/hit_test_data_provider.h"
 #include "components/viz/client/local_surface_id_provider.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "content/renderer/mus/renderer_window_tree_client.h"
 #include "services/ui/public/cpp/property_type_converters.h"
 #include "services/ui/public/interfaces/window_manager.mojom.h"
diff --git a/content/renderer/mus/renderer_window_tree_client.cc b/content/renderer/mus/renderer_window_tree_client.cc
index 0305fe24..7447b54 100644
--- a/content/renderer/mus/renderer_window_tree_client.cc
+++ b/content/renderer/mus/renderer_window_tree_client.cc
@@ -12,7 +12,6 @@
 #include "components/viz/client/client_layer_tree_frame_sink.h"
 #include "components/viz/client/hit_test_data_provider.h"
 #include "components/viz/client/local_surface_id_provider.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "content/renderer/mash_util.h"
 #include "content/renderer/mus/mus_embedded_frame.h"
 #include "content/renderer/mus/mus_embedded_frame_delegate.h"
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 4ff4df9..011ee69 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -137,7 +137,6 @@
 #include "content/renderer/resource_timing_info_conversions.h"
 #include "content/renderer/savable_resources.h"
 #include "content/renderer/screen_orientation/screen_orientation_dispatcher.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/service_worker_network_provider.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/service_worker/web_service_worker_provider_impl.h"
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 8f83112..1b131852 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -340,8 +340,7 @@
 }
 
 void RenderFrameProxy::SetChildFrameSurface(
-    const viz::SurfaceInfo& surface_info,
-    const viz::SurfaceSequence& sequence) {
+    const viz::SurfaceInfo& surface_info) {
   // If this WebFrame has already been detached, its parent will be null. This
   // can happen when swapping a WebRemoteFrame with a WebLocalFrame, where this
   // message may arrive after the frame was removed from the frame tree, but
@@ -354,7 +353,7 @@
                                              frame_rect().size());
   }
   compositing_helper_->SetFallbackSurfaceId(surface_info.id(),
-                                            frame_rect().size(), sequence);
+                                            frame_rect().size());
 }
 
 bool RenderFrameProxy::OnMessageReceived(const IPC::Message& msg) {
@@ -424,9 +423,8 @@
 }
 
 void RenderFrameProxy::OnSetChildFrameSurface(
-    const viz::SurfaceInfo& surface_info,
-    const viz::SurfaceSequence& sequence) {
-  SetChildFrameSurface(surface_info, sequence);
+    const viz::SurfaceInfo& surface_info) {
+  SetChildFrameSurface(surface_info);
 }
 
 void RenderFrameProxy::OnUpdateOpener(int opener_routing_id) {
@@ -736,7 +734,7 @@
 #if defined(USE_AURA)
 void RenderFrameProxy::OnMusEmbeddedFrameSurfaceChanged(
     const viz::SurfaceInfo& surface_info) {
-  SetChildFrameSurface(surface_info, viz::SurfaceSequence());
+  SetChildFrameSurface(surface_info);
 }
 
 void RenderFrameProxy::OnMusEmbeddedFrameSinkIdAllocated(
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 10554f05..bf21044 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -31,7 +31,6 @@
 
 namespace viz {
 class SurfaceInfo;
-struct SurfaceSequence;
 }
 
 namespace content {
@@ -198,8 +197,7 @@
 
   void ResendResizeParams();
 
-  void SetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                            const viz::SurfaceSequence& sequence);
+  void SetChildFrameSurface(const viz::SurfaceInfo& surface_info);
 
   // IPC::Listener
   bool OnMessageReceived(const IPC::Message& msg) override;
@@ -208,8 +206,8 @@
   void OnDeleteProxy();
   void OnChildFrameProcessGone();
   void OnCompositorFrameSwapped(const IPC::Message& message);
-  void OnSetChildFrameSurface(const viz::SurfaceInfo& surface_info,
-                              const viz::SurfaceSequence& sequence);
+  // TODO(fsamuel): Rename OnFirstSurfaceActivation().
+  void OnSetChildFrameSurface(const viz::SurfaceInfo& surface_info);
   void OnUpdateOpener(int opener_routing_id);
   void OnViewChanged(const viz::FrameSinkId& frame_sink_id);
   void OnDidStopLoading();
@@ -295,6 +293,6 @@
   DISALLOW_COPY_AND_ASSIGN(RenderFrameProxy);
 };
 
-}  // namespace
+}  // namespace content
 
 #endif  // CONTENT_RENDERER_RENDER_FRAME_PROXY_H_
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 82468087..81d1fa7 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -31,6 +31,7 @@
 #include "content/public/renderer/child_url_loader_factory_getter.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/document_state.h"
+#include "content/public/renderer/worker_thread.h"
 #include "content/renderer/loader/request_extra_data.h"
 #include "content/renderer/loader/web_data_consumer_handle_impl.h"
 #include "content/renderer/loader/web_url_loader_impl.h"
@@ -42,7 +43,6 @@
 #include "content/renderer/service_worker/embedded_worker_instance_client_impl.h"
 #include "content/renderer/service_worker/service_worker_dispatcher.h"
 #include "content/renderer/service_worker/service_worker_fetch_context_impl.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/service_worker_network_provider.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/service_worker/service_worker_timeout_timer.h"
@@ -358,6 +358,97 @@
   // This frees the ref to the internal data of |response|.
 }
 
+template <typename Signature>
+class CallbackWrapperOnWorkerThread;
+
+// Always lives (create/run/destroy) on the same one worker thread.
+// This is needed because we're using Mojo ThreadSafeAssociatedInterfacePtr for
+// |context_->service_worker_host|, so we need to ensure Web*Callbacks are
+// destructed on the worker thread. If the worker thread dies before the
+// callback is run, this gets notified in WillStopCurrentWorkerThread() and
+// deletes itself and the callback on the worker thread, otherwise, it runs the
+// callback on the worker thread as normal and deletes itself.
+//
+// TODO(leonhsl): Once we can detach ServiceWorkerHost interface's association
+// on the legacy IPC channel, we can avoid using
+// ThreadSafeAssociatedInterfacePtr for |context_->service_worker_host|, then we
+// can eliminate this wrapping mechanism.
+template <typename... Args>
+class CallbackWrapperOnWorkerThread<void(Args...)>
+    : public WorkerThread::Observer {
+ public:
+  using Signature = void(Args...);
+
+  static base::WeakPtr<CallbackWrapperOnWorkerThread<Signature>> Create(
+      base::OnceCallback<Signature> callback) {
+    // |wrapper| controls its own lifetime via WorkerThread::Observer
+    // implementation.
+    auto* wrapper =
+        new CallbackWrapperOnWorkerThread<Signature>(std::move(callback));
+    return wrapper->weak_ptr_factory_.GetWeakPtr();
+  }
+
+  ~CallbackWrapperOnWorkerThread() override {
+    DCHECK_GT(WorkerThread::GetCurrentId(), 0);
+    WorkerThread::RemoveObserver(this);
+  }
+
+  void Run(Args... args) {
+    DCHECK(callback_);
+    std::move(callback_).Run(std::forward<Args>(args)...);
+    delete this;
+  }
+
+ private:
+  explicit CallbackWrapperOnWorkerThread(base::OnceCallback<Signature> callback)
+      : callback_(std::move(callback)), weak_ptr_factory_(this) {
+    DCHECK_GT(WorkerThread::GetCurrentId(), 0);
+    WorkerThread::AddObserver(this);
+  }
+
+  // WorkerThread::Observer implementation.
+  void WillStopCurrentWorkerThread() override { delete this; }
+
+  base::OnceCallback<Signature> callback_;
+  base::WeakPtrFactory<CallbackWrapperOnWorkerThread> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallbackWrapperOnWorkerThread);
+};
+
+template <typename Signature>
+base::OnceCallback<Signature> WrapCallbackThreadSafe(
+    base::OnceCallback<Signature> callback) {
+  return base::BindOnce(
+      &CallbackWrapperOnWorkerThread<Signature>::Run,
+      CallbackWrapperOnWorkerThread<Signature>::Create(std::move(callback)));
+}
+
+void DidGetClients(
+    std::unique_ptr<blink::WebServiceWorkerClientsCallbacks> callbacks,
+    std::vector<blink::mojom::ServiceWorkerClientInfoPtr> clients) {
+  blink::WebServiceWorkerClientsInfo info;
+  blink::WebVector<blink::WebServiceWorkerClientInfo> web_clients(
+      clients.size());
+  for (size_t i = 0; i < clients.size(); ++i)
+    web_clients[i] = ToWebServiceWorkerClientInfo(*(clients[i]));
+  info.clients.Swap(web_clients);
+  callbacks->OnSuccess(info);
+}
+
+void DidClaimClients(
+    std::unique_ptr<blink::WebServiceWorkerClientsClaimCallbacks> callbacks,
+    blink::mojom::ServiceWorkerErrorType error,
+    const base::Optional<std::string>& error_msg) {
+  if (error != blink::mojom::ServiceWorkerErrorType::kNone) {
+    DCHECK(error_msg);
+    callbacks->OnError(blink::WebServiceWorkerError(
+        error, blink::WebString::FromUTF8(*error_msg)));
+    return;
+  }
+  DCHECK(!error_msg);
+  callbacks->OnSuccess();
+}
+
 }  // namespace
 
 // Holding data that needs to be bound to the worker context on the
@@ -697,14 +788,10 @@
   DCHECK(callbacks);
   auto options = blink::mojom::ServiceWorkerClientQueryOptions::New(
       weboptions.include_uncontrolled, weboptions.client_type);
-  // base::Unretained(this) is safe because the callback passed to
-  // GetClients() is owned by |context_->service_worker_host|, whose only
-  // owner is |this| and won't outlive |this|.
   (*context_->service_worker_host)
-      ->GetClients(
-          std::move(options),
-          base::BindOnce(&ServiceWorkerContextClient::OnDidGetClients,
-                         base::Unretained(this), std::move(callbacks)));
+      ->GetClients(std::move(options),
+                   WrapCallbackThreadSafe(
+                       base::BindOnce(&DidGetClients, std::move(callbacks))));
 }
 
 void ServiceWorkerContextClient::OpenNewTab(
@@ -1241,13 +1328,9 @@
     std::unique_ptr<blink::WebServiceWorkerClientsClaimCallbacks> callbacks) {
   DCHECK(callbacks);
   DCHECK(context_->service_worker_host);
-  // base::Unretained(this) is safe because the callback passed to
-  // ClaimClients() is owned by |context_->service_worker_host|, whose only
-  // owner is |this| and won't outlive |this|.
   (*context_->service_worker_host)
-      ->ClaimClients(
-          base::BindOnce(&ServiceWorkerContextClient::OnDidClaimClients,
-                         base::Unretained(this), std::move(callbacks)));
+      ->ClaimClients(WrapCallbackThreadSafe(
+          base::BindOnce(&DidClaimClients, std::move(callbacks))));
 }
 
 void ServiceWorkerContextClient::DispatchOrQueueFetchEvent(
@@ -1478,14 +1561,12 @@
              blink::mojom::kInvalidServiceWorkerHandleId &&
          event->source_info_for_service_worker->version_id !=
              blink::mojom::kInvalidServiceWorkerVersionId);
-  std::unique_ptr<ServiceWorkerHandleReference> handle =
-      ServiceWorkerHandleReference::Adopt(
-          std::move(event->source_info_for_service_worker), sender_);
   ServiceWorkerDispatcher* dispatcher =
       ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
           sender_.get(), main_thread_task_runner_.get());
   scoped_refptr<WebServiceWorkerImpl> worker =
-      dispatcher->GetOrCreateServiceWorker(std::move(handle));
+      dispatcher->GetOrCreateServiceWorker(
+          std::move(event->source_info_for_service_worker));
   proxy_->DispatchExtendableMessageEvent(
       request_id, blink::WebString::FromUTF16(event->message),
       event->source_origin,
@@ -1628,20 +1709,6 @@
   context_->client_callbacks.Remove(request_id);
 }
 
-void ServiceWorkerContextClient::OnDidGetClients(
-    std::unique_ptr<blink::WebServiceWorkerClientsCallbacks> callbacks,
-    std::vector<blink::mojom::ServiceWorkerClientInfoPtr> clients) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerContextClient::OnDidGetClients");
-  blink::WebServiceWorkerClientsInfo info;
-  blink::WebVector<blink::WebServiceWorkerClientInfo> web_clients(
-      clients.size());
-  for (size_t i = 0; i < clients.size(); ++i)
-    web_clients[i] = ToWebServiceWorkerClientInfo(*(clients[i]));
-  info.clients.Swap(web_clients);
-  callbacks->OnSuccess(info);
-}
-
 void ServiceWorkerContextClient::OnOpenWindowResponse(
     int request_id,
     const blink::mojom::ServiceWorkerClientInfo& client) {
@@ -1754,24 +1821,6 @@
   context_->skip_waiting_callbacks.Remove(request_id);
 }
 
-void ServiceWorkerContextClient::OnDidClaimClients(
-    std::unique_ptr<blink::WebServiceWorkerClientsClaimCallbacks> callbacks,
-    blink::mojom::ServiceWorkerErrorType error,
-    const base::Optional<std::string>& error_msg) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerContextClient::OnDidClaimClients");
-
-  if (error != blink::mojom::ServiceWorkerErrorType::kNone) {
-    DCHECK(error_msg);
-    callbacks->OnError(blink::WebServiceWorkerError(
-        error, blink::WebString::FromUTF8(*error_msg)));
-    return;
-  }
-
-  DCHECK(!error_msg);
-  callbacks->OnSuccess();
-}
-
 void ServiceWorkerContextClient::Ping(PingCallback callback) {
   std::move(callback).Run();
 }
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 3e6edae3..2decc63 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -360,9 +360,6 @@
 
   void OnDidGetClient(int request_id,
                       const blink::mojom::ServiceWorkerClientInfo& client);
-  void OnDidGetClients(
-      std::unique_ptr<blink::WebServiceWorkerClientsCallbacks> callbacks,
-      std::vector<blink::mojom::ServiceWorkerClientInfoPtr> clients);
   void OnOpenWindowResponse(
       int request_id,
       const blink::mojom::ServiceWorkerClientInfo& client);
@@ -375,10 +372,6 @@
       const blink::mojom::ServiceWorkerClientInfo& client);
   void OnNavigateClientError(int request_id, const GURL& url);
   void OnDidSkipWaiting(int request_id);
-  void OnDidClaimClients(
-      std::unique_ptr<blink::WebServiceWorkerClientsClaimCallbacks> callbacks,
-      blink::mojom::ServiceWorkerErrorType error,
-      const base::Optional<std::string>& error_msg);
   // Called to resolve the FetchEvent.preloadResponse promise.
   void OnNavigationPreloadResponse(
       int fetch_event_id,
diff --git a/content/renderer/service_worker/service_worker_dispatcher.cc b/content/renderer/service_worker/service_worker_dispatcher.cc
index a38b326..b87dd6c 100644
--- a/content/renderer/service_worker/service_worker_dispatcher.cc
+++ b/content/renderer/service_worker/service_worker_dispatcher.cc
@@ -18,7 +18,6 @@
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/content_constants.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/service_worker/web_service_worker_impl.h"
 #include "third_party/WebKit/common/service_worker/service_worker_error_type.mojom.h"
@@ -111,18 +110,17 @@
 
 scoped_refptr<WebServiceWorkerImpl>
 ServiceWorkerDispatcher::GetOrCreateServiceWorker(
-    std::unique_ptr<ServiceWorkerHandleReference> handle_ref) {
-  if (!handle_ref)
+    blink::mojom::ServiceWorkerObjectInfoPtr info) {
+  if (!info || info->handle_id == blink::mojom::kInvalidServiceWorkerHandleId ||
+      info->version_id == blink::mojom::kInvalidServiceWorkerVersionId)
     return nullptr;
 
-  WorkerObjectMap::iterator found =
-      service_workers_.find(handle_ref->handle_id());
+  WorkerObjectMap::iterator found = service_workers_.find(info->handle_id);
   if (found != service_workers_.end())
     return found->second;
 
   // WebServiceWorkerImpl constructor calls AddServiceWorker.
-  return new WebServiceWorkerImpl(std::move(handle_ref),
-                                  thread_safe_sender_.get());
+  return new WebServiceWorkerImpl(std::move(info), thread_safe_sender_.get());
 }
 
 void ServiceWorkerDispatcher::OnServiceWorkerStateChanged(
diff --git a/content/renderer/service_worker/service_worker_dispatcher.h b/content/renderer/service_worker/service_worker_dispatcher.h
index c5e1559..de1b9931 100644
--- a/content/renderer/service_worker/service_worker_dispatcher.h
+++ b/content/renderer/service_worker/service_worker_dispatcher.h
@@ -37,7 +37,6 @@
 
 namespace content {
 
-class ServiceWorkerHandleReference;
 class ThreadSafeSender;
 class WebServiceWorkerImpl;
 
@@ -54,9 +53,9 @@
   void OnMessageReceived(const IPC::Message& msg);
 
   // Returns the existing service worker or a newly created one with the given
-  // handle reference. Returns nullptr if the given reference is invalid.
+  // object info. Returns nullptr if the given object info is invalid.
   scoped_refptr<WebServiceWorkerImpl> GetOrCreateServiceWorker(
-      std::unique_ptr<ServiceWorkerHandleReference> handle_ref);
+      blink::mojom::ServiceWorkerObjectInfoPtr info);
 
   static ServiceWorkerDispatcher* GetOrCreateThreadSpecificInstance(
       scoped_refptr<ThreadSafeSender> thread_safe_sender,
@@ -70,10 +69,6 @@
     return main_thread_task_runner_.get();
   }
 
-  scoped_refptr<ThreadSafeSender> thread_safe_sender() {
-    return thread_safe_sender_;
-  }
-
  private:
   using WorkerObjectMap = std::map<int, WebServiceWorkerImpl*>;
 
diff --git a/content/renderer/service_worker/service_worker_dispatcher_unittest.cc b/content/renderer/service_worker/service_worker_dispatcher_unittest.cc
index 8be7e30..a18ad62 100644
--- a/content/renderer/service_worker/service_worker_dispatcher_unittest.cc
+++ b/content/renderer/service_worker/service_worker_dispatcher_unittest.cc
@@ -6,109 +6,40 @@
 
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
-#include "content/child/thread_safe_sender.h"
 #include "content/common/service_worker/service_worker_container.mojom.h"
-#include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_types.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/service_worker/web_service_worker_impl.h"
-#include "content/renderer/service_worker/web_service_worker_registration_impl.h"
-#include "ipc/ipc_sync_message_filter.h"
-#include "ipc/ipc_test_sink.h"
 #include "mojo/public/cpp/bindings/associated_binding_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/common/service_worker/service_worker_error_type.mojom.h"
-#include "third_party/WebKit/common/service_worker/service_worker_registration.mojom.h"
+#include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
 
 namespace content {
 
 namespace {
 
-class MockServiceWorkerRegistrationObjectHost
-    : public blink::mojom::ServiceWorkerRegistrationObjectHost {
+class MockServiceWorkerObjectHost
+    : public blink::mojom::ServiceWorkerObjectHost {
  public:
-  MockServiceWorkerRegistrationObjectHost() {
-    bindings_.set_connection_error_handler(
-        base::Bind(&MockServiceWorkerRegistrationObjectHost::OnConnectionError,
-                   base::Unretained(this)));
-  }
-  ~MockServiceWorkerRegistrationObjectHost() override = default;
+  MockServiceWorkerObjectHost(int32_t handle_id, int64_t version_id)
+      : handle_id_(handle_id), version_id_(version_id) {}
+  ~MockServiceWorkerObjectHost() override = default;
 
-  void AddBinding(
-      blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedRequest
-          request) {
-    bindings_.AddBinding(this, std::move(request));
-  }
-
-  blink::mojom::ServiceWorkerRegistrationObjectAssociatedRequest
-  CreateRegistrationObjectRequest() {
-    if (!remote_registration_)
-      return mojo::MakeRequest(&remote_registration_);
-    return nullptr;
+  blink::mojom::ServiceWorkerObjectInfoPtr CreateObjectInfo() {
+    auto info = blink::mojom::ServiceWorkerObjectInfo::New();
+    info->handle_id = handle_id_;
+    info->version_id = version_id_;
+    bindings_.AddBinding(this, mojo::MakeRequest(&info->host_ptr_info));
+    return info;
   }
 
   int GetBindingCount() const { return bindings_.size(); }
 
  private:
-  // Implements blink::mojom::ServiceWorkerRegistrationObjectHost.
-  void Update(UpdateCallback callback) override {
-    std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kNone,
-                            base::nullopt);
-  }
-  void Unregister(UnregisterCallback callback) override {
-    std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kNone,
-                            base::nullopt);
-  }
-  void EnableNavigationPreload(
-      bool enable,
-      EnableNavigationPreloadCallback callback) override {
-    std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kNone,
-                            base::nullopt);
-  }
-  void GetNavigationPreloadState(
-      GetNavigationPreloadStateCallback callback) override {
-    std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kNone,
-                            base::nullopt, nullptr);
-  }
-  void SetNavigationPreloadHeader(
-      const std::string& value,
-      SetNavigationPreloadHeaderCallback callback) override {
-    std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kNone,
-                            base::nullopt);
-  }
-
-  void OnConnectionError() {
-    // If there are still bindings, |this| is still being used.
-    if (!bindings_.empty())
-      return;
-    // Will destroy corresponding remote WebServiceWorkerRegistrationImpl
-    // instance.
-    remote_registration_.reset();
-  }
-
-  mojo::AssociatedBindingSet<blink::mojom::ServiceWorkerRegistrationObjectHost>
-      bindings_;
-  blink::mojom::ServiceWorkerRegistrationObjectAssociatedPtr
-      remote_registration_;
-};
-
-class ServiceWorkerTestSender : public ThreadSafeSender {
- public:
-  explicit ServiceWorkerTestSender(IPC::TestSink* ipc_sink)
-      : ThreadSafeSender(nullptr, nullptr),
-        ipc_sink_(ipc_sink) {}
-
-  bool Send(IPC::Message* message) override {
-    return ipc_sink_->Send(message);
-  }
-
- private:
-  ~ServiceWorkerTestSender() override {}
-
-  IPC::TestSink* ipc_sink_;
-
-  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerTestSender);
+  int32_t handle_id_;
+  int64_t version_id_;
+  mojo::AssociatedBindingSet<blink::mojom::ServiceWorkerObjectHost> bindings_;
 };
 
 }  // namespace
@@ -118,83 +49,63 @@
   ServiceWorkerDispatcherTest() {}
 
   void SetUp() override {
-    sender_ = new ServiceWorkerTestSender(&ipc_sink_);
-    dispatcher_.reset(new ServiceWorkerDispatcher(sender_.get(), nullptr));
-  }
-
-  blink::mojom::ServiceWorkerRegistrationObjectInfoPtr
-  CreateServiceWorkerRegistrationObjectInfo() {
-    auto info = blink::mojom::ServiceWorkerRegistrationObjectInfo::New();
-    info->registration_id = 20;
-    remote_registration_object_host_.AddBinding(
-        mojo::MakeRequest(&info->host_ptr_info));
-    info->request =
-        remote_registration_object_host_.CreateRegistrationObjectRequest();
-
-    info->active = blink::mojom::ServiceWorkerObjectInfo::New();
-    info->active->handle_id = 100;
-    info->active->version_id = 200;
-    info->waiting = blink::mojom::ServiceWorkerObjectInfo::New();
-    info->waiting->handle_id = 101;
-    info->waiting->version_id = 201;
-    info->installing = blink::mojom::ServiceWorkerObjectInfo::New();
-    info->installing->handle_id = 102;
-    info->installing->version_id = 202;
-    return info;
+    dispatcher_.reset(
+        new ServiceWorkerDispatcher(nullptr /* thread_safe_sender */,
+                                    nullptr /* main_thread_task_runner */));
   }
 
   bool ContainsServiceWorker(int handle_id) {
     return ContainsKey(dispatcher_->service_workers_, handle_id);
   }
 
-  std::unique_ptr<ServiceWorkerHandleReference> Adopt(
-      blink::mojom::ServiceWorkerObjectInfoPtr info) {
-    return ServiceWorkerHandleReference::Adopt(
-        std::move(info), dispatcher_->thread_safe_sender());
-  }
-
   ServiceWorkerDispatcher* dispatcher() { return dispatcher_.get(); }
-  ThreadSafeSender* thread_safe_sender() { return sender_.get(); }
-  IPC::TestSink* ipc_sink() { return &ipc_sink_; }
 
  private:
   base::MessageLoop message_loop_;
-  IPC::TestSink ipc_sink_;
   std::unique_ptr<ServiceWorkerDispatcher> dispatcher_;
-  scoped_refptr<ServiceWorkerTestSender> sender_;
-  MockServiceWorkerRegistrationObjectHost remote_registration_object_host_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDispatcherTest);
 };
 
 TEST_F(ServiceWorkerDispatcherTest, GetServiceWorker) {
-  blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info =
-      CreateServiceWorkerRegistrationObjectInfo();
+  scoped_refptr<WebServiceWorkerImpl> worker1;
+  scoped_refptr<WebServiceWorkerImpl> worker2;
+  auto mock_service_worker_object_host =
+      std::make_unique<MockServiceWorkerObjectHost>(100 /* handle_id */,
+                                                    200 /* version_id */);
+  ASSERT_EQ(0, mock_service_worker_object_host->GetBindingCount());
 
-  // Should return a worker object newly created with the given reference.
-  scoped_refptr<WebServiceWorkerImpl> worker(
-      dispatcher()->GetOrCreateServiceWorker(Adopt(info->installing->Clone())));
-  EXPECT_TRUE(worker);
-  EXPECT_TRUE(ContainsServiceWorker(info->installing->handle_id));
-  EXPECT_EQ(0UL, ipc_sink()->message_count());
+  // Should return a worker object newly created with the 1st given |info|.
+  {
+    blink::mojom::ServiceWorkerObjectInfoPtr info =
+        mock_service_worker_object_host->CreateObjectInfo();
+    EXPECT_EQ(1, mock_service_worker_object_host->GetBindingCount());
+    int handle_id = info->handle_id;
+    worker1 = dispatcher()->GetOrCreateServiceWorker(std::move(info));
+    EXPECT_TRUE(worker1);
+    EXPECT_TRUE(ContainsServiceWorker(handle_id));
+    // |worker1| is holding the 1st blink::mojom::ServiceWorkerObjectHost Mojo
+    // connection to |mock_service_worker_object_host|.
+    EXPECT_EQ(1, mock_service_worker_object_host->GetBindingCount());
+  }
 
-  // Should return the same worker object and release the given reference.
-  scoped_refptr<WebServiceWorkerImpl> existing_worker =
-      dispatcher()->GetOrCreateServiceWorker(
-          Adopt(std::move(info->installing)));
-  EXPECT_EQ(worker, existing_worker);
-  ASSERT_EQ(1UL, ipc_sink()->message_count());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(0)->type());
-  ipc_sink()->ClearMessages();
+  // Should return the same worker object and release the 2nd given |info|.
+  {
+    blink::mojom::ServiceWorkerObjectInfoPtr info =
+        mock_service_worker_object_host->CreateObjectInfo();
+    EXPECT_EQ(2, mock_service_worker_object_host->GetBindingCount());
+    worker2 = dispatcher()->GetOrCreateServiceWorker(std::move(info));
+    EXPECT_EQ(worker1, worker2);
+    base::RunLoop().RunUntilIdle();
+    // The Mojo connection kept by |info| should be released.
+    EXPECT_EQ(1, mock_service_worker_object_host->GetBindingCount());
+  }
 
   // Should return nullptr when a given object is invalid.
   scoped_refptr<WebServiceWorkerImpl> invalid_worker =
       dispatcher()->GetOrCreateServiceWorker(
-          Adopt(blink::mojom::ServiceWorkerObjectInfo::New()));
+          blink::mojom::ServiceWorkerObjectInfo::New());
   EXPECT_FALSE(invalid_worker);
-  EXPECT_EQ(0UL, ipc_sink()->message_count());
 }
 
 }  // namespace content
diff --git a/content/renderer/service_worker/service_worker_handle_reference.cc b/content/renderer/service_worker/service_worker_handle_reference.cc
deleted file mode 100644
index f51a5d3..0000000
--- a/content/renderer/service_worker/service_worker_handle_reference.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
-
-#include "base/memory/ptr_util.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/common/service_worker/service_worker_messages.h"
-#include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
-
-namespace content {
-
-std::unique_ptr<ServiceWorkerHandleReference>
-ServiceWorkerHandleReference::Adopt(
-    blink::mojom::ServiceWorkerObjectInfoPtr info,
-    scoped_refptr<ThreadSafeSender> sender) {
-  DCHECK(sender);
-  if (info->handle_id == blink::mojom::kInvalidServiceWorkerHandleId)
-    return nullptr;
-  return base::WrapUnique(
-      new ServiceWorkerHandleReference(std::move(info), std::move(sender)));
-}
-
-ServiceWorkerHandleReference::ServiceWorkerHandleReference(
-    blink::mojom::ServiceWorkerObjectInfoPtr info,
-    scoped_refptr<ThreadSafeSender> sender)
-    : info_(std::move(info)), sender_(sender) {
-  DCHECK_NE(info_->handle_id, blink::mojom::kInvalidServiceWorkerHandleId);
-}
-
-ServiceWorkerHandleReference::~ServiceWorkerHandleReference() {
-  DCHECK_NE(info_->handle_id, blink::mojom::kInvalidServiceWorkerHandleId);
-  sender_->Send(new ServiceWorkerHostMsg_DecrementServiceWorkerRefCount(
-      info_->handle_id));
-}
-
-}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_handle_reference.h b/content/renderer/service_worker/service_worker_handle_reference.h
deleted file mode 100644
index c692a0f56..0000000
--- a/content/renderer/service_worker/service_worker_handle_reference.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_HANDLE_REFERENCE_H_
-#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_HANDLE_REFERENCE_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "content/common/content_export.h"
-#include "content/common/service_worker/service_worker_types.h"
-#include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
-
-namespace content {
-
-class ThreadSafeSender;
-
-// Represents an interprocess reference to ServiceWorkerHandle managed in the
-// browser process. The constructor and destructor sends a message to increment
-// or decrement the reference count to the browser process.
-class CONTENT_EXPORT ServiceWorkerHandleReference {
- public:
-  // Creates a new ServiceWorkerHandleReference by adopting a ref-count. If
-  // the handle id is kInvalidServiceWorkerHandleId, returns null instead.
-  static std::unique_ptr<ServiceWorkerHandleReference> Adopt(
-      blink::mojom::ServiceWorkerObjectInfoPtr info,
-      scoped_refptr<ThreadSafeSender> sender);
-
-  ~ServiceWorkerHandleReference();
-
-  int handle_id() const { return info_->handle_id; }
-  const GURL& url() const { return info_->url; }
-  blink::mojom::ServiceWorkerState state() const { return info_->state; }
-  int64_t version_id() const { return info_->version_id; }
-
- private:
-  ServiceWorkerHandleReference(blink::mojom::ServiceWorkerObjectInfoPtr info,
-                               scoped_refptr<ThreadSafeSender> sender);
-  blink::mojom::ServiceWorkerObjectInfoPtr info_;
-  scoped_refptr<ThreadSafeSender> sender_;
-  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerHandleReference);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_HANDLE_REFERENCE_H_
diff --git a/content/renderer/service_worker/service_worker_network_provider.cc b/content/renderer/service_worker/service_worker_network_provider.cc
index 92c1059..3f9e54b 100644
--- a/content/renderer/service_worker/service_worker_network_provider.cc
+++ b/content/renderer/service_worker/service_worker_network_provider.cc
@@ -16,7 +16,6 @@
 #include "content/renderer/loader/request_extra_data.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/service_worker/service_worker_dispatcher.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "ipc/ipc_sync_channel.h"
 #include "mojo/public/cpp/bindings/associated_group.h"
@@ -327,7 +326,7 @@
       info->provider_id, std::move(info->client_request),
       std::move(info->host_ptr_info));
   context_->SetRegistrationForServiceWorkerGlobalScope(
-      std::move(info->registration), sender);
+      std::move(info->registration));
 
   if (info->script_loader_factory_ptr_info.is_valid()) {
     script_loader_factory_.Bind(
diff --git a/content/renderer/service_worker/service_worker_provider_context.cc b/content/renderer/service_worker/service_worker_provider_context.cc
index da91715..f552cc5 100644
--- a/content/renderer/service_worker/service_worker_provider_context.cc
+++ b/content/renderer/service_worker/service_worker_provider_context.cc
@@ -19,7 +19,6 @@
 #include "content/public/renderer/child_url_loader_factory_getter.h"
 #include "content/renderer/service_worker/controller_service_worker_connector.h"
 #include "content/renderer/service_worker/service_worker_dispatcher.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/service_worker_subresource_loader.h"
 #include "content/renderer/service_worker/web_service_worker_impl.h"
 #include "content/renderer/service_worker/web_service_worker_registration_impl.h"
@@ -43,7 +42,7 @@
   ~ProviderStateForClient() = default;
 
   // |controller| will be set by SetController() and taken by TakeController().
-  std::unique_ptr<ServiceWorkerHandleReference> controller;
+  blink::mojom::ServiceWorkerObjectInfoPtr controller;
   // Keeps version id of the current controller service worker object.
   int64_t controller_version_id = blink::mojom::kInvalidServiceWorkerVersionId;
 
@@ -89,12 +88,9 @@
 struct ServiceWorkerProviderContext::ProviderStateForServiceWorker {
   ProviderStateForServiceWorker() = default;
   ~ProviderStateForServiceWorker() = default;
-  // These are valid until TakeRegistrationForServiceWorkerGlobalScope() is
-  // called.
+  // |registration| is set by SetRegistrationForServiceWorkerGlobalScope() and
+  // taken by TakeRegistrationForServiceWorkerGlobalScope().
   blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration;
-  std::unique_ptr<ServiceWorkerHandleReference> installing;
-  std::unique_ptr<ServiceWorkerHandleReference> waiting;
-  std::unique_ptr<ServiceWorkerHandleReference> active;
 };
 
 // For service worker clients.
@@ -147,20 +143,11 @@
 ServiceWorkerProviderContext::~ServiceWorkerProviderContext() = default;
 
 void ServiceWorkerProviderContext::SetRegistrationForServiceWorkerGlobalScope(
-    blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration,
-    scoped_refptr<ThreadSafeSender> sender) {
+    blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration) {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   ProviderStateForServiceWorker* state = state_for_service_worker_.get();
   DCHECK(state);
   DCHECK(!state->registration);
-  DCHECK(!state->installing && !state->waiting && !state->active);
-
-  state->installing = ServiceWorkerHandleReference::Adopt(
-      std::move(registration->installing), sender);
-  state->waiting = ServiceWorkerHandleReference::Adopt(
-      std::move(registration->waiting), sender);
-  state->active = ServiceWorkerHandleReference::Adopt(
-      std::move(registration->active), sender);
 
   state->registration = std::move(registration);
 }
@@ -177,24 +164,14 @@
   DCHECK_NE(state->registration->registration_id,
             blink::mojom::kInvalidServiceWorkerRegistrationId);
 
-  ServiceWorkerDispatcher* dispatcher =
-      ServiceWorkerDispatcher::GetThreadSpecificInstance();
-  DCHECK(dispatcher);
   DCHECK(state->registration->request.is_pending());
   scoped_refptr<WebServiceWorkerRegistrationImpl> registration =
       WebServiceWorkerRegistrationImpl::CreateForServiceWorkerGlobalScope(
           std::move(state->registration), std::move(io_task_runner));
-  registration->SetInstalling(
-      dispatcher->GetOrCreateServiceWorker(std::move(state->installing)));
-  registration->SetWaiting(
-      dispatcher->GetOrCreateServiceWorker(std::move(state->waiting)));
-  registration->SetActive(
-      dispatcher->GetOrCreateServiceWorker(std::move(state->active)));
-
   return registration;
 }
 
-std::unique_ptr<ServiceWorkerHandleReference>
+blink::mojom::ServiceWorkerObjectInfoPtr
 ServiceWorkerProviderContext::TakeController() {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(state_for_client_);
@@ -278,15 +255,6 @@
   ServiceWorkerDispatcher* dispatcher =
       ServiceWorkerDispatcher::GetThreadSpecificInstance();
   DCHECK(dispatcher);
-  std::unique_ptr<ServiceWorkerHandleReference> installing =
-      ServiceWorkerHandleReference::Adopt(std::move(info->installing),
-                                          dispatcher->thread_safe_sender());
-  std::unique_ptr<ServiceWorkerHandleReference> waiting =
-      ServiceWorkerHandleReference::Adopt(std::move(info->waiting),
-                                          dispatcher->thread_safe_sender());
-  std::unique_ptr<ServiceWorkerHandleReference> active =
-      ServiceWorkerHandleReference::Adopt(std::move(info->active),
-                                          dispatcher->thread_safe_sender());
 
   auto found = state_for_client_->registrations_.find(info->registration_id);
   if (found != state_for_client_->registrations_.end()) {
@@ -302,13 +270,6 @@
   scoped_refptr<WebServiceWorkerRegistrationImpl> registration =
       WebServiceWorkerRegistrationImpl::CreateForServiceWorkerClient(
           std::move(info), weak_factory_.GetWeakPtr());
-
-  registration->SetInstalling(
-      dispatcher->GetOrCreateServiceWorker(std::move(installing)));
-  registration->SetWaiting(
-      dispatcher->GetOrCreateServiceWorker(std::move(waiting)));
-  registration->SetActive(
-      dispatcher->GetOrCreateServiceWorker(std::move(active)));
   return registration;
 }
 
@@ -336,22 +297,22 @@
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
   ProviderStateForClient* state = state_for_client_.get();
   DCHECK(state);
-  DCHECK(!state->controller || state->controller->handle_id() !=
+  DCHECK(!state->controller || state->controller->handle_id !=
                                    blink::mojom::kInvalidServiceWorkerHandleId);
-  ServiceWorkerDispatcher* dispatcher =
-      ServiceWorkerDispatcher::GetThreadSpecificInstance();
 
   auto& controller = controller_info->object_info;
   state->controller_version_id = controller->version_id;
-  state->controller = ServiceWorkerHandleReference::Adopt(
-      std::move(controller), dispatcher->thread_safe_sender());
+  state->controller =
+      controller->handle_id != blink::mojom::kInvalidServiceWorkerHandleId
+          ? std::move(controller)
+          : nullptr;
 
   // Propagate the controller to workers related to this provider.
   if (state->controller) {
     for (const auto& worker : state->worker_clients) {
       // This is a Mojo interface call to the (dedicated or shared) worker
       // thread.
-      worker->SetControllerServiceWorker(state->controller->version_id());
+      worker->SetControllerServiceWorker(state->controller->version_id);
     }
   }
   for (blink::mojom::WebFeature feature : used_features)
@@ -406,17 +367,12 @@
     const base::string16& message,
     std::vector<mojo::ScopedMessagePipeHandle> message_pipes) {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
-  ServiceWorkerDispatcher* dispatcher =
-      ServiceWorkerDispatcher::GetThreadSpecificInstance();
-  std::unique_ptr<ServiceWorkerHandleReference> source_handle =
-      ServiceWorkerHandleReference::Adopt(std::move(source),
-                                          dispatcher->thread_safe_sender());
 
   ProviderStateForClient* state = state_for_client_.get();
   DCHECK(state);
   if (state->web_service_worker_provider) {
     state->web_service_worker_provider->PostMessageToClient(
-        std::move(source_handle), message, std::move(message_pipes));
+        std::move(source), message, std::move(message_pipes));
   }
 }
 
diff --git a/content/renderer/service_worker/service_worker_provider_context.h b/content/renderer/service_worker/service_worker_provider_context.h
index 440315d..f6551f0 100644
--- a/content/renderer/service_worker/service_worker_provider_context.h
+++ b/content/renderer/service_worker/service_worker_provider_context.h
@@ -37,7 +37,6 @@
 class ServiceWorkerProviderContextTest;
 }  // namespace service_worker_provider_context_unittest
 
-class ServiceWorkerHandleReference;
 class WebServiceWorkerRegistrationImpl;
 struct ServiceWorkerProviderContextDeleter;
 
@@ -100,22 +99,15 @@
   // SetRegistrationForServiceWorkerGlobalScope() is called during the setup for
   // service worker startup, so it is guaranteed to be called before
   // TakeRegistrationForServiceWorkerGlobalScope().
-  // |sender| is to initialize ServiceWorkerHandleReference which still needs to
-  // send legacy Incre/Decre IPCs, will disappear together with class
-  // ServiceWorkerHandleReference once ServiceWorkerObjectInfo starts to retain
-  // reference to ServiceWorkerHandle in the browser process.
   void SetRegistrationForServiceWorkerGlobalScope(
-      blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration,
-      scoped_refptr<ThreadSafeSender> sender);
+      blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration);
 
   // For service worker execution contexts. Used for initializing
   // ServiceWorkerGlobalScope#registration. Called on the worker thread.
   // This takes the registration that was passed to
   // SetRegistrationForServiceWorkerScope(), then creates a new
   // WebServiceWorkerRegistrationImpl instance and returns it. |io_task_runner|
-  // is used to initialize WebServiceWorkerRegistrationImpl. While creating the
-  // WebServiceWorkerRegistrationImpl, increments interprocess references to its
-  // versions via ServiceWorkerHandleReference.
+  // is used to initialize WebServiceWorkerRegistrationImpl.
   scoped_refptr<WebServiceWorkerRegistrationImpl>
   TakeRegistrationForServiceWorkerGlobalScope(
       scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
@@ -124,9 +116,9 @@
   // worker object (ServiceWorkerContainer#controller).
   int64_t GetControllerVersionId();
 
-  // For service worker clients. Takes the controller service worker object set
-  // by SetController() if any, otherwise returns nullptr.
-  std::unique_ptr<ServiceWorkerHandleReference> TakeController();
+  // For service worker clients. Takes the controller service worker object info
+  // set by SetController() if any, otherwise returns nullptr.
+  blink::mojom::ServiceWorkerObjectInfoPtr TakeController();
 
   // S13nServiceWorker:
   // For service worker clients. Returns URLLoaderFactory for loading
diff --git a/content/renderer/service_worker/service_worker_provider_context_unittest.cc b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
index a5bc07b2..20a11b57 100644
--- a/content/renderer/service_worker/service_worker_provider_context_unittest.cc
+++ b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
@@ -21,7 +21,6 @@
 #include "content/renderer/loader/child_url_loader_factory_getter_impl.h"
 #include "content/renderer/service_worker/controller_service_worker_connector.h"
 #include "content/renderer/service_worker/service_worker_dispatcher.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/service_worker/web_service_worker_impl.h"
 #include "content/renderer/service_worker/web_service_worker_registration_impl.h"
@@ -32,6 +31,7 @@
 #include "services/network/public/interfaces/url_loader_factory.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/common/service_worker/service_worker_error_type.mojom.h"
+#include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
 #include "third_party/WebKit/common/service_worker/service_worker_provider_type.mojom.h"
 #include "third_party/WebKit/common/service_worker/service_worker_registration.mojom.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerProviderClient.h"
@@ -41,27 +41,55 @@
 namespace content {
 namespace service_worker_provider_context_unittest {
 
+class MockServiceWorkerObjectHost
+    : public blink::mojom::ServiceWorkerObjectHost {
+ public:
+  MockServiceWorkerObjectHost(int32_t handle_id, int64_t version_id)
+      : handle_id_(handle_id), version_id_(version_id) {}
+  ~MockServiceWorkerObjectHost() override = default;
+
+  blink::mojom::ServiceWorkerObjectInfoPtr CreateObjectInfo() {
+    auto info = blink::mojom::ServiceWorkerObjectInfo::New();
+    info->handle_id = handle_id_;
+    info->version_id = version_id_;
+    bindings_.AddBinding(this, mojo::MakeRequest(&info->host_ptr_info));
+    return info;
+  }
+
+  int GetBindingCount() const { return bindings_.size(); }
+
+ private:
+  int32_t handle_id_;
+  int64_t version_id_;
+  mojo::AssociatedBindingSet<blink::mojom::ServiceWorkerObjectHost> bindings_;
+};
+
 class MockServiceWorkerRegistrationObjectHost
     : public blink::mojom::ServiceWorkerRegistrationObjectHost {
  public:
-  MockServiceWorkerRegistrationObjectHost() {
+  explicit MockServiceWorkerRegistrationObjectHost(int64_t registration_id)
+      : registration_id_(registration_id) {
     bindings_.set_connection_error_handler(
         base::Bind(&MockServiceWorkerRegistrationObjectHost::OnConnectionError,
                    base::Unretained(this)));
   }
   ~MockServiceWorkerRegistrationObjectHost() override = default;
 
-  void AddBinding(
-      blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedRequest
-          request) {
-    bindings_.AddBinding(this, std::move(request));
-  }
+  blink::mojom::ServiceWorkerRegistrationObjectInfoPtr CreateObjectInfo(
+      MockServiceWorkerObjectHost* active,
+      MockServiceWorkerObjectHost* waiting,
+      MockServiceWorkerObjectHost* installing) {
+    auto info = blink::mojom::ServiceWorkerRegistrationObjectInfo::New();
+    info->registration_id = registration_id_;
+    bindings_.AddBinding(this, mojo::MakeRequest(&info->host_ptr_info));
+    info->request = remote_registration_
+                        ? nullptr
+                        : mojo::MakeRequest(&remote_registration_);
 
-  blink::mojom::ServiceWorkerRegistrationObjectAssociatedRequest
-  CreateRegistrationObjectRequest() {
-    if (!remote_registration_)
-      return mojo::MakeRequest(&remote_registration_);
-    return nullptr;
+    info->active = active->CreateObjectInfo();
+    info->waiting = waiting->CreateObjectInfo();
+    info->installing = installing->CreateObjectInfo();
+    return info;
   }
 
   int GetBindingCount() const { return bindings_.size(); }
@@ -103,6 +131,7 @@
     remote_registration_.reset();
   }
 
+  int64_t registration_id_;
   mojo::AssociatedBindingSet<blink::mojom::ServiceWorkerRegistrationObjectHost>
       bindings_;
   blink::mojom::ServiceWorkerRegistrationObjectAssociatedPtr
@@ -256,27 +285,6 @@
             std::move(fake_loader_factory), nullptr);
   }
 
-  blink::mojom::ServiceWorkerRegistrationObjectInfoPtr
-  CreateServiceWorkerRegistrationObjectInfo() {
-    auto info = blink::mojom::ServiceWorkerRegistrationObjectInfo::New();
-    info->registration_id = 20;
-    remote_registration_object_host_.AddBinding(
-        mojo::MakeRequest(&info->host_ptr_info));
-    info->request =
-        remote_registration_object_host_.CreateRegistrationObjectRequest();
-
-    info->active = blink::mojom::ServiceWorkerObjectInfo::New();
-    info->active->handle_id = 100;
-    info->active->version_id = 200;
-    info->waiting = blink::mojom::ServiceWorkerObjectInfo::New();
-    info->waiting->handle_id = 101;
-    info->waiting->version_id = 201;
-    info->installing = blink::mojom::ServiceWorkerObjectInfo::New();
-    info->installing->handle_id = 102;
-    info->installing->version_id = 202;
-    return info;
-  }
-
   void StartRequest(network::mojom::URLLoaderFactory* factory,
                     const GURL& url) {
     network::ResourceRequest request;
@@ -300,17 +308,12 @@
 
   ThreadSafeSender* thread_safe_sender() { return sender_.get(); }
   IPC::TestSink* ipc_sink() { return &ipc_sink_; }
-  const MockServiceWorkerRegistrationObjectHost&
-  remote_registration_object_host() const {
-    return remote_registration_object_host_;
-  }
 
  protected:
   base::MessageLoop message_loop_;
   IPC::TestSink ipc_sink_;
   std::unique_ptr<ServiceWorkerDispatcher> dispatcher_;
   scoped_refptr<ServiceWorkerTestSender> sender_;
-  MockServiceWorkerRegistrationObjectHost remote_registration_object_host_;
 
   // S13nServiceWorker:
   base::test::ScopedFeatureList scoped_feature_list_;
@@ -320,13 +323,31 @@
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderContextTest);
 };
 
-TEST_F(ServiceWorkerProviderContextTest, CreateForController) {
-  // Assume that these objects are passed from the browser process and own
-  // references to browser-side registration/worker representations.
+TEST_F(ServiceWorkerProviderContextTest,
+       CreateForServiceWorkerExecutionContext) {
+  auto active_host = std::make_unique<MockServiceWorkerObjectHost>(
+      100 /* handle_id */, 200 /* version_id */);
+  auto waiting_host = std::make_unique<MockServiceWorkerObjectHost>(
+      101 /* handle_id */, 201 /* version_id */);
+  auto installing_host = std::make_unique<MockServiceWorkerObjectHost>(
+      102 /* handle_id */, 202 /* version_id */);
+  ASSERT_EQ(0, active_host->GetBindingCount());
+  ASSERT_EQ(0, waiting_host->GetBindingCount());
+  ASSERT_EQ(0, installing_host->GetBindingCount());
+  auto mock_registration_object_host =
+      std::make_unique<MockServiceWorkerRegistrationObjectHost>(
+          10 /* registration_id */);
+  ASSERT_EQ(0, mock_registration_object_host->GetBindingCount());
+
   blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info =
-      CreateServiceWorkerRegistrationObjectInfo();
+      mock_registration_object_host->CreateObjectInfo(
+          active_host.get(), waiting_host.get(), installing_host.get());
   // ServiceWorkerRegistrationObjectHost Mojo connection has been added.
-  ASSERT_EQ(1, remote_registration_object_host().GetBindingCount());
+  EXPECT_EQ(1, mock_registration_object_host->GetBindingCount());
+  // ServiceWorkerObjectHost Mojo connections have been added.
+  EXPECT_EQ(1, active_host->GetBindingCount());
+  EXPECT_EQ(1, waiting_host->GetBindingCount());
+  EXPECT_EQ(1, installing_host->GetBindingCount());
 
   // Set up ServiceWorkerProviderContext for ServiceWorkerGlobalScope.
   const int kProviderId = 10;
@@ -335,35 +356,32 @@
 
   // The passed references should be adopted and owned by the provider context.
   provider_context->SetRegistrationForServiceWorkerGlobalScope(
-      std::move(registration_info), thread_safe_sender());
+      std::move(registration_info));
   EXPECT_EQ(0UL, ipc_sink()->message_count());
 
   // Destruction of the provider context should release references to the
   // associated registration and its versions.
   provider_context = nullptr;
-  ASSERT_EQ(3UL, ipc_sink()->message_count());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(0)->type());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(1)->type());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(2)->type());
-  // ServiceWorkerRegistrationObjectHost Mojo connection got broken.
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(0, remote_registration_object_host().GetBindingCount());
+  // ServiceWorkerRegistrationObjectHost Mojo connection got broken.
+  EXPECT_EQ(0, mock_registration_object_host->GetBindingCount());
+  // ServiceWorkerObjectHost Mojo connections got broken.
+  EXPECT_EQ(0, active_host->GetBindingCount());
+  EXPECT_EQ(0, waiting_host->GetBindingCount());
+  EXPECT_EQ(0, installing_host->GetBindingCount());
 }
 
 TEST_F(ServiceWorkerProviderContextTest, SetController) {
   const int kProviderId = 10;
 
   {
-    // Assume that these objects are passed from the browser process and own
-    // references to browser-side registration/worker representations.
-    blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info =
-        CreateServiceWorkerRegistrationObjectInfo();
+    auto mock_service_worker_object_host =
+        std::make_unique<MockServiceWorkerObjectHost>(100 /* handle_id */,
+                                                      200 /* version_id */);
+    ASSERT_EQ(0, mock_service_worker_object_host->GetBindingCount());
+    blink::mojom::ServiceWorkerObjectInfoPtr worker_info =
+        mock_service_worker_object_host->CreateObjectInfo();
+    EXPECT_EQ(1, mock_service_worker_object_host->GetBindingCount());
 
     // (1) In the case there is no WebSWProviderClient but SWProviderContext for
     // the provider, the passed reference should be adopted and owned by the
@@ -378,7 +396,7 @@
 
     ipc_sink()->ClearMessages();
     auto info = mojom::ControllerServiceWorkerInfo::New();
-    info->object_info = std::move(registration_info->active);
+    info->object_info = std::move(worker_info);
     container_ptr->SetController(std::move(info),
                                  std::vector<blink::mojom::WebFeature>(), true);
     base::RunLoop().RunUntilIdle();
@@ -387,18 +405,20 @@
     // Destruction of the provider context should release references to the
     // the controller.
     provider_context = nullptr;
-    ASSERT_EQ(1UL, ipc_sink()->message_count());
-    EXPECT_EQ(static_cast<uint32_t>(
-                  ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-              ipc_sink()->GetMessageAt(0)->type());
+    base::RunLoop().RunUntilIdle();
+    // ServiceWorkerObjectHost Mojo connection got broken.
+    EXPECT_EQ(0, mock_service_worker_object_host->GetBindingCount());
     ipc_sink()->ClearMessages();
   }
 
   {
-    // Assume that these objects are passed from the browser process and own
-    // references to browser-side registration/worker representations.
-    blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info =
-        CreateServiceWorkerRegistrationObjectInfo();
+    auto mock_service_worker_object_host =
+        std::make_unique<MockServiceWorkerObjectHost>(101 /* handle_id */,
+                                                      201 /* version_id */);
+    ASSERT_EQ(0, mock_service_worker_object_host->GetBindingCount());
+    blink::mojom::ServiceWorkerObjectInfoPtr worker_info =
+        mock_service_worker_object_host->CreateObjectInfo();
+    EXPECT_EQ(1, mock_service_worker_object_host->GetBindingCount());
 
     // (2) In the case there are both SWProviderContext and SWProviderClient for
     // the provider, the passed reference should be adopted by the provider
@@ -424,16 +444,14 @@
 
     ipc_sink()->ClearMessages();
     auto info = mojom::ControllerServiceWorkerInfo::New();
-    info->object_info = std::move(registration_info->active);
+    info->object_info = std::move(worker_info);
     container_ptr->SetController(std::move(info),
                                  std::vector<blink::mojom::WebFeature>(), true);
     base::RunLoop().RunUntilIdle();
 
     EXPECT_TRUE(client->was_set_controller_called());
-    ASSERT_EQ(1UL, ipc_sink()->message_count());
-    EXPECT_EQ(static_cast<uint32_t>(
-                  ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-              ipc_sink()->GetMessageAt(0)->type());
+    // ServiceWorkerObjectHost Mojo connection got broken.
+    EXPECT_EQ(0, mock_service_worker_object_host->GetBindingCount());
   }
 }
 
@@ -464,7 +482,7 @@
                                std::vector<blink::mojom::WebFeature>(), true);
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(nullptr, provider_context->TakeController());
+  EXPECT_FALSE(provider_context->TakeController());
   EXPECT_TRUE(client->was_set_controller_called());
 }
 
@@ -474,17 +492,25 @@
   EnableS13nServiceWorker();
   const int kProviderId = 10;
 
-  // Assume that these objects are passed from the browser process and own
-  // references to browser-side registration/worker representations.
-  blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info =
-      CreateServiceWorkerRegistrationObjectInfo();
+  auto active_host = std::make_unique<MockServiceWorkerObjectHost>(
+      100 /* handle_id */, 200 /* version_id */);
+  auto waiting_host = std::make_unique<MockServiceWorkerObjectHost>(
+      101 /* handle_id */, 201 /* version_id */);
+  ASSERT_EQ(0, active_host->GetBindingCount());
+  ASSERT_EQ(0, waiting_host->GetBindingCount());
+  blink::mojom::ServiceWorkerObjectInfoPtr active_worker_info =
+      active_host->CreateObjectInfo();
+  blink::mojom::ServiceWorkerObjectInfoPtr waiting_worker_info =
+      waiting_host->CreateObjectInfo();
+  EXPECT_EQ(1, active_host->GetBindingCount());
+  EXPECT_EQ(1, waiting_host->GetBindingCount());
 
   // (1) Test if setting the controller via the CTOR works.
   FakeControllerServiceWorker fake_controller1;
   auto controller_info1 = mojom::ControllerServiceWorkerInfo::New();
   mojom::ControllerServiceWorkerPtr controller_ptr1;
   fake_controller1.Clone(mojo::MakeRequest(&controller_ptr1));
-  controller_info1->object_info = std::move(registration_info->active);
+  controller_info1->object_info = std::move(active_worker_info);
   controller_info1->endpoint = controller_ptr1.PassInterface();
 
   mojom::ServiceWorkerContainerAssociatedPtr container_ptr;
@@ -515,7 +541,7 @@
   auto controller_info2 = mojom::ControllerServiceWorkerInfo::New();
   mojom::ControllerServiceWorkerPtr controller_ptr2;
   fake_controller2.Clone(mojo::MakeRequest(&controller_ptr2));
-  controller_info2->object_info = std::move(registration_info->waiting);
+  controller_info2->object_info = std::move(waiting_worker_info);
   controller_info2->endpoint = controller_ptr2.PassInterface();
   container_ptr->SetController(std::move(controller_info2),
                                std::vector<blink::mojom::WebFeature>(), true);
@@ -524,10 +550,8 @@
   // released.
   ipc_sink()->ClearMessages();
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(1UL, ipc_sink()->message_count());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(0)->type());
+  EXPECT_EQ(0UL, ipc_sink()->message_count());
+  EXPECT_EQ(0, active_host->GetBindingCount());
 
   // Subresource loader factory must be available, and should be the same
   // one as we got before.
@@ -554,10 +578,8 @@
   // released.
   ipc_sink()->ClearMessages();
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(1UL, ipc_sink()->message_count());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(0)->type());
+  EXPECT_EQ(0UL, ipc_sink()->message_count());
+  EXPECT_EQ(0, waiting_host->GetBindingCount());
 
   // Subresource loader factory must not be available.
   EXPECT_EQ(nullptr, provider_context->GetSubresourceLoaderFactory());
@@ -611,10 +633,13 @@
 TEST_F(ServiceWorkerProviderContextTest, PostMessageToClient) {
   const int kProviderId = 10;
 
-  // Assume that these objects are passed from the browser process and own
-  // references to browser-side registration/worker representations.
-  blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info =
-      CreateServiceWorkerRegistrationObjectInfo();
+  auto mock_service_worker_object_host =
+      std::make_unique<MockServiceWorkerObjectHost>(100 /* handle_id */,
+                                                    200 /* version_id */);
+  ASSERT_EQ(0, mock_service_worker_object_host->GetBindingCount());
+  blink::mojom::ServiceWorkerObjectInfoPtr worker_info =
+      mock_service_worker_object_host->CreateObjectInfo();
+  EXPECT_EQ(1, mock_service_worker_object_host->GetBindingCount());
 
   mojom::ServiceWorkerContainerHostAssociatedPtrInfo host_ptr_info;
   mojom::ServiceWorkerContainerHostAssociatedRequest host_request =
@@ -635,17 +660,14 @@
 
   ipc_sink()->ClearMessages();
   container_ptr->PostMessageToClient(
-      std::move(registration_info->active), base::string16(),
+      std::move(worker_info), base::string16(),
       std::vector<mojo::ScopedMessagePipeHandle>());
   base::RunLoop().RunUntilIdle();
 
   // The passed reference should be owned by the provider client (but the
   // reference is immediately released by the mock provider client).
   EXPECT_TRUE(client->was_dispatch_message_event_called());
-  ASSERT_EQ(1UL, ipc_sink()->message_count());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(0)->type());
+  EXPECT_EQ(0, mock_service_worker_object_host->GetBindingCount());
 }
 
 TEST_F(ServiceWorkerProviderContextTest, CountFeature) {
@@ -690,13 +712,33 @@
   auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
       kProviderId, nullptr, nullptr);
 
-  blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info =
-      CreateServiceWorkerRegistrationObjectInfo();
-  int64_t registration_id = info->registration_id;
-  ASSERT_EQ(1, remote_registration_object_host().GetBindingCount());
+  auto active_host = std::make_unique<MockServiceWorkerObjectHost>(
+      100 /* handle_id */, 200 /* version_id */);
+  auto waiting_host = std::make_unique<MockServiceWorkerObjectHost>(
+      101 /* handle_id */, 201 /* version_id */);
+  auto installing_host = std::make_unique<MockServiceWorkerObjectHost>(
+      102 /* handle_id */, 202 /* version_id */);
+  ASSERT_EQ(0, active_host->GetBindingCount());
+  ASSERT_EQ(0, waiting_host->GetBindingCount());
+  ASSERT_EQ(0, installing_host->GetBindingCount());
+  const int64_t registration_id = 10;
+  auto mock_registration_object_host =
+      std::make_unique<MockServiceWorkerRegistrationObjectHost>(
+          registration_id);
+  ASSERT_EQ(0, mock_registration_object_host->GetBindingCount());
+
+  blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info =
+      mock_registration_object_host->CreateObjectInfo(
+          active_host.get(), waiting_host.get(), installing_host.get());
+  // ServiceWorkerRegistrationObjectHost Mojo connection has been added.
+  EXPECT_EQ(1, mock_registration_object_host->GetBindingCount());
+  // ServiceWorkerObjectHost Mojo connections have been added.
+  EXPECT_EQ(1, active_host->GetBindingCount());
+  EXPECT_EQ(1, waiting_host->GetBindingCount());
+  EXPECT_EQ(1, installing_host->GetBindingCount());
 
   provider_context->SetRegistrationForServiceWorkerGlobalScope(
-      std::move(info), thread_safe_sender());
+      std::move(registration_info));
   EXPECT_EQ(0UL, ipc_sink()->message_count());
 
   // Should return a newly created registration object which adopts all
@@ -707,31 +749,25 @@
           blink::scheduler::GetSingleThreadTaskRunnerForTesting());
   EXPECT_TRUE(registration);
   EXPECT_EQ(registration_id, registration->RegistrationId());
-  EXPECT_EQ(1, remote_registration_object_host().GetBindingCount());
+  EXPECT_EQ(1, mock_registration_object_host->GetBindingCount());
   ASSERT_EQ(0UL, ipc_sink()->message_count());
 
   ipc_sink()->ClearMessages();
   // The registration dtor decrements the refcounts.
   registration = nullptr;
-  ASSERT_EQ(3UL, ipc_sink()->message_count());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(0)->type());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(1)->type());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(2)->type());
-  // The Mojo connection has been dropped.
+  ASSERT_EQ(0UL, ipc_sink()->message_count());
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(0, remote_registration_object_host().GetBindingCount());
+  // ServiceWorkerRegistrationObjectHost Mojo connection got broken.
+  EXPECT_EQ(0, mock_registration_object_host->GetBindingCount());
+  // ServiceWorkerObjectHost Mojo connections got broken.
+  EXPECT_EQ(0, active_host->GetBindingCount());
+  EXPECT_EQ(0, waiting_host->GetBindingCount());
+  EXPECT_EQ(0, installing_host->GetBindingCount());
 }
 
 TEST_F(ServiceWorkerProviderContextTest, GetOrAdoptRegistration) {
   scoped_refptr<WebServiceWorkerRegistrationImpl> registration1;
   scoped_refptr<WebServiceWorkerRegistrationImpl> registration2;
-  int64_t registration_id = blink::mojom::kInvalidServiceWorkerRegistrationId;
   // Set up ServiceWorkerProviderContext for ServiceWorkerGlobalScope.
   const int kProviderId = 10;
   auto provider_context = base::MakeRefCounted<ServiceWorkerProviderContext>(
@@ -739,54 +775,75 @@
       nullptr, nullptr /* controller_info */,
       nullptr /* loader_factory_getter */);
 
+  auto active_host = std::make_unique<MockServiceWorkerObjectHost>(
+      100 /* handle_id */, 200 /* version_id */);
+  auto waiting_host = std::make_unique<MockServiceWorkerObjectHost>(
+      101 /* handle_id */, 201 /* version_id */);
+  auto installing_host = std::make_unique<MockServiceWorkerObjectHost>(
+      102 /* handle_id */, 202 /* version_id */);
+  ASSERT_EQ(0, active_host->GetBindingCount());
+  ASSERT_EQ(0, waiting_host->GetBindingCount());
+  ASSERT_EQ(0, installing_host->GetBindingCount());
+  const int64_t registration_id = 10;
+  auto mock_registration_object_host =
+      std::make_unique<MockServiceWorkerRegistrationObjectHost>(
+          registration_id);
+  ASSERT_EQ(0, mock_registration_object_host->GetBindingCount());
+
   {
-    blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info =
-        CreateServiceWorkerRegistrationObjectInfo();
-    registration_id = info->registration_id;
-    // The 1st ServiceWorkerRegistrationObjectHost Mojo connection has been
-    // added.
-    ASSERT_EQ(1, remote_registration_object_host().GetBindingCount());
+    blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info =
+        mock_registration_object_host->CreateObjectInfo(
+            active_host.get(), waiting_host.get(), installing_host.get());
+    // ServiceWorkerRegistrationObjectHost Mojo connection has been added.
+    EXPECT_EQ(1, mock_registration_object_host->GetBindingCount());
+    // ServiceWorkerObjectHost Mojo connections have been added.
+    EXPECT_EQ(1, active_host->GetBindingCount());
+    EXPECT_EQ(1, waiting_host->GetBindingCount());
+    EXPECT_EQ(1, installing_host->GetBindingCount());
 
     ASSERT_FALSE(ContainsRegistration(provider_context.get(), registration_id));
     // Should return a registration object newly created with adopting the
     // refcounts.
     registration1 =
         provider_context->GetOrCreateRegistrationForServiceWorkerClient(
-            std::move(info));
+            std::move(registration_info));
     EXPECT_TRUE(registration1);
     EXPECT_TRUE(ContainsRegistration(provider_context.get(), registration_id));
     EXPECT_EQ(registration_id, registration1->RegistrationId());
-    EXPECT_EQ(1, remote_registration_object_host().GetBindingCount());
+    EXPECT_EQ(1, mock_registration_object_host->GetBindingCount());
     EXPECT_EQ(0UL, ipc_sink()->message_count());
   }
 
   ipc_sink()->ClearMessages();
 
   {
-    blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info =
-        CreateServiceWorkerRegistrationObjectInfo();
-    // The 2nd Mojo connection has been added.
-    ASSERT_EQ(2, remote_registration_object_host().GetBindingCount());
+    blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info =
+        mock_registration_object_host->CreateObjectInfo(
+            active_host.get(), waiting_host.get(), installing_host.get());
+    // ServiceWorkerRegistrationObjectHost Mojo connection has been added.
+    EXPECT_EQ(2, mock_registration_object_host->GetBindingCount());
+    // ServiceWorkerObjectHost Mojo connections have been added.
+    EXPECT_EQ(2, active_host->GetBindingCount());
+    EXPECT_EQ(2, waiting_host->GetBindingCount());
+    EXPECT_EQ(2, installing_host->GetBindingCount());
+
     // Should return the same registration object without incrementing the
     // refcounts.
     registration2 =
         provider_context->GetOrCreateRegistrationForServiceWorkerClient(
-            std::move(info));
+            std::move(registration_info));
     EXPECT_TRUE(registration2);
     EXPECT_EQ(registration1, registration2);
-    // The 2nd Mojo connection has been dropped.
     base::RunLoop().RunUntilIdle();
-    EXPECT_EQ(1, remote_registration_object_host().GetBindingCount());
-    ASSERT_EQ(3UL, ipc_sink()->message_count());
-    EXPECT_EQ(static_cast<uint32_t>(
-                  ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-              ipc_sink()->GetMessageAt(0)->type());
-    EXPECT_EQ(static_cast<uint32_t>(
-                  ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-              ipc_sink()->GetMessageAt(1)->type());
-    EXPECT_EQ(static_cast<uint32_t>(
-                  ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-              ipc_sink()->GetMessageAt(2)->type());
+    ASSERT_EQ(0UL, ipc_sink()->message_count());
+    // The 2nd ServiceWorkerRegistrationObjectHost Mojo connection has been
+    // dropped.
+    EXPECT_EQ(1, mock_registration_object_host->GetBindingCount());
+    // The corresponding ServiceWorkerObjectHost Mojo connections have been
+    // dropped.
+    EXPECT_EQ(1, active_host->GetBindingCount());
+    EXPECT_EQ(1, waiting_host->GetBindingCount());
+    EXPECT_EQ(1, installing_host->GetBindingCount());
   }
 
   ipc_sink()->ClearMessages();
@@ -794,20 +851,15 @@
   // The registration dtor decrements the refcounts.
   registration1 = nullptr;
   registration2 = nullptr;
-  ASSERT_EQ(3UL, ipc_sink()->message_count());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(0)->type());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(1)->type());
-  EXPECT_EQ(static_cast<uint32_t>(
-                ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID),
-            ipc_sink()->GetMessageAt(2)->type());
-  // The 1st Mojo connection has been dropped.
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(ContainsRegistration(provider_context.get(), registration_id));
-  EXPECT_EQ(0, remote_registration_object_host().GetBindingCount());
+  ASSERT_EQ(0UL, ipc_sink()->message_count());
+  // The 1st ServiceWorkerRegistrationObjectHost Mojo connection got broken.
+  EXPECT_EQ(0, mock_registration_object_host->GetBindingCount());
+  // The corresponding ServiceWorkerObjectHost Mojo connections got broken.
+  EXPECT_EQ(0, active_host->GetBindingCount());
+  EXPECT_EQ(0, waiting_host->GetBindingCount());
+  EXPECT_EQ(0, installing_host->GetBindingCount());
 }
 
 }  // namespace service_worker_provider_context_unittest
diff --git a/content/renderer/service_worker/service_worker_timeout_timer.cc b/content/renderer/service_worker/service_worker_timeout_timer.cc
index b6e0abd..669134f 100644
--- a/content/renderer/service_worker/service_worker_timeout_timer.cc
+++ b/content/renderer/service_worker/service_worker_timeout_timer.cc
@@ -113,6 +113,9 @@
     iter = inflight_events_.erase(iter);
     id_event_map_.erase(event_id);
     std::move(callback).Run();
+    // Shut down the worker as soon as possible since the worker may have gone
+    // into bad state.
+    zero_idle_timer_delay_ = true;
   }
 
   // If |inflight_events_| is empty, the worker is now idle.
diff --git a/content/renderer/service_worker/service_worker_timeout_timer.h b/content/renderer/service_worker/service_worker_timeout_timer.h
index 7d657a1..f134353 100644
--- a/content/renderer/service_worker/service_worker_timeout_timer.h
+++ b/content/renderer/service_worker/service_worker_timeout_timer.h
@@ -28,7 +28,9 @@
 // S13nServiceWorker:
 // 1) Event timeout: when an event starts, StartEvent() records the expiration
 // time of the event (kEventTimeout). If EndEvent() has not been called within
-// the timeout time, |abort_callback| passed to StartEvent() is called.
+// the timeout time, |abort_callback| passed to StartEvent() is called. Also,
+// |zero_idle_timer_delay_| is set to true to shut down the worker as soon as
+// possible since the worker may have gone into bad state.
 // 2) Idle timeout: when a certain time has passed (kIdleDelay) since all of
 // events have ended, ServiceWorkerTimeoutTimer calls the |idle_callback|.
 // |idle_callback| will be continuously called at a certain interval
diff --git a/content/renderer/service_worker/service_worker_timeout_timer_unittest.cc b/content/renderer/service_worker/service_worker_timeout_timer_unittest.cc
index ff3af3ae..90997c76 100644
--- a/content/renderer/service_worker/service_worker_timeout_timer_unittest.cc
+++ b/content/renderer/service_worker/service_worker_timeout_timer_unittest.cc
@@ -148,11 +148,9 @@
                                ServiceWorkerTimeoutTimer::kUpdateInterval +
                                base::TimeDelta::FromSeconds(1));
 
+  // |event| should have been aborted, and at the same time, the idle timeout
+  // should also be fired since there has been an aborted event.
   EXPECT_TRUE(event.has_aborted());
-  EXPECT_FALSE(is_idle);
-  task_runner()->FastForwardBy(ServiceWorkerTimeoutTimer::kIdleDelay +
-                               base::TimeDelta::FromSeconds(1));
-
   EXPECT_TRUE(is_idle);
 }
 
diff --git a/content/renderer/service_worker/web_service_worker_impl.cc b/content/renderer/service_worker/web_service_worker_impl.cc
index c078c10b..560f5ddc 100644
--- a/content/renderer/service_worker/web_service_worker_impl.cc
+++ b/content/renderer/service_worker/web_service_worker_impl.cc
@@ -11,9 +11,7 @@
 #include "content/child/thread_safe_sender.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/renderer/service_worker/service_worker_dispatcher.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/web_service_worker_provider_impl.h"
-#include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
 #include "third_party/WebKit/public/platform/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
 #include "third_party/WebKit/public/platform/WebString.h"
@@ -44,18 +42,17 @@
 }  // namespace
 
 WebServiceWorkerImpl::WebServiceWorkerImpl(
-    std::unique_ptr<ServiceWorkerHandleReference> handle_ref,
+    blink::mojom::ServiceWorkerObjectInfoPtr info,
     ThreadSafeSender* thread_safe_sender)
-    : handle_ref_(std::move(handle_ref)),
-      state_(handle_ref_->state()),
+    : info_(std::move(info)),
+      state_(info_->state),
       thread_safe_sender_(thread_safe_sender),
       proxy_(nullptr) {
-  DCHECK_NE(blink::mojom::kInvalidServiceWorkerHandleId,
-            handle_ref_->handle_id());
+  DCHECK_NE(blink::mojom::kInvalidServiceWorkerHandleId, info_->handle_id);
   ServiceWorkerDispatcher* dispatcher =
       ServiceWorkerDispatcher::GetThreadSpecificInstance();
   DCHECK(dispatcher);
-  dispatcher->AddServiceWorker(handle_ref_->handle_id(), this);
+  dispatcher->AddServiceWorker(info_->handle_id, this);
 }
 
 void WebServiceWorkerImpl::OnStateChanged(
@@ -77,7 +74,7 @@
 }
 
 blink::WebURL WebServiceWorkerImpl::Url() const {
-  return handle_ref_->url();
+  return info_->url;
 }
 
 blink::mojom::ServiceWorkerState WebServiceWorkerImpl::GetState() const {
@@ -90,14 +87,14 @@
     const WebSecurityOrigin& source_origin,
     blink::WebVector<blink::MessagePortChannel> channels) {
   thread_safe_sender_->Send(new ServiceWorkerHostMsg_PostMessageToWorker(
-      handle_ref_->handle_id(),
+      info_->handle_id,
       static_cast<WebServiceWorkerProviderImpl*>(provider)->provider_id(),
       message.Utf16(), url::Origin(source_origin), channels.ReleaseVector()));
 }
 
 void WebServiceWorkerImpl::Terminate() {
   thread_safe_sender_->Send(
-      new ServiceWorkerHostMsg_TerminateWorker(handle_ref_->handle_id()));
+      new ServiceWorkerHostMsg_TerminateWorker(info_->handle_id));
 }
 
 // static
@@ -113,7 +110,7 @@
   ServiceWorkerDispatcher* dispatcher =
       ServiceWorkerDispatcher::GetThreadSpecificInstance();
   if (dispatcher)
-    dispatcher->RemoveServiceWorker(handle_ref_->handle_id());
+    dispatcher->RemoveServiceWorker(info_->handle_id);
 }
 
 }  // namespace content
diff --git a/content/renderer/service_worker/web_service_worker_impl.h b/content/renderer/service_worker/web_service_worker_impl.h
index 0bba378..9c4fd16c 100644
--- a/content/renderer/service_worker/web_service_worker_impl.h
+++ b/content/renderer/service_worker/web_service_worker_impl.h
@@ -13,6 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string16.h"
 #include "content/common/content_export.h"
+#include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorker.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 
@@ -22,21 +23,21 @@
 
 namespace content {
 
-class ServiceWorkerHandleReference;
 class ThreadSafeSender;
 
 // Each instance corresponds to one ServiceWorker object in JS context, and
 // is held by ServiceWorker object in Blink's C++ layer via
 // WebServiceWorker::Handle.
 //
-// Each instance holds one ServiceWorkerHandleReference so that
-// corresponding ServiceWorkerHandle doesn't go away in the browser process
-// while the ServiceWorker object is alive.
+// Each instance holds one Mojo connection for interface
+// blink::mojom::ServiceWorkerObjectHost inside |info_|, so the corresponding
+// ServiceWorkerHandle doesn't go away in the browser process while the
+// ServiceWorker object is alive.
 class CONTENT_EXPORT WebServiceWorkerImpl
     : public blink::WebServiceWorker,
       public base::RefCounted<WebServiceWorkerImpl> {
  public:
-  WebServiceWorkerImpl(std::unique_ptr<ServiceWorkerHandleReference> handle_ref,
+  WebServiceWorkerImpl(blink::mojom::ServiceWorkerObjectInfoPtr info,
                        ThreadSafeSender* thread_safe_sender);
 
   void OnStateChanged(blink::mojom::ServiceWorkerState new_state);
@@ -62,7 +63,7 @@
   friend class base::RefCounted<WebServiceWorkerImpl>;
   ~WebServiceWorkerImpl() override;
 
-  std::unique_ptr<ServiceWorkerHandleReference> handle_ref_;
+  blink::mojom::ServiceWorkerObjectInfoPtr info_;
   blink::mojom::ServiceWorkerState state_;
   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
   blink::WebServiceWorkerProxy* proxy_;
diff --git a/content/renderer/service_worker/web_service_worker_provider_impl.cc b/content/renderer/service_worker/web_service_worker_provider_impl.cc
index 8264f15..9a0fc62 100644
--- a/content/renderer/service_worker/web_service_worker_provider_impl.cc
+++ b/content/renderer/service_worker/web_service_worker_provider_impl.cc
@@ -12,7 +12,6 @@
 #include "content/child/thread_safe_sender.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/renderer/service_worker/service_worker_dispatcher.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/service_worker/web_service_worker_impl.h"
 #include "content/renderer/service_worker/web_service_worker_registration_impl.h"
@@ -64,9 +63,10 @@
   if (!provider_client_)
     return;
 
-  std::unique_ptr<ServiceWorkerHandleReference> controller =
+  blink::mojom::ServiceWorkerObjectInfoPtr controller =
       context_->TakeController();
-  if (!controller)
+  if (!controller ||
+      controller->handle_id == blink::mojom::kInvalidServiceWorkerHandleId)
     return;
   SetController(std::move(controller), context_->used_features(),
                 false /* notify_controllerchange */);
@@ -190,7 +190,7 @@
 }
 
 void WebServiceWorkerProviderImpl::SetController(
-    std::unique_ptr<ServiceWorkerHandleReference> controller,
+    blink::mojom::ServiceWorkerObjectInfoPtr controller,
     const std::set<blink::mojom::WebFeature>& features,
     bool should_notify_controller_change) {
   if (!provider_client_)
@@ -205,14 +205,14 @@
 }
 
 void WebServiceWorkerProviderImpl::PostMessageToClient(
-    std::unique_ptr<ServiceWorkerHandleReference> source_handle,
+    blink::mojom::ServiceWorkerObjectInfoPtr source,
     const base::string16& message,
     std::vector<mojo::ScopedMessagePipeHandle> message_pipes) {
   if (!provider_client_)
     return;
 
   scoped_refptr<WebServiceWorkerImpl> source_worker =
-      GetDispatcher()->GetOrCreateServiceWorker(std::move(source_handle));
+      GetDispatcher()->GetOrCreateServiceWorker(std::move(source));
   auto message_ports =
       blink::MessagePortChannel::CreateFromHandles(std::move(message_pipes));
   provider_client_->DispatchMessageEvent(
diff --git a/content/renderer/service_worker/web_service_worker_provider_impl.h b/content/renderer/service_worker/web_service_worker_provider_impl.h
index ef1ed83..1ff7906 100644
--- a/content/renderer/service_worker/web_service_worker_provider_impl.h
+++ b/content/renderer/service_worker/web_service_worker_provider_impl.h
@@ -25,7 +25,6 @@
 namespace content {
 
 class ServiceWorkerDispatcher;
-class ServiceWorkerHandleReference;
 class ServiceWorkerProviderContext;
 class ThreadSafeSender;
 
@@ -59,13 +58,13 @@
                                  blink::WebString* error_message) override;
   // Sets the ServiceWorkerContainer#controller for this provider. It's not
   // used when this WebServiceWorkerProvider is for a service worker context.
-  void SetController(std::unique_ptr<ServiceWorkerHandleReference> controller,
+  void SetController(blink::mojom::ServiceWorkerObjectInfoPtr controller,
                      const std::set<blink::mojom::WebFeature>& features,
                      bool should_notify_controller_change);
   // Posts a message to the ServiceWorkerContainer for this provider.
   // Corresponds to Client#postMessage().
   void PostMessageToClient(
-      std::unique_ptr<ServiceWorkerHandleReference> source_handle,
+      blink::mojom::ServiceWorkerObjectInfoPtr source,
       const base::string16& message,
       std::vector<mojo::ScopedMessagePipeHandle> message_pipes);
   // For UseCounter purposes. Called when the controller service worker used a
diff --git a/content/renderer/service_worker/web_service_worker_registration_impl.cc b/content/renderer/service_worker/web_service_worker_registration_impl.cc
index 0e769d0..9cca686 100644
--- a/content/renderer/service_worker/web_service_worker_registration_impl.cc
+++ b/content/renderer/service_worker/web_service_worker_registration_impl.cc
@@ -14,7 +14,6 @@
 #include "content/child/child_process.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/renderer/service_worker/service_worker_dispatcher.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/service_worker/web_service_worker_impl.h"
 #include "content/renderer/service_worker/web_service_worker_provider_impl.h"
@@ -148,6 +147,7 @@
                                 base::Unretained(impl.get()),
                                 std::move(impl->info_->request)));
   impl->state_ = LifecycleState::kAttachedAndBound;
+  impl->RefreshVersionAttributes();
   return impl;
 }
 
@@ -163,6 +163,7 @@
   impl->host_for_client_.Bind(std::move(impl->info_->host_ptr_info));
   impl->BindRequest(std::move(impl->info_->request));
   impl->state_ = LifecycleState::kAttachedAndBound;
+  impl->RefreshVersionAttributes();
   return impl;
 }
 
@@ -178,39 +179,7 @@
   DCHECK(!host_for_client_);
   host_for_client_.Bind(std::move(info_->host_ptr_info));
   state_ = LifecycleState::kAttachedAndBound;
-}
-
-void WebServiceWorkerRegistrationImpl::SetInstalling(
-    const scoped_refptr<WebServiceWorkerImpl>& service_worker) {
-  if (state_ == LifecycleState::kDetached)
-    return;
-  DCHECK_EQ(LifecycleState::kAttachedAndBound, state_);
-  if (proxy_)
-    proxy_->SetInstalling(WebServiceWorkerImpl::CreateHandle(service_worker));
-  else
-    queued_tasks_.push_back(QueuedTask(INSTALLING, service_worker));
-}
-
-void WebServiceWorkerRegistrationImpl::SetWaiting(
-    const scoped_refptr<WebServiceWorkerImpl>& service_worker) {
-  if (state_ == LifecycleState::kDetached)
-    return;
-  DCHECK_EQ(LifecycleState::kAttachedAndBound, state_);
-  if (proxy_)
-    proxy_->SetWaiting(WebServiceWorkerImpl::CreateHandle(service_worker));
-  else
-    queued_tasks_.push_back(QueuedTask(WAITING, service_worker));
-}
-
-void WebServiceWorkerRegistrationImpl::SetActive(
-    const scoped_refptr<WebServiceWorkerImpl>& service_worker) {
-  if (state_ == LifecycleState::kDetached)
-    return;
-  DCHECK_EQ(LifecycleState::kAttachedAndBound, state_);
-  if (proxy_)
-    proxy_->SetActive(WebServiceWorkerImpl::CreateHandle(service_worker));
-  else
-    queued_tasks_.push_back(QueuedTask(ACTIVE, service_worker));
+  RefreshVersionAttributes();
 }
 
 void WebServiceWorkerRegistrationImpl::SetProxy(
@@ -461,6 +430,66 @@
         registration_id_);
 }
 
+void WebServiceWorkerRegistrationImpl::SetInstalling(
+    blink::mojom::ServiceWorkerObjectInfoPtr info) {
+  if (state_ == LifecycleState::kDetached)
+    return;
+  DCHECK_EQ(LifecycleState::kAttachedAndBound, state_);
+
+  ServiceWorkerDispatcher* dispatcher =
+      ServiceWorkerDispatcher::GetThreadSpecificInstance();
+  DCHECK(dispatcher);
+  scoped_refptr<WebServiceWorkerImpl> service_worker =
+      dispatcher->GetOrCreateServiceWorker(std::move(info));
+  if (proxy_)
+    proxy_->SetInstalling(WebServiceWorkerImpl::CreateHandle(service_worker));
+  else
+    queued_tasks_.push_back(QueuedTask(INSTALLING, service_worker));
+}
+
+void WebServiceWorkerRegistrationImpl::SetWaiting(
+    blink::mojom::ServiceWorkerObjectInfoPtr info) {
+  if (state_ == LifecycleState::kDetached)
+    return;
+  DCHECK_EQ(LifecycleState::kAttachedAndBound, state_);
+
+  ServiceWorkerDispatcher* dispatcher =
+      ServiceWorkerDispatcher::GetThreadSpecificInstance();
+  DCHECK(dispatcher);
+  scoped_refptr<WebServiceWorkerImpl> service_worker =
+      dispatcher->GetOrCreateServiceWorker(std::move(info));
+  if (proxy_)
+    proxy_->SetWaiting(WebServiceWorkerImpl::CreateHandle(service_worker));
+  else
+    queued_tasks_.push_back(QueuedTask(WAITING, service_worker));
+}
+
+void WebServiceWorkerRegistrationImpl::SetActive(
+    blink::mojom::ServiceWorkerObjectInfoPtr info) {
+  if (state_ == LifecycleState::kDetached)
+    return;
+  DCHECK_EQ(LifecycleState::kAttachedAndBound, state_);
+
+  ServiceWorkerDispatcher* dispatcher =
+      ServiceWorkerDispatcher::GetThreadSpecificInstance();
+  DCHECK(dispatcher);
+  scoped_refptr<WebServiceWorkerImpl> service_worker =
+      dispatcher->GetOrCreateServiceWorker(std::move(info));
+  if (proxy_)
+    proxy_->SetActive(WebServiceWorkerImpl::CreateHandle(service_worker));
+  else
+    queued_tasks_.push_back(QueuedTask(ACTIVE, service_worker));
+}
+
+void WebServiceWorkerRegistrationImpl::RefreshVersionAttributes() {
+  DCHECK(info_->installing);
+  SetInstalling(std::move(info_->installing));
+  DCHECK(info_->waiting);
+  SetWaiting(std::move(info_->waiting));
+  DCHECK(info_->active);
+  SetActive(std::move(info_->active));
+}
+
 void WebServiceWorkerRegistrationImpl::SetVersionAttributes(
     int changed_mask,
     blink::mojom::ServiceWorkerObjectInfoPtr installing,
@@ -487,21 +516,15 @@
   ChangedVersionAttributesMask mask(changed_mask);
   if (mask.installing_changed()) {
     DCHECK(installing);
-    SetInstalling(dispatcher->GetOrCreateServiceWorker(
-        ServiceWorkerHandleReference::Adopt(std::move(installing),
-                                            dispatcher->thread_safe_sender())));
+    SetInstalling(std::move(installing));
   }
   if (mask.waiting_changed()) {
     DCHECK(waiting);
-    SetWaiting(dispatcher->GetOrCreateServiceWorker(
-        ServiceWorkerHandleReference::Adopt(std::move(waiting),
-                                            dispatcher->thread_safe_sender())));
+    SetWaiting(std::move(waiting));
   }
   if (mask.active_changed()) {
     DCHECK(active);
-    SetActive(dispatcher->GetOrCreateServiceWorker(
-        ServiceWorkerHandleReference::Adopt(std::move(active),
-                                            dispatcher->thread_safe_sender())));
+    SetActive(std::move(active));
   }
 }
 
diff --git a/content/renderer/service_worker/web_service_worker_registration_impl.h b/content/renderer/service_worker/web_service_worker_registration_impl.h
index 04dbd38..fedd009 100644
--- a/content/renderer/service_worker/web_service_worker_registration_impl.h
+++ b/content/renderer/service_worker/web_service_worker_registration_impl.h
@@ -17,6 +17,7 @@
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "third_party/WebKit/common/service_worker/service_worker_error_type.mojom.h"
+#include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
 #include "third_party/WebKit/common/service_worker/service_worker_registration.mojom.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRegistration.h"
 
@@ -94,10 +95,6 @@
   void AttachForServiceWorkerClient(
       blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info);
 
-  void SetInstalling(const scoped_refptr<WebServiceWorkerImpl>& service_worker);
-  void SetWaiting(const scoped_refptr<WebServiceWorkerImpl>& service_worker);
-  void SetActive(const scoped_refptr<WebServiceWorkerImpl>& service_worker);
-
   // blink::WebServiceWorkerRegistration overrides.
   void SetProxy(blink::WebServiceWorkerRegistrationProxy* proxy) override;
   blink::WebServiceWorkerRegistrationProxy* Proxy() override;
@@ -132,6 +129,13 @@
       base::WeakPtr<ServiceWorkerProviderContext> provider_context);
   ~WebServiceWorkerRegistrationImpl() override;
 
+  void SetInstalling(blink::mojom::ServiceWorkerObjectInfoPtr info);
+  void SetWaiting(blink::mojom::ServiceWorkerObjectInfoPtr info);
+  void SetActive(blink::mojom::ServiceWorkerObjectInfoPtr info);
+  // Refreshes the JavaScript ServiceWorkerRegistration object (|proxy_|) with
+  // the {installing,waiting,active} service worker object infos from |info_|.
+  void RefreshVersionAttributes();
+
   // Implements blink::mojom::ServiceWorkerRegistrationObject.
   void SetVersionAttributes(
       int changed_mask,
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index 0a4f82d..746ce45 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -22,7 +22,6 @@
 #include "content/renderer/loader/request_extra_data.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
-#include "content/renderer/service_worker/service_worker_handle_reference.h"
 #include "content/renderer/service_worker/service_worker_network_provider.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/service_worker/worker_fetch_context_impl.h"
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
index 9384f7b..d9846520 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
@@ -7,17 +7,16 @@
 import android.content.Context;
 
 import org.chromium.base.ApplicationStatus;
+import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
-import org.chromium.content.app.ContentApplication;
 
 /**
  * Entry point for the content shell application.  Handles initialization of information that needs
  * to be shared across the main activity and the child services created.
  */
-public class ContentShellApplication extends ContentApplication {
-
+public class ContentShellApplication extends BaseChromiumApplication {
     public static final String COMMAND_LINE_FILE = "/data/local/tmp/content-shell-command-line";
     private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "content_shell";
 
diff --git a/content/shell/browser/layout_test/layout_test_browser_main.cc b/content/shell/browser/layout_test/layout_test_browser_main.cc
index 289894f..90c85a0d 100644
--- a/content/shell/browser/layout_test/layout_test_browser_main.cc
+++ b/content/shell/browser/layout_test/layout_test_browser_main.cc
@@ -88,9 +88,8 @@
   std::cout << "#READY\n";
   std::cout.flush();
 
-  base::CommandLine::StringVector args =
-      base::CommandLine::ForCurrentProcess()->GetArgs();
-  content::TestInfoExtractor test_extractor(args);
+  content::TestInfoExtractor test_extractor(
+      *base::CommandLine::ForCurrentProcess());
   bool ran_at_least_once = false;
   std::unique_ptr<content::TestInfo> test_info;
   while ((test_info = test_extractor.GetNextTest())) {
diff --git a/content/shell/browser/layout_test/test_info_extractor.cc b/content/shell/browser/layout_test/test_info_extractor.cc
index 9804e95d..2f3aaa2 100644
--- a/content/shell/browser/layout_test/test_info_extractor.cc
+++ b/content/shell/browser/layout_test/test_info_extractor.cc
@@ -15,6 +15,14 @@
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "net/base/filename_util.h"
+#include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/url_util.h"
+
+#if defined(OS_FUCHSIA)
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
 
 namespace content {
 
@@ -42,6 +50,43 @@
 }
 #endif  // defined(OS_ANDROID)
 
+#if defined(OS_FUCHSIA)
+// Fuchsia doesn't support stdin stream for packaged apps. This means that when
+// running content_shell on Fuchsia it's not possible to use stdin to pass list
+// of tests. To workaround this issue for layout tests we redirect stdin stream
+// to a TCP socket connected to the layout test runner. The runner uses
+// --stdin-redirect to specify address and port for stdin redirection.
+constexpr char kStdinRedirectSwitch[] = "stdin-redirect";
+
+void ConnectStdinSocket(const std::string& host_and_port) {
+  std::string host;
+  int port;
+  net::IPAddress address;
+  if (!net::ParseHostAndPort(host_and_port, &host, &port) ||
+      !address.AssignFromIPLiteral(host)) {
+    LOG(FATAL) << "Invalid stdin address: " << host_and_port;
+  }
+
+  sockaddr_storage sockaddr_storage;
+  sockaddr* addr = reinterpret_cast<sockaddr*>(&sockaddr_storage);
+  socklen_t addr_len = sizeof(sockaddr_storage);
+  net::IPEndPoint endpoint(address, port);
+  bool converted = endpoint.ToSockAddr(addr, &addr_len);
+  CHECK(converted);
+
+  int fd = socket(addr->sa_family, SOCK_STREAM, 0);
+  PCHECK(fd >= 0);
+  int result = connect(fd, addr, addr_len);
+  PCHECK(result == 0) << "Failed to connect to " << host_and_port;
+
+  result = dup2(fd, STDIN_FILENO);
+  PCHECK(result == STDIN_FILENO) << "Failed to dup socket to stdin";
+
+  PCHECK(close(fd) == 0);
+}
+
+#endif  // defined(OS_FUCHSIA)
+
 std::unique_ptr<TestInfo> GetTestInfoFromLayoutTestName(
     const std::string& test_name) {
   // A test name is formated like file:///path/to/test'--pixel-test'pixelhash
@@ -116,9 +161,13 @@
       current_working_directory(current_working_directory) {}
 TestInfo::~TestInfo() {}
 
-TestInfoExtractor::TestInfoExtractor(
-    const base::CommandLine::StringVector& cmd_args)
-    : cmdline_args_(cmd_args), cmdline_position_(0) {}
+TestInfoExtractor::TestInfoExtractor(const base::CommandLine& cmd_line)
+    : cmdline_args_(cmd_line.GetArgs()), cmdline_position_(0) {
+#if defined(OS_FUCHSIA)
+  if (cmd_line.HasSwitch(kStdinRedirectSwitch))
+    ConnectStdinSocket(cmd_line.GetSwitchValueASCII(kStdinRedirectSwitch));
+#endif  // defined(OS_FUCHSIA)
+}
 
 TestInfoExtractor::~TestInfoExtractor() {}
 
diff --git a/content/shell/browser/layout_test/test_info_extractor.h b/content/shell/browser/layout_test/test_info_extractor.h
index 560e5c0..452c6fe59 100644
--- a/content/shell/browser/layout_test/test_info_extractor.h
+++ b/content/shell/browser/layout_test/test_info_extractor.h
@@ -32,7 +32,7 @@
 
 class TestInfoExtractor {
  public:
-  explicit TestInfoExtractor(const base::CommandLine::StringVector& cmd_args);
+  explicit TestInfoExtractor(const base::CommandLine& cmd_line);
   ~TestInfoExtractor();
 
   std::unique_ptr<TestInfo> GetNextTest();
diff --git a/content/shell/browser/shell_url_request_context_getter.cc b/content/shell/browser/shell_url_request_context_getter.cc
index 6afa9c8e..f8463618 100644
--- a/content/shell/browser/shell_url_request_context_getter.cc
+++ b/content/shell/browser/shell_url_request_context_getter.cc
@@ -34,13 +34,13 @@
 #include "net/http/http_network_session.h"
 #include "net/proxy/proxy_config_service.h"
 #include "net/proxy/proxy_service.h"
+#include "net/reporting/reporting_feature.h"
 #include "net/reporting/reporting_policy.h"
 #include "net/reporting/reporting_service.h"
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/default_channel_id_store.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
-#include "services/network/public/cpp/network_features.h"
 #include "services/network/public/cpp/network_switches.h"
 #include "url/url_constants.h"
 
diff --git a/content/shell/test_runner/event_sender.cc b/content/shell/test_runner/event_sender.cc
index 36a9fb8..69d72e2 100644
--- a/content/shell/test_runner/event_sender.cc
+++ b/content/shell/test_runner/event_sender.cc
@@ -41,6 +41,7 @@
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebPagePopup.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "ui/events/blink/blink_event_util.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
@@ -619,6 +620,7 @@
   void MouseScrollBy(gin::Arguments* args);
   void ScheduleAsynchronousClick(gin::Arguments* args);
   void ScheduleAsynchronousKeyDown(gin::Arguments* args);
+  void ConsumeUserActivation();
   void MouseDown(gin::Arguments* args);
   void MouseUp(gin::Arguments* args);
   void SetMouseButtonState(gin::Arguments* args);
@@ -753,6 +755,8 @@
                  &EventSenderBindings::ScheduleAsynchronousClick)
       .SetMethod("scheduleAsynchronousKeyDown",
                  &EventSenderBindings::ScheduleAsynchronousKeyDown)
+      .SetMethod("consumeUserActivation",
+                 &EventSenderBindings::ConsumeUserActivation)
       .SetProperty("forceLayoutOnEvents",
                    &EventSenderBindings::ForceLayoutOnEvents,
                    &EventSenderBindings::SetForceLayoutOnEvents)
@@ -1072,6 +1076,11 @@
                                        static_cast<KeyLocationCode>(location));
 }
 
+void EventSenderBindings::ConsumeUserActivation() {
+  if (sender_)
+    sender_->ConsumeUserActivation();
+}
+
 void EventSenderBindings::MouseDown(gin::Arguments* args) {
   if (!sender_)
     return;
@@ -2258,6 +2267,11 @@
                                   modifiers, location));
 }
 
+void EventSender::ConsumeUserActivation() {
+  blink::WebUserGestureIndicator::ConsumeUserGesture(
+      view()->MainFrame()->ToWebLocalFrame());
+}
+
 double EventSender::GetCurrentEventTimeSec() {
   return (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF() +
          time_offset_ms_ / 1000.0;
diff --git a/content/shell/test_runner/event_sender.h b/content/shell/test_runner/event_sender.h
index b401231f..8010338 100644
--- a/content/shell/test_runner/event_sender.h
+++ b/content/shell/test_runner/event_sender.h
@@ -172,6 +172,9 @@
   void ScheduleAsynchronousKeyDown(const std::string& code_str,
                                    int modifiers,
                                    KeyLocationCode location);
+  // Consumes the transient user activation state for follow-up tests that don't
+  // expect it.
+  void ConsumeUserActivation();
 
   double GetCurrentEventTimeSec();
 
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index b686f96..e418e79 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -188,12 +188,12 @@
     return;
   }
 
-  navigation_handle()->CallWillRedirectRequestForTesting(new_url, false, GURL(),
-                                                         false);
+  GetNavigationHandle()->CallWillRedirectRequestForTesting(new_url, false,
+                                                           GURL(), false);
 }
 
 void TestRenderFrameHost::SimulateNavigationCommit(const GURL& url) {
-  if (frame_tree_node()->navigation_request())
+  if (frame_tree_node_->navigation_request())
     PrepareForCommit();
 
   bool is_auto_subframe =
@@ -267,20 +267,20 @@
 }
 
 void TestRenderFrameHost::SimulateNavigationErrorPageCommit() {
-  CHECK(navigation_handle());
+  CHECK(GetNavigationHandle());
   GURL error_url = GURL(kUnreachableWebDataURL);
   OnDidStartProvisionalLoad(error_url, std::vector<GURL>(),
                             base::TimeTicks::Now());
   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   params.nav_entry_id = 0;
   params.did_create_new_entry = true;
-  params.url = navigation_handle()->GetURL();
+  params.url = GetNavigationHandle()->GetURL();
   params.transition = GetParent() ? ui::PAGE_TRANSITION_MANUAL_SUBFRAME
                                   : ui::PAGE_TRANSITION_LINK;
   params.was_within_same_document = false;
   params.url_is_unreachable = true;
-  params.page_state = PageState::CreateForTesting(navigation_handle()->GetURL(),
-                                                  false, nullptr, nullptr);
+  params.page_state = PageState::CreateForTesting(
+      GetNavigationHandle()->GetURL(), false, nullptr, nullptr);
   SendNavigateWithParams(&params);
 }
 
@@ -472,12 +472,12 @@
 void TestRenderFrameHost::SendNavigateWithParamsAndInterfaceProvider(
     FrameHostMsg_DidCommitProvisionalLoad_Params* params,
     service_manager::mojom::InterfaceProviderRequest request) {
-  if (navigation_handle()) {
+  if (GetNavigationHandle()) {
     scoped_refptr<net::HttpResponseHeaders> response_headers =
         new net::HttpResponseHeaders(std::string());
     response_headers->AddHeader(std::string("Content-Type: ") +
                                 contents_mime_type_);
-    navigation_handle()->set_response_headers_for_testing(response_headers);
+    GetNavigationHandle()->set_response_headers_for_testing(response_headers);
   }
   DidCommitProvisionalLoad(
       std::make_unique<FrameHostMsg_DidCommitProvisionalLoad_Params>(*params),
diff --git a/docs/testing/web_platform_tests.md b/docs/testing/web_platform_tests.md
index 269ece1..1b564ab 100644
--- a/docs/testing/web_platform_tests.md
+++ b/docs/testing/web_platform_tests.md
@@ -199,6 +199,9 @@
 account](https://help.github.com/articles/adding-an-email-address-to-your-github-account/)
 to link your exported commits to your GitHub profile.
 
+If you are a Googler, you can also register your GitHub account at go/github,
+making it easier for other Googlers to find you.
+
 ### What if there are conflicts?
 
 This cannot be avoided entirely as the two repositories are independent, but
diff --git a/docs/win_cross.md b/docs/win_cross.md
index 926a552..f1cfcd8 100644
--- a/docs/win_cross.md
+++ b/docs/win_cross.md
@@ -8,7 +8,7 @@
 
 * goma. Sorry. ([internal bug](http://b/64390790)) You can use the
   [jumbo build](jumbo.md) for faster build times.
-* mini_installer ([bug](https://crbug.com/762073))
+* renderer processes crash at startup ([bug](https://crbug.com/803591))
 * on Mac hosts, building a 32-bit chrome ([bug](https://crbug.com/794838))
 
 All other targets build fine (including `chrome`, `browser_tests`, ...).
@@ -51,6 +51,12 @@
 
     ninja -C out/gnwin base_unittests.exe
 
+## Copying and running chrome
+
+A convenient way to copy chrome over to a Windows box is to build the
+`mini_installer` target.  Then, copy just `mini_installer.exe` over
+to the Windows box and run it to install the chrome you just built.
+
 ## Running tests on swarming
 
 You can run the Windows binaries you built on swarming, like so:
diff --git a/extensions/browser/api/messaging/BUILD.gn b/extensions/browser/api/messaging/BUILD.gn
index 12a8e0f..2683c5a5f 100644
--- a/extensions/browser/api/messaging/BUILD.gn
+++ b/extensions/browser/api/messaging/BUILD.gn
@@ -25,6 +25,7 @@
   ]
 
   deps = [
+    "//base",
     "//content/public/browser",
     "//content/public/common",
     "//extensions/common",
diff --git a/extensions/renderer/resources/guest_view/guest_view_container.js b/extensions/renderer/resources/guest_view/guest_view_container.js
index 2ef77f4f..b0fda86b 100644
--- a/extensions/renderer/resources/guest_view/guest_view_container.js
+++ b/extensions/renderer/resources/guest_view/guest_view_container.js
@@ -58,7 +58,8 @@
     if (document.readyState == 'loading')
       return;
 
-    registerInternalElement(guestViewContainerType.VIEW_TYPE.toLowerCase());
+    registerInternalElement(
+        $String.toLowerCase(guestViewContainerType.VIEW_TYPE));
     registerGuestViewElement(guestViewContainerType);
     window.removeEventListener(event.type, listener, useCapture);
   }, useCapture);
@@ -292,10 +293,9 @@
     guestViewContainerType.setupElement(proto);
   }
 
-  window[guestViewContainerType.VIEW_TYPE] =
-      DocumentNatives.RegisterElement(
-          guestViewContainerType.VIEW_TYPE.toLowerCase(),
-          {prototype: proto});
+  window[guestViewContainerType.VIEW_TYPE] = DocumentNatives.RegisterElement(
+      $String.toLowerCase(guestViewContainerType.VIEW_TYPE),
+      {prototype: proto});
 
   // Delete the callbacks so developers cannot call them and produce unexpected
   // behavior.
diff --git a/extensions/renderer/resources/guest_view/guest_view_deny.js b/extensions/renderer/resources/guest_view/guest_view_deny.js
index 395594e..b6735604 100644
--- a/extensions/renderer/resources/guest_view/guest_view_deny.js
+++ b/extensions/renderer/resources/guest_view/guest_view_deny.js
@@ -23,14 +23,15 @@
 
 // Registers a GuestView custom element.
 function registerGuestViewElement(viewType) {
-  var proto = Object.create(HTMLElement.prototype);
+  var proto = $Object.create(HTMLElement.prototype);
 
   proto.createdCallback = function() {
-    window.console.error(ERROR_MESSAGE.replace(/%1/g, viewType.toLowerCase()));
+    window.console.error(
+        $String.replace(ERROR_MESSAGE, /%1/g, $String.toLowerCase(viewType)));
   };
 
-  window[viewType] = DocumentNatives.RegisterElement(viewType.toLowerCase(),
-                                                     {prototype: proto});
+  window[viewType] = DocumentNatives.RegisterElement(
+      $String.toLowerCase(viewType), {prototype: proto});
 
   // Delete the callbacks so developers cannot call them and produce unexpected
   // behavior.
diff --git a/extensions/renderer/resources/guest_view/guest_view_events.js b/extensions/renderer/resources/guest_view/guest_view_events.js
index 1417c23..869aaf8 100644
--- a/extensions/renderer/resources/guest_view/guest_view_events.js
+++ b/extensions/renderer/resources/guest_view/guest_view_events.js
@@ -160,7 +160,7 @@
 // Adds an 'on<event>' property on the view, which can be used to set/unset
 // an event handler.
 GuestViewEvents.prototype.setupEventProperty = function(eventName) {
-  var propertyName = 'on' + eventName.toLowerCase();
+  var propertyName = 'on' + $String.toLowerCase(eventName);
   $Object.defineProperty(this.view.element, propertyName, {
     get: $Function.bind(function() {
       return this.on[propertyName];
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view.js b/extensions/renderer/resources/guest_view/web_view/web_view.js
index 383c85c..718b82e 100644
--- a/extensions/renderer/resources/guest_view/web_view/web_view.js
+++ b/extensions/renderer/resources/guest_view/web_view/web_view.js
@@ -79,23 +79,19 @@
 
 // Sets the <webview>.request property.
 WebViewImpl.prototype.setRequestPropertyOnWebViewElement = function(request) {
-  Object.defineProperty(
-      this.element,
-      'request',
-      {
-        value: request,
-        enumerable: true
-      }
-  );
+  $Object.defineProperty(
+      this.element, 'request', {value: request, enumerable: true});
 };
 
 WebViewImpl.prototype.setupElementProperties = function() {
   // We cannot use {writable: true} property descriptor because we want a
   // dynamic getter value.
-  Object.defineProperty(this.element, 'contentWindow', {
-    get: $Function.bind(function() {
-      return this.guest.getContentWindow();
-    }, this),
+  $Object.defineProperty(this.element, 'contentWindow', {
+    get: $Function.bind(
+        function() {
+          return this.guest.getContentWindow();
+        },
+        this),
     // No setter.
     enumerable: true
   });
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
index 0fa17f0..d763e6c 100644
--- a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
+++ b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
@@ -141,9 +141,11 @@
 Dialog.prototype.showWarningMessage = function() {
   var VOWELS = ['a', 'e', 'i', 'o', 'u'];
   var dialogType = this.event.messageType;
-  var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A';
-  this.WARNING_MSG_REQUEST_BLOCKED = this.WARNING_MSG_REQUEST_BLOCKED.
-      replace('%1', article).replace('%2', dialogType);
+  var article =
+      ($Array.indexOf(VOWELS, dialogType.charAt(0)) >= 0) ? 'An' : 'A';
+  this.WARNING_MSG_REQUEST_BLOCKED = $String.replace(
+      $String.replace(this.WARNING_MSG_REQUEST_BLOCKED, '%1', article), '%2',
+      dialogType);
   window.console.warn(this.WARNING_MSG_REQUEST_BLOCKED);
 };
 
@@ -255,13 +257,13 @@
 };
 
 PermissionRequest.prototype.showWarningMessage = function() {
-  window.console.warn(
-      this.WARNING_MSG_REQUEST_BLOCKED.replace('%1', this.event.permission));
+  window.console.warn($String.replace(
+      this.WARNING_MSG_REQUEST_BLOCKED, '%1', this.event.permission));
 };
 
 // Checks that the requested permission is valid. Returns true if valid.
 PermissionRequest.prototype.validPermissionCheck = function() {
-  if (PERMISSION_TYPES.indexOf(this.event.permission) < 0) {
+  if ($Array.indexOf(PERMISSION_TYPES, this.event.permission) < 0) {
     // The permission type is not allowed. Trigger the default response.
     this.defaultAction();
     return false;
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_events.js b/extensions/renderer/resources/guest_view/web_view/web_view_events.js
index fb184ec..a689122 100644
--- a/extensions/renderer/resources/guest_view/web_view/web_view_events.js
+++ b/extensions/renderer/resources/guest_view/web_view/web_view_events.js
@@ -244,27 +244,16 @@
   for (var i = 0; i < DeclarativeWebRequestSchema.events.length; ++i) {
     var eventSchema = DeclarativeWebRequestSchema.events[i];
     var webRequestEvent = createDeclarativeWebRequestEvent(eventSchema);
-    Object.defineProperty(
-        request,
-        eventSchema.name,
-        {
-          get: webRequestEvent,
-          enumerable: true
-        }
-        );
+    $Object.defineProperty(
+        request, eventSchema.name, {get: webRequestEvent, enumerable: true});
   }
 
   // Populate the WebRequest events from the API definition.
   for (var i = 0; i < WebRequestSchema.events.length; ++i) {
     var webRequestEvent = createWebRequestEvent(WebRequestSchema.events[i]);
-    Object.defineProperty(
-        request,
-        WebRequestSchema.events[i].name,
-        {
-          get: webRequestEvent,
-          enumerable: true
-        }
-        );
+    $Object.defineProperty(
+        request, WebRequestSchema.events[i].name,
+        {get: webRequestEvent, enumerable: true});
   }
 
   this.view.setRequestPropertyOnWebViewElement(request);
@@ -291,8 +280,8 @@
   var showWarningMessage = function(code, reason) {
     var WARNING_MSG_LOAD_ABORTED = '<webview>: ' +
         'The load has aborted with error %1: %2.';
-    window.console.warn(
-        WARNING_MSG_LOAD_ABORTED.replace('%1', code).replace('%2', reason));
+    window.console.warn($String.replace(
+        $String.replace(WARNING_MSG_LOAD_ABORTED, '%1', code), '%2', reason));
   };
   var webViewEvent = this.makeDomEvent(event, eventName);
   if (this.view.dispatchEvent(webViewEvent)) {
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_request_custom_bindings.js b/extensions/renderer/resources/guest_view/web_view/web_view_request_custom_bindings.js
index db8b80f7..3fd27b58 100644
--- a/extensions/renderer/resources/guest_view/web_view/web_view_request_custom_bindings.js
+++ b/extensions/renderer/resources/guest_view/web_view/web_view_request_custom_bindings.js
@@ -42,7 +42,7 @@
   // Setup all data types for the declarative webRequest API from the schema.
   for (var i = 0; i < declarativeWebRequestSchema.types.length; ++i) {
     var typeSchema = declarativeWebRequestSchema.types[i];
-    var typeId = typeSchema.id.replace('declarativeWebRequest.', '');
+    var typeId = $String.replace(typeSchema.id, 'declarativeWebRequest.', '');
     var action = function(typeId) {
       return function(parameters) {
         setupInstance(this, parameters, typeId);
diff --git a/extensions/renderer/resources/web_request_event.js b/extensions/renderer/resources/web_request_event.js
index 8e55f5a..4a463fd7 100644
--- a/extensions/renderer/resources/web_request_event.js
+++ b/extensions/renderer/resources/web_request_event.js
@@ -84,7 +84,7 @@
 
   var subEvent = createSubEvent(subEventName, this.argSchemas);
   var subEventCallback = cb;
-  if (opt_extraInfo && opt_extraInfo.indexOf('blocking') >= 0) {
+  if (opt_extraInfo && $Array.indexOf(opt_extraInfo, 'blocking') >= 0) {
     var eventName = this.eventName;
     subEventCallback = function() {
       var requestId = arguments[0].requestId;
@@ -98,7 +98,8 @@
         throw e;
       }
     };
-  } else if (opt_extraInfo && opt_extraInfo.indexOf('asyncBlocking') >= 0) {
+  } else if (
+      opt_extraInfo && $Array.indexOf(opt_extraInfo, 'asyncBlocking') >= 0) {
     var eventName = this.eventName;
     subEventCallback = function() {
       var details = arguments[0];
diff --git a/extensions/renderer/safe_builtins.cc b/extensions/renderer/safe_builtins.cc
index 32fe256..24514d4 100644
--- a/extensions/renderer/safe_builtins.cc
+++ b/extensions/renderer/safe_builtins.cc
@@ -80,8 +80,8 @@
     "             'reverse'],\n"
     "            ['from', 'isArray']);\n"
     "saveBuiltin(String,\n"
-    "            ['indexOf', 'slice', 'split', 'substr', 'toUpperCase',\n"
-    "             'replace']);\n"
+    "            ['indexOf', 'slice', 'split', 'substr', 'toLowerCase',\n"
+    "             'toUpperCase', 'replace']);\n"
     "// Use exec rather than test to defend against clobbering in the\n"
     "// presence of ES2015 semantics, which read RegExp.prototype.exec.\n"
     "saveBuiltin(RegExp,\n"
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 3a21090..acc73ed5 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -396,10 +396,6 @@
 @property(nonatomic, strong)
     SigninInteractionCoordinator* signinInteractionCoordinator;
 
-// Activates browsing and enables web views if |enabled| is YES.
-// Disables browsing and purges web views if |enabled| is NO.
-// Must be called only on the main thread.
-- (void)setWebUsageEnabled:(BOOL)enabled;
 // Activates |mainBVC| and |otrBVC| and sets |currentBVC| as primary iff
 // |currentBVC| can be made active.
 - (void)activateBVCAndMakeCurrentBVCPrimary;
@@ -868,16 +864,6 @@
   return _browsingDataRemovalController;
 }
 
-- (void)setWebUsageEnabled:(BOOL)enabled {
-  DCHECK([NSThread isMainThread]);
-  if (enabled) {
-    [self activateBVCAndMakeCurrentBVCPrimary];
-  } else {
-    [self.mainBVC setActive:NO];
-    [self.otrBVC setActive:NO];
-  }
-}
-
 - (void)activateBVCAndMakeCurrentBVCPrimary {
   // If there are pending removal operations, the activation will be deferred
   // until the callback for |removeBrowsingDataFromBrowserState:| is received.
@@ -1539,6 +1525,23 @@
                      completion:nil];
 }
 
+- (void)prepareForBrowsingDataRemoval {
+  // Disables browsing and purges web views.
+  // Must be called only on the main thread.
+  DCHECK([NSThread isMainThread]);
+  [self.mainBVC setActive:NO];
+  [self.otrBVC setActive:NO];
+}
+
+- (void)browsingDataWasRemoved {
+  // Activates browsing and enables web views.
+  // Must be called only on the main thread.
+  DCHECK([NSThread isMainThread]);
+  [self.mainBVC setActive:YES];
+  [self.otrBVC setActive:YES];
+  [self.currentBVC setPrimary:YES];
+}
+
 #pragma mark - ApplicationSettingsCommands
 
 // TODO(crbug.com/779791) : Remove show settings from MainController.
@@ -2039,10 +2042,10 @@
   // TODO(crbug.com/632772): Remove web usage disabling once
   // https://bugs.webkit.org/show_bug.cgi?id=149079 has been fixed.
   if (mask & IOSChromeBrowsingDataRemover::REMOVE_SITE_DATA) {
-    [self setWebUsageEnabled:NO];
+    [self prepareForBrowsingDataRemoval];
   }
   ProceduralBlock browsingDataRemoved = ^{
-    [self setWebUsageEnabled:YES];
+    [self browsingDataWasRemoved];
     if (completionHandler) {
       completionHandler();
     }
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 9ed8bdc..63a3d6b 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1075,6 +1075,9 @@
       <message name="IDS_IOS_EXPORT_PASSWORDS_CANCEL_BUTTON" desc="Label of a confirmation dialog button which allows the user to cancel passwords export. [Length: 22em] [iOS only]">
         Cancel
       </message>
+      <message name="IDS_IOS_SETTINGS_EXPORT_PASSWORDS_SET_UP_SCREENLOCK_CONTENT" desc="Message informing the user that in order to export the passwords, a screen lock needs to be set up on the device. This is shown as an alert message after the user tries to view or copy the password from a settings page. [Length: about two lines]">
+        To export passwords, you must first set a passcode on your device.
+      </message>
       <message name="IDS_IOS_SAVE_PASSWORDS_MANAGE_ACCOUNT" desc="Header text with link for the view in Settings for managing saved passwords. [Length: unlimited] [iOS only]">
         View and manage saved passwords at <ph name="BEGIN_LINK">BEGIN_LINK</ph>passwords.google.com<ph name="END_LINK">END_LINK</ph>
       </message>
diff --git a/ios/chrome/app/tests_fake_hook.mm b/ios/chrome/app/tests_fake_hook.mm
index e58ad5da..da4a92e59 100644
--- a/ios/chrome/app/tests_fake_hook.mm
+++ b/ios/chrome/app/tests_fake_hook.mm
@@ -28,7 +28,7 @@
 bool DisableUpdateService() {
   return false;
 }
-bool ForceAdaptiveToolbar() {
+bool ForceUIRefreshPhase1() {
   return false;
 }
 void SetUpTestsIfPresent() {}
diff --git a/ios/chrome/app/tests_hook.h b/ios/chrome/app/tests_hook.h
index 92d074e..afd241f 100644
--- a/ios/chrome/app/tests_hook.h
+++ b/ios/chrome/app/tests_hook.h
@@ -32,9 +32,9 @@
 bool DisableUpdateService();
 
 // TODO(crbug.com/800266): Removes this hook.
-// Returns true if the AdaptiveToolbar UI should be displayed, overriding the
-// flag value.
-bool ForceAdaptiveToolbar();
+// Returns true if the first phase of the UI refresh will be displayed,
+// overriding the flag value.
+bool ForceUIRefreshPhase1();
 
 // Global integration tests setup.  This is not used by EarlGrey-based
 // integration tests.
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 5cd66987..28d3d32 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -112,13 +112,13 @@
     "//components/webdata_services",
     "//google_apis",
     "//ios/chrome/app/strings",
-    "//ios/chrome/browser/bookmarks:features",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/download",
     "//ios/chrome/browser/drag_and_drop",
     "//ios/chrome/browser/payments:constants",
     "//ios/chrome/browser/ssl:features",
     "//ios/chrome/browser/sync/glue",
+    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/activity_services:features",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/external_search:features",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 7c922d25..2310565 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -36,7 +36,6 @@
 #include "components/security_state/core/features.h"
 #include "components/signin/core/browser/signin_switches.h"
 #include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/bookmarks/bookmark_new_generation_features.h"
 #include "ios/chrome/browser/chrome_switches.h"
 #include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
 #include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
@@ -49,6 +48,7 @@
 #import "ios/chrome/browser/ui/omnibox/omnibox_clipping_feature.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h"
+#include "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/web/public/features.h"
@@ -217,9 +217,6 @@
     {"clipping-textfield", flag_descriptions::kClippingTextfieldName,
      flag_descriptions::kClippingTextfieldDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kClippingTextfield)},
-    {"bookmark-new-edit-page", flag_descriptions::kBookmarkNewEditPageName,
-     flag_descriptions::kBookmarkNewEditPageDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kBookmarkNewEditPage)},
     {"PasswordExport", flag_descriptions::kPasswordExportName,
      flag_descriptions::kPasswordExportDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(password_manager::features::kPasswordExport)},
@@ -232,9 +229,10 @@
      flag_descriptions::kShowAutofillTypePredictionsDescription,
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillShowTypePredictions)},
-    {"adaptive-toolbar", flag_descriptions::kAdaptiveToolbarName,
-     flag_descriptions::kAdaptiveToolbarDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kAdaptiveToolbar)},
+    {"ui-refresh-phase-1", flag_descriptions::kUIRefreshPhase1Name,
+     flag_descriptions::kUIRefreshPhase1Description, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kUIRefreshPhase1)},
+
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/bookmarks/BUILD.gn b/ios/chrome/browser/bookmarks/BUILD.gn
index c8f8059..1581e81 100644
--- a/ios/chrome/browser/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/bookmarks/BUILD.gn
@@ -50,13 +50,3 @@
     "//ios/chrome/browser/browser_state",
   ]
 }
-
-source_set("features") {
-  sources = [
-    "bookmark_new_generation_features.cc",
-    "bookmark_new_generation_features.h",
-  ]
-  deps = [
-    "//base",
-  ]
-}
diff --git a/ios/chrome/browser/bookmarks/bookmark_new_generation_features.cc b/ios/chrome/browser/bookmarks/bookmark_new_generation_features.cc
deleted file mode 100644
index 79f004a1e..0000000
--- a/ios/chrome/browser/bookmarks/bookmark_new_generation_features.cc
+++ /dev/null
@@ -1,9 +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.
-
-#include "ios/chrome/browser/bookmarks/bookmark_new_generation_features.h"
-
-// Feature flag for the new edit page and folder picker of the new bookmark UI.
-const base::Feature kBookmarkNewEditPage{"BookmarkNewEditPage",
-                                         base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/bookmarks/bookmark_new_generation_features.h b/ios/chrome/browser/bookmarks/bookmark_new_generation_features.h
deleted file mode 100644
index ffe8bac94..0000000
--- a/ios/chrome/browser/bookmarks/bookmark_new_generation_features.h
+++ /dev/null
@@ -1,14 +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.
-
-#ifndef IOS_CHROME_BROWSER_BOOKMARKS_BOOKMARK_NEW_GENERATION_FEATURES_H
-#define IOS_CHROME_BROWSER_BOOKMARKS_BOOKMARK_NEW_GENERATION_FEATURES_H
-
-#include "base/feature_list.h"
-#include "build/build_config.h"
-
-// Feature flag for the new edit page and folder picker of the new bookmark UI.
-extern const base::Feature kBookmarkNewEditPage;
-
-#endif  // IOS_CHROME_BROWSER_BOOKMARKS_BOOKMARK_NEW_GENERATION_FEATURES_H
diff --git a/ios/chrome/browser/browsing_data/BUILD.gn b/ios/chrome/browser/browsing_data/BUILD.gn
index 9cb5519a..0bc1a65 100644
--- a/ios/chrome/browser/browsing_data/BUILD.gn
+++ b/ios/chrome/browser/browsing_data/BUILD.gn
@@ -99,7 +99,6 @@
     "//ios/chrome/browser/sessions:serialisation",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/snapshots",
-    "//ios/chrome/browser/ui:ui_internal",
     "//ios/web",
     "//net",
   ]
diff --git a/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm b/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
index a596b31..72bb13f 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
+++ b/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
@@ -25,7 +25,6 @@
 #include "ios/chrome/browser/sessions/session_util.h"
 #include "ios/chrome/browser/signin/account_consistency_service_factory.h"
 #import "ios/chrome/browser/snapshots/snapshots_util.h"
-#import "ios/chrome/browser/ui/browser_view_controller.h"
 #import "ios/chrome/browser/ui/external_file_remover.h"
 #import "ios/chrome/browser/ui/external_file_remover_factory.h"
 #include "ios/web/public/web_thread.h"
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index aa7293e5..6c797e0b 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -11,15 +11,6 @@
 
 namespace flag_descriptions {
 
-const char kAdaptiveToolbarName[] = "Adaptive Toolbar";
-const char kAdaptiveToolbarDescription[] =
-    "When enabled, the adaptive toolbar will be used.";
-
-const char kBookmarkNewEditPageName[] = "Bookmark New Edit Page";
-const char kBookmarkNewEditPageDescription[] =
-    "When enabled, the new bookmark edit page and folder picker will be used "
-    "in the new bookmark UI.";
-
 const char kBrowserTaskScheduler[] = "Task Scheduler";
 const char kBrowserTaskSchedulerDescription[] =
     "Enables redirection of some task posting APIs to the task scheduler.";
@@ -137,6 +128,10 @@
     "BVC is visible, the tab switcher will remain in the VC hierarchy "
     "underneath it.";
 
+const char kUIRefreshPhase1Name[] = "UI Refresh Phase 1";
+const char kUIRefreshPhase1Description[] =
+    "When enabled, the first phase of the iOS UI refresh will be displayed.";
+
 const char kUseDdljsonApiName[] = "Use new ddljson API for Doodles";
 const char kUseDdljsonApiDescription[] =
     "Enables the new ddljson API to fetch Doodles for the NTP.";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index 80e714c..5d39da99 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -7,15 +7,6 @@
 
 namespace flag_descriptions {
 
-// Title and description for the flag to enable the adaptive toolbar.
-extern const char kAdaptiveToolbarName[];
-extern const char kAdaptiveToolbarDescription[];
-
-// Title and description for the flag to enable the new bookmark edit page in
-// the new bookmark UI.
-extern const char kBookmarkNewEditPageName[];
-extern const char kBookmarkNewEditPageDescription[];
-
 // Title and description for the flag to control redirection to the task
 // scheduler.
 extern const char kBrowserTaskScheduler[];
@@ -126,6 +117,10 @@
 extern const char kTabSwitcherPresentsBVCName[];
 extern const char kTabSwitcherPresentsBVCDescription[];
 
+// Title and description for the flag to enable the phase 1 UI Refresh.
+extern const char kUIRefreshPhase1Name[];
+extern const char kUIRefreshPhase1Description[];
+
 // Title and description for the flag to enable the ddljson Doodle API.
 extern const char kUseDdljsonApiName[];
 extern const char kUseDdljsonApiDescription[];
diff --git a/ios/chrome/browser/metrics/ukm_egtest.mm b/ios/chrome/browser/metrics/ukm_egtest.mm
index da1734e..b789f596 100644
--- a/ios/chrome/browser/metrics/ukm_egtest.mm
+++ b/ios/chrome/browser/metrics/ukm_egtest.mm
@@ -181,6 +181,13 @@
   [ChromeEarlGrey waitForMainTabCount:(tab_count + 1)];
 }
 
+// Grant/revoke metrics consent and update MetricsServicesManager.
+void UpdateMetricsConsent(bool new_state) {
+  g_metrics_enabled = new_state;
+  GetApplicationContext()->GetMetricsServicesManager()->UpdateUploadPermissions(
+      true);
+}
+
 // Signs in to sync.
 void SignIn() {
   ChromeIdentity* identity = [SigninEarlGreyUtils fakeIdentity1];
@@ -287,6 +294,9 @@
   [super tearDown];
 }
 
+// The tests in this file should correspond with the ones in
+// //chrome/browser/metrics/ukm_browsertest.cc
+
 // Make sure that UKM is disabled while an incognito tab is open.
 - (void)testRegularPlusIncognito {
   uint64_t original_client_id = metrics::UkmEGTestHelper::client_id();
@@ -312,28 +322,41 @@
              @"Client ID was reset.");
 }
 
-// Make sure that UKM is disabled when sync is not enabled.
-- (void)testNoSync {
+// TODO(crbug.com/792933): Implement testIncognitoPlusRegular
+
+// testOpenNonSync not needed, since there can't be multiple profiles.
+
+// Make sure that UKM is disabled when metrics consent is revoked.
+- (void)testMetricsConsent {
   uint64_t original_client_id = metrics::UkmEGTestHelper::client_id();
 
-  SignOut();
+  UpdateMetricsConsent(false);
 
   AssertUKMEnabled(false);
-  // Client ID should have been reset by signout.
-  GREYAssert(original_client_id != metrics::UkmEGTestHelper::client_id(),
-             @"Client ID was not reset.");
 
-  original_client_id = metrics::UkmEGTestHelper::client_id();
-  SignInWithPromo();
+  UpdateMetricsConsent(true);
 
   AssertUKMEnabled(true);
-  // Client ID should not have been reset.
-  GREYAssert(original_client_id == metrics::UkmEGTestHelper::client_id(),
-             @"Client ID was reset.");
+  // Client ID should have been reset.
+  GREYAssert(original_client_id != metrics::UkmEGTestHelper::client_id(),
+             @"Client ID was not reset.");
+}
+
+// Make sure that providing metrics consent doesn't enable UKM w/o sync.
+- (void)testConsentAddedButNoSync {
+  SignOut();
+  UpdateMetricsConsent(false);
+  AssertUKMEnabled(false);
+
+  UpdateMetricsConsent(true);
+  AssertUKMEnabled(false);
+
+  SignInWithPromo();
+  AssertUKMEnabled(true);
 }
 
 // Make sure that UKM is disabled when sync is disabled.
-- (void)testDisableSync {
+- (void)testSingleDisableSync {
   uint64_t original_client_id = metrics::UkmEGTestHelper::client_id();
 
   [ChromeEarlGreyUI openSettingsMenu];
@@ -377,28 +400,34 @@
       performAction:grey_tap()];
 }
 
-// Make sure that UKM is disabled when metrics consent is revoked.
-- (void)testNoConsent {
+// testMultiDisableSync not needed, since there can't be multiple profiles.
+
+// TODO(crbug.com/793082): Implement testSecondaryPassphrase.
+
+// Make sure that UKM is disabled when sync is not enabled.
+- (void)testSingleSyncSignout {
   uint64_t original_client_id = metrics::UkmEGTestHelper::client_id();
 
-  // Revoke metrics consent and update MetricsServicesManager.
-  g_metrics_enabled = false;
-  GetApplicationContext()->GetMetricsServicesManager()->UpdateUploadPermissions(
-      true);
+  SignOut();
 
   AssertUKMEnabled(false);
-
-  // Grant metrics consent and update MetricsServicesManager.
-  g_metrics_enabled = true;
-  GetApplicationContext()->GetMetricsServicesManager()->UpdateUploadPermissions(
-      true);
-
-  AssertUKMEnabled(true);
-  // Client ID should have been reset.
+  // Client ID should have been reset by signout.
   GREYAssert(original_client_id != metrics::UkmEGTestHelper::client_id(),
              @"Client ID was not reset.");
+
+  original_client_id = metrics::UkmEGTestHelper::client_id();
+  SignInWithPromo();
+
+  AssertUKMEnabled(true);
+  // Client ID should not have been reset.
+  GREYAssert(original_client_id == metrics::UkmEGTestHelper::client_id(),
+             @"Client ID was reset.");
 }
 
+// testMultiSyncSignout not needed, since there can't be multiple profiles.
+
+// testMetricsReporting not needed, since iOS doesn't use sampling.
+
 - (void)testHistoryDelete {
   uint64_t original_client_id = metrics::UkmEGTestHelper::client_id();
 
diff --git a/ios/chrome/browser/signin/BUILD.gn b/ios/chrome/browser/signin/BUILD.gn
index 6740511..fddf120 100644
--- a/ios/chrome/browser/signin/BUILD.gn
+++ b/ios/chrome/browser/signin/BUILD.gn
@@ -57,6 +57,7 @@
     "//base",
     "//components/browser_sync",
     "//components/content_settings/core/browser",
+    "//components/image_fetcher/ios",
     "//components/keyed_service/core",
     "//components/keyed_service/ios",
     "//components/metrics",
diff --git a/ios/chrome/browser/signin/account_fetcher_service_factory.cc b/ios/chrome/browser/signin/account_fetcher_service_factory.cc
index 74b02d24..147bf7f 100644
--- a/ios/chrome/browser/signin/account_fetcher_service_factory.cc
+++ b/ios/chrome/browser/signin/account_fetcher_service_factory.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/memory/singleton.h"
+#include "components/image_fetcher/ios/ios_image_decoder_impl.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/signin/core/browser/account_fetcher_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
@@ -54,7 +55,8 @@
   service->Initialize(
       SigninClientFactory::GetForBrowserState(browser_state),
       OAuth2TokenServiceFactory::GetForBrowserState(browser_state),
-      ios::AccountTrackerServiceFactory::GetForBrowserState(browser_state));
+      ios::AccountTrackerServiceFactory::GetForBrowserState(browser_state),
+      image_fetcher::CreateIOSImageDecoder());
   return service;
 }
 
diff --git a/ios/chrome/browser/tabs/tab.h b/ios/chrome/browser/tabs/tab.h
index 696f42f..35492ef2 100644
--- a/ios/chrome/browser/tabs/tab.h
+++ b/ios/chrome/browser/tabs/tab.h
@@ -103,9 +103,6 @@
 @property(nonatomic, readonly) id<FindInPageControllerDelegate>
     findInPageControllerDelegate;
 
-// Whether or not desktop user agent is used for the currently visible page.
-@property(nonatomic, readonly) BOOL usesDesktopUserAgent;
-
 // The delegate to use for the legacy fullscreen controller.  It should not be
 // set if the new fullscreen is enabled.
 // TODO(crbug.com/778823): Remove this property.
@@ -171,15 +168,6 @@
 // Updates the timestamp of the last time the tab is visited.
 - (void)updateLastVisitedTimestamp;
 
-// Loads the original url of the last non-redirect item (including non-history
-// items). Used by request desktop/mobile site so that the updated user agent is
-// used.
-- (void)reloadWithUserAgentType:(web::UserAgentType)userAgentType;
-
-// Ensures the toolbar visibility matches |visible|.
-// TODO(crbug.com/778823): Remove this code.
-- (void)updateFullscreenWithToolbarVisible:(BOOL)visible;
-
 // Called when this tab is shown.
 - (void)wasShown;
 
@@ -189,6 +177,18 @@
 // Called before capturing a snapshot for Tab.
 - (void)willUpdateSnapshot;
 
+// Ensures the toolbar visibility matches |visible|.
+// TODO(crbug.com/778823): Remove this code.
+- (void)updateFullscreenWithToolbarVisible:(BOOL)visible;
+
+// Whether or not desktop user agent is used for the currently visible page.
+@property(nonatomic, readonly) BOOL usesDesktopUserAgent;
+
+// Loads the original url of the last non-redirect item (including non-history
+// items). Used by request desktop/mobile site so that the updated user agent is
+// used.
+- (void)reloadWithUserAgentType:(web::UserAgentType)userAgentType;
+
 // Evaluates U2F result.
 - (void)evaluateU2FResultFromURL:(const GURL&)url;
 
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index bc86765..72c5802 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -34,7 +34,6 @@
 #include "components/infobars/core/infobar_manager.h"
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/metrics_services_manager/metrics_services_manager.h"
-#include "components/navigation_metrics/navigation_metrics.h"
 #include "components/prefs/pref_service.h"
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/search_engines/template_url_service.h"
@@ -46,10 +45,8 @@
 #import "ios/chrome/browser/autofill/form_suggestion_tab_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#import "ios/chrome/browser/crash_loop_detection_util.h"
 #include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/find_in_page/find_in_page_controller.h"
-#import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/history/history_tab_helper.h"
 #include "ios/chrome/browser/history/top_sites_factory.h"
@@ -183,11 +180,6 @@
 // Handles exportable files if possible.
 - (void)handleExportableFile:(net::HttpResponseHeaders*)headers;
 
-// Returns YES if TabUsageRecorder::RecordPageLoadStart should be called for the
-// given navigation.
-- (BOOL)shouldRecordPageLoadStartForNavigation:
-    (web::NavigationContext*)navigation;
-
 @end
 
 @implementation Tab
@@ -203,6 +195,8 @@
 @synthesize legacyFullscreenControllerDelegate =
     legacyFullscreenControllerDelegate_;
 
+#pragma mark - Initializers
+
 - (instancetype)initWithWebState:(web::WebState*)webState {
   DCHECK(webState);
   self = [super init];
@@ -222,51 +216,21 @@
   return self;
 }
 
+#pragma mark - NSObject protocol
+
 - (void)dealloc {
   // The WebState owns the Tab, so -webStateDestroyed: should be called before
   // -dealloc and _webStateImpl set to nullptr.
   DCHECK(!_webStateImpl);
 }
 
-- (id<FindInPageControllerDelegate>)findInPageControllerDelegate {
-  return self;
-}
-
-- (void)setParentTabModel:(TabModel*)model {
-  DCHECK(!model || !_parentTabModel);
-  _parentTabModel = model;
-}
-
 - (NSString*)description {
   return
       [NSString stringWithFormat:@"%p ... %@ - %s", self, self.title,
                                  self.webState->GetVisibleURL().spec().c_str()];
 }
 
-- (id<TabDialogDelegate>)dialogDelegate {
-  return dialogDelegate_;
-}
-
-- (BOOL)loadFinished {
-  return self.webState && !self.webState->IsLoading();
-}
-
-- (BOOL)isVoiceSearchResultsTab {
-  // TODO(crbug.com/778416): Move this logic entirely into helper.
-  // If nothing has been loaded in the Tab, it cannot be displaying a voice
-  // search results page.
-  web::NavigationItem* item =
-      self.webState->GetNavigationManager()->GetVisibleItem();
-  if (!item)
-    return NO;
-  // Navigating through history to a NavigationItem that was created for a voice
-  // search query should just be treated like a normal page load.
-  if ((item->GetTransitionType() & ui::PAGE_TRANSITION_FORWARD_BACK) != 0)
-    return NO;
-  // Check whether |item| has been marked as a voice search result navigation.
-  return VoiceSearchNavigationTabHelper::FromWebState(self.webState)
-      ->IsNavigationFromVoiceSearch(item);
-}
+#pragma mark - Properties
 
 - (NSString*)title {
   base::string16 title = self.webState->GetTitle();
@@ -297,28 +261,16 @@
   return _webStateImpl;
 }
 
-- (UIView*)view {
-  if (!self.webState)
-    return nil;
-
-  // Record reload of previously-evicted tab.
-  if (self.webState->IsEvicted() && [_parentTabModel tabUsageRecorder])
-    [_parentTabModel tabUsageRecorder]->RecordPageLoadStart(self.webState);
-
-  // Do not trigger the load if the tab has crashed. SadTabTabHelper is
-  // responsible for handing reload logic for crashed tabs.
-  if (!self.webState->IsCrashed()) {
-    self.webState->GetNavigationManager()->LoadIfNecessary();
-  }
-  return self.webState->GetView();
+- (BOOL)canGoBack {
+  return self.navigationManager && self.navigationManager->CanGoBack();
 }
 
-- (UIView*)viewForPrinting {
-  return self.webController.viewForPrinting;
+- (BOOL)canGoForward {
+  return self.navigationManager && self.navigationManager->CanGoForward();
 }
 
-- (web::NavigationManager*)navigationManager {
-  return self.webState ? self.webState->GetNavigationManager() : nullptr;
+- (id<FindInPageControllerDelegate>)findInPageControllerDelegate {
+  return self;
 }
 
 - (void)setLegacyFullscreenControllerDelegate:
@@ -368,11 +320,279 @@
   overscrollActionsControllerDelegate_ = overscrollActionsControllerDelegate;
 }
 
+- (BOOL)isVoiceSearchResultsTab {
+  // TODO(crbug.com/778416): Move this logic entirely into helper.
+  // If nothing has been loaded in the Tab, it cannot be displaying a voice
+  // search results page.
+  web::NavigationItem* item =
+      self.webState->GetNavigationManager()->GetVisibleItem();
+  if (!item)
+    return NO;
+  // Navigating through history to a NavigationItem that was created for a voice
+  // search query should just be treated like a normal page load.
+  if ((item->GetTransitionType() & ui::PAGE_TRANSITION_FORWARD_BACK) != 0)
+    return NO;
+  // Check whether |item| has been marked as a voice search result navigation.
+  return VoiceSearchNavigationTabHelper::FromWebState(self.webState)
+      ->IsNavigationFromVoiceSearch(item);
+}
+
+- (BOOL)loadFinished {
+  return self.webState && !self.webState->IsLoading();
+}
+
+#pragma mark - Public API
+
+- (void)setParentTabModel:(TabModel*)model {
+  DCHECK(!model || !_parentTabModel);
+  _parentTabModel = model;
+}
+
+- (UIView*)view {
+  if (!self.webState)
+    return nil;
+
+  // Record reload of previously-evicted tab.
+  if (self.webState->IsEvicted() && [_parentTabModel tabUsageRecorder])
+    [_parentTabModel tabUsageRecorder]->RecordPageLoadStart(self.webState);
+
+  // Do not trigger the load if the tab has crashed. SadTabTabHelper is
+  // responsible for handing reload logic for crashed tabs.
+  if (!self.webState->IsCrashed()) {
+    self.webState->GetNavigationManager()->LoadIfNecessary();
+  }
+  return self.webState->GetView();
+}
+
+- (UIView*)viewForPrinting {
+  return self.webController.viewForPrinting;
+}
+
 // Halt the tab, which amounts to halting its webController.
 - (void)terminateNetworkActivity {
   [self.webController terminateNetworkActivity];
 }
 
+- (void)dismissModals {
+  [_openInController disable];
+  [self.webController dismissModals];
+}
+
+- (web::NavigationManager*)navigationManager {
+  return self.webState ? self.webState->GetNavigationManager() : nullptr;
+}
+
+- (void)goToItem:(const web::NavigationItem*)item {
+  DCHECK(item);
+  int index = self.navigationManager->GetIndexOfItem(item);
+  DCHECK_NE(index, -1);
+  self.navigationManager->GoToIndex(index);
+}
+
+- (void)goBack {
+  if (self.navigationManager) {
+    DCHECK(self.navigationManager->CanGoBack());
+    base::RecordAction(base::UserMetricsAction("Back"));
+    self.navigationManager->GoBack();
+  }
+}
+
+- (void)goForward {
+  if (self.navigationManager) {
+    DCHECK(self.navigationManager->CanGoForward());
+    base::RecordAction(base::UserMetricsAction("Forward"));
+    self.navigationManager->GoForward();
+  }
+}
+
+- (double)lastVisitedTimestamp {
+  return _lastVisitedTimestamp;
+}
+
+- (void)updateLastVisitedTimestamp {
+  _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970];
+}
+
+- (void)wasShown {
+  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
+    [self updateFullscreenWithToolbarVisible:YES];
+  }
+  if (self.webState)
+    self.webState->WasShown();
+}
+
+- (void)wasHidden {
+  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
+    [self updateFullscreenWithToolbarVisible:YES];
+  }
+  if (self.webState)
+    self.webState->WasHidden();
+}
+
+- (void)willUpdateSnapshot {
+  [_overscrollActionsController clear];
+}
+
+#pragma mark - Public API (relating to Fullscreen)
+
+- (void)updateFullscreenWithToolbarVisible:(BOOL)visible {
+  DCHECK(!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen));
+  [_legacyFullscreenController moveHeaderToRestingPosition:visible];
+}
+
+#pragma mark - Public API (relatinge to User agent)
+
+- (BOOL)usesDesktopUserAgent {
+  if (!self.navigationManager)
+    return NO;
+
+  web::NavigationItem* visibleItem = self.navigationManager->GetVisibleItem();
+  return visibleItem &&
+         visibleItem->GetUserAgentType() == web::UserAgentType::DESKTOP;
+}
+
+- (void)reloadWithUserAgentType:(web::UserAgentType)userAgentType {
+  // This removes the web view, which will be recreated at the end of this.
+  [self.webController requirePageReconstruction];
+
+  // TODO(crbug.com/228171): A hack in session_controller -addPendingItem
+  // discusses making tab responsible for distinguishing history stack
+  // navigation from new navigations.
+  web::NavigationManager* navigationManager = [self navigationManager];
+  DCHECK(navigationManager);
+
+  web::NavigationItem* lastNonRedirectItem =
+      navigationManager->GetTransientItem();
+  if (!lastNonRedirectItem || IsItemRedirectItem(lastNonRedirectItem))
+    lastNonRedirectItem = navigationManager->GetVisibleItem();
+  if (!lastNonRedirectItem || IsItemRedirectItem(lastNonRedirectItem))
+    lastNonRedirectItem = GetLastCommittedNonRedirectedItem(navigationManager);
+
+  if (!lastNonRedirectItem)
+    return;
+
+  // |reloadURL| will be empty if a page was open by DOM.
+  GURL reloadURL(lastNonRedirectItem->GetOriginalRequestURL());
+  if (reloadURL.is_empty()) {
+    DCHECK(self.webState && self.webState->HasOpener());
+    reloadURL = lastNonRedirectItem->GetVirtualURL();
+  }
+
+  web::NavigationManager::WebLoadParams params(reloadURL);
+  params.referrer = lastNonRedirectItem->GetReferrer();
+  params.transition_type = ui::PAGE_TRANSITION_RELOAD;
+
+  switch (userAgentType) {
+    case web::UserAgentType::DESKTOP:
+      params.user_agent_override_option =
+          web::NavigationManager::UserAgentOverrideOption::DESKTOP;
+      break;
+    case web::UserAgentType::MOBILE:
+      params.user_agent_override_option =
+          web::NavigationManager::UserAgentOverrideOption::MOBILE;
+      break;
+    case web::UserAgentType::NONE:
+      NOTREACHED();
+  }
+
+  navigationManager->LoadURLWithParams(params);
+}
+
+#pragma mark - Public API (relating to U2F)
+
+- (void)evaluateU2FResultFromURL:(const GURL&)URL {
+  DCHECK(_secondFactorController);
+  [_secondFactorController evaluateU2FResultFromU2FURL:URL
+                                              webState:self.webState];
+}
+
+#pragma mark - FindInPageControllerDelegate protocol
+
+- (void)willAdjustScrollPosition {
+  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
+    // Skip the next attempt to correct the scroll offset for the toolbar
+    // height.  Used when programatically scrolling down the y offset.
+    [_legacyFullscreenController shouldSkipNextScrollOffsetForHeader];
+  }
+}
+
+#pragma mark - CRWWebStateObserver protocol
+
+- (void)webState:(web::WebState*)webState
+    didCommitNavigationWithDetails:(const web::LoadCommittedDetails&)details {
+  DCHECK([self navigationManager]);
+  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
+    // TODO(crbug.com/381201): Move this call to DidFinishNavigation callback.
+    [_legacyFullscreenController disableFullScreen];
+  }
+}
+
+- (void)webState:(web::WebState*)webState
+    didStartNavigation:(web::NavigationContext*)navigation {
+  if (!navigation->IsSameDocument() &&
+      !base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
+    // Move the toolbar to visible during page load.
+    [_legacyFullscreenController disableFullScreen];
+  }
+
+  [self.dialogDelegate cancelDialogForTab:self];
+  [_openInController disable];
+}
+
+- (void)webState:(web::WebState*)webState
+    didLoadPageWithSuccess:(BOOL)loadSuccess {
+  DCHECK([self loadFinished]);
+
+  // Cancel prerendering if response is "application/octet-stream". It can be a
+  // video file which should not be played from preload tab (crbug.com/436813).
+  if (self.isPrerenderTab &&
+      self.webState->GetContentsMimeType() == "application/octet-stream") {
+    [self discardPrerender];
+  }
+
+  if (loadSuccess) {
+    scoped_refptr<net::HttpResponseHeaders> headers =
+        _webStateImpl->GetHttpResponseHeaders();
+    [self handleExportableFile:headers.get()];
+  } else {
+    if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
+      [_legacyFullscreenController disableFullScreen];
+    }
+  }
+}
+
+- (void)webStateDidChangeVisibleSecurityState:(web::WebState*)webState {
+  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
+    // Disable fullscreen if SSL cert is invalid.
+    web::NavigationItem* item = [self navigationManager]->GetTransientItem();
+    if (item) {
+      web::SecurityStyle securityStyle = item->GetSSL().security_style;
+      if (securityStyle == web::SECURITY_STYLE_AUTHENTICATION_BROKEN) {
+        [_legacyFullscreenController disableFullScreen];
+      }
+    }
+
+    [self updateFullscreenWithToolbarVisible:YES];
+  }
+}
+
+- (void)webStateDidSuppressDialog:(web::WebState*)webState {
+  DCHECK(self.isPrerenderTab);
+  [self discardPrerender];
+}
+
+- (void)renderProcessGoneForWebState:(web::WebState*)webState {
+  DCHECK(webState == _webStateImpl);
+  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
+    UIApplicationState state =
+        [UIApplication sharedApplication].applicationState;
+    if (webState->IsVisible() && state == UIApplicationStateActive) {
+      [_legacyFullscreenController disableFullScreen];
+    }
+  }
+  [self.dialogDelegate cancelDialogForTab:self];
+}
+
 - (void)webStateDestroyed:(web::WebState*)webState {
   DCHECK_EQ(_webStateImpl, webState);
   self.overscrollActionsControllerDelegate = nil;
@@ -398,41 +618,15 @@
   _webStateImpl = nullptr;
 }
 
-- (void)dismissModals {
-  [_openInController disable];
-  [self.webController dismissModals];
-}
-
-- (void)goBack {
-  if (self.navigationManager) {
-    DCHECK(self.navigationManager->CanGoBack());
-    base::RecordAction(base::UserMetricsAction("Back"));
-    self.navigationManager->GoBack();
+- (void)webStateDidStopLoading:(web::WebState*)webState {
+  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
+    // This is the maximum that a page will ever load and it is safe to allow
+    // fullscreen mode.
+    [_legacyFullscreenController enableFullScreen];
   }
 }
 
-- (void)goForward {
-  if (self.navigationManager) {
-    DCHECK(self.navigationManager->CanGoForward());
-    base::RecordAction(base::UserMetricsAction("Forward"));
-    self.navigationManager->GoForward();
-  }
-}
-
-- (BOOL)canGoBack {
-  return self.navigationManager && self.navigationManager->CanGoBack();
-}
-
-- (BOOL)canGoForward {
-  return self.navigationManager && self.navigationManager->CanGoForward();
-}
-
-- (void)goToItem:(const web::NavigationItem*)item {
-  DCHECK(item);
-  int index = self.navigationManager->GetIndexOfItem(item);
-  DCHECK_NE(index, -1);
-  self.navigationManager->GoToIndex(index);
-}
+#pragma mark - CRWWebDelegate protocol
 
 - (BOOL)openExternalURL:(const GURL&)url
               sourceURL:(const GURL&)sourceURL
@@ -495,27 +689,65 @@
   return NO;
 }
 
-- (void)webState:(web::WebState*)webState
-    didFinishNavigation:(web::NavigationContext*)navigation {
-  [_parentTabModel notifyTabChanged:self];
+- (BOOL)webController:(CRWWebController*)webController
+        shouldOpenURL:(const GURL&)url
+      mainDocumentURL:(const GURL&)mainDocumentURL {
+  // chrome:// URLs are only allowed if the mainDocumentURL is also a chrome://
+  // URL.
+  if (url.SchemeIs(kChromeUIScheme) &&
+      !mainDocumentURL.SchemeIs(kChromeUIScheme)) {
+    return NO;
+  }
+
+  // Always allow frame loads.
+  BOOL isFrameLoad = (url != mainDocumentURL);
+  if (isFrameLoad)
+    return YES;
+
+  // TODO(crbug.com/546402): If this turns out to be useful, find a less hacky
+  // hook point to send this from.
+  NSString* urlString = base::SysUTF8ToNSString(url.spec());
+  if ([urlString length]) {
+    [[NSNotificationCenter defaultCenter]
+        postNotificationName:kTabUrlMayStartLoadingNotificationForCrashReporting
+                      object:self
+                    userInfo:@{kTabUrlKey : urlString}];
+  }
+
+  return YES;
 }
 
-// Records metric for the interface's orientation.
-- (void)recordInterfaceOrientation {
-  switch ([[UIApplication sharedApplication] statusBarOrientation]) {
-    case UIInterfaceOrientationPortrait:
-    case UIInterfaceOrientationPortraitUpsideDown:
-      UMA_HISTOGRAM_BOOLEAN("Tab.PageLoadInPortrait", YES);
-      break;
-    case UIInterfaceOrientationLandscapeLeft:
-    case UIInterfaceOrientationLandscapeRight:
-      UMA_HISTOGRAM_BOOLEAN("Tab.PageLoadInPortrait", NO);
-      break;
-    case UIInterfaceOrientationUnknown:
-      // TODO(crbug.com/228832): Convert from a boolean histogram to an
-      // enumerated histogram and log this case as well.
-      break;
+- (BOOL)webController:(CRWWebController*)webController
+    shouldOpenExternalURL:(const GURL&)URL {
+  if (self.isPrerenderTab) {
+    [self discardPrerender];
+    return NO;
   }
+  return YES;
+}
+
+- (CGFloat)headerHeightForWebController:(CRWWebController*)webController {
+  return [self.tabHeadersDelegate tabHeaderHeightForTab:self];
+}
+
+- (void)webController:(CRWWebController*)webController
+    didLoadPassKitObject:(NSData*)data {
+  [self.passKitDialogProvider presentPassKitDialog:data];
+}
+
+#pragma mark - Private methods
+
+- (void)discardPrerender {
+  DCHECK(self.isPrerenderTab);
+  [delegate_ discardPrerender];
+}
+
+- (BOOL)isPrerenderTab {
+  DCHECK(_browserState);
+  PrerenderService* prerenderService =
+      PrerenderServiceFactory::GetForBrowserState(_browserState);
+  return prerenderService &&
+         prerenderService->IsWebStatePrerendered(self.webState);
 }
 
 - (OpenInController*)openInController {
@@ -555,402 +787,6 @@
           suggestedFilename:base::SysUTF16ToNSString(filename)];
 }
 
-- (BOOL)shouldRecordPageLoadStartForNavigation:
-    (web::NavigationContext*)navigation {
-  web::NavigationItem* lastCommittedItem =
-      [self navigationManager]->GetLastCommittedItem();
-  if (!lastCommittedItem) {
-    // Opening a child window and loading URL there (crbug.com/773160).
-    return NO;
-  }
-
-  web::NavigationItem* pendingItem = [self navigationManager]->GetPendingItem();
-  if (pendingItem) {
-    using web::UserAgentType;
-    UserAgentType committedUserAgent = lastCommittedItem->GetUserAgentType();
-    UserAgentType pendingUserAgent = pendingItem->GetUserAgentType();
-    if (committedUserAgent != web::UserAgentType::NONE &&
-        pendingUserAgent != web::UserAgentType::NONE &&
-        committedUserAgent != pendingUserAgent) {
-      // Switching to Desktop or Mobile User Agent.
-      return YES;
-    }
-  }
-
-  ui::PageTransition transition = navigation->GetPageTransition();
-  if (!ui::PageTransitionIsNewNavigation(transition)) {
-    // Back forward navigation or reload.
-    return NO;
-  }
-
-  if ((ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT & transition) != 0) {
-    // Client redirect.
-    return NO;
-  }
-
-  using ui::PageTransitionCoreTypeIs;
-  return (
-      PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) ||
-      PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_LINK) ||
-      PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_GENERATED) ||
-      PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_AUTO_BOOKMARK) ||
-      PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_FORM_SUBMIT) ||
-      PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_KEYWORD) ||
-      PageTransitionCoreTypeIs(transition,
-                               ui::PAGE_TRANSITION_KEYWORD_GENERATED));
-}
-
-#pragma mark -
-#pragma mark FindInPageControllerDelegate
-
-- (void)willAdjustScrollPosition {
-  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
-    // Skip the next attempt to correct the scroll offset for the toolbar
-    // height.  Used when programatically scrolling down the y offset.
-    [_legacyFullscreenController shouldSkipNextScrollOffsetForHeader];
-  }
-}
-
-#pragma mark -
-#pragma mark FullScreen
-
-- (void)updateFullscreenWithToolbarVisible:(BOOL)visible {
-  DCHECK(!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen));
-  [_legacyFullscreenController moveHeaderToRestingPosition:visible];
-}
-
-#pragma mark -
-
-- (BOOL)usesDesktopUserAgent {
-  if (!self.navigationManager)
-    return NO;
-
-  web::NavigationItem* visibleItem = self.navigationManager->GetVisibleItem();
-  return visibleItem &&
-         visibleItem->GetUserAgentType() == web::UserAgentType::DESKTOP;
-}
-
-- (void)reloadWithUserAgentType:(web::UserAgentType)userAgentType {
-  // This removes the web view, which will be recreated at the end of this.
-  [self.webController requirePageReconstruction];
-
-  // TODO(crbug.com/228171): A hack in session_controller -addPendingItem
-  // discusses making tab responsible for distinguishing history stack
-  // navigation from new navigations.
-  web::NavigationManager* navigationManager = [self navigationManager];
-  DCHECK(navigationManager);
-
-  web::NavigationItem* lastNonRedirectItem =
-      navigationManager->GetTransientItem();
-  if (!lastNonRedirectItem || IsItemRedirectItem(lastNonRedirectItem))
-    lastNonRedirectItem = navigationManager->GetVisibleItem();
-  if (!lastNonRedirectItem || IsItemRedirectItem(lastNonRedirectItem))
-    lastNonRedirectItem = GetLastCommittedNonRedirectedItem(navigationManager);
-
-  if (!lastNonRedirectItem)
-    return;
-
-  // |reloadURL| will be empty if a page was open by DOM.
-  GURL reloadURL(lastNonRedirectItem->GetOriginalRequestURL());
-  if (reloadURL.is_empty()) {
-    DCHECK(self.webState && self.webState->HasOpener());
-    reloadURL = lastNonRedirectItem->GetVirtualURL();
-  }
-
-  web::NavigationManager::WebLoadParams params(reloadURL);
-  params.referrer = lastNonRedirectItem->GetReferrer();
-  params.transition_type = ui::PAGE_TRANSITION_RELOAD;
-
-  switch (userAgentType) {
-    case web::UserAgentType::DESKTOP:
-      params.user_agent_override_option =
-          web::NavigationManager::UserAgentOverrideOption::DESKTOP;
-      break;
-    case web::UserAgentType::MOBILE:
-      params.user_agent_override_option =
-          web::NavigationManager::UserAgentOverrideOption::MOBILE;
-      break;
-    case web::UserAgentType::NONE:
-      NOTREACHED();
-  }
-
-  navigationManager->LoadURLWithParams(params);
-}
-
-- (void)evaluateU2FResultFromURL:(const GURL&)URL {
-  DCHECK(_secondFactorController);
-  [_secondFactorController evaluateU2FResultFromU2FURL:URL
-                                              webState:self.webState];
-}
-
-#pragma mark - CRWWebDelegate and CRWWebStateObserver protocol methods.
-
-- (void)webState:(web::WebState*)webState
-    didStartNavigation:(web::NavigationContext*)navigation {
-  // After a crash the NTP is loaded by default.
-  if (navigation->GetUrl().host() != kChromeUINewTabHost) {
-    static BOOL hasLoadedPage = NO;
-    if (!hasLoadedPage) {
-      // As soon as load is initialted, a crash shouldn't be counted as a
-      // startup crash. Since initiating a url load requires user action and is
-      // a significant source of crashes that could lead to false positives in
-      // crash loop detection.
-      crash_util::ResetFailedStartupAttemptCount();
-      hasLoadedPage = YES;
-    }
-  }
-
-  if (!navigation->IsSameDocument() &&
-      !base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
-    // Move the toolbar to visible during page load.
-    [_legacyFullscreenController disableFullScreen];
-  }
-
-  if ([self shouldRecordPageLoadStartForNavigation:navigation] &&
-      [_parentTabModel tabUsageRecorder] && !self.isPrerenderTab) {
-    [_parentTabModel tabUsageRecorder]->RecordPageLoadStart(webState);
-  }
-
-  [self.dialogDelegate cancelDialogForTab:self];
-  [_parentTabModel notifyTabChanged:self];
-  [_openInController disable];
-  [[NSNotificationCenter defaultCenter]
-      postNotificationName:
-          kTabClosingCurrentDocumentNotificationForCrashReporting
-                    object:self];
-
-  web::NavigationItem* navigationItem =
-      [self navigationManager]->GetPendingItem();
-
-  // TODO(crbug.com/676129): the pending item is not correctly set when the
-  // page is reloading, use the last committed item if pending item is null.
-  // Remove this once tracking bug is fixed.
-  if (!navigationItem)
-    navigationItem = [self navigationManager]->GetLastCommittedItem();
-
-  [[OmniboxGeolocationController sharedInstance]
-      addLocationToNavigationItem:navigationItem
-                     browserState:_browserState];
-}
-
-- (void)webState:(web::WebState*)webState
-    didCommitNavigationWithDetails:(const web::LoadCommittedDetails&)details {
-  DCHECK([self navigationManager]);
-  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
-    // TODO(crbug.com/381201): Move this call to DidFinishNavigation callback.
-    [_legacyFullscreenController disableFullScreen];
-  }
-  GURL lastCommittedURL = webState->GetLastCommittedURL();
-
-  [_parentTabModel notifyTabLoading:self];
-
-  web::NavigationItem* previousItem = nullptr;
-  if (details.previous_item_index >= 0) {
-    previousItem = webState->GetNavigationManager()->GetItemAtIndex(
-        details.previous_item_index);
-  }
-
-  [_parentTabModel navigationCommittedInTab:self previousItem:previousItem];
-
-  // Sending a notification about the url change for crash reporting.
-  // TODO(crbug.com/661675): Consider using the navigation entry committed
-  // notification now that it's in the right place.
-  NSString* URLSpec = base::SysUTF8ToNSString(lastCommittedURL.spec());
-  if (URLSpec.length) {
-    [[NSNotificationCenter defaultCenter]
-        postNotificationName:kTabUrlStartedLoadingNotificationForCrashReporting
-                      object:self
-                    userInfo:@{kTabUrlKey : URLSpec}];
-  }
-}
-
-- (void)webState:(web::WebState*)webState
-    didLoadPageWithSuccess:(BOOL)loadSuccess {
-  DCHECK([self loadFinished]);
-
-  // Cancel prerendering if response is "application/octet-stream". It can be a
-  // video file which should not be played from preload tab (crbug.com/436813).
-  if (self.isPrerenderTab &&
-      self.webState->GetContentsMimeType() == "application/octet-stream") {
-    [self discardPrerender];
-  }
-
-  bool wasPost = false;
-  GURL lastCommittedURL;
-  web::NavigationItem* lastCommittedItem =
-      [self navigationManager]->GetLastCommittedItem();
-  if (lastCommittedItem) {
-    wasPost = lastCommittedItem->HasPostData();
-    lastCommittedURL = lastCommittedItem->GetVirtualURL();
-  }
-  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen) &&
-      !loadSuccess) {
-    [_legacyFullscreenController disableFullScreen];
-  }
-  [self recordInterfaceOrientation];
-  navigation_metrics::RecordMainFrameNavigation(
-      lastCommittedURL, true, self.browserState->IsOffTheRecord());
-
-  if (loadSuccess) {
-    scoped_refptr<net::HttpResponseHeaders> headers =
-        _webStateImpl->GetHttpResponseHeaders();
-    [self handleExportableFile:headers.get()];
-  }
-
-  [_parentTabModel notifyTabFinishedLoading:self success:loadSuccess];
-
-  if (!self.isPrerenderTab) {
-    [[OmniboxGeolocationController sharedInstance]
-        finishPageLoadForTab:self
-                 loadSuccess:loadSuccess];
-  }
-}
-
-- (void)webState:(web::WebState*)webState
-    didChangeLoadingProgress:(double)progress {
-  // TODO(crbug.com/546406): It is probably possible to do something smarter,
-  // but the fact that this is not always sent will have to be taken into
-  // account.
-  [_parentTabModel notifyTabChanged:self];
-}
-
-- (void)webStateDidChangeTitle:(web::WebState*)webState {
-  [_parentTabModel notifyTabChanged:self];
-}
-
-- (void)webStateDidStopLoading:(web::WebState*)webState {
-  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
-    // This is the maximum that a page will ever load and it is safe to allow
-    // fullscreen mode.
-    [_legacyFullscreenController enableFullScreen];
-  }
-  [_parentTabModel notifyTabChanged:self];
-}
-
-- (BOOL)webController:(CRWWebController*)webController
-    shouldOpenExternalURL:(const GURL&)URL {
-  if (self.isPrerenderTab) {
-    [self discardPrerender];
-    return NO;
-  }
-  return YES;
-}
-
-- (double)lastVisitedTimestamp {
-  return _lastVisitedTimestamp;
-}
-
-- (void)updateLastVisitedTimestamp {
-  _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970];
-}
-
-- (BOOL)webController:(CRWWebController*)webController
-        shouldOpenURL:(const GURL&)url
-      mainDocumentURL:(const GURL&)mainDocumentURL {
-  // chrome:// URLs are only allowed if the mainDocumentURL is also a chrome://
-  // URL.
-  if (url.SchemeIs(kChromeUIScheme) &&
-      !mainDocumentURL.SchemeIs(kChromeUIScheme)) {
-    return NO;
-  }
-
-  // Always allow frame loads.
-  BOOL isFrameLoad = (url != mainDocumentURL);
-  if (isFrameLoad)
-    return YES;
-
-  // TODO(crbug.com/546402): If this turns out to be useful, find a less hacky
-  // hook point to send this from.
-  NSString* urlString = base::SysUTF8ToNSString(url.spec());
-  if ([urlString length]) {
-    [[NSNotificationCenter defaultCenter]
-        postNotificationName:kTabUrlMayStartLoadingNotificationForCrashReporting
-                      object:self
-                    userInfo:@{kTabUrlKey : urlString}];
-  }
-
-  return YES;
-}
-
-#pragma mark - CRWWebDelegate and CRWWebStateObserver protocol methods
-
-- (void)webStateDidSuppressDialog:(web::WebState*)webState {
-  DCHECK(self.isPrerenderTab);
-  [self discardPrerender];
-}
-
-- (CGFloat)headerHeightForWebController:(CRWWebController*)webController {
-  return [self.tabHeadersDelegate tabHeaderHeightForTab:self];
-}
-
-- (void)webStateDidChangeVisibleSecurityState:(web::WebState*)webState {
-  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
-    // Disable fullscreen if SSL cert is invalid.
-    web::NavigationItem* item = [self navigationManager]->GetTransientItem();
-    if (item) {
-      web::SecurityStyle securityStyle = item->GetSSL().security_style;
-      if (securityStyle == web::SECURITY_STYLE_AUTHENTICATION_BROKEN) {
-        [_legacyFullscreenController disableFullScreen];
-      }
-    }
-  }
-
-  [_parentTabModel notifyTabChanged:self];
-  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
-    [self updateFullscreenWithToolbarVisible:YES];
-  }
-}
-
-- (void)renderProcessGoneForWebState:(web::WebState*)webState {
-  DCHECK(webState == _webStateImpl);
-  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
-    UIApplicationState state =
-        [UIApplication sharedApplication].applicationState;
-    if (webState->IsVisible() && state == UIApplicationStateActive) {
-      [_legacyFullscreenController disableFullScreen];
-    }
-  }
-  [self.dialogDelegate cancelDialogForTab:self];
-}
-
-- (void)webController:(CRWWebController*)webController
-    didLoadPassKitObject:(NSData*)data {
-  [self.passKitDialogProvider presentPassKitDialog:data];
-}
-
-- (void)discardPrerender {
-  DCHECK(self.isPrerenderTab);
-  [delegate_ discardPrerender];
-}
-
-- (BOOL)isPrerenderTab {
-  DCHECK(_browserState);
-  PrerenderService* prerenderService =
-      PrerenderServiceFactory::GetForBrowserState(_browserState);
-  return prerenderService &&
-         prerenderService->IsWebStatePrerendered(self.webState);
-}
-
-- (void)wasShown {
-  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
-    [self updateFullscreenWithToolbarVisible:YES];
-  }
-  if (self.webState)
-    self.webState->WasShown();
-}
-
-- (void)wasHidden {
-  if (!base::FeatureList::IsEnabled(fullscreen::features::kNewFullscreen)) {
-    [self updateFullscreenWithToolbarVisible:YES];
-  }
-  if (self.webState)
-    self.webState->WasHidden();
-}
-
-- (void)willUpdateSnapshot {
-  [_overscrollActionsController clear];
-}
-
 @end
 
 #pragma mark - TestingSupport
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm
index 1d4d59b..8ffe501 100644
--- a/ios/chrome/browser/tabs/tab_model.mm
+++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -17,6 +17,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "components/favicon/ios/web_favicon_driver.h"
+#include "components/navigation_metrics/navigation_metrics.h"
 #include "components/sessions/core/serialized_navigation_entry.h"
 #include "components/sessions/core/session_id.h"
 #include "components/sessions/core/tab_restore_service.h"
@@ -24,6 +25,8 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/chrome_url_util.h"
+#include "ios/chrome/browser/crash_loop_detection_util.h"
+#import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h"
 #import "ios/chrome/browser/metrics/tab_usage_recorder.h"
 #import "ios/chrome/browser/prerender/prerender_service_factory.h"
 #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
@@ -55,10 +58,13 @@
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/certificate_policy_cache.h"
+#import "ios/web/public/load_committed_details.h"
 #include "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 #import "ios/web/public/serializable_user_data_manager.h"
+#import "ios/web/public/web_state/navigation_context.h"
 #include "ios/web/public/web_state/session_certificate_policy_cache.h"
+#import "ios/web/public/web_state/web_state_observer_bridge.h"
 #include "ios/web/public/web_thread.h"
 #include "url/gurl.h"
 
@@ -108,9 +114,108 @@
                  base::Unretained(web_state_list)));
 }
 
+// Returns whether |rhs| and |lhs| are different user agent types. If either
+// of them is web::UserAgentType::NONE, then return NO.
+BOOL IsTransitionBetweenDesktopAndMobileUserAgent(web::UserAgentType lhs,
+                                                  web::UserAgentType rhs) {
+  if (lhs == web::UserAgentType::NONE)
+    return NO;
+
+  if (rhs == web::UserAgentType::NONE)
+    return NO;
+
+  return lhs != rhs;
+}
+
+// Returns whether TabUsageRecorder::RecordPageLoadStart should be called for
+// the given navigation.
+BOOL ShouldRecordPageLoadStartForNavigation(
+    web::NavigationContext* navigation) {
+  web::NavigationManager* navigation_manager =
+      navigation->GetWebState()->GetNavigationManager();
+
+  web::NavigationItem* last_committed_item =
+      navigation_manager->GetLastCommittedItem();
+  if (!last_committed_item) {
+    // Opening a child window and loading URL there.
+    // http://crbug.com/773160
+    return NO;
+  }
+
+  web::NavigationItem* pending_item = navigation_manager->GetPendingItem();
+  if (pending_item) {
+    if (IsTransitionBetweenDesktopAndMobileUserAgent(
+            pending_item->GetUserAgentType(),
+            last_committed_item->GetUserAgentType())) {
+      // Switching between Desktop and Mobile user agent.
+      return NO;
+    }
+  }
+
+  ui::PageTransition transition = navigation->GetPageTransition();
+  if (!ui::PageTransitionIsNewNavigation(transition)) {
+    // Back/forward navigation or reload.
+    return NO;
+  }
+
+  if ((transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT) != 0) {
+    // Client redirect.
+    return NO;
+  }
+
+  static const ui::PageTransition kRecordedPageTransitionTypes[] = {
+      ui::PAGE_TRANSITION_TYPED,
+      ui::PAGE_TRANSITION_LINK,
+      ui::PAGE_TRANSITION_GENERATED,
+      ui::PAGE_TRANSITION_AUTO_BOOKMARK,
+      ui::PAGE_TRANSITION_FORM_SUBMIT,
+      ui::PAGE_TRANSITION_KEYWORD,
+      ui::PAGE_TRANSITION_KEYWORD_GENERATED,
+  };
+
+  for (size_t i = 0; i < arraysize(kRecordedPageTransitionTypes); ++i) {
+    const ui::PageTransition recorded_type = kRecordedPageTransitionTypes[i];
+    if (ui::PageTransitionCoreTypeIs(transition, recorded_type)) {
+      return YES;
+    }
+  }
+
+  return NO;
+}
+
+// Records metrics for the interface's orientation.
+void RecordInterfaceOrientationMetric() {
+  switch ([[UIApplication sharedApplication] statusBarOrientation]) {
+    case UIInterfaceOrientationPortrait:
+    case UIInterfaceOrientationPortraitUpsideDown:
+      UMA_HISTOGRAM_BOOLEAN("Tab.PageLoadInPortrait", YES);
+      break;
+    case UIInterfaceOrientationLandscapeLeft:
+    case UIInterfaceOrientationLandscapeRight:
+      UMA_HISTOGRAM_BOOLEAN("Tab.PageLoadInPortrait", NO);
+      break;
+    case UIInterfaceOrientationUnknown:
+      // TODO(crbug.com/228832): Convert from a boolean histogram to an
+      // enumerated histogram and log this case as well.
+      break;
+  }
+}
+
+// Records metrics for main frame navigation.
+void RecordMainFrameNavigationMetric(web::WebState* web_state) {
+  DCHECK(web_state);
+  DCHECK(web_state->GetBrowserState());
+  DCHECK(web_state->GetNavigationManager());
+  web::NavigationItem* item =
+      web_state->GetNavigationManager()->GetLastCommittedItem();
+  navigation_metrics::RecordMainFrameNavigation(
+      item ? item->GetVirtualURL() : GURL::EmptyGURL(), true,
+      web_state->GetBrowserState()->IsOffTheRecord());
+}
+
 }  // anonymous namespace
 
-@interface TabModel () {
+@interface TabModel ()<CRWWebStateObserver, WebStateListObserving> {
   // Delegate for the WebStateList.
   std::unique_ptr<WebStateListDelegate> _webStateListDelegate;
 
@@ -143,6 +248,9 @@
 
   // Used to ensure thread-safety of the certificate policy management code.
   base::CancelableTaskTracker _clearPoliciesTaskTracker;
+
+  // Used to observe owned Tabs' WebStates.
+  std::unique_ptr<web::WebStateObserver> _webStateObserver;
 }
 
 // Session window for the contents of the tab model.
@@ -222,6 +330,8 @@
     _browserState = browserState;
     DCHECK(_browserState);
 
+    _webStateObserver = std::make_unique<web::WebStateObserverBridge>(self);
+
     // Normal browser states are the only ones to get tab restore. Tab sync
     // handles incognito browser states by filtering on profile, so it's
     // important to the backend code to always have a sync window delegate.
@@ -249,6 +359,9 @@
     [retainedWebStateListObservers addObject:tabModelClosingWebStateObserver];
 
     _webStateListObservers.push_back(
+        std::make_unique<WebStateListObserverBridge>(self));
+
+    _webStateListObservers.push_back(
         std::make_unique<WebStateListObserverBridge>(
             tabModelClosingWebStateObserver));
 
@@ -588,6 +701,7 @@
 
   _clearPoliciesTaskTracker.TryCancelAll();
   _tabUsageRecorder.reset();
+  _webStateObserver.reset();
 }
 
 - (void)navigationCommittedInTab:(Tab*)tab
@@ -742,4 +856,153 @@
   }
 }
 
+#pragma mark - CRWWebStateObserver
+
+- (void)webState:(web::WebState*)webState
+    didCommitNavigationWithDetails:
+        (const web::LoadCommittedDetails&)load_details {
+  Tab* tab = LegacyTabHelper::GetTabForWebState(webState);
+  [self notifyTabChanged:tab];
+
+  web::NavigationItem* previousItem = nullptr;
+  if (load_details.previous_item_index >= 0) {
+    DCHECK(webState->GetNavigationManager());
+    previousItem = webState->GetNavigationManager()->GetItemAtIndex(
+        load_details.previous_item_index);
+  }
+
+  [self navigationCommittedInTab:tab previousItem:previousItem];
+
+  // Sending a notification about the url change for crash reporting.
+  // TODO(crbug.com/661675): Consider using the navigation entry committed
+  // notification now that it's in the right place.
+  const std::string& lastCommittedURL = webState->GetLastCommittedURL().spec();
+  if (!lastCommittedURL.empty()) {
+    [[NSNotificationCenter defaultCenter]
+        postNotificationName:kTabUrlStartedLoadingNotificationForCrashReporting
+                      object:tab
+                    userInfo:@{
+                      kTabUrlKey : base::SysUTF8ToNSString(lastCommittedURL)
+                    }];
+  }
+}
+
+- (void)webState:(web::WebState*)webState
+    didStartNavigation:(web::NavigationContext*)navigation {
+  Tab* tab = LegacyTabHelper::GetTabForWebState(webState);
+
+  // In order to avoid false positive in the crash loop detection, disable the
+  // counter as soon as an URL is loaded. This requires an user action and is a
+  // significant source of crashes. Ignore NTP as it is loaded by default after
+  // a crash.
+  if (navigation->GetUrl().host_piece() != kChromeUINewTabHost) {
+    static dispatch_once_t dispatch_once_token;
+    dispatch_once(&dispatch_once_token, ^{
+      crash_util::ResetFailedStartupAttemptCount();
+    });
+  }
+
+  if (_tabUsageRecorder && ShouldRecordPageLoadStartForNavigation(navigation)) {
+    _tabUsageRecorder->RecordPageLoadStart(webState);
+  }
+
+  [self notifyTabChanged:tab];
+  [[NSNotificationCenter defaultCenter]
+      postNotificationName:
+          kTabClosingCurrentDocumentNotificationForCrashReporting
+                    object:tab];
+
+  DCHECK(webState->GetNavigationManager());
+  web::NavigationItem* navigationItem =
+      webState->GetNavigationManager()->GetPendingItem();
+
+  // TODO(crbug.com/676129): the pending item is not correctly set when the
+  // page is reloading, use the last committed item if pending item is null.
+  // Remove this once tracking bug is fixed.
+  if (!navigationItem) {
+    navigationItem = webState->GetNavigationManager()->GetLastCommittedItem();
+  }
+
+  [[OmniboxGeolocationController sharedInstance]
+      addLocationToNavigationItem:navigationItem
+                     browserState:ios::ChromeBrowserState::FromBrowserState(
+                                      webState->GetBrowserState())];
+}
+
+- (void)webState:(web::WebState*)webState
+    didFinishNavigation:(web::NavigationContext*)navigation {
+  Tab* tab = LegacyTabHelper::GetTabForWebState(webState);
+  [self notifyTabChanged:tab];
+}
+
+- (void)webState:(web::WebState*)webState didLoadPageWithSuccess:(BOOL)success {
+  DCHECK(!webState->IsLoading());
+  Tab* tab = LegacyTabHelper::GetTabForWebState(webState);
+  [self notifyTabFinishedLoading:tab success:success];
+
+  RecordInterfaceOrientationMetric();
+  RecordMainFrameNavigationMetric(webState);
+
+  [[OmniboxGeolocationController sharedInstance] finishPageLoadForTab:tab
+                                                          loadSuccess:success];
+}
+
+- (void)webState:(web::WebState*)webState
+    didChangeLoadingProgress:(double)progress {
+  // TODO(crbug.com/546406): It is probably possible to do something smarter,
+  // but the fact that this is not always sent will have to be taken into
+  // account.
+  Tab* tab = LegacyTabHelper::GetTabForWebState(webState);
+  [self notifyTabChanged:tab];
+}
+
+- (void)webStateDidChangeTitle:(web::WebState*)webState {
+  Tab* tab = LegacyTabHelper::GetTabForWebState(webState);
+  [self notifyTabChanged:tab];
+}
+
+- (void)webStateDidChangeVisibleSecurityState:(web::WebState*)webState {
+  Tab* tab = LegacyTabHelper::GetTabForWebState(webState);
+  [self notifyTabChanged:tab];
+}
+
+- (void)webStateDestroyed:(web::WebState*)webState {
+  // The TabModel is removed from WebState's observer when the WebState is
+  // detached from WebStateList which happens before WebState destructor,
+  // so this method should never be called.
+  NOTREACHED();
+}
+
+- (void)webStateDidStopLoading:(web::WebState*)webState {
+  Tab* tab = LegacyTabHelper::GetTabForWebState(webState);
+  [self notifyTabChanged:tab];
+}
+
+#pragma mark - WebStateListObserving
+
+- (void)webStateList:(WebStateList*)webStateList
+    didInsertWebState:(web::WebState*)webState
+              atIndex:(int)index
+           activating:(BOOL)activating {
+  DCHECK(webState);
+  webState->AddObserver(_webStateObserver.get());
+}
+
+- (void)webStateList:(WebStateList*)webStateList
+    didReplaceWebState:(web::WebState*)oldWebState
+          withWebState:(web::WebState*)newWebState
+               atIndex:(int)atIndex {
+  DCHECK(oldWebState);
+  DCHECK(newWebState);
+  newWebState->AddObserver(_webStateObserver.get());
+  oldWebState->RemoveObserver(_webStateObserver.get());
+}
+
+- (void)webStateList:(WebStateList*)webStateList
+    didDetachWebState:(web::WebState*)webState
+              atIndex:(int)atIndex {
+  DCHECK(webState);
+  webState->RemoveObserver(_webStateObserver.get());
+}
+
 @end
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 98e985a..67b5473f6 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -64,6 +64,7 @@
     "uikit_ui_util.mm",
   ]
   deps = [
+    ":feature_flags",
     "//base",
     "//base:i18n",
     "//ios/chrome/app:tests_hook",
@@ -82,6 +83,17 @@
   configs += [ "//build/config/compiler:enable_arc" ]
 }
 
+source_set("feature_flags") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "ui_feature_flags.cc",
+    "ui_feature_flags.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
 source_set("unit_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
@@ -393,14 +405,20 @@
     "//ui/base",
     "//ui/gfx",
     "//url",
+
+    # Fake dependencies to break cycles
+    "//ios/chrome/browser/browsing_data:browsing_data_internal",
+    "//ios/chrome/browser/ui/settings",
   ]
   public_deps = [
     "//ios/chrome/browser/ui/side_swipe",
     "//ios/chrome/browser/ui/toolbar",
   ]
   allow_circular_includes_from = [
+    "//ios/chrome/browser/browsing_data:browsing_data_internal",
     "//ios/chrome/browser/ui/ntp:ntp_internal",
     "//ios/chrome/browser/ui/overscroll_actions",
+    "//ios/chrome/browser/ui/settings",
     "//ios/chrome/browser/ui/stack_view",
     "//ios/chrome/browser/ui/tab_switcher",
     "//ios/chrome/browser/ui/tabs:coordinator",
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 82900c6e..1e79baa5 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -1682,7 +1682,7 @@
 
 - (BOOL)prefersStatusBarHidden {
   BOOL defaultValue = NO;
-  if (IsAdaptiveToolbarEnabled()) {
+  if (IsUIRefreshPhase1Enabled()) {
     defaultValue = [super prefersStatusBarHidden];
   }
   return self.hideStatusBar || defaultValue;
@@ -1934,7 +1934,7 @@
   _toolbarModelIOS.reset([_dependencyFactory
       newToolbarModelIOSWithDelegate:_toolbarModelDelegate.get()]);
 
-  if (IsAdaptiveToolbarEnabled()) {
+  if (IsUIRefreshPhase1Enabled()) {
     PrimaryToolbarCoordinator* topToolbarCoordinator =
         [[PrimaryToolbarCoordinator alloc] initWithBrowserState:_browserState];
     self.primaryToolbarCoordinator = topToolbarCoordinator;
diff --git a/ios/chrome/browser/ui/commands/application_commands.h b/ios/chrome/browser/ui/commands/application_commands.h
index 0803b25..236c587 100644
--- a/ios/chrome/browser/ui/commands/application_commands.h
+++ b/ios/chrome/browser/ui/commands/application_commands.h
@@ -98,6 +98,12 @@
 // Shows the Add Account UI, presenting from |baseViewController|.
 - (void)showAddAccountFromViewController:(UIViewController*)baseViewController;
 
+// Prepares the UI for ClearBrowsingData.
+- (void)prepareForBrowsingDataRemoval;
+
+// Updates the UI once ClearBrowsingData has occured.
+- (void)browsingDataWasRemoved;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_APPLICATION_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/download/legacy_download_manager_controller_unittest.mm b/ios/chrome/browser/ui/download/legacy_download_manager_controller_unittest.mm
index a7b63a5a..1aba2212 100644
--- a/ios/chrome/browser/ui/download/legacy_download_manager_controller_unittest.mm
+++ b/ios/chrome/browser/ui/download/legacy_download_manager_controller_unittest.mm
@@ -87,7 +87,8 @@
   EXPECT_TRUE([_controller googleDriveButton]);
 }
 
-TEST_F(LegacyDownloadManagerControllerTest, TestStart) {
+// TODO(crbug.com/804250): this test is flaky.
+TEST_F(LegacyDownloadManagerControllerTest, FLAKY_TestStart) {
   [_controller start];
   EXPECT_TRUE(
       [[UIApplication sharedApplication] isNetworkActivityIndicatorVisible]);
diff --git a/ios/chrome/browser/ui/download/pass_kit_coordinator_unittest.mm b/ios/chrome/browser/ui/download/pass_kit_coordinator_unittest.mm
index 73195c0..ee8cc6c 100644
--- a/ios/chrome/browser/ui/download/pass_kit_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/download/pass_kit_coordinator_unittest.mm
@@ -63,7 +63,8 @@
 
 // Tests that PassKitCoordinator presents PKAddPassesViewController for the
 // valid PKPass object.
-TEST_F(PassKitCoordinatorTest, ValidPassKitObject) {
+// TODO(crbug.com/804250): this test is flaky.
+TEST_F(PassKitCoordinatorTest, FLAKY_ValidPassKitObject) {
   std::string data = testing::GetTestPass();
   NSData* nsdata = [NSData dataWithBytes:data.c_str() length:data.size()];
   PKPass* pass = [[PKPass alloc] initWithData:nsdata error:nil];
@@ -99,7 +100,8 @@
 }
 
 // Tests presenting multiple valid PKPass objects.
-TEST_F(PassKitCoordinatorTest, MultiplePassKitObjects) {
+// TODO(crbug.com/804250): this test is flaky.
+TEST_F(PassKitCoordinatorTest, FLAKY_MultiplePassKitObjects) {
   if (IsIPadIdiom()) {
     // Wallet app is not supported on iPads.
     return;
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
index f3b0a05..d31f786 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -301,27 +301,29 @@
                 completionAnimator:(UIViewPropertyAnimator*)completionAnimator {
   // Hide the rightView button so its not visibile on its initial layout
   // while the expan animation is happening.
-  self.rightView.hidden = YES;
-  self.rightView.alpha = 0;
-  self.rightView.frame = CGRectLayoutOffset(
-      [self rightViewRectForBounds:self.bounds], kToolbarButtonAnimationOffset);
+  self.clearButton.hidden = YES;
+  self.clearButton.alpha = 0;
+  self.clearButton.frame =
+      CGRectLayoutOffset([self rightViewRectForBounds:self.bounds],
+                         [self clearButtonAnimationOffset]);
 
   [completionAnimator addAnimations:^{
-    self.rightView.hidden = NO;
-    self.rightView.alpha = 1.0;
-    self.rightView.frame = CGRectLayoutOffset(self.rightView.frame,
-                                              -kToolbarButtonAnimationOffset);
+    self.clearButton.hidden = NO;
+    self.clearButton.alpha = 1.0;
+
+    self.clearButton.frame = CGRectLayoutOffset(
+        self.clearButton.frame, -[self clearButtonAnimationOffset]);
   }];
 }
 
 - (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator {
   [animator addAnimations:^{
-    self.rightView.alpha = 0;
-    self.rightView.frame =
-        CGRectLayoutOffset(self.rightView.frame, kToolbarButtonAnimationOffset);
+    self.clearButton.alpha = 0;
+    self.clearButton.frame = CGRectLayoutOffset(self.clearButton.frame,
+                                                kToolbarButtonAnimationOffset);
   }];
   [animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
-    self.rightView = nil;
+    [self resetClearButton];
   }];
 }
 
@@ -941,4 +943,29 @@
   return CGRectZero;
 }
 
+// Accesses the clear button view when it's available; correctly resolves RTL.
+- (UIView*)clearButton {
+  if ([self isTextFieldLTR]) {
+    return self.rightView;
+  } else {
+    return self.leftView;
+  }
+}
+
+- (void)resetClearButton {
+  if ([self isTextFieldLTR]) {
+    self.rightView = nil;
+  } else {
+    self.rightView = nil;
+  }
+}
+
+- (CGFloat)clearButtonAnimationOffset {
+  if ([self isTextFieldLTR]) {
+    return kToolbarButtonAnimationOffset;
+  } else {
+    return -kToolbarButtonAnimationOffset;
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index 0e468be..4b8f90c 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -43,6 +43,8 @@
     "password_details_collection_view_controller.h",
     "password_details_collection_view_controller.mm",
     "password_details_collection_view_controller_delegate.h",
+    "password_exporter.h",
+    "password_exporter.mm",
     "privacy_collection_view_controller.h",
     "privacy_collection_view_controller.mm",
     "reauthentication_module.h",
@@ -116,6 +118,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browser_state:browser_state_impl",
     "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/browsing_data:browsing_data_internal",
     "//ios/chrome/browser/content_settings",
     "//ios/chrome/browser/feature_engagement",
     "//ios/chrome/browser/history",
@@ -181,6 +184,7 @@
     "password_details_collection_view_controller_for_testing.h",
     "personal_data_manager_data_changed_observer.cc",
     "personal_data_manager_data_changed_observer.h",
+    "reauthentication_module_for_testing.h",
   ]
   deps = [
     ":settings",
@@ -226,6 +230,7 @@
     "import_data_collection_view_controller_unittest.mm",
     "password_details_collection_view_controller_unittest.mm",
     "privacy_collection_view_controller_unittest.mm",
+    "reauthentication_module_unittest.mm",
     "save_passwords_collection_view_controller_unittest.mm",
     "search_engine_settings_collection_view_controller_unittest.mm",
     "settings_navigation_controller_unittest.mm",
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.mm
index 93b9be4..0bb887d 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.mm
@@ -30,6 +30,7 @@
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.h"
+#import "ios/chrome/browser/browsing_data/browsing_data_removal_controller.h"
 #include "ios/chrome/browser/browsing_data/ios_browsing_data_counter_factory.h"
 #include "ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
@@ -38,6 +39,7 @@
 #include "ios/chrome/browser/history/web_history_service_factory.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
+#import "ios/chrome/browser/ui/chrome_web_view_factory.h"
 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
@@ -635,11 +637,29 @@
 
 - (void)clearDataForDataTypes:(int)dataTypeMask {
   DCHECK(dataTypeMask);
-  ClearBrowsingDataCommand* command =
-      [[ClearBrowsingDataCommand alloc] initWithBrowserState:_browserState
-                                                        mask:dataTypeMask
-                                                  timePeriod:_timePeriod];
-  [self chromeExecuteCommand:command];
+
+  BrowsingDataRemovalController* browsingDataRemovalController =
+      [[BrowsingDataRemovalController alloc] init];
+
+  if (dataTypeMask & IOSChromeBrowsingDataRemover::REMOVE_SITE_DATA) {
+    [self.dispatcher prepareForBrowsingDataRemoval];
+  }
+
+  [browsingDataRemovalController
+      removeBrowsingDataFromBrowserState:_browserState
+                                    mask:dataTypeMask
+                              timePeriod:_timePeriod
+                       completionHandler:^{
+                         [self.dispatcher browsingDataWasRemoved];
+                       }];
+
+  if (dataTypeMask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES) {
+    base::Time beginDeleteTime =
+        browsing_data::CalculateBeginDeleteTime(_timePeriod);
+    [ChromeWebViewFactory clearExternalCookies:_browserState
+                                      fromTime:beginDeleteTime
+                                        toTime:base::Time::Max()];
+  }
 
   // Send the "Cleared Browsing Data" event to the feature_engagement::Tracker
   // when the user initiates a clear browsing data action. No event is sent if
diff --git a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
index 393ba663..17a8052 100644
--- a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
@@ -37,9 +37,6 @@
 
 namespace {
 
-// A help article on how to set up a passcode.
-constexpr char kPasscodeArticleURL[] = "https://support.apple.com/HT204060";
-
 typedef NS_ENUM(NSInteger, SectionIdentifier) {
   SectionIdentifierSite = kSectionIdentifierEnumZero,
   SectionIdentifierUsername,
@@ -383,6 +380,7 @@
     [_weakReauthenticationModule
         attemptReauthWithLocalizedReason:
             l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_SHOW)
+                    canReusePreviousAuth:YES
                                  handler:showPasswordHandler];
   } else {
     [self showPasscodeDialog];
@@ -444,6 +442,7 @@
     [_weakReauthenticationModule
         attemptReauthWithLocalizedReason:
             l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_COPY)
+                    canReusePreviousAuth:YES
                                  handler:copyPasswordHandler];
   } else {
     [self showPasscodeDialog];
diff --git a/ios/chrome/browser/ui/settings/password_details_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password_details_collection_view_controller_unittest.mm
index c2be56a..e1330a0 100644
--- a/ios/chrome/browser/ui/settings/password_details_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password_details_collection_view_controller_unittest.mm
@@ -38,6 +38,7 @@
 }
 
 - (void)attemptReauthWithLocalizedReason:(NSString*)localizedReason
+                    canReusePreviousAuth:(BOOL)canReusePreviousAuth
                                  handler:(void (^)(BOOL success))
                                              showCopyPasswordsHandler {
   self.localizedReasonForAuthentication = localizedReason;
diff --git a/ios/chrome/browser/ui/settings/password_exporter.h b/ios/chrome/browser/ui/settings/password_exporter.h
new file mode 100644
index 0000000..54c0e2e0
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/password_exporter.h
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_EXPORTER_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_EXPORTER_H_
+
+#import <Foundation/Foundation.h>
+
+@protocol ReauthenticationProtocol;
+
+@protocol PasswordExporterDelegate<NSObject>
+
+// Displays a dialog informing the user that they must set up a passcode
+// in order to export passwords.
+- (void)showSetPasscodeDialog;
+
+@end
+
+/** Class handling all the operations necessary to export passwords.*/
+@interface PasswordExporter : NSObject
+
+// The designated initializer. |reauthenticationModule| and |delegate| must
+// not be nil.
+- (instancetype)initWithReauthenticationModule:
+                    (id<ReauthenticationProtocol>)reuthenticationModule
+                                      delegate:
+                                          (id<PasswordExporterDelegate>)delegate
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+// Method to be called in order to start the export flow. This initiates
+// the re-authentication procedure and asks for password serialization.
+- (void)startExportFlow;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_EXPORTER_H_
diff --git a/ios/chrome/browser/ui/settings/password_exporter.mm b/ios/chrome/browser/ui/settings/password_exporter.mm
new file mode 100644
index 0000000..3cb73bb
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/password_exporter.mm
@@ -0,0 +1,64 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/settings/password_exporter.h"
+
+#include "base/logging.h"
+#import "ios/chrome/browser/ui/settings/reauthentication_module.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface PasswordExporter () {
+  // Module containing the reauthentication mechanism used for exporting
+  // passwords.
+  __weak id<ReauthenticationProtocol> _weakReauthenticationModule;
+  // Instance of the view controller initiating the export. Used
+  // for displaying alerts.
+  __weak id<PasswordExporterDelegate> _weakDelegate;
+}
+
+@end
+
+@implementation PasswordExporter
+
+- (instancetype)initWithReauthenticationModule:
+                    (id<ReauthenticationProtocol>)reauthenticationModule
+                                      delegate:(id<PasswordExporterDelegate>)
+                                                   delegate {
+  DCHECK(delegate);
+  DCHECK(reauthenticationModule);
+  self = [super init];
+  if (self) {
+    _weakReauthenticationModule = reauthenticationModule;
+    _weakDelegate = delegate;
+  }
+  return self;
+}
+
+- (void)startExportFlow {
+  if ([_weakReauthenticationModule canAttemptReauth]) {
+    // TODO(crbug.com/789122): Ask for password serialization.
+    [self startReauthentication];
+  } else {
+    [_weakDelegate showSetPasscodeDialog];
+  }
+}
+
+#pragma mark -  Private methods
+
+- (void)startReauthentication {
+  [_weakReauthenticationModule
+      attemptReauthWithLocalizedReason:l10n_util::GetNSString(
+                                           IDS_IOS_EXPORT_PASSWORDS)
+                  canReusePreviousAuth:NO
+                               handler:^(BOOL success){
+                                   // TODO(crbug.com/789122): Store reauth
+                                   // result and continue the export flow.
+                               }];
+}
+@end
diff --git a/ios/chrome/browser/ui/settings/reauthentication_module.h b/ios/chrome/browser/ui/settings/reauthentication_module.h
index fa3c742..a72a23c9 100644
--- a/ios/chrome/browser/ui/settings/reauthentication_module.h
+++ b/ios/chrome/browser/ui/settings/reauthentication_module.h
@@ -9,6 +9,9 @@
 
 #import "ios/chrome/browser/ui/settings/reauthentication_protocol.h"
 
+// A help article on how to set up a passcode.
+extern const char kPasscodeArticleURL[];
+
 @protocol SuccessfulReauthTimeAccessor<NSObject>
 
 // Method meant to be called by the |ReauthenticationModule| to update
@@ -21,9 +24,9 @@
 @end
 
 /**
- * This is used by |PasswordsDetailsCollectionViewController| to re-authenticate
- * the user before displaying the password in plain text, or allowing it to be
- * copied.
+ * This is used by |PasswordsDetailsCollectionViewController| and
+ * |PasswordExporter|to re-authenticate the user before displaying the password
+ * in plain text, allowing it to be copied, or exporting passwords.
  */
 @interface ReauthenticationModule : NSObject<ReauthenticationProtocol>
 
diff --git a/ios/chrome/browser/ui/settings/reauthentication_module.mm b/ios/chrome/browser/ui/settings/reauthentication_module.mm
index 336331b..f13aa6d 100644
--- a/ios/chrome/browser/ui/settings/reauthentication_module.mm
+++ b/ios/chrome/browser/ui/settings/reauthentication_module.mm
@@ -13,9 +13,12 @@
 #error "This file requires ARC support."
 #endif
 
+constexpr char kPasscodeArticleURL[] = "https://support.apple.com/HT204060";
+
 @implementation ReauthenticationModule {
-  // Authentication context on which the authentication policy is evaluated.
-  LAContext* _context;
+  // Block that creates a new |LAContext| object everytime one is required,
+  // meant to make testing with a mock object possible.
+  LAContext* (^_createLAContext)(void);
 
   // Accessor allowing the module to request the update of the time when the
   // successful re-authentication was performed and to get the time of the last
@@ -28,21 +31,25 @@
   DCHECK(successfulReauthTimeAccessor);
   self = [super init];
   if (self) {
-    _context = [[LAContext alloc] init];
+    _createLAContext = ^{
+      return [[LAContext alloc] init];
+    };
     _successfulReauthTimeAccessor = successfulReauthTimeAccessor;
   }
   return self;
 }
 
 - (BOOL)canAttemptReauth {
+  LAContext* context = _createLAContext();
   // The authentication method is Touch ID or passcode.
   return
-      [_context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:nil];
+      [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:nil];
 }
 
 - (void)attemptReauthWithLocalizedReason:(NSString*)localizedReason
+                    canReusePreviousAuth:(BOOL)canReusePreviousAuth
                                  handler:(void (^)(BOOL success))handler {
-  if ([self isPreviousAuthValid]) {
+  if (canReusePreviousAuth && [self isPreviousAuthValid]) {
     handler(YES);
     UMA_HISTOGRAM_ENUMERATION(
         "PasswordManager.ReauthToAccessPasswordInSettings",
@@ -51,10 +58,10 @@
     return;
   }
 
-  _context = [[LAContext alloc] init];
+  LAContext* context = _createLAContext();
 
   // No fallback option is provided.
-  _context.localizedFallbackTitle = @"";
+  context.localizedFallbackTitle = @"";
 
   __weak ReauthenticationModule* weakSelf = self;
   void (^replyBlock)(BOOL, NSError*) = ^(BOOL success, NSError* error) {
@@ -74,9 +81,9 @@
     });
   };
 
-  [_context evaluatePolicy:LAPolicyDeviceOwnerAuthentication
-           localizedReason:localizedReason
-                     reply:replyBlock];
+  [context evaluatePolicy:LAPolicyDeviceOwnerAuthentication
+          localizedReason:localizedReason
+                    reply:replyBlock];
 }
 
 - (BOOL)isPreviousAuthValid {
@@ -95,4 +102,10 @@
   return previousAuthValid;
 }
 
+#pragma mark - ForTesting
+
+- (void)setCreateLAContext:(LAContext* (^)(void))createLAContext {
+  _createLAContext = createLAContext;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/reauthentication_module_for_testing.h b/ios/chrome/browser/ui/settings/reauthentication_module_for_testing.h
new file mode 100644
index 0000000..4939204
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/reauthentication_module_for_testing.h
@@ -0,0 +1,20 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_REAUTHENTICATION_MODULE_FOR_TESTING_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_REAUTHENTICATION_MODULE_FOR_TESTING_H_
+
+#import "ios/chrome/browser/ui/settings/reauthentication_module.h"
+
+#import <LocalAuthentication/LocalAuthentication.h>
+
+@interface ReauthenticationModule (ForTesting)
+
+// Allows the replacement of the |LAContext| objects used by
+// |ReauthenticationModule| with a mock to facilitate testing.
+- (void)setCreateLAContext:(LAContext* (^)(void))createLAContext;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_REAUTHENTICATION_MODULE_FOR_TESTING_H
diff --git a/ios/chrome/browser/ui/settings/reauthentication_module_unittest.mm b/ios/chrome/browser/ui/settings/reauthentication_module_unittest.mm
new file mode 100644
index 0000000..3132ba2
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/reauthentication_module_unittest.mm
@@ -0,0 +1,117 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/settings/reauthentication_module_for_testing.h"
+
+#import <LocalAuthentication/LocalAuthentication.h>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+#import "third_party/ocmock/gtest_support.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface TestingSuccessfulReauthTimeAccessor
+    : NSObject<SuccessfulReauthTimeAccessor> {
+  // Object storing the time of a fake previous successful re-authentication
+  // to be used by the |ReauthenticationModule|.
+  NSDate* successfulReauthTime_;
+}
+
+@end
+
+@implementation TestingSuccessfulReauthTimeAccessor
+
+- (void)updateSuccessfulReauthTime {
+  successfulReauthTime_ = [[NSDate alloc] init];
+}
+
+- (void)updateSuccessfulReauthTime:(NSDate*)time {
+  successfulReauthTime_ = time;
+}
+
+- (NSDate*)lastSuccessfulReauthTime {
+  return successfulReauthTime_;
+}
+
+@end
+
+namespace {
+
+class ReauthenticationModuleTest : public ::testing::Test {
+ protected:
+  ReauthenticationModuleTest() {}
+
+  void SetUp() override {
+    auth_context_ = [OCMockObject niceMockForClass:[LAContext class]];
+    time_accessor_ = [[TestingSuccessfulReauthTimeAccessor alloc] init];
+    reauthentication_module_ = [[ReauthenticationModule alloc]
+        initWithSuccessfulReauthTimeAccessor:time_accessor_];
+    [reauthentication_module_ setCreateLAContext:^LAContext*() {
+      return auth_context_;
+    }];
+  }
+
+  id auth_context_;
+  TestingSuccessfulReauthTimeAccessor* time_accessor_;
+  ReauthenticationModule* reauthentication_module_;
+};
+
+TEST_F(ReauthenticationModuleTest, ReauthReuseNotPermitted) {
+  [time_accessor_ updateSuccessfulReauthTime];
+
+  OCMExpect([auth_context_ evaluatePolicy:LAPolicyDeviceOwnerAuthentication
+                          localizedReason:[OCMArg any]
+                                    reply:[OCMArg any]]);
+  [reauthentication_module_ attemptReauthWithLocalizedReason:@"Test"
+                                        canReusePreviousAuth:NO
+                                                     handler:^(BOOL success){
+                                                     }];
+
+  EXPECT_OCMOCK_VERIFY(auth_context_);
+}
+
+TEST_F(ReauthenticationModuleTest, ReauthReusePermittedLessThanSixtySeconds) {
+  [time_accessor_ updateSuccessfulReauthTime];
+
+  [[auth_context_ reject] evaluatePolicy:LAPolicyDeviceOwnerAuthentication
+                         localizedReason:[OCMArg any]
+                                   reply:[OCMArg any]];
+
+  // Use @try/@catch as -reject raises an exception.
+  @try {
+    [reauthentication_module_ attemptReauthWithLocalizedReason:@"Test"
+                                          canReusePreviousAuth:YES
+                                                       handler:^(BOOL success){
+                                                       }];
+    EXPECT_OCMOCK_VERIFY(auth_context_);
+  } @catch (NSException* exception) {
+    // The exception is raised when
+    // - attemptReauthWithLocalizedReason:canReusePreviousAuth:handler:
+    // is invoked. As this should not happen, mark the test as failed.
+    GTEST_FAIL();
+  }
+}
+
+TEST_F(ReauthenticationModuleTest, ReauthReusePermittedMoreThanSixtySeconds) {
+  const int kIntervalForFakePreviousAuthInSeconds = -70;
+  [time_accessor_ updateSuccessfulReauthTime:
+                      [NSDate dateWithTimeIntervalSinceNow:
+                                  kIntervalForFakePreviousAuthInSeconds]];
+
+  OCMExpect([auth_context_ evaluatePolicy:LAPolicyDeviceOwnerAuthentication
+                          localizedReason:[OCMArg any]
+                                    reply:[OCMArg any]]);
+  [reauthentication_module_ attemptReauthWithLocalizedReason:@"Test"
+                                        canReusePreviousAuth:YES
+                                                     handler:^(BOOL success){
+                                                     }];
+
+  EXPECT_OCMOCK_VERIFY(auth_context_);
+}
+
+}  // namespace
diff --git a/ios/chrome/browser/ui/settings/reauthentication_protocol.h b/ios/chrome/browser/ui/settings/reauthentication_protocol.h
index ba63a9e2..57b051ef 100644
--- a/ios/chrome/browser/ui/settings/reauthentication_protocol.h
+++ b/ios/chrome/browser/ui/settings/reauthentication_protocol.h
@@ -13,9 +13,12 @@
 - (BOOL)canAttemptReauth;
 
 // Attempts to reauthenticate the user with Touch ID or passcode if Touch ID is
-// not available and the device is running iOS 9. |handler|
-// will take action depending on the result of the reauth attempt.
+// not available. If |canReusePreviousAuth| is YES, a previous successful
+// reauthentication can be taken into consideration, otherwise a new
+// reauth attempt must be made. |handler| will take action depending on the
+// result of the reauth attempt.
 - (void)attemptReauthWithLocalizedReason:(NSString*)localizedReason
+                    canReusePreviousAuth:(BOOL)canReusePreviousAuth
                                  handler:(void (^)(BOOL success))handler;
 
 @end
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.h b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.h
index d907dbcd..29c719f 100644
--- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.h
+++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.h
@@ -38,6 +38,7 @@
 // |getLoginsFromPasswordStore| finishes.
 - (void)onGetPasswordStoreResults:
     (const std::vector<std::unique_ptr<autofill::PasswordForm>>&)result;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_SAVE_PASSWORDS_COLLECTION_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
index ab53f18..f58fadc 100644
--- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
@@ -25,6 +25,7 @@
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_member.h"
 #include "components/prefs/pref_service.h"
+#include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/url_formatter.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
@@ -38,6 +39,7 @@
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
 #import "ios/chrome/browser/ui/settings/password_details_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/password_details_collection_view_controller_delegate.h"
+#import "ios/chrome/browser/ui/settings/password_exporter.h"
 #import "ios/chrome/browser/ui/settings/reauthentication_module.h"
 #import "ios/chrome/browser/ui/settings/settings_utils.h"
 #import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h"
@@ -98,6 +100,7 @@
   if (!results.empty())
     [delegate_ onGetPasswordStoreResults:results];
 }
+
 }  // namespace password_manager
 
 // Use the type of the items to convey the Saved/Blacklisted status.
@@ -113,7 +116,8 @@
 @interface SavePasswordsCollectionViewController ()<
     BooleanObserver,
     PasswordDetailsCollectionViewControllerDelegate,
-    SuccessfulReauthTimeAccessor> {
+    SuccessfulReauthTimeAccessor,
+    PasswordExporterDelegate> {
   // The observable boolean that binds to the password manager setting state.
   // Saved passwords are only on if the password manager is enabled.
   PrefBackedBoolean* passwordManagerEnabled_;
@@ -157,10 +161,15 @@
 // Kick off async request to get logins from password store.
 - (void)getLoginsFromPasswordStore;
 
+// Object handling passwords export operations.
+@property(nonatomic, strong) PasswordExporter* passwordExporter;
+
 @end
 
 @implementation SavePasswordsCollectionViewController
 
+@synthesize passwordExporter = passwordExporter_;
+
 #pragma mark - Initialization
 
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState {
@@ -172,6 +181,10 @@
     browserState_ = browserState;
     reauthenticationModule_ = [[ReauthenticationModule alloc]
         initWithSuccessfulReauthTimeAccessor:self];
+    passwordExporter_ = [[PasswordExporter alloc]
+        initWithReauthenticationModule:reauthenticationModule_
+                              delegate:self];
+
     self.title = l10n_util::GetNSString(IDS_IOS_SAVE_PASSWORDS);
     self.collectionViewAccessibilityIdentifier =
         @"SavePasswordsCollectionViewController";
@@ -487,12 +500,17 @@
                              handler:nil];
   [exportConfirmation addAction:cancelAction];
 
-  // TODO(crbug.com/789122): Ask for password serialization
-  // and wire re-authentication.
+  __weak SavePasswordsCollectionViewController* weakSelf = self;
   UIAlertAction* exportAction = [UIAlertAction
       actionWithTitle:l10n_util::GetNSString(IDS_IOS_EXPORT_PASSWORDS)
                 style:UIAlertActionStyleDefault
-              handler:nil];
+              handler:^(UIAlertAction* action) {
+                SavePasswordsCollectionViewController* strongSelf = weakSelf;
+                if (!strongSelf) {
+                  return;
+                }
+                [strongSelf.passwordExporter startExportFlow];
+              }];
   [exportConfirmation addAction:exportAction];
 
   [self presentViewController:exportConfirmation animated:YES completion:nil];
@@ -706,4 +724,33 @@
   return successfulReauthTime_;
 }
 
+#pragma mark PasswordExporterDelegate
+
+- (void)showSetPasscodeDialog {
+  UIAlertController* alertController = [UIAlertController
+      alertControllerWithTitle:l10n_util::GetNSString(
+                                   IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_TITLE)
+                       message:
+                           l10n_util::GetNSString(
+                               IDS_IOS_SETTINGS_EXPORT_PASSWORDS_SET_UP_SCREENLOCK_CONTENT)
+                preferredStyle:UIAlertControllerStyleAlert];
+
+  ProceduralBlockWithURL blockOpenURL = BlockToOpenURL(self, self.dispatcher);
+  UIAlertAction* learnAction = [UIAlertAction
+      actionWithTitle:l10n_util::GetNSString(
+                          IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_LEARN_HOW)
+                style:UIAlertActionStyleDefault
+              handler:^(UIAlertAction*) {
+                blockOpenURL(GURL(kPasscodeArticleURL));
+              }];
+  [alertController addAction:learnAction];
+  UIAlertAction* okAction =
+      [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_OK)
+                               style:UIAlertActionStyleDefault
+                             handler:nil];
+  [alertController addAction:okAction];
+  alertController.preferredAction = okAction;
+  [self presentViewController:alertController animated:YES completion:nil];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
index f91ba7c..c12fd53 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -10,9 +10,6 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
-#import "ios/chrome/browser/ui/commands/clear_browsing_data_command.h"
-#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/material_components/app_bar_presenting.h"
@@ -111,9 +108,6 @@
 // Creates an autoreleased "CANCEL" button that closes the settings when tapped.
 - (UIBarButtonItem*)cancelButton;
 
-// Intercepts some commands and forwards all others up the responder chain.
-- (void)chromeExecuteCommand:(id)sender;
-
 @end
 
 @implementation SettingsNavigationController {
@@ -488,30 +482,6 @@
   return NO;
 }
 
-#pragma mark - UIResponder (ChromeExecuteCommand)
-
-- (void)chromeExecuteCommand:(id)sender {
-  switch ([sender tag]) {
-    case IDC_CLEAR_BROWSING_DATA_IOS: {
-      // Check that the data for the right browser state is being cleared before
-      // forwarding it up the responder chain.
-      ios::ChromeBrowserState* commandBrowserState =
-          [base::mac::ObjCCast<ClearBrowsingDataCommand>(sender) browserState];
-
-      // Clearing browsing data for the wrong profile is a destructive action.
-      // Executing it on the wrong profile is a privacy issue. Kill the
-      // app if this ever happens.
-      CHECK_EQ(commandBrowserState, [self mainBrowserState]);
-      break;
-    }
-    default:
-      NOTREACHED()
-          << "Unexpected command " << [sender tag]
-          << " Settings commands must execute on the main browser state.";
-  }
-  [[self nextResponder] chromeExecuteCommand:sender];
-}
-
 #pragma mark - UIResponder
 
 - (NSArray*)keyCommands {
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/BUILD.gn b/ios/chrome/browser/ui/toolbar/adaptive/BUILD.gn
index 202f2d3..0a578fcf 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/adaptive/BUILD.gn
@@ -4,7 +4,7 @@
 
 source_set("adaptive") {
   sources = [
-    "adaptive_toolbar_coordinator+protected.h",
+    "adaptive_toolbar_coordinator+subclassing.h",
     "adaptive_toolbar_coordinator.h",
     "adaptive_toolbar_coordinator.mm",
     "primary_toolbar_coordinator.h",
@@ -43,6 +43,7 @@
 source_set("adaptive_ui") {
   sources = [
     "adaptive_toolbar_view.h",
+    "adaptive_toolbar_view_controller+subclassing.h",
     "adaptive_toolbar_view_controller.h",
     "adaptive_toolbar_view_controller.mm",
     "primary_toolbar_view.h",
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+protected.h b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+subclassing.h
similarity index 89%
rename from ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+protected.h
rename to ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+subclassing.h
index 2f5fee19..2804f544 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+protected.h
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+subclassing.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_ADAPTIVE_TOOLBAR_COORDINATOR_PROTECTED_H_
-#define IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_ADAPTIVE_TOOLBAR_COORDINATOR_PROTECTED_H_
+#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_ADAPTIVE_TOOLBAR_COORDINATOR_SUBCLASSING_H_
+#define IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_ADAPTIVE_TOOLBAR_COORDINATOR_SUBCLASSING_H_
 
 #import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator.h"
 
@@ -19,4 +19,4 @@
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_ADAPTIVE_TOOLBAR_COORDINATOR_PROTECTED_H_
+#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_ADAPTIVE_TOOLBAR_COORDINATOR_SUBCLASSING_H_
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator.mm
index faf5817..54e5dceb 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator.mm
@@ -6,7 +6,7 @@
 
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+protected.h"
+#import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+subclassing.h"
 #import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_factory.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_button_visibility_configuration.h"
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm
index ccf4600..7fa1b5b 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm
@@ -34,7 +34,7 @@
   return true;
 }
 
-bool ForceAdaptiveToolbar() {
+bool ForceUIRefreshPhase1() {
   return true;
 }
 
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller+subclassing.h b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller+subclassing.h
new file mode 100644
index 0000000..bda27da
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller+subclassing.h
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_ADAPTIVE_TOOLBAR_VIEW_CONTROLLER_SUBCLASSING_H_
+#define IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_ADAPTIVE_TOOLBAR_VIEW_CONTROLLER_SUBCLASSING_H_
+
+#import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.h"
+
+// Protected interface of the AdaptiveToolbarViewController.
+@interface AdaptiveToolbarViewController (Subclassing)
+
+// Sets the progress of the progressBar to 1 then hides it.
+- (void)stopProgressBar;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_ADAPTIVE_TOOLBAR_VIEW_CONTROLLER_SUBCLASSING_H_
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
index d9b02c8..2d07f1b5 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
@@ -95,17 +95,8 @@
   self.view.shareButton.enabled = enabled;
 }
 
-#pragma mark - Private
+#pragma mark - Protected
 
-// Updates all buttons visibility to match any recent WebState or SizeClass
-// change.
-- (void)updateAllButtonsVisibility {
-  for (ToolbarButton* button in self.view.allButtons) {
-    [button updateHiddenInCurrentSizeClass];
-  }
-}
-
-// Sets the progress of the progressBar to 1 then hides it.
 - (void)stopProgressBar {
   __weak MDCProgressView* weakProgressBar = self.view.progressBar;
   __weak AdaptiveToolbarViewController* weakSelf = self;
@@ -119,4 +110,14 @@
        }];
 }
 
+#pragma mark - Private
+
+// Updates all buttons visibility to match any recent WebState or SizeClass
+// change.
+- (void)updateAllButtonsVisibility {
+  for (ToolbarButton* button in self.view.allButtons) {
+    [button updateHiddenInCurrentSizeClass];
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
index 0e92376..2849d8b3 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
@@ -14,7 +14,7 @@
 #include "ios/chrome/browser/ui/omnibox/location_bar_delegate.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_popup_positioner.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h"
-#import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+protected.h"
+#import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+subclassing.h"
 #import "ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/toolbar/public/web_toolbar_controller_constants.h"
@@ -84,7 +84,7 @@
 }
 
 - (void)showPrerenderingAnimation {
-  // TODO(crbug.com/803377): Implement that.
+  [self.viewController showPrerenderingAnimation];
 }
 
 - (BOOL)isOmniboxFirstResponder {
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h
index 27e02b8..37b5565 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h
@@ -14,6 +14,9 @@
 // Sets the location bar view, containing the omnibox.
 - (void)setLocationBarView:(UIView*)locationBarView;
 
+// Shows the animation when transitioning to a prerendered page.
+- (void)showPrerenderingAnimation;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_PRIMARY_TOOLBAR_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm
index d30bcf9a..ce2495a 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm
@@ -5,10 +5,12 @@
 #import "ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h"
 
 #import "base/logging.h"
+#import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller+subclassing.h"
 #import "ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_constants.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_tools_menu_button.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
+#import "ios/third_party/material_components_ios/src/components/ProgressView/src/MaterialProgressView.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -23,6 +25,18 @@
 
 @dynamic view;
 
+#pragma mark - Public
+
+- (void)showPrerenderingAnimation {
+  __weak PrimaryToolbarViewController* weakSelf = self;
+  [self.view.progressBar setProgress:0];
+  [self.view.progressBar setHidden:NO
+                          animated:YES
+                        completion:^(BOOL finished) {
+                          [weakSelf stopProgressBar];
+                        }];
+}
+
 #pragma mark - UIViewController
 
 - (void)loadView {
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_coordinator.mm
index f0a22de6..a0d0918 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_coordinator.mm
@@ -4,7 +4,7 @@
 
 #import "ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_coordinator.h"
 
-#import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+protected.h"
+#import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+subclassing.h"
 #import "ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_view_controller.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_configuration.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_configuration.mm
index 00e73d0..971e1ee6 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_configuration.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_configuration.mm
@@ -36,7 +36,7 @@
 }
 
 - (UIColor*)backgroundColor {
-  if (IsAdaptiveToolbarEnabled()) {
+  if (IsUIRefreshPhase1Enabled()) {
     switch (self.style) {
       case NORMAL:
         return UIColorFromRGB(kAdaptiveToolbarBackgroundColor);
@@ -54,7 +54,7 @@
 }
 
 - (UIColor*)omniboxBackgroundColor {
-  if (IsAdaptiveToolbarEnabled()) {
+  if (IsUIRefreshPhase1Enabled()) {
     switch (self.style) {
       case NORMAL:
         return UIColorFromRGB(kAdaptiveLocationBackgroundColor);
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
index 2ea62cc..73f9d92 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
@@ -218,11 +218,6 @@
   // TODO(crbug.com/803383): This should be done inside the location bar.
   // Updates the omnibox.
   [self.locationBarCoordinator updateOmniboxState];
-  // Updates the toolbar buttons.
-  // TODO(crbug.com/803386): This call is needed for interstitials. Check if it
-  // is possible to remove it.
-  if ([self getWebState])
-    [self.mediator updateConsumerForWebState:[self getWebState]];
 }
 
 - (void)updateToolbarForSideSwipeSnapshot:(web::WebState*)webState {
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator.mm
index 9045ffbf..f79370e 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator.mm
@@ -119,6 +119,11 @@
   [self.consumer setLoadingProgressFraction:progress];
 }
 
+- (void)webStateDidChangeVisibleSecurityState:(web::WebState*)webState {
+  DCHECK_EQ(_webState, webState);
+  [self updateConsumer];
+}
+
 - (void)webStateDestroyed:(web::WebState*)webState {
   DCHECK_EQ(_webState, webState);
   _webState->RemoveObserver(_webStateObserver.get());
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator_unittest.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator_unittest.mm
index 243f223..377e7378 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_mediator_unittest.mm
@@ -382,6 +382,27 @@
 }
 
 // Test the Toolbar is updated when the Webstate observer method
+// didFinishNavigation is called.
+TEST_F(ToolbarMediatorTest, TestDidChangeVisibleSecurityState) {
+  SetUpBookmarks();
+  mediator_.webStateList = web_state_list_.get();
+  SetUpActiveWebState();
+  mediator_.consumer = consumer_;
+  mediator_.bookmarkModel = bookmark_model_;
+
+  navigation_manager_->set_can_go_forward(true);
+  navigation_manager_->set_can_go_back(true);
+
+  web_state_->SetCurrentURL(GURL(kTestUrl));
+  web_state_->OnVisibleSecurityStateChanged();
+
+  [[consumer_ verify] setCanGoForward:YES];
+  [[consumer_ verify] setCanGoBack:YES];
+  [[consumer_ verify] setPageBookmarked:YES];
+  [[consumer_ verify] setShareMenuEnabled:YES];
+}
+
+// Test the Toolbar is updated when the Webstate observer method
 // didChangeLoadingProgress is called.
 TEST_F(ToolbarMediatorTest, TestLoadingProgress) {
   mediator_.webStateList = web_state_list_.get();
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
index 40848be70..4b2be1d 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
@@ -241,6 +241,7 @@
 - (void)setBackgroundToIncognitoNTPColorWithAlpha:(CGFloat)alpha {
   self.view.backgroundView.alpha = alpha;
   self.view.shadowView.alpha = 1 - alpha;
+  self.view.progressBar.alpha = 1 - alpha;
 }
 
 - (void)showPrerenderingAnimation {
diff --git a/ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h b/ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h
index cd6a688e..1571f2d 100644
--- a/ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h
+++ b/ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h
@@ -33,7 +33,7 @@
 // Stops the coordinator.
 - (void)stop;
 
-// Show the animation when transitioning to a prerendered page.
+// Shows the animation when transitioning to a prerendered page.
 - (void)showPrerenderingAnimation;
 // Whether the omnibox is currently the first responder.
 - (BOOL)isOmniboxFirstResponder;
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h b/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h
index b418b5c7..fb16e7c 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h
+++ b/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h
@@ -12,8 +12,4 @@
 // function instead.
 extern const base::Feature kSafeAreaCompatibleToolbar;
 
-// Feature to choose whether to use the Adaptive Toolbar or the standard
-// toolbar.
-extern const base::Feature kAdaptiveToolbar;
-
 #endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_PRIVATE_BASE_FEATURE_H_
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.mm b/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.mm
index ec6570c..889e5ee 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.mm
@@ -10,6 +10,3 @@
 
 const base::Feature kSafeAreaCompatibleToolbar{
     "SafeAreaCompatibleToolbar", base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kAdaptiveToolbar{"AdaptiveToolbar",
-                                     base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
new file mode 100644
index 0000000..0887a973
--- /dev/null
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -0,0 +1,8 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/ui/ui_feature_flags.h"
+
+const base::Feature kUIRefreshPhase1{"UIRefreshPhase1",
+                                     base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_feature_flags.h b/ios/chrome/browser/ui/ui_feature_flags.h
new file mode 100644
index 0000000..e57373c5
--- /dev/null
+++ b/ios/chrome/browser/ui/ui_feature_flags.h
@@ -0,0 +1,14 @@
+// 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.
+
+#ifndef IOS_CHROME_BROWSER_UI_UI_FEATURE_FLAGS_H_
+#define IOS_CHROME_BROWSER_UI_UI_FEATURE_FLAGS_H_
+
+#include "base/feature_list.h"
+
+// Used to enable the first phase of the UI refresh. This flag should not be
+// used directly. Instead use ui_util::IsUIRefreshPhase1Enabled().
+extern const base::Feature kUIRefreshPhase1;
+
+#endif  // IOS_CHROME_BROWSER_UI_UI_FEATURE_FLAGS_H_
diff --git a/ios/chrome/browser/ui/ui_util.h b/ios/chrome/browser/ui/ui_util.h
index f3ad79c..1216c42 100644
--- a/ios/chrome/browser/ui/ui_util.h
+++ b/ios/chrome/browser/ui/ui_util.h
@@ -39,8 +39,8 @@
 // Returns true if the device is an iPhone X.
 bool IsIPhoneX();
 
-// Returns whether the feature to display the adaptive toolbar is enabled.
-bool IsAdaptiveToolbarEnabled();
+// Returns whether the first phase of the UI refresh will be displayed..
+bool IsUIRefreshPhase1Enabled();
 
 // Returns whether the feature to force the toolbar to respect the safe area is
 // enabled.
diff --git a/ios/chrome/browser/ui/ui_util.mm b/ios/chrome/browser/ui/ui_util.mm
index 5c5ce1c..49813d7 100644
--- a/ios/chrome/browser/ui/ui_util.mm
+++ b/ios/chrome/browser/ui/ui_util.mm
@@ -12,6 +12,7 @@
 #include "ios/chrome/app/tests_hook.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_private_base_feature.h"
+#import "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ui/base/device_form_factor.h"
 #include "ui/gfx/ios/uikit_util.h"
@@ -57,10 +58,10 @@
           CGRectGetHeight([[UIScreen mainScreen] nativeBounds]) == 2436);
 }
 
-bool IsAdaptiveToolbarEnabled() {
-  if (tests_hook::ForceAdaptiveToolbar())
+bool IsUIRefreshPhase1Enabled() {
+  if (tests_hook::ForceUIRefreshPhase1())
     return true;
-  return base::FeatureList::IsEnabled(kAdaptiveToolbar);
+  return base::FeatureList::IsEnabled(kUIRefreshPhase1);
 }
 
 bool IsSafeAreaCompatibleToolbarEnabled() {
diff --git a/ios/chrome/test/app/password_test_util.mm b/ios/chrome/test/app/password_test_util.mm
index caf44b2..c84dcb8 100644
--- a/ios/chrome/test/app/password_test_util.mm
+++ b/ios/chrome/test/app/password_test_util.mm
@@ -28,6 +28,7 @@
 }
 
 - (void)attemptReauthWithLocalizedReason:(NSString*)localizedReason
+                    canReusePreviousAuth:(BOOL)canReusePreviousAuth
                                  handler:(void (^)(BOOL success))
                                              showCopyPasswordsHandler {
   showCopyPasswordsHandler(_shouldSucceed);
diff --git a/ios/chrome/test/earl_grey/eg_tests_hook.mm b/ios/chrome/test/earl_grey/eg_tests_hook.mm
index c74977e..f1f1ada 100644
--- a/ios/chrome/test/earl_grey/eg_tests_hook.mm
+++ b/ios/chrome/test/earl_grey/eg_tests_hook.mm
@@ -34,7 +34,7 @@
   return true;
 }
 
-bool ForceAdaptiveToolbar() {
+bool ForceUIRefreshPhase1() {
   return false;
 }
 
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 2d43cd7..5da225b 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -173,6 +173,7 @@
   "//components/autofill/ios/browser",
   "//components/content_settings/core/browser",
   "//components/flags_ui",
+  "//components/image_fetcher/ios",
   "//components/infobars/core",
   "//components/keyed_service/core",
   "//components/keyed_service/ios",
diff --git a/ios/web_view/internal/DEPS b/ios/web_view/internal/DEPS
index aaaec8c..b5a9d94 100644
--- a/ios/web_view/internal/DEPS
+++ b/ios/web_view/internal/DEPS
@@ -3,6 +3,7 @@
   "+components/autofill",
   "+components/content_settings/core",
   "+components/flags_ui",
+  "+components/image_fetcher/ios",
   "+components/infobars/core",
   "+components/keyed_service/core",
   "+components/keyed_service/ios",
diff --git a/ios/web_view/internal/signin/web_view_account_fetcher_service_factory.mm b/ios/web_view/internal/signin/web_view_account_fetcher_service_factory.mm
index 277a9a2..1e07672 100644
--- a/ios/web_view/internal/signin/web_view_account_fetcher_service_factory.mm
+++ b/ios/web_view/internal/signin/web_view_account_fetcher_service_factory.mm
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/memory/singleton.h"
+#include "components/image_fetcher/ios/ios_image_decoder_impl.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/signin/core/browser/account_fetcher_service.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
@@ -59,7 +60,8 @@
   service->Initialize(
       WebViewSigninClientFactory::GetForBrowserState(browser_state),
       WebViewOAuth2TokenServiceFactory::GetForBrowserState(browser_state),
-      WebViewAccountTrackerServiceFactory::GetForBrowserState(browser_state));
+      WebViewAccountTrackerServiceFactory::GetForBrowserState(browser_state),
+      image_fetcher::CreateIOSImageDecoder());
   return service;
 }
 
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 8557659..e73a87eb 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1817,6 +1817,8 @@
         "reporting/reporting_delivery_agent.h",
         "reporting/reporting_endpoint_manager.cc",
         "reporting/reporting_endpoint_manager.h",
+        "reporting/reporting_feature.cc",
+        "reporting/reporting_feature.h",
         "reporting/reporting_garbage_collector.cc",
         "reporting/reporting_garbage_collector.h",
         "reporting/reporting_header_parser.cc",
@@ -2583,10 +2585,10 @@
     "log/test_net_log_util.h",
     "nqe/network_quality_estimator_test_util.cc",
     "nqe/network_quality_estimator_test_util.h",
-    "proxy/mock_proxy_resolver.cc",
-    "proxy/mock_proxy_resolver.h",
     "proxy/mock_pac_file_fetcher.cc",
     "proxy/mock_pac_file_fetcher.h",
+    "proxy/mock_proxy_resolver.cc",
+    "proxy/mock_proxy_resolver.h",
     "proxy/proxy_config_service_common_unittest.cc",
     "proxy/proxy_config_service_common_unittest.h",
     "socket/socket_test_util.cc",
@@ -4975,6 +4977,8 @@
     "proxy/mojo_proxy_resolver_v8_tracing_bindings_unittest.cc",
     "proxy/multi_threaded_proxy_resolver_unittest.cc",
     "proxy/network_delegate_error_observer_unittest.cc",
+    "proxy/pac_file_decider_unittest.cc",
+    "proxy/pac_file_fetcher_impl_unittest.cc",
     "proxy/proxy_bypass_rules_unittest.cc",
     "proxy/proxy_config_service_android_unittest.cc",
     "proxy/proxy_config_service_linux_unittest.cc",
@@ -4985,8 +4989,6 @@
     "proxy/proxy_resolver_v8_tracing_unittest.cc",
     "proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc",
     "proxy/proxy_resolver_v8_unittest.cc",
-    "proxy/pac_file_decider_unittest.cc",
-    "proxy/pac_file_fetcher_impl_unittest.cc",
     "proxy/proxy_server_unittest.cc",
     "proxy/proxy_service_unittest.cc",
     "quic/chromium/bidirectional_stream_quic_impl_unittest.cc",
diff --git a/net/network_error_logging/network_error_logging_end_to_end_test.cc b/net/network_error_logging/network_error_logging_end_to_end_test.cc
index ffcbc4c..3da56ed6a 100644
--- a/net/network_error_logging/network_error_logging_end_to_end_test.cc
+++ b/net/network_error_logging/network_error_logging_end_to_end_test.cc
@@ -5,12 +5,14 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/values_test_util.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "net/base/net_errors.h"
 #include "net/network_error_logging/network_error_logging_service.h"
+#include "net/reporting/reporting_feature.h"
 #include "net/reporting/reporting_policy.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
@@ -55,6 +57,9 @@
       : test_server_(test_server::EmbeddedTestServer::TYPE_HTTPS),
         upload_should_hang_(false),
         upload_received_(false) {
+    scoped_feature_list_.InitWithFeatures(
+        {features::kReporting, features::kNetworkErrorLogging}, {});
+
     // Make report delivery happen instantly.
     auto policy = std::make_unique<ReportingPolicy>();
     policy->delivery_interval = base::TimeDelta::FromSeconds(0);
@@ -140,6 +145,7 @@
     return std::move(response);
   }
 
+  base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<URLRequestContext> url_request_context_;
   test_server::EmbeddedTestServer test_server_;
 
diff --git a/net/network_error_logging/network_error_logging_service.cc b/net/network_error_logging/network_error_logging_service.cc
index ebded2f..e9d6f7b 100644
--- a/net/network_error_logging/network_error_logging_service.cc
+++ b/net/network_error_logging/network_error_logging_service.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/json/json_reader.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -23,6 +24,13 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
+namespace features {
+
+const base::Feature kNetworkErrorLogging{"NetworkErrorLogging",
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
+
+}  // namespace features
+
 namespace net {
 
 namespace {
@@ -119,6 +127,9 @@
 // static
 std::unique_ptr<NetworkErrorLoggingService>
 NetworkErrorLoggingService::Create() {
+  if (!base::FeatureList::IsEnabled(features::kNetworkErrorLogging))
+    return std::unique_ptr<NetworkErrorLoggingService>();
+
   // Would be MakeUnique, but the constructor is private so MakeUnique can't see
   // it.
   return base::WrapUnique(new NetworkErrorLoggingService());
diff --git a/net/network_error_logging/network_error_logging_service_unittest.cc b/net/network_error_logging/network_error_logging_service_unittest.cc
index 56fe21fe..e04a2f2 100644
--- a/net/network_error_logging/network_error_logging_service_unittest.cc
+++ b/net/network_error_logging/network_error_logging_service_unittest.cc
@@ -10,13 +10,13 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/values_test_util.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "net/base/ip_address.h"
 #include "net/base/net_errors.h"
 #include "net/network_error_logging/network_error_logging_service.h"
-#include "net/reporting/reporting_policy.h"
 #include "net/reporting/reporting_service.h"
 #include "net/socket/next_proto.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -85,14 +85,8 @@
     return true;
   }
 
-  const ReportingPolicy& GetPolicy() const override {
-    NOTREACHED();
-    return dummy_policy_;
-  }
-
  private:
   std::vector<Report> reports_;
-  ReportingPolicy dummy_policy_;
 
   DISALLOW_COPY_AND_ASSIGN(TestReportingService);
 };
@@ -100,6 +94,7 @@
 class NetworkErrorLoggingServiceTest : public ::testing::Test {
  protected:
   NetworkErrorLoggingServiceTest() {
+    scoped_feature_list_.InitAndEnableFeature(features::kNetworkErrorLogging);
     service_ = NetworkErrorLoggingService::Create();
     CreateReportingService();
   }
@@ -163,12 +158,22 @@
   const GURL kReferrer_ = GURL("https://referrer.com/");
 
  private:
+  base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<NetworkErrorLoggingService> service_;
   std::unique_ptr<TestReportingService> reporting_service_;
 };
 
-TEST_F(NetworkErrorLoggingServiceTest, CreateService) {
-  // Service is created by default in the test fixture..
+TEST_F(NetworkErrorLoggingServiceTest, FeatureDisabled) {
+  // N.B. This test does not actually use the test fixture.
+
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(features::kNetworkErrorLogging);
+
+  auto service = NetworkErrorLoggingService::Create();
+  EXPECT_FALSE(service);
+}
+
+TEST_F(NetworkErrorLoggingServiceTest, FeatureEnabled) {
   EXPECT_TRUE(service());
 }
 
diff --git a/net/quic/chromium/quic_stream_factory.cc b/net/quic/chromium/quic_stream_factory.cc
index 97a5306..d5ed39e 100644
--- a/net/quic/chromium/quic_stream_factory.cc
+++ b/net/quic/chromium/quic_stream_factory.cc
@@ -326,8 +326,10 @@
   int DoResolveHostComplete(int rv);
   int DoConnect();
   int DoConnectComplete(int rv);
+  int DoConfirmConnection(int rv);
 
-  void OnIOComplete(int rv);
+  void OnResolveHostComplete(int rv);
+  void OnConnectComplete(int rv);
 
   const QuicSessionKey& key() const { return key_; }
 
@@ -369,6 +371,7 @@
     STATE_RESOLVE_HOST_COMPLETE,
     STATE_CONNECT,
     STATE_CONNECT_COMPLETE,
+    STATE_CONFIRM_CONNECTION,
   };
 
   IoState io_state_;
@@ -468,6 +471,9 @@
       case STATE_CONNECT_COMPLETE:
         rv = DoConnectComplete(rv);
         break;
+      case STATE_CONFIRM_CONNECTION:
+        rv = DoConfirmConnection(rv);
+        break;
       default:
         NOTREACHED() << "io_state_: " << io_state_;
         break;
@@ -476,16 +482,21 @@
   return rv;
 }
 
-void QuicStreamFactory::Job::OnIOComplete(int rv) {
-  IoState start_state = io_state_;
+void QuicStreamFactory::Job::OnResolveHostComplete(int rv) {
+  DCHECK_EQ(STATE_RESOLVE_HOST_COMPLETE, io_state_);
+
   rv = DoLoop(rv);
-  if (start_state == STATE_RESOLVE_HOST_COMPLETE &&
-      !host_resolution_callback_.is_null()) {
+  if (!host_resolution_callback_.is_null())
     base::ResetAndReturn(&host_resolution_callback_).Run(rv);
-  }
-  if (rv != ERR_IO_PENDING && !callback_.is_null()) {
+
+  if (rv != ERR_IO_PENDING && !callback_.is_null())
     base::ResetAndReturn(&callback_).Run(rv);
-  }
+}
+
+void QuicStreamFactory::Job::OnConnectComplete(int rv) {
+  rv = DoLoop(rv);
+  if (rv != ERR_IO_PENDING && !callback_.is_null())
+    base::ResetAndReturn(&callback_).Run(rv);
 }
 
 void QuicStreamFactory::Job::PopulateNetErrorDetails(
@@ -507,7 +518,7 @@
   io_state_ = STATE_RESOLVE_HOST_COMPLETE;
   return host_resolver_->Resolve(
       HostResolver::RequestInfo(key_.destination()), priority_, &address_list_,
-      base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()),
+      base::Bind(&QuicStreamFactory::Job::OnResolveHostComplete, GetWeakPtr()),
       &request_, net_log_);
 }
 
@@ -554,7 +565,7 @@
     return ERR_QUIC_PROTOCOL_ERROR;
 
   rv = session_->CryptoConnect(
-      base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()));
+      base::Bind(&QuicStreamFactory::Job::OnConnectComplete, GetWeakPtr()));
 
   if (!session_->connection()->connected() &&
       session_->error() == QUIC_PROOF_INVALID) {
@@ -565,6 +576,11 @@
 }
 
 int QuicStreamFactory::Job::DoConnectComplete(int rv) {
+  io_state_ = STATE_CONFIRM_CONNECTION;
+  return rv;
+}
+
+int QuicStreamFactory::Job::DoConfirmConnection(int rv) {
   net_log_.EndEvent(NetLogEventType::QUIC_STREAM_FACTORY_JOB_CONNECT);
   if (session_ && session_->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
     num_sent_client_hellos_ += session_->GetNumSentClientHellos();
diff --git a/net/reporting/reporting_feature.cc b/net/reporting/reporting_feature.cc
new file mode 100644
index 0000000..9f4e28e
--- /dev/null
+++ b/net/reporting/reporting_feature.cc
@@ -0,0 +1,11 @@
+// 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.
+
+#include "net/reporting/reporting_feature.h"
+
+namespace features {
+
+const base::Feature kReporting{"Reporting", base::FEATURE_DISABLED_BY_DEFAULT};
+
+}  // namespace features
diff --git a/net/reporting/reporting_feature.h b/net/reporting/reporting_feature.h
new file mode 100644
index 0000000..4bd3d39
--- /dev/null
+++ b/net/reporting/reporting_feature.h
@@ -0,0 +1,17 @@
+// 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.
+
+#ifndef NET_REPORTING_REPORTING_FEATURE_H_
+#define NET_REPORTING_REPORTING_FEATURE_H_
+
+#include "base/feature_list.h"
+#include "net/base/net_export.h"
+
+namespace features {
+
+extern const base::Feature NET_EXPORT kReporting;
+
+}  // namespace features
+
+#endif  // NET_REPORTING_REPORTING_FEATURE_H_
diff --git a/net/reporting/reporting_header_parser_fuzzer.cc b/net/reporting/reporting_header_parser_fuzzer.cc
index 470d496a..302cc8fb 100644
--- a/net/reporting/reporting_header_parser_fuzzer.cc
+++ b/net/reporting/reporting_header_parser_fuzzer.cc
@@ -55,10 +55,10 @@
   policy.max_report_age =
       base::TimeDelta::FromMicroseconds(policy_data.max_report_age_us());
   policy.max_report_attempts = policy_data.max_report_attempts();
-  policy.clear_reports_on_network_changes =
-      policy_data.clear_reports_on_network_changes();
-  policy.clear_clients_on_network_changes =
-      policy_data.clear_clients_on_network_changes();
+  policy.persist_reports_across_network_changes =
+      policy_data.persist_reports_across_network_changes();
+  policy.persist_clients_across_network_changes =
+      policy_data.persist_clients_across_network_changes();
 }
 
 DEFINE_BINARY_PROTO_FUZZER(
diff --git a/net/reporting/reporting_network_change_observer.cc b/net/reporting/reporting_network_change_observer.cc
index 20e33a3..c7acb88 100644
--- a/net/reporting/reporting_network_change_observer.cc
+++ b/net/reporting/reporting_network_change_observer.cc
@@ -38,11 +38,11 @@
     if (type != NetworkChangeNotifier::ConnectionType::CONNECTION_NONE)
       return;
 
-    if (context_->policy().clear_reports_on_network_changes)
+    if (!context_->policy().persist_reports_across_network_changes)
       context_->cache()->RemoveAllReports(
           ReportingReport::Outcome::ERASED_NETWORK_CHANGED);
 
-    if (context_->policy().clear_clients_on_network_changes)
+    if (!context_->policy().persist_clients_across_network_changes)
       context_->cache()->RemoveAllClients();
   }
 
diff --git a/net/reporting/reporting_network_change_observer_unittest.cc b/net/reporting/reporting_network_change_observer_unittest.cc
index ce114d1..ae35fbda8 100644
--- a/net/reporting/reporting_network_change_observer_unittest.cc
+++ b/net/reporting/reporting_network_change_observer_unittest.cc
@@ -60,8 +60,8 @@
 
 TEST_F(ReportingNetworkChangeObserverTest, ClearNothing) {
   ReportingPolicy new_policy = policy();
-  new_policy.clear_reports_on_network_changes = false;
-  new_policy.clear_clients_on_network_changes = false;
+  new_policy.persist_reports_across_network_changes = true;
+  new_policy.persist_clients_across_network_changes = true;
   UsePolicy(new_policy);
 
   cache()->AddReport(kUrl_, kGroup_, kType_,
@@ -79,8 +79,8 @@
 
 TEST_F(ReportingNetworkChangeObserverTest, ClearReports) {
   ReportingPolicy new_policy = policy();
-  new_policy.clear_reports_on_network_changes = true;
-  new_policy.clear_clients_on_network_changes = false;
+  new_policy.persist_reports_across_network_changes = false;
+  new_policy.persist_clients_across_network_changes = true;
   UsePolicy(new_policy);
 
   cache()->AddReport(kUrl_, kGroup_, kType_,
@@ -98,8 +98,8 @@
 
 TEST_F(ReportingNetworkChangeObserverTest, ClearClients) {
   ReportingPolicy new_policy = policy();
-  new_policy.clear_reports_on_network_changes = false;
-  new_policy.clear_clients_on_network_changes = true;
+  new_policy.persist_reports_across_network_changes = true;
+  new_policy.persist_clients_across_network_changes = false;
   UsePolicy(new_policy);
 
   cache()->AddReport(kUrl_, kGroup_, kType_,
@@ -117,8 +117,8 @@
 
 TEST_F(ReportingNetworkChangeObserverTest, ClearReportsAndClients) {
   ReportingPolicy new_policy = policy();
-  new_policy.clear_reports_on_network_changes = true;
-  new_policy.clear_clients_on_network_changes = true;
+  new_policy.persist_reports_across_network_changes = false;
+  new_policy.persist_clients_across_network_changes = false;
   UsePolicy(new_policy);
 
   cache()->AddReport(kUrl_, kGroup_, kType_,
diff --git a/net/reporting/reporting_policy.cc b/net/reporting/reporting_policy.cc
index 007eb89..1c4d163 100644
--- a/net/reporting/reporting_policy.cc
+++ b/net/reporting/reporting_policy.cc
@@ -18,8 +18,8 @@
       garbage_collection_interval(base::TimeDelta::FromMinutes(5)),
       max_report_age(base::TimeDelta::FromMinutes(15)),
       max_report_attempts(5),
-      clear_reports_on_network_changes(true),
-      clear_clients_on_network_changes(false) {
+      persist_reports_across_network_changes(false),
+      persist_clients_across_network_changes(true) {
   endpoint_backoff_policy.num_errors_to_ignore = 0;
   endpoint_backoff_policy.initial_delay_ms = 60 * 1000;  // 1 minute
   endpoint_backoff_policy.multiply_factor = 2.0;
diff --git a/net/reporting/reporting_policy.h b/net/reporting/reporting_policy.h
index 772bff5..86d8858 100644
--- a/net/reporting/reporting_policy.h
+++ b/net/reporting/reporting_policy.h
@@ -51,13 +51,13 @@
   // discarded as failed.
   int max_report_attempts;
 
-  // Whether to clear reports when the network changes to avoid leaking browsing
-  // data between networks.
-  bool clear_reports_on_network_changes;
+  // Whether to persist (versus clear) reports when the network changes to avoid
+  // leaking browsing data between networks.
+  bool persist_reports_across_network_changes;
 
-  // Whether to clear clients when the network changes to avoid leaking browsing
-  // data between networks.
-  bool clear_clients_on_network_changes;
+  // Whether to persist (versus clear) clients when the network changes to avoid
+  // leaking browsing data between networks.
+  bool persist_clients_across_network_changes;
 };
 
 }  // namespace net
diff --git a/net/reporting/reporting_policy.proto b/net/reporting/reporting_policy.proto
index c908b86..c7b9cb0 100644
--- a/net/reporting/reporting_policy.proto
+++ b/net/reporting/reporting_policy.proto
@@ -21,8 +21,8 @@
   required uint64 garbage_collection_interval_us = 7;
   required uint64 max_report_age_us = 8;
   required int32 max_report_attempts = 9;
-  required bool clear_reports_on_network_changes = 10;
-  required bool clear_clients_on_network_changes = 11;
+  required bool persist_reports_across_network_changes = 10;
+  required bool persist_clients_across_network_changes = 11;
 }
 
 message ReportingHeaderParserFuzzInput {
diff --git a/net/reporting/reporting_service.cc b/net/reporting/reporting_service.cc
index 46fbba8e..59976e23 100644
--- a/net/reporting/reporting_service.cc
+++ b/net/reporting/reporting_service.cc
@@ -62,10 +62,6 @@
     return context_->uploader()->RequestIsUpload(request);
   }
 
-  const ReportingPolicy& GetPolicy() const override {
-    return context_->policy();
-  }
-
  private:
   std::unique_ptr<ReportingContext> context_;
 
diff --git a/net/reporting/reporting_service.h b/net/reporting/reporting_service.h
index 37958702..aa7dc40e 100644
--- a/net/reporting/reporting_service.h
+++ b/net/reporting/reporting_service.h
@@ -70,8 +70,6 @@
   // about report uploads.
   virtual bool RequestIsUpload(const URLRequest& request) = 0;
 
-  virtual const ReportingPolicy& GetPolicy() const = 0;
-
  protected:
   ReportingService() {}
 
diff --git a/net/ssl/ssl_config.cc b/net/ssl/ssl_config.cc
index 72d63d83..75ea0f1d 100644
--- a/net/ssl/ssl_config.cc
+++ b/net/ssl/ssl_config.cc
@@ -12,7 +12,7 @@
 
 const uint16_t kDefaultSSLVersionMax = SSL_PROTOCOL_VERSION_TLS1_2;
 
-const TLS13Variant kDefaultTLS13Variant = kTLS13VariantDraft22;
+const TLS13Variant kDefaultTLS13Variant = kTLS13VariantDraft23;
 
 SSLConfig::CertAndStatus::CertAndStatus() = default;
 SSLConfig::CertAndStatus::CertAndStatus(scoped_refptr<X509Certificate> cert_arg,
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 6cfc3a38..ebb098dd 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -144,7 +144,6 @@
 #endif
 
 #if BUILDFLAG(ENABLE_REPORTING)
-#include "net/reporting/reporting_policy.h"
 #include "net/reporting/reporting_service.h"
 #include "net/url_request/network_error_logging_delegate.h"
 #endif  // BUILDFLAG(ENABLE_REPORTING)
@@ -7050,12 +7049,6 @@
     return true;
   }
 
-  const ReportingPolicy& GetPolicy() const override {
-    static ReportingPolicy dummy_policy_;
-    NOTIMPLEMENTED();
-    return dummy_policy_;
-  }
-
  private:
   std::vector<Header> headers_;
 };
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn
index 7ccd21c..3399f7f6 100644
--- a/services/network/public/cpp/BUILD.gn
+++ b/services/network/public/cpp/BUILD.gn
@@ -14,8 +14,6 @@
     "mutable_partial_network_traffic_annotation_tag_struct_traits.h",
     "net_adapters.cc",
     "net_adapters.h",
-    "network_features.cc",
-    "network_features.h",
     "network_switches.cc",
     "network_switches.h",
     "proxy_resolving_client_socket.cc",
diff --git a/services/network/public/cpp/network_features.cc b/services/network/public/cpp/network_features.cc
deleted file mode 100644
index ad31b70..0000000
--- a/services/network/public/cpp/network_features.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/network/public/cpp/network_features.h"
-
-namespace features {
-
-const base::Feature kReporting{"Reporting", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kNetworkErrorLogging{"NetworkErrorLogging",
-                                         base::FEATURE_DISABLED_BY_DEFAULT};
-
-}  // namespace features
diff --git a/services/network/public/cpp/network_features.h b/services/network/public/cpp/network_features.h
deleted file mode 100644
index 9c818f1..0000000
--- a/services/network/public/cpp/network_features.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_NETWORK_FEATURES_
-#define SERVICES_NETWORK_PUBLIC_CPP_NETWORK_FEATURES_
-
-#include "base/feature_list.h"
-
-namespace features {
-
-extern const base::Feature kReporting;
-extern const base::Feature kNetworkErrorLogging;
-
-}  // namespace features
-
-#endif  // SERVICES_NETWORK_PUBLIC_CPP_NETWORK_FEATURES_
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 243031d9..6cf37de 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -41,7 +41,6 @@
 #include "services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h"
 #include "services/viz/public/cpp/compositing/surface_id_struct_traits.h"
 #include "services/viz/public/cpp/compositing/surface_info_struct_traits.h"
-#include "services/viz/public/cpp/compositing/surface_sequence_struct_traits.h"
 #include "services/viz/public/cpp/compositing/transferable_resource_struct_traits.h"
 #include "services/viz/public/interfaces/compositing/begin_frame_args.mojom.h"
 #include "services/viz/public/interfaces/compositing/compositor_frame.mojom.h"
@@ -49,7 +48,6 @@
 #include "services/viz/public/interfaces/compositing/filter_operations.mojom.h"
 #include "services/viz/public/interfaces/compositing/returned_resource.mojom.h"
 #include "services/viz/public/interfaces/compositing/surface_info.mojom.h"
-#include "services/viz/public/interfaces/compositing/surface_sequence.mojom.h"
 #include "services/viz/public/interfaces/compositing/transferable_resource.mojom.h"
 #include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
 #include "skia/public/interfaces/blur_image_filter_tile_mode_struct_traits.h"
@@ -448,19 +446,6 @@
   EXPECT_EQ(sorting_context_id, output_sqs.sorting_context_id);
 }
 
-TEST_F(StructTraitsTest, SurfaceSequence) {
-  const FrameSinkId frame_sink_id(2016, 1234);
-  const uint32_t sequence = 0xfbadbeef;
-
-  SurfaceSequence input(frame_sink_id, sequence);
-  SurfaceSequence output;
-  mojom::SurfaceSequence::Deserialize(mojom::SurfaceSequence::Serialize(&input),
-                                      &output);
-
-  EXPECT_EQ(frame_sink_id, output.frame_sink_id);
-  EXPECT_EQ(sequence, output.sequence);
-}
-
 // Note that this is a fairly trivial test of CompositorFrame serialization as
 // most of the heavy lifting has already been done by CompositorFrameMetadata,
 // RenderPass, and QuadListBasic unit tests.
diff --git a/services/viz/public/cpp/compositing/surface_sequence.typemap b/services/viz/public/cpp/compositing/surface_sequence.typemap
deleted file mode 100644
index b2377ba..0000000
--- a/services/viz/public/cpp/compositing/surface_sequence.typemap
+++ /dev/null
@@ -1,12 +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.
-
-mojom = "//services/viz/public/interfaces/compositing/surface_sequence.mojom"
-public_headers = [ "//components/viz/common/surfaces/surface_sequence.h" ]
-traits_headers =
-    [ "//services/viz/public/cpp/compositing/surface_sequence_struct_traits.h" ]
-deps = [
-  "//components/viz/common",
-]
-type_mappings = [ "viz.mojom.SurfaceSequence=viz::SurfaceSequence" ]
diff --git a/services/viz/public/cpp/compositing/surface_sequence_struct_traits.h b/services/viz/public/cpp/compositing/surface_sequence_struct_traits.h
deleted file mode 100644
index 24563cb02..0000000
--- a/services/viz/public/cpp/compositing/surface_sequence_struct_traits.h
+++ /dev/null
@@ -1,35 +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 SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
-#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
-
-#include "components/viz/common/surfaces/surface_sequence.h"
-#include "services/viz/public/interfaces/compositing/surface_sequence.mojom-shared.h"
-
-namespace mojo {
-
-template <>
-struct StructTraits<viz::mojom::SurfaceSequenceDataView, viz::SurfaceSequence> {
-  static const viz::FrameSinkId& frame_sink_id(const viz::SurfaceSequence& id) {
-    return id.frame_sink_id;
-  }
-
-  static uint32_t sequence(const viz::SurfaceSequence& id) {
-    return id.sequence;
-  }
-
-  static bool Read(viz::mojom::SurfaceSequenceDataView data,
-                   viz::SurfaceSequence* out) {
-    viz::FrameSinkId frame_sink_id;
-    if (!data.ReadFrameSinkId(&frame_sink_id))
-      return false;
-    *out = viz::SurfaceSequence(frame_sink_id, data.sequence());
-    return true;
-  }
-};
-
-}  // namespace mojo
-
-#endif  // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
diff --git a/services/viz/public/cpp/compositing/typemaps.gni b/services/viz/public/cpp/compositing/typemaps.gni
index 689f6f4..5e57cf6 100644
--- a/services/viz/public/cpp/compositing/typemaps.gni
+++ b/services/viz/public/cpp/compositing/typemaps.gni
@@ -19,7 +19,6 @@
   "//services/viz/public/cpp/compositing/returned_resource.typemap",
   "//services/viz/public/cpp/compositing/selection.typemap",
   "//services/viz/public/cpp/compositing/shared_quad_state.typemap",
-  "//services/viz/public/cpp/compositing/surface_sequence.typemap",
   "//services/viz/public/cpp/compositing/surface_id.typemap",
   "//services/viz/public/cpp/compositing/surface_info.typemap",
   "//services/viz/public/cpp/compositing/transferable_resource.typemap",
diff --git a/services/viz/public/interfaces/BUILD.gn b/services/viz/public/interfaces/BUILD.gn
index 7f2c09c..1cad4c4 100644
--- a/services/viz/public/interfaces/BUILD.gn
+++ b/services/viz/public/interfaces/BUILD.gn
@@ -28,7 +28,6 @@
     "compositing/shared_quad_state.mojom",
     "compositing/surface_id.mojom",
     "compositing/surface_info.mojom",
-    "compositing/surface_sequence.mojom",
     "compositing/texture_releaser.mojom",
     "compositing/transferable_resource.mojom",
     "compositing/video_detector_observer.mojom",
diff --git a/services/viz/public/interfaces/compositing/surface_sequence.mojom b/services/viz/public/interfaces/compositing/surface_sequence.mojom
deleted file mode 100644
index 7d59501..0000000
--- a/services/viz/public/interfaces/compositing/surface_sequence.mojom
+++ /dev/null
@@ -1,15 +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.
-
-module viz.mojom;
-
-import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
-
-// A per-surface-namespace sequence number that's used to coordinate
-// dependencies between frames. A sequence number may be satisfied once, and
-// may be depended on once.
-struct SurfaceSequence {
-  FrameSinkId frame_sink_id;
-  uint32 sequence;
-};
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 80ec356f..69307f7 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -41832,6 +41832,27 @@
         }
       },
       {
+        "args": [],
+        "isolate_name": "performance_browser_tests",
+        "name": "performance_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:1626",
+              "id": "build126-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 600,
+          "upload_test_results": true
+        }
+      },
+      {
         "args": [
           "power.idle_platform",
           "-v",
@@ -49837,6 +49858,27 @@
         }
       },
       {
+        "args": [],
+        "isolate_name": "performance_browser_tests",
+        "name": "performance_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "id": "build132-b1",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 600,
+          "upload_test_results": true
+        }
+      },
+      {
         "args": [
           "power.idle_platform",
           "-v",
@@ -53837,6 +53879,27 @@
         }
       },
       {
+        "args": [],
+        "isolate_name": "performance_browser_tests",
+        "name": "performance_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0d26",
+              "id": "build30-b4",
+              "os": "Mac-10.11",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 600,
+          "upload_test_results": true
+        }
+      },
+      {
         "args": [
           "power.idle_platform",
           "-v",
@@ -65528,6 +65591,27 @@
         }
       },
       {
+        "args": [],
+        "isolate_name": "performance_browser_tests",
+        "name": "performance_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "id": "build103-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 600,
+          "upload_test_results": true
+        }
+      },
+      {
         "args": [
           "power.idle_platform",
           "-v",
@@ -69446,6 +69530,27 @@
         }
       },
       {
+        "args": [],
+        "isolate_name": "performance_browser_tests",
+        "name": "performance_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:041a",
+              "id": "build166-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 600,
+          "upload_test_results": true
+        }
+      },
+      {
         "args": [
           "power.idle_platform",
           "-v",
@@ -81248,6 +81353,27 @@
         }
       },
       {
+        "args": [],
+        "isolate_name": "performance_browser_tests",
+        "name": "performance_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build140-m1",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 600,
+          "upload_test_results": true
+        }
+      },
+      {
         "args": [
           "power.idle_platform",
           "-v",
@@ -85166,6 +85292,27 @@
         }
       },
       {
+        "args": [],
+        "isolate_name": "performance_browser_tests",
+        "name": "performance_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "102b:0532",
+              "id": "build145-m1",
+              "os": "Windows-2012ServerR2-SP0",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 600,
+          "upload_test_results": true
+        }
+      },
+      {
         "args": [
           "power.idle_platform",
           "-v",
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 282e3db..0dc7dae 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -267,7 +267,6 @@
 crbug.com/591099 compositing/overflow/siblings-composited-with-border-radius-ancestor.html [ Failure ]
 crbug.com/591099 compositing/overflow/siblings-with-border-radius-ancestor.html [ Failure ]
 crbug.com/591099 compositing/overflow/textarea-scroll-touch.html [ Failure ]
-crbug.com/591099 compositing/overflow/theme-affects-visual-overflow.html [ Failure Pass ]
 crbug.com/591099 compositing/overflow/universal-accelerated-overflow-scroll.html [ Pass Timeout ]
 crbug.com/591099 compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Crash Failure ]
 crbug.com/591099 compositing/reflections/compositing-change-inside-reflection.html [ Failure ]
@@ -720,16 +719,17 @@
 crbug.com/591099 css3/filters/effect-invert.html [ Failure ]
 crbug.com/591099 css3/filters/effect-opacity-hw.html [ Failure ]
 crbug.com/591099 css3/filters/effect-opacity.html [ Failure ]
-crbug.com/714962 css3/filters/effect-reference-image-lazy-attach.html [ Failure ]
-crbug.com/714962 css3/filters/effect-reference-image.html [ Failure ]
-crbug.com/714962 css3/filters/effect-reference-on-transparent-element.html [ Failure ]
+crbug.com/714962 css3/filters/effect-reference-image-lazy-attach.html [ Failure Pass ]
+crbug.com/714962 css3/filters/effect-reference-image.html [ Failure Pass ]
+crbug.com/714962 css3/filters/effect-reference-on-transparent-element.html [ Failure Pass ]
 crbug.com/714962 css3/filters/effect-reference-tile.html [ Crash ]
+crbug.com/714962 css3/filters/effect-reference-zoom-hw.html [ Failure ]
 crbug.com/591099 css3/filters/effect-saturate-hw.html [ Failure ]
 crbug.com/591099 css3/filters/effect-saturate.html [ Failure ]
 crbug.com/591099 css3/filters/effect-sepia-hw.html [ Failure ]
 crbug.com/591099 css3/filters/effect-sepia.html [ Failure ]
-crbug.com/714962 css3/filters/empty-element-with-filter.html [ Failure ]
-crbug.com/714962 css3/filters/filterRegions.html [ Failure ]
+crbug.com/714962 css3/filters/empty-element-with-filter.html [ Failure Pass ]
+crbug.com/714962 css3/filters/filterRegions.html [ Failure Pass ]
 crbug.com/591099 css3/filters/filtered-inline.html [ Failure ]
 crbug.com/714962 css3/filters/nested-filter.html [ Failure ]
 crbug.com/591099 css3/filters/regions-expanding.html [ Failure ]
@@ -1021,7 +1021,7 @@
 crbug.com/591099 editing/deleting/merge-no-br.html [ Failure ]
 crbug.com/591099 editing/deleting/merge-whitespace-pre.html [ Failure ]
 crbug.com/591099 editing/deleting/table-cells.html [ Failure ]
-crbug.com/591099 editing/deleting/transpose-empty.html [ Failure ]
+crbug.com/591099 editing/deleting/transpose-empty.html [ Failure Pass ]
 crbug.com/591099 editing/deleting/type-delete-after-quote.html [ Failure ]
 crbug.com/591099 editing/execCommand/12244.html [ Failure ]
 crbug.com/591099 editing/execCommand/4580583-1.html [ Failure ]
@@ -1180,7 +1180,6 @@
 crbug.com/714962 editing/selection/drag-drop-events.html [ Failure ]
 crbug.com/714962 editing/selection/drag-drop-restore.html [ Failure ]
 crbug.com/591099 editing/selection/drag-in-iframe.html [ Failure ]
-crbug.com/591099 editing/selection/drag-select-1.html [ Failure Pass ]
 crbug.com/714962 editing/selection/drag-select-rapidly.html [ Failure ]
 crbug.com/714962 editing/selection/drag-text-delay.html [ Failure ]
 crbug.com/591099 editing/selection/drag-to-contenteditable-iframe.html [ Failure ]
@@ -1233,6 +1232,7 @@
 crbug.com/591099 editing/selection/mouse/extend_by_word_with_base_is_end.html [ Failure ]
 crbug.com/714962 editing/selection/mouse/mouse_up_focus.html [ Timeout ]
 crbug.com/714962 editing/selection/mouse/overidden_user_select_in_dom_tree.html [ Failure ]
+crbug.com/591099 editing/selection/mouse/overriden_user_select_in_shadow_tree.html [ Failure ]
 crbug.com/714962 editing/selection/mouse/user-drag-element-and-user-select-none.html [ Failure ]
 crbug.com/591099 editing/selection/move-3875618-fix.html [ Failure ]
 crbug.com/591099 editing/selection/move-3875641-fix.html [ Failure ]
@@ -1280,7 +1280,6 @@
 crbug.com/591099 editing/selection/selection-background.html [ Failure ]
 crbug.com/591099 editing/selection/selection-button-text.html [ Failure ]
 crbug.com/591099 editing/selection/selection-invalid-offset.html [ Failure ]
-crbug.com/591099 editing/selection/selection-linebreaks-rtl-writing-modes.html [ Failure Pass ]
 crbug.com/591099 editing/selection/shift-click.html [ Failure ]
 crbug.com/714962 editing/selection/skip-over-contenteditable.html [ Failure ]
 crbug.com/591099 editing/selection/subpixel-positioned-selection.html [ Failure ]
@@ -1330,7 +1329,7 @@
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_ECDH.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_ECDSA.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_HMAC.worker.html [ Timeout ]
-crbug.com/714962 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.html [ Timeout ]
+crbug.com/714962 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.html [ Timeout ]
@@ -1339,7 +1338,7 @@
 crbug.com/709227 external/wpt/WebCryptoAPI/import_export/symmetric_importKey.worker.html [ Failure ]
 crbug.com/714962 external/wpt/WebCryptoAPI/import_export/test_rsa_importKey.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/acid/acid3/test.html [ Crash ]
-crbug.com/591099 external/wpt/compat/webkit-text-fill-color-property-005.html [ Failure Pass ]
+crbug.com/591099 external/wpt/compat/webkit-text-fill-color-property-005.html [ Pass ]
 crbug.com/591099 external/wpt/credential-management/federatedcredential-framed-get.sub.https.html [ Pass ]
 crbug.com/591099 external/wpt/credential-management/passwordcredential-framed-get.sub.https.html [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-003-left-table.xht [ Failure ]
@@ -1364,7 +1363,6 @@
 crbug.com/714962 external/wpt/css/css-backgrounds/background-image-004.html [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-backgrounds/background-image-005.html [ Failure ]
 crbug.com/714962 external/wpt/css/css-backgrounds/background-image-006.html [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-backgrounds/css3-background-clip.html [ Failure ]
 crbug.com/714962 external/wpt/css/css-display/display-contents-dynamic-before-after-001.html [ Failure ]
 crbug.com/714962 external/wpt/css/css-display/display-contents-dynamic-before-after-first-letter-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-table-001-inline.html [ Failure ]
@@ -1720,15 +1718,15 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vrl-018.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vrl-020.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vrl-030.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-003.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-005.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-003.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-005.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-007.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-009.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-011.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-013.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-011.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-013.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-015.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-017.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-019.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-017.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-019.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-021.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-023.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-025.xht [ Failure Pass ]
@@ -1737,23 +1735,23 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-031.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-033.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-035.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-037.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-037.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-039.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-041.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-043.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-045.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-047.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-049.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-051.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-049.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-051.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-053.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-055.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-055.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-057.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-059.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-061.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-063.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-063.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-065.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-067.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-069.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-069.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-071.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-073.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-075.xht [ Failure ]
@@ -1762,19 +1760,19 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-081.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-083.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-085.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-087.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-087.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-089.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-091.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-093.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-091.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-093.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-095.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-097.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-097.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-103.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-105.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-107.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-109.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-111.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-113.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-115.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-115.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-117.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-119.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-121.xht [ Failure Pass ]
@@ -1786,7 +1784,7 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-133.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-135.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-137.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-139.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-139.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-141.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-143.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-145.xht [ Failure Pass ]
@@ -1803,12 +1801,12 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-167.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-169.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-171.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-173.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-173.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-175.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-177.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-179.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-181.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-183.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-183.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-185.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-187.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-189.xht [ Failure Pass ]
@@ -1831,15 +1829,15 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-223.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-225.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-227.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-229.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vlr-229.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-004.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-006.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-008.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-010.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-010.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-012.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-014.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-016.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-016.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-018.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-020.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-022.xht [ Failure ]
@@ -1896,14 +1894,14 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-128.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-130.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-132.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-134.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-136.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-134.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-136.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-138.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-140.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-142.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-144.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-144.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-146.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-148.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-148.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-150.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-152.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-154.xht [ Failure ]
@@ -1919,7 +1917,7 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-174.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-176.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-178.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-180.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-180.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-182.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-184.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-186.xht [ Failure ]
@@ -1958,21 +1956,21 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/clearance-calculations-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/clearance-calculations-vrl-006.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/clearance-calculations-vrl-008.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/direction-vlr-003.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/direction-vlr-003.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/direction-vlr-005.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/direction-vrl-002.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/direction-vrl-004.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/direction-vrl-004.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-008.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-lft-orthog-htb-in-vrl-002.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/float-shrink-to-fit-vrl-008.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/float-vlr-005.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/float-vlr-005.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/float-vlr-007.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vlr-013.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-004.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-006.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-006.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/float-vrl-008.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-012.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/horizontal-rule-vrl-002.xht [ Failure ]
@@ -2046,18 +2044,18 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/table-column-order-005.xht [ Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-003.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-005.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-007.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-009.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-007.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-009.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-align-vlr-011.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-013.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-015.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-017.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-019.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-017.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vlr-019.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-002.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-004.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-006.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-008.xht [ Failure Pass ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-010.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-010.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-012.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-014.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-align-vrl-016.xht [ Failure ]
@@ -2066,7 +2064,7 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/text-baseline-vrl-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-combine-upright-decorations-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-combine-upright-layout-rules-001.html [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/text-indent-vlr-003.xht [ Failure ]
+crbug.com/714962 external/wpt/css/css-writing-modes/text-indent-vlr-003.xht [ Failure Pass ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-indent-vlr-005.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-indent-vlr-011.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/text-indent-vlr-013.xht [ Failure Pass ]
@@ -2114,8 +2112,8 @@
 crbug.com/591099 external/wpt/css/cssom-view/elementsFromPoint-svg.html [ Failure ]
 crbug.com/714962 external/wpt/css/cssom/medialist-dynamic-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/cssom/stylesheet-replacedata-dynamic.html [ Failure ]
-crbug.com/591099 external/wpt/css/geometry/interfaces.html [ Timeout ]
-crbug.com/591099 external/wpt/css/geometry/interfaces.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/css/geometry/interfaces.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/css/geometry/interfaces.worker.html [ Pass Timeout ]
 crbug.com/714962 external/wpt/css/selectors/focus-within-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/selectors/focus-within-004.html [ Failure ]
 crbug.com/714962 external/wpt/css/selectors/focus-within-007.html [ Failure ]
@@ -2282,7 +2280,7 @@
 crbug.com/591099 external/wpt/feature-policy/autoplay-allowed-by-feature-policy.https.sub.html [ Failure ]
 crbug.com/591099 external/wpt/feature-policy/payment-allowed-by-feature-policy.https.sub.html [ Pass ]
 crbug.com/591099 external/wpt/feature-policy/payment-disabled-by-feature-policy.https.sub.html [ Pass ]
-crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
+crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html-media-capture/capture_audio_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_image_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_video_cancel-manual.html [ Failure ]
@@ -2359,7 +2357,6 @@
 crbug.com/591099 external/wpt/intersection-observer/remove-element.html [ Failure ]
 crbug.com/714962 external/wpt/intersection-observer/root-margin.html [ Failure ]
 crbug.com/591099 external/wpt/intersection-observer/same-document-root.html [ Failure ]
-crbug.com/591099 external/wpt/keyboard-lock/navigator-keyboardLock-two-parallel-requests.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/longtask-timing/longtask-in-sibling-iframe.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/media-source/mediasource-getvideoplaybackquality.html [ Timeout ]
 crbug.com/591099 external/wpt/mediacapture-streams/MediaStreamTrack-getSettings.https.html [ Pass ]
@@ -3013,6 +3010,7 @@
 crbug.com/591099 fast/css/hover-affects-ancestor.html [ Failure ]
 crbug.com/714962 fast/css/hover-pseudo-element-quirks.html [ Failure ]
 crbug.com/591099 fast/css/hover-subselector.html [ Failure ]
+crbug.com/591099 fast/css/hover-update.html [ Timeout ]
 crbug.com/591099 fast/css/hsl-color.html [ Failure ]
 crbug.com/591099 fast/css/hsla-color.html [ Failure ]
 crbug.com/591099 fast/css/ignore-empty-focus-ring-rects.html [ Failure ]
@@ -3453,6 +3451,7 @@
 crbug.com/591099 fast/events/mousemove-to-resizer-changes-cursor.html [ Failure ]
 crbug.com/591099 fast/events/mouseover-mouseout.html [ Failure ]
 crbug.com/591099 fast/events/no-blur-on-enter-button.html [ Failure ]
+crbug.com/591099 fast/events/node-event-anchor-lock.html [ Failure ]
 crbug.com/714962 fast/events/offsetX-offsetY.html [ Failure ]
 crbug.com/591099 fast/events/onblur-remove.html [ Failure ]
 crbug.com/714962 fast/events/onchange-click-hang.html [ Failure ]
@@ -3460,6 +3459,7 @@
 crbug.com/591099 fast/events/onclick-list-marker.html [ Failure ]
 crbug.com/591099 fast/events/onload-re-entry.html [ Failure ]
 crbug.com/591099 fast/events/onload-webkit-before-webcore.html [ Failure ]
+crbug.com/591099 fast/events/open-window-from-another-frame.html [ Timeout ]
 crbug.com/591099 fast/events/pointer-events-2.html [ Failure ]
 crbug.com/714962 fast/events/pointerevents/mouse-node-remove.html [ Failure ]
 crbug.com/714962 fast/events/pointerevents/mouse-pointer-boundary-events-for-shadowdom.html [ Failure ]
@@ -3567,7 +3567,7 @@
 crbug.com/714962 fast/forms/calendar-picker/month-picker-mouse-operations.html [ Failure ]
 crbug.com/714962 fast/forms/calendar-picker/week-picker-appearance-step.html [ Failure ]
 crbug.com/714962 fast/forms/calendar-picker/week-picker-appearance.html [ Failure ]
-crbug.com/591099 fast/forms/calendar-picker/week-picker-key-operations.html [ Timeout ]
+crbug.com/591099 fast/forms/calendar-picker/week-picker-key-operations.html [ Pass Timeout ]
 crbug.com/714962 fast/forms/calendar-picker/week-picker-mouse-operations.html [ Failure ]
 crbug.com/591099 fast/forms/caret-rtl.html [ Failure ]
 crbug.com/714962 fast/forms/checkbox/checkbox-focus-by-mouse.html [ Failure ]
@@ -3673,7 +3673,7 @@
 crbug.com/591099 fast/forms/label/labels-remove-htmlFor-label.html [ Crash ]
 crbug.com/591099 fast/forms/label/labels-remove-parent-label.html [ Crash ]
 crbug.com/591099 fast/forms/label/labels-set-htmlFor-attribute.html [ Crash ]
-crbug.com/591099 fast/forms/label/selection-disabled-label.html [ Failure ]
+crbug.com/591099 fast/forms/label/selection-disabled-label.html [ Failure Crash ]
 crbug.com/591099 fast/forms/long-text-in-input.html [ Crash Failure ]
 crbug.com/591099 fast/forms/mailto/advanced-get.html [ Failure ]
 crbug.com/591099 fast/forms/mailto/advanced-put.html [ Failure ]
@@ -3974,6 +3974,7 @@
 crbug.com/591099 fast/forms/textarea/textarea-setinnerhtml.html [ Failure ]
 crbug.com/591099 fast/forms/textarea/textarea-width.html [ Failure ]
 crbug.com/714962 fast/forms/time-multiple-fields/time-multiple-fields-clearbutton-change-and-input-events.html [ Failure ]
+crbug.com/591099 fast/forms/time-multiple-fields/time-multiple-fields-focus.html [ Failure ]
 crbug.com/714962 fast/forms/time-multiple-fields/time-multiple-fields-mouse-events.html [ Failure ]
 crbug.com/714962 fast/forms/time-multiple-fields/time-multiple-fields-narrow-width-scroll.html [ Failure ]
 crbug.com/714962 fast/forms/time-multiple-fields/time-multiple-fields-spinbutton-change-and-input-events.html [ Failure ]
@@ -4109,6 +4110,7 @@
 crbug.com/591099 fast/inline/inline-with-empty-inline-children.html [ Failure ]
 crbug.com/591099 fast/inline/inline-wrap-with-parent-padding.html [ Failure ]
 crbug.com/591099 fast/inline/justify-emphasis-inline-box.html [ Failure ]
+crbug.com/591099 fast/inline/layout-after-inserting-nested-br.html [ Failure ]
 crbug.com/591099 fast/inline/left-right-center-inline-alignment-in-ltr-and-rtl-blocks.html [ Failure ]
 crbug.com/591099 fast/inline/outline-continuations.html [ Failure ]
 crbug.com/714962 fast/inline/outline-offset.html [ Failure ]
@@ -4205,7 +4207,7 @@
 crbug.com/591099 fast/lists/ordered-list-with-no-ol-tag.html [ Failure ]
 crbug.com/591099 fast/lists/remove-listmarker-and-make-anonblock-empty-2.html [ Failure ]
 crbug.com/591099 fast/lists/remove-listmarker-from-anonblock-with-continuation-crash.html [ Crash ]
-crbug.com/591099 fast/loader/child-frame-add-after-back-forward.html [ Timeout ]
+crbug.com/591099 fast/loader/child-frame-add-after-back-forward.html [ Timeout Failure ]
 crbug.com/591099 fast/loader/document-with-fragment-url-1.html [ Timeout ]
 crbug.com/591099 fast/loader/document-with-fragment-url-3.html [ Timeout ]
 crbug.com/591099 fast/loader/document-with-fragment-url-4.html [ Timeout ]
@@ -4743,7 +4745,7 @@
 crbug.com/714962 fast/replaced/vertical-rl/absolute-position-with-auto-height-and-top-and-bottom.html [ Failure ]
 crbug.com/714962 fast/replaced/vertical-rl/absolute-position-with-auto-width-and-left-and-right.html [ Failure ]
 crbug.com/591099 fast/replaced/width100percent-image.html [ Failure ]
-crbug.com/714962 fast/replaced/width100percent-textarea.html [ Failure ]
+crbug.com/714962 fast/replaced/width100percent-textarea.html [ Failure Pass ]
 crbug.com/591099 fast/ruby/add-text-to-block-ruby-with-after-pseudo-crash.html [ Crash ]
 crbug.com/591099 fast/ruby/base-shorter-than-text.html [ Failure ]
 crbug.com/591099 fast/ruby/float-object-doesnt-crash.html [ Crash ]
@@ -5238,7 +5240,6 @@
 crbug.com/591099 fast/text/sub-pixel/text-scaling-pixel.html [ Failure ]
 crbug.com/714962 fast/text/tab-min-size.html [ Failure Pass ]
 crbug.com/714962 fast/text/text-range-bounds.html [ Failure ]
-crbug.com/591099 fast/text/textIteratorNilRenderer.html [ Failure Pass ]
 crbug.com/591099 fast/text/trailing-white-space-2.html [ Failure ]
 crbug.com/714962 fast/text/transform-text-first-line-capitalize.html [ Failure ]
 crbug.com/714962 fast/text/transform-text-first-line-lowercase.html [ Failure ]
@@ -5625,6 +5626,7 @@
 crbug.com/591099 http/tests/devtools/elements/navigate-styles-sidebar-with-arrow-keys.js [ Crash Pass ]
 crbug.com/714962 http/tests/devtools/elements/shadow/breadcrumb-shadow-roots.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/shadow/create-shadow-root.js [ Crash ]
+crbug.com/591099 http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-1.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/shadow/inspect-deep-shadow-element.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/shadow/shadow-distribution.js [ Crash ]
 crbug.com/714962 http/tests/devtools/elements/shadow/shadow-host-display-modes.js [ Crash ]
@@ -5692,13 +5694,14 @@
 crbug.com/591099 http/tests/devtools/sources/debugger-breakpoints/dom-breakpoints.js [ Crash ]
 crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints.js [ Crash ]
 crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-jquery.js [ Crash Pass ]
+crbug.com/591099 http/tests/devtools/sources/debugger-frameworks/frameworks-steppings.js [ Crash ]
 crbug.com/591099 http/tests/devtools/sources/debugger-pause/debugger-eval-on-call-frame-inside-iframe.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger-pause/debugger-eval-while-paused.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger-pause/debugger-pause-in-internal.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger-pause/debugger-pause-on-promise-rejection.js [ Crash ]
 crbug.com/591099 http/tests/devtools/sources/debugger-step/debugger-step-into-custom-element-callbacks.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger-step/debugger-step-out-custom-element-callbacks.js [ Crash Pass ]
-crbug.com/591099 http/tests/devtools/sources/debugger-step/debugger-step-out-event-listener.js [ Crash ]
+crbug.com/591099 http/tests/devtools/sources/debugger-step/debugger-step-out-event-listener.js [ Crash Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger-ui/debugger-inline-values.js [ Crash ]
 crbug.com/591099 http/tests/devtools/sources/debugger-ui/function-generator-details.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger-ui/watch-expressions-panel-switch.js [ Crash Pass ]
@@ -5706,14 +5709,9 @@
 crbug.com/591099 http/tests/devtools/sources/debugger/live-edit-no-reveal.js [ Failure ]
 crbug.com/591099 http/tests/devtools/sources/debugger/properties-special.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/text-autosizing-override.js [ Failure ]
-crbug.com/714962 http/tests/devtools/tracing/scroll-invalidations.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-bound-function.js [ Failure ]
-crbug.com/714962 http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.js [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Pass Timeout ]
-crbug.com/714962 http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js [ Failure Timeout ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js [ Failure Timeout ]
-crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js [ Pass Timeout ]
 crbug.com/591099 http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy-relocate-and-no-reload.html [ Timeout ]
 crbug.com/591099 http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy-relocate-and-reload.html [ Timeout ]
 crbug.com/591099 http/tests/feature-policy-experimental-features/vibrate-allowed-by-container-policy.html [ Timeout ]
@@ -5782,8 +5780,10 @@
 crbug.com/714962 http/tests/navigation/javascriptlink-subframeload.html [ Timeout ]
 crbug.com/591099 http/tests/navigation/metaredirect-basic.html [ Failure ]
 crbug.com/591099 http/tests/navigation/metaredirect-goback.html [ Failure ]
-crbug.com/591099 http/tests/navigation/no-referrer-reset.html [ Failure ]
+crbug.com/591099 http/tests/navigation/no-referrer-reset.html [ Failure Timeout ]
+crbug.com/591099 http/tests/navigation/no-referrer-same-window.html [ Timeout ]
 crbug.com/714962 http/tests/navigation/no-referrer-subframe.html [ Timeout ]
+crbug.com/591099 http/tests/navigation/no-referrer-target-blank.html [ Timeout ]
 crbug.com/591099 http/tests/navigation/onload-navigation-iframe-2.html [ Failure ]
 crbug.com/714962 http/tests/navigation/ping-cookie.html [ Timeout ]
 crbug.com/714962 http/tests/navigation/ping-cross-origin-from-https.html [ Timeout ]
@@ -6005,7 +6005,7 @@
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-labelledby.js [ Timeout ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-summary.js [ Crash ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-visiblity.js [ Timeout ]
-crbug.com/591099 inspector-protocol/css/css-add-rule.js [ Timeout ]
+crbug.com/591099 inspector-protocol/css/css-add-rule.js [ Pass Timeout ]
 crbug.com/714962 inspector-protocol/css/css-get-platform-fonts.js [ Failure ]
 crbug.com/591099 inspector-protocol/css/css-set-style-text.js [ Pass Timeout ]
 crbug.com/714962 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-viewport.js [ Failure ]
@@ -6511,7 +6511,6 @@
 crbug.com/714962 paint/invalidation/svg/feImage-target-style-change.svg [ Failure ]
 crbug.com/714962 paint/invalidation/svg/filter-child-repaint.svg [ Failure ]
 crbug.com/714962 paint/invalidation/svg/filter-refresh.svg [ Failure ]
-crbug.com/591099 paint/invalidation/svg/foreign-object-repaint.svg [ Failure Pass ]
 crbug.com/714962 paint/invalidation/svg/hairline-stroke-squarecap.svg [ Failure ]
 crbug.com/714962 paint/invalidation/svg/hit-test-with-br.xhtml [ Failure ]
 crbug.com/714962 paint/invalidation/svg/image-with-clip-path.svg [ Failure ]
@@ -6604,7 +6603,6 @@
 crbug.com/591099 paint/invalidation/svg/use-setAttribute-crash.svg [ Failure ]
 crbug.com/714962 paint/invalidation/svg/window.svg [ Failure ]
 crbug.com/714962 paint/invalidation/svg/zoom-coords-viewattr-01-b.svg [ Failure ]
-crbug.com/714962 paint/invalidation/svg/zoom-foreignObject.svg [ Failure Pass ]
 crbug.com/591099 paint/invalidation/table/add-table-overpaint.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/block-selection-gap-in-table-cell.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/border-collapse-change-collapse-to-separate.html [ Failure ]
@@ -6823,7 +6821,7 @@
 crbug.com/591099 printing/thead-repeats-at-top-of-each-page.html [ Failure ]
 crbug.com/591099 printing/thead-under-multicol.html [ Failure ]
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
-crbug.com/714962 scrollbars/border-box-rect-clips-scrollbars.html [ Failure ]
+crbug.com/714962 scrollbars/border-box-rect-clips-scrollbars.html [ Failure Pass ]
 crbug.com/591099 scrollbars/custom-scrollbar-enable-changes-thickness-with-iframe.html [ Failure ]
 crbug.com/591099 scrollbars/custom-scrollbar-with-incomplete-style.html [ Failure ]
 crbug.com/714962 scrollbars/custom-scrollbars-paint-outside-iframe.html [ Failure ]
@@ -6940,7 +6938,7 @@
 crbug.com/591099 svg/as-image/svg-as-relative-image-with-explicit-size.html [ Failure ]
 crbug.com/591099 svg/as-image/svg-as-relative-image.html [ Failure ]
 crbug.com/591099 svg/as-image/svg-image-leak-loader.html [ Failure ]
-crbug.com/714962 svg/as-image/svg-image-with-css-animation.html [ Failure ]
+crbug.com/714962 svg/as-image/svg-image-with-css-animation.html [ Failure Pass ]
 crbug.com/714962 svg/as-image/svg-intrinsic-size-rectangular-vertical.html [ Failure ]
 crbug.com/714962 svg/as-image/svg-intrinsic-size-rectangular.html [ Failure ]
 crbug.com/591099 svg/as-image/svg-non-integer-scaled-image.html [ Failure ]
@@ -7033,8 +7031,8 @@
 crbug.com/591099 svg/custom/foreign-object-skew.svg [ Failure ]
 crbug.com/591099 svg/custom/getscreenctm-in-mixed-content.xhtml [ Failure ]
 crbug.com/591099 svg/custom/getscreenctm-in-mixed-content2.xhtml [ Failure ]
-crbug.com/591099 svg/custom/getscreenctm-in-scrollable-div-area-nested.xhtml [ Failure ]
-crbug.com/591099 svg/custom/getscreenctm-in-scrollable-div-area.xhtml [ Failure ]
+crbug.com/591099 svg/custom/getscreenctm-in-scrollable-div-area-nested.xhtml [ Failure Pass ]
+crbug.com/591099 svg/custom/getscreenctm-in-scrollable-div-area.xhtml [ Failure Pass ]
 crbug.com/591099 svg/custom/getsvgdocument.html [ Failure ]
 crbug.com/714962 svg/custom/group-opacity.svg [ Failure ]
 crbug.com/591099 svg/custom/hit-test-path-stroke.svg [ Failure ]
@@ -7068,7 +7066,6 @@
 crbug.com/591099 svg/custom/svg-fonts-in-html.html [ Failure ]
 crbug.com/591099 svg/custom/svg-fonts-word-spacing.html [ Failure ]
 crbug.com/591099 svg/custom/tabindex-order.html [ Failure ]
-crbug.com/714962 svg/custom/text-clip.svg [ Failure Pass ]
 crbug.com/591099 svg/custom/text-match-highlight.html [ Failure ]
 crbug.com/714962 svg/custom/transformed-outlines.svg [ Failure ]
 crbug.com/591099 svg/custom/transformed-text-pattern.html [ Failure ]
@@ -7113,7 +7110,6 @@
 crbug.com/591099 svg/foreignObject/mask.html [ Failure ]
 crbug.com/591099 svg/foreignObject/multiple-foreign-objects.html [ Failure ]
 crbug.com/591099 svg/foreignObject/svg-document-in-html-document.svg [ Failure ]
-crbug.com/714962 svg/foreignObject/vertical-foreignObject.html [ Failure Pass ]
 crbug.com/591099 svg/hittest/clip-path-shape.html [ Failure ]
 crbug.com/591099 svg/hittest/ellipse-hittest.html [ Failure ]
 crbug.com/591099 svg/hittest/empty-container.html [ Failure ]
@@ -7130,7 +7126,6 @@
 crbug.com/591099 svg/hixie/error/012.xml [ Failure ]
 crbug.com/591099 svg/hixie/error/013.xml [ Failure ]
 crbug.com/591099 svg/hixie/mixed/006.xml [ Failure ]
-crbug.com/591099 svg/hixie/mixed/009.xml [ Failure Pass ]
 crbug.com/591099 svg/hixie/mixed/011.xml [ Failure ]
 crbug.com/714962 svg/hixie/perf/007.xml [ Failure ]
 crbug.com/714962 svg/hixie/viewbox/preserveAspectRatio/001.xml [ Failure ]
@@ -7192,7 +7187,6 @@
 crbug.com/591099 svg/zoom/page/zoom-svg-through-object-with-absolute-size.xhtml [ Failure ]
 crbug.com/591099 svg/zoom/page/zoom-svg-through-object-with-override-size.html [ Failure ]
 crbug.com/591099 svg/zoom/page/zoom-svg-through-object-with-percentage-size.xhtml [ Failure ]
-crbug.com/591099 svg/zoom/text/zoom-hixie-mixed-008.xml [ Failure Pass ]
 crbug.com/591099 svg/zoom/text/zoom-hixie-mixed-009.xml [ Failure ]
 crbug.com/591099 svg/zoom/text/zoom-svg-float-border-padding.xml [ Failure ]
 crbug.com/591099 tables/layering/paint-test-layering-1.html [ Failure ]
@@ -7544,7 +7538,6 @@
 crbug.com/714962 virtual/gpu/fast/canvas/canvas-css-clip-path.html [ Failure ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-drawImage-animated-images.html [ Failure ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-drawImage-video-imageSmoothingEnabled.html [ Pass ]
-crbug.com/591099 virtual/gpu/fast/canvas/canvas-fillPath-shadow.html [ Pass Timeout ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-imageSmoothingQuality.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-measure-bidi-text.html [ Failure ]
 crbug.com/714962 virtual/gpu/fast/canvas/canvas-textMetrics-width.html [ Failure ]
@@ -7688,6 +7681,7 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mousemove-to-resizer-changes-cursor.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouseover-mouseout.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/no-blur-on-enter-button.html [ Failure ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/node-event-anchor-lock.html [ Failure ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/offsetX-offsetY.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/onblur-remove.html [ Failure ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/onchange-click-hang.html [ Failure ]
@@ -7695,6 +7689,7 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/onclick-list-marker.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/onload-re-entry.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/onload-webkit-before-webcore.html [ Failure ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/open-window-from-another-frame.html [ Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointer-events-2.html [ Failure ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-node-remove.html [ Failure ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-boundary-events-for-shadowdom.html [ Failure ]
@@ -7762,17 +7757,14 @@
 crbug.com/591099 virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Failure ]
 crbug.com/591099 virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure ]
 crbug.com/591099 virtual/scalefactor150/fast/hidpi/static/popup-menu-with-scrollbar-appearance.html [ Failure ]
-crbug.com/591099 virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
 crbug.com/714962 virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance.html [ Failure ]
 crbug.com/714962 virtual/scalefactor200/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure ]
 crbug.com/714962 virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance.html [ Failure ]
 crbug.com/591099 virtual/scalefactor200/fast/hidpi/static/popup-menu-with-scrollbar-appearance.html [ Failure ]
-crbug.com/591099 virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
 crbug.com/714962 virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance.html [ Failure ]
 crbug.com/714962 virtual/scalefactor200withzoom/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure ]
 crbug.com/714962 virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ Failure ]
 crbug.com/591099 virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-with-scrollbar-appearance.html [ Failure ]
-crbug.com/591099 virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure Pass ]
 crbug.com/591099 virtual/scroll_customization/ [ Skip ]
 crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-animation.html [ Pass ]
 crbug.com/591099 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-global.html [ Pass ]
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations
index 9e9ef4b..0bbc033 100644
--- a/third_party/WebKit/LayoutTests/LeakExpectations
+++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -11,6 +11,7 @@
 
 # FIXME: scroll customization leaks memory. See
 # codereview.chromium.org/1236913004/ for context.
+crbug.com/410974 virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scroll-customization-property.html [ Leak ]
 crbug.com/410974 virtual/scroll_customization/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html [ Leak ]
 crbug.com/410974 virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scrollstate-distribute-to-scroll-chain-descendant.html [ Leak ]
 
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index ee29e4d..e5791c39 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -467,3 +467,6 @@
 crbug.com/779366 fast/shapes/crash-allocating-very-large-raster-shape.html [ Slow ]
 
 crbug.com/787971 external/wpt/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.worker.html [ Slow ]
+
+# This test has many test cases and each case requires a gesture scroll with pauses in between.
+crbug.com/765326 virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scroll-customization-property.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 1ba11692..9cf1dafe 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -527,6 +527,7 @@
 crbug.com/714962 virtual/layout_ng/fast/inline/drawStyledEmptyInlines.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/inline-borders-with-bidi-override.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/inline-focus-ring-under-absolute-enclosing-relative-div.html [ Failure ]
+crbug.com/714962 virtual/layout_ng/fast/inline/layout-after-inserting-nested-br.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/left-right-center-inline-alignment-in-ltr-and-rtl-blocks.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/out-of-flow-objects-and-whitespace-after-empty-inline.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/outline-continuations.html [ Failure ]
@@ -710,8 +711,6 @@
 
 crbug.com/788110 [ Linux Win10 ] inspector-protocol/layout-fonts/unicode-range-combining-chars-fallback.js [ Pass Failure ]
 
-crbug.com/803276 [ Mac Win ] inspector-protocol/memory/sampling-native-profile.js [ Skip ]
-
 # Run these tests with under virtual/scalefactor... only.
 crbug.com/567837 fast/hidpi/static [ Skip ]
 
@@ -1401,6 +1400,7 @@
 crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/pointerevents/pointer-event-consumed-touchstart-in-slop-region.html [ Skip ]
 crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/pointerevents/pointer-event-in-slop-region.html [ Skip ]
 crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/synthetic-events/tap-on-scaled-screen.html  [ Skip ]
+crbug.com/613672 [ Mac ] virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scroll-customization-property.html [ Skip ]
 
 # We should send PointerLeave events for stylus devices.
 crbug.com/583413 external/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html  [ Failure ]
@@ -3418,6 +3418,9 @@
 # Does not work on Mac
 crbug.com/793771 [ Mac ] virtual/modern-media-controls/media/controls/modern/scrubbing.html [ Skip ]
 
+# Flaky on Windows
+crbug.com/801341 [ Win ] http/tests/misc/webtiming-resolution.html [ Failure Pass ]
+
 crbug.com/797138 external/wpt/credential-management/federatedcredential-framed-get.sub.https.html [ Crash ]
 crbug.com/797138 external/wpt/credential-management/passwordcredential-framed-get.sub.https.html [ Crash ]
 
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/scrollbars-with-clipped-owner.html b/third_party/WebKit/LayoutTests/compositing/overflow/scrollbars-with-clipped-owner.html
index af256e3d..cc81804 100644
--- a/third_party/WebKit/LayoutTests/compositing/overflow/scrollbars-with-clipped-owner.html
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/scrollbars-with-clipped-owner.html
@@ -1,6 +1,13 @@
 <!DOCTYPE HTML>
 <html>
   <head>
+    <script>
+        // Disable implicit root scroller since the outer div is full screen
+        // and would otherwise be promoted to rootScroller. Doing so causes it
+        // to be composited and produces off-by-one differences due to how
+        // scrollbar positions are calculated in the compositor.
+        window.internals.runtimeFlags.implicitRootScrollerEnabled = false;
+    </script>
     <style>
       body {
         margin: 0px;
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 646fe916..7c5e182 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -79925,6 +79925,18 @@
      {}
     ]
    ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003.html": [
+    [
+     "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-root-node-001a.html": [
     [
      "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-root-node-001a.html",
@@ -124564,6 +124576,11 @@
      {}
     ]
    ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-root-node-001-ref.html": [
     [
      {}
@@ -151694,6 +151711,11 @@
      {}
     ]
    ],
+   "webauthn/createcredential-badargs-rp.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webauthn/createcredential-passing.https-expected.txt": [
     [
      {}
@@ -299472,6 +299494,14 @@
    "6092f9269a40b5d763b3e71cb235d917c418ed38",
    "reftest"
   ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003-ref.html": [
+   "8ce06ed245c0bb9d391c751ad73a8bdc9c6934ab",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003.html": [
+   "3f3c416f2f966ea2208f89a0e90b26385ee35694",
+   "reftest"
+  ],
   "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-root-node-001-ref.html": [
    "b06b801d20ebf9776648cb522ec427a1676e7490",
    "support"
@@ -353132,6 +353162,10 @@
    "832fb99e215923e9d102f48f2a0cd06ea11ff86b",
    "support"
   ],
+  "webauthn/createcredential-badargs-rp.https-expected.txt": [
+   "6b8193f882d66d96ace82fbd997eb624d90b19e7",
+   "support"
+  ],
   "webauthn/createcredential-badargs-rp.https.html": [
    "941a9bda02e22b7d54855e3a4714a49d8392fa9d",
    "testharness"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003-ref.html
new file mode 100644
index 0000000..5eadc30
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <style>
+    .limeSquare {
+      background: lime;
+      height: 100px; width: 100px;
+    }
+  </style>
+</head>
+<body>
+  <div class="limeSquare"></div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003.html
new file mode 100644
index 0000000..1a5175c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-003.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing that paint order isn't influenced
+         by "order" for absolutely positioned flex children</title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#abspos-items">
+  <link rel="help" href="http://www.w3.org/TR/css-flexbox-1/#painting">
+  <link rel="match" href="flexbox-paint-ordering-003-ref.html">
+  <style>
+    .container { display: flex; }
+    .absPosLowOrder {
+      position: absolute;
+      order: 5;
+      background: red;
+      height: 0;
+      width: 0;
+    }
+    .absPosHighOrder {
+      position: absolute;
+      order: 10;
+      height: 0;
+      width: 0;
+    }
+    .redBlock {
+      height: 100px;
+      width: 100px;
+      background: red;
+    }
+    .limeBlock {
+      height: 100px;
+      width: 100px;
+      background: lime;
+    }
+  </style>
+</head>
+<body>
+  <div class="container">
+    <!-- Note: The following elements will be superimposed.  If they weren't
+         positioned, then they'd be flex items, and their relative "order"
+         values would force the first one (with the red child) to paint on top.
+         But since they're absolutely positioned, they're not flex items &
+         "order" has no effect, and so the lime one should end up on top. -->
+    <div class="absPosHighOrder"><div class="redBlock"></div></div>
+    <div class="absPosLowOrder"><div class="limeBlock"></div></div>
+  </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/device-memory/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/device-memory/OWNERS
new file mode 100644
index 0000000..d7c51dc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/device-memory/OWNERS
@@ -0,0 +1,4 @@
+# TEAM: progressive-web-metrics@chromium.org
+# COMPONENT: Blink>PerformanceAPIs
+fmeawad@chromium.org
+panicker@chromium.org
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/navigator/device-memory.https.any.js b/third_party/WebKit/LayoutTests/external/wpt/device-memory/device-memory.https.any.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/navigator/device-memory.https.any.js
rename to third_party/WebKit/LayoutTests/external/wpt/device-memory/device-memory.https.any.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
index 75e8ed7..a217f85f5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 5263 tests; 5151 PASS, 112 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 5263 tests; 5152 PASS, 111 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test driver
 PASS Document interface: attribute domain
 PASS Document interface: attribute referrer
@@ -4966,7 +4966,7 @@
 PASS MessageEvent interface: attribute lastEventId
 PASS MessageEvent interface: attribute source
 PASS MessageEvent interface: attribute ports
-FAIL MessageEvent interface: operation initMessageEvent(DOMString, boolean, boolean, any, USVString, DOMString, MessageEventSource, [object Object]) assert_equals: property has wrong .length expected 1 but got 0
+PASS MessageEvent interface: operation initMessageEvent(DOMString, boolean, boolean, any, USVString, DOMString, MessageEventSource, [object Object])
 PASS MessageEvent must be primary interface of new MessageEvent("message", { data: 5 })
 PASS Stringification of new MessageEvent("message", { data: 5 })
 PASS MessageEvent interface: new MessageEvent("message", { data: 5 }) must inherit property "data" with the proper type
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/platform/mac/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
rename to third_party/WebKit/LayoutTests/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
diff --git a/third_party/WebKit/LayoutTests/fast/events/drag-on-removed-slider-does-not-crash.html b/third_party/WebKit/LayoutTests/fast/events/drag-on-removed-slider-does-not-crash.html
new file mode 100644
index 0000000..094d4aa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/drag-on-removed-slider-does-not-crash.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
+<input max=100 type="range" id="slider">
+
+<script>
+document.getElementById("slider").addEventListener("input", function() {
+  this.removeAttribute("type");
+});
+var centerY = slider.offsetTop + slider.offsetHeight / 2;
+var centerX = slider.offsetLeft + slider.offsetWidth / 2;
+var rightEdgeX = slider.offsetLeft + slider.offsetWidth - 1;
+const touchIdentifier = 1;
+
+function smoothDrag() {
+  return new Promise((resolve, reject) => {
+    chrome.gpuBenchmarking.smoothDrag(centerX, centerY, rightEdgeX, centerY,
+      resolve, touchIdentifier);
+  })
+}
+
+const IS_MAC = navigator.platform.indexOf('Mac') == 0;
+promise_test(t => {
+  if (!IS_MAC) {
+    return smoothDrag();
+  } else {
+    return new Promise((resolve, reject) => {
+      resolve();
+    });
+  }
+}, 'Drag on removed slider should not crash.');
+
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-click-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-click-expected.txt
new file mode 100644
index 0000000..bdee900
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-click-expected.txt
@@ -0,0 +1,4 @@
+Mock: Opening a file chooser.
+Ensure clicking on an INPUT element with TYPE=FILE launches a file chooser. Automated test passes if 'Opening a file chooser' was logged.
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-click.html b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-click.html
new file mode 100644
index 0000000..0f2a035
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-click.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>INPUT TYPE=FILE and click events</title>
+<p>
+  Ensure clicking on an INPUT element with TYPE=FILE launches a file
+  chooser. Automated test passes if 'Opening a file chooser' was
+  logged.
+</p>
+<input type="file">
+<script>
+if (testRunner && eventSender) {
+  testRunner.dumpAsText();
+  const file = document.querySelector('input');
+  const x = file.offsetLeft + file.offsetWidth / 2;
+  const y = file.offsetTop + file.offsetHeight / 2;
+
+  eventSender.mouseMoveTo(x, y);
+  eventSender.mouseDown();
+  eventSender.mouseMoveTo(x, y);
+  eventSender.mouseUp();
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-enter-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-enter-expected.txt
new file mode 100644
index 0000000..b90e224
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-enter-expected.txt
@@ -0,0 +1,4 @@
+Mock: Opening a file chooser.
+Ensure pressing Enter key with focus on an INPUT element with TYPE=FILE launches a file chooser. Automated test passes if 'Opening a file chooser' was logged.
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-enter.html b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-enter.html
new file mode 100644
index 0000000..b670103
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-enter.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>INPUT TYPE=FILE and key events - Enter key</title>
+<p>
+  Ensure pressing Enter key with focus on an INPUT element with
+  TYPE=FILE launches a file chooser. Automated test passes if 'Opening
+  a file chooser' was logged.
+</p>
+<input type="file">
+<script>
+if (testRunner && eventSender) {
+  testRunner.dumpAsText();
+  const file = document.querySelector('input');
+  file.focus();
+  // Despite the name, 'keyDown' simulates a full down/press/up sequence.
+  eventSender.keyDown('Enter', []);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-other-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-other-expected.txt
new file mode 100644
index 0000000..1ae0677
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-other-expected.txt
@@ -0,0 +1,3 @@
+Ensure pressing non-enter/space keys with focus on an INPUT element with TYPE=FILE does not launch a file chooser. Automated test fails if 'Opening a file chooser' was logged.
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-other.html b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-other.html
new file mode 100644
index 0000000..7b35573
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-other.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>INPUT TYPE=FILE and key events - Other keys</title>
+<p>
+  Ensure pressing non-enter/space keys with focus on an INPUT element
+  with TYPE=FILE does <b>not</b> launch a file chooser. Automated test
+  <b>fails</b> if 'Opening a file chooser' was logged.
+</p>
+<input type="file">
+<script>
+if (testRunner && eventSender) {
+  testRunner.dumpAsText();
+  const file = document.querySelector('input');
+  file.focus();
+  ['x', '0', 'ArrowRight', 'ControlLeft'].forEach(key => {
+    // Despite the name, 'keyDown' simulates a full down/press/up sequence.
+    eventSender.keyDown(key, []);
+  });
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-space-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-space-expected.txt
new file mode 100644
index 0000000..eee8e57
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-space-expected.txt
@@ -0,0 +1,4 @@
+Mock: Opening a file chooser.
+Ensure pressing Space key with focus on an INPUT element with TYPE=FILE launches a file chooser. Automated test passes if 'Opening a file chooser' was logged.
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-space.html b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-space.html
new file mode 100644
index 0000000..3eff66d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-key-space.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>INPUT TYPE=FILE and key events - Space key</title>
+<p>
+  Ensure pressing Space key with focus on an INPUT element with
+  TYPE=FILE launches a file chooser. Automated test passes if 'Opening
+  a file chooser' was logged.
+</p>
+<input type="file">
+<script>
+if (testRunner && eventSender) {
+  testRunner.dumpAsText();
+  const file = document.querySelector('input');
+  file.focus();
+  // Despite the name, 'keyDown' simulates a full down/press/up sequence.
+  eventSender.keyDown(' ', []);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-click-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-click-expected.txt
new file mode 100644
index 0000000..4c350037
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-click-expected.txt
@@ -0,0 +1,4 @@
+Mock: Opening a file chooser.
+Ensure clicking on an INPUT element with TYPE=FILE and WEBKITDIRECTORY launches a file chooser. Automated test passes if 'Opening a file chooser' was logged.
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-click.html b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-click.html
new file mode 100644
index 0000000..ade732ad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-click.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>INPUT TYPE=FILE WEBKITDIRECTORY and click events</title>
+<p>
+  Ensure clicking on an INPUT element with TYPE=FILE and
+  WEBKITDIRECTORY launches a file chooser. Automated test passes if
+  'Opening a file chooser' was logged.
+</p>
+<input type="file" webkitdirectory>
+<script>
+if (testRunner && eventSender) {
+  testRunner.dumpAsText();
+  const file = document.querySelector('input');
+  const x = file.offsetLeft + file.offsetWidth / 2;
+  const y = file.offsetTop + file.offsetHeight / 2;
+
+  eventSender.mouseMoveTo(x, y);
+  eventSender.mouseDown();
+  eventSender.mouseMoveTo(x, y);
+  eventSender.mouseUp();
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-enter-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-enter-expected.txt
new file mode 100644
index 0000000..fe6cfc35
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-enter-expected.txt
@@ -0,0 +1,4 @@
+Mock: Opening a file chooser.
+Ensure pressing Enter key with focus on an INPUT element with TYPE=FILE and WEBKITDIRECTORY launches a file chooser. Automated test passes if 'Opening a file chooser' was logged.
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-enter.html b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-enter.html
new file mode 100644
index 0000000..ed28f60a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-enter.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>INPUT TYPE=FILE WEBKITDIRECTORY and key events - Enter key</title>
+<p>
+  Ensure pressing Enter key with focus on an INPUT element with
+  TYPE=FILE and WEBKITDIRECTORY launches a file chooser. Automated
+  test passes if 'Opening a file chooser' was logged.
+</p>
+<input type="file" webkitdirectory>
+<script>
+if (testRunner && eventSender) {
+  testRunner.dumpAsText();
+  const file = document.querySelector('input');
+  file.focus();
+  // Despite the name, 'keyDown' simulates a full down/press/up sequence.
+  eventSender.keyDown('Enter', []);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-other-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-other-expected.txt
new file mode 100644
index 0000000..3b2aa3f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-other-expected.txt
@@ -0,0 +1,3 @@
+Ensure pressing non-enter/space keys with focus on an INPUT element with TYPE=FILE and WEBKITDIRECTORY does not launch a file chooser. Automated test fails if 'Opening a file chooser' was logged.
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-other.html b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-other.html
new file mode 100644
index 0000000..9281426c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-other.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>INPUT TYPE=FILE WEBKITDIRECTORY and key events - Other keys</title>
+<p>
+  Ensure pressing non-enter/space keys with focus on an INPUT element
+  with TYPE=FILE and WEBKITDIRECTORY does <b>not</b> launch a file
+  chooser. Automated test <b>fails</b> if 'Opening a file chooser' was
+  logged.
+</p>
+<input type="file" webkitdirectory>
+<script>
+if (testRunner && eventSender) {
+  testRunner.dumpAsText();
+  const file = document.querySelector('input');
+  file.focus();
+  ['x', '0', 'ArrowRight', 'ControlLeft'].forEach(key => {
+    // Despite the name, 'keyDown' simulates a full down/press/up sequence.
+    eventSender.keyDown(key, []);
+  });
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-space-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-space-expected.txt
new file mode 100644
index 0000000..2cb7d24
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-space-expected.txt
@@ -0,0 +1,4 @@
+Mock: Opening a file chooser.
+Ensure pressing Space key with focus on an INPUT element with TYPE=FILE and WEBKITDIRECTORY launches a file chooser. Automated test passes if 'Opening a file chooser' was logged.
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-space.html b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-space.html
new file mode 100644
index 0000000..7ba04ce
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/file/file-input-webkitdirectory-key-space.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>INPUT TYPE=FILE WEBKITDIRECTORY and key events - Space key</title>
+<p>
+  Ensure pressing Space key with focus on an INPUT element with
+  TYPE=FILE and WEBKITDIRECTORY launches a file chooser. Automated
+  test passes if 'Opening a file chooser' was logged.
+</p>
+<input type="file" webkitdirectory>
+<script>
+if (testRunner && eventSender) {
+  testRunner.dumpAsText();
+  const file = document.querySelector('input');
+  file.focus();
+  // Despite the name, 'keyDown' simulates a full down/press/up sequence.
+  eventSender.keyDown(' ', []);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-2d-events.html b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-2d-events.html
index 8ed45f4..40931a2 100644
--- a/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-2d-events.html
+++ b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-2d-events.html
@@ -43,7 +43,7 @@
 
   var video = document.createElement('video');
   try {
-    video.src = window.URL.createObjectURL(stream);
+    video.srcObject = stream;
     testPassed('Plugged stream to video tag.');
   } catch(e) {
     testFailed('Exception plugging stream to <video>: ' + e);
diff --git a/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-request-frame-events.html b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-request-frame-events.html
index e7af6132..6a35877 100644
--- a/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-request-frame-events.html
+++ b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-request-frame-events.html
@@ -47,7 +47,7 @@
   // var video = document.createElement('video');
   var video = document.getElementById('v');
   try {
-    video.src = window.URL.createObjectURL(stream);
+    video.srcObject = stream;
     testPassed('Plugged stream to video tag.');
   } catch(e) {
     testFailed('Exception plugging stream to <video>: ' + e);
diff --git a/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-webgl-events.html b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-webgl-events.html
index fd619c8..93cb03db 100644
--- a/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-webgl-events.html
+++ b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-webgl-events.html
@@ -40,7 +40,7 @@
 
   var video = document.createElement('video');
   try {
-    video.src = window.URL.createObjectURL(stream);
+    video.srcObject = stream;
     testPassed('Plugged stream to video tag.');
   } catch(e) {
     testFailed('Exception plugging stream to <video>: ' + e);
diff --git a/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-sdes-constraint.html b/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-sdes-constraint.html
new file mode 100644
index 0000000..c06dbda
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-sdes-constraint.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>RTCPeerConnection.createOffer</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+
+sdes_constraint = {'mandatory': {'DtlsSrtpKeyAgreement': false}};
+
+promise_test(async t => {
+  let pc1 = new RTCPeerConnection();
+  let pc2 = new RTCPeerConnection();
+  let stream = await navigator.mediaDevices.getUserMedia({audio: true});
+  let track = stream.getAudioTracks()[0];
+  pc1.addTrack(track);
+  let offer = await pc1.createOffer();
+  assert_true(offer.sdp.match('\na=fingerprint') !== null);
+  assert_true(offer.sdp.match('\na=crypto') === null);
+  await pc1.setLocalDescription(offer);
+  await pc2.setRemoteDescription(offer);
+  let answer = await pc2.createAnswer();
+  assert_true(answer.sdp.match('\na=fingerprint') !== null);
+  assert_true(answer.sdp.match('\na=crypto') === null);
+  await pc2.setLocalDescription(answer);
+  await pc1.setRemoteDescription(answer);
+}, 'No constraints means DTLS-SRTP');
+
+promise_test(async t => {
+  let pc1 = new RTCPeerConnection(null, sdes_constraint);
+  let pc2 = new RTCPeerConnection(null, sdes_constraint);
+  pc1.oncandidate = c => pc2.addCandidate();
+  pc2.oncandidate = c => pc1.addCandidate();
+  let stream = await navigator.mediaDevices.getUserMedia({audio: true});
+  let track = stream.getAudioTracks()[0];
+  pc1.addTrack(track);
+  let offer = await pc1.createOffer();
+  // assert_regexp_match doesn't work
+  assert_true(offer.sdp.match('\na=fingerprint') === null);
+  assert_true(offer.sdp.match('\na=crypto') !== null);
+  await pc1.setLocalDescription(offer);
+  await pc2.setRemoteDescription(offer);
+  let answer = await pc2.createAnswer();
+  assert_true(answer.sdp.match('\na=fingerprint') === null);
+  assert_true(answer.sdp.match('\na=crypto') !== null);
+  await pc2.setLocalDescription(answer);
+  await pc1.setRemoteDescription(answer);
+}, 'DTLS constraint false means SDES');
+
+promise_test(async t => {
+  let pc1 = new RTCPeerConnection(null, sdes_constraint);
+  let pc2 = new RTCPeerConnection();
+  let stream = await navigator.mediaDevices.getUserMedia({audio: true});
+  let track = stream.getAudioTracks()[0];
+  pc1.addTrack(track);
+  let offer = await pc1.createOffer();
+  await pc1.setLocalDescription(offer);
+  try {
+    await pc2.setRemoteDescription(offer);
+    assert_unreached('pc2.setRemote should have thrown');
+  } catch(e) {
+    assert_equals(e.name, 'OperationError');
+  }
+
+}, 'SDES can\'t connect to default configuration');
+
+promise_test(async t => {
+  let pc1 = new RTCPeerConnection();
+  let pc2 = new RTCPeerConnection(null, sdes_constraint);
+  let stream = await navigator.mediaDevices.getUserMedia({audio: true});
+  let track = stream.getAudioTracks()[0];
+  pc1.addTrack(track);
+  let offer = await pc1.createOffer();
+  try {
+    await pc2.setRemoteDescription(offer);
+    assert_unreached('pc2.setRemote should have thrown');
+  } catch(e) {
+    assert_equals(e.name, 'OperationError');
+  }
+}, 'Default configuration can\'t connect to SDES');
+
+causes_sdes = async function(constraint) {
+  pc = new RTCPeerConnection(null, constraint);
+  let stream = await navigator.mediaDevices.getUserMedia({audio: true});
+  let track = stream.getAudioTracks()[0];
+  pc.addTrack(track);
+  let offer = await pc.createOffer();
+  return offer.sdp.match('\na=crypto') !== null
+}
+
+valid_constraint_for_pc = async function(constraint) {
+  console.log(JSON.stringify(constraint));
+  try {
+    pc = new RTCPeerConnection(null, constraint);
+    return true;
+  } catch (e) {
+    assert_equals(e.name, 'OperationError');
+    return false;
+  }
+}
+
+promise_test(async t => {
+  assert_true(await causes_sdes(sdes_constraint));
+  assert_false(await causes_sdes(
+    {'mandatory': {'DtlsSrtpKeyAgreement': true}}));
+  assert_true(await causes_sdes(
+    {'mandatory': {'DtlsSrtpKeyAgreement': 'false'}}));
+  assert_false(await causes_sdes(
+    {'optional': [{'DtlsSrtpKeyAgreement': true}]}));
+  assert_true(await causes_sdes(
+    {'optional': [{'DtlsSrtpKeyAgreement': false}]}));
+}, 'SDES shows up when expected');
+
+valid_for_pc = function(constraint) {
+  try {
+    pc = new RTCPeerConnection(null, constraint);
+    return true;
+  } catch (e) {
+    return false;
+  }
+}
+
+test(t => {
+  assert_true(valid_for_pc(sdes_constraint));
+  assert_true(valid_for_pc({'optional': [{'DtlsSrtpKeyAgreement': false}]}));
+  assert_true(valid_for_pc({'optional': [{'DtlsSrtpKeyAgreement': 'false'}]}));
+  assert_false(valid_for_pc({'DtlsSrtpKeyAgreement': false}),
+               'Modern style constraint is not supported');
+}, 'Syntaxes valid for PC are as expected');
+
+
+</script>
+</body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/scrollstate-distribute-to-scroll-chain-descendant.html b/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/scrollstate-distribute-to-scroll-chain-descendant.html
index 0bd6d4d..90bc078 100644
--- a/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/scrollstate-distribute-to-scroll-chain-descendant.html
+++ b/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/scrollstate-distribute-to-scroll-chain-descendant.html
@@ -1,55 +1,85 @@
 <!DOCTYPE html>
-<html>
-<head>
 <meta charset="utf-8">
 <title>ScrollState constructor behaves correctly</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
-</head>
-<body>
+<style>
+* {
+  margin: 0 0;
+}
+div {
+  width: 400px;
+  height: 400px;
+  scroll-customization: auto;
+  overflow: scroll;
+}
+</style>
+
+<p> Verify the correctness of distributeToScrollChainDescendant(). </p>
+
 <script>
-test(function() {
-  assert_true('ScrollState' in window, "'ScrollState' in window");
-  // TODO(tdresser): Don't rely on window.internals. See crbug.com/483091 for details.
-  assert_true(window.internals !== null, "'ScrollState' in window");
-}, "These tests only work with scroll customization enabled.");
-
-var elementCount = 10;
-var remainingNumberOfTimesToBeCalled = elementCount;
-
-var distributeScroll = function(scrollState) {
-  this.calledOrder = elementCount - remainingNumberOfTimesToBeCalled;
-  remainingNumberOfTimesToBeCalled--;
-  scrollState.distributeToScrollChainDescendant();
-}
-
-var elements = [];
-for (var i = 0; i < elementCount; ++i) {
-  var element = document.createElement("div");
-  element.creationOrder = i;
-  element.setDistributeScroll(distributeScroll.bind(element), "disable-native-scroll");
-  elements.push(element);
-}
-
-if ('ScrollState' in window && window.internals) {
   test(function() {
-    var scrollState = new ScrollState({deltaX: 100, isDirectManipulation: true});
+    assert_true('ScrollState' in window, "'ScrollState' in window");
+    // TODO(tdresser): Don't rely on window.internals. See crbug.com/483091 for
+    // details.
+    assert_true(window.internals !== null, "'internals' in window");
+  }, "These tests only work with scroll customization enabled.");
+
+  var elementCount = 10;
+  var remainingNumberOfTimesToBeCalled = elementCount;
+  var elements = [];
+
+  var distributeScroll = function(scrollState) {
+    this.calledOrder = elementCount - remainingNumberOfTimesToBeCalled;
+    remainingNumberOfTimesToBeCalled--;
+    scrollState.distributeToScrollChainDescendant();
+  }
+
+  var parentNode = document.body;
+  for (var i = 0; i < elementCount; ++i) {
+    var element = document.createElement("div");
+    element.creationOrder = i;
+    element.id = 'e' + i;
+    element.style.scrollCustomization = 'auto';
+    parentNode.appendChild(element);
+    elements.push(element);
+    parentNode = element;
+  }
+
+  // Normal codepath for scrolling involves notifying all the elements in the
+  // scroll chain about a GestureScrollBegin. The element finds the direction
+  // of the scroll and decides whether or not its customization matches the
+  // direction. Since this test uses a synthetic chain, this step needs to
+  // be simulated by a GestureScrollBegin. This will also call an related
+  // customized scroll handlers. Therefore, to avoid the unwanted calls to the
+  // corresponding distributeScroll handlers, they are set up after the
+  // gesture.
+  eventSender.gestureScrollBegin(200, 200);
+
+  elements.forEach((el) => {
+    el.setDistributeScroll(distributeScroll.bind(el),
+     "disable-native-scroll");
+  });
+
+
+  test(() => {
+    var scrollState = new ScrollState(
+        { deltaX: 100, isDirectManipulation: true});
     window.internals.setScrollChain(scrollState, elements);
     scrollState.distributeToScrollChainDescendant();
-    assert_equals(0, remainingNumberOfTimesToBeCalled);
+    assert_equals(remainingNumberOfTimesToBeCalled, 0);
     for (var i = 0; i < elementCount; ++i) {
       assert_equals(elements[i].creationOrder, elements[i].calledOrder);
     }
-  }, "distributeToScrollChainDescendant propagates correctly.");
+  }, "distributeToScrollChainDescendant propagates correctly");
 
-  test(function() {
-    var scrollState = new ScrollState({deltaX: 100, isDirectManipulation: true});
+  test(() => {
+    var scrollState =
+        new ScrollState({deltaX: 100, isDirectManipulation: true});
     window.internals.setScrollChain(scrollState, []);
     assert_equals(0, remainingNumberOfTimesToBeCalled);
     scrollState.distributeToScrollChainDescendant();
     assert_equals(0, remainingNumberOfTimesToBeCalled);
-  }, "distributeToScrollChainDescendant with empty scroll chain does nothing.");
-}
+  },
+  "distributeToScrollChainDescendant with empty scroll chain does nothing.");
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html b/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html
index 49d119b..764ac2b 100644
--- a/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html
+++ b/third_party/WebKit/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html
@@ -10,6 +10,7 @@
 * {
   margin:0;
   padding:0;
+  scroll-customization: auto;
 }
 
 *::-webkit-scrollbar {
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache-expected.txt
index d0d1b8b..2f4eb5e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache-expected.txt
@@ -19,6 +19,19 @@
 v8.compile Properties:
 {
     data : {
+        columnNumber : 0
+        lineNumber : 0
+        streamed : <boolean>
+        url : .../devtools/resources/v8-cache-script.js
+    }
+    endTime : <number>
+    startTime : <number>
+    type : "v8.compile"
+}
+Text details for v8.compile: v8-cache-script.js:1
+v8.compile Properties:
+{
+    data : {
         cacheProduceOptions : "code"
         columnNumber : 0
         lineNumber : 0
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/memory/sampling-native-profile-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/memory/sampling-native-profile-expected.txt
deleted file mode 100644
index 1664a79a..0000000
--- a/third_party/WebKit/LayoutTests/inspector-protocol/memory/sampling-native-profile-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Test sampling native memory profiler.
-Sampling started
-Sampling stopped
-Found sample: true
-
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/memory/sampling-native-profile.js b/third_party/WebKit/LayoutTests/inspector-protocol/memory/sampling-native-profile.js
deleted file mode 100644
index e054cca..0000000
--- a/third_party/WebKit/LayoutTests/inspector-protocol/memory/sampling-native-profile.js
+++ /dev/null
@@ -1,28 +0,0 @@
-(async function(testRunner) {
-  var {page, session, dp} = await testRunner.startBlank(`Test sampling native memory profiler.`);
-
-  await dp.Memory.startSampling({
-      samplingInterval: 100000, suppressRandomness: true});
-  testRunner.log('Sampling started');
-  await session.evaluate(`
-    const canvas = document.createElement('canvas');
-    canvas.width = 500;
-    canvas.height = 200;
-    const ctx = canvas.getContext('2d');
-    ctx.fillStyle = 'green';
-    ctx.fillRect(0, 0, 10, 10);
-    document.body.appendChild(canvas);
-    `);
-  const message = await dp.Memory.getSamplingProfile();
-  await dp.Memory.stopSampling();
-  testRunner.log('Sampling stopped');
-
-  const profile = message.result.profile;
-  const foundTheSample = profile.samples.some(sample =>
-    sample.size >= 500 * 200 && sample.stack.some(frame => frame.includes('HTMLCanvasElement')));
-  testRunner.log('Found sample: ' + foundTheSample);
-  if (!foundTheSample)
-    testRunner.log(profile);
-
-  testRunner.completeTest();
-})
diff --git a/third_party/WebKit/LayoutTests/media/autoplay-muted.html b/third_party/WebKit/LayoutTests/media/autoplay-muted.html
index 424de18..4f3a9cae3 100644
--- a/third_party/WebKit/LayoutTests/media/autoplay-muted.html
+++ b/third_party/WebKit/LayoutTests/media/autoplay-muted.html
@@ -94,6 +94,8 @@
         document.onclick = t.step_func_done(function() {
             e.muted = false;
             assert_false(e.paused, "The video should not be paused.");
+            // Consume the triggered transient user activation
+            eventSender.consumeUserActivation();
         });
     }, "Test that unmuting autoplayed video with gesture doesn't pause it.");
 
diff --git a/third_party/WebKit/LayoutTests/media/controls/toggle-class-without-poster.html b/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-preload-metadata.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/media/controls/toggle-class-without-poster.html
rename to third_party/WebKit/LayoutTests/media/controls/toggle-class-with-preload-metadata.html
index 5c3e123..36877f3 100644
--- a/third_party/WebKit/LayoutTests/media/controls/toggle-class-without-poster.html
+++ b/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-preload-metadata.html
@@ -14,7 +14,7 @@
   checkControlsClassName(video, 'phase-pre-ready state-no-source use-default-poster');
 
   video.onloadedmetadata = t.step_func_done(() => {
-    checkControlsClassName(video, 'phase-ready state-stopped use-default-poster');
+    checkControlsClassName(video, 'phase-ready state-stopped');
   });
 
   video.src = findMediaFile('video', '../content/counting');
diff --git a/third_party/WebKit/LayoutTests/media/controls/toggle-class-without-poster.html b/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-preload-none.html
similarity index 75%
copy from third_party/WebKit/LayoutTests/media/controls/toggle-class-without-poster.html
copy to third_party/WebKit/LayoutTests/media/controls/toggle-class-with-preload-none.html
index 5c3e123..9f7dded 100644
--- a/third_party/WebKit/LayoutTests/media/controls/toggle-class-without-poster.html
+++ b/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-preload-none.html
@@ -5,7 +5,7 @@
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../media-controls.js"></script>
 <script src="../media-file.js"></script>
-<video controls width=400 preload=metadata></video>
+<video controls width=400 preload=none></video>
 <script>
 async_test(t => {
   const video = document.querySelector('video');
@@ -13,8 +13,8 @@
 
   checkControlsClassName(video, 'phase-pre-ready state-no-source use-default-poster');
 
-  video.onloadedmetadata = t.step_func_done(() => {
-    checkControlsClassName(video, 'phase-ready state-stopped use-default-poster');
+  window.onload = t.step_func_done(() => {
+    checkControlsClassName(video, 'phase-pre-ready state-no-metadata use-default-poster');
   });
 
   video.src = findMediaFile('video', '../content/counting');
diff --git a/third_party/WebKit/LayoutTests/media/media-play-promise.html b/third_party/WebKit/LayoutTests/media/media-play-promise.html
index e70ef77a..40cba406 100644
--- a/third_party/WebKit/LayoutTests/media/media-play-promise.html
+++ b/third_party/WebKit/LayoutTests/media/media-play-promise.html
@@ -333,6 +333,8 @@
     // Test that play() on an element when media playback requires a gesture
     // returns a rejected promise if there is no user gesture.
     function playRequiresUserGestureAndDoesNotHaveIt(t, audio) {
+        // Consume transient user activation triggered in the previous test.
+        eventSender.consumeUserActivation();
         audio.src = findMediaFile("audio", "content/test");
         playExpectingRejectedPromise(t, audio, "NotAllowedError");
     }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/resize-iframe-text.html b/third_party/WebKit/LayoutTests/paint/invalidation/resize-iframe-text.html
index 11fbdea8..97f825e7 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/resize-iframe-text.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/resize-iframe-text.html
@@ -2,11 +2,16 @@
 <script src="../../resources/run-after-layout-and-paint.js"></script>
 <script src="resources/text-based-repaint.js"></script>
 <script>
+// Disable implicit root scroller since the iframe full screen and would
+// otherwise be promoted to rootScroller which changes painting and
+// invalidation.
+if (window.internals)
+  window.internals.runtimeFlags.implicitRootScrollerEnabled = false;
 if (window.testRunner)
   testRunner.useUnfortunateSynchronousResizeMode();
 onload = function() {
   runAfterLayoutAndPaint(function() {
-    // Use smaller size because window.resizeTo/By() will fail if the sizae is
+    // Use smaller size because window.resizeTo/By() will fail if the size is
     // bigger than the screen size.
     window.resizeTo(500, 200);
     runRepaintAndPixelTest();
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
index e3ff36489..23ac4fb1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
@@ -9,7 +9,7 @@
         {
           "object": "LayoutSVGPath path",
           "rect": [189, 197, 139, 139],
-          "reason": "style change"
+          "reason": "full"
         },
         {
           "object": "LayoutSVGPath path",
@@ -35,7 +35,7 @@
     },
     {
       "object": "LayoutSVGPath path",
-      "reason": "style change"
+      "reason": "full"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-marker-creation-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-marker-creation-expected.txt
index 71d7a73..ca1d5b3 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-marker-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-marker-creation-expected.txt
@@ -9,7 +9,7 @@
         {
           "object": "LayoutSVGPath path",
           "rect": [189, 197, 139, 139],
-          "reason": "style change"
+          "reason": "full"
         }
       ]
     }
@@ -17,7 +17,7 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGPath path",
-      "reason": "style change"
+      "reason": "full"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt
index 1ea80a34..650c5220a 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt
@@ -14,7 +14,7 @@
         {
           "object": "LayoutSVGRect rect",
           "rect": [0, 100, 800, 100],
-          "reason": "style change"
+          "reason": "full"
         },
         {
           "object": "LayoutSVGRect rect",
@@ -35,7 +35,7 @@
     },
     {
       "object": "LayoutSVGRect rect",
-      "reason": "style change"
+      "reason": "full"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-mask-creation-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-mask-creation-expected.txt
index 35c81cb..d54295d 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-mask-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/js-late-mask-creation-expected.txt
@@ -9,7 +9,7 @@
         {
           "object": "LayoutSVGRect rect",
           "rect": [0, 100, 800, 100],
-          "reason": "style change"
+          "reason": "full"
         }
       ]
     }
@@ -17,7 +17,7 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGRect rect",
-      "reason": "style change"
+      "reason": "full"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
deleted file mode 100644
index 9ba21178..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-This is a testharness.js-based test.
-PASS rp missing
-PASS rp is string
-FAIL Bad rp: id is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "SecurityError: The relying party ID '[object Object]' is not a registrable domain suffix of, nor equal to 'https://web-platform.test:8444'." ("SecurityError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: id is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "SecurityError: The relying party ID 'null' is not a registrable domain suffix of, nor equal to 'https://web-platform.test:8444'." ("SecurityError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: id is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: name is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: name is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: name is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: icon is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: icon is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: icon is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt
index b9d0c7a..33379cc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt
@@ -29,7 +29,7 @@
         {
           "object": "LayoutSVGText text",
           "rect": [16, 39, 784, 174],
-          "reason": "style change"
+          "reason": "full"
         },
         {
           "object": "LayoutSVGText text",
@@ -66,11 +66,11 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "RootInlineBox",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "LayoutSVGInlineText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-clipPath-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-clipPath-creation-expected.txt
index f240fe95..ebbb60ac 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-clipPath-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-clipPath-creation-expected.txt
@@ -19,7 +19,7 @@
         {
           "object": "LayoutSVGText text",
           "rect": [16, 39, 784, 174],
-          "reason": "style change"
+          "reason": "full"
         }
       ]
     }
@@ -31,11 +31,11 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "RootInlineBox",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "LayoutSVGInlineText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-gradient-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-gradient-creation-expected.txt
index 3716038..0a60892 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-gradient-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-gradient-creation-expected.txt
@@ -14,7 +14,7 @@
         {
           "object": "LayoutSVGText text",
           "rect": [33, 21, 693, 197],
-          "reason": "style change"
+          "reason": "full"
         }
       ]
     }
@@ -22,11 +22,11 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGText text",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "RootInlineBox",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "LayoutSVGInlineText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-pattern-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-pattern-creation-expected.txt
index 362c28e8..eac8a81 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-pattern-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/js-late-pattern-creation-expected.txt
@@ -14,7 +14,7 @@
         {
           "object": "LayoutSVGText text",
           "rect": [33, 21, 618, 197],
-          "reason": "style change"
+          "reason": "full"
         }
       ]
     }
@@ -22,11 +22,11 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGText text",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "RootInlineBox",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "LayoutSVGInlineText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt
index 1250726..b6e8e476 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-clipPath-and-object-creation-expected.txt
@@ -29,7 +29,7 @@
         {
           "object": "LayoutSVGText text",
           "rect": [16, 42, 784, 170],
-          "reason": "style change"
+          "reason": "full"
         },
         {
           "object": "LayoutSVGText text",
@@ -66,11 +66,11 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "RootInlineBox",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "LayoutSVGInlineText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-clipPath-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-clipPath-creation-expected.txt
index 1130e8d..e52307a8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-clipPath-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-clipPath-creation-expected.txt
@@ -19,7 +19,7 @@
         {
           "object": "LayoutSVGText text",
           "rect": [16, 42, 784, 170],
-          "reason": "style change"
+          "reason": "full"
         }
       ]
     }
@@ -31,11 +31,11 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "RootInlineBox",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "LayoutSVGInlineText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-gradient-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-gradient-creation-expected.txt
index 4a6c1ef1..f8a23a0c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-gradient-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-gradient-creation-expected.txt
@@ -14,7 +14,7 @@
         {
           "object": "LayoutSVGText text",
           "rect": [33, 23, 697, 194],
-          "reason": "style change"
+          "reason": "full"
         }
       ]
     }
@@ -22,11 +22,11 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGText text",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "RootInlineBox",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "LayoutSVGInlineText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-pattern-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-pattern-creation-expected.txt
index 83a4a3e..d8b70f5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-pattern-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/js-late-pattern-creation-expected.txt
@@ -14,7 +14,7 @@
         {
           "object": "LayoutSVGText text",
           "rect": [33, 23, 622, 194],
-          "reason": "style change"
+          "reason": "full"
         }
       ]
     }
@@ -22,11 +22,11 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGText text",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "RootInlineBox",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "LayoutSVGInlineText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win7/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
deleted file mode 100644
index 9ba21178..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-This is a testharness.js-based test.
-PASS rp missing
-PASS rp is string
-FAIL Bad rp: id is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "SecurityError: The relying party ID '[object Object]' is not a registrable domain suffix of, nor equal to 'https://web-platform.test:8444'." ("SecurityError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: id is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "SecurityError: The relying party ID 'null' is not a registrable domain suffix of, nor equal to 'https://web-platform.test:8444'." ("SecurityError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: id is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: name is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: name is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: name is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: icon is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: icon is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: icon is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/rootscroller/rootscroller-during-fullscreen.html b/third_party/WebKit/LayoutTests/rootscroller/rootscroller-during-fullscreen.html
new file mode 100644
index 0000000..c7c87fc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/rootscroller/rootscroller-during-fullscreen.html
@@ -0,0 +1,149 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+  // This test verifies the rootScroller behavior while the document is in
+  // fullscreen. We expect that the effective rootScroller of all documents on
+  // a page revert to the document itself. On exiting fullscreen, the
+  // designated document.rootScroller should take effect again.
+
+  // Helper async function to block execution for n number of rAFs.
+  async function nFrames(n) {
+    return new Promise(resolve => {
+      let remainingFrames = n;
+      let func = function() {
+        --remainingFrames;
+        if (remainingFrames === 0)
+          resolve();
+        else {
+          requestAnimationFrame(func);
+        }
+      };
+
+      if (n === 0) {
+        resolve();
+      } else {
+        requestAnimationFrame(() => {
+          func(resolve);
+        });
+      }
+    });
+  }
+
+  const test = async_test("Fullscreen rootScroller Test");
+  let iframe;
+  let childDocument;
+  let scroller;
+
+  async function fullscreenChanged() {
+    if (document.webkitIsFullScreen) {
+      await nFrames(2);
+      test.step(() => {
+        assert_equals(
+            window.internals.effectiveRootScroller(document),
+            document,
+            "Entering fullscreen should reset root document's effective " +
+            "root scroller");
+        assert_equals(
+            window.internals.effectiveRootScroller(childDocument),
+            childDocument,
+            "Entering fullscreen should reset iframe's effective root " +
+            "scroller");
+      });
+      document.webkitExitFullscreen();
+    } else {
+      await nFrames(2);
+      test.step(() => {
+        assert_equals(
+            window.internals.effectiveRootScroller(document),
+            iframe,
+            "Exiting fullscreen should set the iframe back as the root " +
+            "document's effective root scroller.");
+        assert_equals(
+            window.internals.effectiveRootScroller(childDocument),
+            scroller,
+            "Exiting fullscreen should set the scroller div back as the " +
+            "iframe's effective root scroller.");
+      });
+      test.done();
+    }
+  }
+
+  addEventListener('load', async () => {
+    if (!window.internals)
+      return;
+
+    iframe = document.getElementById('frame');
+    childDocument = iframe.contentDocument;
+    scroller = childDocument.getElementById('scroller');
+
+    scroller.addEventListener('click', () => {
+      scroller.webkitRequestFullscreen();
+    });
+
+    document.addEventListener('webkitfullscreenchange', fullscreenChanged);
+
+    document.rootScroller = iframe;
+    childDocument.rootScroller = scroller;
+
+    await nFrames(1);
+
+    test.step(() => {
+      assert_equals(
+          window.internals.effectiveRootScroller(document),
+          iframe,
+          "Root document should initially have iframe as effective root " +
+          "scroller");
+      assert_equals(
+          window.internals.effectiveRootScroller(childDocument),
+          scroller,
+          "Iframe should initially have scroller div as effective root " +
+          "scroller");
+    });
+
+    // Fullscreen must be click-activated since it needs a user gesture.
+    chrome.gpuBenchmarking.pointerActionSequence([
+      {
+        "source": "mouse",
+        "actions": [
+          { "name": "pointerDown", "x": 10, "y": 10 },
+          { "name": "pointerUp" }
+        ]
+      }]);
+  });
+</script>
+
+<style>
+  ::-webkit-scrollbar {
+    width: 0px;
+    height: 0px;
+  }
+  html, body {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+  }
+  iframe {
+    width: 100%;
+    height: 100%;
+    border: 0;
+  }
+</style>
+
+<iframe id="frame" srcdoc="
+  <!DOCTYPE html>
+  <style>
+    body,html {
+      width: 100%;
+      height: 100%;
+      margin: 0;
+    }
+    ::-webkit-scrollbar {
+      width: 0px;
+      height: 0px;
+    }
+  </style>
+  <div id='scroller' style='width:100%; height:100%; overflow: auto;'>
+    <div style='height: 2000px; width: 2000px;'></div>
+  </div>" allowfullscreen>
+</iframe>
diff --git a/third_party/WebKit/LayoutTests/rootscroller/set-rootscroller-before-load-expected.html b/third_party/WebKit/LayoutTests/rootscroller/set-rootscroller-before-load-expected.html
new file mode 100644
index 0000000..179a06d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/rootscroller/set-rootscroller-before-load-expected.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, user-scalable=no" />
+<style>
+  html, body {
+    height: 100%;
+    width: 100%;
+    margin: 0;
+  }
+  body {
+    background-color: red;
+  }
+  #bottom {
+    position: fixed;
+    left: 50px;
+    right: 50px;
+    height: 20px;
+    bottom: 0px;
+    background-color: coral;
+    z-index: 2;
+  }
+  #container {
+    width: 100%;
+    height: 600px;
+    background-color: #808080;
+    transform: translateZ(0);
+  }
+</style>
+
+<div id="container">
+  <div style="height: 2000px"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/rootscroller/set-rootscroller-before-load.html b/third_party/WebKit/LayoutTests/rootscroller/set-rootscroller-before-load.html
new file mode 100644
index 0000000..5760a7c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/rootscroller/set-rootscroller-before-load.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<meta name="viewport" content="width=device-width, user-scalable=no" />
+<link rel=match href=set-root-scroller-before-load.html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+  // Set the browser controls to be 100px and hidden.
+  // NOTE: It is important that this test be run with the Android viewport
+  // flags turned on.
+  if (window.internals) {
+    window.internals.setBrowserControlsState(100, 0, false);
+    testRunner.setShouldGeneratePixelResults(true);
+    testRunner.waitUntilDone();
+  }
+
+  addEventListener("load", function() {
+    const iframe = document.getElementById("iframe");
+    const scroller = iframe.contentDocument.getElementById("scroller");
+    document.rootScroller = iframe;
+    iframe.contentDocument.rootScroller = scroller;
+    requestAnimationFrame(() => {
+      assert_equals(
+          internals.effectiveRootScroller(document), iframe,
+          "rootScroller in main document should be iframe.");
+      assert_equals(
+          internals.effectiveRootScroller(iframe.contentDocument), scroller,
+          "rootScroller in iframe should be scroller element.");
+      testRunner.notifyDone();
+    });
+  });
+</script>
+<style>
+  html, body {
+    height: 100%;
+    width: 100%;
+    margin: 0;
+  }
+  #iframe {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    border: 0;
+  }
+</style>
+
+<iframe id="iframe" srcdoc="
+    <style>
+      html,body {
+        height: 100%;
+        width: 100%;
+        margin:0;
+        background-color: blue;
+      }
+      #scroller {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        background-color: #808080;
+        overflow: auto;
+      }
+    </style>
+    <div id='scroller'>
+        <div style='height:2000px'></div>
+    </div>
+    "></iframe>
+<script>
+  document.rootScroller = document.getElementById("iframe");
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/custom/duplicate-ids-remove-first-expected.html b/third_party/WebKit/LayoutTests/svg/custom/duplicate-ids-remove-first-expected.html
new file mode 100644
index 0000000..f718ea6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/custom/duplicate-ids-remove-first-expected.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 100px; height: 100px; background-color: green"></div>
diff --git a/third_party/WebKit/LayoutTests/svg/custom/duplicate-ids-remove-first.html b/third_party/WebKit/LayoutTests/svg/custom/duplicate-ids-remove-first.html
new file mode 100644
index 0000000..7c09acd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/custom/duplicate-ids-remove-first.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
+<svg>
+  <linearGradient id="f">
+    <stop stop-color="red"/>
+  </linearGradient>
+  <linearGradient id="f">
+    <stop stop-color="green"/>
+  </linearGradient>
+  <rect width="100" height="100" fill="url(#f) orange"/>
+</svg>
+<script>
+runAfterLayoutAndPaint(function() {
+  document.querySelector('lineargradient').remove();
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/android/rootscroller/nested-rootscroller-browser-controls-bounds-hidden.html b/third_party/WebKit/LayoutTests/virtual/android/rootscroller/nested-rootscroller-browser-controls-bounds-hidden.html
index ffe35d5..cce3b7e6 100644
--- a/third_party/WebKit/LayoutTests/virtual/android/rootscroller/nested-rootscroller-browser-controls-bounds-hidden.html
+++ b/third_party/WebKit/LayoutTests/virtual/android/rootscroller/nested-rootscroller-browser-controls-bounds-hidden.html
@@ -6,13 +6,18 @@
   // flags turned on.
   if (window.internals) {
     window.internals.setBrowserControlsState(100, 0, true);
-    window.internals.setBrowserControlsShownRatio(0);
+    testRunner.waitUntilDone();
   }
 
   addEventListener("load", function() {
     var iframe = document.getElementById("iframe");
     document.rootScroller = iframe;
     iframe.contentDocument.rootScroller = iframe.contentDocument.getElementById("scroller");
+
+    if (window.internals)
+      window.internals.setBrowserControlsShownRatio(0);
+
+    requestAnimationFrame(() => { testRunner.notifyDone(); });
   });
 </script>
 <style>
diff --git a/third_party/WebKit/LayoutTests/virtual/android/rootscroller/nested-rootscroller-browser-controls-bounds-shown.html b/third_party/WebKit/LayoutTests/virtual/android/rootscroller/nested-rootscroller-browser-controls-bounds-shown.html
index ba19c0c..70cb3f33 100644
--- a/third_party/WebKit/LayoutTests/virtual/android/rootscroller/nested-rootscroller-browser-controls-bounds-shown.html
+++ b/third_party/WebKit/LayoutTests/virtual/android/rootscroller/nested-rootscroller-browser-controls-bounds-shown.html
@@ -6,13 +6,18 @@
   // flags turned on.
   if (window.internals) {
     window.internals.setBrowserControlsState(100, 0, false);
-    window.internals.setBrowserControlsShownRatio(1);
+    testRunner.waitUntilDone();
   }
 
   addEventListener("load", function() {
     var iframe = document.getElementById("iframe");
     document.rootScroller = iframe;
     iframe.contentDocument.rootScroller = iframe.contentDocument.getElementById("scroller");
+
+    if (window.internals)
+      window.internals.setBrowserControlsShownRatio(1);
+
+    requestAnimationFrame(() => { testRunner.notifyDone(); });
   });
 </script>
 <style>
diff --git a/third_party/WebKit/LayoutTests/virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scroll-customization-property.html b/third_party/WebKit/LayoutTests/virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scroll-customization-property.html
new file mode 100644
index 0000000..642c98aa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scroll-customization-property.html
@@ -0,0 +1,213 @@
+<!doctype html>
+<title> Scroll Customization Property </title>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<style>
+* {
+  margin: 0;
+  padding: 0;
+}
+
+
+p {
+  position: relative;
+}
+
+#test-div {
+  height: 400px;
+  width: 400px;
+  overflow: scroll;
+}
+</style>
+
+<div id="test-div">
+  <div id="spacer" style="width: 1000px; height:1000px;" ></div>
+</div>
+
+<script>
+  test(function() {
+    assert_true('internals' in window, '"internals" is needed for this test.');
+    assert_true('gpuBenchmarking' in chrome,
+                '"gpuBenchmarking" is required for this test');
+    assert_true(internals.runtimeFlags.scrollCustomizationEnabled,
+        '"ScrollCustomization" feature must be enabled.');
+    assert_true('ScrollState' in window, "'ScrollState' in window");
+  }, 'These tests only work when certain features are enabled.');
+
+  var element = document.getElementById('test-div');
+  test(function() {
+    assert_true('scrollCustomization' in element.style);
+  }, 'Verify "scroll-customization" is part of element\'s style.');
+
+  // Used to track invocation of scroll customization handlers.
+  element.didCallApplyScrollHandler = false;
+  element.didCallScrollCustomizationHandlers = false;
+
+  var testCases = [
+  //  [scroll customization,  gesture,      scroll customization handler called]
+      ["pan-up pan-x",        "pan-right",   true],
+      ["pan-up pan-x",        "pan-left",    true],
+      ["pan-up pan-x",        "pan-up",      true],
+      ["pan-up pan-x",        "pan-down",   false],
+      ["pan-up pan-left",     "pan-right",  false],
+      ["pan-up pan-left",     "pan-left",    true],
+      ["pan-up pan-left",     "pan-up",      true],
+      ["pan-up pan-left",     "pan-down",   false],
+      ["pan-up pan-right",    "pan-right",   true],
+      ["pan-up pan-right",    "pan-left",   false],
+      ["pan-up pan-right",    "pan-up",      true],
+      ["pan-up pan-right",    "pan-down",   false],
+      ["pan-up",              "pan-right",  false],
+      ["pan-up",              "pan-left",   false],
+      ["pan-up",              "pan-up",      true],
+      ["pan-up",              "pan-down",   false],
+      ["pan-x",               "pan-right",   true],
+      ["pan-x",               "pan-left",    true],
+      ["pan-x",               "pan-up",     false],
+      ["pan-x",               "pan-down",   false],
+      ["pan-left",            "pan-right",  false],
+      ["pan-left",            "pan-left",    true],
+      ["pan-left",            "pan-up",     false],
+      ["pan-left",            "pan-down",   false],
+      ["pan-right",           "pan-right",   true],
+      ["pan-right",           "pan-left",   false],
+      ["pan-right",           "pan-up",     false],
+      ["pan-right",           "pan-down",   false],
+      ["none",                "pan-right",  false],
+      ["none",                "pan-left",   false],
+      ["none",                "pan-up",     false],
+      ["none",                "pan-down",   false],
+      ["auto",                "pan-right",   true],
+      ["auto",                "pan-left",    true],
+      ["auto",                "pan-up",      true],
+      ["auto",                "pan-down",    true],
+      ["pan-left pan-y",      "pan-right",  false],
+      ["pan-left pan-y",      "pan-left",    true],
+      ["pan-left pan-y",      "pan-up",      true],
+      ["pan-left pan-y",      "pan-down",    true],
+      ["pan-right pan-y",     "pan-right",   true],
+      ["pan-right pan-y",     "pan-left",   false],
+      ["pan-right pan-y",     "pan-up",      true],
+      ["pan-right pan-y",     "pan-down",    true],
+      ["pan-y",               "pan-right",  false],
+      ["pan-y",               "pan-left",   false],
+      ["pan-y",               "pan-up",      true],
+      ["pan-y",               "pan-down",    true],
+      ["pan-down pan-x",      "pan-right",   true],
+      ["pan-down pan-x",      "pan-left",    true],
+      ["pan-down pan-x",      "pan-up",     false],
+      ["pan-down pan-x",      "pan-down",    true],
+      ["pan-down pan-left",   "pan-right",  false],
+      ["pan-down pan-left",   "pan-left",    true],
+      ["pan-down pan-left",   "pan-up",     false],
+      ["pan-down pan-left",   "pan-down",    true],
+      ["pan-down pan-right",  "pan-right",   true],
+      ["pan-down pan-right",  "pan-left",   false],
+      ["pan-down pan-right",  "pan-up",     false],
+      ["pan-down pan-right",  "pan-down",    true],
+      ["pan-down",            "pan-right",  false],
+      ["pan-down",            "pan-left",   false],
+      ["pan-down",            "pan-up",     false],
+      ["pan-down",            "pan-down",    true],
+      // The following cases are invalid and should not be set as customization.
+      ["pan-left pan-right",  "pan-left",   false],
+      ["pan-left pan-right",  "pan-right",  false],
+      ["pan-left pan-right",  "pan-up",     false],
+      ["pan-left pan-right",  "pan-down",   false],
+      ["pan-y pan-y",         "pan-left",   false],
+      ["pan-y pan-y",         "pan-right",  false],
+      ["pan-y pan-y",         "pan-up",     false],
+      ["pan-y pan-y",         "pan-down",   false],
+  ];
+
+
+  function applyScrollCallback(unused_ss) {
+    element.didCallApplyScrollHandler = true;
+  }
+
+  function distributeScrollCallback(unused_ss) {
+    element.didCallDistributeScrollHandler = true;
+  }
+
+  element.setApplyScroll(
+        applyScrollCallback, 'perform-before-native-scroll');
+  element.setDistributeScroll(
+        distributeScrollCallback, 'perform-before-native-scroll');
+
+
+  // Called before each test.
+  function resetState() {
+    // Make sure the <div> can scroll in all directions. This is necessary or
+    // otherwise there won't be a scroll chain containing which includes
+    // |element|.
+    element.scrollTop =  400;
+    element.scrollLeft = 400;
+
+    element.didCallApplyScrollHandler = false;
+    element.didCallDistributeScrollHandler = false;
+    element.style.scrollCustomization = 'none';
+  }
+
+  function didCallScrollCustomizationHandlers() {
+    assert_equals(element.didCallApplyScrollHandler, element.didCallDistributeScrollHandler,
+                  "It is invalid to call only one of the applyScroll" +
+                      " and distributeScroll handler methods.");
+    return element.didCallApplyScrollHandler;
+  }
+
+  // Returns a promise after applying the |gesture|. The |gesture| will result
+  // in a scrolling phase.
+  function applyGesture(gesture) {
+    var deltaX = 0, deltaY = 0;
+    // The delta has to be large enough to avoid getting a fling instead.
+    var  delta = 50;
+    switch (gesture) {
+      case 'pan-right':
+      deltaX = -delta;
+      break;
+      case 'pan-left':
+      deltaX = delta;
+      break;
+      case 'pan-down':
+      deltaY = -delta;
+      break;
+      case 'pan-up':
+      deltaY = delta;
+      break;
+    }
+
+    var startingX = 100, startingY = 100;
+    // TODO(ekaramad): The test takes too long due to mandatory delay. Revisit
+    // this when and if it becomes possible to create gesture scroll without the
+    // delay (https://crbug.com/803168).
+    // Necessary to avoid getting a fling instead. Cannot be too small.
+    var pauseSeconds = 0.05;
+    return new Promise((resolve) => {
+      chrome.gpuBenchmarking.pointerActionSequence([{
+        source: 'touch',
+        actions: [
+        { name: 'pointerDown', x: startingX, y: startingY },
+        //{ name: 'pause', duration: pauseSeconds},
+        { name: 'pointerMove', x: (startingX + deltaX),
+        y: (startingY + deltaY)},
+        { name: 'pause', duration: pauseSeconds},
+        { name: 'pointerUp'}
+        ]
+      }], resolve);
+    });
+  }
+
+  // Define the set of promise tests for all test cases.
+  testCases.forEach((testcase) => {
+    promise_test(async() => {
+      resetState();
+      element.style.scrollCustomization = testcase[0];
+      await applyGesture(testcase[1]);
+      let handlersWereCalled = didCallScrollCustomizationHandlers();
+      assert_equals(handlersWereCalled, testcase[2],
+        `Handlers were ${handlersWereCalled ? '' : 'not '}called. They must`
+        + ` ${testcase[2] ? '' : 'not '}have.`);
+    }, `Verify correctness of "scroll-customization: ${testcase[0]}"`
+        + ` when gesture "${testcase[1]}" is applied.`);
+  });
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-gradient-creation-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-gradient-creation-expected.txt
index d210fa0..f1b014ba 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-gradient-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-gradient-creation-expected.txt
@@ -27,11 +27,11 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGText text",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "RootInlineBox",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "LayoutSVGInlineText #text",
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
index 7d033ce..4cad7811 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
@@ -19,7 +19,7 @@
         {
           "object": "LayoutSVGPath path",
           "rect": [189, 197, 139, 139],
-          "reason": "style change"
+          "reason": "full"
         },
         {
           "object": "LayoutSVGRoot svg id='svg-root'",
@@ -40,7 +40,7 @@
     },
     {
       "object": "LayoutSVGPath path",
-      "reason": "style change"
+      "reason": "full"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-marker-creation-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-marker-creation-expected.txt
index 8a7be2e..5c3a253 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-marker-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-marker-creation-expected.txt
@@ -19,7 +19,7 @@
         {
           "object": "LayoutSVGPath path",
           "rect": [189, 197, 139, 139],
-          "reason": "style change"
+          "reason": "full"
         }
       ]
     }
@@ -27,7 +27,7 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGPath path",
-      "reason": "style change"
+      "reason": "full"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt
index e65f85a5..eed315f4 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-mask-and-object-creation-expected.txt
@@ -50,7 +50,7 @@
     },
     {
       "object": "LayoutSVGRect rect",
-      "reason": "style change"
+      "reason": "full"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-mask-creation-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-mask-creation-expected.txt
index 29e43ef..ef536ce 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-mask-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-mask-creation-expected.txt
@@ -37,7 +37,7 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGRect rect",
-      "reason": "style change"
+      "reason": "full"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-pattern-creation-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-pattern-creation-expected.txt
index 4451434..064a88a5 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-pattern-creation-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/svg/js-late-pattern-creation-expected.txt
@@ -27,11 +27,11 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGText text",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "RootInlineBox",
-      "reason": "style change"
+      "reason": "full"
     },
     {
       "object": "LayoutSVGInlineText #text",
diff --git a/third_party/WebKit/Source/BUILD.gn b/third_party/WebKit/Source/BUILD.gn
index b029620..1e970fa 100644
--- a/third_party/WebKit/Source/BUILD.gn
+++ b/third_party/WebKit/Source/BUILD.gn
@@ -24,6 +24,10 @@
   # a class has an empty destructor which would be unnecessarily invoked
   # when finalized.
   blink_gc_plugin_option_warn_unneeded_finalizer = false
+
+  # Set to true to have the clang Blink GC plugin additionally check if a
+  # TraceWrappers method also dispatches to all its base classes.
+  blink_gc_plugin_option_warn_trace_wrappers_missing_base_dispatch = false
 }
 
 # features ---------------------------------------------------------------------
@@ -140,6 +144,14 @@
         "warn-unneeded-finalizer",
       ]
     }
+    if (blink_gc_plugin_option_warn_trace_wrappers_missing_base_dispatch) {
+      cflags += [
+        "-Xclang",
+        "-plugin-arg-blink-gc-plugin",
+        "-Xclang",
+        "warn_trace_wrappers_missing_base_dispatch",
+      ]
+    }
   }
 }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorldTest.cpp b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorldTest.cpp
index eacb6d5..4365830 100644
--- a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorldTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorldTest.cpp
@@ -116,8 +116,8 @@
   retrieved_worlds.clear();
 
   // Start a worker thread and create worlds on that.
-  std::unique_ptr<WorkerBackingThread> thread =
-      WorkerBackingThread::Create("DOMWrapperWorld test thread");
+  std::unique_ptr<WorkerBackingThread> thread = WorkerBackingThread::Create(
+      WebThreadCreationParams("DOMWrapperWorld test thread"));
   scoped_refptr<WebTaskRunner> main_thread_task_runner =
       Platform::Current()->CurrentThread()->GetWebTaskRunner();
   thread->BackingThread().PostTask(
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
index c4e7f6a..b2dd852 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
@@ -134,12 +134,20 @@
 
     v8::Local<v8::Script> script;
 
+    v8::ScriptCompiler::CompileOptions compile_options;
+    V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+    v8::ScriptCompiler::NoCacheReason no_cache_reason;
+    std::tie(compile_options, produce_cache_options, no_cache_reason) =
+        V8ScriptRunner::GetCompileOptions(v8_cache_options, source);
     if (!V8ScriptRunner::CompileScript(ScriptState::From(context), source,
-                                       access_control_status, v8_cache_options,
-                                       referrer_info)
+                                       access_control_status, compile_options,
+                                       no_cache_reason, referrer_info)
              .ToLocal(&script))
       return result;
 
+    V8ScriptRunner::ProduceCache(GetIsolate(), script, source,
+                                 produce_cache_options, compile_options);
+
     if (!V8ScriptRunner::RunCompiledScript(GetIsolate(), script,
                                            GetFrame()->GetDocument())
              .ToLocal(&result))
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerTest.cpp
index 812faca2..5ea1e01e 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerTest.cpp
@@ -167,9 +167,14 @@
   EXPECT_TRUE(source_code.Streamer());
   v8::TryCatch try_catch(scope.GetIsolate());
   v8::Local<v8::Script> script;
+  v8::ScriptCompiler::CompileOptions compile_options;
+  V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+  v8::ScriptCompiler::NoCacheReason no_cache_reason;
+  std::tie(compile_options, produce_cache_options, no_cache_reason) =
+      V8ScriptRunner::GetCompileOptions(kV8CacheOptionsDefault, source_code);
   EXPECT_TRUE(V8ScriptRunner::CompileScript(
                   scope.GetScriptState(), source_code, kSharableCrossOrigin,
-                  kV8CacheOptionsDefault, ReferrerScriptInfo())
+                  compile_options, no_cache_reason, ReferrerScriptInfo())
                   .ToLocal(&script));
   EXPECT_FALSE(try_catch.HasCaught());
 }
@@ -207,9 +212,14 @@
   EXPECT_TRUE(source_code.Streamer());
   v8::TryCatch try_catch(scope.GetIsolate());
   v8::Local<v8::Script> script;
+  v8::ScriptCompiler::CompileOptions compile_options;
+  V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+  v8::ScriptCompiler::NoCacheReason no_cache_reason;
+  std::tie(compile_options, produce_cache_options, no_cache_reason) =
+      V8ScriptRunner::GetCompileOptions(kV8CacheOptionsDefault, source_code);
   EXPECT_FALSE(V8ScriptRunner::CompileScript(
                    scope.GetScriptState(), source_code, kSharableCrossOrigin,
-                   kV8CacheOptionsDefault, ReferrerScriptInfo())
+                   compile_options, no_cache_reason, ReferrerScriptInfo())
                    .ToLocal(&script));
   EXPECT_TRUE(try_catch.HasCaught());
 }
@@ -359,9 +369,14 @@
   EXPECT_TRUE(source_code.Streamer());
   v8::TryCatch try_catch(scope.GetIsolate());
   v8::Local<v8::Script> script;
+  v8::ScriptCompiler::CompileOptions compile_options;
+  V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+  v8::ScriptCompiler::NoCacheReason no_cache_reason;
+  std::tie(compile_options, produce_cache_options, no_cache_reason) =
+      V8ScriptRunner::GetCompileOptions(kV8CacheOptionsDefault, source_code);
   EXPECT_TRUE(V8ScriptRunner::CompileScript(
                   scope.GetScriptState(), source_code, kSharableCrossOrigin,
-                  kV8CacheOptionsDefault, ReferrerScriptInfo())
+                  compile_options, no_cache_reason, ReferrerScriptInfo())
                   .ToLocal(&script));
   EXPECT_FALSE(try_catch.HasCaught());
 }
@@ -396,9 +411,14 @@
   EXPECT_TRUE(source_code.Streamer());
   v8::TryCatch try_catch(scope.GetIsolate());
   v8::Local<v8::Script> script;
+  v8::ScriptCompiler::CompileOptions compile_options;
+  V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+  v8::ScriptCompiler::NoCacheReason no_cache_reason;
+  std::tie(compile_options, produce_cache_options, no_cache_reason) =
+      V8ScriptRunner::GetCompileOptions(kV8CacheOptionsDefault, source_code);
   EXPECT_TRUE(V8ScriptRunner::CompileScript(
                   scope.GetScriptState(), source_code, kSharableCrossOrigin,
-                  kV8CacheOptionsDefault, ReferrerScriptInfo())
+                  compile_options, no_cache_reason, ReferrerScriptInfo())
                   .ToLocal(&script));
   EXPECT_FALSE(try_catch.HasCaught());
 }
@@ -434,9 +454,14 @@
   EXPECT_TRUE(source_code.Streamer());
   v8::TryCatch try_catch(scope.GetIsolate());
   v8::Local<v8::Script> script;
+  v8::ScriptCompiler::CompileOptions compile_options;
+  V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+  v8::ScriptCompiler::NoCacheReason no_cache_reason;
+  std::tie(compile_options, produce_cache_options, no_cache_reason) =
+      V8ScriptRunner::GetCompileOptions(kV8CacheOptionsDefault, source_code);
   EXPECT_TRUE(V8ScriptRunner::CompileScript(
                   scope.GetScriptState(), source_code, kSharableCrossOrigin,
-                  kV8CacheOptionsDefault, ReferrerScriptInfo())
+                  compile_options, no_cache_reason, ReferrerScriptInfo())
                   .ToLocal(&script));
   EXPECT_FALSE(try_catch.HasCaught());
 }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.cpp
index 309535d0..5b8f5c50 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamerThread.cpp
@@ -50,7 +50,8 @@
 
 WebThread& ScriptStreamerThread::PlatformThread() {
   if (!IsRunning()) {
-    thread_ = Platform::Current()->CreateThread("ScriptStreamerThread");
+    thread_ = Platform::Current()->CreateThread(
+        WebThreadCreationParams("ScriptStreamerThread"));
   }
   return *thread_;
 }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
index aa9b6dc..0671710 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
@@ -35,10 +35,12 @@
   return false;
 }
 
-TEST(ScriptWrappableVisitorTest, ScriptWrappableVisitorTracesWrappers) {
+TEST(ScriptWrappableMarkingVisitorTest,
+     ScriptWrappableMarkingVisitorTracesWrappers) {
   V8TestingScope scope;
-  ScriptWrappableVisitor* visitor =
-      V8PerIsolateData::From(scope.GetIsolate())->GetScriptWrappableVisitor();
+  ScriptWrappableMarkingVisitor* visitor =
+      V8PerIsolateData::From(scope.GetIsolate())
+          ->GetScriptWrappableMarkingVisitor();
   DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create();
   DeathAwareScriptWrappable* dependency = DeathAwareScriptWrappable::Create();
   target->SetWrappedDependency(dependency);
@@ -70,7 +72,8 @@
   visitor->AbortTracing();
 }
 
-TEST(ScriptWrappableVisitorTest, OilpanCollectObjectsNotReachableFromV8) {
+TEST(ScriptWrappableMarkingVisitorTest,
+     OilpanCollectObjectsNotReachableFromV8) {
   V8TestingScope scope;
   v8::Isolate* isolate = scope.GetIsolate();
 
@@ -90,7 +93,8 @@
   EXPECT_TRUE(DeathAwareScriptWrappable::HasDied());
 }
 
-TEST(ScriptWrappableVisitorTest, OilpanDoesntCollectObjectsReachableFromV8) {
+TEST(ScriptWrappableMarkingVisitorTest,
+     OilpanDoesntCollectObjectsReachableFromV8) {
   V8TestingScope scope;
   v8::Isolate* isolate = scope.GetIsolate();
   v8::HandleScope handle_scope(isolate);
@@ -107,7 +111,7 @@
   EXPECT_FALSE(DeathAwareScriptWrappable::HasDied());
 }
 
-TEST(ScriptWrappableVisitorTest, V8ReportsLiveObjectsDuringScavenger) {
+TEST(ScriptWrappableMarkingVisitorTest, V8ReportsLiveObjectsDuringScavenger) {
   V8TestingScope scope;
   v8::Isolate* isolate = scope.GetIsolate();
   v8::HandleScope handle_scope(isolate);
@@ -130,7 +134,7 @@
   EXPECT_FALSE(DeathAwareScriptWrappable::HasDied());
 }
 
-TEST(ScriptWrappableVisitorTest, V8ReportsLiveObjectsDuringFullGc) {
+TEST(ScriptWrappableMarkingVisitorTest, V8ReportsLiveObjectsDuringFullGc) {
   V8TestingScope scope;
   v8::Isolate* isolate = scope.GetIsolate();
   v8::HandleScope handle_scope(isolate);
@@ -146,12 +150,13 @@
   EXPECT_FALSE(DeathAwareScriptWrappable::HasDied());
 }
 
-TEST(ScriptWrappableVisitorTest, OilpanClearsHeadersWhenObjectDied) {
+TEST(ScriptWrappableMarkingVisitorTest, OilpanClearsHeadersWhenObjectDied) {
   V8TestingScope scope;
 
   DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::Create();
-  ScriptWrappableVisitor* visitor =
-      V8PerIsolateData::From(scope.GetIsolate())->GetScriptWrappableVisitor();
+  ScriptWrappableMarkingVisitor* visitor =
+      V8PerIsolateData::From(scope.GetIsolate())
+          ->GetScriptWrappableMarkingVisitor();
   visitor->TracePrologue();
   auto header = HeapObjectHeader::FromPayload(object);
   visitor->HeadersToUnmark()->push_back(header);
@@ -162,12 +167,14 @@
   visitor->AbortTracing();
 }
 
-TEST(ScriptWrappableVisitorTest, OilpanClearsMarkingDequeWhenObjectDied) {
+TEST(ScriptWrappableMarkingVisitorTest,
+     OilpanClearsMarkingDequeWhenObjectDied) {
   V8TestingScope scope;
 
   DeathAwareScriptWrappable* object = DeathAwareScriptWrappable::Create();
-  ScriptWrappableVisitor* visitor =
-      V8PerIsolateData::From(scope.GetIsolate())->GetScriptWrappableVisitor();
+  ScriptWrappableMarkingVisitor* visitor =
+      V8PerIsolateData::From(scope.GetIsolate())
+          ->GetScriptWrappableMarkingVisitor();
   visitor->TracePrologue();
 
   visitor->TraceWrappersWithManualWriteBarrier(object);
@@ -181,12 +188,13 @@
   visitor->AbortTracing();
 }
 
-TEST(ScriptWrappableVisitorTest,
+TEST(ScriptWrappableMarkingVisitorTest,
      MarkedObjectDoesNothingOnWriteBarrierHitWhenDependencyIsMarkedToo) {
   V8TestingScope scope;
 
-  ScriptWrappableVisitor* visitor =
-      V8PerIsolateData::From(scope.GetIsolate())->GetScriptWrappableVisitor();
+  ScriptWrappableMarkingVisitor* visitor =
+      V8PerIsolateData::From(scope.GetIsolate())
+          ->GetScriptWrappableMarkingVisitor();
   visitor->TracePrologue();
 
   DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create();
@@ -209,12 +217,13 @@
   visitor->AbortTracing();
 }
 
-TEST(ScriptWrappableVisitorTest,
+TEST(ScriptWrappableMarkingVisitorTest,
      MarkedObjectMarksDependencyOnWriteBarrierHitWhenNotMarked) {
   V8TestingScope scope;
 
-  ScriptWrappableVisitor* visitor =
-      V8PerIsolateData::From(scope.GetIsolate())->GetScriptWrappableVisitor();
+  ScriptWrappableMarkingVisitor* visitor =
+      V8PerIsolateData::From(scope.GetIsolate())
+          ->GetScriptWrappableMarkingVisitor();
   visitor->TracePrologue();
 
   DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::Create();
@@ -261,12 +270,13 @@
   TraceWrapperV8Reference<v8::String> handle_;
 };
 
-class InterceptingScriptWrappableVisitor
-    : public blink::ScriptWrappableVisitor {
+class InterceptingScriptWrappableMarkingVisitor
+    : public blink::ScriptWrappableMarkingVisitor {
  public:
-  InterceptingScriptWrappableVisitor(v8::Isolate* isolate)
-      : ScriptWrappableVisitor(isolate), marked_wrappers_(new size_t(0)) {}
-  ~InterceptingScriptWrappableVisitor() { delete marked_wrappers_; }
+  InterceptingScriptWrappableMarkingVisitor(v8::Isolate* isolate)
+      : ScriptWrappableMarkingVisitor(isolate),
+        marked_wrappers_(new size_t(0)) {}
+  ~InterceptingScriptWrappableMarkingVisitor() { delete marked_wrappers_; }
 
   void Visit(const TraceWrapperV8Reference<v8::Value>&) const override {
     *marked_wrappers_ += 1;
@@ -291,33 +301,36 @@
   size_t* marked_wrappers_;  // Indirection required because of const override.
 };
 
-class InterceptingScriptWrappableVisitorScope
+class InterceptingScriptWrappableMarkingVisitorScope
     : public V8PerIsolateData::TemporaryScriptWrappableVisitorScope {
-  WTF_MAKE_NONCOPYABLE(InterceptingScriptWrappableVisitorScope);
+  WTF_MAKE_NONCOPYABLE(InterceptingScriptWrappableMarkingVisitorScope);
   STACK_ALLOCATED();
 
  public:
-  InterceptingScriptWrappableVisitorScope(v8::Isolate* isolate)
+  InterceptingScriptWrappableMarkingVisitorScope(v8::Isolate* isolate)
       : V8PerIsolateData::TemporaryScriptWrappableVisitorScope(
             isolate,
-            std::unique_ptr<InterceptingScriptWrappableVisitor>(
-                new InterceptingScriptWrappableVisitor(isolate))) {
+            std::unique_ptr<InterceptingScriptWrappableMarkingVisitor>(
+                new InterceptingScriptWrappableMarkingVisitor(isolate))) {
     Visitor()->Start();
   }
 
-  virtual ~InterceptingScriptWrappableVisitorScope() { Visitor()->end(); }
+  virtual ~InterceptingScriptWrappableMarkingVisitorScope() {
+    Visitor()->end();
+  }
 
-  InterceptingScriptWrappableVisitor* Visitor() {
-    return reinterpret_cast<InterceptingScriptWrappableVisitor*>(
+  InterceptingScriptWrappableMarkingVisitor* Visitor() {
+    return reinterpret_cast<InterceptingScriptWrappableMarkingVisitor*>(
         CurrentVisitor());
   }
 };
 
 }  // namespace
 
-TEST(ScriptWrappableVisitorTest, WriteBarrierOnUnmarkedContainer) {
+TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnUnmarkedContainer) {
   V8TestingScope scope;
-  InterceptingScriptWrappableVisitorScope visitor_scope(scope.GetIsolate());
+  InterceptingScriptWrappableMarkingVisitorScope visitor_scope(
+      scope.GetIsolate());
   auto* raw_visitor = visitor_scope.Visitor();
 
   v8::Local<v8::String> str =
@@ -332,9 +345,10 @@
   CHECK_EQ(1u, raw_visitor->NumberOfMarkedWrappers());
 }
 
-TEST(ScriptWrappableVisitorTest, WriteBarrierTriggersOnMarkedContainer) {
+TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierTriggersOnMarkedContainer) {
   V8TestingScope scope;
-  InterceptingScriptWrappableVisitorScope visitor_scope(scope.GetIsolate());
+  InterceptingScriptWrappableMarkingVisitorScope visitor_scope(
+      scope.GetIsolate());
   auto* raw_visitor = visitor_scope.Visitor();
 
   v8::Local<v8::String> str =
@@ -348,23 +362,24 @@
   CHECK_EQ(1u, raw_visitor->NumberOfMarkedWrappers());
 }
 
-TEST(ScriptWrappableVisitorTest, VtableAtObjectStart) {
+TEST(ScriptWrappableMarkingVisitorTest, VtableAtObjectStart) {
   // This test makes sure that the subobject v8::EmbedderHeapTracer is placed
-  // at the start of a ScriptWrappableVisitor object. We do this to mitigate
-  // potential problems that could be caused by LTO when passing
+  // at the start of a ScriptWrappableMarkingVisitor object. We do this to
+  // mitigate potential problems that could be caused by LTO when passing
   // v8::EmbedderHeapTracer across the API boundary.
   V8TestingScope scope;
-  std::unique_ptr<blink::ScriptWrappableVisitor> visitor(
-      new ScriptWrappableVisitor(scope.GetIsolate()));
+  std::unique_ptr<blink::ScriptWrappableMarkingVisitor> visitor(
+      new ScriptWrappableMarkingVisitor(scope.GetIsolate()));
   CHECK_EQ(
       static_cast<void*>(visitor.get()),
       static_cast<void*>(dynamic_cast<v8::EmbedderHeapTracer*>(visitor.get())));
 }
 
-TEST(ScriptWrappableVisitor, WriteBarrierForScriptWrappable) {
+TEST(ScriptWrappableMarkingVisitor, WriteBarrierForScriptWrappable) {
   // Regression test for crbug.com/702490.
   V8TestingScope scope;
-  InterceptingScriptWrappableVisitorScope visitor_scope(scope.GetIsolate());
+  InterceptingScriptWrappableMarkingVisitorScope visitor_scope(
+      scope.GetIsolate());
   auto* raw_visitor = visitor_scope.Visitor();
 
   // Mark the ScriptWrappable.
@@ -385,10 +400,11 @@
   CHECK_EQ(1u, raw_visitor->NumberOfMarkedWrappers());
 }
 
-TEST(ScriptWrappableVisitorTest, WriteBarrierOnHeapVectorSwap1) {
+TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnHeapVectorSwap1) {
   V8TestingScope scope;
-  ScriptWrappableVisitor* visitor =
-      V8PerIsolateData::From(scope.GetIsolate())->GetScriptWrappableVisitor();
+  ScriptWrappableMarkingVisitor* visitor =
+      V8PerIsolateData::From(scope.GetIsolate())
+          ->GetScriptWrappableMarkingVisitor();
 
   HeapVector<DeathAwareScriptWrappable::Wrapper> vector1;
   DeathAwareScriptWrappable* entry1 = DeathAwareScriptWrappable::Create();
@@ -408,10 +424,11 @@
   visitor->AbortTracing();
 }
 
-TEST(ScriptWrappableVisitorTest, WriteBarrierOnHeapVectorSwap2) {
+TEST(ScriptWrappableMarkingVisitorTest, WriteBarrierOnHeapVectorSwap2) {
   V8TestingScope scope;
-  ScriptWrappableVisitor* visitor =
-      V8PerIsolateData::From(scope.GetIsolate())->GetScriptWrappableVisitor();
+  ScriptWrappableMarkingVisitor* visitor =
+      V8PerIsolateData::From(scope.GetIsolate())
+          ->GetScriptWrappableMarkingVisitor();
 
   HeapVector<DeathAwareScriptWrappable::Wrapper> vector1;
   DeathAwareScriptWrappable* entry1 = DeathAwareScriptWrappable::Create();
@@ -482,10 +499,11 @@
 
 }  // namespace
 
-TEST(ScriptWrappableVisitorTest, MixinTracing) {
+TEST(ScriptWrappableMarkingVisitorTest, MixinTracing) {
   V8TestingScope scope;
-  ScriptWrappableVisitor* visitor =
-      V8PerIsolateData::From(scope.GetIsolate())->GetScriptWrappableVisitor();
+  ScriptWrappableMarkingVisitor* visitor =
+      V8PerIsolateData::From(scope.GetIsolate())
+          ->GetScriptWrappableMarkingVisitor();
 
   DeathAwareScriptWrappable* base_wrapper = DeathAwareScriptWrappable::Create();
   DeathAwareScriptWrappable* mixin_wrapper =
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
index 0b6b84d..d790900 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
@@ -123,11 +123,13 @@
   v8::Isolate* isolate_;
 };
 
-class HeapSnaphotWrapperVisitor : public ScriptWrappableVisitor,
+// TODO(ulan): Refactor this class to derive from ScriptWrappableVisitor
+// and not rely on marking infrastructure.
+class HeapSnaphotWrapperVisitor : public ScriptWrappableMarkingVisitor,
                                   public v8::PersistentHandleVisitor {
  public:
   explicit HeapSnaphotWrapperVisitor(v8::Isolate* isolate)
-      : ScriptWrappableVisitor(isolate),
+      : ScriptWrappableMarkingVisitor(isolate),
         current_parent_(nullptr),
         only_trace_single_level_(false),
         first_script_wrappable_traced_(false) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
index c5a1ecc..5a26332 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
@@ -515,12 +515,12 @@
 static void InitializeV8Common(v8::Isolate* isolate) {
   isolate->AddGCPrologueCallback(V8GCController::GcPrologue);
   isolate->AddGCEpilogueCallback(V8GCController::GcEpilogue);
-  std::unique_ptr<ScriptWrappableVisitor> visitor(
-      new ScriptWrappableVisitor(isolate));
-  V8PerIsolateData::From(isolate)->SetScriptWrappableVisitor(
+  std::unique_ptr<ScriptWrappableMarkingVisitor> visitor(
+      new ScriptWrappableMarkingVisitor(isolate));
+  V8PerIsolateData::From(isolate)->SetScriptWrappableMarkingVisitor(
       std::move(visitor));
   isolate->SetEmbedderHeapTracer(
-      V8PerIsolateData::From(isolate)->GetScriptWrappableVisitor());
+      V8PerIsolateData::From(isolate)->GetScriptWrappableMarkingVisitor());
 
   isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
 
@@ -679,8 +679,8 @@
   DCHECK(ThreadState::MainThreadState());
   ThreadState::MainThreadState()->RegisterTraceDOMWrappers(
       isolate, V8GCController::TraceDOMWrappers,
-      ScriptWrappableVisitor::InvalidateDeadObjectsInMarkingDeque,
-      ScriptWrappableVisitor::PerformCleanup);
+      ScriptWrappableMarkingVisitor::InvalidateDeadObjectsInMarkingDeque,
+      ScriptWrappableMarkingVisitor::PerformCleanup);
 
   V8PerIsolateData::From(isolate)->SetThreadDebugger(
       std::make_unique<MainThreadDebugger>(isolate));
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
index add5cc7..7af2beb 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
@@ -112,6 +112,19 @@
                                      no_cache_reason);
 }
 
+// Compile a script eagerly so that we can produce full code cache.
+v8::MaybeLocal<v8::Script> CompileEager(
+    v8::ScriptCompiler::NoCacheReason no_cache_reason,
+    v8::Isolate* isolate,
+    v8::Local<v8::String> code,
+    v8::ScriptOrigin origin,
+    InspectorCompileScriptEvent::V8CacheResult*) {
+  v8::ScriptCompiler::Source source(code, origin);
+  return v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &source,
+                                     v8::ScriptCompiler::kEagerCompile,
+                                     no_cache_reason);
+}
+
 // Compile a script, and consume a V8 cache that was generated previously.
 static v8::MaybeLocal<v8::Script> CompileAndConsumeCache(
     CachedMetadataHandler* cache_handler,
@@ -152,9 +165,10 @@
     v8::Local<v8::String> code,
     v8::ScriptOrigin origin,
     InspectorCompileScriptEvent::V8CacheResult* cache_result) {
-  DCHECK(produce_options == v8::ScriptCompiler::kProduceParserCache ||
-         produce_options == v8::ScriptCompiler::kProduceCodeCache ||
-         produce_options == v8::ScriptCompiler::kProduceFullCodeCache);
+  // TODO(crbug.com/783124): We want to remove the support for producing
+  // parser cache soon. This function should be removed once the support
+  // for parser cache is removed.
+  DCHECK_EQ(produce_options, v8::ScriptCompiler::kProduceParserCache);
   v8::ScriptCompiler::Source source(code, origin);
   v8::MaybeLocal<v8::Script> script = v8::ScriptCompiler::Compile(
       isolate->GetCurrentContext(), &source, produce_options);
@@ -210,9 +224,9 @@
 bool IsResourceHotForCaching(CachedMetadataHandler* cache_handler,
                              int hot_hours) {
   const double cache_within_seconds = hot_hours * 60 * 60;
-  uint32_t tag = CacheTag(kCacheTagTimeStamp, cache_handler->Encoding());
   scoped_refptr<CachedMetadata> cached_metadata =
-      cache_handler->GetCachedMetadata(tag);
+      cache_handler->GetCachedMetadata(
+          V8ScriptRunner::TagForTimeStamp(cache_handler));
   if (!cached_metadata)
     return false;
   double time_stamp;
@@ -225,7 +239,7 @@
 // Final compile call for a streamed compilation. Most decisions have already
 // been made, but we need to write back data into the cache.
 v8::MaybeLocal<v8::Script> PostStreamCompile(
-    V8CacheOptions cache_options,
+    v8::ScriptCompiler::CompileOptions compile_options,
     CachedMetadataHandler* cache_handler,
     ScriptStreamer* streamer,
     v8::Isolate* isolate,
@@ -241,8 +255,8 @@
   // If the non-streaming compiler uses the parser cache, retrieve and store
   // the cache data. If the code cache uses time stamp as heuristic, set that
   // time stamp.
-  switch (cache_options) {
-    case kV8CacheOptionsParse: {
+  switch (compile_options) {
+    case v8::ScriptCompiler::kProduceParserCache: {
       const v8::ScriptCompiler::CachedData* new_cached_data =
           streamer->Source()->GetCachedData();
       if (!new_cached_data)
@@ -263,17 +277,15 @@
       break;
     }
 
-    case kV8CacheOptionsDefault:
-    case kV8CacheOptionsCode:
-      V8ScriptRunner::SetCacheTimeStamp(cache_handler);
+    case v8::ScriptCompiler::kConsumeParserCache:
+    case v8::ScriptCompiler::kConsumeCodeCache:
+    case v8::ScriptCompiler::kNoCompileOptions:
+    case v8::ScriptCompiler::kEagerCompile:
       break;
 
-    case kV8CacheOptionsCodeWithoutHeatCheck:
-    case kV8CacheOptionsFullCodeWithoutHeatCheck:
-      // Currently WithoutHeatCheck doesn't support streaming.
+    case v8::ScriptCompiler::kProduceCodeCache:
+    case v8::ScriptCompiler::kProduceFullCodeCache:
       NOTREACHED();
-    case kV8CacheOptionsNone:
-      break;
   }
   return script;
 }
@@ -285,80 +297,159 @@
     InspectorCompileScriptEvent::V8CacheResult*)>
     CompileFn;
 
-// Select a compile function from any of the above, mainly depending on
-// cacheOptions.
+// Select a compile function from any of the above depending on compile_options.
 static CompileFn SelectCompileFunction(
-    V8CacheOptions cache_options,
+    v8::ScriptCompiler::CompileOptions compile_options,
     CachedMetadataHandler* cache_handler,
-    v8::Local<v8::String> code,
-    v8::ScriptCompiler::NoCacheReason no_handler_reason) {
-  static const int kMinimalCodeLength = 1024;
-  static const int kHotHours = 72;
-
-  // Caching is not available in this case.
-  if (!cache_handler) {
-    return WTF::Bind(CompileWithoutOptions, no_handler_reason);
-  }
-
-  if (cache_options == kV8CacheOptionsNone) {
-    return WTF::Bind(CompileWithoutOptions,
-                     v8::ScriptCompiler::kNoCacheBecauseCachingDisabled);
-  }
-
-  // Caching is not worthwhile for small scripts.  Do not use caching
-  // unless explicitly expected, indicated by the cache option.
-  if (code->Length() < kMinimalCodeLength) {
-    return WTF::Bind(CompileWithoutOptions,
-                     v8::ScriptCompiler::kNoCacheBecauseScriptTooSmall);
-  }
-
-  // The cacheOptions will guide our strategy:
-  switch (cache_options) {
-    case kV8CacheOptionsParse: {
-      // Use parser-cache; in-memory only.
+    v8::ScriptCompiler::NoCacheReason no_cache_reason) {
+  switch (compile_options) {
+    case v8::ScriptCompiler::kNoCompileOptions:
+      return WTF::Bind(CompileWithoutOptions, no_cache_reason);
+    case v8::ScriptCompiler::kEagerCompile:
+      return WTF::Bind(CompileEager, no_cache_reason);
+    case v8::ScriptCompiler::kProduceParserCache: {
       uint32_t parser_tag = V8ScriptRunner::TagForParserCache(cache_handler);
-      scoped_refptr<CachedMetadata> parser_cache(
-          cache_handler->GetCachedMetadata(parser_tag));
-      if (parser_cache) {
-        return WTF::Bind(CompileAndConsumeCache, WrapPersistent(cache_handler),
-                         std::move(parser_cache),
-                         v8::ScriptCompiler::kConsumeParserCache);
-      }
       return WTF::Bind(CompileAndProduceCache, WrapPersistent(cache_handler),
                        parser_tag, v8::ScriptCompiler::kProduceParserCache,
                        CachedMetadataHandler::kCacheLocally);
     }
+    case v8::ScriptCompiler::kConsumeParserCache: {
+      // Use parser-cache; in-memory only.
+      uint32_t parser_tag = V8ScriptRunner::TagForParserCache(cache_handler);
+      scoped_refptr<CachedMetadata> parser_cache(
+          cache_handler->GetCachedMetadata(parser_tag));
+      DCHECK(parser_cache);
+      return WTF::Bind(CompileAndConsumeCache, WrapPersistent(cache_handler),
+                       std::move(parser_cache),
+                       v8::ScriptCompiler::kConsumeParserCache);
+    }
+    case v8::ScriptCompiler::kConsumeCodeCache: {
+      uint32_t code_cache_tag = V8ScriptRunner::TagForCodeCache(cache_handler);
+      scoped_refptr<CachedMetadata> code_cache =
+          cache_handler->GetCachedMetadata(code_cache_tag);
+      DCHECK(code_cache);
+      return WTF::Bind(CompileAndConsumeCache, WrapPersistent(cache_handler),
+                       std::move(code_cache),
+                       v8::ScriptCompiler::kConsumeCodeCache);
+    }
+    case v8::ScriptCompiler::kProduceCodeCache:
+    case v8::ScriptCompiler::kProduceFullCodeCache:
+      NOTREACHED();
+  }
 
+  // All switch branches should return and we should never get here.
+  // But some compilers aren't sure, hence this default.
+  NOTREACHED();
+  return WTF::Bind(CompileWithoutOptions, v8::ScriptCompiler::kNoCacheNoReason);
+}
+
+// Select a compile function for a streaming compile.
+CompileFn SelectCompileFunction(
+    v8::ScriptCompiler::CompileOptions compile_options,
+    CachedMetadataHandler* cache_handler,
+    ScriptStreamer* streamer) {
+  DCHECK(streamer->IsFinished());
+  DCHECK(!streamer->StreamingSuppressed());
+
+  // Streaming compilation may involve use of code cache.
+  // TODO(leszeks): Add compile timer to streaming compilation.
+  return WTF::Bind(PostStreamCompile, compile_options,
+                   WrapPersistent(cache_handler), WrapPersistent(streamer));
+}
+}  // namespace
+
+std::tuple<v8::ScriptCompiler::CompileOptions,
+           V8ScriptRunner::ProduceCacheOptions,
+           v8::ScriptCompiler::NoCacheReason>
+V8ScriptRunner::GetCompileOptions(V8CacheOptions cache_options,
+                                  const ScriptSourceCode& source) {
+  static const int kMinimalCodeLength = 1024;
+  static const int kHotHours = 72;
+  v8::ScriptCompiler::NoCacheReason no_cache_reason;
+
+  switch (source.SourceLocationType()) {
+    case ScriptSourceLocationType::kInline:
+      no_cache_reason = v8::ScriptCompiler::kNoCacheBecauseInlineScript;
+      break;
+    case ScriptSourceLocationType::kInlineInsideDocumentWrite:
+      no_cache_reason = v8::ScriptCompiler::kNoCacheBecauseInDocumentWrite;
+      break;
+    case ScriptSourceLocationType::kExternalFile:
+      no_cache_reason =
+          v8::ScriptCompiler::kNoCacheBecauseResourceWithNoCacheHandler;
+      break;
+    // TODO(leszeks): Possibly differentiate between the other kinds of script
+    // origin also.
+    default:
+      no_cache_reason = v8::ScriptCompiler::kNoCacheBecauseNoResource;
+      break;
+  }
+
+  CachedMetadataHandler* cache_handler = source.CacheHandler();
+  if (!cache_handler) {
+    return std::make_tuple(v8::ScriptCompiler::kNoCompileOptions,
+                           ProduceCacheOptions::kNoProduceCache,
+                           no_cache_reason);
+  }
+
+  if (cache_options == kV8CacheOptionsNone) {
+    no_cache_reason = v8::ScriptCompiler::kNoCacheBecauseCachingDisabled;
+    return std::make_tuple(v8::ScriptCompiler::kNoCompileOptions,
+                           ProduceCacheOptions::kNoProduceCache,
+                           no_cache_reason);
+  }
+
+  if (source.Source().length() < kMinimalCodeLength) {
+    no_cache_reason = v8::ScriptCompiler::kNoCacheBecauseScriptTooSmall;
+    return std::make_tuple(v8::ScriptCompiler::kNoCompileOptions,
+                           ProduceCacheOptions::kNoProduceCache,
+                           no_cache_reason);
+  }
+
+  switch (cache_options) {
+    case kV8CacheOptionsParse: {
+      uint32_t parser_tag = V8ScriptRunner::TagForParserCache(cache_handler);
+      scoped_refptr<CachedMetadata> parser_cache(
+          cache_handler->GetCachedMetadata(parser_tag));
+      if (parser_cache) {
+        return std::make_tuple(v8::ScriptCompiler::kConsumeParserCache,
+                               ProduceCacheOptions::kNoProduceCache,
+                               no_cache_reason);
+      }
+      return std::make_tuple(v8::ScriptCompiler::kProduceParserCache,
+                             ProduceCacheOptions::kNoProduceCache,
+                             no_cache_reason);
+    }
     case kV8CacheOptionsDefault:
     case kV8CacheOptionsCode:
     case kV8CacheOptionsCodeWithoutHeatCheck:
     case kV8CacheOptionsFullCodeWithoutHeatCheck: {
       uint32_t code_cache_tag = V8ScriptRunner::TagForCodeCache(cache_handler);
-      // Use code caching for recently seen resources.
-      // Use compression depending on the cache option.
       scoped_refptr<CachedMetadata> code_cache =
           cache_handler->GetCachedMetadata(code_cache_tag);
       if (code_cache) {
-        return WTF::Bind(CompileAndConsumeCache, WrapPersistent(cache_handler),
-                         std::move(code_cache),
-                         v8::ScriptCompiler::kConsumeCodeCache);
+        return std::make_tuple(v8::ScriptCompiler::kConsumeCodeCache,
+                               ProduceCacheOptions::kNoProduceCache,
+                               no_cache_reason);
       }
       if (cache_options != kV8CacheOptionsCodeWithoutHeatCheck &&
           cache_options != kV8CacheOptionsFullCodeWithoutHeatCheck &&
           !IsResourceHotForCaching(cache_handler, kHotHours)) {
-        V8ScriptRunner::SetCacheTimeStamp(cache_handler);
-        return WTF::Bind(CompileWithoutOptions,
-                         v8::ScriptCompiler::kNoCacheBecauseCacheTooCold);
+        return std::make_tuple(v8::ScriptCompiler::kNoCompileOptions,
+                               ProduceCacheOptions::kSetTimeStamp,
+                               v8::ScriptCompiler::kNoCacheBecauseCacheTooCold);
       }
-      return WTF::Bind(
-          CompileAndProduceCache, WrapPersistent(cache_handler), code_cache_tag,
-          (cache_options == kV8CacheOptionsFullCodeWithoutHeatCheck)
-              ? v8::ScriptCompiler::kProduceFullCodeCache
-              : v8::ScriptCompiler::kProduceCodeCache,
-          CachedMetadataHandler::kSendToPlatform);
-      break;
+      if (cache_options == kV8CacheOptionsFullCodeWithoutHeatCheck) {
+        return std::make_tuple(
+            v8::ScriptCompiler::kEagerCompile,
+            ProduceCacheOptions::kProduceCodeCache,
+            v8::ScriptCompiler::kNoCacheBecauseDeferredProduceCodeCache);
+      }
+      return std::make_tuple(
+          v8::ScriptCompiler::kNoCompileOptions,
+          ProduceCacheOptions::kProduceCodeCache,
+          v8::ScriptCompiler::kNoCacheBecauseDeferredProduceCodeCache);
     }
-
     case kV8CacheOptionsNone:
       // Shouldn't happen, as this is handled above.
       // Case is here so that compiler can check all cases are handled.
@@ -369,28 +460,17 @@
   // All switch branches should return and we should never get here.
   // But some compilers aren't sure, hence this default.
   NOTREACHED();
-  return WTF::Bind(CompileWithoutOptions, v8::ScriptCompiler::kNoCacheNoReason);
+  return std::make_tuple(v8::ScriptCompiler::kNoCompileOptions,
+                         ProduceCacheOptions::kNoProduceCache,
+                         v8::ScriptCompiler::kNoCacheNoReason);
 }
 
-// Select a compile function for a streaming compile.
-CompileFn SelectCompileFunction(V8CacheOptions cache_options,
-                                CachedMetadataHandler* cache_handler,
-                                ScriptStreamer* streamer) {
-  DCHECK(streamer->IsFinished());
-  DCHECK(!streamer->StreamingSuppressed());
-
-  // Streaming compilation may involve use of code cache.
-  // TODO(leszeks): Add compile timer to streaming compilation.
-  return WTF::Bind(PostStreamCompile, cache_options,
-                   WrapPersistent(cache_handler), WrapPersistent(streamer));
-}
-}  // namespace
-
 v8::MaybeLocal<v8::Script> V8ScriptRunner::CompileScript(
     ScriptState* script_state,
     const ScriptSourceCode& source,
     AccessControlStatus access_control_status,
-    V8CacheOptions cache_options,
+    v8::ScriptCompiler::CompileOptions compile_options,
+    v8::ScriptCompiler::NoCacheReason no_cache_reason,
     const ReferrerScriptInfo& referrer_info) {
   v8::Isolate* isolate = script_state->GetIsolate();
   if (source.Source().length() >= v8::String::kMaxLength) {
@@ -424,29 +504,10 @@
       v8::False(isolate),  // is_module
       referrer_info.ToV8HostDefinedOptions(isolate));
 
-  v8::ScriptCompiler::NoCacheReason no_handler_reason;
-  switch (source.SourceLocationType()) {
-    case ScriptSourceLocationType::kInline:
-      no_handler_reason = v8::ScriptCompiler::kNoCacheBecauseInlineScript;
-      break;
-    case ScriptSourceLocationType::kInlineInsideDocumentWrite:
-      no_handler_reason = v8::ScriptCompiler::kNoCacheBecauseInDocumentWrite;
-      break;
-    case ScriptSourceLocationType::kExternalFile:
-      no_handler_reason =
-          v8::ScriptCompiler::kNoCacheBecauseResourceWithNoCacheHandler;
-      break;
-    // TODO(leszeks): Possibly differentiate between the other kinds of script
-    // origin also.
-    default:
-      no_handler_reason = v8::ScriptCompiler::kNoCacheBecauseNoResource;
-      break;
-  }
-
   CompileFn compile_fn =
-      streamer ? SelectCompileFunction(cache_options, cache_handler, streamer)
-               : SelectCompileFunction(cache_options, cache_handler, code,
-                                       no_handler_reason);
+      streamer ? SelectCompileFunction(compile_options, cache_handler, streamer)
+               : SelectCompileFunction(compile_options, cache_handler,
+                                       no_cache_reason);
 
   if (!*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(kTraceEventCategoryGroup))
     return std::move(compile_fn).Run(isolate, code, origin, nullptr);
@@ -522,19 +583,90 @@
   return result;
 }
 
+void V8ScriptRunner::ProduceCache(
+    v8::Isolate* isolate,
+    v8::Local<v8::Script> script,
+    const ScriptSourceCode& source,
+    ProduceCacheOptions produce_cache_options,
+    v8::ScriptCompiler::CompileOptions compile_options) {
+  TRACE_EVENT0("v8", "v8.run");
+  RuntimeCallStatsScopedTracer rcs_scoped_tracer(isolate);
+  RUNTIME_CALL_TIMER_SCOPE(isolate, RuntimeCallStats::CounterId::kV8);
+
+  switch (produce_cache_options) {
+    case ProduceCacheOptions::kSetTimeStamp:
+      V8ScriptRunner::SetCacheTimeStamp(source.CacheHandler());
+      break;
+    case ProduceCacheOptions::kProduceCodeCache: {
+      constexpr const char* kTraceEventCategoryGroup = "v8,devtools.timeline";
+      TRACE_EVENT_BEGIN1(kTraceEventCategoryGroup, "v8.compile", "fileName",
+                         source.Url().GetString().Utf8());
+
+      std::unique_ptr<v8::ScriptCompiler::CachedData> cached_data(
+          v8::ScriptCompiler::CreateCodeCache(
+              script->GetUnboundScript(), V8String(isolate, source.Source())));
+      if (cached_data) {
+        // TODO(crbug.com/783124): This code is mostly a duplicate of code in
+        // CompileAndProduceCache that is used to produce parser cache.
+        // We want to remove the support for producing parser cache soon and
+        // CompileAndProduceCache function should be removed then.
+        const char* data = reinterpret_cast<const char*>(cached_data->data);
+        int length = cached_data->length;
+        if (length > 1024) {
+          // Omit histogram samples for small cache data to avoid outliers.
+          int cache_size_ratio =
+              static_cast<int>(100.0 * length / source.Source().length());
+          DEFINE_THREAD_SAFE_STATIC_LOCAL(
+              CustomCountHistogram, code_cache_size_histogram,
+              ("V8.CodeCacheSizeRatio", 0, 10000, 50));
+          code_cache_size_histogram.Count(cache_size_ratio);
+        }
+        CachedMetadataHandler* cache_handler = source.CacheHandler();
+        cache_handler->ClearCachedMetadata(
+            CachedMetadataHandler::kCacheLocally);
+        cache_handler->SetCachedMetadata(
+            V8ScriptRunner::TagForCodeCache(cache_handler), data, length,
+            CachedMetadataHandler::kSendToPlatform);
+      }
+
+      TRACE_EVENT_END1(
+          kTraceEventCategoryGroup, "v8.compile", "data",
+          InspectorCompileScriptEvent::Data(
+              source.Url().GetString(), source.StartPosition(),
+              InspectorCompileScriptEvent::V8CacheResult(
+                  InspectorCompileScriptEvent::V8CacheResult::ProduceResult(
+                      compile_options, cached_data ? cached_data->length : 0),
+                  Optional<InspectorCompileScriptEvent::V8CacheResult::
+                               ConsumeResult>()),
+              source.Streamer()));
+      break;
+    }
+    case ProduceCacheOptions::kNoProduceCache:
+      break;
+  }
+}
+
 v8::MaybeLocal<v8::Value> V8ScriptRunner::CompileAndRunInternalScript(
     v8::Isolate* isolate,
     ScriptState* script_state,
     const ScriptSourceCode& source_code) {
   DCHECK_EQ(isolate, script_state->GetIsolate());
 
+  v8::ScriptCompiler::CompileOptions compile_options;
+  V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+  v8::ScriptCompiler::NoCacheReason no_cache_reason;
+  std::tie(compile_options, produce_cache_options, no_cache_reason) =
+      V8ScriptRunner::GetCompileOptions(kV8CacheOptionsDefault, source_code);
+  // Currently internal scripts don't have cache handlers. So we should not
+  // produce cache for them.
+  DCHECK_EQ(produce_cache_options, ProduceCacheOptions::kNoProduceCache);
   v8::Local<v8::Script> script;
   // Use default ScriptReferrerInfo here:
   // - nonce: empty for internal script, and
   // - parser_state: always "not parser inserted" for internal scripts.
-  if (!V8ScriptRunner::CompileScript(
-           script_state, source_code, kSharableCrossOrigin,
-           kV8CacheOptionsDefault, ReferrerScriptInfo())
+  if (!V8ScriptRunner::CompileScript(script_state, source_code,
+                                     kSharableCrossOrigin, compile_options,
+                                     no_cache_reason, ReferrerScriptInfo())
            .ToLocal(&script))
     return v8::MaybeLocal<v8::Value>();
 
@@ -678,13 +810,16 @@
   return CacheTag(kCacheTagCode, cache_handler->Encoding());
 }
 
+uint32_t V8ScriptRunner::TagForTimeStamp(CachedMetadataHandler* cache_handler) {
+  return CacheTag(kCacheTagTimeStamp, cache_handler->Encoding());
+}
+
 // Store a timestamp to the cache as hint.
 void V8ScriptRunner::SetCacheTimeStamp(CachedMetadataHandler* cache_handler) {
   double now = WTF::CurrentTime();
-  uint32_t tag = CacheTag(kCacheTagTimeStamp, cache_handler->Encoding());
   cache_handler->ClearCachedMetadata(CachedMetadataHandler::kCacheLocally);
-  cache_handler->SetCachedMetadata(tag, reinterpret_cast<char*>(&now),
-                                   sizeof(now),
+  cache_handler->SetCachedMetadata(TagForTimeStamp(cache_handler),
+                                   reinterpret_cast<char*>(&now), sizeof(now),
                                    CachedMetadataHandler::kSendToPlatform);
 }
 
@@ -749,13 +884,14 @@
   v8::Local<v8::String> code(V8String(isolate, script_string));
   v8::ScriptCompiler::Source source(code, origin);
   scoped_refptr<CachedMetadata> cached_metadata;
-  const v8::ScriptCompiler::CachedData* cached_data = nullptr;
+  std::unique_ptr<v8::ScriptCompiler::CachedData> cached_data;
 
   v8::Local<v8::UnboundScript> unbound_script;
   if (v8::ScriptCompiler::CompileUnboundScript(
-          isolate, &source, v8::ScriptCompiler::kProduceFullCodeCache)
+          isolate, &source, v8::ScriptCompiler::kEagerCompile)
           .ToLocal(&unbound_script)) {
-    cached_data = source.GetCachedData();
+    cached_data.reset(
+        v8::ScriptCompiler::CreateCodeCache(unbound_script, code));
     if (cached_data && cached_data->length) {
       cached_metadata = CachedMetadata::Create(
           CacheTag(kCacheTagCode, encoding.GetName()),
@@ -770,7 +906,7 @@
           file_name, TextPosition(),
           InspectorCompileScriptEvent::V8CacheResult(
               InspectorCompileScriptEvent::V8CacheResult::ProduceResult(
-                  v8::ScriptCompiler::kProduceFullCodeCache,
+                  v8::ScriptCompiler::kEagerCompile,
                   cached_data ? cached_data->length : 0),
               Optional<
                   InspectorCompileScriptEvent::V8CacheResult::ConsumeResult>()),
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
index a370fc4..660bf596 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.h
@@ -61,14 +61,22 @@
     kNotOpaque,
   };
 
+  enum class ProduceCacheOptions {
+    kNoProduceCache,
+    kSetTimeStamp,
+    kProduceCodeCache,
+  };
+
   // For the following methods, the caller sites have to hold
   // a HandleScope and a ContextScope.
   // CachedMetadataHandler is set when metadata caching is supported.
-  static v8::MaybeLocal<v8::Script> CompileScript(ScriptState*,
-                                                  const ScriptSourceCode&,
-                                                  AccessControlStatus,
-                                                  V8CacheOptions,
-                                                  const ReferrerScriptInfo&);
+  static v8::MaybeLocal<v8::Script> CompileScript(
+      ScriptState*,
+      const ScriptSourceCode&,
+      AccessControlStatus,
+      v8::ScriptCompiler::CompileOptions,
+      v8::ScriptCompiler::NoCacheReason,
+      const ReferrerScriptInfo&);
   static v8::MaybeLocal<v8::Module> CompileModule(v8::Isolate*,
                                                   const String& source,
                                                   const String& file_name,
@@ -107,6 +115,17 @@
                                                   v8::Local<v8::Module>,
                                                   v8::Local<v8::Context>);
 
+  static std::tuple<v8::ScriptCompiler::CompileOptions,
+                    ProduceCacheOptions,
+                    v8::ScriptCompiler::NoCacheReason>
+  GetCompileOptions(V8CacheOptions, const ScriptSourceCode&);
+
+  static void ProduceCache(v8::Isolate*,
+                           v8::Local<v8::Script>,
+                           const ScriptSourceCode&,
+                           ProduceCacheOptions,
+                           v8::ScriptCompiler::CompileOptions);
+
   // Only to be used from ScriptModule::ReportException().
   static void ReportExceptionForModule(v8::Isolate*,
                                        v8::Local<v8::Value> exception,
@@ -115,6 +134,7 @@
 
   static uint32_t TagForParserCache(CachedMetadataHandler*);
   static uint32_t TagForCodeCache(CachedMetadataHandler*);
+  static uint32_t TagForTimeStamp(CachedMetadataHandler*);
   static void SetCacheTimeStamp(CachedMetadataHandler*);
 
   // Utilities for calling functions added to the V8 extras binding object.
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunnerTest.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunnerTest.cpp
index 3b4c677..c224f4ad 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunnerTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunnerTest.cpp
@@ -48,17 +48,51 @@
   unsigned TagForCodeCache(CachedMetadataHandler* cache_handler) const {
     return V8ScriptRunner::TagForCodeCache(cache_handler);
   }
+  unsigned TagForTimeStamp(CachedMetadataHandler* cache_handler) const {
+    return V8ScriptRunner::TagForTimeStamp(cache_handler);
+  }
   void SetCacheTimeStamp(CachedMetadataHandler* cache_handler) {
     V8ScriptRunner::SetCacheTimeStamp(cache_handler);
   }
 
-  bool CompileScript(ScriptState* script_state,
+  bool CompileScript(v8::Isolate* isolate,
+                     ScriptState* script_state,
                      const ScriptSourceCode& source_code,
                      V8CacheOptions cache_options) {
-    return !V8ScriptRunner::CompileScript(script_state, source_code,
-                                          kNotSharableCrossOrigin,
-                                          cache_options, ReferrerScriptInfo())
-                .IsEmpty();
+    v8::ScriptCompiler::CompileOptions compile_options;
+    V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+    v8::ScriptCompiler::NoCacheReason no_cache_reason;
+    std::tie(compile_options, produce_cache_options, no_cache_reason) =
+        V8ScriptRunner::GetCompileOptions(cache_options, source_code);
+    v8::MaybeLocal<v8::Script> compiled_script = V8ScriptRunner::CompileScript(
+        script_state, source_code, kNotSharableCrossOrigin, compile_options,
+        no_cache_reason, ReferrerScriptInfo());
+    if (compiled_script.IsEmpty()) {
+      return false;
+    }
+    V8ScriptRunner::ProduceCache(isolate, compiled_script.ToLocalChecked(),
+                                 source_code, produce_cache_options,
+                                 compile_options);
+    return true;
+  }
+
+  bool CompileScript(
+      v8::Isolate* isolate,
+      ScriptState* script_state,
+      const ScriptSourceCode& source_code,
+      v8::ScriptCompiler::CompileOptions compile_options,
+      v8::ScriptCompiler::NoCacheReason no_cache_reason,
+      V8ScriptRunner::ProduceCacheOptions produce_cache_options) {
+    v8::MaybeLocal<v8::Script> compiled_script = V8ScriptRunner::CompileScript(
+        script_state, source_code, kNotSharableCrossOrigin, compile_options,
+        no_cache_reason, ReferrerScriptInfo());
+    if (compiled_script.IsEmpty()) {
+      return false;
+    }
+    V8ScriptRunner::ProduceCache(isolate, compiled_script.ToLocalChecked(),
+                                 source_code, produce_cache_options,
+                                 compile_options);
+    return true;
   }
 
   ScriptResource* CreateEmptyResource() {
@@ -86,12 +120,12 @@
   V8TestingScope scope;
   ScriptSourceCode source_code(Code(), ScriptSourceLocationType::kInternal,
                                nullptr /* cache_handler */, Url());
-  EXPECT_TRUE(
-      CompileScript(scope.GetScriptState(), source_code, kV8CacheOptionsNone));
-  EXPECT_TRUE(
-      CompileScript(scope.GetScriptState(), source_code, kV8CacheOptionsParse));
-  EXPECT_TRUE(
-      CompileScript(scope.GetScriptState(), source_code, kV8CacheOptionsCode));
+  EXPECT_TRUE(CompileScript(scope.GetIsolate(), scope.GetScriptState(),
+                            source_code, kV8CacheOptionsNone));
+  EXPECT_TRUE(CompileScript(scope.GetIsolate(), scope.GetScriptState(),
+                            source_code, kV8CacheOptionsParse));
+  EXPECT_TRUE(CompileScript(scope.GetIsolate(), scope.GetScriptState(),
+                            source_code, kV8CacheOptionsCode));
 }
 
 TEST_F(V8ScriptRunnerTest, emptyResourceDoesNotHaveCacheHandler) {
@@ -102,8 +136,8 @@
 TEST_F(V8ScriptRunnerTest, parseOption) {
   V8TestingScope scope;
   ScriptSourceCode source_code(nullptr, CreateResource(UTF8Encoding()));
-  EXPECT_TRUE(
-      CompileScript(scope.GetScriptState(), source_code, kV8CacheOptionsParse));
+  EXPECT_TRUE(CompileScript(scope.GetIsolate(), scope.GetScriptState(),
+                            source_code, kV8CacheOptionsParse));
   CachedMetadataHandler* cache_handler = source_code.CacheHandler();
   EXPECT_TRUE(
       cache_handler->GetCachedMetadata(TagForParserCache(cache_handler)));
@@ -122,8 +156,8 @@
   CachedMetadataHandler* cache_handler = source_code.CacheHandler();
   SetCacheTimeStamp(cache_handler);
 
-  EXPECT_TRUE(
-      CompileScript(scope.GetScriptState(), source_code, kV8CacheOptionsCode));
+  EXPECT_TRUE(CompileScript(scope.GetIsolate(), scope.GetScriptState(),
+                            source_code, kV8CacheOptionsCode));
 
   EXPECT_FALSE(
       cache_handler->GetCachedMetadata(TagForParserCache(cache_handler)));
@@ -135,6 +169,71 @@
       TagForCodeCache(another_resource->CacheHandler())));
 }
 
+TEST_F(V8ScriptRunnerTest, consumeCodeOption) {
+  V8TestingScope scope;
+  ScriptSourceCode source_code(nullptr, CreateResource(UTF8Encoding()));
+  // Set timestamp to simulate a warm run.
+  CachedMetadataHandler* cache_handler = source_code.CacheHandler();
+  SetCacheTimeStamp(cache_handler);
+
+  // Warm run - should produce code cache.
+  EXPECT_TRUE(CompileScript(scope.GetIsolate(), scope.GetScriptState(),
+                            source_code, kV8CacheOptionsCode));
+
+  // Check the produced cache is for code and not parser cache.
+  EXPECT_FALSE(
+      cache_handler->GetCachedMetadata(TagForParserCache(cache_handler)));
+  EXPECT_TRUE(cache_handler->GetCachedMetadata(TagForCodeCache(cache_handler)));
+
+  // Hot run - should consume code cache.
+  v8::ScriptCompiler::CompileOptions compile_options;
+  V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+  v8::ScriptCompiler::NoCacheReason no_cache_reason;
+  std::tie(compile_options, produce_cache_options, no_cache_reason) =
+      V8ScriptRunner::GetCompileOptions(kV8CacheOptionsDefault, source_code);
+  EXPECT_EQ(produce_cache_options,
+            V8ScriptRunner::ProduceCacheOptions::kNoProduceCache);
+  EXPECT_EQ(compile_options,
+            v8::ScriptCompiler::CompileOptions::kConsumeCodeCache);
+  EXPECT_TRUE(CompileScript(scope.GetIsolate(), scope.GetScriptState(),
+                            source_code, compile_options, no_cache_reason,
+                            produce_cache_options));
+  EXPECT_TRUE(cache_handler->GetCachedMetadata(TagForCodeCache(cache_handler)));
+}
+
+TEST_F(V8ScriptRunnerTest, produceAndConsumeCodeOption) {
+  V8TestingScope scope;
+  ScriptSourceCode source_code(nullptr, CreateResource(UTF8Encoding()));
+  CachedMetadataHandler* cache_handler = source_code.CacheHandler();
+
+  // Cold run - should set the timestamp
+  EXPECT_TRUE(CompileScript(scope.GetIsolate(), scope.GetScriptState(),
+                            source_code, kV8CacheOptionsDefault));
+  EXPECT_TRUE(cache_handler->GetCachedMetadata(TagForTimeStamp(cache_handler)));
+  EXPECT_FALSE(
+      cache_handler->GetCachedMetadata(TagForCodeCache(cache_handler)));
+
+  // Warm run - should produce code cache
+  EXPECT_TRUE(CompileScript(scope.GetIsolate(), scope.GetScriptState(),
+                            source_code, kV8CacheOptionsDefault));
+  EXPECT_TRUE(cache_handler->GetCachedMetadata(TagForCodeCache(cache_handler)));
+
+  // Hot run - should consume code cache
+  v8::ScriptCompiler::CompileOptions compile_options;
+  V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+  v8::ScriptCompiler::NoCacheReason no_cache_reason;
+  std::tie(compile_options, produce_cache_options, no_cache_reason) =
+      V8ScriptRunner::GetCompileOptions(kV8CacheOptionsDefault, source_code);
+  EXPECT_EQ(produce_cache_options,
+            V8ScriptRunner::ProduceCacheOptions::kNoProduceCache);
+  EXPECT_EQ(compile_options,
+            v8::ScriptCompiler::CompileOptions::kConsumeCodeCache);
+  EXPECT_TRUE(CompileScript(scope.GetIsolate(), scope.GetScriptState(),
+                            source_code, compile_options, no_cache_reason,
+                            produce_cache_options));
+  EXPECT_TRUE(cache_handler->GetCachedMetadata(TagForCodeCache(cache_handler)));
+}
+
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp
index e851064b..af33a7b 100644
--- a/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp
@@ -271,12 +271,20 @@
   // - A work{er,let} script doesn't have a nonce, and
   // - a work{er,let} script is always "not parser inserted".
   ReferrerScriptInfo referrer_info;
+  v8::ScriptCompiler::CompileOptions compile_options;
+  V8ScriptRunner::ProduceCacheOptions produce_cache_options;
+  v8::ScriptCompiler::NoCacheReason no_cache_reason;
+  std::tie(compile_options, produce_cache_options, no_cache_reason) =
+      V8ScriptRunner::GetCompileOptions(v8_cache_options, source_code);
   if (V8ScriptRunner::CompileScript(script_state_.get(), source_code,
-                                    kSharableCrossOrigin, v8_cache_options,
-                                    referrer_info)
-          .ToLocal(&compiled_script))
+                                    kSharableCrossOrigin, compile_options,
+                                    no_cache_reason, referrer_info)
+          .ToLocal(&compiled_script)) {
+    V8ScriptRunner::ProduceCache(isolate_, compiled_script, source_code,
+                                 produce_cache_options, compile_options);
     maybe_result = V8ScriptRunner::RunCompiledScript(isolate_, compiled_script,
                                                      global_scope_);
+  }
 
   if (!block.CanContinue()) {
     ForbidExecution();
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index bcc7d65e..0aee4be 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -775,6 +775,7 @@
     "$blink_core_output_dir/css/properties/longhands/Ry.h",
     "$blink_core_output_dir/css/properties/longhands/Scale.h",
     "$blink_core_output_dir/css/properties/longhands/ScrollBehavior.h",
+    "$blink_core_output_dir/css/properties/longhands/ScrollCustomization.h",
     "$blink_core_output_dir/css/properties/longhands/ScrollMarginBlockEnd.h",
     "$blink_core_output_dir/css/properties/longhands/ScrollMarginBlockStart.h",
     "$blink_core_output_dir/css/properties/longhands/ScrollMarginBottom.h",
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn
index e880527..c82f9a4 100644
--- a/third_party/WebKit/Source/core/css/BUILD.gn
+++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -644,6 +644,7 @@
     "properties/longhands/RyCustom.cpp",
     "properties/longhands/ScaleCustom.cpp",
     "properties/longhands/ScrollBehaviorCustom.cpp",
+    "properties/longhands/ScrollCustomizationCustom.cpp",
     "properties/longhands/ScrollMarginBlockEndCustom.cpp",
     "properties/longhands/ScrollMarginBlockStartCustom.cpp",
     "properties/longhands/ScrollMarginBottomCustom.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp b/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp
index 54e48645..231294f0 100644
--- a/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp
+++ b/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp
@@ -97,9 +97,9 @@
     CSSPropertyOverflowX, CSSPropertyOverflowY, CSSPropertyPaddingBottom,
     CSSPropertyPaddingLeft, CSSPropertyPaddingRight, CSSPropertyPaddingTop,
     CSSPropertyPointerEvents, CSSPropertyPosition, CSSPropertyResize,
-    CSSPropertyRight, CSSPropertyScrollBehavior, CSSPropertySpeak,
-    CSSPropertyTableLayout, CSSPropertyTabSize, CSSPropertyTextAlign,
-    CSSPropertyTextAlignLast, CSSPropertyTextDecoration,
+    CSSPropertyRight, CSSPropertyScrollBehavior, CSSPropertyScrollCustomization,
+    CSSPropertySpeak, CSSPropertyTableLayout, CSSPropertyTabSize,
+    CSSPropertyTextAlign, CSSPropertyTextAlignLast, CSSPropertyTextDecoration,
     CSSPropertyTextDecorationLine, CSSPropertyTextDecorationStyle,
     CSSPropertyTextDecorationColor, CSSPropertyTextDecorationSkipInk,
     CSSPropertyTextJustify, CSSPropertyTextUnderlinePosition,
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
index 0afcd5e..3c21b9c 100644
--- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
+++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -47,6 +47,7 @@
 #include "platform/fonts/TextRenderingMode.h"
 #include "platform/graphics/GraphicsTypes.h"
 #include "platform/graphics/TouchAction.h"
+#include "platform/scroll/ScrollCustomization.h"
 #include "platform/scroll/ScrollableArea.h"
 #include "platform/text/TextRun.h"
 #include "platform/text/WritingMode.h"
@@ -1511,6 +1512,34 @@
 }
 
 template <>
+inline ScrollCustomization::ScrollDirection CSSIdentifierValue::ConvertTo()
+    const {
+  switch (value_id_) {
+    case CSSValueNone:
+      return ScrollCustomization::kScrollDirectionNone;
+    case CSSValueAuto:
+      return ScrollCustomization::kScrollDirectionAuto;
+    case CSSValuePanLeft:
+      return ScrollCustomization::kScrollDirectionPanLeft;
+    case CSSValuePanRight:
+      return ScrollCustomization::kScrollDirectionPanRight;
+    case CSSValuePanX:
+      return ScrollCustomization::kScrollDirectionPanX;
+    case CSSValuePanUp:
+      return ScrollCustomization::kScrollDirectionPanUp;
+    case CSSValuePanDown:
+      return ScrollCustomization::kScrollDirectionPanDown;
+    case CSSValuePanY:
+      return ScrollCustomization::kScrollDirectionPanY;
+    default:
+      break;
+  }
+
+  NOTREACHED();
+  return ScrollCustomization::kScrollDirectionNone;
+}
+
+template <>
 inline CSSIdentifierValue::CSSIdentifierValue(CSSBoxType css_box)
     : CSSValue(kIdentifierClass) {
   switch (css_box) {
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index e1277c9d4e..4db7537f 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -2194,6 +2194,18 @@
       },
     },
     {
+      name: "scroll-customization",
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
+      converter: "ConvertFlags<blink::ScrollCustomization::ScrollDirection>",
+      type_name: "ScrollCustomization::ScrollDirection",
+      field_group: "*",
+      field_size: 4,
+      field_template: "primitive",
+      default_value: "ScrollCustomization::kScrollDirectionNone",
+      include_paths: ["platform/scroll/ScrollCustomization.h"],
+      runtime_flag: "ScrollCustomization",
+    },
+    {
       name: "scroll-margin-block-start",
       property_methods: ["ParseSingleValue"],
       runtime_flag: "CSSScrollSnapPoints",
diff --git a/third_party/WebKit/Source/core/css/CSSRule.cpp b/third_party/WebKit/Source/core/css/CSSRule.cpp
index fa928b5..2d75fe4 100644
--- a/third_party/WebKit/Source/core/css/CSSRule.cpp
+++ b/third_party/WebKit/Source/core/css/CSSRule.cpp
@@ -48,13 +48,13 @@
 void CSSRule::SetParentStyleSheet(CSSStyleSheet* style_sheet) {
   parent_is_rule_ = false;
   parent_style_sheet_ = style_sheet;
-  ScriptWrappableVisitor::WriteBarrier(parent_style_sheet_);
+  ScriptWrappableMarkingVisitor::WriteBarrier(parent_style_sheet_);
 }
 
 void CSSRule::SetParentRule(CSSRule* rule) {
   parent_is_rule_ = true;
   parent_rule_ = rule;
-  ScriptWrappableVisitor::WriteBarrier(parent_rule_);
+  ScriptWrappableMarkingVisitor::WriteBarrier(parent_rule_);
 }
 
 void CSSRule::Trace(blink::Visitor* visitor) {
diff --git a/third_party/WebKit/Source/core/css/CSSValueKeywords.json5 b/third_party/WebKit/Source/core/css/CSSValueKeywords.json5
index f736793..8627816 100644
--- a/third_party/WebKit/Source/core/css/CSSValueKeywords.json5
+++ b/third_party/WebKit/Source/core/css/CSSValueKeywords.json5
@@ -1172,5 +1172,15 @@
     // auto,
     // contain
     // none
+
+    //scroll-customization
+    // auto
+    // pan-x,
+    // pan-left,
+    // pan-right,
+    // pan-y,
+    // pan-up,
+    // pan-down
+    // none
   ],
 }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserTest.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserTest.cpp
index 12bf5de..05df892 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserTest.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserTest.cpp
@@ -5,6 +5,7 @@
 #include "core/css/parser/CSSPropertyParser.h"
 
 #include "core/css/CSSColorValue.h"
+#include "core/css/CSSIdentifierValue.h"
 #include "core/css/CSSValueList.h"
 #include "core/css/StyleSheetContents.h"
 #include "core/css/parser/CSSParser.h"
@@ -344,4 +345,47 @@
       UseCounter::IsCounted(*doc, WebFeature::kBasicShapeEllipseNoRadius));
 }
 
+TEST(CSSPropertyParserTest, ScrollCustomizationPropertySingleValue) {
+  RuntimeEnabledFeatures::SetScrollCustomizationEnabled(true);
+  const CSSValue* value = CSSParser::ParseSingleValue(
+      CSSPropertyScrollCustomization, "pan-down",
+      StrictCSSParserContext(SecureContextMode::kSecureContext));
+  DCHECK(value);
+  const CSSValueList* list = ToCSSValueList(value);
+  EXPECT_EQ(1U, list->length());
+  EXPECT_EQ(CSSValuePanDown, ToCSSIdentifierValue(list->Item(0U)).GetValueID());
+}
+
+TEST(CSSPropertyParserTest, ScrollCustomizationPropertyTwoValuesCombined) {
+  RuntimeEnabledFeatures::SetScrollCustomizationEnabled(true);
+  const CSSValue* value = CSSParser::ParseSingleValue(
+      CSSPropertyScrollCustomization, "pan-left pan-y",
+      StrictCSSParserContext(SecureContextMode::kSecureContext));
+  const CSSValueList* list = ToCSSValueList(value);
+  EXPECT_EQ(2U, list->length());
+  EXPECT_EQ(CSSValuePanLeft, ToCSSIdentifierValue(list->Item(0U)).GetValueID());
+  EXPECT_EQ(CSSValuePanY, ToCSSIdentifierValue(list->Item(1U)).GetValueID());
+}
+
+TEST(CSSPropertyParserTest, ScrollCustomizationPropertyInvalidEntries) {
+  // We expect exactly one property value per coordinate.
+  RuntimeEnabledFeatures::SetScrollCustomizationEnabled(true);
+  const CSSValue* value = CSSParser::ParseSingleValue(
+      CSSPropertyScrollCustomization, "pan-left pan-right",
+      StrictCSSParserContext(SecureContextMode::kSecureContext));
+  EXPECT_FALSE(value);
+  value = CSSParser::ParseSingleValue(
+      CSSPropertyScrollCustomization, "pan-up pan-down",
+      StrictCSSParserContext(SecureContextMode::kSecureContext));
+  EXPECT_FALSE(value);
+  value = CSSParser::ParseSingleValue(
+      CSSPropertyScrollCustomization, "pan-x pan-left",
+      StrictCSSParserContext(SecureContextMode::kSecureContext));
+  EXPECT_FALSE(value);
+  value = CSSParser::ParseSingleValue(
+      CSSPropertyScrollCustomization, "pan-x pan-x",
+      StrictCSSParserContext(SecureContextMode::kSecureContext));
+  EXPECT_FALSE(value);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
index f671701..751b65aa 100644
--- a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
+++ b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
@@ -2276,4 +2276,38 @@
   }
 }
 
+// Returns up to two values for 'scroll-customization' property. The values
+// correspond to the customization values for 'x' and 'y' axes.
+CSSValue* ComputedStyleUtils::ScrollCustomizationFlagsToCSSValue(
+    ScrollCustomization::ScrollDirection scroll_customization) {
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  if (scroll_customization == ScrollCustomization::kScrollDirectionAuto) {
+    list->Append(*CSSIdentifierValue::Create(CSSValueAuto));
+  } else if (scroll_customization ==
+             ScrollCustomization::kScrollDirectionNone) {
+    list->Append(*CSSIdentifierValue::Create(CSSValueNone));
+  } else {
+    if ((scroll_customization & ScrollCustomization::kScrollDirectionPanX) ==
+        ScrollCustomization::kScrollDirectionPanX)
+      list->Append(*CSSIdentifierValue::Create(CSSValuePanX));
+    else if (scroll_customization &
+             ScrollCustomization::kScrollDirectionPanLeft)
+      list->Append(*CSSIdentifierValue::Create(CSSValuePanLeft));
+    else if (scroll_customization &
+             ScrollCustomization::kScrollDirectionPanRight)
+      list->Append(*CSSIdentifierValue::Create(CSSValuePanRight));
+    if ((scroll_customization & ScrollCustomization::kScrollDirectionPanY) ==
+        ScrollCustomization::kScrollDirectionPanY)
+      list->Append(*CSSIdentifierValue::Create(CSSValuePanY));
+    else if (scroll_customization & ScrollCustomization::kScrollDirectionPanUp)
+      list->Append(*CSSIdentifierValue::Create(CSSValuePanUp));
+    else if (scroll_customization &
+             ScrollCustomization::kScrollDirectionPanDown)
+      list->Append(*CSSIdentifierValue::Create(CSSValuePanDown));
+  }
+
+  DCHECK(list->length());
+  return list;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h
index 4b9b7383..2330805 100644
--- a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h
+++ b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h
@@ -195,6 +195,8 @@
                                                 const LayoutObject*,
                                                 Node*,
                                                 bool allow_visited_style);
+  static CSSValue* ScrollCustomizationFlagsToCSSValue(
+      ScrollCustomization::ScrollDirection);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/ScrollCustomizationCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/ScrollCustomizationCustom.cpp
new file mode 100644
index 0000000..ca81dd2f
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/longhands/ScrollCustomizationCustom.cpp
@@ -0,0 +1,73 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/longhands/ScrollCustomization.h"
+
+#include "core/css/CSSValueList.h"
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
+
+class CSSParserLocalContext;
+namespace blink {
+
+namespace {
+
+static bool ConsumePan(CSSParserTokenRange& range,
+                       CSSValue** pan_x,
+                       CSSValue** pan_y) {
+  CSSValueID id = range.Peek().Id();
+  if ((id == CSSValuePanX || id == CSSValuePanRight || id == CSSValuePanLeft) &&
+      !*pan_x) {
+    *pan_x = CSSPropertyParserHelpers::ConsumeIdent(range);
+  } else if ((id == CSSValuePanY || id == CSSValuePanDown ||
+              id == CSSValuePanUp) &&
+             !*pan_y) {
+    *pan_y = CSSPropertyParserHelpers::ConsumeIdent(range);
+  } else {
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+namespace CSSLonghand {
+
+const CSSValue* ScrollCustomization::ParseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&) const {
+  CSSValueList* list = CSSValueList::CreateSpaceSeparated();
+  CSSValueID id = range.Peek().Id();
+  if (id == CSSValueAuto || id == CSSValueNone) {
+    list->Append(*CSSPropertyParserHelpers::ConsumeIdent(range));
+    return list;
+  }
+
+  CSSValue* pan_x = nullptr;
+  CSSValue* pan_y = nullptr;
+  if (!ConsumePan(range, &pan_x, &pan_y))
+    return nullptr;
+  if (!range.AtEnd() && !ConsumePan(range, &pan_x, &pan_y))
+    return nullptr;
+
+  if (pan_x)
+    list->Append(*pan_x);
+  if (pan_y)
+    list->Append(*pan_y);
+  return list;
+}
+
+const CSSValue* ScrollCustomization::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ScrollCustomizationFlagsToCSSValue(
+      style.ScrollCustomization());
+}
+
+}  // namespace CSSLonghand
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/threaded/MultiThreadedTestUtil.h b/third_party/WebKit/Source/core/css/threaded/MultiThreadedTestUtil.h
index 64e32bc..78c9657 100644
--- a/third_party/WebKit/Source/core/css/threaded/MultiThreadedTestUtil.h
+++ b/third_party/WebKit/Source/core/css/threaded/MultiThreadedTestUtil.h
@@ -57,7 +57,8 @@
     Vector<std::unique_ptr<WaitableEvent>> waits;
 
     for (int i = 0; i < num_threads_; ++i) {
-      threads.push_back(WebThreadSupportingGC::Create(""));
+      threads.push_back(
+          WebThreadSupportingGC::Create(WebThreadCreationParams("")));
       waits.push_back(std::make_unique<WaitableEvent>());
     }
 
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 939ffe2..17b4f87 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -4684,10 +4684,10 @@
 static void LiveNodeListBaseWriteBarrier(void* parent,
                                          const LiveNodeListBase* list) {
   if (IsHTMLCollectionType(list->GetType())) {
-    ScriptWrappableVisitor::WriteBarrier(
+    ScriptWrappableMarkingVisitor::WriteBarrier(
         static_cast<const HTMLCollection*>(list));
   } else {
-    ScriptWrappableVisitor::WriteBarrier(
+    ScriptWrappableMarkingVisitor::WriteBarrier(
         static_cast<const LiveNodeList*>(list));
   }
 }
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 516e6bdb..aec9faf 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -124,12 +124,14 @@
 #include "core/layout/AdjustForAbsoluteZoom.h"
 #include "core/layout/LayoutTextFragment.h"
 #include "core/layout/LayoutView.h"
+#include "core/layout/svg/SVGResources.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
 #include "core/page/PointerLockController.h"
 #include "core/page/SpatialNavigation.h"
 #include "core/page/scrolling/RootScrollerController.h"
+#include "core/page/scrolling/RootScrollerUtil.h"
 #include "core/page/scrolling/ScrollCustomizationCallbacks.h"
 #include "core/page/scrolling/ScrollState.h"
 #include "core/page/scrolling/ScrollStateCallback.h"
@@ -139,7 +141,6 @@
 #include "core/resize_observer/ResizeObservation.h"
 #include "core/svg/SVGAElement.h"
 #include "core/svg/SVGElement.h"
-#include "core/svg/SVGTreeScopeResources.h"
 #include "core/svg_names.h"
 #include "core/xml_names.h"
 #include "platform/EventDispatchForbiddenScope.h"
@@ -615,6 +616,11 @@
                                        ->GlobalRootScrollerController()
                                        .IsViewportScrollCallback(callback);
 
+  disable_custom_callbacks |=
+      !RootScrollerUtil::IsGlobal(this) &&
+      RuntimeEnabledFeatures::ScrollCustomizationEnabled() &&
+      !GetScrollCustomizationCallbacks().InScrollPhase(this);
+
   if (!callback || disable_custom_callbacks) {
     NativeDistributeScroll(scroll_state);
     return;
@@ -628,7 +634,7 @@
   if (callback->NativeScrollBehavior() ==
       WebNativeScrollBehavior::kPerformAfterNativeScroll)
     callback->handleEvent(&scroll_state);
-};
+}
 
 void Element::NativeApplyScroll(ScrollState& scroll_state) {
   // All elements in the scroll chain should be boxes.
@@ -697,6 +703,10 @@
                                        .GetPage()
                                        ->GlobalRootScrollerController()
                                        .IsViewportScrollCallback(callback);
+  disable_custom_callbacks |=
+      !RootScrollerUtil::IsGlobal(this) &&
+      RuntimeEnabledFeatures::ScrollCustomizationEnabled() &&
+      !GetScrollCustomizationCallbacks().InScrollPhase(this);
 
   if (!callback || disable_custom_callbacks) {
     NativeApplyScroll(scroll_state);
@@ -1794,11 +1804,8 @@
     if (this == GetDocument().CssTarget())
       GetDocument().SetCSSTarget(nullptr);
 
-    if (HasPendingResources()) {
-      GetTreeScope()
-          .EnsureSVGTreeScopedResources()
-          .RemoveElementFromPendingResources(*this);
-    }
+    if (HasPendingResources())
+      SVGResources::RemoveWatchesForElement(*this);
 
     if (GetCustomElementState() == CustomElementState::kCustom)
       CustomElement::EnqueueDisconnectedCallback(this);
@@ -3271,6 +3278,24 @@
   }
 }
 
+void Element::WillBeginCustomizedScrollPhase(
+    ScrollCustomization::ScrollDirection direction) {
+  DCHECK(!GetScrollCustomizationCallbacks().InScrollPhase(this));
+  LayoutBox* box = GetLayoutBox();
+  if (!box)
+    return;
+
+  ScrollCustomization::ScrollDirection scroll_customization =
+      box->Style()->ScrollCustomization();
+
+  GetScrollCustomizationCallbacks().SetInScrollPhase(
+      this, direction & scroll_customization);
+}
+
+void Element::DidEndCustomizedScrollPhase() {
+  GetScrollCustomizationCallbacks().SetInScrollPhase(this, false);
+}
+
 // Step 1 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
 static Element* ContextElementForInsertion(const String& where,
                                            Element* element,
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index 3ca2c75..c244f88b 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -36,6 +36,7 @@
 #include "core/resize_observer/ResizeObserver.h"
 #include "platform/bindings/TraceWrapperMember.h"
 #include "platform/heap/Handle.h"
+#include "platform/scroll/ScrollCustomization.h"
 #include "platform/scroll/ScrollTypes.h"
 #include "public/platform/WebFocusType.h"
 
@@ -839,6 +840,9 @@
   EnsureResizeObserverData();
   void SetNeedsResizeObserverUpdate();
 
+  void WillBeginCustomizedScrollPhase(ScrollCustomization::ScrollDirection);
+  void DidEndCustomizedScrollPhase();
+
  protected:
   Element(const QualifiedName& tag_name, Document*, ConstructionType);
 
diff --git a/third_party/WebKit/Source/core/dom/IdTargetObserver.h b/third_party/WebKit/Source/core/dom/IdTargetObserver.h
index 8952e72..5b74de2 100644
--- a/third_party/WebKit/Source/core/dom/IdTargetObserver.h
+++ b/third_party/WebKit/Source/core/dom/IdTargetObserver.h
@@ -43,6 +43,8 @@
  protected:
   IdTargetObserver(IdTargetObserverRegistry&, const AtomicString& id);
 
+  const AtomicString& Id() const { return id_; }
+
  private:
   IdTargetObserverRegistry& Registry() { return *registry_; }
 
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index be06d6e..295b3e3 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -340,7 +340,7 @@
 
   DCHECK(data_.rare_data_);
   SetFlag(kHasRareDataFlag);
-  ScriptWrappableVisitor::WriteBarrier(RareData());
+  ScriptWrappableMarkingVisitor::WriteBarrier(RareData());
   return *RareData();
 }
 
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
index c86b5d7..edb5c59 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -1577,12 +1577,6 @@
          ToHTMLInputElement(text_control)->type() == InputTypeNames::password;
 }
 
-bool IsTextSecurityNode(const Node* node) {
-  return node && node->GetLayoutObject() &&
-         node->GetLayoutObject()->Style()->TextSecurity() !=
-             ETextSecurity::kNone;
-}
-
 // If current position is at grapheme boundary, return 0; otherwise, return the
 // distance to its nearest left grapheme boundary.
 size_t ComputeDistanceToLeftGraphemeBoundary(const Position& position) {
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.h b/third_party/WebKit/Source/core/editing/EditingUtilities.h
index c0bd3f3..4ddf35b 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.h
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.h
@@ -174,7 +174,6 @@
 bool IsBlockFlowElement(const Node&);
 EUserSelect UsedValueOfUserSelect(const Node&);
 bool IsInPasswordField(const Position&);
-bool IsTextSecurityNode(const Node*);
 CORE_EXPORT TextDirection DirectionOfEnclosingBlockOf(const Position&);
 CORE_EXPORT TextDirection
 DirectionOfEnclosingBlockOf(const PositionInFlatTree&);
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp
index 5ca993d..184fe4a 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp
@@ -30,10 +30,21 @@
 #include "core/editing/EditingUtilities.h"
 #include "core/editing/iterators/BackwardsTextBuffer.h"
 #include "core/html/HTMLElement.h"
+#include "core/layout/LayoutObject.h"
 #include "platform/wtf/text/StringBuilder.h"
 
 namespace blink {
 
+namespace {
+
+bool IsTextSecurityNode(const Node& node) {
+  return node.GetLayoutObject() &&
+         node.GetLayoutObject()->Style()->TextSecurity() !=
+             ETextSecurity::kNone;
+}
+
+}  // anonymous namespace
+
 TextIteratorTextState::TextIteratorTextState(
     const TextIteratorBehavior& behavior)
     : behavior_(behavior) {}
@@ -146,7 +157,7 @@
                                      unsigned text_end_offset) {
   DCHECK(text_node);
   text_ =
-      behavior_.EmitsSmallXForTextSecurity() && IsTextSecurityNode(text_node)
+      behavior_.EmitsSmallXForTextSecurity() && IsTextSecurityNode(*text_node)
           ? RepeatString("x", string.length())
           : string,
 
diff --git a/third_party/WebKit/Source/core/events/MessageEvent.idl b/third_party/WebKit/Source/core/events/MessageEvent.idl
index 7be2489..2226c4a 100644
--- a/third_party/WebKit/Source/core/events/MessageEvent.idl
+++ b/third_party/WebKit/Source/core/events/MessageEvent.idl
@@ -40,10 +40,9 @@
     [CachedAttribute=isPortsDirty] readonly attribute FrozenArray<MessagePort> ports;
     [RuntimeEnabled=Suborigins] readonly attribute DOMString suborigin;
 
-    // TODO(foolip): |typeArg| should not be optional, none of the arguments
-    // should have [Default=Undefined] (they have other default values in the
-    // spec) and |sourceArg|'s type is wrong.
-    [Custom, MeasureAs=InitMessageEvent] void initMessageEvent([Default=Undefined] optional DOMString typeArg,
+    // TODO(foolip): none of the arguments should have [Default=Undefined] (they
+    // have other default values in the spec) and |sourceArg|'s type is wrong.
+    [Custom, MeasureAs=InitMessageEvent] void initMessageEvent([Default=Undefined] DOMString typeArg,
                                    [Default=Undefined] optional boolean canBubbleArg,
                                    [Default=Undefined] optional boolean cancelableArg,
                                    [Default=Undefined] optional any dataArg,
diff --git a/third_party/WebKit/Source/core/fetch/DataConsumerHandleTestUtil.cpp b/third_party/WebKit/Source/core/fetch/DataConsumerHandleTestUtil.cpp
index 366558c..38c6a66 100644
--- a/third_party/WebKit/Source/core/fetch/DataConsumerHandleTestUtil.cpp
+++ b/third_party/WebKit/Source/core/fetch/DataConsumerHandleTestUtil.cpp
@@ -40,7 +40,7 @@
 DataConsumerHandleTestUtil::Thread::Thread(
     const char* name,
     InitializationPolicy initialization_policy)
-    : thread_(WebThreadSupportingGC::Create(name)),
+    : thread_(WebThreadSupportingGC::Create(WebThreadCreationParams(name))),
       initialization_policy_(initialization_policy),
       waitable_event_(std::make_unique<WaitableEvent>()) {
   thread_->PostTask(FROM_HERE, CrossThreadBind(&Thread::Initialize,
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index b0bf07bf..23da9fd6 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -549,6 +549,12 @@
               String("CSS cannot be loaded from `file:` URLs unless they end "
                      "in a `.css` file extension.")};
 
+    case WebFeature::kCreateObjectURLMediaStream:
+      return {"CreateObjectURLMediaStreamDeprecated", M68,
+              replacedWillBeRemoved("URL.createObjectURL with media streams",
+                                    "HTMLMediaElement.srcObject", M68,
+                                    "5618491470118912")};
+
     case WebFeature::kWebAudioDezipperGainNodeGain:
       return {"WebAudioDezipperGainNodeGain", Unknown,
               DeprecatedWebAudioDezippering("GainNode.gain")};
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.cpp b/third_party/WebKit/Source/core/frame/UseCounter.cpp
index 84f99b2..6ce902b 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.cpp
+++ b/third_party/WebKit/Source/core/frame/UseCounter.cpp
@@ -48,7 +48,7 @@
 }
 
 // Make sure update_use_counter_css.py was run which updates histograms.xml.
-constexpr int kMaximumCSSSampleId = 589;
+constexpr int kMaximumCSSSampleId = 590;
 
 }  // namespace
 
@@ -1138,12 +1138,13 @@
       return 588;
     case CSSPropertyTextDecorationSkipInk:
       return 589;
+    case CSSPropertyScrollCustomization:
+      return 590;
     // 1. Add new features above this line (don't change the assigned numbers of
     // the existing items).
     // 2. Update kMaximumCSSSampleId with the new maximum value.
     // 3. Run the update_use_counter_css.py script in
     // chromium/src/tools/metrics/histograms to update the UMA histogram names.
-
     case CSSPropertyInvalid:
       NOTREACHED();
       return 0;
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
index 86fee14b..c0eea8a 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
@@ -35,6 +35,7 @@
 #include "core/loader/FrameLoadRequest.h"
 #include "core/loader/FrameLoader.h"
 #include "core/page/Page.h"
+#include "core/page/scrolling/RootScrollerController.h"
 #include "core/probe/CoreProbes.h"
 #include "core/timing/DOMWindowPerformance.h"
 #include "core/timing/Performance.h"
@@ -273,6 +274,8 @@
     embedded_content_view_->AttachToLayout();
   }
 
+  GetDocument().GetRootScrollerController().DidUpdateIFrameFrameView(*this);
+
   if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
     cache->ChildrenChanged(layout_embedded_content);
 }
diff --git a/third_party/WebKit/Source/core/html/forms/SliderThumbElement.cpp b/third_party/WebKit/Source/core/html/forms/SliderThumbElement.cpp
index 5fa5989..ebbd609 100644
--- a/third_party/WebKit/Source/core/html/forms/SliderThumbElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/SliderThumbElement.cpp
@@ -344,7 +344,7 @@
 
 void SliderContainerElement::HandleTouchEvent(TouchEvent* event) {
   HTMLInputElement* input = HostInput();
-  if (input->IsDisabledFormControl())
+  if (!input || input->IsDisabledFormControl() || !event)
     return;
 
   if (event->type() == EventTypeNames::touchend) {
@@ -365,6 +365,9 @@
   TouchList* touches = event->targetTouches();
   SliderThumbElement* thumb = ToSliderThumbElement(
       GetTreeScope().getElementById(ShadowElementNames::SliderThumb()));
+  if (!thumb || !touches)
+    return;
+
   if (touches->length() == 1) {
     if (event->type() == EventTypeNames::touchstart) {
       start_point_ = touches->item(0)->AbsoluteLocation();
diff --git a/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp
index 241d5d8..513023f4 100644
--- a/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp
@@ -3609,7 +3609,7 @@
 #if DCHECK_IS_ON()
   // There can be up to three children: an interstitial (media remoting or
   // picture in picture), text track container, and media controls. The media
-  // controls has to be the last child if presend, and has to be the next
+  // controls has to be the last child if present, and has to be the next
   // sibling of the text track container if both present. When present, media
   // remoting interstitial has to be the first child.
   unsigned number_of_children = shadow_root.CountChildren();
diff --git a/third_party/WebKit/Source/core/input/ScrollManager.cpp b/third_party/WebKit/Source/core/input/ScrollManager.cpp
index a843c09..4cb5ac5 100644
--- a/third_party/WebKit/Source/core/input/ScrollManager.cpp
+++ b/third_party/WebKit/Source/core/input/ScrollManager.cpp
@@ -24,6 +24,7 @@
 #include "core/page/scrolling/SnapCoordinator.h"
 #include "core/paint/PaintLayer.h"
 #include "platform/Histogram.h"
+#include "platform/scroll/ScrollCustomization.h"
 #include "platform/wtf/PtrUtil.h"
 
 namespace blink {
@@ -252,6 +253,7 @@
     frame_->GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
 
   DCHECK(!current_scroll_chain_.empty());
+
   scroll_state.SetScrollChain(current_scroll_chain_);
 
   scroll_state.distributeToScrollChainDescendant();
@@ -363,6 +365,8 @@
   if (current_scroll_chain_.empty())
     return WebInputEventResult::kNotHandled;
 
+  NotifyScrollPhaseBeginForCustomizedScroll(*scroll_state);
+
   CustomizedScroll(*scroll_state);
 
   if (gesture_event.source_device == kWebGestureDeviceTouchscreen)
@@ -516,6 +520,7 @@
         ScrollState::Create(std::move(scroll_state_data));
     CustomizedScroll(*scroll_state);
     SnapAtGestureScrollEnd();
+    NotifyScrollPhaseEndForCustomizedScroll();
   }
 
   ClearGestureScrollState();
@@ -744,4 +749,24 @@
   return scroll_begin;
 }
 
+void ScrollManager::NotifyScrollPhaseBeginForCustomizedScroll(
+    const ScrollState& scroll_state) {
+  ScrollCustomization::ScrollDirection direction =
+      ScrollCustomization::GetScrollDirectionFromDeltas(
+          scroll_state.deltaXHint(), scroll_state.deltaYHint());
+  for (auto id : current_scroll_chain_) {
+    Node* node = DOMNodeIds::NodeForId(id);
+    if (node && node->IsElementNode())
+      ToElement(node)->WillBeginCustomizedScrollPhase(direction);
+  }
+}
+
+void ScrollManager::NotifyScrollPhaseEndForCustomizedScroll() {
+  for (auto id : current_scroll_chain_) {
+    Node* node = DOMNodeIds::NodeForId(id);
+    if (node && node->IsElementNode())
+      ToElement(node)->DidEndCustomizedScrollPhase();
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/input/ScrollManager.h b/third_party/WebKit/Source/core/input/ScrollManager.h
index 545313b..60b14be1 100644
--- a/third_party/WebKit/Source/core/input/ScrollManager.h
+++ b/third_party/WebKit/Source/core/input/ScrollManager.h
@@ -122,6 +122,9 @@
 
   void SnapAtGestureScrollEnd();
 
+  void NotifyScrollPhaseBeginForCustomizedScroll(const ScrollState&);
+  void NotifyScrollPhaseEndForCustomizedScroll();
+
   // NOTE: If adding a new field to this class please ensure that it is
   // cleared in |ScrollManager::clear()|.
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorMemoryAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorMemoryAgent.cpp
index b425d02..2fd5a1f 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorMemoryAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorMemoryAgent.cpp
@@ -30,21 +30,12 @@
 
 #include "core/inspector/InspectorMemoryAgent.h"
 
-#include "base/debug/stack_trace.h"
 #include "core/frame/LocalFrameClient.h"
 #include "core/inspector/InspectedFrames.h"
 #include "platform/InstanceCounters.h"
-#include "platform/memory_profiler/SamplingNativeHeapProfiler.h"
 
 namespace blink {
 
-const unsigned kDefaultNativeMemorySamplingInterval = 128 * 1024;
-
-namespace MemoryAgentState {
-static const char samplingProfileInterval[] =
-    "memoryAgentSamplingProfileInterval";
-}  // namespace MemoryAgentState
-
 using PrepareForLeakDetectionCallback =
     protocol::Memory::Backend::PrepareForLeakDetectionCallback;
 using protocol::Response;
@@ -85,87 +76,4 @@
   InspectorBaseAgent::Trace(visitor);
 }
 
-void InspectorMemoryAgent::Restore() {
-  int sampling_interval = 0;
-  state_->getInteger(MemoryAgentState::samplingProfileInterval,
-                     &sampling_interval);
-  // The action below won't start sampling if the sampling_interval is zero.
-  startSampling(protocol::Maybe<int>(sampling_interval),
-                protocol::Maybe<bool>());
-}
-
-Response InspectorMemoryAgent::startSampling(
-    protocol::Maybe<int> in_sampling_interval,
-    protocol::Maybe<bool> in_suppressRandomness) {
-  int interval =
-      in_sampling_interval.fromMaybe(kDefaultNativeMemorySamplingInterval);
-  if (interval <= 0)
-    return Response::Error("Invalid sampling rate.");
-  SamplingNativeHeapProfiler::GetInstance()->SetSamplingInterval(interval);
-  state_->setInteger(MemoryAgentState::samplingProfileInterval, interval);
-  if (in_suppressRandomness.fromMaybe(false))
-    SamplingNativeHeapProfiler::GetInstance()->SuppressRandomnessForTest();
-  SamplingNativeHeapProfiler::GetInstance()->Start();
-  return Response::OK();
-}
-
-Response InspectorMemoryAgent::stopSampling() {
-  int sampling_interval = 0;
-  state_->getInteger(MemoryAgentState::samplingProfileInterval,
-                     &sampling_interval);
-  if (!sampling_interval)
-    return Response::Error("Sampling profiler is not started.");
-  SamplingNativeHeapProfiler::GetInstance()->Stop();
-  state_->setInteger(MemoryAgentState::samplingProfileInterval, 0);
-  return Response::OK();
-}
-
-Response InspectorMemoryAgent::getSamplingProfile(
-    std::unique_ptr<protocol::Memory::SamplingProfile>* out_profile) {
-  std::unique_ptr<protocol::Array<protocol::Memory::SamplingProfileNode>>
-      samples =
-          protocol::Array<protocol::Memory::SamplingProfileNode>::create();
-  std::vector<SamplingNativeHeapProfiler::Sample> raw_samples =
-      SamplingNativeHeapProfiler::GetInstance()->GetSamples();
-  // TODO(alph): Only report samples recorded within the current session.
-  for (auto it = raw_samples.begin(); it != raw_samples.end(); ++it) {
-    std::unique_ptr<protocol::Array<protocol::String>> stack =
-        protocol::Array<protocol::String>::create();
-    std::vector<std::string> source_stack = Symbolize(it->stack);
-    for (auto it2 = source_stack.begin(); it2 != source_stack.end(); ++it2)
-      stack->addItem(it2->c_str());
-    samples->addItem(protocol::Memory::SamplingProfileNode::create()
-                         .setSize(it->size)
-                         .setCount(it->count)
-                         .setStack(std::move(stack))
-                         .build());
-  }
-  std::unique_ptr<protocol::Memory::SamplingProfile> result =
-      protocol::Memory::SamplingProfile::create()
-          .setSamples(std::move(samples))
-          .build();
-  *out_profile = std::move(result);
-  return Response::OK();
-}
-
-std::vector<std::string> InspectorMemoryAgent::Symbolize(
-    const std::vector<void*>& addresses) {
-  // TODO(alph): Move symbolization to the client.
-  std::vector<std::string> result;
-  base::debug::StackTrace trace(addresses.data(), addresses.size());
-  std::string text = trace.ToString();
-
-  size_t next_pos;
-  for (size_t pos = 0;; pos = next_pos + 1) {
-    next_pos = text.find('\n', pos);
-    if (next_pos == std::string::npos)
-      break;
-    std::string line = text.substr(pos, next_pos - pos);
-    size_t space_pos = line.rfind(' ');
-    result.push_back(
-        line.substr(space_pos == std::string::npos ? 0 : space_pos + 1));
-  }
-  return result;
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorMemoryAgent.h b/third_party/WebKit/Source/core/inspector/InspectorMemoryAgent.h
index 8f88c04a..2c953846 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorMemoryAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorMemoryAgent.h
@@ -52,7 +52,6 @@
   ~InspectorMemoryAgent() override;
 
   void Trace(blink::Visitor*) override;
-  void Restore() override;
 
   protocol::Response getDOMCounters(int* documents,
                                     int* nodes,
@@ -63,24 +62,11 @@
   // BlinkLeakDetectorClient:
   void OnLeakDetectionComplete() override;
 
-  // Memory protocol domain:
-  protocol::Response startSampling(
-      protocol::Maybe<int> in_samplingInterval,
-      protocol::Maybe<bool> in_suppressRandomness) override;
-  protocol::Response stopSampling() override;
-  protocol::Response getSamplingProfile(
-      std::unique_ptr<protocol::Memory::SamplingProfile>*) override;
-
  private:
   explicit InspectorMemoryAgent(InspectedFrames*);
-
-  std::vector<std::string> Symbolize(const std::vector<void*>& addresses);
-
   std::unique_ptr<BlinkLeakDetector> detector_;
   std::unique_ptr<PrepareForLeakDetectionCallback> callback_;
   Member<InspectedFrames> frames_;
-  std::map<void*, std::string> symbols_cache_;
-
   DISALLOW_COPY_AND_ASSIGN(InspectorMemoryAgent);
 };
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
index 00298cb..20b205a 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
@@ -335,18 +335,17 @@
 const char* CompileOptionsString(v8::ScriptCompiler::CompileOptions options) {
   switch (options) {
     case v8::ScriptCompiler::kNoCompileOptions:
-      return "no";
+      return "code";
     case v8::ScriptCompiler::kProduceParserCache:
       return "parser";
     case v8::ScriptCompiler::kConsumeParserCache:
       return "parser";
-    case v8::ScriptCompiler::kProduceCodeCache:
-      return "code";
-    case v8::ScriptCompiler::kProduceFullCodeCache:
-      return "full code";
     case v8::ScriptCompiler::kConsumeCodeCache:
       return "code";
-    default:
+    case v8::ScriptCompiler::kEagerCompile:
+      return "full code";
+    case v8::ScriptCompiler::kProduceCodeCache:
+    case v8::ScriptCompiler::kProduceFullCodeCache:
       NOTREACHED();
   }
   NOTREACHED();
@@ -1057,8 +1056,8 @@
     int cache_size)
     : produce_options(produce_options), cache_size(cache_size) {
   DCHECK(produce_options == v8::ScriptCompiler::kProduceParserCache ||
-         produce_options == v8::ScriptCompiler::kProduceCodeCache ||
-         produce_options == v8::ScriptCompiler::kProduceFullCodeCache);
+         produce_options == v8::ScriptCompiler::kNoCompileOptions ||
+         produce_options == v8::ScriptCompiler::kEagerCompile);
 }
 
 InspectorCompileScriptEvent::V8CacheResult::ConsumeResult::ConsumeResult(
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index a19cf00..377abc97 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -6886,45 +6886,6 @@
                         "moderate",
                         "critical"
                     ]
-                },
-                {
-                    "id": "SamplingProfileNode",
-                    "description": "Heap profile sample.",
-                    "type": "object",
-                    "properties": [
-                        {
-                            "name": "size",
-                            "description": "Size of the sampled allocation.",
-                            "type": "number"
-                        },
-                        {
-                            "name": "count",
-                            "description": "Number of sampled allocations of that size.",
-                            "type": "number"
-                        },
-                        {
-                            "name": "stack",
-                            "description": "Execution stack at the point of allocation.",
-                            "type": "array",
-                            "items": {
-                                "type": "string"
-                            }
-                        }
-                    ]
-                },
-                {
-                    "id": "SamplingProfile",
-                    "description": "Array of heap profile samples.",
-                    "type": "object",
-                    "properties": [
-                        {
-                            "name": "samples",
-                            "type": "array",
-                            "items": {
-                                "$ref": "SamplingProfileNode"
-                            }
-                        }
-                    ]
                 }
             ],
             "commands": [
@@ -6969,38 +6930,6 @@
                             "$ref": "PressureLevel"
                         }
                     ]
-                },
-                {
-                    "name": "startSampling",
-                    "description": "Start collecting native memory profile.",
-                    "parameters": [
-                        {
-                            "name": "samplingInterval",
-                            "description": "Average number of bytes between samples.",
-                            "optional": true,
-                            "type": "integer"
-                        },
-                        {
-                            "name": "suppressRandomness",
-                            "description": "Do not randomize intervals between samples.",
-                            "optional": true,
-                            "type": "boolean"
-                        }
-                    ]
-                },
-                {
-                    "name": "stopSampling",
-                    "description": "Stop collecting native memory profile."
-                },
-                {
-                    "name": "getSamplingProfile",
-                    "description": "Retrieve collected native memory profile.",
-                    "returns": [
-                        {
-                            "name": "profile",
-                            "$ref": "SamplingProfile"
-                        }
-                    ]
                 }
             ]
         },
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.pdl b/third_party/WebKit/Source/core/inspector/browser_protocol.pdl
index 2ce44ef..20af43d7 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.pdl
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.pdl
@@ -3151,37 +3151,6 @@
       # Memory pressure level of the notification.
       PressureLevel level
 
-  # Start collecting native memory profile.
-  command startSampling
-    parameters
-      # Average number of bytes between samples.
-      optional integer samplingInterval
-      # Do not randomize intervals between samples.
-      optional boolean suppressRandomness
-
-  # Stop collecting native memory profile.
-  command stopSampling
-
-  # Retrieve collected native memory profile.
-  command getSamplingProfile
-    returns
-      SamplingProfile profile
-
-  # Heap profile sample.
-  type SamplingProfileNode extends object
-    properties
-      # Size of the sampled allocation.
-      number size
-      # Number of sampled allocations of that size.
-      number count
-      # Execution stack at the point of allocation.
-      array of string stack
-
-  # Array of heap profile samples.
-  type SamplingProfile extends object
-    properties
-      array of SamplingProfileNode samples
-
 # Network domain allows tracking network activities of the page. It exposes information about http,
 # file, data and other requests and responses, their headers, bodies, timing, etc.
 domain Network
diff --git a/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json b/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
index 0a1aa05..7cc7e78 100644
--- a/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
+++ b/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
@@ -69,7 +69,7 @@
             },
             {
                 "domain": "Memory",
-                "include": ["getDOMCounters", "prepareForLeakDetection", "startSampling", "stopSampling", "getSamplingProfile"],
+                "include": ["getDOMCounters", "prepareForLeakDetection"],
                 "async": ["prepareForLeakDetection"]
             },
             {
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index 0d245be..3d19660d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -51,6 +51,7 @@
 #include "core/layout/api/LineLayoutItem.h"
 #include "core/layout/line/InlineTextBox.h"
 #include "core/page/Page.h"
+#include "core/page/scrolling/RootScrollerController.h"
 #include "core/paint/BlockPaintInvalidator.h"
 #include "core/paint/BlockPainter.h"
 #include "core/paint/ObjectPaintInvalidator.h"
@@ -409,6 +410,10 @@
 
 void LayoutBlock::UpdateAfterLayout() {
   InvalidateStickyConstraints();
+
+  if (RuntimeEnabledFeatures::ImplicitRootScrollerEnabled() && GetNode())
+    GetDocument().GetRootScrollerController().ConsiderForImplicit(*GetNode());
+
   LayoutBox::UpdateAfterLayout();
 }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 2482b93..64ea6dd 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -58,7 +58,6 @@
 #include "core/layout/shapes/ShapeOutsideInfo.h"
 #include "core/page/AutoscrollController.h"
 #include "core/page/Page.h"
-#include "core/page/scrolling/RootScrollerController.h"
 #include "core/page/scrolling/RootScrollerUtil.h"
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "core/page/scrolling/SnapCoordinator.h"
diff --git a/third_party/WebKit/Source/core/layout/LayoutIFrame.cpp b/third_party/WebKit/Source/core/layout/LayoutIFrame.cpp
index 73abc66..f6f15609 100644
--- a/third_party/WebKit/Source/core/layout/LayoutIFrame.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutIFrame.cpp
@@ -26,6 +26,7 @@
 #include "core/layout/LayoutIFrame.h"
 
 #include "core/layout/LayoutAnalyzer.h"
+#include "core/page/scrolling/RootScrollerController.h"
 
 namespace blink {
 
@@ -60,4 +61,11 @@
   ClearNeedsLayout();
 }
 
+void LayoutIFrame::UpdateAfterLayout() {
+  if (RuntimeEnabledFeatures::ImplicitRootScrollerEnabled() && GetNode())
+    GetDocument().GetRootScrollerController().ConsiderForImplicit(*GetNode());
+
+  LayoutEmbeddedContent::UpdateAfterLayout();
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutIFrame.h b/third_party/WebKit/Source/core/layout/LayoutIFrame.h
index 820aabb..81d404a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutIFrame.h
+++ b/third_party/WebKit/Source/core/layout/LayoutIFrame.h
@@ -41,6 +41,7 @@
   bool IsInlineBlockOrInlineTable() const override;
 
   void UpdateLayout() override;
+  void UpdateAfterLayout() override;
 
   bool IsOfType(LayoutObjectType type) const override {
     return type == kLayoutObjectLayoutIFrame ||
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
index d958b72..4698ad26 100644
--- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -848,6 +848,14 @@
 }
 
 LayoutPoint LayoutInline::FirstLineBoxTopLeft() const {
+  if (const NGPhysicalBoxFragment* box_fragment =
+          EnclosingBlockFlowFragmentOf(*this)) {
+    const auto& fragments =
+        NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this);
+    if (fragments.IsEmpty())
+      return LayoutPoint();
+    return fragments.front().offset_to_container_box.ToLayoutPoint();
+  }
   if (InlineBox* first_box = FirstLineBoxIncludingCulling())
     return first_box->Location();
   return LayoutPoint();
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
index 1638a3b..edea234 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
@@ -146,11 +146,14 @@
   SetWidth(LayoutUnit(std::max(min_width, std::min(max_width, w))));
 
   // Buttons and track pieces can all have margins along the axis of the
-  // scrollbar.
-  SetMarginLeft(
-      MinimumValueForLength(Style()->MarginLeft(), LayoutUnit(visible_size)));
-  SetMarginRight(
-      MinimumValueForLength(Style()->MarginRight(), LayoutUnit(visible_size)));
+  // scrollbar. Values are rounded because scrollbar parts need to be rendered
+  // at device pixel boundaries.
+  SetMarginLeft(LayoutUnit(
+      MinimumValueForLength(Style()->MarginLeft(), LayoutUnit(visible_size))
+          .Round()));
+  SetMarginRight(LayoutUnit(
+      MinimumValueForLength(Style()->MarginRight(), LayoutUnit(visible_size))
+          .Round()));
 }
 
 void LayoutScrollbarPart::ComputeScrollbarHeight() {
@@ -174,11 +177,14 @@
   SetHeight(LayoutUnit(std::max(min_height, std::min(max_height, h))));
 
   // Buttons and track pieces can all have margins along the axis of the
-  // scrollbar.
-  SetMarginTop(
-      MinimumValueForLength(Style()->MarginTop(), LayoutUnit(visible_size)));
-  SetMarginBottom(
-      MinimumValueForLength(Style()->MarginBottom(), LayoutUnit(visible_size)));
+  // scrollbar. Values are rounded because scrollbar parts need to be rendered
+  // at device pixel boundaries.
+  SetMarginTop(LayoutUnit(
+      MinimumValueForLength(Style()->MarginTop(), LayoutUnit(visible_size))
+          .Round()));
+  SetMarginBottom(LayoutUnit(
+      MinimumValueForLength(Style()->MarginBottom(), LayoutUnit(visible_size))
+          .Round()));
 }
 
 void LayoutScrollbarPart::ComputePreferredLogicalWidths() {
diff --git a/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp b/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
index 634ca6d6..574de644 100644
--- a/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
+++ b/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
@@ -9,6 +9,7 @@
 #include "core/frame/WebLocalFrameImpl.h"
 #include "core/input/EventHandler.h"
 #include "core/inspector/DevToolsEmulator.h"
+#include "core/layout/LayoutScrollbarPart.h"
 #include "core/layout/LayoutView.h"
 #include "core/page/Page.h"
 #include "core/paint/PaintLayerScrollableArea.h"
@@ -1658,6 +1659,95 @@
   EXPECT_TRUE(layout_viewport->HorizontalScrollbar());
 }
 
+class ScrollbarTrackMarginsTest : public ScrollbarsTest {
+ public:
+  void PrepareTest(const String& track_style) {
+    WebView().Resize(WebSize(200, 200));
+
+    SimRequest request("https://example.com/test.html", "text/html");
+    LoadURL("https://example.com/test.html");
+    request.Complete(R"HTML(
+      <!DOCTYPE html>
+        <style>
+        ::-webkit-scrollbar {
+          width: 10px;
+        })HTML" + track_style +
+                     R"HTML(
+        #d1 {
+          position: absolute;
+          left: 0;
+          right: 0;
+          top: 0;
+          bottom: 0;
+          overflow-x:scroll;
+          overflow-y:scroll;
+        }
+      </style>
+      <div id='d1'/>
+    )HTML");
+
+    // No DCHECK failure. Issue 801123.
+    Compositor().BeginFrame();
+
+    Element* div = GetDocument().getElementById("d1");
+    ASSERT_TRUE(div);
+
+    ScrollableArea* div_scrollable =
+        ToLayoutBox(div->GetLayoutObject())->GetScrollableArea();
+
+    ASSERT_TRUE(div_scrollable->HorizontalScrollbar());
+    LayoutScrollbar* horizontal_scrollbar =
+        ToLayoutScrollbar(div_scrollable->HorizontalScrollbar());
+    horizontal_track_ = horizontal_scrollbar->GetPart(kTrackBGPart);
+    ASSERT_TRUE(horizontal_track_);
+
+    ASSERT_TRUE(div_scrollable->VerticalScrollbar());
+    LayoutScrollbar* vertical_scrollbar =
+        ToLayoutScrollbar(div_scrollable->VerticalScrollbar());
+    vertical_track_ = vertical_scrollbar->GetPart(kTrackBGPart);
+    ASSERT_TRUE(vertical_track_);
+  }
+
+  LayoutScrollbarPart* horizontal_track_ = nullptr;
+  LayoutScrollbarPart* vertical_track_ = nullptr;
+};
+
+INSTANTIATE_TEST_CASE_P(All, ScrollbarTrackMarginsTest, ::testing::Bool());
+
+TEST_P(ScrollbarTrackMarginsTest,
+       CustomScrollbarFractionalMarginsWillNotCauseDCHECKFailure) {
+  PrepareTest(R"CSS(
+    ::-webkit-scrollbar-track {
+      margin-left: 10.2px;
+      margin-top: 20.4px;
+      margin-right: 30.6px;
+      margin-bottom: 40.8px;
+    })CSS");
+
+  EXPECT_EQ(10, horizontal_track_->MarginLeft());
+  EXPECT_EQ(31, horizontal_track_->MarginRight());
+  EXPECT_EQ(20, vertical_track_->MarginTop());
+  EXPECT_EQ(41, vertical_track_->MarginBottom());
+}
+
+TEST_P(ScrollbarTrackMarginsTest,
+       CustomScrollbarScaledMarginsWillNotCauseDCHECKFailure) {
+  WebView().SetZoomFactorForDeviceScaleFactor(1.25f);
+
+  PrepareTest(R"CSS(
+    ::-webkit-scrollbar-track {
+      margin-left: 11px;
+      margin-top: 21px;
+      margin-right: 31px;
+      margin-bottom: 41px;
+    })CSS");
+
+  EXPECT_EQ(14, horizontal_track_->MarginLeft());
+  EXPECT_EQ(39, horizontal_track_->MarginRight());
+  EXPECT_EQ(26, vertical_track_->MarginTop());
+  EXPECT_EQ(51, vertical_track_->MarginBottom());
+}
+
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
index 137bd34..73ebbff 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
@@ -119,6 +119,7 @@
 
   // Compute box properties regardless of needs_box_fragment since close tag may
   // also set needs_box_fragment.
+  box->padding = item_result.padding;
   box->has_start_edge = item_result.has_edge;
   if (box->has_start_edge) {
     box->margin_inline_start = item_result.margins.inline_start;
@@ -241,6 +242,7 @@
   box_data_list_.push_back(
       BoxData{box->fragment_start, fragment_end, box->item, size});
   BoxData& box_data = box_data_list_.back();
+  box_data.padding = box->padding;
   if (box->has_start_edge) {
     box_data.has_line_left_edge = true;
     box_data.margin_line_left = box->margin_inline_start;
@@ -441,6 +443,7 @@
   size.inline_size += border_padding_line_left + border_padding_line_right;
   box.SetInlineSize(size.inline_size.ClampNegativeToZero());
   box.SetBlockSize(size.block_size);
+  box.SetPadding(padding);
 
   for (unsigned i = fragment_start; i < fragment_end; i++) {
     NGLineBoxFragmentBuilder::Child& child = (*line_box)[i];
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.h
index fa37027..8380241 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.h
@@ -58,6 +58,7 @@
   // is set.
   bool has_start_edge = false;
   bool has_end_edge = false;
+  NGBoxStrut padding;
   // |CreateBoxFragment()| needs margin, border+padding, and the sum of them.
   LayoutUnit margin_inline_start;
   LayoutUnit margin_inline_end;
@@ -180,6 +181,7 @@
 
     bool has_line_left_edge = false;
     bool has_line_right_edge = false;
+    NGBoxStrut padding;
     // |CreateBoxFragment()| needs margin, border+padding, and the sum of them.
     LayoutUnit margin_line_left;
     LayoutUnit margin_line_right;
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
index e47ead6..0e90fa75 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
@@ -47,8 +47,9 @@
   // NGLayoutResult for atomic inline items.
   scoped_refptr<NGLayoutResult> layout_result;
 
-  // Margins for atomic inline items and open/close tags.
+  // Margins and padding for atomic inline items and open/close tags.
   NGBoxStrut margins;
+  NGBoxStrut padding;
 
   // Borders/padding for open tags.
   LayoutUnit borders_paddings_block_start;
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
index e156753e..2e9df3c 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
@@ -574,6 +574,7 @@
   DCHECK(item.Style());
   item_result->margins =
       ComputeMarginsForVisualContainer(constraint_space_, *item.Style());
+  item_result->padding = ComputePadding(constraint_space_, *item.Style());
   item_result->inline_size += item_result->margins.InlineSum();
 
   line_.position += item_result->inline_size;
@@ -694,6 +695,7 @@
       (style.HasMargin() && item_result->has_edge)) {
     NGBoxStrut borders = ComputeBorders(constraint_space_, style);
     NGBoxStrut paddings = ComputePadding(constraint_space_, style);
+    item_result->padding = paddings;
     item_result->borders_paddings_block_start =
         borders.block_start + paddings.block_start;
     item_result->borders_paddings_block_end =
diff --git a/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc b/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc
index 8f37743..b3e3d92 100644
--- a/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc
+++ b/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc
@@ -106,6 +106,8 @@
 
   container_builder.SetInlineSize(containing_block_logical_width);
   container_builder.SetBlockSize(containing_block_logical_height);
+  container_builder.SetPadding(
+      ComputePadding(*constraint_space, *container_style));
 
   // Determine static position.
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index 6bc6fa3b..ff538d8 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -498,6 +498,7 @@
 
   container_builder_.SetEndMarginStrut(end_margin_strut);
   container_builder_.SetIntrinsicBlockSize(intrinsic_block_size_);
+  container_builder_.SetPadding(ComputePadding(ConstraintSpace(), Style()));
 
   // We only finalize for fragmentation if the fragment has a BFC offset. This
   // may occur with a zero block size fragment. We need to know the BFC offset
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
index bac71ad..317dc35 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
@@ -563,6 +563,7 @@
   builder.SetIsOldLayoutRoot();
   builder.SetInlineSize(box_size.inline_size);
   builder.SetBlockSize(box_size.block_size);
+  builder.SetPadding(ComputePadding(constraint_space, box_->StyleRef()));
 
   // For now we copy the exclusion space straight through, this is incorrect
   // but needed as not all elements which participate in a BFC are switched
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm.cc
index 933b688..ea7f111 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm.cc
@@ -187,6 +187,7 @@
   }
   container_builder_.SetInlineSize(border_box_size.inline_size);
   container_builder_.SetBlockSize(border_box_size.block_size);
+  container_builder_.SetPadding(ComputePadding(ConstraintSpace(), Style()));
 
   return container_builder_.ToBoxFragment();
 }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
index 71c5f2d2..ac8759b 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
@@ -51,6 +51,11 @@
   return *this;
 }
 
+NGFragmentBuilder& NGFragmentBuilder::SetPadding(const NGBoxStrut& padding) {
+  padding_ = padding;
+  return *this;
+}
+
 NGContainerFragmentBuilder& NGFragmentBuilder::AddChild(
     scoped_refptr<NGPhysicalFragment> child,
     const NGLogicalOffset& child_offset) {
@@ -268,6 +273,8 @@
   scoped_refptr<NGPhysicalBoxFragment> fragment =
       base::AdoptRef(new NGPhysicalBoxFragment(
           layout_object_, Style(), physical_size, children_,
+          padding_.ConvertToPhysical(GetWritingMode(), Direction())
+              .SnapToDevicePixels(),
           contents_visual_rect, baselines_, BoxType(), is_old_layout_root_,
           border_edges_.ToPhysical(GetWritingMode()), std::move(break_token)));
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
index d25e6247..96a113c6 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
@@ -6,6 +6,7 @@
 #define NGFragmentBuilder_h
 
 #include "core/layout/ng/geometry/ng_border_edges.h"
+#include "core/layout/ng/geometry/ng_box_strut.h"
 #include "core/layout/ng/geometry/ng_physical_offset_rect.h"
 #include "core/layout/ng/geometry/ng_physical_rect.h"
 #include "core/layout/ng/inline/ng_baseline.h"
@@ -44,6 +45,7 @@
   NGLogicalSize Size() const final { return {inline_size_, block_size_}; }
 
   NGFragmentBuilder& SetIntrinsicBlockSize(LayoutUnit);
+  NGFragmentBuilder& SetPadding(const NGBoxStrut&);
 
   using NGContainerFragmentBuilder::AddChild;
 
@@ -185,6 +187,7 @@
   LayoutObject* layout_object_;
 
   LayoutUnit intrinsic_block_size_;
+  NGBoxStrut padding_;
 
   NGPhysicalFragment::NGBoxType box_type_;
   bool is_old_layout_root_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_page_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_page_layout_algorithm.cc
index 476ad7f..262e2a6 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_page_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_page_layout_algorithm.cc
@@ -72,6 +72,7 @@
   border_box_size.block_size = ComputeBlockSizeForFragment(
       ConstraintSpace(), Style(), intrinsic_block_size);
   container_builder_.SetBlockSize(border_box_size.block_size);
+  container_builder_.SetPadding(ComputePadding(ConstraintSpace(), Style()));
 
   NGOutOfFlowLayoutPart(&container_builder_, Node().IsAbsoluteContainer(),
                         Node().IsFixedContainer(), Node().GetScrollbarSizes(),
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
index f9b2dbf..0e2c06e4 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
@@ -14,6 +14,7 @@
     const ComputedStyle& style,
     NGPhysicalSize size,
     Vector<scoped_refptr<NGPhysicalFragment>>& children,
+    const NGPixelSnappedPhysicalBoxStrut& padding,
     const NGPhysicalOffsetRect& contents_visual_rect,
     Vector<NGBaseline>& baselines,
     NGBoxType box_type,
@@ -27,7 +28,8 @@
                                   children,
                                   contents_visual_rect,
                                   std::move(break_token)),
-      baselines_(std::move(baselines)) {
+      baselines_(std::move(baselines)),
+      padding_(padding) {
   DCHECK(baselines.IsEmpty());  // Ensure move semantics is used.
   box_type_ = box_type;
   is_old_layout_root_ = is_old_layout_root;
@@ -105,9 +107,9 @@
   Vector<NGBaseline> baselines_copy(baselines_);
   scoped_refptr<NGPhysicalFragment> physical_fragment =
       base::AdoptRef(new NGPhysicalBoxFragment(
-          layout_object_, Style(), size_, children_copy, contents_visual_rect_,
-          baselines_copy, BoxType(), is_old_layout_root_, border_edge_,
-          break_token_));
+          layout_object_, Style(), size_, children_copy, padding_,
+          contents_visual_rect_, baselines_copy, BoxType(), is_old_layout_root_,
+          border_edge_, break_token_));
   return physical_fragment;
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
index 8cd7064..501e4ad 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
@@ -6,6 +6,7 @@
 #define NGPhysicalBoxFragment_h
 
 #include "core/CoreExport.h"
+#include "core/layout/ng/geometry/ng_box_strut.h"
 #include "core/layout/ng/inline/ng_baseline.h"
 #include "core/layout/ng/ng_physical_container_fragment.h"
 
@@ -19,6 +20,7 @@
                         const ComputedStyle& style,
                         NGPhysicalSize size,
                         Vector<scoped_refptr<NGPhysicalFragment>>& children,
+                        const NGPixelSnappedPhysicalBoxStrut& padding,
                         const NGPhysicalOffsetRect& contents_visual_rect,
                         Vector<NGBaseline>& baselines,
                         NGBoxType box_type,
@@ -28,6 +30,8 @@
 
   const NGBaseline* Baseline(const NGBaselineRequest&) const;
 
+  const NGPixelSnappedPhysicalBoxStrut& Padding() const { return padding_; }
+
   bool HasSelfPaintingLayer() const;
   bool ChildrenInline() const;
 
@@ -47,6 +51,7 @@
 
  private:
   Vector<NGBaseline> baselines_;
+  NGPixelSnappedPhysicalBoxStrut padding_;
 };
 
 DEFINE_TYPE_CASTS(NGPhysicalBoxFragment,
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
index 71b6cd3..e9243c8 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
@@ -27,17 +27,22 @@
 
 namespace blink {
 
-static inline SVGTreeScopeResources& SvgTreeScopeResourcesFromElement(
-    Element* element) {
-  DCHECK(element);
-  return element->GetTreeScope().EnsureSVGTreeScopedResources();
+namespace {
+
+SVGTreeScopeResources::Resource* ResourceForContainer(
+    const LayoutSVGResourceContainer& resource_container) {
+  const SVGElement& element = *resource_container.GetElement();
+  return element.GetTreeScope()
+      .EnsureSVGTreeScopedResources()
+      .ExistingResourceForId(element.GetIdAttribute());
 }
 
+}  // namespace
+
 LayoutSVGResourceContainer::LayoutSVGResourceContainer(SVGElement* node)
     : LayoutSVGHiddenContainer(node),
       is_in_layout_(false),
       invalidation_mask_(0),
-      registered_(false),
       is_invalidating_(false) {}
 
 LayoutSVGResourceContainer::~LayoutSVGResourceContainer() = default;
@@ -68,45 +73,42 @@
 
 void LayoutSVGResourceContainer::WillBeDestroyed() {
   LayoutSVGHiddenContainer::WillBeDestroyed();
-  SvgTreeScopeResourcesFromElement(GetElement())
-      .RemoveResource(GetElement()->GetIdAttribute(), this);
-  DCHECK(clients_.IsEmpty());
+  // The resource is being torn down. If we have any clients, move those to be
+  // pending on the resource (if one exists.)
+  if (SVGTreeScopeResources::Resource* resource = ResourceForContainer(*this))
+    MakeClientsPending(*resource);
 }
 
 void LayoutSVGResourceContainer::StyleDidChange(
     StyleDifference diff,
     const ComputedStyle* old_style) {
   LayoutSVGHiddenContainer::StyleDidChange(diff, old_style);
-  SvgTreeScopeResourcesFromElement(GetElement())
-      .UpdateResource(GetElement()->GetIdAttribute(), this);
+  // The resource has (read: may have) been attached. Notify any pending
+  // clients that they can now try to add themselves as clients to the
+  // resource.
+  if (SVGTreeScopeResources::Resource* resource = ResourceForContainer(*this)) {
+    if (resource->Target() == GetElement())
+      resource->NotifyResourceClients();
+  }
 }
 
-void LayoutSVGResourceContainer::DetachAllClients(const AtomicString& to_id) {
+void LayoutSVGResourceContainer::MakeClientsPending(
+    SVGTreeScopeResources::Resource& resource) {
   RemoveAllClientsFromCache();
 
   for (auto* client : clients_) {
-    // Unlink the resource from the client's SVGResources. (The actual
-    // removal will be signaled after processing all the clients.)
+    // Unlink the resource from the client's SVGResources.
     SVGResources* resources =
         SVGResourcesCache::CachedResourcesForLayoutObject(client);
     // Or else the client wouldn't be in the list in the first place.
     DCHECK(resources);
     resources->ResourceDestroyed(this);
 
-    // Add a pending resolution based on the id of the old resource.
-    Element* client_element = ToElement(client->GetNode());
-    SvgTreeScopeResourcesFromElement(client_element)
-        .AddPendingResource(to_id, *client_element);
+    resource.AddWatch(ToSVGElement(*client->GetNode()));
   }
   clients_.clear();
 }
 
-void LayoutSVGResourceContainer::IdChanged(const AtomicString& old_id,
-                                           const AtomicString& new_id) {
-  SvgTreeScopeResourcesFromElement(GetElement())
-      .UpdateResource(old_id, new_id, this);
-}
-
 void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
     InvalidationMode mode) {
   if (is_invalidating_)
@@ -177,10 +179,11 @@
   ClearInvalidationMask();
 }
 
-void LayoutSVGResourceContainer::RemoveClient(LayoutObject* client) {
+bool LayoutSVGResourceContainer::RemoveClient(LayoutObject* client) {
   DCHECK(client);
   RemoveClientFromCache(client, false);
   clients_.erase(client);
+  return clients_.IsEmpty();
 }
 
 void LayoutSVGResourceContainer::InvalidateCacheAndMarkForLayout(
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h
index 86f9b41..052a2ca5 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h
@@ -21,6 +21,7 @@
 #define LayoutSVGResourceContainer_h
 
 #include "core/layout/svg/LayoutSVGHiddenContainer.h"
+#include "core/svg/SVGTreeScopeResources.h"
 
 namespace blink {
 
@@ -61,8 +62,10 @@
            resource_type == kRadialGradientResourceType;
   }
 
-  void IdChanged(const AtomicString& old_id, const AtomicString& new_id);
-  void DetachAllClients(const AtomicString& to_id);
+  // Detach all clients from this resource, and add them as watches to the tree
+  // scope's resource entry (the argument.)
+  void MakeClientsPending(SVGTreeScopeResources::Resource&);
+  bool HasClients() const { return !clients_.IsEmpty(); }
 
   void InvalidateCacheAndMarkForLayout(SubtreeLayoutScope* = nullptr);
 
@@ -94,23 +97,16 @@
   bool is_in_layout_;
 
  private:
-  friend class SVGTreeScopeResources;
-  // The m_registered flag is updated by SVGTreeScopeResources, and indicates
-  // that this resource is the one that is resident in the id->resource map.
-  void SetRegistered(bool registered) { registered_ = registered; }
-  bool IsRegistered() const { return registered_; }
-
   friend class SVGResourcesCache;
   void AddClient(LayoutObject*);
-  void RemoveClient(LayoutObject*);
+  bool RemoveClient(LayoutObject*);
 
-  // Track global (markAllClientsForInvalidation) invals to avoid redundant
-  // crawls.
+  // Track global (markAllClientsForInvalidation) invalidations to avoid
+  // redundant crawls.
   unsigned invalidation_mask_ : 8;
 
-  unsigned registered_ : 1;
   unsigned is_invalidating_ : 1;
-  // 22 padding bits available
+  // 23 padding bits available
 
   HashSet<LayoutObject*> clients_;
 };
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGResources.cpp b/third_party/WebKit/Source/core/layout/svg/SVGResources.cpp
index 5b0172de..ec442220 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGResources.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/SVGResources.cpp
@@ -157,12 +157,15 @@
 ContainerType* AttachToResource(SVGTreeScopeResources& tree_scope_resources,
                                 const AtomicString& id,
                                 SVGElement& element) {
-  if (LayoutSVGResourceContainer* container =
-          tree_scope_resources.ResourceById(id)) {
+  SVGTreeScopeResources::Resource* resource =
+      tree_scope_resources.ResourceForId(id);
+  if (!resource)
+    return nullptr;
+  if (LayoutSVGResourceContainer* container = resource->ResourceContainer()) {
     if (IsResourceOfType<ContainerType>(container))
       return static_cast<ContainerType*>(container);
   }
-  tree_scope_resources.AddPendingResource(id, element);
+  resource->AddWatch(element);
   return nullptr;
 }
 }
@@ -279,6 +282,22 @@
                                                        : std::move(resources);
 }
 
+void SVGResources::RemoveUnreferencedResources(const LayoutObject& object) {
+  SVGTreeScopeResources& tree_scope_resources =
+      ToSVGElement(*object.GetNode())
+          .TreeScopeForIdResolution()
+          .EnsureSVGTreeScopedResources();
+  tree_scope_resources.RemoveUnreferencedResources();
+}
+
+void SVGResources::RemoveWatchesForElement(Element& element) {
+  SECURITY_DCHECK(element.IsSVGElement());
+  SVGElement& svg_element = ToSVGElement(element);
+  SVGTreeScopeResources& tree_scope_resources =
+      svg_element.TreeScopeForIdResolution().EnsureSVGTreeScopedResources();
+  tree_scope_resources.RemoveWatchesForElement(svg_element);
+}
+
 void SVGResources::LayoutIfNeeded() {
   if (clipper_filter_masker_data_) {
     if (LayoutSVGResourceClipper* clipper =
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGResources.h b/third_party/WebKit/Source/core/layout/svg/SVGResources.h
index b8b275e..635c5515 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGResources.h
+++ b/third_party/WebKit/Source/core/layout/svg/SVGResources.h
@@ -29,6 +29,7 @@
 namespace blink {
 
 class ComputedStyle;
+class Element;
 class LayoutObject;
 class LayoutSVGResourceClipper;
 class LayoutSVGResourceContainer;
@@ -47,6 +48,10 @@
 
   static std::unique_ptr<SVGResources> BuildResources(const LayoutObject*,
                                                       const ComputedStyle&);
+
+  static void RemoveWatchesForElement(Element&);
+  static void RemoveUnreferencedResources(const LayoutObject&);
+
   void LayoutIfNeeded();
 
   static bool SupportsMarkers(const SVGElement&);
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGResourcesCache.cpp b/third_party/WebKit/Source/core/layout/svg/SVGResourcesCache.cpp
index 9dd812a..ea821c63 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGResourcesCache.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/SVGResourcesCache.cpp
@@ -76,8 +76,13 @@
   HashSet<LayoutSVGResourceContainer*> resource_set;
   resources->BuildSetOfResources(resource_set);
 
+  bool did_empty_client_set = false;
   for (auto* resource_container : resource_set)
-    resource_container->RemoveClient(object);
+    did_empty_client_set |= resource_container->RemoveClient(object);
+
+  // Remove any registrations that became empty after the above.
+  if (did_empty_client_set)
+    SVGResources::RemoveUnreferencedResources(*object);
 }
 
 static inline SVGResourcesCache& ResourcesCache(Document& document) {
@@ -156,6 +161,26 @@
       layout_object, needs_layout);
 }
 
+void SVGResourcesCache::ResourceReferenceChanged(LayoutObject& layout_object) {
+  DCHECK(layout_object.IsSVG());
+  DCHECK(layout_object.GetNode());
+  DCHECK(layout_object.GetNode()->IsSVGElement());
+
+  if (!layout_object.Parent())
+    return;
+
+  // Only LayoutObjects that can actually have resources should be pending and
+  // hence be able to call this method.
+  DCHECK(LayoutObjectCanHaveResources(&layout_object));
+
+  SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument());
+  cache.RemoveResourcesFromLayoutObject(&layout_object);
+  cache.AddResourcesFromLayoutObject(&layout_object, layout_object.StyleRef());
+
+  LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
+      &layout_object, true);
+}
+
 void SVGResourcesCache::ClientWasAddedToTree(LayoutObject* layout_object,
                                              const ComputedStyle& new_style) {
   if (!layout_object->GetNode())
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGResourcesCache.h b/third_party/WebKit/Source/core/layout/svg/SVGResourcesCache.h
index ca5f5ef..d462dd5 100644
--- a/third_party/WebKit/Source/core/layout/svg/SVGResourcesCache.h
+++ b/third_party/WebKit/Source/core/layout/svg/SVGResourcesCache.h
@@ -30,7 +30,6 @@
 
 class LayoutObject;
 class ComputedStyle;
-class LayoutSVGResourceContainer;
 class SVGResources;
 
 class SVGResourcesCache {
@@ -61,6 +60,10 @@
                                  StyleDifference,
                                  const ComputedStyle& new_style);
 
+  // Called when the target element of a resource referenced by the
+  // LayoutObject may have changed.
+  static void ResourceReferenceChanged(LayoutObject&);
+
   class TemporaryStyleScope {
     STACK_ALLOCATED();
 
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
index b802b35..8fceeb55 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
@@ -8,10 +8,12 @@
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
 #include "core/frame/LocalFrameView.h"
+#include "core/fullscreen/DocumentFullscreen.h"
 #include "core/html/HTMLFrameOwnerElement.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/LayoutEmbeddedContent.h"
 #include "core/layout/LayoutView.h"
+#include "core/page/ChromeClient.h"
 #include "core/page/Page.h"
 #include "core/page/scrolling/RootScrollerUtil.h"
 #include "core/page/scrolling/TopDocumentRootScrollerController.h"
@@ -46,7 +48,7 @@
   LayoutRect bounding_box(quads[0].BoundingBox());
 
   return bounding_box.Location() == LayoutPoint::Zero() &&
-         bounding_box.Size() == top_document.GetLayoutView()->Size();
+         bounding_box.Size() == top_document.GetLayoutView()->GetLayoutSize();
 }
 
 }  // namespace
@@ -59,12 +61,15 @@
 RootScrollerController::RootScrollerController(Document& document)
     : document_(&document),
       effective_root_scroller_(&document),
-      document_has_document_element_(false) {}
+      document_has_document_element_(false),
+      needs_apply_properties_(false) {}
 
 void RootScrollerController::Trace(blink::Visitor* visitor) {
   visitor->Trace(document_);
   visitor->Trace(root_scroller_);
   visitor->Trace(effective_root_scroller_);
+  visitor->Trace(implicit_candidates_);
+  visitor->Trace(implicit_root_scroller_);
 }
 
 void RootScrollerController::Set(Element* new_root_scroller) {
@@ -104,13 +109,31 @@
   }
 }
 
+void RootScrollerController::DidUpdateIFrameFrameView(
+    HTMLFrameOwnerElement& element) {
+  if (&element != effective_root_scroller_.Get())
+    return;
+
+  // Make sure we do a layout so we try to recalculate the effective root
+  // scroller. Ensure properties are applied even if the effective root
+  // scroller doesn't change.
+  needs_apply_properties_ = true;
+  document_->GetFrame()->View()->SetNeedsLayout();
+}
+
 void RootScrollerController::RecomputeEffectiveRootScroller() {
-  bool root_scroller_valid =
-      root_scroller_ && IsValidRootScroller(*root_scroller_);
+  ProcessImplicitCandidates();
 
   Node* new_effective_root_scroller = document_;
-  if (root_scroller_valid)
-    new_effective_root_scroller = root_scroller_;
+
+  if (!DocumentFullscreen::fullscreenElement(*document_)) {
+    bool root_scroller_valid =
+        root_scroller_ && IsValidRootScroller(*root_scroller_);
+    if (root_scroller_valid)
+      new_effective_root_scroller = root_scroller_;
+    else if (implicit_root_scroller_)
+      new_effective_root_scroller = implicit_root_scroller_;
+  }
 
   // TODO(bokan): This is a terrible hack but required because the viewport
   // apply scroll works on Elements rather than Nodes. If we're going from
@@ -123,8 +146,12 @@
   document_has_document_element_ = document_->documentElement();
 
   if (old_has_document_element || !document_has_document_element_) {
-    if (effective_root_scroller_ == new_effective_root_scroller)
+    if (effective_root_scroller_ == new_effective_root_scroller) {
+      if (needs_apply_properties_)
+        ApplyRootScrollerProperties(*effective_root_scroller_);
+
       return;
+    }
   }
 
   Node* old_effective_root_scroller = effective_root_scroller_;
@@ -144,20 +171,51 @@
   if (!element.GetLayoutObject())
     return false;
 
+  // Ignore anything inside a FlowThread (multi-col, paginated, etc.).
+  if (element.GetLayoutObject()->IsInsideFlowThread())
+    return false;
+
   if (!element.GetLayoutObject()->HasOverflowClip() &&
       !element.IsFrameOwnerElement())
     return false;
 
+  if (element.IsFrameOwnerElement() &&
+      !ToHTMLFrameOwnerElement(&element)->OwnedEmbeddedContentView())
+    return false;
+
   if (!FillsViewport(element))
     return false;
 
   return true;
 }
 
-void RootScrollerController::ApplyRootScrollerProperties(Node& node) const {
+bool RootScrollerController::IsValidImplicit(const Element& element) const {
+  // Valid implicit root scroller are a subset of valid root scrollers.
+  if (!IsValidRootScroller(element))
+    return false;
+
+  // Valid iframes can always be implicitly promoted.
+  if (element.IsFrameOwnerElement())
+    return true;
+
+  const ComputedStyle* style = element.GetLayoutObject()->Style();
+  if (!style)
+    return false;
+
+  // Regular Elements must have overflow: auto or scroll.
+  return style->OverflowX() == EOverflow::kAuto ||
+         style->OverflowX() == EOverflow::kScroll ||
+         style->OverflowY() == EOverflow::kAuto ||
+         style->OverflowY() == EOverflow::kScroll;
+}
+
+void RootScrollerController::ApplyRootScrollerProperties(Node& node) {
   DCHECK(document_->GetFrame());
   DCHECK(document_->GetFrame()->View());
 
+  if (&node == effective_root_scroller_)
+    needs_apply_properties_ = false;
+
   // If the node has been removed from the Document, we shouldn't be touching
   // anything related to the Frame- or Layout- hierarchies.
   if (!node.IsInTreeScope())
@@ -169,7 +227,7 @@
 
     if (frame_owner->ContentFrame()->IsLocalFrame()) {
       LocalFrameView* frame_view =
-          ToLocalFrame(frame_owner->ContentFrame())->View();
+          ToLocalFrameView(frame_owner->OwnedEmbeddedContentView());
 
       bool is_root_scroller = &EffectiveRootScroller() == &node;
 
@@ -207,6 +265,41 @@
     child_view->SetLayoutSize(document_->GetFrame()->View()->GetLayoutSize());
 }
 
+void RootScrollerController::ProcessImplicitCandidates() {
+  if (!RuntimeEnabledFeatures::ImplicitRootScrollerEnabled())
+    return;
+
+  Element* highest_z_element = nullptr;
+  bool highest_is_ambiguous = false;
+
+  HeapHashSet<WeakMember<Element>> copy(implicit_candidates_);
+  for (auto& element : copy) {
+    if (!IsValidImplicit(*element)) {
+      implicit_candidates_.erase(element);
+      continue;
+    }
+
+    if (!highest_z_element) {
+      highest_z_element = element;
+    } else {
+      int element_z = element->GetLayoutObject()->Style()->ZIndex();
+      int highest_z = highest_z_element->GetLayoutObject()->Style()->ZIndex();
+
+      if (element_z > highest_z) {
+        highest_z_element = element;
+        highest_is_ambiguous = false;
+      } else if (element_z == highest_z) {
+        highest_is_ambiguous = true;
+      }
+    }
+  }
+
+  if (highest_is_ambiguous)
+    implicit_root_scroller_ = nullptr;
+  else
+    implicit_root_scroller_ = highest_z_element;
+}
+
 PaintLayer* RootScrollerController::RootScrollerPaintLayer() const {
   return RootScrollerUtil::PaintLayerForRootScroller(effective_root_scroller_);
 }
@@ -227,4 +320,19 @@
     page->GlobalRootScrollerController().DidChangeRootScroller();
 }
 
+void RootScrollerController::ConsiderForImplicit(Node& node) {
+  DCHECK(RuntimeEnabledFeatures::ImplicitRootScrollerEnabled());
+
+  if (!node.IsElementNode())
+    return;
+
+  if (!IsValidImplicit(ToElement(node)))
+    return;
+
+  if (document_->GetPage()->GetChromeClient().IsPopup())
+    return;
+
+  implicit_candidates_.insert(&ToElement(node));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.h b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.h
index 1989f67a..c8d68522 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.h
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.h
@@ -74,6 +74,11 @@
   // rely on DidUpdateLayout.
   void DidResizeFrameView();
 
+  // Called when an iframe in this document has an updated FrameView (e.g.
+  // FrameView removed, swapped, etc.) so that we can recompute the effective
+  // root scroller and set the appropriate properties on the view.
+  void DidUpdateIFrameFrameView(HTMLFrameOwnerElement&);
+
   // Returns the PaintLayer associated with the currently effective root
   // scroller.
   PaintLayer* RootScrollerPaintLayer() const;
@@ -87,6 +92,14 @@
 
   void ElementRemoved(const Element&);
 
+  // In the "implicit root scroller" mode, we might promote an element to
+  // become the effective root scroller even if the page doesn't set it as so
+  // to improve the user experience.  In this mode, as elements layout they'll
+  // call this method and, if they meet the root scroller restrictions, will be
+  // added to the implicit candidate set. After layout is done we'll go
+  // through that set and select the best candidate.
+  void ConsiderForImplicit(Node&);
+
  private:
   RootScrollerController(Document&);
 
@@ -98,12 +111,21 @@
   // effective root scroller.
   bool IsValidRootScroller(const Element&) const;
 
+  // Determines whether the given element meets the criteria to be implicitly
+  // set as the root scroller (in addition to being a valid root scroller).
+  bool IsValidImplicit(const Element&) const;
+
   // Set certain properties to the effective root scroller. Called when a Node
   // becomes or unbecomes the effective root scroller.
-  void ApplyRootScrollerProperties(Node&) const;
+  void ApplyRootScrollerProperties(Node&);
 
   void UpdateIFrameGeometryAndLayoutSize(HTMLFrameOwnerElement&) const;
 
+  // Called after layout, runs through implicit candidates, removing ones that
+  // are no longer meet the root scroller restrictions. Of the remaining ones,
+  // will choose the best and set it as the implicit_root_scroller_.
+  void ProcessImplicitCandidates();
+
   // The owning Document whose root scroller this object manages.
   WeakMember<Document> document_;
 
@@ -119,7 +141,19 @@
   // RootScrollerController.
   Member<Node> effective_root_scroller_;
 
+  // Candidate Elements that we should examine after layout to determine which
+  // should be root scroller. This is used when "implicit root scroller" is
+  // enabled, where a valid Element can become the root scroller without being
+  // explicitly set using document.setRootScroller.
+  HeapHashSet<WeakMember<Element>> implicit_candidates_;
+
+  WeakMember<Element> implicit_root_scroller_;
+
   bool document_has_document_element_;
+
+  // This flag is used to force applicationn of rootScroller properties even if
+  // the effective rootScroller doesn't change.
+  bool needs_apply_properties_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
index 8fa70b8..461080f3 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerTest.cpp
@@ -49,10 +49,12 @@
 class RootScrollerTest : public ::testing::Test,
                          public ::testing::WithParamInterface<bool>,
                          private ScopedRootLayerScrollingForTest,
+                         private ScopedImplicitRootScrollerForTest,
                          private ScopedSetRootScrollerForTest {
  public:
   RootScrollerTest()
       : ScopedRootLayerScrollingForTest(GetParam()),
+        ScopedImplicitRootScrollerForTest(false),
         ScopedSetRootScrollerForTest(true),
         base_url_("http://www.test.com/") {
     RegisterMockedHttpURLLoad("overflow-scrolling.html");
@@ -1177,9 +1179,12 @@
 
 class RootScrollerSimTest : public ::testing::WithParamInterface<bool>,
                             private ScopedRootLayerScrollingForTest,
+                            private ScopedImplicitRootScrollerForTest,
                             public SimTest {
  public:
-  RootScrollerSimTest() : ScopedRootLayerScrollingForTest(GetParam()) {}
+  RootScrollerSimTest()
+      : ScopedRootLayerScrollingForTest(GetParam()),
+        ScopedImplicitRootScrollerForTest(false) {}
 };
 
 INSTANTIATE_TEST_CASE_P(All, RootScrollerSimTest, ::testing::Bool());
@@ -1243,6 +1248,152 @@
   EXPECT_EQ(120, frame->DomWindow()->visualViewport()->pageTop());
 }
 
+// Tests basic implicit root scroller mode with a <div>.
+TEST_P(RootScrollerSimTest, ImplicitRootScroller) {
+  ScopedSetRootScrollerForTest disable_root_scroller(false);
+  ScopedImplicitRootScrollerForTest enable_implicit(true);
+
+  WebView().Resize(WebSize(800, 600));
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+          <!DOCTYPE html>
+          <style>
+            ::-webkit-scrollbar {
+              width: 0px;
+              height: 0px;
+            }
+            body, html {
+              width: 100%;
+              height: 100%;
+              margin: 0px;
+            }
+            #spacer {
+              width: 1000px;
+              height: 1000px;
+            }
+            #container {
+              width: 100%;
+              height: 100%;
+            }
+          </style>
+          <div id="container">
+            <div id="spacer"></div>
+          </div>
+      )HTML");
+  Compositor().BeginFrame();
+
+  ASSERT_EQ(&GetDocument(),
+            GetDocument().GetRootScrollerController().EffectiveRootScroller());
+  Element* container = GetDocument().getElementById("container");
+
+  // overflow: auto and overflow: scroll should cause a valid element to be
+  // promoted to root scroller. Otherwise, they shouldn't, even if they're
+  // otherwise a valid root scroller element.
+  std::vector<std::tuple<String, String, Node*>> test_cases = {
+      {"overflow", "hidden", &GetDocument()},
+      {"overflow", "auto", container},
+      {"overflow", "scroll", container},
+      {"overflow", "visible", &GetDocument()},
+      // Overflow: hidden in one axis forces the other axis to auto so it should
+      // be promoted.
+      {"overflow-x", "hidden", container},
+      {"overflow-x", "auto", container},
+      {"overflow-x", "scroll", container},
+      {"overflow-x", "visible", &GetDocument()},
+      {"overflow-y", "hidden", container},
+      {"overflow-y", "auto", container},
+      {"overflow-y", "scroll", container},
+      {"overflow-y", "visible", &GetDocument()}};
+
+  for (auto test_case : test_cases) {
+    String& style = std::get<0>(test_case);
+    String& style_val = std::get<1>(test_case);
+    Node* expected_root_scroller = std::get<2>(test_case);
+
+    container->style()->setProperty(&GetDocument(), style, style_val, String(),
+                                    ASSERT_NO_EXCEPTION);
+    Compositor().BeginFrame();
+    ASSERT_EQ(
+        expected_root_scroller,
+        GetDocument().GetRootScrollerController().EffectiveRootScroller());
+    container->style()->setProperty(&GetDocument(), std::get<0>(test_case),
+                                    String(), String(), ASSERT_NO_EXCEPTION);
+    Compositor().BeginFrame();
+    ASSERT_EQ(
+        &GetDocument(),
+        GetDocument().GetRootScrollerController().EffectiveRootScroller());
+  }
+
+  // Now remove the overflowing element and rerun the tests. There should be no
+  // difference based on the fact that the scroller has overflow or not.
+  Element* spacer = GetDocument().getElementById("spacer");
+  spacer->remove();
+
+  for (auto test_case : test_cases) {
+    String& style = std::get<0>(test_case);
+    String& style_val = std::get<1>(test_case);
+    Node* expected_root_scroller = std::get<2>(test_case);
+
+    container->style()->setProperty(&GetDocument(), style, style_val, String(),
+                                    ASSERT_NO_EXCEPTION);
+    Compositor().BeginFrame();
+    ASSERT_EQ(
+        expected_root_scroller,
+        GetDocument().GetRootScrollerController().EffectiveRootScroller());
+    container->style()->setProperty(&GetDocument(), std::get<0>(test_case),
+                                    String(), String(), ASSERT_NO_EXCEPTION);
+    Compositor().BeginFrame();
+    ASSERT_EQ(
+        &GetDocument(),
+        GetDocument().GetRootScrollerController().EffectiveRootScroller());
+  }
+}
+
+// Tests implicit root scroller mode for iframes.
+TEST_P(RootScrollerSimTest, ImplicitRootScrollerIframe) {
+  ScopedSetRootScrollerForTest disable_root_scroller(false);
+  ScopedImplicitRootScrollerForTest enable_implicit(true);
+
+  WebView().Resize(WebSize(800, 600));
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+          <!DOCTYPE html>
+          <style>
+            ::-webkit-scrollbar {
+              width: 0px;
+              height: 0px;
+            }
+            body, html {
+              width: 100%;
+              height: 100%;
+              margin: 0px;
+            }
+            iframe {
+              width: 100%;
+              height: 100%;
+              border: 0;
+            }
+          </style>
+          <iframe id="container"
+                  srcdoc="<!DOCTYPE html><style>html {height: 300%;}</style>">
+          </iframe>
+      )HTML");
+  Compositor().BeginFrame();
+
+  Element* container = GetDocument().getElementById("container");
+  ASSERT_EQ(container,
+            GetDocument().GetRootScrollerController().EffectiveRootScroller());
+
+  container->style()->setProperty(&GetDocument(), "height", "95%", String(),
+                                  ASSERT_NO_EXCEPTION);
+  Compositor().BeginFrame();
+
+  ASSERT_EQ(&GetDocument(),
+            GetDocument().GetRootScrollerController().EffectiveRootScroller());
+}
+
 class RootScrollerHitTest : public RootScrollerTest {
  public:
   void CheckHitTestAtBottomOfScreen() {
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.cpp
index 9d0039d..e90b3d9 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.cpp
@@ -105,6 +105,13 @@
   return &layer == root_scroller_layer;
 }
 
+bool IsGlobal(const Element* element) {
+  return element->GetDocument()
+             .GetPage()
+             ->GlobalRootScrollerController()
+             .GlobalRootScroller() == element;
+}
+
 }  // namespace RootScrollerUtil
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.h b/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.h
index c35766a..53ee86d6 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.h
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.h
@@ -7,6 +7,7 @@
 
 namespace blink {
 
+class Element;
 class LayoutBox;
 class Node;
 class PaintLayer;
@@ -32,6 +33,7 @@
 
 bool IsGlobal(const LayoutBox&);
 bool IsGlobal(const PaintLayer&);
+bool IsGlobal(const Element*);
 
 }  // namespace RootScrollerUtil
 
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollCustomizationCallbacks.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollCustomizationCallbacks.cpp
index 591894f..d46d3f4 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollCustomizationCallbacks.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollCustomizationCallbacks.cpp
@@ -40,4 +40,15 @@
   return it->value.Get();
 }
 
+bool ScrollCustomizationCallbacks::InScrollPhase(Element* element) const {
+  return in_scrolling_phase_.Contains(element) &&
+         in_scrolling_phase_.at(element);
+}
+
+void ScrollCustomizationCallbacks::SetInScrollPhase(Element* element,
+                                                    bool value) {
+  DCHECK(element);
+  in_scrolling_phase_.Set(element, value);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollCustomizationCallbacks.h b/third_party/WebKit/Source/core/page/scrolling/ScrollCustomizationCallbacks.h
index 7a6bc643f..ced35257 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollCustomizationCallbacks.h
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollCustomizationCallbacks.h
@@ -24,10 +24,13 @@
   void SetApplyScroll(Element*, ScrollStateCallback*);
   void RemoveApplyScroll(Element*);
   ScrollStateCallback* GetApplyScroll(Element*);
+  bool InScrollPhase(Element*) const;
+  void SetInScrollPhase(Element*, bool);
 
   void Trace(blink::Visitor* visitor) {
     visitor->Trace(apply_scroll_callbacks_);
     visitor->Trace(distribute_scroll_callbacks_);
+    visitor->Trace(in_scrolling_phase_);
   };
 
  private:
@@ -35,6 +38,8 @@
       HeapHashMap<WeakMember<Element>, Member<ScrollStateCallback>>;
   ScrollStateCallbackList apply_scroll_callbacks_;
   ScrollStateCallbackList distribute_scroll_callbacks_;
+  HeapHashMap<WeakMember<Element>, bool> in_scrolling_phase_;
+
   DISALLOW_COPY_AND_ASSIGN(ScrollCustomizationCallbacks);
 };
 
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollState.h b/third_party/WebKit/Source/core/page/scrolling/ScrollState.h
index 5367640..93eb4b2d4 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollState.h
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollState.h
@@ -63,6 +63,14 @@
   // True if this scroll is the result of the user interacting directly with
   // the screen, e.g., via touch.
   bool isDirectManipulation() const { return data_->is_direct_manipulation; }
+  // When gesture begins it equals deltaXHint(). Otherwise, it returns deltaX().
+  double effectiveDeltaX() const {
+    return data_->is_beginning ? data_->delta_x_hint : data_->delta_x;
+  }
+  // When gesture begins it equals deltaYHint(). Otherwise, it returns deltaY().
+  double effectiveDeltaY() const {
+    return data_->is_beginning ? data_->delta_y_hint : data_->delta_y;
+  }
 
   // Non web exposed methods.
   void ConsumeDeltaNative(double x, double y);
diff --git a/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp b/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp
index a51ef7e..43e36ba 100644
--- a/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp
@@ -107,7 +107,13 @@
   return element;
 }
 
-void SetNeedsCompositingUpdateOnAncestors(ScrollableArea* area) {
+void SetNeedsCompositingUpdateOnAncestors(Element* element) {
+  if (!element || !element->GetDocument().IsActive())
+    return;
+
+  ScrollableArea* area =
+      RootScrollerUtil::ScrollableAreaForRootScroller(element);
+
   if (!area || !area->Layer())
     return;
 
@@ -117,7 +123,6 @@
       continue;
 
     LayoutView* layout_view = ToLocalFrame(frame)->View()->GetLayoutView();
-
     if (RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
       PaintLayer* frame_root_layer = layout_view->Layer();
       DCHECK(frame_root_layer);
@@ -153,8 +158,7 @@
   // scrolling the element so it will apply scroll to the element itself.
   target->setApplyScroll(viewport_apply_scroll_, "disable-native-scroll");
 
-  ScrollableArea* old_root_scroller_area =
-      RootScrollerUtil::ScrollableAreaForRootScroller(global_root_scroller_);
+  Element* old_root_scroller = global_root_scroller_;
 
   global_root_scroller_ = target;
 
@@ -165,11 +169,14 @@
   // in RootFrameViewport.
   viewport_apply_scroll_->SetScroller(target_scroller);
 
-  SetNeedsCompositingUpdateOnAncestors(old_root_scroller_area);
-  SetNeedsCompositingUpdateOnAncestors(target_scroller);
+  SetNeedsCompositingUpdateOnAncestors(old_root_scroller);
+  SetNeedsCompositingUpdateOnAncestors(target);
 
-  if (old_root_scroller_area)
-    old_root_scroller_area->DidChangeGlobalRootScroller();
+  if (ScrollableArea* area =
+          RootScrollerUtil::ScrollableAreaForRootScroller(old_root_scroller)) {
+    if (old_root_scroller->GetDocument().IsActive())
+      area->DidChangeGlobalRootScroller();
+  }
 
   target_scroller->DidChangeGlobalRootScroller();
 }
diff --git a/third_party/WebKit/Source/core/paint/ng/ng_box_fragment_painter.cc b/third_party/WebKit/Source/core/paint/ng/ng_box_fragment_painter.cc
index c92e6520..ed571a5 100644
--- a/third_party/WebKit/Source/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/WebKit/Source/core/paint/ng/ng_box_fragment_painter.cc
@@ -50,7 +50,8 @@
           box.Style(),
           box.GetLayoutObject()->GeneratingNode(),
           BoxStrutToLayoutRectOutsets(box.PhysicalFragment().BorderWidths()),
-          LayoutRectOutsets()),
+          BoxStrutToLayoutRectOutsets(
+              ToNGPhysicalBoxFragment(box.PhysicalFragment()).Padding())),
       box_fragment_(box),
       border_edges_(
           NGBorderEdges::FromPhysical(box.PhysicalFragment().BorderEdges(),
diff --git a/third_party/WebKit/Source/core/svg/SVGClipPathElement.h b/third_party/WebKit/Source/core/svg/SVGClipPathElement.h
index 4d4792d2..3ba1bfe0 100644
--- a/third_party/WebKit/Source/core/svg/SVGClipPathElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGClipPathElement.h
@@ -46,8 +46,6 @@
  private:
   explicit SVGClipPathElement(Document&);
 
-  bool NeedsPendingResourceHandling() const override { return false; }
-
   void SvgAttributeChanged(const QualifiedName&) override;
   void ChildrenChanged(const ChildrenChange&) override;
 
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp
index 5142774..c76781d5 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -49,7 +49,6 @@
 #include "core/svg/SVGGraphicsElement.h"
 #include "core/svg/SVGSVGElement.h"
 #include "core/svg/SVGTitleElement.h"
-#include "core/svg/SVGTreeScopeResources.h"
 #include "core/svg/SVGUseElement.h"
 #include "core/svg/properties/SVGProperty.h"
 #include "core/svg_names.h"
@@ -111,13 +110,6 @@
     SvgRareData()->SetNeedsOverrideComputedStyleUpdate();
 }
 
-void SVGElement::BuildPendingResourcesIfNeeded() {
-  if (!NeedsPendingResourceHandling() || !isConnected() || InUseShadowTree())
-    return;
-  GetTreeScope().EnsureSVGTreeScopedResources().NotifyResourceAvailable(
-      GetIdAttribute());
-}
-
 SVGElementRareData* SVGElement::EnsureSVGRareData() {
   if (!svg_rare_data_)
     svg_rare_data_ = new SVGElementRareData();
@@ -393,7 +385,6 @@
     ContainerNode* root_parent) {
   Element::InsertedInto(root_parent);
   UpdateRelativeLengthsInformation();
-  BuildPendingResourcesIfNeeded();
 
   const AtomicString& nonce_value = FastGetAttribute(nonceAttr);
   if (!nonce_value.IsEmpty()) {
@@ -403,7 +394,6 @@
       setAttribute(nonceAttr, g_empty_atom);
     }
   }
-
   return kInsertionDone;
 }
 
@@ -962,16 +952,6 @@
 
   if (params.name == HTMLNames::idAttr) {
     RebuildAllIncomingReferences();
-
-    LayoutObject* object = GetLayoutObject();
-    // Notify resources about id changes, this is important as we cache
-    // resources by id in SVGDocumentExtensions
-    if (object && object->IsSVGResourceContainer()) {
-      ToLayoutSVGResourceContainer(object)->IdChanged(params.old_value,
-                                                      params.new_value);
-    }
-    if (isConnected())
-      BuildPendingResourcesIfNeeded();
     InvalidateInstances();
     return;
   }
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.h b/third_party/WebKit/Source/core/svg/SVGElement.h
index 1b54285c..1189d73f 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGElement.h
@@ -88,7 +88,6 @@
     kAncestorScope  // Used by SVGSVGElement::get{Enclosure|Intersection}List()
   };
   virtual AffineTransform LocalCoordinateSpaceTransform(CTMScope) const;
-  virtual bool NeedsPendingResourceHandling() const { return true; }
 
   bool InstanceUpdatesBlocked() const;
   void SetInstanceUpdatesBlocked(bool);
@@ -273,8 +272,6 @@
   }
   void WillRecalcStyle(StyleRecalcChange) override;
 
-  void BuildPendingResourcesIfNeeded();
-
   HeapHashSet<WeakMember<SVGElement>> elements_with_relative_lengths_;
 
   typedef HeapHashMap<QualifiedName, Member<SVGAnimatedPropertyBase>>
diff --git a/third_party/WebKit/Source/core/svg/SVGFilterElement.h b/third_party/WebKit/Source/core/svg/SVGFilterElement.h
index 33b152e..c2e7f2b2 100644
--- a/third_party/WebKit/Source/core/svg/SVGFilterElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGFilterElement.h
@@ -67,8 +67,6 @@
  private:
   explicit SVGFilterElement(Document&);
 
-  bool NeedsPendingResourceHandling() const override { return false; }
-
   void SvgAttributeChanged(const QualifiedName&) override;
   void ChildrenChanged(const ChildrenChange&) override;
 
diff --git a/third_party/WebKit/Source/core/svg/SVGGradientElement.h b/third_party/WebKit/Source/core/svg/SVGGradientElement.h
index 921971bd..6858372 100644
--- a/third_party/WebKit/Source/core/svg/SVGGradientElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGGradientElement.h
@@ -72,8 +72,6 @@
   void SvgAttributeChanged(const QualifiedName&) override;
 
  private:
-  bool NeedsPendingResourceHandling() const final { return false; }
-
   void CollectStyleForPresentationAttribute(
       const QualifiedName&,
       const AtomicString&,
diff --git a/third_party/WebKit/Source/core/svg/SVGMarkerElement.h b/third_party/WebKit/Source/core/svg/SVGMarkerElement.h
index 4ae4380..b6f6f7c3 100644
--- a/third_party/WebKit/Source/core/svg/SVGMarkerElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGMarkerElement.h
@@ -82,8 +82,6 @@
  private:
   explicit SVGMarkerElement(Document&);
 
-  bool NeedsPendingResourceHandling() const override { return false; }
-
   void SvgAttributeChanged(const QualifiedName&) override;
   void ChildrenChanged(const ChildrenChange&) override;
 
diff --git a/third_party/WebKit/Source/core/svg/SVGMaskElement.h b/third_party/WebKit/Source/core/svg/SVGMaskElement.h
index d24e46a..6b38ca7e 100644
--- a/third_party/WebKit/Source/core/svg/SVGMaskElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGMaskElement.h
@@ -53,7 +53,6 @@
   explicit SVGMaskElement(Document&);
 
   bool IsValid() const override { return SVGTests::IsValid(); }
-  bool NeedsPendingResourceHandling() const override { return false; }
 
   void CollectStyleForPresentationAttribute(
       const QualifiedName&,
diff --git a/third_party/WebKit/Source/core/svg/SVGPatternElement.h b/third_party/WebKit/Source/core/svg/SVGPatternElement.h
index 6a6d0ba..1cd2a8e 100644
--- a/third_party/WebKit/Source/core/svg/SVGPatternElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGPatternElement.h
@@ -80,7 +80,6 @@
   explicit SVGPatternElement(Document&);
 
   bool IsValid() const override { return SVGTests::IsValid(); }
-  bool NeedsPendingResourceHandling() const override { return false; }
 
   void CollectStyleForPresentationAttribute(
       const QualifiedName&,
diff --git a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
index 0f780af..f1e5389 100644
--- a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
@@ -7,226 +7,133 @@
 #include "core/dom/Element.h"
 #include "core/dom/TreeScope.h"
 #include "core/layout/svg/LayoutSVGResourceContainer.h"
+#include "core/layout/svg/SVGResources.h"
 #include "core/layout/svg/SVGResourcesCache.h"
-#include "core/svg/SVGUseElement.h"
 #include "platform/wtf/text/AtomicString.h"
 
 namespace blink {
 
+SVGTreeScopeResources::Resource::Resource(TreeScope& tree_scope,
+                                          const AtomicString& id)
+    : IdTargetObserver(tree_scope.GetIdTargetObserverRegistry(), id),
+      tree_scope_(tree_scope),
+      target_(tree_scope.getElementById(id)) {}
+
+SVGTreeScopeResources::Resource::~Resource() = default;
+
+void SVGTreeScopeResources::Resource::Trace(Visitor* visitor) {
+  visitor->Trace(tree_scope_);
+  visitor->Trace(target_);
+  visitor->Trace(pending_clients_);
+  IdTargetObserver::Trace(visitor);
+}
+
+void SVGTreeScopeResources::Resource::AddWatch(SVGElement& element) {
+  pending_clients_.insert(&element);
+  element.SetHasPendingResources();
+}
+
+void SVGTreeScopeResources::Resource::RemoveWatch(SVGElement& element) {
+  pending_clients_.erase(&element);
+}
+
+bool SVGTreeScopeResources::Resource::IsEmpty() const {
+  LayoutSVGResourceContainer* container = ResourceContainer();
+  return (!container || !container->HasClients()) && pending_clients_.IsEmpty();
+}
+
+void SVGTreeScopeResources::Resource::NotifyResourceClients() {
+  HeapHashSet<Member<SVGElement>> pending_clients;
+  pending_clients.swap(pending_clients_);
+
+  for (SVGElement* client_element : pending_clients) {
+    if (LayoutObject* layout_object = client_element->GetLayoutObject())
+      SVGResourcesCache::ResourceReferenceChanged(*layout_object);
+  }
+}
+
+LayoutSVGResourceContainer* SVGTreeScopeResources::Resource::ResourceContainer()
+    const {
+  if (!target_)
+    return nullptr;
+  LayoutObject* layout_object = target_->GetLayoutObject();
+  if (!layout_object || !layout_object->IsSVGResourceContainer())
+    return nullptr;
+  return ToLayoutSVGResourceContainer(layout_object);
+}
+
+void SVGTreeScopeResources::Resource::IdTargetChanged() {
+  Element* new_target = tree_scope_->getElementById(Id());
+  if (new_target == target_)
+    return;
+  // Detach clients from the old resource, moving them to the pending list
+  // and then notify pending clients.
+  if (LayoutSVGResourceContainer* old_resource = ResourceContainer())
+    old_resource->MakeClientsPending(*this);
+  target_ = new_target;
+  NotifyResourceClients();
+}
+
 SVGTreeScopeResources::SVGTreeScopeResources(TreeScope* tree_scope)
     : tree_scope_(tree_scope) {}
 
 SVGTreeScopeResources::~SVGTreeScopeResources() = default;
 
-static LayoutSVGResourceContainer* LookupResource(TreeScope& tree_scope,
-                                                  const AtomicString& id) {
-  Element* element = tree_scope.getElementById(id);
-  if (!element)
+SVGTreeScopeResources::Resource* SVGTreeScopeResources::ResourceForId(
+    const AtomicString& id) {
+  if (id.IsEmpty())
     return nullptr;
-  LayoutObject* layout_object = element->GetLayoutObject();
-  if (!layout_object || !layout_object->IsSVGResourceContainer())
-    return nullptr;
-  return ToLayoutSVGResourceContainer(layout_object);
+  auto& entry = resources_.insert(id, nullptr).stored_value->value;
+  if (!entry)
+    entry = new Resource(*tree_scope_, id);
+  return entry;
 }
 
-void SVGTreeScopeResources::UpdateResource(
-    const AtomicString& id,
-    LayoutSVGResourceContainer* resource) {
-  DCHECK(resource);
-  if (resource->IsRegistered() || id.IsEmpty())
-    return;
-  // Lookup the current resource. (Could differ from what's in the map if an
-  // element was just added/removed.)
-  LayoutSVGResourceContainer* current_resource =
-      LookupResource(*tree_scope_, id);
-  // Lookup the currently registered resource.
-  auto it = resources_.find(id);
-  if (it != resources_.end()) {
-    // Is the local map up-to-date already?
-    if (it->value == current_resource)
-      return;
-    UnregisterResource(it);
-  }
-  if (current_resource)
-    RegisterResource(id, current_resource);
-}
-
-void SVGTreeScopeResources::UpdateResource(
-    const AtomicString& old_id,
-    const AtomicString& new_id,
-    LayoutSVGResourceContainer* resource) {
-  RemoveResource(old_id, resource);
-  UpdateResource(new_id, resource);
-}
-
-void SVGTreeScopeResources::RemoveResource(
-    const AtomicString& id,
-    LayoutSVGResourceContainer* resource) {
-  DCHECK(resource);
-  if (!resource->IsRegistered() || id.IsEmpty())
-    return;
-  auto it = resources_.find(id);
-  // If this is not the currently registered resource for this id, then do
-  // nothing.
-  if (it == resources_.end() || it->value != resource)
-    return;
-  UnregisterResource(it);
-  // If the layout tree is being torn down, then don't attempt to update the
-  // map, since that layout object is likely to be stale already.
-  if (resource->DocumentBeingDestroyed())
-    return;
-  // Another resource could now be current. Perform a lookup and potentially
-  // update the map.
-  LayoutSVGResourceContainer* current_resource =
-      LookupResource(*tree_scope_, id);
-  if (!current_resource)
-    return;
-  // Since this is a removal, don't allow re-adding the resource.
-  if (current_resource == resource)
-    return;
-  RegisterResource(id, current_resource);
-}
-
-void SVGTreeScopeResources::RegisterResource(
-    const AtomicString& id,
-    LayoutSVGResourceContainer* resource) {
-  DCHECK(!id.IsEmpty());
-  DCHECK(resource);
-  DCHECK(!resource->IsRegistered());
-
-  resources_.Set(id, resource);
-  resource->SetRegistered(true);
-
-  NotifyPendingClients(id);
-}
-
-void SVGTreeScopeResources::UnregisterResource(ResourceMap::iterator it) {
-  LayoutSVGResourceContainer* resource = it->value;
-  DCHECK(resource);
-  DCHECK(resource->IsRegistered());
-
-  resource->DetachAllClients(it->key);
-
-  resource->SetRegistered(false);
-  resources_.erase(it);
-}
-
-LayoutSVGResourceContainer* SVGTreeScopeResources::ResourceById(
+SVGTreeScopeResources::Resource* SVGTreeScopeResources::ExistingResourceForId(
     const AtomicString& id) const {
   if (id.IsEmpty())
     return nullptr;
   return resources_.at(id);
 }
 
-void SVGTreeScopeResources::AddPendingResource(const AtomicString& id,
-                                               Element& element) {
-  DCHECK(element.isConnected());
-
-  if (id.IsEmpty())
+void SVGTreeScopeResources::RemoveUnreferencedResources() {
+  if (resources_.IsEmpty())
     return;
-  auto result = pending_resources_.insert(id, nullptr);
-  if (result.is_new_entry)
-    result.stored_value->value = new SVGPendingElements;
-  result.stored_value->value->insert(&element);
-
-  element.SetHasPendingResources();
-}
-
-bool SVGTreeScopeResources::IsElementPendingResource(
-    Element& element,
-    const AtomicString& id) const {
-  if (id.IsEmpty())
-    return false;
-  const SVGPendingElements* pending_elements = pending_resources_.at(id);
-  return pending_elements && pending_elements->Contains(&element);
-}
-
-void SVGTreeScopeResources::ClearHasPendingResourcesIfPossible(
-    Element& element) {
-  // This algorithm takes time proportional to the number of pending resources
-  // and need not.
-  // If performance becomes an issue we can keep a counted set of elements and
-  // answer the question efficiently.
-  for (const auto& entry : pending_resources_) {
-    SVGPendingElements* elements = entry.value.Get();
-    DCHECK(elements);
-    if (elements->Contains(&element))
-      return;
+  // Remove resources that are no longer referenced.
+  Vector<AtomicString> to_be_removed;
+  for (const auto& entry : resources_) {
+    Resource* resource = entry.value.Get();
+    DCHECK(resource);
+    if (resource->IsEmpty()) {
+      resource->Unregister();
+      to_be_removed.push_back(entry.key);
+    }
   }
-  element.ClearHasPendingResources();
+  resources_.RemoveAll(to_be_removed);
 }
 
-void SVGTreeScopeResources::RemoveElementFromPendingResources(
-    Element& element) {
-  if (pending_resources_.IsEmpty() || !element.HasPendingResources())
+void SVGTreeScopeResources::RemoveWatchesForElement(SVGElement& element) {
+  if (resources_.IsEmpty() || !element.HasPendingResources())
     return;
   // Remove the element from pending resources.
   Vector<AtomicString> to_be_removed;
-  for (const auto& entry : pending_resources_) {
-    SVGPendingElements* elements = entry.value.Get();
-    DCHECK(elements);
-    DCHECK(!elements->IsEmpty());
-
-    elements->erase(&element);
-    if (elements->IsEmpty())
+  for (const auto& entry : resources_) {
+    Resource* resource = entry.value.Get();
+    DCHECK(resource);
+    resource->RemoveWatch(element);
+    if (resource->IsEmpty()) {
+      resource->Unregister();
       to_be_removed.push_back(entry.key);
+    }
   }
-  pending_resources_.RemoveAll(to_be_removed);
+  resources_.RemoveAll(to_be_removed);
 
-  ClearHasPendingResourcesIfPossible(element);
-}
-
-void SVGTreeScopeResources::NotifyPendingClients(const AtomicString& id) {
-  DCHECK(!id.IsEmpty());
-  SVGPendingElements* pending_elements = pending_resources_.Take(id);
-  if (!pending_elements)
-    return;
-  // Update cached resources of pending clients.
-  for (Element* client_element : *pending_elements) {
-    DCHECK(client_element->HasPendingResources());
-    ClearHasPendingResourcesIfPossible(*client_element);
-
-    LayoutObject* layout_object = client_element->GetLayoutObject();
-    if (!layout_object)
-      continue;
-    DCHECK(layout_object->IsSVG());
-
-    StyleDifference diff;
-    diff.SetNeedsFullLayout();
-    SVGResourcesCache::ClientStyleChanged(layout_object, diff,
-                                          layout_object->StyleRef());
-    layout_object->SetNeedsLayoutAndFullPaintInvalidation(
-        LayoutInvalidationReason::kSvgResourceInvalidated);
-  }
-}
-
-void SVGTreeScopeResources::NotifyResourceAvailable(const AtomicString& id) {
-  if (id.IsEmpty())
-    return;
-  // Get pending elements for this id.
-  SVGPendingElements* pending_elements = pending_resources_.Take(id);
-  if (!pending_elements)
-    return;
-  // Rebuild pending resources for each client of a pending resource that is
-  // being removed.
-  for (Element* client_element : *pending_elements) {
-    DCHECK(client_element->HasPendingResources());
-    if (!client_element->HasPendingResources())
-      continue;
-    // TODO(fs): Ideally we'd always resolve pending resources async instead of
-    // inside insertedInto and svgAttributeChanged. For now we only do it for
-    // <use> since that would stamp out DOM.
-    if (auto* use = ToSVGUseElementOrNull(client_element))
-      use->InvalidateShadowTree();
-    else
-      client_element->BuildPendingResource();
-
-    ClearHasPendingResourcesIfPossible(*client_element);
-  }
+  element.ClearHasPendingResources();
 }
 
 void SVGTreeScopeResources::Trace(blink::Visitor* visitor) {
-  visitor->Trace(pending_resources_);
+  visitor->Trace(resources_);
   visitor->Trace(tree_scope_);
 }
-}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h
index 3152958..7a2171f 100644
--- a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h
+++ b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h
@@ -6,6 +6,7 @@
 #define SVGTreeScopeResources_h
 
 #include "base/macros.h"
+#include "core/dom/IdTargetObserver.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/HashMap.h"
@@ -15,8 +16,9 @@
 namespace blink {
 
 class Element;
-class TreeScope;
 class LayoutSVGResourceContainer;
+class SVGElement;
+class TreeScope;
 
 // This class keeps track of SVG resources and pending references to such for a
 // TreeScope. It's per-TreeScope because that matches the lookup scope of an
@@ -27,36 +29,40 @@
   explicit SVGTreeScopeResources(TreeScope*);
   ~SVGTreeScopeResources();
 
-  void UpdateResource(const AtomicString& id, LayoutSVGResourceContainer*);
-  void UpdateResource(const AtomicString& old_id,
-                      const AtomicString& new_id,
-                      LayoutSVGResourceContainer*);
-  void RemoveResource(const AtomicString& id, LayoutSVGResourceContainer*);
-  LayoutSVGResourceContainer* ResourceById(const AtomicString& id) const;
+  class Resource : public IdTargetObserver {
+   public:
+    Resource(TreeScope&, const AtomicString& id);
+    ~Resource() override;
 
-  // Pending resources are such which are referenced by any object in the SVG
-  // document, but do NOT exist yet. For instance, dynamically built gradients
-  // / patterns / clippers...
-  void AddPendingResource(const AtomicString& id, Element&);
-  bool IsElementPendingResource(Element&, const AtomicString& id) const;
-  void NotifyResourceAvailable(const AtomicString& id);
-  void RemoveElementFromPendingResources(Element&);
+    Element* Target() const { return target_; }
+    LayoutSVGResourceContainer* ResourceContainer() const;
+
+    void AddWatch(SVGElement&);
+    void RemoveWatch(SVGElement&);
+
+    bool IsEmpty() const;
+
+    void Trace(blink::Visitor*);
+
+    void NotifyResourceClients();
+
+   private:
+    void IdTargetChanged() override;
+
+    Member<TreeScope> tree_scope_;
+    Member<Element> target_;
+    HeapHashSet<Member<SVGElement>> pending_clients_;
+  };
+  Resource* ResourceForId(const AtomicString& id);
+  Resource* ExistingResourceForId(const AtomicString& id) const;
+
+  void RemoveUnreferencedResources();
+  void RemoveWatchesForElement(SVGElement&);
 
   void Trace(blink::Visitor*);
 
  private:
-  void ClearHasPendingResourcesIfPossible(Element&);
-
-  using SVGPendingElements = HeapHashSet<Member<Element>>;
-  using ResourceMap = HashMap<AtomicString, LayoutSVGResourceContainer*>;
-
-  void RegisterResource(const AtomicString& id, LayoutSVGResourceContainer*);
-  void UnregisterResource(ResourceMap::iterator);
-  void NotifyPendingClients(const AtomicString& id);
-
-  ResourceMap resources_;
-  // Resources that are pending.
-  HeapHashMap<AtomicString, Member<SVGPendingElements>> pending_resources_;
+  HeapHashMap<AtomicString, Member<Resource>> resources_;
   Member<TreeScope> tree_scope_;
 
   DISALLOW_COPY_AND_ASSIGN(SVGTreeScopeResources);
diff --git a/third_party/WebKit/Source/core/svg/properties/SVGPropertyTearOff.h b/third_party/WebKit/Source/core/svg/properties/SVGPropertyTearOff.h
index 7b8f8dd0..28ce517 100644
--- a/third_party/WebKit/Source/core/svg/properties/SVGPropertyTearOff.h
+++ b/third_party/WebKit/Source/core/svg/properties/SVGPropertyTearOff.h
@@ -68,7 +68,7 @@
     context_element_ = context_element;
     // Requires SVGPropertyTearOffBase to be the left-most class in the
     // inheritance hierarchy.
-    ScriptWrappableVisitor::WriteBarrier(context_element_.Get());
+    ScriptWrappableMarkingVisitor::WriteBarrier(context_element_.Get());
     attribute_name_ = attribute_name;
   }
 
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 968faed5..447c306 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -114,6 +114,7 @@
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
 #include "core/page/PrintContext.h"
+#include "core/page/scrolling/RootScrollerController.h"
 #include "core/page/scrolling/ScrollState.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/compositing/CompositedLayerMapping.h"
@@ -749,6 +750,13 @@
   document_->GetPage()->GetChromeClient().SetBrowserControlsShownRatio(ratio);
 }
 
+Node* Internals::effectiveRootScroller(Document* document) {
+  if (!document)
+    document = document_;
+
+  return &document->GetRootScrollerController().EffectiveRootScroller();
+}
+
 ShadowRoot* Internals::shadowRoot(Element* host) {
   // FIXME: Internals::shadowRoot() in tests should be converted to
   // youngestShadowRoot() or oldestShadowRoot().
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h
index 08f8527..0277c953 100644
--- a/third_party/WebKit/Source/core/testing/Internals.h
+++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -110,6 +110,8 @@
                                bool shrinks_layout);
   void setBrowserControlsShownRatio(float);
 
+  Node* effectiveRootScroller(Document*);
+
   ShadowRoot* createUserAgentShadowRoot(Element* host);
 
   ShadowRoot* shadowRoot(Element* host);
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl
index a8c55ed..a05ada7f 100644
--- a/third_party/WebKit/Source/core/testing/Internals.idl
+++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -56,6 +56,8 @@
     void setBrowserControlsState(float top_height, float bottom_height, boolean shrinksLayout);
     void setBrowserControlsShownRatio(float ratio);
 
+    Node effectiveRootScroller(Document document);
+
     [RaisesException] DOMString shadowRootType(Node root);
     [RaisesException] boolean hasShadowInsertionPoint(Node root);
     [RaisesException] boolean hasContentElement(Node root);
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
index fcd96ed..9bea88a1 100644
--- a/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
+++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
@@ -30,7 +30,8 @@
   DedicatedWorkerThreadForTest(DedicatedWorkerObjectProxy& worker_object_proxy)
       : DedicatedWorkerThread(nullptr /* ThreadableLoadingContext */,
                               worker_object_proxy) {
-    worker_backing_thread_ = WorkerBackingThread::CreateForTest("Test thread");
+    worker_backing_thread_ = WorkerBackingThread::CreateForTest(
+        WebThreadCreationParams("Test thread"));
   }
 
   WorkerOrWorkletGlobalScope* CreateWorkerGlobalScope(
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp b/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp
index 639d9c08..ecd5eda 100644
--- a/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp
@@ -51,8 +51,8 @@
     ThreadableLoadingContext* loading_context,
     DedicatedWorkerObjectProxy& worker_object_proxy)
     : WorkerThread(loading_context, worker_object_proxy),
-      worker_backing_thread_(
-          WorkerBackingThread::Create("DedicatedWorker Thread")),
+      worker_backing_thread_(WorkerBackingThread::Create(
+          WebThreadCreationParams("DedicatedWorker Thread"))),
       worker_object_proxy_(worker_object_proxy) {}
 
 DedicatedWorkerThread::~DedicatedWorkerThread() = default;
diff --git a/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp b/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp
index f1962ee..7635fb1 100644
--- a/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp
@@ -43,8 +43,8 @@
     ThreadableLoadingContext* loading_context,
     WorkerReportingProxy& worker_reporting_proxy)
     : WorkerThread(loading_context, worker_reporting_proxy),
-      worker_backing_thread_(
-          WorkerBackingThread::Create("SharedWorker Thread")),
+      worker_backing_thread_(WorkerBackingThread::Create(
+          WebThreadCreationParams("SharedWorker Thread"))),
       name_(name.IsolatedCopy()) {}
 
 SharedWorkerThread::~SharedWorkerThread() = default;
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletTest.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorkletTest.cpp
index 14ef0deef..b782298 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletTest.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletTest.cpp
@@ -69,7 +69,7 @@
   static void EnsureSharedBackingThread() {
     DCHECK(IsMainThread());
     WorkletThreadHolder<ThreadedWorkletThreadForTest>::CreateForTest(
-        "ThreadedWorkletThreadForTest");
+        WebThreadCreationParams("ThreadedWorkletThreadForTest"));
   }
 
   static void ClearSharedBackingThread() {
diff --git a/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp b/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
index 82562c6..9519c79 100644
--- a/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
@@ -56,9 +56,9 @@
   Isolates().erase(isolate);
 }
 
-WorkerBackingThread::WorkerBackingThread(const char* name,
+WorkerBackingThread::WorkerBackingThread(const WebThreadCreationParams& params,
                                          bool should_call_gc_on_shutdown)
-    : backing_thread_(WebThreadSupportingGC::Create(name)),
+    : backing_thread_(WebThreadSupportingGC::Create(params)),
       is_owning_thread_(true),
       should_call_gc_on_shutdown_(should_call_gc_on_shutdown) {}
 
@@ -84,8 +84,8 @@
 
   ThreadState::Current()->RegisterTraceDOMWrappers(
       isolate_, V8GCController::TraceDOMWrappers,
-      ScriptWrappableVisitor::InvalidateDeadObjectsInMarkingDeque,
-      ScriptWrappableVisitor::PerformCleanup);
+      ScriptWrappableMarkingVisitor::InvalidateDeadObjectsInMarkingDeque,
+      ScriptWrappableMarkingVisitor::PerformCleanup);
   if (RuntimeEnabledFeatures::V8IdleTasksEnabled())
     V8PerIsolateData::EnableIdleTasks(
         isolate_, WTF::WrapUnique(new V8IdleTaskRunner(
diff --git a/third_party/WebKit/Source/core/workers/WorkerBackingThread.h b/third_party/WebKit/Source/core/workers/WorkerBackingThread.h
index 17c2776..7e36d18 100644
--- a/third_party/WebKit/Source/core/workers/WorkerBackingThread.h
+++ b/third_party/WebKit/Source/core/workers/WorkerBackingThread.h
@@ -26,8 +26,9 @@
 // ShutdownOnBackingThread() when it no longer needs the thread.
 class CORE_EXPORT WorkerBackingThread final {
  public:
-  static std::unique_ptr<WorkerBackingThread> Create(const char* name) {
-    return WTF::WrapUnique(new WorkerBackingThread(name, false));
+  static std::unique_ptr<WorkerBackingThread> Create(
+      const WebThreadCreationParams& params) {
+    return WTF::WrapUnique(new WorkerBackingThread(params, false));
   }
   static std::unique_ptr<WorkerBackingThread> Create(WebThread* thread) {
     return WTF::WrapUnique(new WorkerBackingThread(thread, false));
@@ -35,8 +36,9 @@
 
   // These are needed to suppress leak reports. See
   // https://crbug.com/590802 and https://crbug.com/v8/1428.
-  static std::unique_ptr<WorkerBackingThread> CreateForTest(const char* name) {
-    return WTF::WrapUnique(new WorkerBackingThread(name, true));
+  static std::unique_ptr<WorkerBackingThread> CreateForTest(
+      const WebThreadCreationParams& params) {
+    return WTF::WrapUnique(new WorkerBackingThread(params, true));
   }
   static std::unique_ptr<WorkerBackingThread> CreateForTest(WebThread* thread) {
     return WTF::WrapUnique(new WorkerBackingThread(thread, true));
@@ -64,7 +66,8 @@
   static void SetRAILModeOnWorkerThreadIsolates(v8::RAILMode);
 
  private:
-  WorkerBackingThread(const char* name, bool should_call_gc_on_shutdown);
+  WorkerBackingThread(const WebThreadCreationParams&,
+                      bool should_call_gc_on_shutdown);
   WorkerBackingThread(WebThread*, bool should_call_gc_on_s_hutdown);
 
   std::unique_ptr<WebThreadSupportingGC> backing_thread_;
diff --git a/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h b/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h
index 45b01831..c232522 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h
+++ b/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h
@@ -80,8 +80,8 @@
   WorkerThreadForTest(ThreadableLoadingContext* loading_context,
                       WorkerReportingProxy& mock_worker_reporting_proxy)
       : WorkerThread(loading_context, mock_worker_reporting_proxy),
-        worker_backing_thread_(
-            WorkerBackingThread::CreateForTest("Test thread")) {}
+        worker_backing_thread_(WorkerBackingThread::CreateForTest(
+            WebThreadCreationParams("Test thread"))) {}
 
   ~WorkerThreadForTest() override = default;
 
diff --git a/third_party/WebKit/Source/core/workers/WorkletThreadHolder.h b/third_party/WebKit/Source/core/workers/WorkletThreadHolder.h
index bdcc79b..2833f079 100644
--- a/third_party/WebKit/Source/core/workers/WorkletThreadHolder.h
+++ b/third_party/WebKit/Source/core/workers/WorkletThreadHolder.h
@@ -32,7 +32,7 @@
       return;
     thread_holder_instance_ = new WorkletThreadHolder<DerivedWorkletThread>;
     thread_holder_instance_->Initialize(
-        WorkerBackingThread::Create(thread_name));
+        WorkerBackingThread::Create(WebThreadCreationParams(thread_name)));
   }
 
   static void EnsureInstance(WebThread* thread) {
@@ -44,12 +44,12 @@
     thread_holder_instance_->Initialize(WorkerBackingThread::Create(thread));
   }
 
-  static void CreateForTest(const char* thread_name) {
+  static void CreateForTest(const WebThreadCreationParams& params) {
     MutexLocker locker(HolderInstanceMutex());
     DCHECK(!thread_holder_instance_);
     thread_holder_instance_ = new WorkletThreadHolder<DerivedWorkletThread>;
     thread_holder_instance_->Initialize(
-        WorkerBackingThread::CreateForTest(thread_name));
+        WorkerBackingThread::CreateForTest(params));
   }
 
   static void CreateForTest(WebThread* thread) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSMetadata.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSMetadata.js
index dc8d335..9b1666a3 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSMetadata.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSMetadata.js
@@ -984,6 +984,18 @@
   'ry': {values: ['auto']},
   'scale': {values: ['none']},
   'scroll-behavior': {values: ['auto', 'smooth']},
+  'scroll-customization': {
+    values: [
+      'none',
+      'auto',
+      'pan-x',
+      'pan-y',
+      'pan-left',
+      'pan-right',
+      'pan-up',
+      'pan-down',
+    ]
+  },
   'shape-outside': {values: ['none', 'border-box', 'content-box', 'padding-box', 'margin-box']},
   'shape-rendering': {values: ['auto', 'optimizespeed', 'geometricprecision', 'crispedges']},
   'stroke': {values: ['none']},
diff --git a/third_party/WebKit/Source/modules/animationworklet/AnimationWorkletThreadTest.cpp b/third_party/WebKit/Source/modules/animationworklet/AnimationWorkletThreadTest.cpp
index 79325f0..725f0811 100644
--- a/third_party/WebKit/Source/modules/animationworklet/AnimationWorkletThreadTest.cpp
+++ b/third_party/WebKit/Source/modules/animationworklet/AnimationWorkletThreadTest.cpp
@@ -39,7 +39,8 @@
 class AnimationWorkletTestPlatform : public TestingPlatformSupport {
  public:
   AnimationWorkletTestPlatform()
-      : thread_(old_platform_->CreateThread("Compositor")) {}
+      : thread_(old_platform_->CreateThread(
+            WebThreadCreationParams("Compositor"))) {}
 
   WebThread* CompositorThread() const override { return thread_.get(); }
 
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
index e221195..5f4750a 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
@@ -595,7 +595,7 @@
   if (MediaElement().IsHTMLVideoElement() &&
       !VideoElement().HasAvailableVideoFrame() &&
       VideoElement().PosterImageURL().IsEmpty() &&
-      state != ControlsState::kScrubbing) {
+      state <= ControlsState::kLoadingMetadata) {
     builder.Append(" ");
     builder.Append(kShowDefaultPosterCSSClass);
   }
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp
index 42cffce..1d6ba06 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp
@@ -6,6 +6,8 @@
 
 #include "core/dom/DOMTokenList.h"
 #include "core/dom/events/Event.h"
+#include "core/html/HTMLDivElement.h"
+#include "core/html/HTMLSpanElement.h"
 #include "core/html/forms/HTMLLabelElement.h"
 #include "core/html/media/HTMLMediaElement.h"
 #include "modules/media_controls/MediaControlsImpl.h"
@@ -20,6 +22,9 @@
 // The default size of an overflow button in pixels.
 constexpr int kDefaultButtonSize = 36;
 
+const char kOverflowContainerWithSubtitleCSSClass[] = "with-subtitle";
+const char kOverflowSubtitleCSSClass[] = "subtitle";
+
 }  // namespace
 
 namespace blink {
@@ -52,8 +57,9 @@
   // We don't want the button visible within the overflow menu.
   button->SetInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
 
-  overflow_menu_text_ =
-      Text::Create(GetDocument(), button->GetOverflowMenuString());
+  overflow_menu_text_ = HTMLSpanElement::Create(GetDocument());
+  overflow_menu_text_->setInnerText(button->GetOverflowMenuString(),
+                                    ASSERT_NO_EXCEPTION);
 
   HTMLLabelElement* element = HTMLLabelElement::Create(GetDocument());
   element->SetShadowPseudoId(
@@ -61,7 +67,15 @@
   // Appending a button to a label element ensures that clicks on the label
   // are passed down to the button, performing the action we'd expect.
   element->AppendChild(button);
-  element->AppendChild(overflow_menu_text_);
+
+  if (MediaControlsImpl::IsModern()) {
+    overflow_menu_container_ = HTMLDivElement::Create(GetDocument());
+    overflow_menu_container_->AppendChild(overflow_menu_text_);
+    UpdateOverflowSubtitleElement(button->GetOverflowMenuSubtitleString());
+    element->AppendChild(overflow_menu_container_);
+  } else {
+    element->AppendChild(overflow_menu_text_);
+  }
 
   // Initialize the internal states of the main element and the overflow one.
   button->is_overflow_element_ = true;
@@ -76,6 +90,39 @@
   return element;
 }
 
+void MediaControlInputElement::UpdateOverflowSubtitleElement(String text) {
+  DCHECK(overflow_menu_container_);
+
+  if (!text) {
+    // If setting the text to null, we want to remove the element.
+    RemoveOverflowSubtitleElement();
+    return;
+  }
+
+  if (overflow_menu_subtitle_) {
+    // If element exists, just update the text.
+    overflow_menu_subtitle_->setInnerText(text, ASSERT_NO_EXCEPTION);
+  } else {
+    // Otherwise, create a new element.
+    overflow_menu_subtitle_ = HTMLSpanElement::Create(GetDocument());
+    overflow_menu_subtitle_->setInnerText(text, ASSERT_NO_EXCEPTION);
+    overflow_menu_subtitle_->setAttribute("class", kOverflowSubtitleCSSClass);
+
+    overflow_menu_container_->AppendChild(overflow_menu_subtitle_);
+    overflow_menu_container_->setAttribute(
+        "class", kOverflowContainerWithSubtitleCSSClass);
+  }
+}
+
+void MediaControlInputElement::RemoveOverflowSubtitleElement() {
+  if (!overflow_menu_subtitle_)
+    return;
+
+  overflow_menu_container_->RemoveChild(overflow_menu_subtitle_);
+  overflow_menu_container_->removeAttribute("class");
+  overflow_menu_subtitle_ = nullptr;
+}
+
 void MediaControlInputElement::SetOverflowElementIsWanted(bool wanted) {
   if (!overflow_element_)
     return;
@@ -105,7 +152,11 @@
     return;
 
   DCHECK(overflow_element_);
-  overflow_menu_text_->ReplaceWholeText(GetOverflowMenuString());
+  overflow_menu_text_->setInnerText(GetOverflowMenuString(),
+                                    ASSERT_NO_EXCEPTION);
+
+  if (MediaControlsImpl::IsModern())
+    UpdateOverflowSubtitleElement(GetOverflowMenuSubtitleString());
 }
 
 MediaControlInputElement::MediaControlInputElement(
@@ -184,6 +235,10 @@
   return MediaElement().GetLocale().QueryString(GetOverflowStringName());
 }
 
+String MediaControlInputElement::GetOverflowMenuSubtitleString() const {
+  return String();
+}
+
 void MediaControlInputElement::RecordCTREvent(CTREvent event) {
   String histogram_name("Media.Controls.CTR.");
   histogram_name.append(GetNameForHistograms());
@@ -219,7 +274,9 @@
   HTMLInputElement::Trace(visitor);
   MediaControlElementBase::Trace(visitor);
   visitor->Trace(overflow_element_);
+  visitor->Trace(overflow_menu_container_);
   visitor->Trace(overflow_menu_text_);
+  visitor->Trace(overflow_menu_subtitle_);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.h b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.h
index 83214ef..c3be0de 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.h
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.h
@@ -82,6 +82,17 @@
   // the overflow menu.
   String GetOverflowMenuString() const;
 
+  // Returns a subtitle for the overflow menu text, or a null String if there
+  // should not be a subtitle.
+  virtual String GetOverflowMenuSubtitleString() const;
+
+  // Create/update subtitle text on the overflow element. If a null String is
+  // given, the subtitle element is removed.
+  void UpdateOverflowSubtitleElement(String text);
+
+  // Remove the subtitle text from the overflow element.
+  void RemoveOverflowSubtitleElement();
+
   // Used for histograms, do not reorder.
   enum class CTREvent {
     kDisplayed = 0,
@@ -96,8 +107,14 @@
   // Setting this pointer is optional so it may be null.
   Member<MediaControlInputElement> overflow_element_;
 
+  // Contains the overflow text and its subtitle (if exists).
+  Member<HTMLDivElement> overflow_menu_container_;
+
   // The text representation of the button within the overflow menu.
-  Member<Text> overflow_menu_text_;
+  Member<HTMLSpanElement> overflow_menu_text_;
+
+  // The subtitle of the text within the overflow menu.
+  Member<HTMLSpanElement> overflow_menu_subtitle_;
 
   // Keeps track if the button was created for the purpose of the overflow menu.
   bool is_overflow_element_ = false;
diff --git a/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css b/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css
index f59a6ec..85641ea 100644
--- a/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css
+++ b/third_party/WebKit/Source/modules/media_controls/resources/modernMediaControls.css
@@ -411,6 +411,23 @@
   margin-right: 6px;
 }
 
+label[pseudo="-internal-media-controls-overflow-menu-list-item"] div {
+  display: inline-grid;
+  margin: 16px 0 16px 0;
+}
+
+label[pseudo="-internal-media-controls-overflow-menu-list-item"] div.with-subtitle {
+  margin: 8px 0 8px 0;
+}
+
+label[pseudo="-internal-media-controls-overflow-menu-list-item"] div span {
+  line-height: normal;
+}
+
+label[pseudo="-internal-media-controls-overflow-menu-list-item"] div span.subtitle {
+  color: rgba(0,0,0,0.54);
+}
+
 audio::-internal-media-controls-text-track-list-header:hover,
 video::-internal-media-controls-text-track-list-header:hover,
 audio::-internal-media-controls-overflow-menu-list-item:hover,
diff --git a/third_party/WebKit/Source/modules/mediastream/URLMediaStream.cpp b/third_party/WebKit/Source/modules/mediastream/URLMediaStream.cpp
index 1f1ceab..925eab3 100644
--- a/third_party/WebKit/Source/modules/mediastream/URLMediaStream.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/URLMediaStream.cpp
@@ -31,7 +31,7 @@
 #include "modules/mediastream/URLMediaStream.h"
 
 #include "core/dom/ExecutionContext.h"
-#include "core/frame/UseCounter.h"
+#include "core/frame/Deprecation.h"
 #include "core/url/DOMURL.h"
 #include "modules/mediastream/MediaStream.h"
 #include "platform/bindings/ScriptState.h"
@@ -47,7 +47,8 @@
   DCHECK(execution_context);
   DCHECK(stream);
 
-  UseCounter::Count(execution_context, WebFeature::kCreateObjectURLMediaStream);
+  Deprecation::CountDeprecation(execution_context,
+                                WebFeature::kCreateObjectURLMediaStream);
   return DOMURL::CreatePublicURL(execution_context, stream);
 }
 
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp
index 2abaee5..4b4cc98 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp
@@ -47,8 +47,8 @@
         installed_scripts_manager)
     : WorkerThread(loading_context, *global_scope_proxy),
       global_scope_proxy_(global_scope_proxy),
-      worker_backing_thread_(
-          WorkerBackingThread::Create("ServiceWorker Thread")),
+      worker_backing_thread_(WorkerBackingThread::Create(
+          WebThreadCreationParams("ServiceWorker Thread"))),
       installed_scripts_manager_(std::move(installed_scripts_manager)) {}
 
 ServiceWorkerThread::~ServiceWorkerThread() {
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp b/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp
index ef2fbc3..874f49e1b 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp
@@ -72,8 +72,9 @@
         AudioHardwareSampleRate(), buffer_size);
   }
 
-  std::unique_ptr<WebThread> CreateThread(const char* name) override {
-    return old_platform_->CreateThread(name);
+  std::unique_ptr<WebThread> CreateThread(
+      const WebThreadCreationParams& params) override {
+    return old_platform_->CreateThread(params);
   }
 
   double AudioHardwareSampleRate() override { return 44100; }
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
index 36e355c..95aed6e 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
@@ -64,6 +64,15 @@
   }
 #endif
   InstanceCounters::IncrementCounter(InstanceCounters::kAudioHandlerCounter);
+
+#if DEBUG_AUDIONODE_REFERENCES
+  fprintf(
+      stderr,
+      "[%16p]: %16p: %2d: AudioHandler::AudioHandler() %d [%d] total: %u\n",
+      Context(), this, GetNodeType(), connection_ref_count_,
+      node_count_[GetNodeType()],
+      InstanceCounters::CounterValue(InstanceCounters::kAudioHandlerCounter));
+#endif
 }
 
 AudioHandler::~AudioHandler() {
@@ -73,9 +82,13 @@
   InstanceCounters::DecrementCounter(InstanceCounters::kAudioHandlerCounter);
 #if DEBUG_AUDIONODE_REFERENCES
   --node_count_[GetNodeType()];
-  fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::~AudioHandler() %d [%d]\n",
-          Context(), this, GetNodeType(), connection_ref_count_,
-          node_count_[GetNodeType()]);
+  fprintf(
+      stderr,
+      "[%16p]: %16p: %2d: AudioHandler::~AudioHandler() %d [%d] remaining: "
+      "%u\n",
+      Context(), this, GetNodeType(), connection_ref_count_,
+      node_count_[GetNodeType()],
+      InstanceCounters::CounterValue(InstanceCounters::kAudioHandlerCounter));
 #endif
 }
 
@@ -545,9 +558,26 @@
 #endif
   BaseAudioContext::GraphAutoLocker locker(context());
   Handler().Dispose();
-  if (context()->ContextState() == BaseAudioContext::kRunning) {
-    context()->GetDeferredTaskHandler().AddRenderingOrphanHandler(
-        std::move(handler_));
+
+  if (context()->HasRealtimeConstraint()) {
+    // Add the handler to the orphan list if the context is not
+    // closed. (Nothing will clean up the orphan list if the context
+    // is closed.)  These will get cleaned up in the post render task
+    // if audio thread is running or when the context is colleced (in
+    // the worst case).
+    if (context()->ContextState() != BaseAudioContext::kClosed) {
+      context()->GetDeferredTaskHandler().AddRenderingOrphanHandler(
+          std::move(handler_));
+    }
+  } else {
+    // For an offline context, only need to save the handler when the
+    // context is running.  The change in the context state is
+    // synchronous with the main thread (even though the offline
+    // thread is not synchronized to the main thread).
+    if (context()->ContextState() == BaseAudioContext::kRunning) {
+      context()->GetDeferredTaskHandler().AddRenderingOrphanHandler(
+          std::move(handler_));
+    }
   }
 }
 
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
index ca36e23..44f2dbf 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
@@ -85,9 +85,10 @@
         AudioHardwareSampleRate(), AudioHardwareBufferSize());
   }
 
-  std::unique_ptr<WebThread> CreateThread(const char* name) override {
+  std::unique_ptr<WebThread> CreateThread(
+      const WebThreadCreationParams& params) override {
     // return base::WrapUnique(old_platform_->CurrentThread());
-    return old_platform_->CreateThread(name);
+    return old_platform_->CreateThread(params);
   }
 
   double AudioHardwareSampleRate() override { return 44100; }
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
index fa5bc38..5e469ba 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
@@ -149,8 +149,8 @@
   if (Context()->audioWorklet() && Context()->audioWorklet()->IsReady()) {
     worklet_backing_thread_ = Context()->audioWorklet()->GetBackingThread();
   } else {
-    render_thread_ =
-        Platform::Current()->CreateThread("offline audio renderer");
+    render_thread_ = Platform::Current()->CreateThread(
+        WebThreadCreationParams("offline audio renderer"));
   }
 
   render_target_ = render_target;
diff --git a/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp b/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp
index fb7a066..fbf4df14 100644
--- a/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp
@@ -59,7 +59,8 @@
   DCHECK(IsMainThread());
   if (thread_)
     return;
-  thread_ = WebThreadSupportingGC::Create("WebCore: Database");
+  thread_ = WebThreadSupportingGC::Create(
+      WebThreadCreationParams("WebCore: Database"));
   thread_->PostTask(FROM_HERE,
                     CrossThreadBind(&DatabaseThread::SetupDatabaseThread,
                                     WrapCrossThreadPersistent(this)));
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 6ec3dd05..62dc3e9 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1289,8 +1289,6 @@
     "mediastream/MediaStreamSource.h",
     "mediastream/MediaStreamWebAudioSource.cpp",
     "mediastream/MediaStreamWebAudioSource.h",
-    "memory_profiler/SamplingNativeHeapProfiler.cpp",
-    "memory_profiler/SamplingNativeHeapProfiler.h",
     "mhtml/ArchiveResource.cpp",
     "mhtml/ArchiveResource.h",
     "mhtml/MHTMLArchive.cpp",
@@ -1332,6 +1330,8 @@
     "scroll/ScrollAnimatorBase.h",
     "scroll/ScrollAnimatorCompositorCoordinator.cpp",
     "scroll/ScrollAnimatorCompositorCoordinator.h",
+    "scroll/ScrollCustomization.cpp",
+    "scroll/ScrollCustomization.h",
     "scroll/ScrollSnapData.h",
     "scroll/ScrollStateData.h",
     "scroll/ScrollTypes.h",
@@ -1531,7 +1531,6 @@
     "//third_party/WebKit/Source/platform/scheduler",
   ]
   deps = [
-    "//base/allocator:features",
     "//components/viz/service",
     "//device/base/synchronization",
     "//device/vr:mojo_bindings_blink",
diff --git a/third_party/WebKit/Source/platform/WebThread.cpp b/third_party/WebKit/Source/platform/WebThread.cpp
index da63a2a..b5dd34cb 100644
--- a/third_party/WebKit/Source/platform/WebThread.cpp
+++ b/third_party/WebKit/Source/platform/WebThread.cpp
@@ -17,6 +17,9 @@
 
 namespace blink {
 
+WebThreadCreationParams::WebThreadCreationParams(const char* name)
+    : name(name) {}
+
 #if defined(OS_WIN)
 static_assert(sizeof(blink::PlatformThreadId) >= sizeof(DWORD),
               "size of platform thread id is too small");
diff --git a/third_party/WebKit/Source/platform/WebThreadSupportingGC.cpp b/third_party/WebKit/Source/platform/WebThreadSupportingGC.cpp
index 551296f..f5ad0f1 100644
--- a/third_party/WebKit/Source/platform/WebThreadSupportingGC.cpp
+++ b/third_party/WebKit/Source/platform/WebThreadSupportingGC.cpp
@@ -14,20 +14,22 @@
 namespace blink {
 
 std::unique_ptr<WebThreadSupportingGC> WebThreadSupportingGC::Create(
-    const char* name) {
-  return WTF::WrapUnique(new WebThreadSupportingGC(name, nullptr));
+    const WebThreadCreationParams& params) {
+  return WTF::WrapUnique(new WebThreadSupportingGC(params, nullptr));
 }
 
 std::unique_ptr<WebThreadSupportingGC> WebThreadSupportingGC::CreateForThread(
     WebThread* thread) {
-  return WTF::WrapUnique(new WebThreadSupportingGC(nullptr, thread));
+  return WTF::WrapUnique(
+      new WebThreadSupportingGC(WebThreadCreationParams(nullptr), thread));
 }
 
-WebThreadSupportingGC::WebThreadSupportingGC(const char* name,
-                                             WebThread* thread)
+WebThreadSupportingGC::WebThreadSupportingGC(
+    const WebThreadCreationParams& params,
+    WebThread* thread)
     : thread_(thread) {
   DCHECK(IsMainThread());
-  DCHECK(!name || !thread);
+  DCHECK(!params.name || !thread);
 #if DCHECK_IS_ON()
   // We call this regardless of whether an existing thread is given or not,
   // as it means that blink is going to run with more than one thread.
@@ -35,7 +37,7 @@
 #endif
   if (!thread_) {
     // If |thread| is not given, create a new one and own it.
-    owning_thread_ = Platform::Current()->CreateThread(name);
+    owning_thread_ = Platform::Current()->CreateThread(params);
     thread_ = owning_thread_.get();
   }
   MemoryCoordinator::RegisterThread(thread_);
diff --git a/third_party/WebKit/Source/platform/WebThreadSupportingGC.h b/third_party/WebKit/Source/platform/WebThreadSupportingGC.h
index 2008f1a0..8abe45d 100644
--- a/third_party/WebKit/Source/platform/WebThreadSupportingGC.h
+++ b/third_party/WebKit/Source/platform/WebThreadSupportingGC.h
@@ -30,7 +30,8 @@
   WTF_MAKE_NONCOPYABLE(WebThreadSupportingGC);
 
  public:
-  static std::unique_ptr<WebThreadSupportingGC> Create(const char* name);
+  static std::unique_ptr<WebThreadSupportingGC> Create(
+      const WebThreadCreationParams&);
   static std::unique_ptr<WebThreadSupportingGC> CreateForThread(WebThread*);
   ~WebThreadSupportingGC();
 
@@ -77,7 +78,7 @@
   }
 
  private:
-  WebThreadSupportingGC(const char* name, WebThread*);
+  WebThreadSupportingGC(const WebThreadCreationParams&, WebThread*);
 
   std::unique_ptr<GCTaskRunner> gc_task_runner_;
 
diff --git a/third_party/WebKit/Source/platform/audio/HRTFDatabaseLoader.cpp b/third_party/WebKit/Source/platform/audio/HRTFDatabaseLoader.cpp
index f1e0fdc1..cbd61f5 100644
--- a/third_party/WebKit/Source/platform/audio/HRTFDatabaseLoader.cpp
+++ b/third_party/WebKit/Source/platform/audio/HRTFDatabaseLoader.cpp
@@ -95,7 +95,8 @@
   DCHECK(!thread_);
 
   // Start the asynchronous database loading process.
-  thread_ = Platform::Current()->CreateThread("HRTF database loader");
+  thread_ = Platform::Current()->CreateThread(
+      WebThreadCreationParams("HRTF database loader"));
   // TODO(alexclarke): Should this be posted as a loading task?
   PostCrossThreadTask(*thread_->GetWebTaskRunner(), FROM_HERE,
                       CrossThreadBind(&HRTFDatabaseLoader::LoadTask,
diff --git a/third_party/WebKit/Source/platform/audio/PushPullFIFOMultithreadTest.cpp b/third_party/WebKit/Source/platform/audio/PushPullFIFOMultithreadTest.cpp
index 00f87d1..21f576f 100644
--- a/third_party/WebKit/Source/platform/audio/PushPullFIFOMultithreadTest.cpp
+++ b/third_party/WebKit/Source/platform/audio/PushPullFIFOMultithreadTest.cpp
@@ -29,7 +29,8 @@
   FIFOClient(PushPullFIFO* fifo, size_t bus_length, size_t jitter_range_ms)
       : fifo_(fifo),
         bus_(AudioBus::Create(fifo->NumberOfChannels(), bus_length)),
-        client_thread_(Platform::Current()->CreateThread("client thread")),
+        client_thread_(Platform::Current()->CreateThread(
+            WebThreadCreationParams("client thread"))),
         done_event_(std::make_unique<WaitableEvent>()),
         jitter_range_ms_(jitter_range_ms) {}
 
diff --git a/third_party/WebKit/Source/platform/audio/ReverbConvolver.cpp b/third_party/WebKit/Source/platform/audio/ReverbConvolver.cpp
index a3c0108..b170391 100644
--- a/third_party/WebKit/Source/platform/audio/ReverbConvolver.cpp
+++ b/third_party/WebKit/Source/platform/audio/ReverbConvolver.cpp
@@ -139,7 +139,7 @@
   // be real-time, but higher than the default...
   if (use_background_threads && background_stages_.size() > 0) {
     background_thread_ = Platform::Current()->CreateThread(
-        "Reverb convolution background thread");
+        WebThreadCreationParams("Reverb convolution background thread"));
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/bindings/ActiveScriptWrappableBase.cpp b/third_party/WebKit/Source/platform/bindings/ActiveScriptWrappableBase.cpp
index 3ba11d1..eca3ad1d 100644
--- a/third_party/WebKit/Source/platform/bindings/ActiveScriptWrappableBase.cpp
+++ b/third_party/WebKit/Source/platform/bindings/ActiveScriptWrappableBase.cpp
@@ -21,7 +21,7 @@
 
 void ActiveScriptWrappableBase::TraceActiveScriptWrappables(
     v8::Isolate* isolate,
-    ScriptWrappableVisitor* visitor) {
+    ScriptWrappableMarkingVisitor* visitor) {
   V8PerIsolateData* isolate_data = V8PerIsolateData::From(isolate);
   const auto* active_script_wrappables = isolate_data->ActiveScriptWrappables();
   if (!active_script_wrappables)
diff --git a/third_party/WebKit/Source/platform/bindings/ActiveScriptWrappableBase.h b/third_party/WebKit/Source/platform/bindings/ActiveScriptWrappableBase.h
index 7ac63c0e..5853b5e 100644
--- a/third_party/WebKit/Source/platform/bindings/ActiveScriptWrappableBase.h
+++ b/third_party/WebKit/Source/platform/bindings/ActiveScriptWrappableBase.h
@@ -16,7 +16,7 @@
 namespace blink {
 
 class ScriptWrappable;
-class ScriptWrappableVisitor;
+class ScriptWrappableMarkingVisitor;
 
 /**
  * Classes deriving from ActiveScriptWrappable will be registered in a
@@ -30,7 +30,7 @@
   ActiveScriptWrappableBase();
 
   static void TraceActiveScriptWrappables(v8::Isolate*,
-                                          ScriptWrappableVisitor*);
+                                          ScriptWrappableMarkingVisitor*);
 
  protected:
   virtual bool IsContextDestroyed() const = 0;
diff --git a/third_party/WebKit/Source/platform/bindings/DOMDataStore.h b/third_party/WebKit/Source/platform/bindings/DOMDataStore.h
index e519368..6755e914 100644
--- a/third_party/WebKit/Source/platform/bindings/DOMDataStore.h
+++ b/third_party/WebKit/Source/platform/bindings/DOMDataStore.h
@@ -137,8 +137,8 @@
       return object->SetWrapper(isolate, wrapper_type_info, wrapper);
     bool updated = wrapper_map_->Set(object, wrapper_type_info, wrapper);
     if (updated) {
-      ScriptWrappableVisitor::WriteBarrier(isolate, &wrapper_map_.value(),
-                                           object);
+      ScriptWrappableMarkingVisitor::WriteBarrier(
+          isolate, &wrapper_map_.value(), object);
     }
     return updated;
   }
diff --git a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.cpp b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.cpp
index 2292cbc6..49dc867c 100644
--- a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.cpp
+++ b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.cpp
@@ -24,9 +24,9 @@
 
 namespace blink {
 
-ScriptWrappableVisitor::~ScriptWrappableVisitor() = default;
+ScriptWrappableMarkingVisitor::~ScriptWrappableMarkingVisitor() = default;
 
-void ScriptWrappableVisitor::TracePrologue() {
+void ScriptWrappableMarkingVisitor::TracePrologue() {
   // This CHECK ensures that wrapper tracing is not started from scopes
   // that forbid GC execution, e.g., constructors.
   CHECK(ThreadState::Current());
@@ -42,18 +42,18 @@
   ThreadState::Current()->SetWrapperTracingInProgress(true);
 }
 
-void ScriptWrappableVisitor::EnterFinalPause() {
+void ScriptWrappableMarkingVisitor::EnterFinalPause() {
   CHECK(ThreadState::Current());
   CHECK(!ThreadState::Current()->IsWrapperTracingForbidden());
   ActiveScriptWrappableBase::TraceActiveScriptWrappables(isolate_, this);
 }
 
-void ScriptWrappableVisitor::TraceEpilogue() {
+void ScriptWrappableMarkingVisitor::TraceEpilogue() {
   CHECK(ThreadState::Current());
   CHECK(!ThreadState::Current()->IsWrapperTracingForbidden());
   DCHECK(marking_deque_.IsEmpty());
 #if DCHECK_IS_ON()
-  ScriptWrappableVisitorVerifier verifier(isolate_, &verifier_deque_);
+  ScriptWrappableVisitorVerifier verifier(&verifier_deque_);
   verifier.Verify();
 #endif
 
@@ -63,7 +63,7 @@
   ScheduleIdleLazyCleanup();
 }
 
-void ScriptWrappableVisitor::AbortTracing() {
+void ScriptWrappableMarkingVisitor::AbortTracing() {
   CHECK(ThreadState::Current());
   should_cleanup_ = true;
   tracing_in_progress_ = false;
@@ -71,12 +71,12 @@
   PerformCleanup();
 }
 
-size_t ScriptWrappableVisitor::NumberOfWrappersToTrace() {
+size_t ScriptWrappableMarkingVisitor::NumberOfWrappersToTrace() {
   CHECK(ThreadState::Current());
   return marking_deque_.size();
 }
 
-void ScriptWrappableVisitor::PerformCleanup() {
+void ScriptWrappableMarkingVisitor::PerformCleanup() {
   if (!should_cleanup_)
     return;
 
@@ -95,7 +95,7 @@
   should_cleanup_ = false;
 }
 
-void ScriptWrappableVisitor::ScheduleIdleLazyCleanup() {
+void ScriptWrappableMarkingVisitor::ScheduleIdleLazyCleanup() {
   WebThread* const thread = Platform::Current()->CurrentThread();
   // Thread might already be gone, or some threads (e.g. PPAPI) don't have a
   // scheduler.
@@ -106,19 +106,20 @@
     return;
 
   Platform::Current()->CurrentThread()->Scheduler()->PostIdleTask(
-      FROM_HERE, WTF::Bind(&ScriptWrappableVisitor::PerformLazyCleanup,
+      FROM_HERE, WTF::Bind(&ScriptWrappableMarkingVisitor::PerformLazyCleanup,
                            WTF::Unretained(this)));
   idle_cleanup_task_scheduled_ = true;
 }
 
-void ScriptWrappableVisitor::PerformLazyCleanup(double deadline_seconds) {
+void ScriptWrappableMarkingVisitor::PerformLazyCleanup(
+    double deadline_seconds) {
   idle_cleanup_task_scheduled_ = false;
 
   if (!should_cleanup_)
     return;
 
   TRACE_EVENT1("blink_gc,devtools.timeline",
-               "ScriptWrappableVisitor::performLazyCleanup",
+               "ScriptWrappableMarkingVisitor::performLazyCleanup",
                "idleDeltaInSeconds",
                deadline_seconds - CurrentTimeTicksInSeconds());
 
@@ -152,7 +153,7 @@
   should_cleanup_ = false;
 }
 
-void ScriptWrappableVisitor::RegisterV8Reference(
+void ScriptWrappableMarkingVisitor::RegisterV8Reference(
     const std::pair<void*, void*>& internal_fields) {
   if (!tracing_in_progress_) {
     return;
@@ -173,7 +174,7 @@
   wrapper_type_info->TraceWrappers(this, script_wrappable);
 }
 
-void ScriptWrappableVisitor::RegisterV8References(
+void ScriptWrappableMarkingVisitor::RegisterV8References(
     const std::vector<std::pair<void*, void*>>&
         internal_fields_of_potential_wrappers) {
   CHECK(ThreadState::Current());
@@ -184,7 +185,7 @@
   }
 }
 
-bool ScriptWrappableVisitor::AdvanceTracing(
+bool ScriptWrappableMarkingVisitor::AdvanceTracing(
     double deadline_in_ms,
     v8::EmbedderHeapTracer::AdvanceTracingActions actions) {
   // Do not drain the marking deque in a state where we can generally not
@@ -205,7 +206,8 @@
   return true;
 }
 
-void ScriptWrappableVisitor::MarkWrapperHeader(HeapObjectHeader* header) const {
+void ScriptWrappableMarkingVisitor::MarkWrapperHeader(
+    HeapObjectHeader* header) const {
   DCHECK(!header->IsWrapperHeaderMarked());
   // Verify that no compactable & movable objects are slated for
   // lazy unmarking.
@@ -215,10 +217,10 @@
   headers_to_unmark_.push_back(header);
 }
 
-void ScriptWrappableVisitor::WriteBarrier(
+void ScriptWrappableMarkingVisitor::WriteBarrier(
     v8::Isolate* isolate,
     const TraceWrapperV8Reference<v8::Value>& dst_object) {
-  ScriptWrappableVisitor* visitor = CurrentVisitor(isolate);
+  ScriptWrappableMarkingVisitor* visitor = CurrentVisitor(isolate);
   if (dst_object.IsEmpty() || !visitor->WrapperTracingInProgress())
     return;
 
@@ -227,11 +229,11 @@
   visitor->TraceWrappers(dst_object);
 }
 
-void ScriptWrappableVisitor::WriteBarrier(
+void ScriptWrappableMarkingVisitor::WriteBarrier(
     v8::Isolate* isolate,
     DOMWrapperMap<ScriptWrappable>* wrapper_map,
     ScriptWrappable* key) {
-  ScriptWrappableVisitor* visitor = CurrentVisitor(isolate);
+  ScriptWrappableMarkingVisitor* visitor = CurrentVisitor(isolate);
   if (!visitor->WrapperTracingInProgress())
     return;
   // Conservatively assume that the source object key is marked.
@@ -244,7 +246,7 @@
   Visit(wrapper_map, key);
 }
 
-void ScriptWrappableVisitor::Visit(
+void ScriptWrappableMarkingVisitor::Visit(
     const TraceWrapperV8Reference<v8::Value>& traced_wrapper) const {
   // The write barrier may try to mark a wrapper because cleanup is still
   // delayed. Bail out in this case. We also allow unconditional marking which
@@ -254,7 +256,7 @@
   traced_wrapper.Get().RegisterExternalReference(isolate_);
 }
 
-void ScriptWrappableVisitor::Visit(
+void ScriptWrappableMarkingVisitor::Visit(
     const WrapperDescriptor& wrapper_descriptor) const {
   HeapObjectHeader* header = wrapper_descriptor.heap_object_header_callback(
       wrapper_descriptor.traceable);
@@ -271,8 +273,9 @@
 #endif
 }
 
-void ScriptWrappableVisitor::Visit(DOMWrapperMap<ScriptWrappable>* wrapper_map,
-                                   const ScriptWrappable* key) const {
+void ScriptWrappableMarkingVisitor::Visit(
+    DOMWrapperMap<ScriptWrappable>* wrapper_map,
+    const ScriptWrappable* key) const {
   wrapper_map->MarkWrapper(const_cast<ScriptWrappable*>(key));
 }
 
@@ -286,7 +289,7 @@
   wrapper_base->TraceWrappers(this);
 }
 
-void ScriptWrappableVisitor::InvalidateDeadObjectsInMarkingDeque() {
+void ScriptWrappableMarkingVisitor::InvalidateDeadObjectsInMarkingDeque() {
   for (auto it = marking_deque_.begin(); it != marking_deque_.end(); ++it) {
     auto& marking_data = *it;
     if (marking_data.ShouldBeInvalidated()) {
@@ -308,24 +311,24 @@
   }
 }
 
-void ScriptWrappableVisitor::InvalidateDeadObjectsInMarkingDeque(
+void ScriptWrappableMarkingVisitor::InvalidateDeadObjectsInMarkingDeque(
     v8::Isolate* isolate) {
-  ScriptWrappableVisitor* script_wrappable_visitor =
-      V8PerIsolateData::From(isolate)->GetScriptWrappableVisitor();
+  ScriptWrappableMarkingVisitor* script_wrappable_visitor =
+      V8PerIsolateData::From(isolate)->GetScriptWrappableMarkingVisitor();
   if (script_wrappable_visitor)
     script_wrappable_visitor->InvalidateDeadObjectsInMarkingDeque();
 }
 
-void ScriptWrappableVisitor::PerformCleanup(v8::Isolate* isolate) {
-  ScriptWrappableVisitor* script_wrappable_visitor =
-      V8PerIsolateData::From(isolate)->GetScriptWrappableVisitor();
+void ScriptWrappableMarkingVisitor::PerformCleanup(v8::Isolate* isolate) {
+  ScriptWrappableMarkingVisitor* script_wrappable_visitor =
+      V8PerIsolateData::From(isolate)->GetScriptWrappableMarkingVisitor();
   if (script_wrappable_visitor)
     script_wrappable_visitor->PerformCleanup();
 }
 
-ScriptWrappableVisitor* ScriptWrappableVisitor::CurrentVisitor(
+ScriptWrappableMarkingVisitor* ScriptWrappableMarkingVisitor::CurrentVisitor(
     v8::Isolate* isolate) {
-  return V8PerIsolateData::From(isolate)->GetScriptWrappableVisitor();
+  return V8PerIsolateData::From(isolate)->GetScriptWrappableMarkingVisitor();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.h b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.h
index a388901..45f32a0 100644
--- a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.h
+++ b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.h
@@ -96,14 +96,115 @@
   const void* raw_object_pointer_;
 };
 
+// Abstract visitor for wrapper references in a ScriptWrappable.
+// Usage:
+// - Define a derived class that overrides Visit(..) methods.
+// - Create an instance of the derived class: visitor.
+// - Call visitor.DispatchTraceWrappers(traceable).
+// DispatchTraceWrappers will invoke Visit() method for all
+// wrapper references in traceable.
+class PLATFORM_EXPORT ScriptWrappableVisitor {
+ public:
+  // Trace all wrappers of |tracable|.
+  //
+  // If you cannot use TraceWrapperMember & the corresponding TraceWrappers()
+  // for some reason (e.g., unions using raw pointers), see
+  // |TraceWrappersWithManualWriteBarrier()| below.
+  template <typename T>
+  void TraceWrappers(const TraceWrapperMember<T>& traceable) const {
+    static_assert(sizeof(T), "T must be fully defined");
+    Visit(traceable.Get());
+  }
+
+  // Enable partial tracing of objects. This is used when tracing interior
+  // objects without their own header.
+  template <typename T>
+  void TraceWrappers(const T& traceable) const {
+    static_assert(sizeof(T), "T must be fully defined");
+    traceable.TraceWrappers(this);
+  }
+
+  // Only called from automatically generated bindings code.
+  template <typename T>
+  void TraceWrappersFromGeneratedCode(const T* traceable) const {
+    Visit(traceable);
+  }
+
+  // Require all users of manual write barriers to make this explicit in their
+  // |TraceWrappers| definition. Be sure to add
+  // |ScriptWrappableMarkingVisitor::WriteBarrier(new_value)| after all
+  // assignments to the field. Otherwise, the objects may be collected
+  // prematurely.
+  template <typename T>
+  void TraceWrappersWithManualWriteBarrier(const T* traceable) const {
+    Visit(traceable);
+  }
+
+  template <typename V8Type>
+  void TraceWrappers(const TraceWrapperV8Reference<V8Type>& v8reference) const {
+    Visit(v8reference.template Cast<v8::Value>());
+  }
+
+  // Trace wrappers in non-main worlds.
+  void TraceWrappers(DOMWrapperMap<ScriptWrappable>*,
+                     const ScriptWrappable* key) const;
+
+  virtual void DispatchTraceWrappers(const TraceWrapperBase*) const;
+  template <typename T>
+  void DispatchTraceWrappers(const Supplement<T>* traceable) const {
+    const TraceWrapperBaseForSupplement* base = traceable;
+    DispatchTraceWrappersForSupplement(base);
+  }
+  // Catch all handlers needed because of mixins except for Supplement<T>.
+  void DispatchTraceWrappers(const void*) const { CHECK(false); }
+
+ protected:
+  // The visitor interface. Derived visitors should override this
+  // function to visit V8 references and ScriptWrappables.
+  virtual void Visit(const TraceWrapperV8Reference<v8::Value>&) const = 0;
+  virtual void Visit(const WrapperDescriptor&) const = 0;
+  virtual void Visit(DOMWrapperMap<ScriptWrappable>*,
+                     const ScriptWrappable* key) const = 0;
+
+  template <typename T>
+  static WrapperDescriptor WrapperDescriptorFor(const T* traceable) {
+    return {traceable, TraceTrait<T>::TraceMarkedWrapper,
+            TraceTrait<T>::GetHeapObjectHeader,
+            ScriptWrappableVisitor::MissedWriteBarrier<T>};
+  }
+
+ private:
+  template <typename T>
+  static NOINLINE void MissedWriteBarrier() {
+    NOTREACHED();
+  }
+
+  // Helper method to invoke the virtual Visit method with wrapper descriptor.
+  template <typename T>
+  void Visit(const T* traceable) const {
+    static_assert(sizeof(T), "T must be fully defined");
+    if (!traceable)
+      return;
+    Visit(WrapperDescriptorFor(traceable));
+  }
+
+  // Supplement-specific implementation of DispatchTraceWrappers.  The suffix of
+  // "ForSupplement" is necessary not to make this member function a candidate
+  // of overload resolutions.
+  void DispatchTraceWrappersForSupplement(
+      const TraceWrapperBaseForSupplement*) const;
+};
+
 // ScriptWrappableVisitor is used to trace through Blink's heap to find all
 // reachable wrappers. V8 calls this visitor during its garbage collection,
 // see v8::EmbedderHeapTracer.
-class PLATFORM_EXPORT ScriptWrappableVisitor : public v8::EmbedderHeapTracer {
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ScriptWrappableVisitor);
+class PLATFORM_EXPORT ScriptWrappableMarkingVisitor
+    : public v8::EmbedderHeapTracer,
+      public ScriptWrappableVisitor {
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScriptWrappableMarkingVisitor);
 
  public:
-  static ScriptWrappableVisitor* CurrentVisitor(v8::Isolate*);
+  static ScriptWrappableMarkingVisitor* CurrentVisitor(v8::Isolate*);
 
   bool WrapperTracingInProgress() const { return tracing_in_progress_; }
 
@@ -140,7 +241,8 @@
     if (TraceTrait<T>::GetHeapObjectHeader(dst_object)->IsWrapperHeaderMarked())
       return;
 
-    CurrentVisitor(thread_state->GetIsolate())->Visit(dst_object);
+    CurrentVisitor(thread_state->GetIsolate())
+        ->Visit(WrapperDescriptorFor(dst_object));
   }
 
   static void WriteBarrier(v8::Isolate*,
@@ -150,60 +252,8 @@
                            DOMWrapperMap<ScriptWrappable>*,
                            ScriptWrappable* key);
 
-  ScriptWrappableVisitor(v8::Isolate* isolate) : isolate_(isolate){};
-  ~ScriptWrappableVisitor() override;
-
-  // Trace all wrappers of |t|.
-  //
-  // If you cannot use TraceWrapperMember & the corresponding TraceWrappers()
-  // for some reason (e.g., unions using raw pointers), see
-  // |TraceWrappersWithManualWriteBarrier()| below.
-  // TODO(ulan): extract TraceWrappers* methods to a general visitor interface.
-  template <typename T>
-  void TraceWrappers(const TraceWrapperMember<T>& traceable) const {
-    Visit(traceable.Get());
-  }
-
-  // Enable partial tracing of objects. This is used when tracing interior
-  // objects without their own header.
-  template <typename T>
-  void TraceWrappers(const T& traceable) const {
-    static_assert(sizeof(T), "T must be fully defined");
-    traceable.TraceWrappers(this);
-  }
-
-  // Only called from automatically generated bindings code.
-  template <typename T>
-  void TraceWrappersFromGeneratedCode(const T* traceable) const {
-    Visit(traceable);
-  }
-
-  // Require all users of manual write barriers to make this explicit in their
-  // |TraceWrappers| definition. Be sure to add
-  // |ScriptWrappableVisitor::WriteBarrier(new_value)| after all assignments to
-  // the field. Otherwise, the objects may be collected prematurely.
-  template <typename T>
-  void TraceWrappersWithManualWriteBarrier(const T* traceable) const {
-    Visit(traceable);
-  }
-
-  template <typename V8Type>
-  void TraceWrappers(const TraceWrapperV8Reference<V8Type>& v8reference) const {
-    Visit(v8reference.template Cast<v8::Value>());
-  }
-
-  // Trace a wrapper in a non-main world.
-  void TraceWrappers(DOMWrapperMap<ScriptWrappable>*,
-                     const ScriptWrappable* key) const;
-
-  virtual void DispatchTraceWrappers(const TraceWrapperBase*) const;
-  template <typename T>
-  void DispatchTraceWrappers(const Supplement<T>* traceable) const {
-    const TraceWrapperBaseForSupplement* base = traceable;
-    DispatchTraceWrappersForSupplement(base);
-  }
-  // Catch all handlers needed because of mixins except for Supplement<T>.
-  void DispatchTraceWrappers(const void*) const { CHECK(false); }
+  ScriptWrappableMarkingVisitor(v8::Isolate* isolate) : isolate_(isolate){};
+  ~ScriptWrappableMarkingVisitor() override;
 
   // v8::EmbedderHeapTracer interface.
 
@@ -219,43 +269,17 @@
   size_t NumberOfWrappersToTrace() override;
 
  protected:
-  // The visitor interface. Derived visitors should override this
-  // function to visit V8 references and ScriptWrappables.
-  // TODO(ulan): extract Visit methods to a general visitor interface.
-  virtual void Visit(const TraceWrapperV8Reference<v8::Value>&) const;
-  virtual void Visit(const WrapperDescriptor&) const;
-  virtual void Visit(DOMWrapperMap<ScriptWrappable>*,
-                     const ScriptWrappable* key) const;
+  // ScriptWrappableVisitor interface.
+  void Visit(const TraceWrapperV8Reference<v8::Value>&) const override;
+  void Visit(const WrapperDescriptor&) const override;
+  void Visit(DOMWrapperMap<ScriptWrappable>*,
+             const ScriptWrappable* key) const override;
 
   v8::Isolate* isolate() const { return isolate_; }
 
  private:
-  template <typename T>
-  static NOINLINE void MissedWriteBarrier() {
-    NOTREACHED();
-  }
-
-  // Helper method to invoke the virtual Visit method with wrapper descriptor.
-  template <typename T>
-  void Visit(const T* traceable) const {
-    static_assert(sizeof(T), "T must be fully defined");
-    if (!traceable)
-      return;
-    WrapperDescriptor wrapper_descriptor = {
-        traceable, TraceTrait<T>::TraceMarkedWrapper,
-        TraceTrait<T>::GetHeapObjectHeader,
-        ScriptWrappableVisitor::MissedWriteBarrier<T>};
-    Visit(wrapper_descriptor);
-  }
-
   void MarkWrapperHeader(HeapObjectHeader*) const;
 
-  // Supplement-specific implementation of DispatchTraceWrappers.  The suffix of
-  // "ForSupplement" is necessary not to make this member function a candidate
-  // of overload resolutions.
-  void DispatchTraceWrappersForSupplement(
-      const TraceWrapperBaseForSupplement*) const;
-
   // Schedule an idle task to perform a lazy (incremental) clean up of
   // wrappers.
   void ScheduleIdleLazyCleanup();
@@ -317,22 +341,22 @@
   mutable WTF::Vector<HeapObjectHeader*> headers_to_unmark_;
   v8::Isolate* isolate_;
 
-  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableVisitorTest, MixinTracing);
-  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableVisitorTest,
+  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableMarkingVisitorTest, MixinTracing);
+  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableMarkingVisitorTest,
                            OilpanClearsMarkingDequeWhenObjectDied);
-  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableVisitorTest,
-                           ScriptWrappableVisitorTracesWrappers);
-  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableVisitorTest,
+  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableMarkingVisitorTest,
+                           ScriptWrappableMarkingVisitorTracesWrappers);
+  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableMarkingVisitorTest,
                            OilpanClearsHeadersWhenObjectDied);
   FRIEND_TEST_ALL_PREFIXES(
-      ScriptWrappableVisitorTest,
+      ScriptWrappableMarkingVisitorTest,
       MarkedObjectDoesNothingOnWriteBarrierHitWhenDependencyIsMarkedToo);
   FRIEND_TEST_ALL_PREFIXES(
-      ScriptWrappableVisitorTest,
+      ScriptWrappableMarkingVisitorTest,
       MarkedObjectMarksDependencyOnWriteBarrierHitWhenNotMarked);
-  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableVisitorTest,
+  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableMarkingVisitorTest,
                            WriteBarrierOnHeapVectorSwap1);
-  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableVisitorTest,
+  FRIEND_TEST_ALL_PREFIXES(ScriptWrappableMarkingVisitorTest,
                            WriteBarrierOnHeapVectorSwap2);
 };
 
diff --git a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitorVerifier.h b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitorVerifier.h
index 849f4ef..164cd59 100644
--- a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitorVerifier.h
+++ b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitorVerifier.h
@@ -15,9 +15,8 @@
   // For each object in the deque the verifier checks that all children of
   // the object are marked.
   ScriptWrappableVisitorVerifier(
-      v8::Isolate* isolate,
       const WTF::Deque<WrapperMarkingData>* verifier_deque)
-      : ScriptWrappableVisitor(isolate), verifier_deque_(verifier_deque) {}
+      : verifier_deque_(verifier_deque) {}
 
   void Verify() {
     for (auto& marking_data : *verifier_deque_) {
diff --git a/third_party/WebKit/Source/platform/bindings/TraceWrapperMember.h b/third_party/WebKit/Source/platform/bindings/TraceWrapperMember.h
index 9e91304..fe361d80 100644
--- a/third_party/WebKit/Source/platform/bindings/TraceWrapperMember.h
+++ b/third_party/WebKit/Source/platform/bindings/TraceWrapperMember.h
@@ -31,7 +31,7 @@
   TraceWrapperMember(T* raw) : Member<T>(raw) {
     // We have to use a write barrier here because of in-place construction
     // in containers, such as HeapVector::push_back.
-    ScriptWrappableVisitor::WriteBarrier(raw);
+    ScriptWrappableMarkingVisitor::WriteBarrier(raw);
   }
 
   TraceWrapperMember(WTF::HashTableDeletedValueType x) : Member<T>(x) {}
@@ -41,21 +41,21 @@
   TraceWrapperMember& operator=(const TraceWrapperMember& other) {
     Member<T>::operator=(other);
     DCHECK_EQ(other.Get(), this->Get());
-    ScriptWrappableVisitor::WriteBarrier(this->Get());
+    ScriptWrappableMarkingVisitor::WriteBarrier(this->Get());
     return *this;
   }
 
   TraceWrapperMember& operator=(const Member<T>& other) {
     Member<T>::operator=(other);
     DCHECK_EQ(other.Get(), this->Get());
-    ScriptWrappableVisitor::WriteBarrier(this->Get());
+    ScriptWrappableMarkingVisitor::WriteBarrier(this->Get());
     return *this;
   }
 
   TraceWrapperMember& operator=(T* other) {
     Member<T>::operator=(other);
     DCHECK_EQ(other, this->Get());
-    ScriptWrappableVisitor::WriteBarrier(this->Get());
+    ScriptWrappableMarkingVisitor::WriteBarrier(this->Get());
     return *this;
   }
 
@@ -81,10 +81,10 @@
     // If incremental marking is enabled we need to emit the write barrier since
     // the swap was performed on HeapVector<Member<T>>.
     for (auto item : a) {
-      ScriptWrappableVisitor::WriteBarrier(item.Get());
+      ScriptWrappableMarkingVisitor::WriteBarrier(item.Get());
     }
     for (auto item : b) {
-      ScriptWrappableVisitor::WriteBarrier(item.Get());
+      ScriptWrappableMarkingVisitor::WriteBarrier(item.Get());
     }
   }
 }
@@ -102,7 +102,7 @@
     // If incremental marking is enabled we need to emit the write barrier since
     // the swap was performed on HeapVector<Member<T>>.
     for (auto item : a) {
-      ScriptWrappableVisitor::WriteBarrier(item.Get());
+      ScriptWrappableMarkingVisitor::WriteBarrier(item.Get());
     }
   }
 }
diff --git a/third_party/WebKit/Source/platform/bindings/TraceWrapperV8Reference.h b/third_party/WebKit/Source/platform/bindings/TraceWrapperV8Reference.h
index 94468ba2..6811605c 100644
--- a/third_party/WebKit/Source/platform/bindings/TraceWrapperV8Reference.h
+++ b/third_party/WebKit/Source/platform/bindings/TraceWrapperV8Reference.h
@@ -69,7 +69,8 @@
  private:
   inline void InternalSet(v8::Isolate* isolate, v8::Local<T> handle) {
     handle_.Reset(isolate, handle);
-    ScriptWrappableVisitor::WriteBarrier(isolate, UnsafeCast<v8::Value>());
+    ScriptWrappableMarkingVisitor::WriteBarrier(isolate,
+                                                UnsafeCast<v8::Value>());
   }
 
   v8::Persistent<T> handle_;
diff --git a/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h b/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h
index 7dc2123..3fa24b5 100644
--- a/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h
+++ b/third_party/WebKit/Source/platform/bindings/V8DOMWrapper.h
@@ -97,7 +97,7 @@
   // so the visitor can make sure to trace the association (in case it is
   // currently tracing).  Because of some optimizations, V8 will not
   // necessarily detect wrappers created during its incremental marking.
-  per_isolate_data->GetScriptWrappableVisitor()->RegisterV8Reference(
+  per_isolate_data->GetScriptWrappableMarkingVisitor()->RegisterV8Reference(
       std::make_pair(const_cast<WrapperTypeInfo*>(wrapper_type_info),
                      script_wrappable));
 }
diff --git a/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp b/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp
index 0604a54..0a08ed0 100644
--- a/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp
+++ b/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.cpp
@@ -358,10 +358,10 @@
 
 void V8PerIsolateData::TemporaryScriptWrappableVisitorScope::
     SwapWithV8PerIsolateDataVisitor(
-        std::unique_ptr<ScriptWrappableVisitor>& visitor) {
-  ScriptWrappableVisitor* current = CurrentVisitor();
+        std::unique_ptr<ScriptWrappableMarkingVisitor>& visitor) {
+  ScriptWrappableMarkingVisitor* current = CurrentVisitor();
   if (current)
-    ScriptWrappableVisitor::PerformCleanup(isolate_);
+    ScriptWrappableMarkingVisitor::PerformCleanup(isolate_);
 
   V8PerIsolateData::From(isolate_)->script_wrappable_visitor_.swap(
       saved_visitor_);
diff --git a/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.h b/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.h
index 58f1170..96097de 100644
--- a/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.h
+++ b/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.h
@@ -205,7 +205,7 @@
    public:
     TemporaryScriptWrappableVisitorScope(
         v8::Isolate* isolate,
-        std::unique_ptr<ScriptWrappableVisitor> visitor)
+        std::unique_ptr<ScriptWrappableMarkingVisitor> visitor)
         : isolate_(isolate), saved_visitor_(std::move(visitor)) {
       SwapWithV8PerIsolateDataVisitor(saved_visitor_);
     }
@@ -213,23 +213,24 @@
       SwapWithV8PerIsolateDataVisitor(saved_visitor_);
     }
 
-    inline ScriptWrappableVisitor* CurrentVisitor() {
-      return V8PerIsolateData::From(isolate_)->GetScriptWrappableVisitor();
+    inline ScriptWrappableMarkingVisitor* CurrentVisitor() {
+      return V8PerIsolateData::From(isolate_)
+          ->GetScriptWrappableMarkingVisitor();
     }
 
    private:
     void SwapWithV8PerIsolateDataVisitor(
-        std::unique_ptr<ScriptWrappableVisitor>&);
+        std::unique_ptr<ScriptWrappableMarkingVisitor>&);
 
     v8::Isolate* isolate_;
-    std::unique_ptr<ScriptWrappableVisitor> saved_visitor_;
+    std::unique_ptr<ScriptWrappableMarkingVisitor> saved_visitor_;
   };
 
-  void SetScriptWrappableVisitor(
-      std::unique_ptr<ScriptWrappableVisitor> visitor) {
+  void SetScriptWrappableMarkingVisitor(
+      std::unique_ptr<ScriptWrappableMarkingVisitor> visitor) {
     script_wrappable_visitor_ = std::move(visitor);
   }
-  ScriptWrappableVisitor* GetScriptWrappableVisitor() {
+  ScriptWrappableMarkingVisitor* GetScriptWrappableMarkingVisitor() {
     return script_wrappable_visitor_.get();
   }
 
@@ -300,7 +301,7 @@
   std::unique_ptr<Data> thread_debugger_;
 
   Persistent<ActiveScriptWrappableSet> active_script_wrappables_;
-  std::unique_ptr<ScriptWrappableVisitor> script_wrappable_visitor_;
+  std::unique_ptr<ScriptWrappableMarkingVisitor> script_wrappable_visitor_;
 
   RuntimeCallStats runtime_call_stats_;
 };
diff --git a/third_party/WebKit/Source/platform/exported/Platform.cpp b/third_party/WebKit/Source/platform/exported/Platform.cpp
index 366f5b9..5ff71d1 100644
--- a/third_party/WebKit/Source/platform/exported/Platform.cpp
+++ b/third_party/WebKit/Source/platform/exported/Platform.cpp
@@ -163,7 +163,8 @@
 
   // Pre-create the File thread so multiple threads can call FileTaskRunner() in
   // a non racy way later.
-  g_platform->file_thread_ = g_platform->CreateThread("File");
+  g_platform->file_thread_ =
+      g_platform->CreateThread(WebThreadCreationParams("File"));
 
   if (BlinkResourceCoordinatorBase::IsEnabled())
     RendererResourceCoordinator::Initialize();
@@ -220,7 +221,8 @@
   return nullptr;
 }
 
-std::unique_ptr<WebThread> Platform::CreateThread(const char* name) {
+std::unique_ptr<WebThread> Platform::CreateThread(
+    const WebThreadCreationParams& params) {
   return nullptr;
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp
index 68fa72c..4a17a56 100644
--- a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoderTest.cpp
@@ -225,8 +225,8 @@
   EXPECT_EQ(0, decode_request_count_);
 
   // Create a thread to rasterize PaintRecord.
-  std::unique_ptr<WebThread> thread =
-      Platform::Current()->CreateThread("RasterThread");
+  std::unique_ptr<WebThread> thread = Platform::Current()->CreateThread(
+      WebThreadCreationParams("RasterThread"));
   PostCrossThreadTask(
       *thread->GetWebTaskRunner(), FROM_HERE,
       CrossThreadBind(&RasterizeMain, CrossThreadUnretained(canvas_.get()),
diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp b/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp
index d1e1aed..cfba57067 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGeneratorTest.cpp
@@ -256,8 +256,8 @@
   // LocalFrame can now be decoded completely.
   SetFrameStatus(ImageFrame::kFrameComplete);
   AddNewData();
-  std::unique_ptr<WebThread> thread =
-      Platform::Current()->CreateThread("DecodeThread");
+  std::unique_ptr<WebThread> thread = Platform::Current()->CreateThread(
+      WebThreadCreationParams("DecodeThread"));
   PostCrossThreadTask(
       *thread->GetWebTaskRunner(), FROM_HERE,
       CrossThreadBind(&DecodeThreadMain, WTF::RetainedRef(generator_),
diff --git a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp
index 9e19081a..b0a2130c 100644
--- a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp
@@ -8,10 +8,8 @@
 #include "cc/layers/layer.h"
 #include "cc/layers/solid_color_layer.h"
 #include "cc/layers/surface_layer.h"
-#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "media/base/media_switches.h"
 #include "platform/mojo/MojoHelper.h"
 #include "platform/wtf/Functional.h"
@@ -25,46 +23,13 @@
 
 namespace blink {
 
-namespace {
-class SequenceSurfaceReferenceFactoryImpl
-    : public viz::SequenceSurfaceReferenceFactory {
- public:
-  SequenceSurfaceReferenceFactoryImpl(base::WeakPtr<SurfaceLayerBridge> bridge)
-      : bridge_(bridge) {}
-
- private:
-  ~SequenceSurfaceReferenceFactoryImpl() override = default;
-
-  // cc::SequenceSurfaceReferenceFactory implementation:
-  void RequireSequence(const viz::SurfaceId& id,
-                       const viz::SurfaceSequence& sequence) const override {
-    DCHECK(bridge_);
-    bridge_->RequireCallback(id, sequence);
-  }
-
-  void SatisfySequence(const viz::SurfaceSequence& sequence) const override {
-    if (bridge_)
-      bridge_->SatisfyCallback(sequence);
-  }
-
-  base::WeakPtr<SurfaceLayerBridge> bridge_;
-
-  DISALLOW_COPY_AND_ASSIGN(SequenceSurfaceReferenceFactoryImpl);
-};
-
-}  // namespace
-
 SurfaceLayerBridge::SurfaceLayerBridge(WebLayerTreeView* layer_tree_view,
                                        WebSurfaceLayerBridgeObserver* observer)
-    : weak_factory_(this),
-      observer_(observer),
+    : observer_(observer),
       binding_(this),
       frame_sink_id_(Platform::Current()->GenerateFrameSinkId()),
       parent_frame_sink_id_(layer_tree_view ? layer_tree_view->GetFrameSinkId()
                                             : viz::FrameSinkId()) {
-  ref_factory_ =
-      new SequenceSurfaceReferenceFactoryImpl(weak_factory_.GetWeakPtr());
-
   DCHECK(!service_.is_bound());
   mojom::blink::OffscreenCanvasProviderPtr provider;
   Platform::Current()->GetInterfaceProvider()->GetInterface(
@@ -83,15 +48,6 @@
   observer_ = nullptr;
 }
 
-void SurfaceLayerBridge::SatisfyCallback(const viz::SurfaceSequence& sequence) {
-  service_->Satisfy(sequence);
-}
-
-void SurfaceLayerBridge::RequireCallback(const viz::SurfaceId& surface_id,
-                                         const viz::SurfaceSequence& sequence) {
-  service_->Require(surface_id, sequence);
-}
-
 void SurfaceLayerBridge::CreateSolidColorLayer() {
   cc_layer_ = cc::SolidColorLayer::Create();
   cc_layer_->SetBackgroundColor(SK_ColorTRANSPARENT);
@@ -114,8 +70,7 @@
       web_layer_->RemoveFromParent();
     }
 
-    scoped_refptr<cc::SurfaceLayer> surface_layer =
-        cc::SurfaceLayer::Create(ref_factory_);
+    scoped_refptr<cc::SurfaceLayer> surface_layer = cc::SurfaceLayer::Create();
     surface_layer->SetPrimarySurfaceId(surface_info.id(), base::nullopt);
     surface_layer->SetFallbackSurfaceId(surface_info.id());
     surface_layer->SetStretchContentToFillBounds(true);
diff --git a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h
index 0361ef34..00340d75 100644
--- a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h
@@ -7,9 +7,7 @@
 
 #include <memory>
 #include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
 #include "components/viz/common/surfaces/surface_id.h"
-#include "components/viz/common/surfaces/surface_reference_factory.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "platform/PlatformExport.h"
 #include "public/platform/WebSurfaceLayerBridge.h"
@@ -41,8 +39,6 @@
 
   // Implementation of blink::mojom::blink::OffscreenCanvasSurfaceClient
   void OnFirstSurfaceActivation(const viz::SurfaceInfo&) override;
-  void SatisfyCallback(const viz::SurfaceSequence&);
-  void RequireCallback(const viz::SurfaceId&, const viz::SurfaceSequence&);
 
   // Implementation of WebSurfaceLayerBridge.
   WebLayer* GetWebLayer() const override { return web_layer_.get(); }
@@ -57,9 +53,6 @@
   scoped_refptr<cc::Layer> cc_layer_;
   std::unique_ptr<WebLayer> web_layer_;
 
-  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory_;
-  base::WeakPtrFactory<SurfaceLayerBridge> weak_factory_;
-
   WebSurfaceLayerBridgeObserver* observer_;
 
   mojo::Binding<blink::mojom::blink::OffscreenCanvasSurfaceClient> binding_;
diff --git a/third_party/WebKit/Source/platform/heap/HeapTest.cpp b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
index 0101c35..8909ac8 100644
--- a/third_party/WebKit/Source/platform/heap/HeapTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
@@ -479,8 +479,8 @@
   static void Test(ThreadedTesterBase* tester) {
     Vector<std::unique_ptr<WebThread>, kNumberOfThreads> threads;
     for (int i = 0; i < kNumberOfThreads; i++) {
-      threads.push_back(
-          Platform::Current()->CreateThread("blink gc testing thread"));
+      threads.push_back(Platform::Current()->CreateThread(
+          WebThreadCreationParams("blink gc testing thread")));
       PostCrossThreadTask(
           *threads.back()->GetWebTaskRunner(), FROM_HERE,
           CrossThreadBind(ThreadFunc, CrossThreadUnretained(tester)));
@@ -5467,7 +5467,8 @@
 
     MutexLocker locker(MainThreadMutex());
     std::unique_ptr<WebThread> worker_thread =
-        Platform::Current()->CreateThread("Test Worker Thread");
+        Platform::Current()->CreateThread(
+            WebThreadCreationParams("Test Worker Thread"));
     PostCrossThreadTask(*worker_thread->GetWebTaskRunner(), FROM_HERE,
                         CrossThreadBind(WorkerThreadMain));
 
@@ -5566,7 +5567,8 @@
 
     MutexLocker locker(MainThreadMutex());
     std::unique_ptr<WebThread> worker_thread =
-        Platform::Current()->CreateThread("Test Worker Thread");
+        Platform::Current()->CreateThread(
+            WebThreadCreationParams("Test Worker Thread"));
     PostCrossThreadTask(
         *worker_thread->GetWebTaskRunner(), FROM_HERE,
         CrossThreadBind(&MemberSameThreadCheckTester::WorkerThreadMain,
@@ -5609,7 +5611,8 @@
 
     MutexLocker locker(MainThreadMutex());
     std::unique_ptr<WebThread> worker_thread =
-        Platform::Current()->CreateThread("Test Worker Thread");
+        Platform::Current()->CreateThread(
+            WebThreadCreationParams("Test Worker Thread"));
     PostCrossThreadTask(
         *worker_thread->GetWebTaskRunner(), FROM_HERE,
         CrossThreadBind(&PersistentSameThreadCheckTester::WorkerThreadMain,
@@ -5652,7 +5655,8 @@
 
     MutexLocker locker(MainThreadMutex());
     std::unique_ptr<WebThread> worker_thread =
-        Platform::Current()->CreateThread("Test Worker Thread");
+        Platform::Current()->CreateThread(
+            WebThreadCreationParams("Test Worker Thread"));
     Persistent<MainThreadObject> main_thread_object = new MainThreadObject();
     PostCrossThreadTask(
         *worker_thread->GetWebTaskRunner(), FROM_HERE,
@@ -6450,8 +6454,8 @@
   // Step 1: Initiate a worker thread, and wait for |object| to get allocated on
   // the worker thread.
   MutexLocker main_thread_mutex_locker(MainThreadMutex());
-  std::unique_ptr<WebThread> worker_thread =
-      Platform::Current()->CreateThread("Test Worker Thread");
+  std::unique_ptr<WebThread> worker_thread = Platform::Current()->CreateThread(
+      WebThreadCreationParams("Test Worker Thread"));
   DestructorLockingObject* object = nullptr;
   PostCrossThreadTask(
       *worker_thread->GetWebTaskRunner(), FROM_HERE,
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceResponseTest.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceResponseTest.cpp
index caf0f866..12eace9 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceResponseTest.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceResponseTest.cpp
@@ -76,8 +76,8 @@
 
   ResourceResponse response(CreateTestResponse());
   RunHeaderRelatedTest(response);
-  std::unique_ptr<WebThread> thread =
-      Platform::Current()->CreateThread("WorkerThread");
+  std::unique_ptr<WebThread> thread = Platform::Current()->CreateThread(
+      WebThreadCreationParams("WorkerThread"));
   PostCrossThreadTask(*thread->GetWebTaskRunner(), FROM_HERE,
                       CrossThreadBind(&RunInThread));
   thread.reset();
diff --git a/third_party/WebKit/Source/platform/memory_profiler/DEPS b/third_party/WebKit/Source/platform/memory_profiler/DEPS
deleted file mode 100644
index 70be7bf..0000000
--- a/third_party/WebKit/Source/platform/memory_profiler/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
-    "+base",
-]
-
diff --git a/third_party/WebKit/Source/platform/memory_profiler/OWNERS b/third_party/WebKit/Source/platform/memory_profiler/OWNERS
deleted file mode 100644
index 87c96616..0000000
--- a/third_party/WebKit/Source/platform/memory_profiler/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-alph@chromium.org
diff --git a/third_party/WebKit/Source/platform/memory_profiler/SamplingNativeHeapProfiler.cpp b/third_party/WebKit/Source/platform/memory_profiler/SamplingNativeHeapProfiler.cpp
deleted file mode 100644
index f3f3cb5..0000000
--- a/third_party/WebKit/Source/platform/memory_profiler/SamplingNativeHeapProfiler.cpp
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "platform/memory_profiler/SamplingNativeHeapProfiler.h"
-
-#include <cmath>
-
-#include "base/allocator/allocator_shim.h"
-#include "base/allocator/features.h"
-#include "base/atomicops.h"
-#include "base/bits.h"
-#include "base/debug/alias.h"
-#include "base/debug/stack_trace.h"
-#include "base/memory/singleton.h"
-#include "base/rand_util.h"
-#include "build/build_config.h"
-
-namespace blink {
-
-using base::allocator::AllocatorDispatch;
-using base::subtle::Atomic32;
-using base::subtle::AtomicWord;
-
-namespace {
-
-const unsigned kMagicSignature = 0x14690ca5;
-const unsigned kDefaultAlignment = 16;
-const unsigned kSkipAllocatorFrames = 4;
-
-Atomic32 g_running;
-Atomic32 g_deterministic;
-AtomicWord g_cumulative_counter = 0;
-AtomicWord g_threshold;
-AtomicWord g_sampling_interval = 128 * 1024;
-
-static void* AllocFn(const AllocatorDispatch* self,
-                     size_t size,
-                     void* context) {
-  SamplingNativeHeapProfiler::Sample sample;
-  if (LIKELY(!base::subtle::NoBarrier_Load(&g_running) ||
-             !SamplingNativeHeapProfiler::CreateAllocSample(size, &sample))) {
-    return self->next->alloc_function(self->next, size, context);
-  }
-  void* address =
-      self->next->alloc_function(self->next, size + kDefaultAlignment, context);
-  return SamplingNativeHeapProfiler::GetInstance()->RecordAlloc(
-      sample, address, kDefaultAlignment, kSkipAllocatorFrames);
-}
-
-static void* AllocZeroInitializedFn(const AllocatorDispatch* self,
-                                    size_t n,
-                                    size_t size,
-                                    void* context) {
-  SamplingNativeHeapProfiler::Sample sample;
-  if (LIKELY(
-          !base::subtle::NoBarrier_Load(&g_running) ||
-          !SamplingNativeHeapProfiler::CreateAllocSample(n * size, &sample))) {
-    return self->next->alloc_zero_initialized_function(self->next, n, size,
-                                                       context);
-  }
-  void* address = self->next->alloc_zero_initialized_function(
-      self->next, 1, n * size + kDefaultAlignment, context);
-  return SamplingNativeHeapProfiler::GetInstance()->RecordAlloc(
-      sample, address, kDefaultAlignment, kSkipAllocatorFrames);
-}
-
-static void* AllocAlignedFn(const AllocatorDispatch* self,
-                            size_t alignment,
-                            size_t size,
-                            void* context) {
-  SamplingNativeHeapProfiler::Sample sample;
-  if (LIKELY(!base::subtle::NoBarrier_Load(&g_running) ||
-             !SamplingNativeHeapProfiler::CreateAllocSample(size, &sample))) {
-    return self->next->alloc_aligned_function(self->next, alignment, size,
-                                              context);
-  }
-  size_t offset = base::bits::Align(sizeof(kMagicSignature), alignment);
-  void* address = self->next->alloc_aligned_function(self->next, alignment,
-                                                     size + offset, context);
-  return SamplingNativeHeapProfiler::GetInstance()->RecordAlloc(
-      sample, address, offset, kSkipAllocatorFrames);
-}
-
-static void* ReallocFn(const AllocatorDispatch* self,
-                       void* address,
-                       size_t size,
-                       void* context) {
-  // Note: size == 0 actually performs free.
-  SamplingNativeHeapProfiler::Sample sample;
-  bool will_sample =
-      base::subtle::NoBarrier_Load(&g_running) &&
-      SamplingNativeHeapProfiler::CreateAllocSample(size, &sample);
-  char* client_address = reinterpret_cast<char*>(address);
-  if (UNLIKELY(address &&
-               reinterpret_cast<unsigned*>(address)[-1] == kMagicSignature)) {
-    address = SamplingNativeHeapProfiler::GetInstance()->RecordFree(address);
-  }
-  intptr_t prev_offset = client_address - reinterpret_cast<char*>(address);
-  bool was_sampled = prev_offset;
-  if (LIKELY(!was_sampled && !will_sample))
-    return self->next->realloc_function(self->next, address, size, context);
-  size_t size_to_allocate = will_sample ? size + kDefaultAlignment : size;
-  address = self->next->realloc_function(self->next, address, size_to_allocate,
-                                         context);
-  if (will_sample) {
-    return SamplingNativeHeapProfiler::GetInstance()->RecordAlloc(
-        sample, address, kDefaultAlignment, kSkipAllocatorFrames,
-        client_address && prev_offset != kDefaultAlignment);
-  }
-  DCHECK(was_sampled && !will_sample);
-  memmove(address, reinterpret_cast<char*>(address) + prev_offset, size);
-  return address;
-}
-
-static void FreeFn(const AllocatorDispatch* self,
-                   void* address,
-                   void* context) {
-  if (UNLIKELY(address &&
-               reinterpret_cast<unsigned*>(address)[-1] == kMagicSignature)) {
-    address = SamplingNativeHeapProfiler::GetInstance()->RecordFree(address);
-  }
-  self->next->free_function(self->next, address, context);
-}
-
-static size_t GetSizeEstimateFn(const AllocatorDispatch* self,
-                                void* address,
-                                void* context) {
-  size_t ret =
-      self->next->get_size_estimate_function(self->next, address, context);
-  return ret;
-}
-
-static unsigned BatchMallocFn(const AllocatorDispatch* self,
-                              size_t size,
-                              void** results,
-                              unsigned num_requested,
-                              void* context) {
-  CHECK(false) << "Not implemented.";
-  return 0;
-}
-
-static void BatchFreeFn(const AllocatorDispatch* self,
-                        void** to_be_freed,
-                        unsigned num_to_be_freed,
-                        void* context) {
-  CHECK(false) << "Not implemented.";
-}
-
-static void FreeDefiniteSizeFn(const AllocatorDispatch* self,
-                               void* ptr,
-                               size_t size,
-                               void* context) {
-  CHECK(false) << "Not implemented.";
-}
-
-AllocatorDispatch g_allocator_dispatch = {&AllocFn,
-                                          &AllocZeroInitializedFn,
-                                          &AllocAlignedFn,
-                                          &ReallocFn,
-                                          &FreeFn,
-                                          &GetSizeEstimateFn,
-                                          &BatchMallocFn,
-                                          &BatchFreeFn,
-                                          &FreeDefiniteSizeFn,
-                                          nullptr};
-
-}  // namespace
-
-// static
-void SamplingNativeHeapProfiler::InstallAllocatorHooksOnce() {
-  static bool hook_installed = InstallAllocatorHooks();
-  base::debug::Alias(&hook_installed);
-}
-
-// static
-bool SamplingNativeHeapProfiler::InstallAllocatorHooks() {
-#if BUILDFLAG(USE_ALLOCATOR_SHIM)
-  base::allocator::InsertAllocatorDispatch(&g_allocator_dispatch);
-#else
-  base::debug::Alias(&g_allocator_dispatch);
-  CHECK(false)
-      << "Can't enable native sampling heap profiler without the shim.";
-#endif  // BUILDFLAG(USE_ALLOCATOR_SHIM)
-  return true;
-}
-
-void SamplingNativeHeapProfiler::Start() {
-  InstallAllocatorHooksOnce();
-  base::subtle::Release_Store(&g_threshold, g_sampling_interval);
-  base::subtle::Release_Store(&g_running, true);
-}
-
-void SamplingNativeHeapProfiler::Stop() {
-  base::subtle::Release_Store(&g_running, false);
-}
-
-void SamplingNativeHeapProfiler::SetSamplingInterval(
-    unsigned sampling_interval) {
-  // TODO(alph): Update the threshold. Make sure not to leave it in a state
-  // when the threshold is already crossed.
-  base::subtle::Release_Store(&g_sampling_interval, sampling_interval);
-}
-
-// static
-intptr_t SamplingNativeHeapProfiler::GetNextSampleInterval(uint64_t interval) {
-  if (base::subtle::NoBarrier_Load(&g_deterministic))
-    return static_cast<intptr_t>(interval);
-  // We sample with a Poisson process, with constant average sampling
-  // interval. This follows the exponential probability distribution with
-  // parameter λ = 1/interval where |interval| is the average number of bytes
-  // between samples.
-  // Let u be a uniformly distributed random number between 0 and 1, then
-  // next_sample = -ln(u) / λ
-  double uniform = base::RandDouble();
-  double value = -log(uniform) * interval;
-  intptr_t min_value = sizeof(intptr_t);
-  // We limit the upper bound of a sample interval to make sure we don't have
-  // huge gaps in the sampling stream. Probability of the upper bound gets hit
-  // is exp(-20) ~ 2e-9, so it should not skew the distibution.
-  intptr_t max_value = interval * 20;
-  if (UNLIKELY(value < min_value))
-    return min_value;
-  if (UNLIKELY(value > max_value))
-    return max_value;
-  return static_cast<intptr_t>(value);
-}
-
-// static
-bool SamplingNativeHeapProfiler::CreateAllocSample(size_t size,
-                                                   Sample* sample) {
-  // Lock-free algorithm that adds the allocation size to the cumulative
-  // counter. When the counter reaches threshold, it picks a single thread
-  // that will record the sample and reset the counter.
-  // The thread that records the sample returns true, others return false.
-  AtomicWord threshold = base::subtle::NoBarrier_Load(&g_threshold);
-  AtomicWord accumulated = base::subtle::NoBarrier_AtomicIncrement(
-      &g_cumulative_counter, static_cast<AtomicWord>(size));
-  if (LIKELY(accumulated < threshold))
-    return false;
-
-  // Return if it was another thread that in fact crossed the threshold.
-  // That other thread is responsible for recording the sample.
-  if (UNLIKELY(accumulated >= threshold + static_cast<AtomicWord>(size)))
-    return false;
-
-  intptr_t next_interval =
-      GetNextSampleInterval(base::subtle::NoBarrier_Load(&g_sampling_interval));
-  base::subtle::Release_Store(&g_threshold, next_interval);
-  accumulated =
-      base::subtle::NoBarrier_AtomicExchange(&g_cumulative_counter, 0);
-
-  DCHECK_NE(size, 0u);
-  sample->size = size;
-  sample->count = std::max<size_t>(1, (accumulated + size / 2) / size);
-  return true;
-}
-
-void SamplingNativeHeapProfiler::RecordStackTrace(Sample* sample,
-                                                  unsigned skip_frames) {
-  // TODO(alph): Consider using debug::TraceStackFramePointers. It should be
-  // somewhat faster than base::debug::StackTrace.
-  base::debug::StackTrace trace;
-  size_t count;
-  void* const* addresses = const_cast<void* const*>(trace.Addresses(&count));
-  // Skip SamplingNativeHeapProfiler frames.
-  sample->stack.insert(
-      sample->stack.end(), &addresses[skip_frames],
-      &addresses[std::max(count, static_cast<size_t>(skip_frames))]);
-}
-
-void* SamplingNativeHeapProfiler::RecordAlloc(Sample& sample,
-                                              void* address,
-                                              unsigned offset,
-                                              unsigned skip_frames,
-                                              bool preserve_data) {
-  // TODO(alph): It's better to use a recursive mutex and move the check
-  // inside the critical section. This way we won't skip the sample generation
-  // on one thread if another thread is recording a sample.
-  if (entered_.Get())
-    return address;
-  base::AutoLock lock(mutex_);
-  entered_.Set(true);
-  sample.offset = offset;
-  void* client_address = reinterpret_cast<char*>(address) + offset;
-  if (preserve_data)
-    memmove(client_address, address, sample.size);
-  RecordStackTrace(&sample, skip_frames);
-  samples_.insert(std::make_pair(client_address, sample));
-  if (offset)
-    reinterpret_cast<unsigned*>(client_address)[-1] = kMagicSignature;
-  entered_.Set(false);
-  return client_address;
-}
-
-void* SamplingNativeHeapProfiler::RecordFree(void* address) {
-  base::AutoLock lock(mutex_);
-  auto& samples = GetInstance()->samples_;
-  auto it = samples.find(address);
-  if (it == samples.end())
-    return address;
-  void* address_to_free = reinterpret_cast<char*>(address) - it->second.offset;
-  samples.erase(it);
-  if (it->second.offset)
-    reinterpret_cast<unsigned*>(address)[-1] = 0;
-  return address_to_free;
-}
-
-// static
-SamplingNativeHeapProfiler* SamplingNativeHeapProfiler::GetInstance() {
-  return base::Singleton<SamplingNativeHeapProfiler>::get();
-}
-
-// static
-void SamplingNativeHeapProfiler::SuppressRandomnessForTest() {
-  base::subtle::Release_Store(&g_deterministic, true);
-}
-
-std::vector<SamplingNativeHeapProfiler::Sample>
-SamplingNativeHeapProfiler::GetSamples() {
-  base::AutoLock lock(mutex_);
-  CHECK(!entered_.Get());
-  entered_.Set(true);
-  std::vector<Sample> samples;
-  for (auto it = samples_.begin(); it != samples_.end(); ++it)
-    samples.push_back(it->second);
-  entered_.Set(false);
-  return samples;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/memory_profiler/SamplingNativeHeapProfiler.h b/third_party/WebKit/Source/platform/memory_profiler/SamplingNativeHeapProfiler.h
deleted file mode 100644
index 21ad80e..0000000
--- a/third_party/WebKit/Source/platform/memory_profiler/SamplingNativeHeapProfiler.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SamplingNativeHeapProfiler_h
-#define SamplingNativeHeapProfiler_h
-
-#include <unordered_map>
-#include <vector>
-
-#include "base/atomicops.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_local.h"
-#include "platform/PlatformExport.h"
-
-namespace base {
-template <typename T>
-struct DefaultSingletonTraits;
-}
-
-namespace blink {
-
-class PLATFORM_EXPORT SamplingNativeHeapProfiler {
- public:
-  struct Sample {
-    size_t size;
-    size_t count;
-    unsigned offset;
-    std::vector<void*> stack;
-  };
-
-  SamplingNativeHeapProfiler() = default;
-
-  void Start();
-  void Stop();
-  void SetSamplingInterval(unsigned sampling_interval);
-  void SuppressRandomnessForTest();
-
-  std::vector<Sample> GetSamples();
-
-  static SamplingNativeHeapProfiler* GetInstance();
-
-  static inline bool CreateAllocSample(size_t, Sample*);
-  void* RecordAlloc(Sample&,
-                    void* address,
-                    unsigned offset,
-                    unsigned skip_frames,
-                    bool preserve_data = false);
-  void* RecordFree(void* address);
-
- private:
-  static void InstallAllocatorHooksOnce();
-  static bool InstallAllocatorHooks();
-  static intptr_t GetNextSampleInterval(uint64_t base_interval);
-
-  void RecordStackTrace(Sample*, unsigned skip_frames);
-
-  base::ThreadLocalBoolean entered_;
-  base::Lock mutex_;
-  std::unordered_map<void*, Sample> samples_;
-
-  friend struct base::DefaultSingletonTraits<SamplingNativeHeapProfiler>;
-
-  DISALLOW_COPY_AND_ASSIGN(SamplingNativeHeapProfiler);
-};
-
-}  // namespace blink
-
-#endif  // SamplingNativeHeapProfiler_h
diff --git a/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp b/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp
index 16a7882..889d740 100644
--- a/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp
+++ b/third_party/WebKit/Source/platform/mhtml/MHTMLArchive.cpp
@@ -51,7 +51,6 @@
 namespace {
 
 const size_t kMaximumLineLength = 76;
-const char kCrlfLineEnding[] = "\r\n";
 
 const char kRFC2047EncodingPrefix[] = "=?utf-8?Q?";
 const size_t kRFC2047EncodingPrefixLength = 10;
@@ -86,7 +85,7 @@
   void DidFinishLine(bool last_line, Vector<char>& out) override {
     if (!last_line) {
       out.push_back('=');
-      out.Append(kCrlfLineEnding, strlen(kCrlfLineEnding));
+      out.Append("\r\n", 2);
     }
   }
 };
@@ -115,7 +114,7 @@
   void DidFinishLine(bool last_line, Vector<char>& out) override {
     out.Append(kRFC2047EncodingSuffix, kRFC2047EncodingSuffixLength);
     if (!last_line) {
-      out.Append(kCrlfLineEnding, strlen(kCrlfLineEnding));
+      out.Append("\r\n", 2);
       out.push_back(' ');
     }
   }
diff --git a/third_party/WebKit/Source/platform/runtime_enabled_features.json5 b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
index e25617ce..c5ea098 100644
--- a/third_party/WebKit/Source/platform/runtime_enabled_features.json5
+++ b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
@@ -502,6 +502,11 @@
       status: "test",
     },
     {
+      name: "ImplicitRootScroller",
+      status: "experimental",
+      settable_from_internals: true,
+    },
+    {
       name: "IncrementalShadowDOM",
     },
     {
diff --git a/third_party/WebKit/Source/platform/scheduler/BUILD.gn b/third_party/WebKit/Source/platform/scheduler/BUILD.gn
index 6b0dcb8..eac970ce 100644
--- a/third_party/WebKit/Source/platform/scheduler/BUILD.gn
+++ b/third_party/WebKit/Source/platform/scheduler/BUILD.gn
@@ -52,6 +52,8 @@
     "child/metrics_helper.h",
     "child/pollable_thread_safe_flag.cc",
     "child/pollable_thread_safe_flag.h",
+    "child/process_state.cc",
+    "child/process_state.h",
     "child/scheduler_helper.cc",
     "child/scheduler_helper.h",
     "child/single_thread_idle_task_runner.cc",
diff --git a/third_party/WebKit/Source/platform/scheduler/child/metrics_helper.cc b/third_party/WebKit/Source/platform/scheduler/child/metrics_helper.cc
index 083d41d..ce59e62 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/metrics_helper.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/metrics_helper.cc
@@ -4,6 +4,8 @@
 
 #include "platform/scheduler/child/metrics_helper.h"
 
+#include "platform/scheduler/child/process_state.h"
+
 namespace blink {
 namespace scheduler {
 
@@ -22,7 +24,15 @@
       thread_task_duration_reporter_(
           "RendererScheduler.TaskDurationPerThreadType"),
       thread_task_cpu_duration_reporter_(
-          "RendererScheduler.TaskCPUDurationPerThreadType") {}
+          "RendererScheduler.TaskCPUDurationPerThreadType"),
+      foreground_thread_task_duration_reporter_(
+          "RendererScheduler.TaskDurationPerThreadType.Foreground"),
+      foreground_thread_task_cpu_duration_reporter_(
+          "RendererScheduler.TaskCPUDurationPerThreadType.Foreground"),
+      background_thread_task_duration_reporter_(
+          "RendererScheduler.TaskDurationPerThreadType.Background"),
+      background_thread_task_cpu_duration_reporter_(
+          "RendererScheduler.TaskCPUDurationPerThreadType.Background") {}
 
 MetricsHelper::~MetricsHelper() {}
 
@@ -43,11 +53,30 @@
     base::TimeTicks start_time,
     base::TimeTicks end_time,
     base::Optional<base::TimeDelta> thread_time) {
-  thread_task_duration_reporter_.RecordTask(thread_type_,
-                                            end_time - start_time);
-  if (thread_time) {
-    thread_task_cpu_duration_reporter_.RecordTask(thread_type_,
-                                                  thread_time.value());
+  base::TimeDelta wall_time = end_time - start_time;
+
+  thread_task_duration_reporter_.RecordTask(thread_type_, wall_time);
+
+  bool backgrounded = internal::ProcessState::Get()->is_process_backgrounded;
+
+  if (backgrounded) {
+    background_thread_task_duration_reporter_.RecordTask(thread_type_,
+                                                         wall_time);
+  } else {
+    foreground_thread_task_duration_reporter_.RecordTask(thread_type_,
+                                                         wall_time);
+  }
+
+  if (!thread_time)
+    return;
+  thread_task_cpu_duration_reporter_.RecordTask(thread_type_,
+                                                thread_time.value());
+  if (backgrounded) {
+    background_thread_task_cpu_duration_reporter_.RecordTask(
+        thread_type_, thread_time.value());
+  } else {
+    foreground_thread_task_cpu_duration_reporter_.RecordTask(
+        thread_type_, thread_time.value());
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/child/metrics_helper.h b/third_party/WebKit/Source/platform/scheduler/child/metrics_helper.h
index 9877114e..15c9b8b4 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/metrics_helper.h
+++ b/third_party/WebKit/Source/platform/scheduler/child/metrics_helper.h
@@ -51,6 +51,14 @@
 
   TaskDurationMetricReporter<ThreadType> thread_task_duration_reporter_;
   TaskDurationMetricReporter<ThreadType> thread_task_cpu_duration_reporter_;
+  TaskDurationMetricReporter<ThreadType>
+      foreground_thread_task_duration_reporter_;
+  TaskDurationMetricReporter<ThreadType>
+      foreground_thread_task_cpu_duration_reporter_;
+  TaskDurationMetricReporter<ThreadType>
+      background_thread_task_duration_reporter_;
+  TaskDurationMetricReporter<ThreadType>
+      background_thread_task_cpu_duration_reporter_;
 
   DISALLOW_COPY_AND_ASSIGN(MetricsHelper);
 };
diff --git a/third_party/WebKit/Source/platform/scheduler/child/process_state.cc b/third_party/WebKit/Source/platform/scheduler/child/process_state.cc
new file mode 100644
index 0000000..85b9e3e
--- /dev/null
+++ b/third_party/WebKit/Source/platform/scheduler/child/process_state.cc
@@ -0,0 +1,26 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/scheduler/child/process_state.h"
+
+#include "base/lazy_instance.h"
+
+namespace blink {
+namespace scheduler {
+namespace internal {
+
+namespace {
+
+base::LazyInstance<ProcessState>::Leaky g_process_state;
+
+}  // namespace
+
+// static
+ProcessState* ProcessState::Get() {
+  return g_process_state.Pointer();
+}
+
+}  // namespace internal
+}  // namespace scheduler
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/process_state.h b/third_party/WebKit/Source/platform/scheduler/child/process_state.h
new file mode 100644
index 0000000..8c34534
--- /dev/null
+++ b/third_party/WebKit/Source/platform/scheduler/child/process_state.h
@@ -0,0 +1,22 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <atomic>
+
+namespace blink {
+namespace scheduler {
+namespace internal {
+
+// Helper lock-free struct to share main state of the process between threads
+// for recording methods.
+// This class should not be used for synchronization between threads.
+struct ProcessState {
+  static ProcessState* Get();
+
+  std::atomic_bool is_process_backgrounded;
+};
+
+}  // namespace internal
+}  // namespace scheduler
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
index b5746de..69b2767 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -25,6 +25,7 @@
 #include "platform/scheduler/base/task_queue_impl.h"
 #include "platform/scheduler/base/task_queue_selector.h"
 #include "platform/scheduler/base/virtual_time_domain.h"
+#include "platform/scheduler/child/process_state.h"
 #include "platform/scheduler/renderer/auto_advancing_virtual_time_domain.h"
 #include "platform/scheduler/renderer/task_queue_throttler.h"
 #include "platform/scheduler/renderer/web_view_scheduler_impl.h"
@@ -271,6 +272,9 @@
   }
   delay_for_background_tab_stopping_ = base::TimeDelta::FromMilliseconds(
       delay_for_background_tab_stopping_millis);
+
+  internal::ProcessState::Get()->is_process_backgrounded =
+      main_thread_only().renderer_backgrounded;
 }
 
 RendererSchedulerImpl::~RendererSchedulerImpl() {
@@ -880,6 +884,7 @@
   }
 
   main_thread_only().renderer_backgrounded = backgrounded;
+  internal::ProcessState::Get()->is_process_backgrounded = backgrounded;
 
   main_thread_only().background_status_changed_at = tick_clock()->NowTicks();
   seqlock_queueing_time_estimator_.seqlock.WriteBegin();
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollCustomization.cpp b/third_party/WebKit/Source/platform/scroll/ScrollCustomization.cpp
new file mode 100644
index 0000000..40d7d5a
--- /dev/null
+++ b/third_party/WebKit/Source/platform/scroll/ScrollCustomization.cpp
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/scroll/ScrollCustomization.h"
+
+namespace blink {
+namespace ScrollCustomization {
+
+ScrollDirection GetScrollDirectionFromDeltas(double delta_x, double delta_y) {
+  // TODO(ekaramad, tdresser): Find out the right value for kEpsilon here (see
+  // https://crbug.com/510550).
+  const double kEpsilon = 0.1f;
+
+  ScrollDirection direction = kScrollDirectionNone;
+  if (delta_x > kEpsilon)
+    direction |= kScrollDirectionPanRight;
+  if (delta_x < -kEpsilon)
+    direction |= kScrollDirectionPanLeft;
+  if (delta_y > kEpsilon)
+    direction |= kScrollDirectionPanDown;
+  if (delta_y < -kEpsilon)
+    direction |= kScrollDirectionPanUp;
+
+  if (!direction) {
+    // TODO(ekaramad, sahel): Remove this and perhaps replace with a DCHECK when
+    // issue https://crbug.com/728214 is fixed.
+    return kScrollDirectionAuto;
+  }
+
+  return direction;
+}
+
+}  // namespace ScrollCustomization
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollCustomization.h b/third_party/WebKit/Source/platform/scroll/ScrollCustomization.h
new file mode 100644
index 0000000..54f05b6
--- /dev/null
+++ b/third_party/WebKit/Source/platform/scroll/ScrollCustomization.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ScrollCustomization_h
+#define ScrollCustomization_h
+
+#include <stdint.h>
+
+#include "platform/PlatformExport.h"
+
+namespace blink {
+namespace ScrollCustomization {
+using ScrollDirection = uint8_t;
+
+constexpr ScrollDirection kScrollDirectionNone = 0;
+constexpr ScrollDirection kScrollDirectionPanLeft = 1 << 0;
+constexpr ScrollDirection kScrollDirectionPanRight = 1 << 1;
+constexpr ScrollDirection kScrollDirectionPanX =
+    kScrollDirectionPanLeft | kScrollDirectionPanRight;
+constexpr ScrollDirection kScrollDirectionPanUp = 1 << 2;
+constexpr ScrollDirection kScrollDirectionPanDown = 1 << 3;
+constexpr ScrollDirection kScrollDirectionPanY =
+    kScrollDirectionPanUp | kScrollDirectionPanDown;
+constexpr ScrollDirection kScrollDirectionAuto =
+    kScrollDirectionPanX | kScrollDirectionPanY;
+
+PLATFORM_EXPORT ScrollDirection GetScrollDirectionFromDeltas(double delta_x,
+                                                             double delta_y);
+}  // namespace ScrollCustomization
+}  // namespace blink
+
+#endif  // ScrollCustomization_h
diff --git a/third_party/WebKit/Source/platform/testing/ImageDecodeBench.cpp b/third_party/WebKit/Source/platform/testing/ImageDecodeBench.cpp
index 361aff4..2fb287b 100644
--- a/third_party/WebKit/Source/platform/testing/ImageDecodeBench.cpp
+++ b/third_party/WebKit/Source/platform/testing/ImageDecodeBench.cpp
@@ -14,8 +14,8 @@
 // the decoded image frame md5 and output that value.
 //
 // TODO(noel): Consider integrating this tool in Chrome telemetry for realz,
-// using the image corpii used to assess Blink image decode performance. Refer
-// to http://crbug.com/398235#c103 and http://crbug.com/258324#c5
+// using the image corpora used to assess Blink image decode performance. See
+// http://crbug.com/398235#c103 and http://crbug.com/258324#c5
 
 #include <fstream>
 
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithMockScheduler.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithMockScheduler.cpp
index 3d0410c..f472c3d 100644
--- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithMockScheduler.cpp
+++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithMockScheduler.cpp
@@ -61,9 +61,10 @@
 }
 
 std::unique_ptr<WebThread>
-TestingPlatformSupportWithMockScheduler::CreateThread(const char* name) {
+TestingPlatformSupportWithMockScheduler::CreateThread(
+    const WebThreadCreationParams& params) {
   std::unique_ptr<scheduler::WebThreadBase> thread =
-      scheduler::WebThreadBase::CreateWorkerThread(name,
+      scheduler::WebThreadBase::CreateWorkerThread(params.name,
                                                    base::Thread::Options());
   thread->Init();
   WaitableEvent event;
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithMockScheduler.h b/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithMockScheduler.h
index bebebb1..740bcf4 100644
--- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithMockScheduler.h
+++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupportWithMockScheduler.h
@@ -32,7 +32,8 @@
   ~TestingPlatformSupportWithMockScheduler() override;
 
   // Platform:
-  std::unique_ptr<WebThread> CreateThread(const char* name) override;
+  std::unique_ptr<WebThread> CreateThread(
+      const WebThreadCreationParams&) override;
   WebThread* CurrentThread() override;
 
   // Runs a single task.
diff --git a/third_party/WebKit/Source/platform/text/QuotedPrintable.cpp b/third_party/WebKit/Source/platform/text/QuotedPrintable.cpp
index 9f80140..9a7e7d50 100644
--- a/third_party/WebKit/Source/platform/text/QuotedPrintable.cpp
+++ b/third_party/WebKit/Source/platform/text/QuotedPrintable.cpp
@@ -34,8 +34,6 @@
 
 namespace blink {
 
-static const char kCrlfLineEnding[] = "\r\n";
-
 static size_t LengthOfLineEndingAtIndex(const char* input,
                                         size_t input_length,
                                         size_t index) {
@@ -84,7 +82,7 @@
       size_t length_of_line_ending =
           LengthOfLineEndingAtIndex(input, input_length, i);
       if (length_of_line_ending) {
-        out.Append(kCrlfLineEnding, strlen(kCrlfLineEnding));
+        out.Append("\r\n", 2);
         current_line_length = 0;
         i += (length_of_line_ending -
               1);  // -1 because we'll ++ in the for() above.
diff --git a/third_party/WebKit/common/service_worker/service_worker_object.mojom b/third_party/WebKit/common/service_worker/service_worker_object.mojom
index c16be3e..cf1c05f 100644
--- a/third_party/WebKit/common/service_worker/service_worker_object.mojom
+++ b/third_party/WebKit/common/service_worker/service_worker_object.mojom
@@ -26,4 +26,20 @@
 
   // ServiceWorker#scriptURL
   url.mojom.Url url;
+
+  // This object's host in the browser process.
+  associated ServiceWorkerObjectHost? host_ptr_info;
+};
+
+// The browser-side host of one ServiceWorker JavaScript object. The renderer
+// uses this interface to ask the browser process to do operations needed to
+// implement ServiceWorker methods.
+interface ServiceWorkerObjectHost {
+  // TODO(leonhsl): Implement all methods.
+  // Replace ServiceWorkerHostMsg_PostMessageToWorker.
+  // PostMessage(string message, url.mojom.Origin source_origin,
+  //     array<handle<message_pipe>> sent_message_ports);
+
+  // Replace ServiceWorkerHostMsg_TerminateWorker.
+  // Terminate();
 };
diff --git a/third_party/WebKit/public/blink_typemaps.gni b/third_party/WebKit/public/blink_typemaps.gni
index b2be8d2..bd89122f 100644
--- a/third_party/WebKit/public/blink_typemaps.gni
+++ b/third_party/WebKit/public/blink_typemaps.gni
@@ -12,7 +12,6 @@
   "//services/viz/public/cpp/compositing/returned_resource.typemap",
   "//services/viz/public/cpp/compositing/surface_id.typemap",
   "//services/viz/public/cpp/compositing/surface_info.typemap",
-  "//services/viz/public/cpp/compositing/surface_sequence.typemap",
   "//skia/public/interfaces/skbitmap_for_blink.typemap",
   "//ui/gfx/mojo/gpu_fence_handle_for_blink.typemap",
 ]
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h
index 0da86d4..7d59e4f 100644
--- a/third_party/WebKit/public/platform/Platform.h
+++ b/third_party/WebKit/public/platform/Platform.h
@@ -135,6 +135,7 @@
 class WebTaskRunner;
 class WebThemeEngine;
 class WebThread;
+struct WebThreadCreationParams;
 class WebTrialTokenValidator;
 class WebURLLoaderMockFactory;
 class WebURLResponse;
@@ -405,7 +406,8 @@
   // Threads -------------------------------------------------------
 
   // Creates an embedder-defined thread.
-  virtual std::unique_ptr<WebThread> CreateThread(const char* name);
+  virtual std::unique_ptr<WebThread> CreateThread(
+      const WebThreadCreationParams&);
 
   // Creates a WebAudio-specific thread with the elevated priority. Do NOT use
   // for any other purpose.
diff --git a/third_party/WebKit/public/platform/WebThread.h b/third_party/WebKit/public/platform/WebThread.h
index c983c13a..844e4147 100644
--- a/third_party/WebKit/public/platform/WebThread.h
+++ b/third_party/WebKit/public/platform/WebThread.h
@@ -46,6 +46,12 @@
 // Always an integer value.
 typedef uintptr_t PlatformThreadId;
 
+struct BLINK_PLATFORM_EXPORT WebThreadCreationParams {
+  explicit WebThreadCreationParams(const char* name);
+
+  const char* name;
+};
+
 // Provides an interface to an embedder-defined thread implementation.
 //
 // Deleting the thread blocks until all pending, non-delayed tasks have been
diff --git a/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom b/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
index 68f944ee..6494220 100644
--- a/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
+++ b/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
@@ -8,12 +8,11 @@
 import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
 import "services/viz/public/interfaces/compositing/surface_id.mojom";
 import "services/viz/public/interfaces/compositing/surface_info.mojom";
-import "services/viz/public/interfaces/compositing/surface_sequence.mojom";
 
-interface OffscreenCanvasSurface {
-  Require(viz.mojom.SurfaceId surface_id, viz.mojom.SurfaceSequence sequence);
-  Satisfy(viz.mojom.SurfaceSequence sequence);
-};
+// The renderer main thread can shutdown the offscreen canvas by closing this
+// interface.
+// TODO(kylechar): Refactor so this empty interface isn't needed.
+interface OffscreenCanvasSurface {};
 
 interface OffscreenCanvasSurfaceClient {
   OnFirstSurfaceActivation(viz.mojom.SurfaceInfo surface_info);
diff --git a/third_party/webrtc_overrides/runtime_enabled_features.cc b/third_party/webrtc_overrides/runtime_enabled_features.cc
index 5aef651..bbb5deba 100644
--- a/third_party/webrtc_overrides/runtime_enabled_features.cc
+++ b/third_party/webrtc_overrides/runtime_enabled_features.cc
@@ -1,23 +1,22 @@
 // Copyright 2018 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+//
+// Define webrtc::runtime_features::IsFeatureEnabled to provide webrtc with a
+// chromium runtime flags access.
 
 #include "base/feature_list.h"
 #include "third_party/webrtc/system_wrappers/include/runtime_enabled_features.h"
 
-// Define webrtc::runtime_features::IsFeatureEnabled to provide webrtc with a
-// chromium runtime flags access.
-
 namespace webrtc {
 
 namespace runtime_enabled_features {
 
-
 const base::Feature kWebRtcDualStreamMode{"WebRTC-DualStreamMode",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
 bool IsFeatureEnabled(std::string feature_name) {
-  if (feature_name == "WebRtcDualStreamMode")
+  if (feature_name == kDualStreamModeFeatureName)
     return base::FeatureList::IsEnabled(kWebRtcDualStreamMode);
   return false;
 }
diff --git a/tools/clang/scripts/run_tool.py b/tools/clang/scripts/run_tool.py
index 842eba0..ef887e8 100755
--- a/tools/clang/scripts/run_tool.py
+++ b/tools/clang/scripts/run_tool.py
@@ -262,7 +262,7 @@
       nargs='*',
       help='optional paths to filter what files the tool is run on')
   parser.add_argument(
-      '--tool-args', nargs='*',
+      '--tool-arg', nargs='?', action='append',
       help='optional arguments passed to the tool')
   parser.add_argument(
       '--tool-path', nargs='?',
@@ -304,7 +304,7 @@
         shard_number, shard_count, len(source_filenames), total_length)
 
   dispatcher = _CompilerDispatcher(os.path.join(tool_path, args.tool),
-                                   args.tool_args,
+                                   args.tool_arg,
                                    args.p,
                                    source_filenames)
   dispatcher.Run()
diff --git a/tools/cygprofile/orderfile_generator_backend.py b/tools/cygprofile/orderfile_generator_backend.py
index 45db9aae..147a067 100755
--- a/tools/cygprofile/orderfile_generator_backend.py
+++ b/tools/cygprofile/orderfile_generator_backend.py
@@ -541,6 +541,9 @@
         assert os.path.exists(self._compiler.lib_chrome_so)
         offsets = process_profiles.GetReachedOffsetsFromDumpFiles(
             files, self._compiler.lib_chrome_so)
+        if not offsets:
+          raise Exception('No profiler offsets found in {}'.format(
+                          '\n'.join(files)))
         with open(self._MERGED_CYGLOG_FILENAME, 'w') as f:
           f.write('\n'.join(map(str, offsets)))
       else:
@@ -548,7 +551,7 @@
           self._step_recorder.RunCommand([self._MERGE_TRACES_SCRIPT] + files,
                                          constants.DIR_SOURCE_ROOT,
                                          stdout=merged_cyglog)
-    except CommandError:
+    except Exception:
       for f in files:
         self._SaveForDebugging(f)
       raise
diff --git a/tools/cygprofile/process_profiles.py b/tools/cygprofile/process_profiles.py
index 12945cd..6d89eafa 100755
--- a/tools/cygprofile/process_profiles.py
+++ b/tools/cygprofile/process_profiles.py
@@ -18,6 +18,17 @@
 import symbol_extractor
 
 
+def _Median(items):
+  if not items:
+    return None
+  sorted_items = sorted(items)
+  if len(sorted_items) & 1:
+    return sorted_items[len(sorted_items)/2]
+  else:
+    return (sorted_items[len(sorted_items)/2 - 1] +
+            sorted_items[len(sorted_items)/2]) / 2
+
+
 class SymbolOffsetProcessor(object):
   """Utility for processing symbols in binaries.
 
@@ -167,44 +178,145 @@
     return offset_to_symbol_info
 
 
-def _SortedFilenames(filenames):
-  """Returns filenames in ascending timestamp order.
+class ProfileManager(object):
+  """Manipulates sets of profiles.
 
-  Args:
-    filenames: (str iterable) List of filenames, matching.  *-TIMESTAMP.*.
+  The manager supports only lightweight-style profiles (see
+  lightweight_cygprofile.cc) and not the older cygprofile offset lists.
 
-  Returns:
-    [str] Ordered by ascending timestamp.
+  A "profile set" refers to a set of data from an instrumented version of chrome
+  that will be processed together, usually to produce a single orderfile. A
+  "run" refers to a session of chrome, visiting several pages and thus
+  comprising a browser process and at least one renderer process. A "dump"
+  refers to the instrumentation in chrome writing out offsets of instrumented
+  functions. There may be several dumps per run, for example one describing
+  chrome startup and a second describing steady-state page interaction. Each
+  process in a run produces one file per dump.
+
+  These dump files have a timestamp of the dump time. Each process produces its
+  own timestamp, but the dumps from each process occur very near in time to each
+  other (< 1 second). If there are several dumps per run, each set of dumps is
+  marked by a "phase" in the filename which is consistent across processes. For
+  example the dump for the startup could be phase 0 and then the steady-state
+  would be labeled phase 1.
+
+  We assume the files are named like *-TIMESTAMP.SUFFIX_PHASE, where TIMESTAMP
+  is in nanoseconds, SUFFIX is string without dashes, PHASE is an integer
+  numbering the phases as 0, 1, 2..., and the only dot is the one between
+  TIMESTAMP and SUFFIX. Note that the current dump filename also includes a
+  process id which is currently unused.
+
+  This manager supports several configurations of dumps.
+
+  * A single dump from a single run. These files are merged together to produce
+    a single dump without regard for browser versus renderer methods.
+
+  * Several phases of dumps from a single run. Files are grouped by phase as
+    described above.
+
+  * Several phases of dumps from multiple runs from a set of telemetry
+    benchmarks. The timestamp is used to distinguish each run because each
+    benchmark takes < 10 seconds to run but there are > 50 seconds of setup
+    time. This files can be grouped into run sets that are within 30 seconds of
+    each other. Each run set is then grouped into phases as before.
   """
-  filename_timestamp = []
-  for filename in filenames:
-    dash_index = filename.rindex('-')
-    dot_index = filename.rindex('.')
-    timestamp = int(filename[dash_index+1:dot_index])
-    filename_timestamp.append((filename, timestamp))
-  filename_timestamp.sort(key=operator.itemgetter(1))
-  return [x[0] for x in filename_timestamp]
 
+  class _RunGroup(object):
+    RUN_GROUP_THRESHOLD_NS = 30e9
 
-def MergeDumps(filenames):
-  """Merges several dumps.
+    def __init__(self):
+      self._filenames = []
 
-  Args:
-    filenames: (str iterable) List of dump filenames.
+    def Filenames(self, phase=None):
+      if phase is None:
+        return self._filenames
+      return [f for f in self._filenames
+              if ProfileManager._Phase(f) == phase]
 
-  Returns:
-    [int] Ordered list of reached offsets. Each offset only appears
-    once in the output, in the order of the first dump that contains it.
-  """
-  dumps = [[int(x.strip()) for x in open(filename)] for filename in filenames]
-  seen_offsets = set()
-  result = []
-  for dump in dumps:
-    for offset in dump:
-      if offset not in seen_offsets:
-        result.append(offset)
-        seen_offsets.add(offset)
-  return result
+    def Add(self, filename):
+      self._filenames.append(filename)
+
+    def IsCloseTo(self, filename):
+      run_group_ts = _Median(
+          [ProfileManager._Timestamp(f) for f in self._filenames])
+      return abs(ProfileManager._Timestamp(filename) -
+                 run_group_ts) < self.RUN_GROUP_THRESHOLD_NS
+
+  def __init__(self, filenames):
+    """Initialize a ProfileManager.
+
+    Args:
+      filenames ([str]): List of filenames describe the profile set.
+    """
+    self._filenames = sorted(filenames, key=self._Timestamp)
+    self._run_groups = None
+
+  def GetMergedOffsets(self, phase=None):
+    """Merges files, as if from a single dump.
+
+    Args:
+      phase (int, optional) If present, restrict to this phase.
+
+    Returns:
+      [int] Ordered list of reached offsets. Each offset only appears
+      once in the output, in the order of the first dump that contains it.
+    """
+    if phase is None:
+      return self._GetOffsetsForGroup(self._filenames)
+    return self._GetOffsetsForGroup(f for f in self._filenames
+                                    if self._Phase(f) == phase)
+
+  def GetRunGroupOffsets(self, phase=None):
+    """Merges files from each run group and returns offset list for each.
+
+    Args:
+      phase (int, optional) If present, restrict to this phase.
+
+    Returns:
+     [ [int] ] List of offsets lists, each as from GetMergedOffsets.
+    """
+    return [self._GetOffsetsForGroup(g) for g in self._GetRunGroups(phase)]
+
+  def _GetOffsetsForGroup(self, filenames):
+    dumps = [self._ReadOffsets(f) for f in filenames]
+    seen_offsets = set()
+    result = []
+    for dump in dumps:
+      for offset in dump:
+        if offset not in seen_offsets:
+          result.append(offset)
+          seen_offsets.add(offset)
+    return result
+
+  def _GetRunGroups(self, phase=None):
+    if self._run_groups is None:
+      self._ComputeRunGroups()
+    return [g.Filenames(phase) for g in self._run_groups]
+
+  @classmethod
+  def _Timestamp(cls, filename):
+      dash_index = filename.rindex('-')
+      dot_index = filename.rindex('.')
+      return int(filename[dash_index+1:dot_index])
+
+  @classmethod
+  def _Phase(cls, filename):
+    return int(filename.split('_')[-1])
+
+  def _ReadOffsets(self, filename):
+    return [int(x.strip()) for x in open(filename)]
+
+  def _ComputeRunGroups(self):
+    self._run_groups = []
+    for f in self._filenames:
+      for g in self._run_groups:
+        if g.IsCloseTo(f):
+          g.Add(f)
+          break
+      else:
+        g = self._RunGroup()
+        g.Add(f)
+        self._run_groups.append(g)
 
 
 def GetReachedOffsetsFromDumpFiles(dump_filenames, library_filename):
@@ -219,7 +331,10 @@
       given by the deduplicated order of offsets found in dump_filenames (see
       also MergeDumps().
   """
-  dump = MergeDumps(dump_filenames)
+  dump = ProfileManager(dump_filenames).GetMergedOffsets()
+  if not dump:
+    logging.error('Empty dump, cannot continue: %s', '\n'.join(dump_filenames))
+    return None
   logging.info('Reached offsets = %d', len(dump))
   processor = SymbolOffsetProcessor(library_filename)
   return processor.GetReachedOffsetsFromDump(dump)
@@ -251,7 +366,9 @@
   args = parser.parse_args()
   logging.info('Merging dumps')
   dump_files = args.dumps.split(',')
-  dumps = MergeDumps(_SortedFilenames(dump_files))
+  profile_manager = ProfileManager(dump_files)
+  profile_manager.SortByTimestamp()
+  dumps = profile_manager.GetMergedOffsets()
 
   instrumented_native_lib = os.path.join(args.instrumented_build_dir,
                                          'lib.unstripped', args.library_name)
diff --git a/tools/cygprofile/process_profiles_unittest.py b/tools/cygprofile/process_profiles_unittest.py
index 37db2ad..33cf934 100644
--- a/tools/cygprofile/process_profiles_unittest.py
+++ b/tools/cygprofile/process_profiles_unittest.py
@@ -19,6 +19,15 @@
     self._symbol_infos = symbol_infos
 
 
+class TestProfileManager(process_profiles.ProfileManager):
+  def __init__(self, filecontents_mapping):
+    super(TestProfileManager, self).__init__(filecontents_mapping.keys())
+    self._filecontents_mapping = filecontents_mapping
+
+  def _ReadOffsets(self, filename):
+    return self._filecontents_mapping[filename]
+
+
 class ProcessProfilesTestCase(unittest.TestCase):
 
   def setUp(self):
@@ -31,13 +40,19 @@
         + [self.symbol_3] * 3)
     self.symbol_infos = [self.symbol_0, self.symbol_1,
                          self.symbol_2, self.symbol_3]
+    self._file_counter = 0
+
+  def File(self, timestamp_sec, phase):
+    self._file_counter += 1
+    return 'file-{}-{}.txt_{}'.format(
+        self._file_counter, timestamp_sec * 1000 * 1000 * 1000, phase)
 
   def testGetOffsetToSymbolInfo(self):
     processor = TestSymbolOffsetProcessor(self.symbol_infos)
     offset_to_symbol_info = processor._GetDumpOffsetToSymbolInfo()
     self.assertListEqual(self.offset_to_symbol_info, offset_to_symbol_info)
 
-  def testGetReachedSymbolsFromDump(self):
+  def testGetReachedOffsetsFromDump(self):
     processor = TestSymbolOffsetProcessor(self.symbol_infos)
     # 2 hits for symbol_1, 0 for symbol_2, 1 for symbol_3
     dump = [8, 12, 48]
@@ -77,13 +92,68 @@
     self.assertListEqual(symbols_b[1:3],
                          processor_b.MatchSymbolNames(['Y', 'X']))
 
-  def testSortedFilenames(self):
-    filenames = ['second-1234-456.txt', 'first-345345-123.txt',
-                 'third.bar.-789.txt']
-    sorted_filenames = process_profiles._SortedFilenames(filenames)
-    self.assertListEqual(
-        ['first-345345-123.txt', 'second-1234-456.txt', 'third.bar.-789.txt'],
-        sorted_filenames)
+  def testMedian(self):
+    self.assertEquals(None, process_profiles._Median([]))
+    self.assertEquals(5, process_profiles._Median([5]))
+    self.assertEquals(5, process_profiles._Median([1, 5, 20]))
+    self.assertEquals(5, process_profiles._Median([4, 6]))
+    self.assertEquals(5, process_profiles._Median([1, 4, 6, 100]))
+    self.assertEquals(5, process_profiles._Median([1, 4, 5, 6, 100]))
+
+  def testRunGroups(self):
+    files = [self.File(40, 0), self.File(100, 0), self.File(200, 1),
+             self.File(35, 1), self.File(42, 0), self.File(95, 0)]
+    mgr = process_profiles.ProfileManager(files)
+    mgr._ComputeRunGroups()
+    self.assertEquals(3, len(mgr._run_groups))
+    self.assertEquals(3, len(mgr._run_groups[0].Filenames()))
+    self.assertEquals(2, len(mgr._run_groups[1].Filenames()))
+    self.assertEquals(1, len(mgr._run_groups[2].Filenames()))
+    self.assertTrue(files[0] in mgr._run_groups[0].Filenames())
+    self.assertTrue(files[3] in mgr._run_groups[0].Filenames())
+    self.assertTrue(files[4] in mgr._run_groups[0].Filenames())
+    self.assertTrue(files[1] in mgr._run_groups[1].Filenames())
+    self.assertTrue(files[5] in mgr._run_groups[1].Filenames())
+    self.assertTrue(files[2] in mgr._run_groups[2].Filenames())
+
+  def testReadOffsets(self):
+    mgr = TestProfileManager({
+        self.File(30, 0): [1, 3, 5, 7],
+        self.File(40, 1): [8, 10],
+        self.File(50, 0): [13, 15]})
+    self.assertListEqual([1, 3, 5, 7, 8, 10, 13, 15],
+                         mgr.GetMergedOffsets())
+    self.assertListEqual([8, 10], mgr.GetMergedOffsets(1))
+    self.assertListEqual([], mgr.GetMergedOffsets(2))
+
+  def testRunGroupOffsets(self):
+    mgr = TestProfileManager({
+        self.File(30, 0): [1, 2, 3, 4],
+        self.File(150, 0): [9, 11, 13],
+        self.File(40, 1): [5, 6, 7]})
+    offsets_list = mgr.GetRunGroupOffsets()
+    self.assertEquals(2, len(offsets_list))
+    self.assertListEqual([1, 2, 3, 4, 5, 6, 7], offsets_list[0])
+    self.assertListEqual([9, 11, 13], offsets_list[1])
+    offsets_list = mgr.GetRunGroupOffsets(0)
+    self.assertEquals(2, len(offsets_list))
+    self.assertListEqual([1, 2, 3, 4], offsets_list[0])
+    self.assertListEqual([9, 11, 13], offsets_list[1])
+    offsets_list = mgr.GetRunGroupOffsets(1)
+    self.assertEquals(2, len(offsets_list))
+    self.assertListEqual([5, 6, 7], offsets_list[0])
+    self.assertListEqual([], offsets_list[1])
+
+  def testSorted(self):
+    # The fact that the ProfileManager sorts by filename is implicit in the
+    # other tests. It is tested explicitly here.
+    mgr = TestProfileManager({
+        self.File(40, 0): [1, 2, 3, 4],
+        self.File(150, 0): [9, 11, 13],
+        self.File(30, 1): [5, 6, 7]})
+    offsets_list = mgr.GetRunGroupOffsets()
+    self.assertEquals(2, len(offsets_list))
+    self.assertListEqual([5, 6, 7, 1, 2, 3, 4], offsets_list[0])
 
 
 if __name__ == '__main__':
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 3183b45f..49fc076 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -27752,6 +27752,7 @@
   <int value="587" label="overscroll-behavior-y"/>
   <int value="588" label="font-variant-east-asian"/>
   <int value="589" label="text-decoration-skip-ink"/>
+  <int value="590" label="scroll-customization"/>
 </enum>
 
 <enum name="MappedEditingCommands">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 1b0bf91..b385f8d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -7198,7 +7198,7 @@
 </histogram>
 
 <histogram name="Blink.ResourceLoadScheduler.DecodedBytes.KBPerFrameStatus"
-    enum="RendererSchedulerFrameType">
+    enum="RendererSchedulerFrameType2">
   <owner>toyoshim@chromium.org</owner>
   <owner>altimin@chromium.org</owner>
   <summary>
@@ -7285,7 +7285,7 @@
 </histogram>
 
 <histogram name="Blink.ResourceLoadScheduler.TrafficBytes.KBPerFrameStatus"
-    enum="RendererSchedulerFrameType">
+    enum="RendererSchedulerFrameType2">
   <owner>toyoshim@chromium.org</owner>
   <owner>altimin@chromium.org</owner>
   <summary>
@@ -110251,6 +110251,14 @@
   <affected-histogram name="RendererScheduler.RendererMainThreadLoad5"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="RendererScheduler.ProcessVisibilityStateSplit"
+    separator=".">
+  <suffix name="Background"/>
+  <suffix name="Foreground"/>
+  <affected-histogram name="RendererScheduler.TaskCPUDurationPerThreadType"/>
+  <affected-histogram name="RendererScheduler.TaskDurationPerThreadType"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="RendererScheduler.TaskCountPerTaskLength"
     separator=".">
   <suffix name="LongerThan16ms"/>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index a83875d..74e0c06 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -372,8 +372,7 @@
           ],
        'perf_tests': [
          ('load_library_perf_tests', 'build145-m1'),
-         # crbug.com/803455
-         # ('performance_browser_tests', 'build145-m1'),
+         ('performance_browser_tests', 'build145-m1'),
          ('media_perftests', 'build146-m1')]
       }
     ])
@@ -409,9 +408,8 @@
            'build140-m1', 'build141-m1', 'build142-m1'
           ],
        'perf_tests': [
-         ('load_library_perf_tests', 'build140-m1')]
-         # crbug.com/803455
-         # ('performance_browser_tests', 'build140-m1')]
+         ('load_library_perf_tests', 'build140-m1'),
+         ('performance_browser_tests', 'build140-m1')]
       }
     ])
   waterfall = add_tester(
@@ -430,8 +428,7 @@
          # crbug.com/785291
          # ('angle_perftests', 'build103-m1'),
          ('load_library_perf_tests', 'build103-m1'),
-         # crbug.com/803455
-         # ('performance_browser_tests', 'build103-m1'),
+         ('performance_browser_tests', 'build103-m1'),
          ('media_perftests', 'build104-m1')]
       }
     ])
@@ -449,9 +446,8 @@
           ],
        'perf_tests': [
          ('angle_perftests', 'build166-m1'),
-         ('load_library_perf_tests', 'build166-m1')]
-         # crbug.com/803455
-         # ('performance_browser_tests', 'build166-m1')]
+         ('load_library_perf_tests', 'build166-m1'),
+         ('performance_browser_tests', 'build166-m1')]
       }
     ])
   waterfall = add_tester(
@@ -528,8 +524,7 @@
            'build30-b4' # replacing build8-b1. crbug.com/724998
           ],
        'perf_tests': [
-         # crbug.com/803455
-         # ('performance_browser_tests', 'build30-b4')
+         ('performance_browser_tests', 'build30-b4')
        ]
       }
     ])
@@ -546,8 +541,7 @@
            'build130-b1', 'build131-b1', 'build132-b1'
           ],
        'perf_tests': [
-         # crbug.com/803455
-         # ('performance_browser_tests', 'build132-b1')
+         ('performance_browser_tests', 'build132-b1')
        ]
       }
     ])
@@ -564,8 +558,7 @@
            'build125-b1', 'build126-b1', 'build127-b1'
           ],
        'perf_tests': [
-         # crbug.com/803455
-         # ('performance_browser_tests', 'build126-b1')
+         ('performance_browser_tests', 'build126-b1')
        ]
       }
     ])
diff --git a/tools/traffic_annotation/README.md b/tools/traffic_annotation/README.md
index 5c5e75f3..99b1947 100644
--- a/tools/traffic_annotation/README.md
+++ b/tools/traffic_annotation/README.md
@@ -99,4 +99,4 @@
 re-enable the test.
 
 CLANG_REVISION = '321529'
-LASTCHANGE=bfcea61717d615f8d021c0da2d7ad7dc0589a0b1-refs/heads/master@{#530086}
+LASTCHANGE=671628d8a99b8420f4dadcdb82751c0d3ea2117a-refs/heads/master@{#530817}
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
index e7edee43..86c64f3e 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
@@ -157,7 +157,8 @@
   fprintf(
       options_file,
       "--generate-compdb --tool=traffic_annotation_extractor -p=%s "
-      "--tool-path=%s --tool-args=--extra-arg=-resource-dir=%s ",
+      "--tool-path=%s --tool-arg=--extra-arg=-resource-dir=%s "
+      "--tool-arg=--extra-arg=-Wno-comment ",
       build_path_.MaybeAsASCII().c_str(),
       base::MakeAbsoluteFilePath(clang_tool_path_).MaybeAsASCII().c_str(),
       base::MakeAbsoluteFilePath(GetClangLibraryPath()).MaybeAsASCII().c_str());
diff --git a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
index 94cbc6e..d93eae7 100644
--- a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
+++ b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
@@ -1 +1 @@
-770c080e777cbd7c18b34c918e1a75247ff00bf9
\ No newline at end of file
+15452c1f82231c0d5a73ebd9468d36af6735b3f8
\ No newline at end of file
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index ed3ee46f..ba10521e 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -11,6 +11,7 @@
  <item id="CRD_ice_config_request" hash_code="49825319" type="0" content_hash_code="8740825" os_list="linux,windows" file_path="remoting/protocol/http_ice_config_request.cc"/>
  <item id="CRD_relay_session_request" hash_code="24058523" type="0" content_hash_code="36997811" os_list="linux,windows" file_path="remoting/protocol/port_allocator.cc"/>
  <item id="CRD_telemetry_log" hash_code="18670926" type="0" content_hash_code="49025478" os_list="linux,windows" file_path="remoting/base/telemetry_log_writer.cc"/>
+ <item id="accounts_image_fetcher" hash_code="98658519" type="0" content_hash_code="45432230" os_list="linux,windows" file_path="components/signin/core/browser/account_fetcher_service.cc"/>
  <item id="adb_client_socket" hash_code="87775794" type="0" content_hash_code="56654828" os_list="linux,windows" file_path="chrome/browser/devtools/device/adb/adb_client_socket.cc"/>
  <item id="affiliation_lookup" hash_code="111904019" type="0" content_hash_code="81061452" os_list="linux,windows" file_path="components/password_manager/core/browser/android_affiliation/affiliation_fetcher.cc"/>
  <item id="android_device_manager_socket" hash_code="37249086" type="0" content_hash_code="6436865" os_list="linux,windows" file_path="chrome/browser/devtools/device/android_device_manager.cc"/>
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 7d3ead2..b12f041 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -3474,6 +3474,8 @@
   switch (event) {
     case AX_EVENT_ALERT:
       return EVENT_SYSTEM_ALERT;
+    case AX_EVENT_EXPANDED_CHANGED:
+      return EVENT_OBJECT_STATECHANGE;
     case AX_EVENT_FOCUS:
       return EVENT_OBJECT_FOCUS;
     case AX_EVENT_MENU_START:
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc
index 5520cfc..6e2518c 100644
--- a/ui/android/delegated_frame_host_android.cc
+++ b/ui/android/delegated_frame_host_android.cc
@@ -14,7 +14,6 @@
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/host/host_frame_sink_manager.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/surfaces/surface.h"
 #include "ui/android/view_android.h"
 #include "ui/android/window_android_compositor.h"
@@ -27,11 +26,10 @@
 namespace {
 
 scoped_refptr<cc::SurfaceLayer> CreateSurfaceLayer(
-    viz::SurfaceManager* surface_manager,
     viz::SurfaceInfo surface_info,
     bool surface_opaque) {
   // manager must outlive compositors using it.
-  auto layer = cc::SurfaceLayer::Create(surface_manager->reference_factory());
+  auto layer = cc::SurfaceLayer::Create();
   layer->SetPrimarySurfaceId(surface_info.id(), base::nullopt);
   layer->SetFallbackSurfaceId(surface_info.id());
   layer->SetBounds(surface_info.size_in_pixels());
@@ -54,13 +52,11 @@
 DelegatedFrameHostAndroid::DelegatedFrameHostAndroid(
     ui::ViewAndroid* view,
     viz::HostFrameSinkManager* host_frame_sink_manager,
-    viz::FrameSinkManagerImpl* frame_sink_manager,
     Client* client,
     const viz::FrameSinkId& frame_sink_id)
     : frame_sink_id_(frame_sink_id),
       view_(view),
       host_frame_sink_manager_(host_frame_sink_manager),
-      frame_sink_manager_(frame_sink_manager),
       client_(client),
       begin_frame_source_(this),
       enable_surface_synchronization_(
@@ -101,8 +97,7 @@
     DCHECK(result);
 
     content_layer_ =
-        CreateSurfaceLayer(frame_sink_manager_->surface_manager(),
-                           surface_info_, !has_transparent_background_);
+        CreateSurfaceLayer(surface_info_, !has_transparent_background_);
     view_->GetLayer()->AddChild(content_layer_);
   } else {
     support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
@@ -127,8 +122,7 @@
   DCHECK(!result_callback.is_null());
 
   scoped_refptr<cc::Layer> readback_layer =
-      CreateSurfaceLayer(frame_sink_manager_->surface_manager(), surface_info_,
-                         !has_transparent_background_);
+      CreateSurfaceLayer(surface_info_, !has_transparent_background_);
   readback_layer->SetHideLayerAndSubtree(true);
   compositor->AttachLayerForReadback(readback_layer);
   std::unique_ptr<viz::CopyOutputRequest> copy_output_request =
diff --git a/ui/android/delegated_frame_host_android.h b/ui/android/delegated_frame_host_android.h
index 5fbfd41..9831d62 100644
--- a/ui/android/delegated_frame_host_android.h
+++ b/ui/android/delegated_frame_host_android.h
@@ -24,7 +24,6 @@
 
 namespace viz {
 class CompositorFrame;
-class FrameSinkManagerImpl;
 class HostFrameSinkManager;
 }  // namespace viz
 
@@ -50,7 +49,6 @@
 
   DelegatedFrameHostAndroid(ViewAndroid* view,
                             viz::HostFrameSinkManager* host_frame_sink_manager,
-                            viz::FrameSinkManagerImpl* frame_sink_manager,
                             Client* client,
                             const viz::FrameSinkId& frame_sink_id);
 
@@ -121,7 +119,6 @@
   ViewAndroid* view_;
 
   viz::HostFrameSinkManager* const host_frame_sink_manager_;
-  viz::FrameSinkManagerImpl* const frame_sink_manager_;
   WindowAndroidCompositor* registered_parent_compositor_ = nullptr;
   Client* client_;
 
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn
index 53bce0f..e985be0 100644
--- a/ui/app_list/BUILD.gn
+++ b/ui/app_list/BUILD.gn
@@ -63,9 +63,8 @@
     "views/image_shadow_animator.h",
     "views/indicator_chip_view.cc",
     "views/indicator_chip_view.h",
+    "views/page_switcher.cc",
     "views/page_switcher.h",
-    "views/page_switcher_vertical.cc",
-    "views/page_switcher_vertical.h",
     "views/pulsing_block_view.cc",
     "views/pulsing_block_view.h",
     "views/search_box_view.cc",
diff --git a/ui/app_list/app_list_constants.cc b/ui/app_list/app_list_constants.cc
index f6746fc..1091cfc7 100644
--- a/ui/app_list/app_list_constants.cc
+++ b/ui/app_list/app_list_constants.cc
@@ -57,7 +57,6 @@
 // Color of the folder bubble shadow.
 const SkColor kFolderShadowColor = SkColorSetRGB(0xBF, 0xBF, 0xBF);
 const float kFolderBubbleOpacity = 0.12f;
-const int kFolderBackgroundBubbleRadius = 288;
 
 const SkColor kCardBackgroundColor = SkColorSetRGB(0xFA, 0xFA, 0xFC);
 
@@ -166,8 +165,11 @@
 // The height/width of the shelf from the bottom/side of the screen.
 const int kShelfSize = 48;
 
-// Max items allowed in a folder.
-const size_t kMaxFolderItems = 20;
+// Max pages allowed in a folder.
+const size_t kMaxFolderPages = 3;
+
+// Max items per page allowed in a folder.
+const size_t kMaxFolderItemsPerPage = 16;
 
 // Maximum length of the folder name in chars.
 const size_t kMaxFolderNameChars = 80;
@@ -176,6 +178,11 @@
 const ui::ResourceBundle::FontStyle kItemTextFontStyle =
     ui::ResourceBundle::SmallFont;
 
+// Range of the height of centerline above screen bottom that all apps should
+// change opacity. NOTE: this is used to change page switcher's opacity as well.
+const float kAllAppsOpacityStartPx = 8.0f;
+const float kAllAppsOpacityEndPx = 144.0f;
+
 // The UMA histogram that logs usage of suggested and regular apps.
 const char kAppListAppLaunched[] = "Apps.AppListAppLaunched";
 
diff --git a/ui/app_list/app_list_constants.h b/ui/app_list/app_list_constants.h
index 58f3b98..ea0393fa 100644
--- a/ui/app_list/app_list_constants.h
+++ b/ui/app_list/app_list_constants.h
@@ -55,8 +55,6 @@
 APP_LIST_EXPORT extern const SkColor kFolderShadowColor;
 APP_LIST_EXPORT extern const float kFolderBubbleOpacity;
 
-APP_LIST_EXPORT extern const int kFolderBackgroundBubbleRadius;
-
 APP_LIST_EXPORT extern const SkColor kCardBackgroundColor;
 
 APP_LIST_EXPORT extern const int kPageTransitionDurationInMs;
@@ -107,12 +105,15 @@
 APP_LIST_EXPORT extern const int kPeekingAppListHeight;
 APP_LIST_EXPORT extern const int kShelfSize;
 
-APP_LIST_EXPORT extern const size_t kMaxFolderItems;
-APP_LIST_EXPORT extern const size_t kMaxFolderItems;
+APP_LIST_EXPORT extern const size_t kMaxFolderPages;
+APP_LIST_EXPORT extern const size_t kMaxFolderItemsPerPage;
 APP_LIST_EXPORT extern const size_t kMaxFolderNameChars;
 
 APP_LIST_EXPORT extern const ui::ResourceBundle::FontStyle kItemTextFontStyle;
 
+APP_LIST_EXPORT extern const float kAllAppsOpacityStartPx;
+APP_LIST_EXPORT extern const float kAllAppsOpacityEndPx;
+
 // The different ways that the app list can transition from PEEKING to
 // FULLSCREEN_ALL_APPS. These values are written to logs.  New enum
 // values can be added, but existing enums must never be renumbered or deleted
diff --git a/ui/app_list/views/app_list_folder_view.cc b/ui/app_list/views/app_list_folder_view.cc
index e177d99..36a27e8 100644
--- a/ui/app_list/views/app_list_folder_view.cc
+++ b/ui/app_list/views/app_list_folder_view.cc
@@ -10,6 +10,8 @@
 #include "ash/app_list/model/app_list_model.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/app_list/app_list_constants.h"
+#include "ui/app_list/app_list_features.h"
+#include "ui/app_list/pagination_model.h"
 #include "ui/app_list/views/app_list_item_view.h"
 #include "ui/app_list/views/app_list_main_view.h"
 #include "ui/app_list/views/apps_container_view.h"
@@ -17,11 +19,14 @@
 #include "ui/app_list/views/contents_view.h"
 #include "ui/app_list/views/folder_background_view.h"
 #include "ui/app_list/views/folder_header_view.h"
+#include "ui/app_list/views/page_switcher.h"
 #include "ui/app_list/views/search_box_view.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/events/event.h"
+#include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/strings/grit/ui_strings.h"
+#include "ui/views/background.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/view_model.h"
 #include "ui/views/view_model_utils.h"
@@ -30,18 +35,37 @@
 
 namespace {
 
-// The preferred width/height for AppListFolderView.
-constexpr int kAppsFolderPreferredWidth = 576;
-constexpr int kAppsFolderPreferredHeight = 504;
+constexpr int kFolderBackgroundCornerRadius = 4;
+constexpr int kItemGridsBottomPadding = 24;
+constexpr int kFolderPadding = 12;
 
 // Indexes of interesting views in ViewModel of AppListFolderView.
-const int kIndexFolderHeader = 0;
-const int kIndexChildItems = 1;
+constexpr int kIndexChildItems = 0;
+constexpr int kIndexFolderHeader = 1;
+constexpr int kIndexPageSwitcher = 2;
 
-// Threshold for the distance from the center of the item to the circle of the
-// folder container ink bubble, beyond which, the item is considered dragged
-// out of the folder boundary.
-const int kOutOfFolderContainerBubbleDelta = 30;
+// A background with rounded corner.
+class FolderBackground : public views::Background {
+ public:
+  FolderBackground(SkColor color, int corner_radius)
+      : color_(color), corner_radius_(corner_radius) {}
+  ~FolderBackground() override = default;
+
+ private:
+  // views::Background overrides:
+  void Paint(gfx::Canvas* canvas, views::View* view) const override {
+    gfx::Rect bounds = view->GetContentsBounds();
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setColor(color_);
+    canvas->DrawRoundRect(bounds, corner_radius_, flags);
+  }
+
+  const SkColor color_;
+  const int corner_radius_;
+
+  DISALLOW_COPY_AND_ASSIGN(FolderBackground);
+};
 
 }  // namespace
 
@@ -55,20 +79,23 @@
       model_(model),
       folder_item_(NULL),
       hide_for_reparent_(false) {
-  AddChildView(folder_header_view_);
-  view_model_->Add(folder_header_view_, kIndexFolderHeader);
-
   items_grid_view_ =
       new AppsGridView(app_list_main_view_->contents_view(), this);
-  items_grid_view_->SetLayout(
-      container_view->apps_grid_view()->cols(),
-      container_view->apps_grid_view()->rows_per_page());
   items_grid_view_->SetModel(model);
   AddChildView(items_grid_view_);
   view_model_->Add(items_grid_view_, kIndexChildItems);
 
+  AddChildView(folder_header_view_);
+  view_model_->Add(folder_header_view_, kIndexFolderHeader);
+
+  page_switcher_ = new PageSwitcher(items_grid_view_->pagination_model(),
+                                    false /* vertical */);
+  AddChildView(page_switcher_);
+  view_model_->Add(page_switcher_, kIndexPageSwitcher);
+
   SetPaintToLayer();
-  layer()->SetFillsBoundsOpaquely(false);
+  SetBackground(std::make_unique<FolderBackground>(
+      kCardBackgroundColor, kFolderBackgroundCornerRadius));
 
   model_->AddObserver(this);
 }
@@ -98,14 +125,18 @@
   // Stop any previous animation.
   layer()->GetAnimator()->StopAnimating();
 
-  // Hide the top items temporarily if showing the view for opening the folder.
-  if (show)
+  if (show) {
+    // Hide the top items temporarily if showing the view for opening the
+    // folder.
     items_grid_view_->SetTopItemViewsVisible(false);
 
+    // Reset page if showing the view.
+    items_grid_view_->pagination_model()->SelectPage(0, false);
+  }
+
   // Set initial state.
   layer()->SetOpacity(show ? 0.0f : 1.0f);
   SetVisible(true);
-  UpdateFolderNameVisibility(true);
 
   ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator());
   animation.SetTweenType(show ? kFolderFadeInTweenType
@@ -115,11 +146,13 @@
       show ? kFolderTransitionInDurationMs : kFolderTransitionOutDurationMs));
 
   layer()->SetOpacity(show ? 1.0f : 0.0f);
-  app_list_main_view_->search_box_view()->ShowBackOrGoogleIcon(show);
 }
 
 gfx::Size AppListFolderView::CalculatePreferredSize() const {
-  gfx::Size size(kAppsFolderPreferredWidth, kAppsFolderPreferredHeight);
+  gfx::Size size = items_grid_view_->GetTileGridSizeWithoutPadding();
+  size.Enlarge(0, kItemGridsBottomPadding +
+                      folder_header_view_->GetPreferredSize().height());
+  size.Enlarge(kFolderPadding * 2, kFolderPadding * 2);
   return size;
 }
 
@@ -168,14 +201,30 @@
   if (rect.IsEmpty())
     return;
 
+  rect.Inset(kFolderPadding, kFolderPadding);
+
+  // Calculate bounds for items grid view.
+  gfx::Rect grid_frame(rect);
+  grid_frame.Inset(items_grid_view_->GetTilePadding());
+  grid_frame.set_height(items_grid_view_->GetPreferredSize().height());
+  view_model_->set_ideal_bounds(kIndexChildItems, grid_frame);
+
+  // Calculate bounds for folder header view..
   gfx::Rect header_frame(rect);
-  gfx::Size size = folder_header_view_->GetPreferredSize();
-  header_frame.set_height(size.height());
+  header_frame.set_y(grid_frame.bottom() +
+                     items_grid_view_->GetTilePadding().bottom() +
+                     kItemGridsBottomPadding);
+  header_frame.set_height(folder_header_view_->GetPreferredSize().height());
   view_model_->set_ideal_bounds(kIndexFolderHeader, header_frame);
 
-  gfx::Rect grid_frame(rect);
-  grid_frame.Subtract(header_frame);
-  view_model_->set_ideal_bounds(kIndexChildItems, grid_frame);
+  // Calculate bounds for page_switcher.
+  gfx::Rect page_switcher_frame(rect);
+  gfx::Size page_switcher_size = page_switcher_->GetPreferredSize();
+  page_switcher_frame.set_x(page_switcher_frame.right() -
+                            page_switcher_size.width());
+  page_switcher_frame.set_y(header_frame.y());
+  page_switcher_frame.set_size(page_switcher_size);
+  view_model_->set_ideal_bounds(kIndexPageSwitcher, page_switcher_frame);
 }
 
 void AppListFolderView::StartSetupDragInRootLevelAppsGridView(
@@ -210,36 +259,9 @@
   return to_folder;
 }
 
-void AppListFolderView::UpdateFolderViewBackground(bool show_bubble) {
-  if (hide_for_reparent_)
-    return;
-
-  // Before showing the folder container inking bubble, hide the folder name.
-  if (show_bubble)
-    UpdateFolderNameVisibility(false);
-
-  container_view_->folder_background_view()->UpdateFolderContainerBubble(
-      show_bubble ? FolderBackgroundView::SHOW_BUBBLE
-                  : FolderBackgroundView::HIDE_BUBBLE);
-}
-
-void AppListFolderView::UpdateFolderNameVisibility(bool visible) {
-  folder_header_view_->UpdateFolderNameVisibility(visible);
-}
-
-void AppListFolderView::SetBackButtonLabel(bool folder) {
-  app_list_main_view_->search_box_view()->SetBackButtonLabel(folder);
-}
-
 bool AppListFolderView::IsPointOutsideOfFolderBoundary(
     const gfx::Point& point) {
-  if (!GetLocalBounds().Contains(point))
-    return true;
-
-  gfx::Point center = GetLocalBounds().CenterPoint();
-  float delta = (point - center).Length();
-  return delta >
-         kFolderBackgroundBubbleRadius + kOutOfFolderContainerBubbleDelta;
+  return !GetLocalBounds().Contains(point);
 }
 
 // When user drags a folder item out of the folder boundary ink bubble, the
diff --git a/ui/app_list/views/app_list_folder_view.h b/ui/app_list/views/app_list_folder_view.h
index 6641797..a1b9c10 100644
--- a/ui/app_list/views/app_list_folder_view.h
+++ b/ui/app_list/views/app_list_folder_view.h
@@ -27,12 +27,13 @@
 class AppListMainView;
 class AppListModel;
 class FolderHeaderView;
+class PageSwitcher;
 
-class AppListFolderView : public views::View,
-                          public FolderHeaderViewDelegate,
-                          public AppListModelObserver,
-                          public ui::ImplicitAnimationObserver,
-                          public AppsGridViewFolderDelegate {
+class APP_LIST_EXPORT AppListFolderView : public views::View,
+                                          public FolderHeaderViewDelegate,
+                                          public AppListModelObserver,
+                                          public ui::ImplicitAnimationObserver,
+                                          public AppsGridViewFolderDelegate {
  public:
   AppListFolderView(AppsContainerView* container_view,
                     AppListModel* model,
@@ -50,9 +51,6 @@
   // AppListFolderView.
   gfx::Rect GetItemIconBoundsAt(int index);
 
-  void UpdateFolderNameVisibility(bool visible);
-  void SetBackButtonLabel(bool folder);
-
   // Hides the view immediately without animation.
   void HideViewImmediately();
 
@@ -94,7 +92,6 @@
   void SetItemName(AppListFolderItem* item, const std::string& name) override;
 
   // Overridden from AppsGridViewFolderDelegate:
-  void UpdateFolderViewBackground(bool show_bubble) override;
   void ReparentItem(AppListItemView* original_drag_view,
                     const gfx::Point& drag_point_in_folder_grid,
                     bool has_native_drag) override;
@@ -111,6 +108,7 @@
   AppListMainView* app_list_main_view_;   // Not Owned.
   FolderHeaderView* folder_header_view_;  // Owned by views hierarchy.
   AppsGridView* items_grid_view_;         // Owned by the views hierarchy.
+  PageSwitcher* page_switcher_ = nullptr;  // Owned by the views hierarchy.
 
   std::unique_ptr<views::ViewModel> view_model_;
 
diff --git a/ui/app_list/views/app_list_item_view.cc b/ui/app_list/views/app_list_item_view.cc
index 47874df..33d27e1 100644
--- a/ui/app_list/views/app_list_item_view.cc
+++ b/ui/app_list/views/app_list_item_view.cc
@@ -52,6 +52,12 @@
 // 650ms.
 constexpr int kTouchLongpressDelayInMs = 300;
 
+// The color of the title for the tiles within folder.
+constexpr SkColor kFolderGridTitleColor = SK_ColorBLACK;
+
+// The color of the selected item view within folder.
+constexpr SkColor kFolderGridSelectedColor = SkColorSetARGBMacro(31, 0, 0, 0);
+
 }  // namespace
 
 // static
@@ -82,7 +88,9 @@
   title_->SetFontList(font);
   title_->SetLineHeight(font.GetHeight());
   title_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
-  title_->SetEnabledColor(kGridTitleColor);
+  title_->SetEnabledColor(apps_grid_view_->is_in_folder()
+                              ? kFolderGridTitleColor
+                              : kGridTitleColor);
 
   SetTitleSubpixelAA();
 
@@ -335,7 +343,8 @@
                (rect.height() - kGridSelectedSize) / 2);
     cc::PaintFlags flags;
     flags.setAntiAlias(true);
-    flags.setColor(kGridSelectedColor);
+    flags.setColor(apps_grid_view_->is_in_folder() ? kFolderGridSelectedColor
+                                                   : kGridSelectedColor);
     flags.setStyle(cc::PaintFlags::kFill_Style);
     canvas->DrawRoundRect(gfx::RectF(rect), kGridSelectedCornerRadius, flags);
   }
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index 9b33e43..054d1c1 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -510,7 +510,13 @@
   // No-op if app list is on fullscreen all apps state and the event location is
   // within apps grid view's bounds.
   if (app_list_state_ == AppListViewState::FULLSCREEN_ALL_APPS &&
-      GetAppsGridView()->GetBoundsInScreen().Contains(event->location())) {
+      GetRootAppsGridView()->GetBoundsInScreen().Contains(event->location())) {
+    return;
+  }
+
+  if (GetAppsContainerView()->IsInFolderView()) {
+    // Close the folder if it is opened.
+    GetAppsContainerView()->app_list_folder_view()->CloseFolderPage();
     return;
   }
 
@@ -684,11 +690,8 @@
       target_state != AppListViewState::FULLSCREEN_ALL_APPS)
     return;
 
-  AppsContainerView* apps_container_view =
-      app_list_main_view_->contents_view()->apps_container_view();
-
-  if (apps_container_view->IsInFolderView())
-    apps_container_view->ResetForShowApps();
+  if (GetAppsContainerView()->IsInFolderView())
+    GetAppsContainerView()->ResetForShowApps();
 
   if (target_state == AppListViewState::PEEKING) {
     app_list_main_view_->contents_view()->SetActiveState(
@@ -701,7 +704,7 @@
     }
   } else {
     // Set timer to ignore further scroll events for this transition.
-    GetAppsGridView()->StartTimerToIgnoreScrollEvents();
+    GetRootAppsGridView()->StartTimerToIgnoreScrollEvents();
 
     app_list_main_view_->contents_view()->SetActiveState(
         AppListModel::STATE_APPS, !is_side_shelf_);
@@ -774,10 +777,16 @@
   return display::Screen::GetScreen()->GetDisplayNearestView(parent_window_);
 }
 
-AppsGridView* AppListView::GetAppsGridView() const {
-  return app_list_main_view_->contents_view()
-      ->apps_container_view()
-      ->apps_grid_view();
+AppsContainerView* AppListView::GetAppsContainerView() {
+  return app_list_main_view_->contents_view()->apps_container_view();
+}
+
+AppsGridView* AppListView::GetRootAppsGridView() {
+  return GetAppsContainerView()->apps_grid_view();
+}
+
+AppsGridView* AppListView::GetFolderAppsGridView() {
+  return GetAppsContainerView()->app_list_folder_view()->items_grid_view();
 }
 
 AppListStateTransitionSource AppListView::GetAppListStateTransitionSource(
@@ -1000,12 +1009,16 @@
     return false;
 
   // Let the Apps grid view handle the event first in FULLSCREEN_ALL_APPS.
-  if (app_list_state_ == AppListViewState::FULLSCREEN_ALL_APPS &&
-      GetAppsGridView()->HandleScrollFromAppListView(offset, type)) {
-    // Set the scroll ignore timer to avoid processing the tail end of the
-    // stream of scroll events, which would close the view.
-    SetOrRestartScrollIgnoreTimer();
-    return true;
+  if (app_list_state_ == AppListViewState::FULLSCREEN_ALL_APPS) {
+    AppsGridView* apps_grid_view = GetAppsContainerView()->IsInFolderView()
+                                       ? GetFolderAppsGridView()
+                                       : GetRootAppsGridView();
+    if (apps_grid_view->HandleScrollFromAppListView(offset, type)) {
+      // Set the scroll ignore timer to avoid processing the tail end of the
+      // stream of scroll events, which would close the view.
+      SetOrRestartScrollIgnoreTimer();
+      return true;
+    }
   }
 
   if (ShouldIgnoreScrollEvents())
@@ -1065,10 +1078,7 @@
 
   // Updates the visibility of app list items according to the change of
   // |app_list_state_|.
-  app_list_main_view_->contents_view()
-      ->apps_container_view()
-      ->apps_grid_view()
-      ->UpdateControlVisibility(app_list_state_, is_in_drag_);
+  GetAppsContainerView()->UpdateControlVisibility(app_list_state_, is_in_drag_);
 }
 
 void AppListView::StartAnimationForState(AppListViewState target_state) {
@@ -1196,8 +1206,8 @@
   DraggingLayout();
 }
 
-PaginationModel* AppListView::GetAppsPaginationModel() const {
-  return GetAppsGridView()->pagination_model();
+PaginationModel* AppListView::GetAppsPaginationModel() {
+  return GetRootAppsGridView()->pagination_model();
 }
 
 gfx::Rect AppListView::GetAppInfoDialogBounds() const {
@@ -1215,10 +1225,7 @@
     return;
 
   is_in_drag_ = is_in_drag;
-  app_list_main_view_->contents_view()
-      ->apps_container_view()
-      ->apps_grid_view()
-      ->UpdateControlVisibility(app_list_state_, is_in_drag_);
+  GetAppsContainerView()->UpdateControlVisibility(app_list_state_, is_in_drag_);
 }
 
 int AppListView::GetScreenBottom() {
@@ -1236,7 +1243,7 @@
 
   // Updates the opacity of the items in the app list.
   search_box_view_->UpdateOpacity();
-  GetAppsGridView()->UpdateOpacity();
+  GetAppsContainerView()->UpdateOpacity();
 
   Layout();
 }
@@ -1247,12 +1254,10 @@
 
   views::Textfield* search_box = search_box_view_->search_box();
   const bool is_search_box_focused = search_box->HasFocus();
-  const bool is_folder_header_view_focused =
-      app_list_main_view_->contents_view()
-          ->apps_container_view()
-          ->app_list_folder_view()
-          ->folder_header_view()
-          ->HasTextFocus();
+  const bool is_folder_header_view_focused = GetAppsContainerView()
+                                                 ->app_list_folder_view()
+                                                 ->folder_header_view()
+                                                 ->HasTextFocus();
   if (is_search_box_focused || is_folder_header_view_focused) {
     // Do not redirect the key event to the |search_box_| when focus is on a
     // text field.
diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h
index 684e8a0..4524adf 100644
--- a/ui/app_list/views/app_list_view.h
+++ b/ui/app_list/views/app_list_view.h
@@ -37,6 +37,7 @@
 }
 
 namespace app_list {
+class AppsContainerView;
 class ApplicationDragAndDropHost;
 class AppListMainView;
 class AppListModel;
@@ -178,7 +179,7 @@
   }
 
   // Gets the PaginationModel owned by this view's apps grid.
-  PaginationModel* GetAppsPaginationModel() const;
+  PaginationModel* GetAppsPaginationModel();
 
   // Gets the content bounds of the app info dialog of the app list in the
   // screen coordinates.
@@ -271,8 +272,14 @@
   // Gets the display nearest to the parent window.
   display::Display GetDisplayNearestView() const;
 
-  // Gets the apps grid view owned by this view.
-  AppsGridView* GetAppsGridView() const;
+  // Gets the apps container view owned by this view.
+  AppsContainerView* GetAppsContainerView();
+
+  // Gets the root apps grid view owned by this view.
+  AppsGridView* GetRootAppsGridView();
+
+  // Gets the apps grid view within the folder view owned by this view.
+  AppsGridView* GetFolderAppsGridView();
 
   // Gets the AppListStateTransitionSource for |app_list_state_| to
   // |target_state|. If we are not interested in recording a state transition
diff --git a/ui/app_list/views/app_list_view_unittest.cc b/ui/app_list/views/app_list_view_unittest.cc
index c817c77..c090f1b 100644
--- a/ui/app_list/views/app_list_view_unittest.cc
+++ b/ui/app_list/views/app_list_view_unittest.cc
@@ -595,13 +595,12 @@
 
   std::vector<views::View*> forward_view_list;
   forward_view_list.push_back(search_box_view()->search_box());
-  forward_view_list.push_back(
-      app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest());
   const views::ViewModelT<AppListItemView>* view_model =
       app_list_folder_view()->items_grid_view()->view_model_for_test();
   for (int i = 0; i < view_model->view_size(); ++i)
     forward_view_list.push_back(view_model->view_at(i));
-  forward_view_list.push_back(search_box_view()->back_button());
+  forward_view_list.push_back(
+      app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest());
   forward_view_list.push_back(search_box_view()->search_box());
   std::vector<views::View*> backward_view_list = forward_view_list;
   std::reverse(backward_view_list.begin(), backward_view_list.end());
@@ -744,12 +743,13 @@
 
   std::vector<views::View*> forward_view_list;
   forward_view_list.push_back(search_box_view()->search_box());
-  forward_view_list.push_back(
-      app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest());
   const views::ViewModelT<AppListItemView>* view_model =
       app_list_folder_view()->items_grid_view()->view_model_for_test();
-  for (int i = 0; i < view_model->view_size(); i += apps_grid_view()->cols())
+  for (int i = 0; i < view_model->view_size();
+       i += app_list_folder_view()->items_grid_view()->cols())
     forward_view_list.push_back(view_model->view_at(i));
+  forward_view_list.push_back(
+      app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest());
   forward_view_list.push_back(search_box_view()->search_box());
 
   // Test traversal triggered by down.
@@ -757,11 +757,11 @@
 
   std::vector<views::View*> backward_view_list;
   backward_view_list.push_back(search_box_view()->search_box());
-  for (int i = view_model->view_size() - 1; i >= 0;
-       i -= apps_grid_view()->cols())
-    backward_view_list.push_back(view_model->view_at(i));
   backward_view_list.push_back(
       app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest());
+  for (int i = view_model->view_size() - 1; i >= 0;
+       i -= app_list_folder_view()->items_grid_view()->cols())
+    backward_view_list.push_back(view_model->view_at(i));
   backward_view_list.push_back(search_box_view()->search_box());
 
   // Test traversal triggered by up.
diff --git a/ui/app_list/views/apps_container_view.cc b/ui/app_list/views/apps_container_view.cc
index 5db8047..962ded1 100644
--- a/ui/app_list/views/apps_container_view.cc
+++ b/ui/app_list/views/apps_container_view.cc
@@ -17,6 +17,7 @@
 #include "ui/app_list/views/apps_grid_view.h"
 #include "ui/app_list/views/contents_view.h"
 #include "ui/app_list/views/folder_background_view.h"
+#include "ui/app_list/views/page_switcher.h"
 #include "ui/app_list/views/search_box_view.h"
 #include "ui/app_list/views/suggestions_container_view.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -42,13 +43,17 @@
   apps_grid_view_->SetLayout(kPreferredCols, kPreferredRows);
   AddChildView(apps_grid_view_);
 
-  folder_background_view_ = new FolderBackgroundView();
-  AddChildView(folder_background_view_);
+  // Page switcher should be initialized after AppsGridView.
+  page_switcher_ = new PageSwitcher(apps_grid_view_->pagination_model(),
+                                    true /* vertical */);
+  AddChildView(page_switcher_);
 
   app_list_folder_view_ =
       new AppListFolderView(this, model, app_list_main_view);
   // The folder view is initially hidden.
   app_list_folder_view_->SetVisible(false);
+  folder_background_view_ = new FolderBackgroundView(app_list_folder_view_);
+  AddChildView(folder_background_view_);
   AddChildView(app_list_folder_view_);
 
   apps_grid_view_->SetModel(model);
@@ -69,7 +74,10 @@
 
   CreateViewsForFolderTopItemsAnimation(folder_item, true);
 
+  // Disable all the items behind the folder so that they will not be reached
+  // during focus traversal.
   contents_view()->GetSearchBoxView()->search_box()->RequestFocus();
+  apps_grid_view_->DisableFocusForShowingActiveFolder(true);
 }
 
 void AppsContainerView::ShowApps(AppListFolderItem* folder_item) {
@@ -78,12 +86,12 @@
 
   PrepareToShowApps(folder_item);
   SetShowState(SHOW_APPS, true);
+  apps_grid_view_->DisableFocusForShowingActiveFolder(false);
 }
 
 void AppsContainerView::ResetForShowApps() {
   SetShowState(SHOW_APPS, false);
-  folder_background_view_->UpdateFolderContainerBubble(
-      FolderBackgroundView::NO_BUBBLE);
+  apps_grid_view_->DisableFocusForShowingActiveFolder(false);
 }
 
 void AppsContainerView::SetDragAndDropHostOfCurrentAppList(
@@ -100,6 +108,7 @@
 
   PrepareToShowApps(folder_item);
   SetShowState(SHOW_ITEM_REPARENT, false);
+  apps_grid_view_->DisableFocusForShowingActiveFolder(false);
 }
 
 bool AppsContainerView::IsInFolderView() const {
@@ -111,13 +120,40 @@
   show_state_ = AppsContainerView::SHOW_APPS;
 }
 
-gfx::Size AppsContainerView::CalculatePreferredSize() const {
-  const gfx::Size grid_size = apps_grid_view_->GetPreferredSize();
-  const gfx::Size folder_view_size = app_list_folder_view_->GetPreferredSize();
+void AppsContainerView::UpdateControlVisibility(AppListViewState app_list_state,
+                                                bool is_in_drag) {
+  apps_grid_view_->UpdateControlVisibility(app_list_state, is_in_drag);
+  page_switcher_->SetVisible(
+      app_list_state == AppListViewState::FULLSCREEN_ALL_APPS || is_in_drag);
+}
 
-  int width = std::max(grid_size.width(), folder_view_size.width());
-  int height = std::max(grid_size.height(), folder_view_size.height());
-  return gfx::Size(width, height);
+void AppsContainerView::UpdateOpacity() {
+  apps_grid_view_->UpdateOpacity();
+
+  // Updates the opacity of page switcher buttons. The same rule as all apps in
+  // AppsGridView.
+  AppListView* app_list_view = contents_view()->app_list_view();
+  bool should_restore_opacity =
+      !app_list_view->is_in_drag() &&
+      (app_list_view->app_list_state() != AppListViewState::CLOSED);
+  int screen_bottom = app_list_view->GetScreenBottom();
+  gfx::Rect switcher_bounds = page_switcher_->GetBoundsInScreen();
+  float centerline_above_work_area =
+      std::max<float>(screen_bottom - switcher_bounds.CenterPoint().y(), 0.f);
+  float opacity =
+      std::min(std::max((centerline_above_work_area - kAllAppsOpacityStartPx) /
+                            (kAllAppsOpacityEndPx - kAllAppsOpacityStartPx),
+                        0.f),
+               1.0f);
+  page_switcher_->layer()->SetOpacity(should_restore_opacity ? 1.0f : opacity);
+}
+
+gfx::Size AppsContainerView::CalculatePreferredSize() const {
+  gfx::Size size = apps_grid_view_->GetPreferredSize();
+  // Add padding to both side of the apps grid to keep it horizontally
+  // centered since we place page switcher on the right side.
+  size.Enlarge(kAppsGridLeftRightPadding * 2, 0);
+  return size;
 }
 
 void AppsContainerView::Layout() {
@@ -126,13 +162,36 @@
     return;
 
   switch (show_state_) {
-    case SHOW_APPS:
-      apps_grid_view_->SetBoundsRect(rect);
+    case SHOW_APPS: {
+      gfx::Rect grid_rect = rect;
+      grid_rect.Inset(kAppsGridLeftRightPadding, 0);
+      apps_grid_view_->SetBoundsRect(grid_rect);
+
+      gfx::Rect page_switcher_rect = rect;
+      const int page_switcher_width =
+          page_switcher_->GetPreferredSize().width();
+      page_switcher_rect.set_x(page_switcher_rect.right() -
+                               page_switcher_width);
+      page_switcher_rect.set_width(page_switcher_width);
+      page_switcher_->SetBoundsRect(page_switcher_rect);
       break;
-    case SHOW_ACTIVE_FOLDER:
+    }
+    case SHOW_ACTIVE_FOLDER: {
       folder_background_view_->SetBoundsRect(rect);
-      app_list_folder_view_->SetBoundsRect(rect);
+
+      // The opened folder view's center should try to overlap with the folder
+      // item's center while it must fit within the bounds of this view.
+      DCHECK(apps_grid_view_->activated_folder_item_view());
+      gfx::Rect item_bounds_in_container = apps_grid_view_->ConvertRectToParent(
+          apps_grid_view_->activated_folder_item_view()->bounds());
+      gfx::Rect folder_bounds_in_container =
+          gfx::Rect(app_list_folder_view_->GetPreferredSize());
+      folder_bounds_in_container += (item_bounds_in_container.CenterPoint() -
+                                     folder_bounds_in_container.CenterPoint());
+      folder_bounds_in_container.AdjustToFit(rect);
+      app_list_folder_view_->SetBoundsRect(folder_bounds_in_container);
       break;
+    }
     case SHOW_ITEM_REPARENT:
       break;
     default:
@@ -275,31 +334,24 @@
   switch (show_state_) {
     case SHOW_APPS:
       folder_background_view_->SetVisible(false);
-      if (show_apps_with_animation) {
+      apps_grid_view_->ResetForShowApps();
+      if (show_apps_with_animation)
         app_list_folder_view_->ScheduleShowHideAnimation(false, false);
-        apps_grid_view_->ScheduleShowHideAnimation(true);
-      } else {
+      else
         app_list_folder_view_->HideViewImmediately();
-        apps_grid_view_->ResetForShowApps();
-      }
       break;
     case SHOW_ACTIVE_FOLDER:
       folder_background_view_->SetVisible(true);
-      apps_grid_view_->ScheduleShowHideAnimation(false);
       app_list_folder_view_->ScheduleShowHideAnimation(true, false);
       break;
     case SHOW_ITEM_REPARENT:
       folder_background_view_->SetVisible(false);
-      folder_background_view_->UpdateFolderContainerBubble(
-          FolderBackgroundView::NO_BUBBLE);
       app_list_folder_view_->ScheduleShowHideAnimation(false, true);
-      apps_grid_view_->ScheduleShowHideAnimation(true);
       break;
     default:
       NOTREACHED();
   }
 
-  app_list_folder_view_->SetBackButtonLabel(IsInFolderView());
   Layout();
 }
 
@@ -317,6 +369,9 @@
 void AppsContainerView::CreateViewsForFolderTopItemsAnimation(
     AppListFolderItem* active_folder,
     bool open_folder) {
+  if (!is_folder_top_items_animation_enabled_)
+    return;
+
   top_icon_views_.clear();
   std::vector<gfx::Rect> top_items_bounds =
       GetTopItemIconBoundsInActiveFolder();
diff --git a/ui/app_list/views/apps_container_view.h b/ui/app_list/views/apps_container_view.h
index 3a18695c..400823a 100644
--- a/ui/app_list/views/apps_container_view.h
+++ b/ui/app_list/views/apps_container_view.h
@@ -27,6 +27,7 @@
 class AppListMainView;
 class AppListModel;
 class FolderBackgroundView;
+class PageSwitcher;
 
 // AppsContainerView contains a root level AppsGridView to render the root level
 // app items, and a AppListFolderView to render the app items inside the
@@ -65,6 +66,14 @@
   // Called to notify the AppsContainerView that a reparent drag has completed.
   void ReparentDragEnded();
 
+  // Updates the visibility of the items in this view according to
+  // |app_list_state| and |is_in_drag|.
+  void UpdateControlVisibility(AppListViewState app_list_state,
+                               bool is_in_drag);
+
+  // Updates the opacity of the items in this view during dragging.
+  void UpdateOpacity();
+
   // views::View overrides:
   gfx::Size CalculatePreferredSize() const override;
   void Layout() override;
@@ -91,6 +100,10 @@
   }
   AppListFolderView* app_list_folder_view() { return app_list_folder_view_; }
 
+  void set_folder_top_items_animation_enabled_for_test(bool enabled) {
+    is_folder_top_items_animation_enabled_ = enabled;
+  }
+
  private:
   enum ShowState {
     SHOW_NONE,  // initial state
@@ -123,6 +136,7 @@
   // The views below are owned by views hierarchy.
   AppsGridView* apps_grid_view_ = nullptr;
   AppListFolderView* app_list_folder_view_ = nullptr;
+  PageSwitcher* page_switcher_ = nullptr;
   FolderBackgroundView* folder_background_view_ = nullptr;
 
   ShowState show_state_ = SHOW_NONE;
@@ -133,6 +147,9 @@
 
   size_t top_icon_animation_pending_count_ = 0u;
 
+  // True if the animation for the folder top items is enabled.
+  bool is_folder_top_items_animation_enabled_ = true;
+
   DISALLOW_COPY_AND_ASSIGN(AppsContainerView);
 };
 
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 6f8fcbf..eba96767 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -31,7 +31,6 @@
 #include "ui/app_list/views/contents_view.h"
 #include "ui/app_list/views/expand_arrow_view.h"
 #include "ui/app_list/views/indicator_chip_view.h"
-#include "ui/app_list/views/page_switcher_vertical.h"
 #include "ui/app_list/views/pulsing_block_view.h"
 #include "ui/app_list/views/search_box_view.h"
 #include "ui/app_list/views/search_result_tile_item_view.h"
@@ -84,6 +83,9 @@
 constexpr int kTileHorizontalPadding = 12;
 constexpr int kTileVerticalPadding = 6;
 
+// Padding of a tile within the folder view.
+constexpr int kFolderTilePadding = 6;
+
 // Width in pixels of the area on the sides that triggers a page flip.
 constexpr int kPageFlipZoneSize = 40;
 
@@ -135,11 +137,6 @@
 constexpr float kExpandArrowShowStartFraction = 0.5f;
 constexpr float kExpandArrowShowEndFraction = 1.0f;
 
-// Range of the height of centerline above screen bottom that all apps should
-// change opacity.
-constexpr float kAllAppsOpacityStartPx = 8.0f;
-constexpr float kAllAppsOpacityEndPx = 144.0f;
-
 // The length of time we ignore scroll events on the AppsGridView after the
 // AppListView transitions to FULLSCREEN_ALL_APPS.
 constexpr base::TimeDelta kIgnoreScrollEventsDurationMs =
@@ -378,10 +375,10 @@
 
   pagination_model_.AddObserver(this);
 
-  page_switcher_view_ = new PageSwitcherVertical(&pagination_model_);
   pagination_controller_.reset(new PaginationController(
-      &pagination_model_, PaginationController::SCROLL_AXIS_VERTICAL));
-  AddChildView(page_switcher_view_);
+      &pagination_model_, folder_delegate_
+                              ? PaginationController::SCROLL_AXIS_HORIZONTAL
+                              : PaginationController::SCROLL_AXIS_VERTICAL));
 }
 
 AppsGridView::~AppsGridView() {
@@ -399,7 +396,6 @@
   if (item_list_)
     item_list_->RemoveObserver(this);
 
-  // Make sure |page_switcher_view_| is deleted before |pagination_model_|.
   view_model_.Clear();
   RemoveAllChildViews(true);
 }
@@ -409,8 +405,7 @@
   rows_per_page_ = rows_per_page;
 }
 
-// static
-gfx::Size AppsGridView::GetTotalTileSize() {
+gfx::Size AppsGridView::GetTotalTileSize() const {
   static gfx::Size rect_size;
 
   if (!rect_size.IsEmpty())
@@ -423,17 +418,17 @@
   return rect_size;
 }
 
-// static
-gfx::Insets AppsGridView::GetTilePadding() {
-  static gfx::Insets tile_padding_full_screen;
+gfx::Insets AppsGridView::GetTilePadding() const {
+  if (folder_delegate_)
+    return gfx::Insets(-kFolderTilePadding, -kFolderTilePadding);
+  return gfx::Insets(-kTileVerticalPadding, -kTileHorizontalPadding);
+}
 
-  // Full screen mode.
-  if (!tile_padding_full_screen.IsEmpty())
-    return tile_padding_full_screen;
-  tile_padding_full_screen =
-      gfx::Insets(-kTileVerticalPadding, -kTileHorizontalPadding,
-                  -kTileVerticalPadding, -kTileHorizontalPadding);
-  return tile_padding_full_screen;
+gfx::Size AppsGridView::GetTileGridSizeWithoutPadding() const {
+  gfx::Size size = GetTileGridSize();
+  gfx::Insets grid_padding = GetTilePadding();
+  size.Enlarge(grid_padding.width(), grid_padding.height());
+  return size;
 }
 
 void AppsGridView::ResetForShowApps() {
@@ -451,6 +446,14 @@
            static_cast<size_t>(view_model_.view_size()));
 }
 
+void AppsGridView::DisableFocusForShowingActiveFolder(bool disabled) {
+  for (auto* v : suggestions_container_->tile_views())
+    v->SetEnabled(!disabled);
+  for (int i = 0; i < view_model_.view_size(); ++i) {
+    view_model_.view_at(i)->SetEnabled(!disabled);
+  }
+}
+
 void AppsGridView::SetModel(AppListModel* model) {
   if (model_)
     model_->RemoveObserver(this);
@@ -494,8 +497,6 @@
   }
   if (suggestions_container_)
     suggestions_container_->ClearSelectedIndex();
-  if (expand_arrow_view_)
-    expand_arrow_view_->SetSelected(false);
 }
 
 bool AppsGridView::IsSelectedView(const AppListItemView* view) const {
@@ -505,7 +506,7 @@
 views::View* AppsGridView::GetSelectedView() const {
   if (selected_view_)
     return selected_view_;
-  if (expand_arrow_view_ && expand_arrow_view_->selected())
+  if (expand_arrow_view_ && expand_arrow_view_->HasFocus())
     return expand_arrow_view_;
   if (suggestions_container_)
     return suggestions_container_->GetSelectedView();
@@ -596,11 +597,6 @@
 
   MaybeStartPageFlipTimer(last_drag_point_);
 
-  gfx::Point page_switcher_point(last_drag_point_);
-  views::View::ConvertPointToTarget(this, page_switcher_view_,
-                                    &page_switcher_point);
-  page_switcher_view_->UpdateUIForDragPoint(page_switcher_point);
-
   if (last_folder_drop_target != folder_drop_target_ ||
       last_reorder_drop_target != reorder_drop_target_ ||
       last_drop_attempt != drop_attempt_) {
@@ -691,11 +687,6 @@
   AnimateToIdealBounds();
 
   StopPageFlipTimer();
-
-  // If user releases mouse inside a folder's grid view, burst the folder
-  // container ink bubble.
-  if (folder_delegate_ && !IsDraggingForReparentInHiddenGridView())
-    folder_delegate_->UpdateFolderViewBackground(false);
 }
 
 void AppsGridView::StopPageFlipTimer() {
@@ -826,10 +817,10 @@
 }
 
 gfx::Size AppsGridView::CalculatePreferredSize() const {
+  if (folder_delegate_)
+    return GetTileGridSize();
+
   gfx::Size size = gfx::Size(kAppsGridPreferredWidth, kAppsGridPreferredHeight);
-  // Add padding to both side of the apps grid to keep it horizontally
-  // centered since we place page switcher on the right side.
-  size.Enlarge(kAppsGridLeftRightPadding * 2, 0);
   return size;
 }
 
@@ -911,12 +902,6 @@
       view->SetBoundsRect(view_model_.ideal_bounds(i));
   }
   views::ViewModelUtils::SetViewBoundsToIdealBounds(pulsing_blocks_model_);
-
-  const int page_switcher_width =
-      page_switcher_view_->GetPreferredSize().width();
-  rect.set_x(rect.right() - page_switcher_width);
-  rect.set_width(page_switcher_width);
-  page_switcher_view_->SetBoundsRect(rect);
 }
 
 void AppsGridView::UpdateControlVisibility(AppListViewState app_list_state,
@@ -935,8 +920,6 @@
     AppListItemView* view = GetItemViewAt(i);
     view->SetVisible(fullscreen_apps_in_drag);
   }
-
-  page_switcher_view_->SetVisible(fullscreen_apps_in_drag);
 }
 
 bool AppsGridView::OnKeyPressed(const ui::KeyEvent& event) {
@@ -1000,6 +983,7 @@
     view_model_.Add(view, i);
     AddChildView(view);
   }
+  UpdateColsAndRowsForFolder();
   UpdatePaging();
   UpdatePulsingBlockViews();
   Layout();
@@ -1016,15 +1000,13 @@
 }
 
 int AppsGridView::TilesPerPage(int page) const {
+  if (folder_delegate_)
+    return kMaxFolderItemsPerPage;
   if (page == 0)
     return cols_ * (rows_per_page_ - 1);
   return cols_ * rows_per_page_;
 }
 
-int AppsGridView::LastIndexOfPage(int page) const {
-  return TilesPerPage(page) - 1;
-}
-
 void AppsGridView::UpdatePaging() {
   if (!view_model_.view_size() || !TilesPerPage(0)) {
     pagination_model_.SetTotalPages(0);
@@ -1164,180 +1146,6 @@
   return GetIndexFromModelIndex(view_index);
 }
 
-void AppsGridView::MoveSelected(int page_delta,
-                                int slot_x_delta,
-                                int slot_y_delta) {
-  if (expand_arrow_view_ && expand_arrow_view_->selected() &&
-      HandleExpandArrowMove(page_delta, slot_x_delta, slot_y_delta)) {
-    return;
-  }
-
-  if (!selected_view_) {
-    // If fullscreen app list is enabled and we are on the first page, moving
-    // selected should consider suggested apps tiles before all apps tiles.
-    int current_page = pagination_model_.selected_page();
-    if (!suggestions_container_ || current_page != 0)
-      return SetSelectedItemByIndex(Index(current_page, 0));
-    if (HandleSuggestionsMove(page_delta, slot_x_delta, slot_y_delta))
-      return;
-  }
-
-  const Index& selected = GetIndexOfView(selected_view_);
-  int target_slot = selected.slot + slot_x_delta + slot_y_delta * cols_;
-
-  // Moving left from the first slot of all apps tiles should move focus to
-  // the last slot of previous page or last tile of suggested apps.
-  if (selected.slot == 0 && slot_x_delta == -1) {
-    if (selected.page == 0) {
-      ClearSelectedView(selected_view_);
-      if (!suggestions_container_)
-        return;
-      suggestions_container_->SetSelectedIndex(
-          suggestions_container_->num_results() - 1);
-      return;
-    } else {
-      page_delta = -1;
-      target_slot = LastIndexOfPage(selected.page + page_delta);
-    }
-  }
-
-  // Moving right from last slot should flip to next page and focus on the
-  // first tile.
-  if (selected.slot == LastIndexOfPage(selected.page) && slot_x_delta == 1) {
-    page_delta = 1;
-    target_slot = 0;
-  }
-
-  // Moving up from the first row of all apps tiles should move focus to the
-  // last row of previous page or suggested apps.
-  if (selected.slot / cols_ == 0 && slot_y_delta == -1) {
-    if (selected.page == 0) {
-      ClearSelectedView(selected_view_);
-      if (!suggestions_container_)
-        return;
-      const int max_suggestion_index =
-          suggestions_container_->num_results() - 1;
-      int selected_index = std::min(max_suggestion_index, selected.slot);
-      suggestions_container_->SetSelectedIndex(selected_index);
-      return;
-    } else {
-      page_delta = -1;
-      target_slot = LastIndexOfPage(selected.page + page_delta) -
-                    (cols_ - 1 - selected.slot);
-    }
-  }
-
-  // Moving down from the last row of all apps tiles should move focus to the
-  // first row of next page if it exists.
-  if (LastIndexOfPage(selected.page) - selected.slot < cols_ &&
-      slot_y_delta == 1) {
-    if (selected.page < pagination_model_.total_pages() - 1) {
-      page_delta = 1;
-      target_slot =
-          (cols_ - 1) - (LastIndexOfPage(selected.page) - selected.slot);
-    } else {
-      target_slot = selected.slot;
-    }
-  }
-
-  // Clamp the target slot to the last item if we are moving in or to the last
-  // page but our target slot is past the end of the item list.
-  if (selected.page + page_delta == pagination_model_.total_pages() - 1) {
-    int last_item_slot =
-        GetIndexFromModelIndex(view_model_.view_size() - 1).slot;
-    if (last_item_slot < target_slot) {
-      target_slot = last_item_slot;
-    }
-  }
-
-  int target_page = std::min(pagination_model_.total_pages() - 1,
-                             std::max(selected.page + page_delta, 0));
-  SetSelectedItemByIndex(Index(target_page, target_slot));
-}
-
-bool AppsGridView::HandleSuggestionsMove(int page_delta,
-                                         int slot_x_delta,
-                                         int slot_y_delta) {
-  DCHECK(suggestions_container_);
-  DCHECK(expand_arrow_view_);
-
-  if (suggestions_container_->selected_index() == -1) {
-    suggestions_container_->SetSelectedIndex(0);
-    return true;
-  }
-
-  if (page_delta == -1 || slot_y_delta == -1)
-    return true;
-
-  if (slot_x_delta != 0) {
-    int new_index = suggestions_container_->selected_index() + slot_x_delta;
-    if (new_index == suggestions_container_->num_results()) {
-      suggestions_container_->ClearSelectedIndex();
-      if (contents_view_->GetActiveState() == AppListModel::STATE_START) {
-        // In state start, moving right out of |suggestions_container_| should
-        // give selection to the expand arrow.
-        expand_arrow_view_->SetSelected(true);
-      } else {
-        DCHECK(contents_view_->GetActiveState() == AppListModel::STATE_APPS);
-        // In state apps, moving right out of |suggestions_container_| should
-        // give selection to the first tile of all apps.
-        SetSelectedItemByIndex(Index(0, 0));
-      }
-    } else if (suggestions_container_->IsValidSelectionIndex(new_index)) {
-      suggestions_container_->SetSelectedIndex(new_index);
-    }
-    return true;
-  }
-
-  if (slot_y_delta == 1) {
-    if (contents_view_->GetActiveState() == AppListModel::STATE_START) {
-      // In state start, moving down from |suggestions_container_| should give
-      // selection to the expand arrow.
-      expand_arrow_view_->SetSelected(true);
-    } else {
-      DCHECK(contents_view_->GetActiveState() == AppListModel::STATE_APPS);
-      // In state apps, moving down from |suggestions_container_| should give
-      // selection to the first row of all apps.
-      SetSelectedItemByIndex(
-          Index(0, suggestions_container_->selected_index()));
-    }
-    suggestions_container_->ClearSelectedIndex();
-    return true;
-  }
-
-  // A page flip to next page from |suggestions_container_| should focus to
-  // the first tile of next page.
-  if (page_delta == 1) {
-    SetSelectedItemByIndex(Index(page_delta, 0));
-    suggestions_container_->ClearSelectedIndex();
-    return true;
-  }
-  return false;
-}
-
-bool AppsGridView::HandleExpandArrowMove(int page_delta,
-                                         int slot_x_delta,
-                                         int slot_y_delta) {
-  DCHECK(suggestions_container_);
-  DCHECK(expand_arrow_view_);
-  DCHECK(contents_view_->GetActiveState() == AppListModel::STATE_START);
-
-  if (page_delta != 0 || slot_x_delta == 1 || slot_y_delta == 1 ||
-      (slot_x_delta == 0 && slot_y_delta == 0)) {
-    return true;
-  }
-
-  if (slot_x_delta == -1 || slot_y_delta == -1) {
-    // Move focus to the last app in ||suggestions_container|.
-    expand_arrow_view_->SetSelected(false);
-    suggestions_container_->SetSelectedIndex(
-        suggestions_container_->num_results() - 1);
-    return true;
-  }
-
-  return false;
-}
-
 const gfx::Vector2d AppsGridView::CalculateTransitionOffset(
     int page_of_view) const {
   gfx::Size grid_size = GetTileGridSize();
@@ -1574,7 +1382,8 @@
   // Items can only be dropped into non-folders (which have no children) or
   // folders that have fewer than the max allowed items.
   // The OEM folder does not allow drag/drop of other items into it.
-  if (target_item->ChildItemCount() >= kMaxFolderItems ||
+  const size_t kMaxItemCount = kMaxFolderItemsPerPage * kMaxFolderPages;
+  if (target_item->ChildItemCount() >= kMaxItemCount ||
       IsOEMFolderItem(target_item)) {
     return false;
   }
@@ -1657,9 +1466,6 @@
     return;
   }
 
-  // Regular drag and drop in a folder's grid view.
-  folder_delegate_->UpdateFolderViewBackground(true);
-
   // Calculate if the drag_view_ is dragged out of the folder's container
   // ink bubble.
   gfx::Rect bounds_to_folder_view = ConvertRectToParent(drag_view_->bounds());
@@ -1767,7 +1573,7 @@
   // Move focus based on target global focus index.
   if (target_global_index < 0 || target_global_index >= cols_ * row_total) {
     // Target index is outside apps grid view.
-    if (folder_delegate_ && arrow_up) {
+    if (folder_delegate_ && !arrow_up) {
       contents_view_->apps_container_view()
           ->app_list_folder_view()
           ->folder_header_view()
@@ -1785,6 +1591,17 @@
   return true;
 }
 
+void AppsGridView::UpdateColsAndRowsForFolder() {
+  if (!folder_delegate_ || !item_list_->item_count())
+    return;
+
+  // Try to shape the apps grid into a square.
+  int items_in_one_page =
+      std::min(kMaxFolderItemsPerPage, item_list_->item_count());
+  cols_ = std::sqrt(items_in_one_page - 1) + 1;
+  rows_per_page_ = (items_in_one_page - 1) / cols_ + 1;
+}
+
 void AppsGridView::DispatchDragEventForReparent(Pointer pointer,
                                                 const gfx::Point& drag_point) {
   folder_delegate_->DispatchDragEventForReparent(pointer, drag_point);
@@ -1969,20 +1786,6 @@
 
     item_view->layer()->SetOpacity(should_restore_opacity ? 1.0f : opacity);
   }
-
-  // Updates the opacity of page switcher buttons. The same rule as all apps.
-  if (page_switcher_view_) {
-    gfx::Rect switcher_bounds = page_switcher_view_->GetBoundsInScreen();
-    centerline_above_work_area =
-        std::max<float>(screen_bottom - switcher_bounds.CenterPoint().y(), 0.f);
-    opacity = std::min(
-        std::max((centerline_above_work_area - kAllAppsOpacityStartPx) /
-                     (kAllAppsOpacityEndPx - kAllAppsOpacityStartPx),
-                 0.f),
-        1.0f);
-    page_switcher_view_->layer()->SetOpacity(should_restore_opacity ? 1.0f
-                                                                    : opacity);
-  }
 }
 
 void AppsGridView::StartTimerToIgnoreScrollEvents() {
@@ -2076,14 +1879,6 @@
     else if (drag_point.y() > height() - kPageFlipZoneSize)
       new_page_flip_target = pagination_model_.selected_page() + 1;
   } else {
-    if (page_switcher_view_->bounds().Contains(drag_point)) {
-      gfx::Point page_switcher_point(drag_point);
-      views::View::ConvertPointToTarget(this, page_switcher_view_,
-                                        &page_switcher_point);
-      new_page_flip_target =
-          page_switcher_view_->GetPageForPoint(page_switcher_point);
-    }
-
     // TODO(xiyuan): Fix this for RTL.
     if (new_page_flip_target == -1 && drag_point.x() < kPageFlipZoneSize)
       new_page_flip_target = pagination_model_.selected_page() - 1;
@@ -2181,6 +1976,7 @@
   bounds_animator_.SetAnimationDelegate(
       drag_view_, std::unique_ptr<gfx::AnimationDelegate>(
                       new ItemRemoveAnimationDelegate(drag_view_)));
+  UpdateColsAndRowsForFolder();
   UpdatePaging();
 }
 
@@ -2223,6 +2019,7 @@
 
   item_list_->AddObserver(this);
   model_->AddObserver(this);
+  UpdateColsAndRowsForFolder();
   UpdatePaging();
 }
 
@@ -2295,6 +2092,7 @@
   bounds_animator_.SetAnimationDelegate(
       drag_view_, std::unique_ptr<gfx::AnimationDelegate>(
                       new ItemRemoveAnimationDelegate(drag_view_)));
+  UpdateColsAndRowsForFolder();
   UpdatePaging();
 
   return true;
@@ -2420,6 +2218,7 @@
   // on drag/animation from PEEKING.
   view->SetVisible(model_->state_fullscreen() != AppListViewState::PEEKING);
 
+  UpdateColsAndRowsForFolder();
   UpdatePaging();
   UpdatePulsingBlockViews();
   Layout();
@@ -2431,6 +2230,7 @@
 
   DeleteItemViewAtIndex(index);
 
+  UpdateColsAndRowsForFolder();
   UpdatePaging();
   UpdatePulsingBlockViews();
   Layout();
@@ -2443,6 +2243,7 @@
   EndDrag(true);
   view_model_.Move(from_index, to_index);
 
+  UpdateColsAndRowsForFolder();
   UpdatePaging();
   AnimateToIdealBounds();
 }
@@ -2540,7 +2341,13 @@
 }
 
 gfx::Size AppsGridView::GetTileGridSize() const {
-  return gfx::Size(kAppsGridPreferredWidth, kAppsGridPreferredHeight);
+  if (!folder_delegate_)
+    return gfx::Size(kAppsGridPreferredWidth, kAppsGridPreferredHeight);
+
+  gfx::Rect bounds = GetExpectedTileBounds(Index(0, 0));
+  bounds.Union(GetExpectedTileBounds(Index(0, rows_per_page_ * cols_ - 1)));
+  bounds.Inset(GetTilePadding());
+  return bounds.size();
 }
 
 int AppsGridView::GetHeightOnTopOfAllAppsTiles(int page) const {
@@ -2559,8 +2366,13 @@
 }
 
 gfx::Rect AppsGridView::GetExpectedTileBounds(const Index& index) const {
+  if (!cols_)
+    return gfx::Rect();
+
   gfx::Rect bounds(GetContentsBounds());
-  bounds.Offset(kAppsGridLeftRightPadding - kTileHorizontalPadding, 0);
+  if (!folder_delegate_)
+    bounds.Offset(-kTileHorizontalPadding, 0);
+
   bounds.Inset(0, GetHeightOnTopOfAllAppsTiles(index.page), 0, 0);
   int row = index.slot / cols_;
   int col = index.slot % cols_;
diff --git a/ui/app_list/views/apps_grid_view.h b/ui/app_list/views/apps_grid_view.h
index 0cbee48..2a7fb28 100644
--- a/ui/app_list/views/apps_grid_view.h
+++ b/ui/app_list/views/apps_grid_view.h
@@ -51,7 +51,6 @@
 class ContentsView;
 class IndicatorChipView;
 class SuggestionsContainerView;
-class PageSwitcher;
 class PaginationController;
 class PulsingBlockView;
 class ExpandArrowView;
@@ -82,14 +81,21 @@
   int rows_per_page() const { return rows_per_page_; }
 
   // Returns the size of a tile view including its padding.
-  static gfx::Size GetTotalTileSize();
+  gfx::Size GetTotalTileSize() const;
 
   // Returns the padding around a tile view.
-  static gfx::Insets GetTilePadding();
+  gfx::Insets GetTilePadding() const;
+
+  // Returns the size of the entire tile grid without padding.
+  gfx::Size GetTileGridSizeWithoutPadding() const;
 
   // This resets the grid view to a fresh state for showing the app list.
   void ResetForShowApps();
 
+  // All items in this view become unfocusable if |disabled| is true. This is
+  // used to trap focus within the folder when it is opened.
+  void DisableFocusForShowingActiveFolder(bool disabled);
+
   // Sets |model| to use. Note this does not take ownership of |model|.
   void SetModel(AppListModel* model);
 
@@ -236,6 +242,8 @@
     folder_delegate_ = folder_delegate;
   }
 
+  bool is_in_folder() const { return !!folder_delegate_; }
+
   AppListItemView* activated_folder_item_view() const {
     return activated_folder_item_view_;
   }
@@ -289,9 +297,6 @@
   // Returns all apps tiles per page based on |page|.
   int TilesPerPage(int page) const;
 
-  // Returns the last index of |page|.
-  int LastIndexOfPage(int page) const;
-
   // Updates from model.
   void Update();
 
@@ -326,20 +331,6 @@
   // Gets the index of the AppListItemView at the end of the view model.
   Index GetLastViewIndex() const;
 
-  void MoveSelected(int page_delta, int slot_x_delta, int slot_y_delta);
-
-  // Returns true if the given moving operation should be handled by
-  // |suggestions_container_|, otherwise false.
-  bool HandleSuggestionsMove(int page_delta,
-                             int slot_x_delta,
-                             int slot_y_delta);
-
-  // Returns true if the given moving operation should be handled by
-  // |expand_arrow_view_|, otherwise false.
-  bool HandleExpandArrowMove(int page_delta,
-                             int slot_x_delta,
-                             int slot_y_delta);
-
   // Calculates the offset for |page_of_view| based on current page and
   // transition target page.
   const gfx::Vector2d CalculateTransitionOffset(int page_of_view) const;
@@ -533,6 +524,9 @@
   // state.
   bool HandleFocusMovementInFullscreenAllAppsState(bool arrow_up);
 
+  // Update number of columns and rows for apps within a folder.
+  void UpdateColsAndRowsForFolder();
+
   AppListModel* model_ = nullptr;         // Owned by AppListView.
   AppListItemList* item_list_ = nullptr;  // Not owned.
 
@@ -542,7 +536,6 @@
   PaginationModel pagination_model_;
   // Must appear after |pagination_model_|.
   std::unique_ptr<PaginationController> pagination_controller_;
-  PageSwitcher* page_switcher_view_ = nullptr;  // Owned by views hierarchy.
 
   // Created by AppListMainView, owned by views hierarchy.
   ContentsView* contents_view_ = nullptr;
diff --git a/ui/app_list/views/apps_grid_view_folder_delegate.h b/ui/app_list/views/apps_grid_view_folder_delegate.h
index 924a653..402fc7b 100644
--- a/ui/app_list/views/apps_grid_view_folder_delegate.h
+++ b/ui/app_list/views/apps_grid_view_folder_delegate.h
@@ -19,10 +19,6 @@
 // A delegate which allows an AppsGridView to communicate with its host folder.
 class APP_LIST_EXPORT AppsGridViewFolderDelegate {
  public:
-  // Updates the folder view background to show or hide folder container ink
-  // bubble.
-  virtual void UpdateFolderViewBackground(bool show_bubble) = 0;
-
   // Called when a folder item is dragged out of the folder to be re-parented.
   // |original_drag_view| is the |drag_view_| inside the folder's grid view.
   // |drag_point_in_folder_grid| is the last drag point in coordinate of the
diff --git a/ui/app_list/views/apps_grid_view_unittest.cc b/ui/app_list/views/apps_grid_view_unittest.cc
index c4880332..2a33975 100644
--- a/ui/app_list/views/apps_grid_view_unittest.cc
+++ b/ui/app_list/views/apps_grid_view_unittest.cc
@@ -30,6 +30,7 @@
 #include "ui/app_list/test/app_list_test_model.h"
 #include "ui/app_list/test/app_list_test_view_delegate.h"
 #include "ui/app_list/test/test_search_result.h"
+#include "ui/app_list/views/app_list_folder_view.h"
 #include "ui/app_list/views/app_list_item_view.h"
 #include "ui/app_list/views/app_list_main_view.h"
 #include "ui/app_list/views/app_list_view.h"
@@ -37,6 +38,7 @@
 #include "ui/app_list/views/apps_grid_view_folder_delegate.h"
 #include "ui/app_list/views/contents_view.h"
 #include "ui/app_list/views/expand_arrow_view.h"
+#include "ui/app_list/views/folder_background_view.h"
 #include "ui/app_list/views/search_box_view.h"
 #include "ui/app_list/views/search_result_tile_item_view.h"
 #include "ui/app_list/views/suggestions_container_view.h"
@@ -178,6 +180,10 @@
     return apps_grid_view_->pagination_model();
   }
 
+  AppListFolderView* app_list_folder_view() const {
+    return contents_view_->apps_container_view()->app_list_folder_view();
+  }
+
   // Points are in |apps_grid_view_|'s coordinates, and fixed for RTL.
   AppListItemView* SimulateDrag(AppsGridView::Pointer pointer,
                                 const gfx::Point& from,
@@ -215,30 +221,6 @@
     apps_grid_view_->OnKeyPressed(key_event);
   }
 
-  bool CheckNoSelection() {
-    return !expand_arrow_view_->selected() &&
-           -1 == suggestions_container_->selected_index() &&
-           !apps_grid_view_->has_selected_view();
-  }
-
-  bool CheckSelectionAtSuggestionsContainer(int index) {
-    return !expand_arrow_view_->selected() &&
-           index == suggestions_container_->selected_index() &&
-           !apps_grid_view_->has_selected_view();
-  }
-
-  bool CheckSelectionAtExpandArrow() {
-    return expand_arrow_view_->selected() &&
-           -1 == suggestions_container_->selected_index() &&
-           !apps_grid_view_->has_selected_view();
-  }
-
-  bool CheckSelectionAtAppsGridView(int index) {
-    return !expand_arrow_view_->selected() &&
-           -1 == suggestions_container_->selected_index() &&
-           apps_grid_view_->IsSelectedView(GetItemViewAt(index));
-  }
-
   AppListView* app_list_view_ = nullptr;    // Owned by native widget.
   AppsGridView* apps_grid_view_ = nullptr;  // Owned by |app_list_view_|.
   ContentsView* contents_view_ = nullptr;   // Owned by |app_list_view_|.
@@ -269,11 +251,6 @@
   TestAppsGridViewFolderDelegate() = default;
   ~TestAppsGridViewFolderDelegate() override = default;
 
-  // Overridden from AppsGridViewFolderDelegate:
-  void UpdateFolderViewBackground(bool show_bubble) override {
-    show_bubble_ = show_bubble;
-  }
-
   void ReparentItem(AppListItemView* original_drag_view,
                     const gfx::Point& drag_point_in_folder_grid,
                     bool has_native_drag) override {}
@@ -293,11 +270,7 @@
 
   void SetRootLevelDragViewVisible(bool visible) override {}
 
-  bool show_bubble() { return show_bubble_; }
-
  private:
-  bool show_bubble_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(TestAppsGridViewFolderDelegate);
 };
 
@@ -407,7 +380,8 @@
 
 TEST_P(AppsGridViewTest, MouseDragMaxItemsInFolder) {
   // Create and add a folder with |kMaxFolderItemsFullscreen - 1| items.
-  size_t kTotalItems = kMaxFolderItems - 1;
+  const size_t kMaxItems = kMaxFolderItemsPerPage * kMaxFolderPages;
+  const size_t kTotalItems = kMaxItems - 1;
   model_->CreateAndPopulateFolderWithApps(kTotalItems);
   EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
   EXPECT_EQ(AppListFolderItem::kItemType,
@@ -421,9 +395,9 @@
   model_->PopulateAppWithId(kTotalItems + 1);
   EXPECT_EQ(3u, model_->top_level_item_list()->item_count());
   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
-  EXPECT_EQ(model_->GetItemName(kMaxFolderItems - 1),
+  EXPECT_EQ(model_->GetItemName(kMaxItems - 1),
             model_->top_level_item_list()->item_at(1)->id());
-  EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
+  EXPECT_EQ(model_->GetItemName(kMaxItems),
             model_->top_level_item_list()->item_at(2)->id());
 
   gfx::Point from = GetItemRectOnCurrentPageAt(0, 1).CenterPoint();
@@ -434,8 +408,8 @@
   apps_grid_view_->EndDrag(false);
   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
-  EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
-  EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
+  EXPECT_EQ(kMaxItems, folder_item->ChildItemCount());
+  EXPECT_EQ(model_->GetItemName(kMaxItems),
             model_->top_level_item_list()->item_at(1)->id());
   test_api_->LayoutToIdealBounds();
 
@@ -444,7 +418,7 @@
   SimulateDrag(AppsGridView::MOUSE, from, to);
   apps_grid_view_->EndDrag(false);
   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
-  EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
+  EXPECT_EQ(kMaxItems, folder_item->ChildItemCount());
   test_api_->LayoutToIdealBounds();
 }
 
@@ -452,8 +426,9 @@
 // folder.
 TEST_P(AppsGridViewTest, MouseDragMaxItemsInFolderWithMovement) {
   // Create and add a folder with |kMaxFolderItemsFullscreen| in it.
-  size_t kTotalItems = kMaxFolderItems;
-  model_->CreateAndPopulateFolderWithApps(kTotalItems);
+  const size_t kMaxItems = kMaxFolderItemsPerPage * kMaxFolderPages;
+  size_t kTotalItems = kMaxItems;
+  model_->CreateAndPopulateFolderWithApps(kMaxItems);
   EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
   EXPECT_EQ(AppListFolderItem::kItemType,
             model_->top_level_item_list()->item_at(0)->GetItemType());
@@ -465,7 +440,7 @@
   model_->PopulateAppWithId(kTotalItems);
   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
   EXPECT_EQ(folder_item->id(), model_->top_level_item_list()->item_at(0)->id());
-  EXPECT_EQ(model_->GetItemName(kMaxFolderItems),
+  EXPECT_EQ(model_->GetItemName(kMaxItems),
             model_->top_level_item_list()->item_at(1)->id());
 
   AppListItemView* folder_view =
@@ -495,7 +470,7 @@
 
   // The item should not have moved into the folder.
   EXPECT_EQ(2u, model_->top_level_item_list()->item_count());
-  EXPECT_EQ(kMaxFolderItems, folder_item->ChildItemCount());
+  EXPECT_EQ(kMaxItems, folder_item->ChildItemCount());
   test_api_->LayoutToIdealBounds();
 }
 
@@ -685,9 +660,7 @@
 
   // Starts a mouse drag and then cancels it.
   SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
-  EXPECT_TRUE(folder_delegate.show_bubble());
   apps_grid_view_->EndDrag(true);
-  EXPECT_FALSE(folder_delegate.show_bubble());
   EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
             model_->GetModelContent());
 }
@@ -749,33 +722,6 @@
       apps_grid_view_->IsSelectedView(GetItemViewAt(kAllAppsItems - 1)));
 }
 
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that moving selection down from the searchbox selects the first app.
-TEST_P(AppsGridViewTest, DISABLED_SelectionDownFromSearchBoxSelectsFirstApp) {
-  model_->PopulateApps(5);
-  // Check that nothing is selected.
-  EXPECT_TRUE(CheckNoSelection());
-
-  // Moves selection to the first app in the suggestions container.
-  SimulateKeyPress(ui::VKEY_DOWN);
-
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(0));
-}
-
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that moving selection up from the first app selects nothing.
-TEST_P(AppsGridViewTest, DISABLED_SelectionUpFromFirstAppSelectsNothing) {
-  model_->PopulateApps(5);
-  // Select the first app.
-  suggestions_container_->SetSelectedIndex(0);
-
-  // Tests moving up.
-  SimulateKeyPress(ui::VKEY_UP);
-
-  // Check that there is no selection in AppsGridView.
-  EXPECT_TRUE(CheckNoSelection());
-}
-
 // Tests that UMA is properly collected when either a suggested or normal app is
 // launched.
 TEST_F(AppsGridViewTest, UMATestForLaunchingApps) {
@@ -801,243 +747,6 @@
   histogram_tester.ExpectBucketCount("Apps.AppListAppLaunchedFullscreen", 1, 1);
 }
 
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that moving selection backwards (left in ltr, right in rtl) from the
-// first app selects nothing, and that selection returns to the suggested apps
-// when selection moves forwards (right in ltr, left in rtl).
-TEST_P(AppsGridViewTest,
-       DISABLED_SelectionMovingBackwardsAndForwardsOnFirstSuggestedApp) {
-  model_->PopulateApps(5);
-
-  // Check that nothing is selected.
-  EXPECT_TRUE(CheckNoSelection());
-
-  // Move selection forward.
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_LEFT : ui::VKEY_RIGHT);
-
-  // Check that the first suggested app is selected.
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(0));
-
-  // Move selection backward.
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_RIGHT : ui::VKEY_LEFT);
-
-  // Check that there is no selection.
-  EXPECT_TRUE(CheckNoSelection());
-
-  // Move selection forward.
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_LEFT : ui::VKEY_RIGHT);
-
-  // Check that the first suggested app is selected.
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(0));
-}
-
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that selection can traverse all suggested apps.
-TEST_P(AppsGridViewTest, DISABLED_SelectionTraversesAllSuggestedApps) {
-  model_->PopulateApps(5);
-
-  // Select the first suggested app.
-  suggestions_container_->SetSelectedIndex(0);
-
-  // Advance selection to the next app.
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_LEFT : ui::VKEY_RIGHT);
-
-  // Check selection at the next suggested app.
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(1));
-
-  // Advance selection to the next app.
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_LEFT : ui::VKEY_RIGHT);
-
-  // Check selection at the next suggested app.
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(2));
-
-  // Advance selection to the next app, which is in the AppsGridView.
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_LEFT : ui::VKEY_RIGHT);
-
-  // Check selection at the first app in AppsGridView.
-  EXPECT_TRUE(CheckSelectionAtAppsGridView(0));
-}
-
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that selection moves from the last suggested app to the first app that
-// is not suggested when selection moves forward.
-TEST_P(AppsGridViewTest,
-       DISABLED_SelectionMovesFromLastSuggestedAppToFirstAppInGrid) {
-  model_->PopulateApps(5);
-  // Select the last of three selected apps.
-  suggestions_container_->SetSelectedIndex(2);
-
-  // Move selection forward, off of the last suggested app.
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_LEFT : ui::VKEY_RIGHT);
-
-  // Check selection at apps grid view position 0 (first app in the app grid).
-  EXPECT_TRUE(CheckSelectionAtAppsGridView(0));
-}
-
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that selection moves to the first element of the next page when the
-// next key is pressed.
-TEST_P(AppsGridViewTest,
-       DISABLED_SelectionMovesToFirstElementOfNextPageWithNextKey) {
-  const int kPages = 2;
-  const int kAllAppsItems = GetTilesPerPage(0) + 1;
-  model_->PopulateApps(kAllAppsItems);
-  // Check that the first page is selected.
-  EXPECT_EQ(0, GetPaginationModel()->selected_page());
-
-  // Move to next page.
-  apps_grid_view_->ClearAnySelectedView();
-  SimulateKeyPress(ui::VKEY_DOWN);
-  SimulateKeyPress(ui::VKEY_NEXT);
-
-  // Check that the selection is on the last app item, and that the page changed
-  // to the last page.
-  EXPECT_TRUE(CheckSelectionAtAppsGridView(kAllAppsItems - 1));
-  EXPECT_EQ(kPages - 1, GetPaginationModel()->selected_page());
-}
-
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that selection moves to the first element of the previous page with the
-// prev key.
-TEST_P(AppsGridViewTest,
-       DISABLED_SelectionMovesToFirstElementOfPrevPageWithPrevKey) {
-  const int kAllAppsItems = GetTilesPerPage(0) + 1;
-  model_->PopulateApps(kAllAppsItems);
-  // Move to next page.
-  apps_grid_view_->ClearAnySelectedView();
-  SimulateKeyPress(ui::VKEY_DOWN);
-  SimulateKeyPress(ui::VKEY_NEXT);
-  EXPECT_TRUE(
-      apps_grid_view_->IsSelectedView(GetItemViewAt(kAllAppsItems - 1)));
-
-  // Press the PREV key to return to the previous page.
-  SimulateKeyPress(ui::VKEY_PRIOR);
-
-  // Check that the page has changed to page 0, and the first app is selected.
-  EXPECT_TRUE(CheckSelectionAtAppsGridView(0));
-  EXPECT_EQ(0, GetPaginationModel()->selected_page());
-}
-
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that in state start there's no selection at the beginning. And hitting
-// down/tab/right arrow key moves the selection to the first app in suggestions
-// container.
-TEST_P(AppsGridViewTest, DISABLED_InitialSelectionInStateStart) {
-  // Simulates that the app list is at state start.
-  contents_view_->SetActiveState(AppListModel::STATE_START);
-  model_->PopulateApps(GetTilesPerPage(0));
-  EXPECT_TRUE(CheckNoSelection());
-
-  SimulateKeyPress(ui::VKEY_DOWN);
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(0));
-
-  apps_grid_view_->ClearAnySelectedView();
-  SimulateKeyPress(ui::VKEY_RIGHT);
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(0));
-
-  apps_grid_view_->ClearAnySelectedView();
-  SimulateKeyPress(ui::VKEY_TAB);
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(0));
-}
-
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that in state start when selection exists. Hitting tab key does
-// nothing while hitting shift+tab key clears selection.
-TEST_P(AppsGridViewTest, DISABLED_ClearSelectionInStateStart) {
-  // Simulates that the app list is at state start.
-  contents_view_->SetActiveState(AppListModel::STATE_START);
-  model_->PopulateApps(GetTilesPerPage(0));
-
-  // Moves selection to the first app in the suggestions container.
-  SimulateKeyPress(ui::VKEY_DOWN);
-
-  SimulateKeyPress(ui::VKEY_TAB);
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(0));
-
-  SimulateKeyPress(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
-  EXPECT_TRUE(CheckNoSelection());
-}
-
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that in state start when selection is on expand arrow, only hitting
-// left/up arrow key moves the selection to the last app in suggestion
-// container.
-TEST_P(AppsGridViewTest, DISABLED_ExpandArrowSelectionInStateStart) {
-  // Simulates that the app list is at state start.
-  contents_view_->SetActiveState(AppListModel::STATE_START);
-  model_->PopulateApps(GetTilesPerPage(0));
-
-  // Moves selection to the expand arrow.
-  expand_arrow_view_->SetSelected(true);
-
-  // Expect the selection to be on the expand arrow.
-  EXPECT_TRUE(CheckSelectionAtExpandArrow());
-
-  SimulateKeyPress(ui::VKEY_DOWN);
-
-  // Expect the selection to be on the expand arrow.
-  EXPECT_TRUE(CheckSelectionAtExpandArrow());
-
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_LEFT : ui::VKEY_RIGHT);
-
-  // Expect the selection to be on the expand arrow.
-  EXPECT_TRUE(CheckSelectionAtExpandArrow());
-
-  SimulateKeyPress(ui::VKEY_TAB);
-
-  // Expect the selection to be on the expand arrow.
-  EXPECT_TRUE(CheckSelectionAtExpandArrow());
-
-  SimulateKeyPress(ui::VKEY_UP);
-
-  // Expect the selection to be on the last suggested app.
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(kNumOfSuggestedApps - 1));
-
-  // Resets selection to the expand arrow.
-  apps_grid_view_->ClearAnySelectedView();
-  expand_arrow_view_->SetSelected(true);
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_RIGHT : ui::VKEY_LEFT);
-
-  // Expect the selection to be on the last suggested app.
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(kNumOfSuggestedApps - 1));
-}
-
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-// Tests that in state start when selection is on app in suggestions container,
-// hitting up key moves clear selection. Hitting left/right key moves the
-// selection to app on the left/right if index is valid. Hitting right key when
-// selection is on the last app in suggestions container or hitting down key
-// move the selection to the expand arrow.
-TEST_P(AppsGridViewTest, DISABLED_SuggestionsContainerSelectionInStateStart) {
-  // Simulates that the app list is at state start.
-  contents_view_->SetActiveState(AppListModel::STATE_START);
-  model_->PopulateApps(GetTilesPerPage(0));
-  SimulateKeyPress(ui::VKEY_DOWN);
-
-  // Tests moving up.
-  SimulateKeyPress(ui::VKEY_UP);
-  EXPECT_TRUE(CheckNoSelection());
-  SimulateKeyPress(ui::VKEY_DOWN);
-
-  // Tests moving right.
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_LEFT : ui::VKEY_RIGHT);
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(1));
-
-  // Tests moving left.
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_RIGHT : ui::VKEY_LEFT);
-  EXPECT_TRUE(CheckSelectionAtSuggestionsContainer(0));
-
-  // Tests moving down.
-  SimulateKeyPress(ui::VKEY_DOWN);
-  EXPECT_TRUE(CheckSelectionAtExpandArrow());
-
-  // Sets selection to the last app in the suggestions container.
-  apps_grid_view_->ClearAnySelectedView();
-  suggestions_container_->SetSelectedIndex(kNumOfSuggestedApps - 1);
-  SimulateKeyPress(is_rtl_ ? ui::VKEY_LEFT : ui::VKEY_RIGHT);
-  EXPECT_TRUE(CheckSelectionAtExpandArrow());
-}
-
 TEST_F(AppsGridViewTest, ItemLabelShortNameOverride) {
   // If the app's full name and short name differ, the title label's tooltip
   // should always be the full name of the app.
@@ -1119,5 +828,103 @@
   ASSERT_NE(0, GetPaginationModel()->transition().progress);
 }
 
+TEST_F(AppsGridViewTest, CloseFolderByClickingBackground) {
+  // Disable the animation for the folder top items for test purpose.
+  AppsContainerView* apps_container_view =
+      contents_view_->apps_container_view();
+  apps_container_view->set_folder_top_items_animation_enabled_for_test(false);
+
+  const size_t kTotalItems = kMaxFolderItemsPerPage;
+  model_->CreateAndPopulateFolderWithApps(kTotalItems);
+  EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
+  EXPECT_EQ(AppListFolderItem::kItemType,
+            model_->top_level_item_list()->item_at(0)->GetItemType());
+
+  // Open the folder.
+  test_api_->PressItemAt(0);
+  EXPECT_TRUE(apps_container_view->IsInFolderView());
+
+  // Simulate mouse press on folder background to close the folder.
+  ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
+                       ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                       ui::EF_LEFT_MOUSE_BUTTON);
+  apps_container_view->folder_background_view()->OnMouseEvent(&event);
+  EXPECT_FALSE(apps_container_view->IsInFolderView());
+}
+
+TEST_F(AppsGridViewTest, PageResetAfterOpenFolder) {
+  // Disable the animation for the folder top items for test purpose.
+  contents_view_->apps_container_view()
+      ->set_folder_top_items_animation_enabled_for_test(false);
+
+  const size_t kTotalItems = kMaxFolderPages * kMaxFolderItemsPerPage;
+  model_->CreateAndPopulateFolderWithApps(kTotalItems);
+  EXPECT_EQ(1u, model_->top_level_item_list()->item_count());
+  EXPECT_EQ(AppListFolderItem::kItemType,
+            model_->top_level_item_list()->item_at(0)->GetItemType());
+
+  // Open the folder. It should be at page 0.
+  test_api_->PressItemAt(0);
+  PaginationModel* pagination_model =
+      app_list_folder_view()->items_grid_view()->pagination_model();
+  EXPECT_EQ(3, pagination_model->total_pages());
+  EXPECT_EQ(0, pagination_model->selected_page());
+
+  // Select page 2.
+  pagination_model->SelectPage(2, false /* animate */);
+  EXPECT_EQ(2, pagination_model->selected_page());
+
+  // Close the folder and reopen it. It should be at page 0.
+  app_list_folder_view()->CloseFolderPage();
+  test_api_->PressItemAt(0);
+  EXPECT_EQ(3, pagination_model->total_pages());
+  EXPECT_EQ(0, pagination_model->selected_page());
+}
+
+TEST_F(AppsGridViewTest, FolderColsAndRows) {
+  // Disable the animation for the folder top items for test purpose.
+  contents_view_->apps_container_view()
+      ->set_folder_top_items_animation_enabled_for_test(false);
+
+  // Populate folders with different number of apps.
+  model_->CreateAndPopulateFolderWithApps(2);
+  model_->CreateAndPopulateFolderWithApps(5);
+  model_->CreateAndPopulateFolderWithApps(9);
+  model_->CreateAndPopulateFolderWithApps(15);
+  model_->CreateAndPopulateFolderWithApps(17);
+
+  // Check the number of cols and rows for each opened folder.
+  AppsGridView* items_grid_view = app_list_folder_view()->items_grid_view();
+  test_api_->PressItemAt(0);
+  EXPECT_EQ(2, items_grid_view->view_model_for_test()->view_size());
+  EXPECT_EQ(2, items_grid_view->cols());
+  EXPECT_EQ(1, items_grid_view->rows_per_page());
+  app_list_folder_view()->CloseFolderPage();
+
+  test_api_->PressItemAt(1);
+  EXPECT_EQ(5, items_grid_view->view_model_for_test()->view_size());
+  EXPECT_EQ(3, items_grid_view->cols());
+  EXPECT_EQ(2, items_grid_view->rows_per_page());
+  app_list_folder_view()->CloseFolderPage();
+
+  test_api_->PressItemAt(2);
+  EXPECT_EQ(9, items_grid_view->view_model_for_test()->view_size());
+  EXPECT_EQ(3, items_grid_view->cols());
+  EXPECT_EQ(3, items_grid_view->rows_per_page());
+  app_list_folder_view()->CloseFolderPage();
+
+  test_api_->PressItemAt(3);
+  EXPECT_EQ(15, items_grid_view->view_model_for_test()->view_size());
+  EXPECT_EQ(4, items_grid_view->cols());
+  EXPECT_EQ(4, items_grid_view->rows_per_page());
+  app_list_folder_view()->CloseFolderPage();
+
+  test_api_->PressItemAt(4);
+  EXPECT_EQ(17, items_grid_view->view_model_for_test()->view_size());
+  EXPECT_EQ(4, items_grid_view->cols());
+  EXPECT_EQ(4, items_grid_view->rows_per_page());
+  app_list_folder_view()->CloseFolderPage();
+}
+
 }  // namespace test
 }  // namespace app_list
diff --git a/ui/app_list/views/expand_arrow_view.cc b/ui/app_list/views/expand_arrow_view.cc
index ff0d0d80..02ada452 100644
--- a/ui/app_list/views/expand_arrow_view.cc
+++ b/ui/app_list/views/expand_arrow_view.cc
@@ -92,25 +92,14 @@
 
 ExpandArrowView::~ExpandArrowView() = default;
 
-void ExpandArrowView::SetSelected(bool selected) {
-  if (selected == selected_)
-    return;
-
-  selected_ = selected;
-  SchedulePaint();
-
-  if (selected)
-    NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true);
-}
-
 void ExpandArrowView::PaintButtonContents(gfx::Canvas* canvas) {
   gfx::Rect rect(GetContentsBounds());
 
   // Draw focused or unfocused background.
   cc::PaintFlags flags;
   flags.setAntiAlias(true);
-  flags.setColor(selected_ ? kFocusedBackgroundColor
-                           : kUnFocusedBackgroundColor);
+  flags.setColor(HasFocus() ? kFocusedBackgroundColor
+                            : kUnFocusedBackgroundColor);
   flags.setStyle(cc::PaintFlags::kFill_Style);
   canvas->DrawCircle(gfx::PointF(rect.CenterPoint()), kSelectedRadius, flags);
 
@@ -154,11 +143,13 @@
 }
 
 void ExpandArrowView::OnFocus() {
-  SetSelected(true);
+  SchedulePaint();
+  Button::OnFocus();
 }
 
 void ExpandArrowView::OnBlur() {
-  SetSelected(false);
+  SchedulePaint();
+  Button::OnBlur();
 }
 
 std::unique_ptr<views::InkDrop> ExpandArrowView::CreateInkDrop() {
diff --git a/ui/app_list/views/expand_arrow_view.h b/ui/app_list/views/expand_arrow_view.h
index 6ea9bae..fad9e9f 100644
--- a/ui/app_list/views/expand_arrow_view.h
+++ b/ui/app_list/views/expand_arrow_view.h
@@ -32,9 +32,6 @@
   ExpandArrowView(ContentsView* contents_view, AppListView* app_list_view);
   ~ExpandArrowView() override;
 
-  bool selected() { return selected_; }
-  void SetSelected(bool selected);
-
   // Overridden from views::Button:
   void PaintButtonContents(gfx::Canvas* canvas) override;
 
@@ -78,8 +75,6 @@
   float pulse_opacity_;
   int pulse_radius_;
 
-  bool selected_ = false;
-
   std::unique_ptr<gfx::SlideAnimation> animation_;
 
   // Whether the expand arrow view is pressed or not. If true, animation should
diff --git a/ui/app_list/views/folder_background_view.cc b/ui/app_list/views/folder_background_view.cc
index 6fffa54d..a7e1dfe 100644
--- a/ui/app_list/views/folder_background_view.cc
+++ b/ui/app_list/views/folder_background_view.cc
@@ -4,94 +4,29 @@
 
 #include "ui/app_list/views/folder_background_view.h"
 
-#include <algorithm>
-
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_features.h"
 #include "ui/app_list/views/app_list_folder_view.h"
-#include "ui/app_list/views/apps_container_view.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/transform_util.h"
 
 namespace app_list {
 
-namespace {
+FolderBackgroundView::FolderBackgroundView(AppListFolderView* folder_view)
+    : folder_view_(folder_view) {}
 
-const float kFolderInkBubbleScale = 1.2f;
-const int kBubbleTransitionDurationMs = 200;
+FolderBackgroundView::~FolderBackgroundView() = default;
 
-}  // namespace
-
-FolderBackgroundView::FolderBackgroundView()
-    : folder_view_(NULL), show_state_(NO_BUBBLE) {
-  SetPaintToLayer();
-  layer()->SetFillsBoundsOpaquely(false);
+bool FolderBackgroundView::OnMousePressed(const ui::MouseEvent& event) {
+  HandleClickOrTap();
+  return true;
 }
 
-FolderBackgroundView::~FolderBackgroundView() {
-}
-
-void FolderBackgroundView::UpdateFolderContainerBubble(ShowState state) {
-  if (show_state_ == state ||
-      (state == HIDE_BUBBLE && show_state_ == NO_BUBBLE)) {
+void FolderBackgroundView::OnGestureEvent(ui::GestureEvent* event) {
+  if (event->type() != ui::ET_GESTURE_TAP)
     return;
-  }
-
-  show_state_ = state;
-
-  // Set the initial state before the animation starts.
-  const gfx::Rect bounds(layer()->bounds().size());
-  gfx::Transform transform =
-      gfx::GetScaleTransform(bounds.CenterPoint(), kFolderInkBubbleScale);
-  if (show_state_ == SHOW_BUBBLE) {
-    layer()->SetOpacity(0.0f);
-    layer()->SetTransform(transform);
-  } else {
-    layer()->SetOpacity(GetBubbleOpacity());
-    layer()->SetTransform(gfx::Transform());
-  }
-
-  ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
-  settings.AddObserver(this);
-  settings.SetTransitionDuration(
-      base::TimeDelta::FromMilliseconds((kBubbleTransitionDurationMs)));
-  if (show_state_ == SHOW_BUBBLE) {
-    settings.SetTweenType(gfx::Tween::LINEAR_OUT_SLOW_IN);
-    layer()->SetOpacity(GetBubbleOpacity());
-    layer()->SetTransform(gfx::Transform());
-  } else {
-    settings.SetTweenType(gfx::Tween::FAST_OUT_LINEAR_IN);
-    layer()->SetOpacity(0.0f);
-    layer()->SetTransform(transform);
-  }
-
-  SchedulePaint();
+  HandleClickOrTap();
+  event->SetHandled();
 }
 
-void FolderBackgroundView::OnPaint(gfx::Canvas* canvas) {
-  if (show_state_ == NO_BUBBLE)
-    return;
-
-  // Draw ink bubble that shows the folder boundary.
-  cc::PaintFlags flags;
-  flags.setStyle(cc::PaintFlags::kFill_Style);
-  flags.setAntiAlias(true);
-  flags.setColor(FolderImage::kFolderBubbleColor);
-  canvas->DrawCircle(GetContentsBounds().CenterPoint(),
-                     kFolderBackgroundBubbleRadius, flags);
-}
-
-void FolderBackgroundView::OnImplicitAnimationsCompleted() {
-  // Show folder name after the ink bubble disappears.
-  if (show_state_ == HIDE_BUBBLE) {
-    static_cast<AppsContainerView*>(parent())->app_list_folder_view()->
-        UpdateFolderNameVisibility(true);
-  }
-}
-
-float FolderBackgroundView::GetBubbleOpacity() const {
-  return kFolderBubbleOpacity;
+void FolderBackgroundView::HandleClickOrTap() {
+  folder_view_->CloseFolderPage();
 }
 
 }  // namespace app_list
diff --git a/ui/app_list/views/folder_background_view.h b/ui/app_list/views/folder_background_view.h
index cd5a0fa..5f16274 100644
--- a/ui/app_list/views/folder_background_view.h
+++ b/ui/app_list/views/folder_background_view.h
@@ -5,46 +5,32 @@
 #ifndef UI_APP_LIST_VIEWS_FOLDER_BACKGROUND_VIEW_H_
 #define UI_APP_LIST_VIEWS_FOLDER_BACKGROUND_VIEW_H_
 
-#include "base/macros.h"
-#include "ui/compositor/layer_animation_observer.h"
 #include "ui/views/view.h"
 
 namespace app_list {
 
 class AppListFolderView;
 
-// Draws the ink bubble indicating the boundary of the folder when user drags an
-// item inside a folder.
-class FolderBackgroundView : public views::View,
-                             public ui::ImplicitAnimationObserver {
+// An invisible background view of the folder in fullscreen app list. It is used
+// to close folder when the user clicks/taps outside the opened folder.
+class FolderBackgroundView : public views::View {
  public:
-  enum ShowState {
-    NO_BUBBLE,
-    SHOW_BUBBLE,
-    HIDE_BUBBLE,
-  };
-
-  FolderBackgroundView();
+  explicit FolderBackgroundView(AppListFolderView* folder_view);
   ~FolderBackgroundView() override;
 
-  // Updates the ink bubble's ShowState.
-  void UpdateFolderContainerBubble(ShowState state);
-
   void set_folder_view(AppListFolderView* folder_view) {
     folder_view_ = folder_view;
   }
 
  private:
   // views::View overrides:
-  void OnPaint(gfx::Canvas* canvas) override;
+  bool OnMousePressed(const ui::MouseEvent& event) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
 
-  // ui::ImplicitAnimationObserver overrides:
-  void OnImplicitAnimationsCompleted() override;
-
-  float GetBubbleOpacity() const;
+  // Handles mouse click event or gesture tap event.
+  void HandleClickOrTap();
 
   AppListFolderView* folder_view_;
-  ShowState show_state_;
 
   DISALLOW_COPY_AND_ASSIGN(FolderBackgroundView);
 };
diff --git a/ui/app_list/views/folder_header_view.cc b/ui/app_list/views/folder_header_view.cc
index e71dd35..41860ae 100644
--- a/ui/app_list/views/folder_header_view.cc
+++ b/ui/app_list/views/folder_header_view.cc
@@ -27,10 +27,8 @@
 
 namespace {
 
-constexpr int kPreferredWidth = 360;
-constexpr int kPreferredHeight = 48;
-constexpr int kBottomSeparatorHeight = 1;
-constexpr int kMaxFolderNameWidthFullScreen = 236;
+constexpr int kMaxFolderNameWidth = 204;
+constexpr SkColor kFolderNameColor = SkColorSetARGBMacro(138, 0, 0, 0);
 
 }  // namespace
 
@@ -38,7 +36,7 @@
  public:
   FolderNameView() { SetBorder(views::CreateEmptyBorder(1, 1, 1, 1)); }
 
-  ~FolderNameView() override {}
+  ~FolderNameView() override = default;
 
   void OnFocus() override {
     SelectAll(false);
@@ -66,8 +64,7 @@
   // Make folder name font size 14px.
   folder_name_view_->SetFontList(font_list.DeriveWithSizeDelta(-1));
   folder_name_view_->SetBackgroundColor(SK_ColorTRANSPARENT);
-  folder_name_view_->SetTextColor(kGridTitleColor);
-
+  folder_name_view_->SetTextColor(kFolderNameColor);
   folder_name_view_->set_controller(this);
   AddChildView(folder_name_view_);
 }
@@ -149,10 +146,8 @@
 }
 
 gfx::Size FolderHeaderView::CalculatePreferredSize() const {
-  const int preferred_height = kPreferredHeight +
-                               kBottomSeparatorBottomPadding +
-                               AppsGridView::GetTilePadding().top();
-  return gfx::Size(kPreferredWidth, preferred_height);
+  return gfx::Size(kMaxFolderNameWidth,
+                   folder_name_view_->GetPreferredSize().height());
 }
 
 views::View* FolderHeaderView::GetFolderNameViewForTest() const {
@@ -160,7 +155,7 @@
 }
 
 int FolderHeaderView::GetMaxFolderNameWidth() const {
-  return kMaxFolderNameWidthFullScreen;
+  return kMaxFolderNameWidth;
 }
 
 base::string16 FolderHeaderView::GetElidedFolderName(
@@ -205,26 +200,6 @@
   return false;
 }
 
-void FolderHeaderView::OnPaint(gfx::Canvas* canvas) {
-  views::View::OnPaint(canvas);
-
-  gfx::Rect rect(GetContentsBounds());
-  if (rect.IsEmpty() || !folder_name_visible_)
-    return;
-
-  // Draw bottom separator line.
-  rect.Inset(kAppsGridLeftRightPadding +
-                 (-AppsGridView::GetTilePadding().left()) +
-                 kBottomSeparatorLeftRightPadding,
-             0);
-  int extra_bottom_padding =
-      kBottomSeparatorBottomPadding + AppsGridView::GetTilePadding().top();
-  rect.set_y(rect.bottom() - kBottomSeparatorHeight - extra_bottom_padding);
-  rect.set_height(kBottomSeparatorHeight);
-  SkColor color = kBottomSeparatorColor;
-  canvas->FillRect(rect, color);
-}
-
 void FolderHeaderView::ContentsChanged(views::Textfield* sender,
                                        const base::string16& new_contents) {
   // Temporarily remove from observer to ignore data change caused by us.
diff --git a/ui/app_list/views/folder_header_view.h b/ui/app_list/views/folder_header_view.h
index 52a49a4..5d5cb2f 100644
--- a/ui/app_list/views/folder_header_view.h
+++ b/ui/app_list/views/folder_header_view.h
@@ -68,7 +68,6 @@
   // views::View overrides:
   void Layout() override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
-  void OnPaint(gfx::Canvas* canvas) override;
 
   // views::TextfieldController overrides:
   void ContentsChanged(views::Textfield* sender,
diff --git a/ui/app_list/views/page_switcher_vertical.cc b/ui/app_list/views/page_switcher.cc
similarity index 66%
rename from ui/app_list/views/page_switcher_vertical.cc
rename to ui/app_list/views/page_switcher.cc
index 05a652a..c14d7c7b 100644
--- a/ui/app_list/views/page_switcher_vertical.cc
+++ b/ui/app_list/views/page_switcher.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/app_list/views/page_switcher_vertical.h"
+#include "ui/app_list/views/page_switcher.h"
 
 #include <algorithm>
 
@@ -34,26 +34,35 @@
 constexpr int kNormalButtonRadius = 3;
 constexpr int kSelectedButtonRadius = 4;
 constexpr int kInkDropRadius = 8;
-// The padding on top/bottom side of each button.
-constexpr int kButtonPadding = 12;
 constexpr int kMaxButtonRadius = 8;
 constexpr int kPreferredButtonStripWidth = kMaxButtonRadius * 2;
-
-// The selected button color.
-constexpr SkColor kSelectedButtonColor = SK_ColorWHITE;
-// The normal button color (54% white).
-constexpr SkColor kNormalColor = SkColorSetA(SK_ColorWHITE, 138);
-constexpr SkColor kInkDropBaseColor = SK_ColorWHITE;
-constexpr SkColor kInkDropRippleColor = SkColorSetA(kInkDropBaseColor, 20);
-constexpr SkColor kInkDropHighlightColor = SkColorSetA(kInkDropBaseColor, 15);
-
 constexpr SkScalar kStrokeWidth = SkIntToScalar(1);
 
+// Constants for the button strip that grows vertically.
+// The padding on top/bottom side of each button.
+constexpr int kVerticalButtonPadding = 12;
+// The selected button color.
+constexpr SkColor kVerticalSelectedButtonColor = SK_ColorWHITE;
+// The normal button color (54% white).
+constexpr SkColor kVerticalNormalColor = SkColorSetA(SK_ColorWHITE, 138);
+constexpr SkColor kVerticalInkDropBaseColor = SK_ColorWHITE;
+constexpr SkColor kVerticalInkDropRippleColor =
+    SkColorSetA(kVerticalInkDropBaseColor, 20);
+constexpr SkColor kVerticalInkDropHighlightColor =
+    SkColorSetA(kVerticalInkDropBaseColor, 15);
+
+// Constants for the button strip that grows horizontally.
+// The padding on left/right side of each button.
+constexpr int kHorizontalButtonPadding = 6;
+// The normal button color (54% black).
+constexpr SkColor kHorizontalNormalColor = SkColorSetA(SK_ColorBLACK, 138);
+
 class PageSwitcherButton : public views::Button {
  public:
-  explicit PageSwitcherButton(views::ButtonListener* listener)
-      : views::Button(listener) {
-    SetInkDropMode(InkDropMode::ON);
+  PageSwitcherButton(views::ButtonListener* listener, bool vertical)
+      : views::Button(listener), vertical_(vertical) {
+    if (vertical)
+      SetInkDropMode(InkDropMode::ON);
   }
 
   ~PageSwitcherButton() override {}
@@ -99,15 +108,15 @@
                      2 * kMaxButtonRadius);
     return std::make_unique<views::FloodFillInkDropRipple>(
         size(), GetLocalBounds().InsetsFrom(bounds),
-        GetInkDropCenterBasedOnLastEvent(), kInkDropRippleColor, 1.0f);
+        GetInkDropCenterBasedOnLastEvent(), kVerticalInkDropRippleColor, 1.0f);
   }
 
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
       const override {
     return std::make_unique<views::InkDropHighlight>(
         gfx::PointF(GetLocalBounds().CenterPoint()),
-        std::make_unique<views::CircleLayerDelegate>(kInkDropHighlightColor,
-                                                     kInkDropRadius));
+        std::make_unique<views::CircleLayerDelegate>(
+            kVerticalInkDropHighlightColor, kInkDropRadius));
   }
 
   void NotifyClick(const ui::Event& event) override {
@@ -128,12 +137,13 @@
   PaintButtonInfo BuildPaintButtonInfo() {
     PaintButtonInfo info;
     if (selected_) {
-      info.color = kSelectedButtonColor;
+      info.color =
+          vertical_ ? kVerticalSelectedButtonColor : kHorizontalNormalColor;
       info.style = cc::PaintFlags::kFill_Style;
       info.radius = SkIntToScalar(kSelectedButtonRadius);
       info.stroke_width = SkIntToScalar(0);
     } else {
-      info.color = kNormalColor;
+      info.color = vertical_ ? kVerticalNormalColor : kHorizontalNormalColor;
       info.style = cc::PaintFlags::kStroke_Style;
       info.radius = SkIntToScalar(kNormalButtonRadius);
       info.stroke_width = kStrokeWidth;
@@ -157,6 +167,9 @@
   // If this button is selected, set to true. By default, set to false;
   bool selected_ = false;
 
+  // True if the page switcher button strip should grow vertically.
+  const bool vertical_;
+
   DISALLOW_COPY_AND_ASSIGN(PageSwitcherButton);
 };
 
@@ -167,13 +180,19 @@
 
 }  // namespace
 
-PageSwitcherVertical::PageSwitcherVertical(PaginationModel* model)
-    : model_(model), buttons_(new views::View) {
+PageSwitcher::PageSwitcher(PaginationModel* model, bool vertical)
+    : model_(model), buttons_(new views::View), vertical_(vertical) {
   SetPaintToLayer();
   layer()->SetFillsBoundsOpaquely(false);
 
-  buttons_->SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::kVertical, gfx::Insets(), kButtonPadding));
+  if (vertical_) {
+    buttons_->SetLayoutManager(std::make_unique<views::BoxLayout>(
+        views::BoxLayout::kVertical, gfx::Insets(), kVerticalButtonPadding));
+  } else {
+    buttons_->SetLayoutManager(std::make_unique<views::BoxLayout>(
+        views::BoxLayout::kHorizontal, gfx::Insets(),
+        kHorizontalButtonPadding));
+  }
 
   AddChildView(buttons_);
 
@@ -182,68 +201,34 @@
   model_->AddObserver(this);
 }
 
-PageSwitcherVertical::~PageSwitcherVertical() {
-  model_->RemoveObserver(this);
+PageSwitcher::~PageSwitcher() {
+  if (model_)
+    model_->RemoveObserver(this);
 }
 
-int PageSwitcherVertical::GetPageForPoint(const gfx::Point& point) const {
-  if (!buttons_->bounds().Contains(point))
-    return -1;
-
-  gfx::Point buttons_point(point);
-  views::View::ConvertPointToTarget(this, buttons_, &buttons_point);
-
-  for (int i = 0; i < buttons_->child_count(); ++i) {
-    const views::View* button = buttons_->child_at(i);
-    if (button->bounds().Contains(buttons_point))
-      return i;
-  }
-
-  return -1;
-}
-
-void PageSwitcherVertical::UpdateUIForDragPoint(const gfx::Point& point) {
-  int page = GetPageForPoint(point);
-
-  const int button_count = buttons_->child_count();
-  if (page >= 0 && page < button_count) {
-    PageSwitcherButton* button =
-        static_cast<PageSwitcherButton*>(buttons_->child_at(page));
-    button->SetState(views::Button::STATE_HOVERED);
-    return;
-  }
-
-  for (int i = 0; i < button_count; ++i) {
-    PageSwitcherButton* button =
-        static_cast<PageSwitcherButton*>(buttons_->child_at(i));
-    button->SetState(views::Button::STATE_NORMAL);
-  }
-}
-
-gfx::Rect PageSwitcherVertical::GetButtonsBoundsInScreen() {
-  return buttons_->GetBoundsInScreen();
-}
-
-gfx::Size PageSwitcherVertical::CalculatePreferredSize() const {
+gfx::Size PageSwitcher::CalculatePreferredSize() const {
   // Always return a size with correct width so that container resize is not
   // needed when more pages are added.
-  return gfx::Size(kPreferredButtonStripWidth,
-                   buttons_->GetPreferredSize().height());
+  if (vertical_) {
+    return gfx::Size(kPreferredButtonStripWidth,
+                     buttons_->GetPreferredSize().height());
+  }
+  return gfx::Size(buttons_->GetPreferredSize().width(),
+                   kPreferredButtonStripWidth);
 }
 
-void PageSwitcherVertical::Layout() {
+void PageSwitcher::Layout() {
   gfx::Rect rect(GetContentsBounds());
-
-  // Makes |buttons_| vertically center and horizontally fill.
   gfx::Size buttons_size(buttons_->GetPreferredSize());
-  gfx::Rect buttons_bounds(rect.x(),
-                           rect.CenterPoint().y() - buttons_size.height() / 2,
-                           rect.width(), buttons_size.height());
-  buttons_->SetBoundsRect(gfx::IntersectRects(rect, buttons_bounds));
+  rect.ClampToCenteredSize(buttons_size);
+  buttons_->SetBoundsRect(rect);
 }
 
-void PageSwitcherVertical::ButtonPressed(views::Button* sender,
-                                         const ui::Event& event) {
+void PageSwitcher::ButtonPressed(views::Button* sender,
+                                 const ui::Event& event) {
+  if (!model_)
+    return;
+
   for (int i = 0; i < buttons_->child_count(); ++i) {
     if (sender == static_cast<views::Button*>(buttons_->child_at(i))) {
       if (model_->selected_page() == i)
@@ -258,10 +243,13 @@
   }
 }
 
-void PageSwitcherVertical::TotalPagesChanged() {
+void PageSwitcher::TotalPagesChanged() {
+  if (!model_)
+    return;
+
   buttons_->RemoveAllChildViews(true);
   for (int i = 0; i < model_->total_pages(); ++i) {
-    PageSwitcherButton* button = new PageSwitcherButton(this);
+    PageSwitcherButton* button = new PageSwitcherButton(this, vertical_);
     button->SetAccessibleName(l10n_util::GetStringFUTF16(
         IDS_APP_LIST_PAGE_SWITCHER, base::FormatNumber(i + 1),
         base::FormatNumber(model_->total_pages())));
@@ -272,18 +260,17 @@
   Layout();
 }
 
-void PageSwitcherVertical::SelectedPageChanged(int old_selected,
-                                               int new_selected) {
+void PageSwitcher::SelectedPageChanged(int old_selected, int new_selected) {
   if (old_selected >= 0 && old_selected < buttons_->child_count())
     GetButtonByIndex(buttons_, old_selected)->SetSelected(false);
   if (new_selected >= 0 && new_selected < buttons_->child_count())
     GetButtonByIndex(buttons_, new_selected)->SetSelected(true);
 }
 
-void PageSwitcherVertical::TransitionStarted() {}
+void PageSwitcher::TransitionStarted() {}
 
-void PageSwitcherVertical::TransitionChanged() {}
+void PageSwitcher::TransitionChanged() {}
 
-void PageSwitcherVertical::TransitionEnded() {}
+void PageSwitcher::TransitionEnded() {}
 
 }  // namespace app_list
diff --git a/ui/app_list/views/page_switcher.h b/ui/app_list/views/page_switcher.h
index 5cb6c0bc..67348355f 100644
--- a/ui/app_list/views/page_switcher.h
+++ b/ui/app_list/views/page_switcher.h
@@ -5,26 +5,46 @@
 #ifndef UI_APP_LIST_VIEWS_PAGE_SWITCHER_H_
 #define UI_APP_LIST_VIEWS_PAGE_SWITCHER_H_
 
-#include "ui/views/view.h"
+#include "base/macros.h"
+#include "ui/app_list/pagination_model_observer.h"
+#include "ui/views/controls/button/button.h"
 
 namespace app_list {
 
-// PageSwitcher represents its underlying PaginationModel with a button strip.
-// Each page in the PageinationModel has a button in the strip and when the
-// button is clicked, the corresponding page becomes selected.
-class PageSwitcher : public views::View {
+class PaginationModel;
+
+// PageSwitcher represents its underlying PaginationModel with a button
+// strip. Each page in the PageinationModel has a button in the strip and
+// when the button is clicked, the corresponding page becomes selected.
+class PageSwitcher : public views::View,
+                     public views::ButtonListener,
+                     public PaginationModelObserver {
  public:
-  // Returns the page index of the page switcher button under the point. If no
-  // page switcher button is under the point, -1 is return. |point| is in
-  // PageSwitcher's coordinates.
-  virtual int GetPageForPoint(const gfx::Point& point) const = 0;
+  PageSwitcher(PaginationModel* model, bool vertical);
+  ~PageSwitcher() override;
 
-  // Shows hover for button under the point. |point| is in PageSwitcher's
-  // coordinates.
-  virtual void UpdateUIForDragPoint(const gfx::Point& point) = 0;
+  // Overridden from views::View:
+  gfx::Size CalculatePreferredSize() const override;
+  void Layout() override;
 
-  // Gets the screen bounds of the buttons in the page switcher.
-  virtual gfx::Rect GetButtonsBoundsInScreen() = 0;
+ private:
+  // Overridden from views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+  // Overridden from PaginationModelObserver:
+  void TotalPagesChanged() override;
+  void SelectedPageChanged(int old_selected, int new_selected) override;
+  void TransitionStarted() override;
+  void TransitionChanged() override;
+  void TransitionEnded() override;
+
+  PaginationModel* model_;  // Owned by AppsGridView.
+  views::View* buttons_;    // Owned by views hierarchy.
+
+  // True if the page switcher button strip should grow vertically.
+  const bool vertical_;
+
+  DISALLOW_COPY_AND_ASSIGN(PageSwitcher);
 };
 
 }  // namespace app_list
diff --git a/ui/app_list/views/page_switcher_vertical.h b/ui/app_list/views/page_switcher_vertical.h
deleted file mode 100644
index 25650aa..0000000
--- a/ui/app_list/views/page_switcher_vertical.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012 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_APP_LIST_VIEWS_PAGE_SWITCHER_VERTICAL_H_
-#define UI_APP_LIST_VIEWS_PAGE_SWITCHER_VERTICAL_H_
-
-#include "base/macros.h"
-#include "ui/app_list/pagination_model_observer.h"
-#include "ui/app_list/views/page_switcher.h"
-#include "ui/views/controls/button/button.h"
-
-namespace app_list {
-
-class PaginationModel;
-
-// PageSwitcher represents its underlying PaginationModel with a button strip.
-// Each page in the PageinationModel has a button in the strip and when the
-// button is clicked, the corresponding page becomes selected.
-class PageSwitcherVertical : public PageSwitcher,
-                             public views::ButtonListener,
-                             public PaginationModelObserver {
- public:
-  explicit PageSwitcherVertical(PaginationModel* model);
-  ~PageSwitcherVertical() override;
-
-  // Overridden from PageSwitcher:
-  int GetPageForPoint(const gfx::Point& point) const override;
-  void UpdateUIForDragPoint(const gfx::Point& point) override;
-  gfx::Rect GetButtonsBoundsInScreen() override;
-
-  // Overridden from views::View:
-  gfx::Size CalculatePreferredSize() const override;
-  void Layout() override;
-
- private:
-  // Overridden from views::ButtonListener:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
-
-  // Overridden from PaginationModelObserver:
-  void TotalPagesChanged() override;
-  void SelectedPageChanged(int old_selected, int new_selected) override;
-  void TransitionStarted() override;
-  void TransitionChanged() override;
-  void TransitionEnded() override;
-
-  PaginationModel* model_;  // Owned by AppsGridView.
-  views::View* buttons_;    // Owned by views hierarchy.
-
-  DISALLOW_COPY_AND_ASSIGN(PageSwitcherVertical);
-};
-
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_VIEWS_PAGE_SWITCHER_VERTICAL_H_
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 6149dd05..b1b5c342 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -172,12 +172,12 @@
   }
 
   void OnFocus() override {
-    search_box_view_->SetSelected(true);
+    search_box_view_->OnOnSearchBoxFocusedChanged();
     Textfield::OnFocus();
   }
 
   void OnBlur() override {
-    search_box_view_->SetSelected(false);
+    search_box_view_->OnOnSearchBoxFocusedChanged();
     // Clear selection and set the caret to the end of the text.
     ClearSelection();
     Textfield::OnBlur();
@@ -547,14 +547,7 @@
   return static_cast<ContentsView*>(contents_view_)->GetSelectedView();
 }
 
-void SearchBoxView::SetSelected(bool selected) {
-  if (selected_ == selected)
-    return;
-  selected_ = selected;
-  if (selected) {
-    // Set the ChromeVox focus to the search box.
-    search_box_->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true);
-  }
+void SearchBoxView::OnOnSearchBoxFocusedChanged() {
   UpdateSearchBoxBorder();
   Layout();
   SchedulePaint();
@@ -726,7 +719,7 @@
 }
 
 void SearchBoxView::UpdateSearchBoxBorder() {
-  if (selected() && !is_search_box_active()) {
+  if (search_box_->HasFocus() && !is_search_box_active()) {
     // Show a gray ring around search box to indicate that the search box is
     // selected. Do not show it when search box is active, because blinking
     // cursor already indicates that.
diff --git a/ui/app_list/views/search_box_view.h b/ui/app_list/views/search_box_view.h
index 33b7aa7..435294b 100644
--- a/ui/app_list/views/search_box_view.h
+++ b/ui/app_list/views/search_box_view.h
@@ -136,8 +136,7 @@
   // Returns selected view in contents view.
   views::View* GetSelectedViewInContentsView() const;
 
-  bool selected() { return selected_; }
-  void SetSelected(bool selected);
+  void OnOnSearchBoxFocusedChanged();
 
  private:
   // Updates model text and selection model with current Textfield info.
@@ -218,9 +217,6 @@
   // The current search box color.
   SkColor search_box_color_ = kDefaultSearchboxColor;
 
-  // Whether the search box is selected.
-  bool selected_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(SearchBoxView);
 };
 
diff --git a/ui/aura/local/window_port_local.cc b/ui/aura/local/window_port_local.cc
index c9b3213..4cdb51a 100644
--- a/ui/aura/local/window_port_local.cc
+++ b/ui/aura/local/window_port_local.cc
@@ -4,7 +4,7 @@
 
 #include "ui/aura/local/window_port_local.h"
 
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/host/host_frame_sink_manager.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/local/layer_tree_frame_sink_local.h"
@@ -171,15 +171,8 @@
 void WindowPortLocal::OnSurfaceChanged(const viz::SurfaceInfo& surface_info) {
   DCHECK_EQ(surface_info.id().frame_sink_id(), frame_sink_id_);
   DCHECK_EQ(surface_info.id().local_surface_id(), local_surface_id_);
-  scoped_refptr<viz::SurfaceReferenceFactory> reference_factory =
-      aura::Env::GetInstance()
-          ->context_factory_private()
-          ->GetFrameSinkManager()
-          ->surface_manager()
-          ->reference_factory();
-  window_->layer()->SetShowPrimarySurface(surface_info.id(),
-                                          window_->bounds().size(),
-                                          SK_ColorWHITE, reference_factory);
+  window_->layer()->SetShowPrimarySurface(
+      surface_info.id(), window_->bounds().size(), SK_ColorWHITE);
   window_->layer()->SetFallbackSurfaceId(surface_info.id());
 }
 
diff --git a/ui/aura/mus/client_surface_embedder.cc b/ui/aura/mus/client_surface_embedder.cc
index 17029d2..b22c68d 100644
--- a/ui/aura/mus/client_surface_embedder.cc
+++ b/ui/aura/mus/client_surface_embedder.cc
@@ -5,7 +5,6 @@
 #include "ui/aura/mus/client_surface_embedder.h"
 
 #include "base/memory/ptr_util.h"
-#include "components/viz/common/surfaces/stub_surface_reference_factory.h"
 #include "ui/aura/window.h"
 #include "ui/gfx/geometry/dip_util.h"
 
@@ -30,7 +29,6 @@
   // this is the case with window decorations provided by Window Manager.
   // This content should appear underneath the content of the embedded client.
   window_->layer()->StackAtTop(surface_layer_.get());
-  ref_factory_ = new viz::StubSurfaceReferenceFactory();
 }
 
 ClientSurfaceEmbedder::~ClientSurfaceEmbedder() = default;
@@ -38,7 +36,7 @@
 void ClientSurfaceEmbedder::SetPrimarySurfaceId(
     const viz::SurfaceId& surface_id) {
   surface_layer_->SetShowPrimarySurface(surface_id, window_->bounds().size(),
-                                        SK_ColorWHITE, ref_factory_);
+                                        SK_ColorWHITE);
 }
 
 void ClientSurfaceEmbedder::SetFallbackSurfaceInfo(
diff --git a/ui/aura/mus/client_surface_embedder.h b/ui/aura/mus/client_surface_embedder.h
index e5085af..cfbb0bc 100644
--- a/ui/aura/mus/client_surface_embedder.h
+++ b/ui/aura/mus/client_surface_embedder.h
@@ -8,9 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/common/surfaces/surface_reference_factory.h"
 #include "ui/gfx/geometry/insets.h"
 
 namespace gfx {
@@ -70,8 +68,6 @@
   bool inject_gutter_;
   gfx::Insets client_area_insets_;
 
-  scoped_refptr<viz::SurfaceReferenceFactory> ref_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(ClientSurfaceEmbedder);
 };
 
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc
index 5b4bcab..777f06e 100644
--- a/ui/aura/mus/window_port_mus.cc
+++ b/ui/aura/mus/window_port_mus.cc
@@ -6,7 +6,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "components/viz/client/local_surface_id_provider.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/host/host_frame_sink_manager.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/transient_window_client.h"
 #include "ui/aura/env.h"
@@ -661,18 +661,13 @@
 }
 
 void WindowPortMus::OnSurfaceChanged(const viz::SurfaceInfo& surface_info) {
+  // TODO(fsamuel): Rename OnFirstSurfaceActivation() and set primary earlier
+  // based on feedback from LayerTreeFrameSinkLocal.
   DCHECK(!switches::IsMusHostingViz());
   DCHECK_EQ(surface_info.id().frame_sink_id(), GetFrameSinkId());
   DCHECK_EQ(surface_info.id().local_surface_id(), local_surface_id_);
-  scoped_refptr<viz::SurfaceReferenceFactory> reference_factory =
-      aura::Env::GetInstance()
-          ->context_factory_private()
-          ->GetFrameSinkManager()
-          ->surface_manager()
-          ->reference_factory();
-  window_->layer()->SetShowPrimarySurface(surface_info.id(),
-                                          window_->bounds().size(),
-                                          SK_ColorWHITE, reference_factory);
+  window_->layer()->SetShowPrimarySurface(
+      surface_info.id(), window_->bounds().size(), SK_ColorWHITE);
   window_->layer()->SetFallbackSurfaceId(surface_info.id());
 }
 
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 9615f95..2584b5c 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -205,7 +205,6 @@
   animation_host_->AddAnimationTimeline(animation_timeline_.get());
 
   host_->SetRootLayer(root_web_layer_);
-  host_->SetFrameSinkId(frame_sink_id_);
   host_->SetVisible(true);
 
   if (command_line->HasSwitch(switches::kUISlowAnimations)) {
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index eb56a10..e1e50227 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -21,8 +21,8 @@
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "components/viz/host/host_frame_sink_client.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkMatrix44.h"
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index c5f6711..2a77c47 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -189,8 +189,7 @@
     if (surface_layer_->primary_surface_id().is_valid()) {
       clone->SetShowPrimarySurface(surface_layer_->primary_surface_id(),
                                    frame_size_in_dip_,
-                                   surface_layer_->background_color(),
-                                   surface_layer_->surface_reference_factory());
+                                   surface_layer_->background_color());
     }
     if (surface_layer_->fallback_surface_id().is_valid())
       clone->SetFallbackSurfaceId(surface_layer_->fallback_surface_id());
@@ -746,16 +745,13 @@
   return texture_layer_->flipped();
 }
 
-void Layer::SetShowPrimarySurface(
-    const viz::SurfaceId& surface_id,
-    const gfx::Size& frame_size_in_dip,
-    SkColor default_background_color,
-    scoped_refptr<viz::SurfaceReferenceFactory> ref_factory) {
+void Layer::SetShowPrimarySurface(const viz::SurfaceId& surface_id,
+                                  const gfx::Size& frame_size_in_dip,
+                                  SkColor default_background_color) {
   DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR);
 
   if (!surface_layer_) {
-    scoped_refptr<cc::SurfaceLayer> new_layer =
-        cc::SurfaceLayer::Create(ref_factory);
+    scoped_refptr<cc::SurfaceLayer> new_layer = cc::SurfaceLayer::Create();
     SwitchToLayer(new_layer);
     surface_layer_ = new_layer;
   }
@@ -767,8 +763,8 @@
   RecomputeDrawsContentAndUVRect();
 
   for (const auto& mirror : mirrors_) {
-    mirror->dest()->SetShowPrimarySurface(
-        surface_id, frame_size_in_dip, default_background_color, ref_factory);
+    mirror->dest()->SetShowPrimarySurface(surface_id, frame_size_in_dip,
+                                          default_background_color);
   }
 }
 
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index 736c4d5..aa3712c 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -22,7 +22,6 @@
 #include "cc/layers/surface_layer.h"
 #include "cc/layers/texture_layer_client.h"
 #include "components/viz/common/resources/transferable_resource.h"
-#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/layer_animation_delegate.h"
@@ -303,12 +302,11 @@
   void SetTextureFlipped(bool flipped);
   bool TextureFlipped() const;
 
+  // TODO(fsamuel): Update this comment.
   // Begins showing content from a surface with a particular ID.
-  void SetShowPrimarySurface(
-      const viz::SurfaceId& surface_id,
-      const gfx::Size& frame_size_in_dip,
-      SkColor default_background_color,
-      scoped_refptr<viz::SurfaceReferenceFactory> surface_ref);
+  void SetShowPrimarySurface(const viz::SurfaceId& surface_id,
+                             const gfx::Size& frame_size_in_dip,
+                             SkColor default_background_color);
 
   // In the event that the primary surface is not yet available in the
   // display compositor, the fallback surface will be used.
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index 1c8dd0fa..d55f320e 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -33,10 +33,7 @@
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "components/viz/common/frame_sinks/copy_output_result.h"
 #include "components/viz/common/resources/transferable_resource.h"
-#include "components/viz/common/surfaces/sequence_surface_reference_factory.h"
 #include "components/viz/common/surfaces/surface_id.h"
-#include "components/viz/common/surfaces/surface_reference_factory.h"
-#include "components/viz/common/surfaces/surface_sequence.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/khronos/GLES2/gl2.h"
@@ -1833,26 +1830,6 @@
   EXPECT_TRUE(delegate.painted());
 }
 
-namespace {
-
-class TestSurfaceReferenceFactory
-    : public viz::SequenceSurfaceReferenceFactory {
- public:
-  TestSurfaceReferenceFactory() = default;
-
- private:
-  ~TestSurfaceReferenceFactory() override = default;
-
-  // cc::SequenceSurfaceReferenceFactory implementation:
-  void SatisfySequence(const viz::SurfaceSequence& seq) const override {}
-  void RequireSequence(const viz::SurfaceId& id,
-                       const viz::SurfaceSequence& seq) const override {}
-
-  DISALLOW_COPY_AND_ASSIGN(TestSurfaceReferenceFactory);
-};
-
-}  // namespace
-
 TEST_F(LayerWithDelegateTest, ExternalContent) {
   std::unique_ptr<Layer> root(
       CreateNoTextureLayer(gfx::Rect(0, 0, 1000, 1000)));
@@ -1872,8 +1849,7 @@
   // Showing surface content changes the underlying cc layer.
   before = child->cc_layer_for_testing();
   child->SetShowPrimarySurface(viz::SurfaceId(), gfx::Size(10, 10),
-                               SK_ColorWHITE,
-                               new TestSurfaceReferenceFactory());
+                               SK_ColorWHITE);
   EXPECT_TRUE(child->cc_layer_for_testing());
   EXPECT_NE(before.get(), child->cc_layer_for_testing());
 
@@ -1886,14 +1862,11 @@
 
 TEST_F(LayerWithDelegateTest, ExternalContentMirroring) {
   std::unique_ptr<Layer> layer(CreateLayer(LAYER_SOLID_COLOR));
-  scoped_refptr<viz::SurfaceReferenceFactory> reference_factory(
-      new TestSurfaceReferenceFactory());
 
   viz::SurfaceId surface_id(
       viz::FrameSinkId(0, 1),
       viz::LocalSurfaceId(2, base::UnguessableToken::Create()));
-  layer->SetShowPrimarySurface(surface_id, gfx::Size(10, 10), SK_ColorWHITE,
-                               reference_factory);
+  layer->SetShowPrimarySurface(surface_id, gfx::Size(10, 10), SK_ColorWHITE);
 
   const auto mirror = layer->Mirror();
   auto* const cc_layer = mirror->cc_layer_for_testing();
@@ -1905,13 +1878,11 @@
   surface_id =
       viz::SurfaceId(viz::FrameSinkId(1, 2),
                      viz::LocalSurfaceId(3, base::UnguessableToken::Create()));
-  layer->SetShowPrimarySurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE,
-                               reference_factory);
+  layer->SetShowPrimarySurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE);
 
   // The mirror should continue to use the same cc_layer.
   EXPECT_EQ(cc_layer, mirror->cc_layer_for_testing());
-  layer->SetShowPrimarySurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE,
-                               reference_factory);
+  layer->SetShowPrimarySurface(surface_id, gfx::Size(20, 20), SK_ColorWHITE);
 
   // Surface updates propagate to the mirror.
   EXPECT_EQ(surface_id, surface->primary_surface_id());
@@ -1932,8 +1903,7 @@
   // Showing surface content changes the underlying cc layer.
   scoped_refptr<cc::Layer> before = layer->cc_layer_for_testing();
   layer->SetShowPrimarySurface(viz::SurfaceId(), gfx::Size(10, 10),
-                               SK_ColorWHITE,
-                               new TestSurfaceReferenceFactory());
+                               SK_ColorWHITE);
   EXPECT_EQ(layer->layer_grayscale(), 0.5f);
   EXPECT_TRUE(layer->cc_layer_for_testing());
   EXPECT_NE(before.get(), layer->cc_layer_for_testing());
diff --git a/ui/events/ozone/evdev/event_auto_repeat_handler.cc b/ui/events/ozone/evdev/event_auto_repeat_handler.cc
index 502d2fae4..ebfbb60d 100644
--- a/ui/events/ozone/evdev/event_auto_repeat_handler.cc
+++ b/ui/events/ozone/evdev/event_auto_repeat_handler.cc
@@ -84,13 +84,10 @@
   if (repeat_sequence_ != sequence)
     return;
 
-  // Post a task behind any pending key releases in the message loop
-  // FIFO. This ensures there's no spurious repeats during periods of UI
-  // thread jank.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
+  base::OnceClosure commit =
       base::BindOnce(&EventAutoRepeatHandler::OnRepeatCommit,
-                     weak_ptr_factory_.GetWeakPtr(), repeat_sequence_));
+                     weak_ptr_factory_.GetWeakPtr(), repeat_sequence_);
+  delegate_->FlushInput(std::move(commit));
 }
 
 void EventAutoRepeatHandler::OnRepeatCommit(unsigned int sequence) {
diff --git a/ui/events/ozone/evdev/event_auto_repeat_handler.h b/ui/events/ozone/evdev/event_auto_repeat_handler.h
index 1be980e..37b1896 100644
--- a/ui/events/ozone/evdev/event_auto_repeat_handler.h
+++ b/ui/events/ozone/evdev/event_auto_repeat_handler.h
@@ -18,6 +18,10 @@
  public:
   class Delegate {
    public:
+    // Gives the client a chance to flush the input queue
+    // cancelling possible spurios auto repeat keys.
+    // Useful under janky situations.
+    virtual void FlushInput(base::OnceClosure closure) = 0;
     virtual void DispatchKey(unsigned int key,
                              bool down,
                              bool repeat,
diff --git a/ui/events/ozone/evdev/keyboard_evdev.cc b/ui/events/ozone/evdev/keyboard_evdev.cc
index 58921f2d..a0f5420 100644
--- a/ui/events/ozone/evdev/keyboard_evdev.cc
+++ b/ui/events/ozone/evdev/keyboard_evdev.cc
@@ -82,6 +82,13 @@
   return result;
 }
 
+void KeyboardEvdev::FlushInput(base::OnceClosure closure) {
+  // Post a task behind any pending key releases in the message loop
+  // FIFO. This ensures there's no spurious repeats during periods of UI
+  // thread jank.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(closure));
+}
+
 void KeyboardEvdev::UpdateModifier(int modifier_flag, bool down) {
   if (modifier_flag == EF_NONE)
     return;
diff --git a/ui/events/ozone/evdev/keyboard_evdev.h b/ui/events/ozone/evdev/keyboard_evdev.h
index 1b8521a..b4ee004 100644
--- a/ui/events/ozone/evdev/keyboard_evdev.h
+++ b/ui/events/ozone/evdev/keyboard_evdev.h
@@ -69,6 +69,7 @@
   void UpdateCapsLockLed();
 
   // EventAutoRepeatHandler::Delegate
+  void FlushInput(base::OnceClosure closure) override;
   void DispatchKey(unsigned int key,
                    bool down,
                    bool repeat,
diff --git a/ui/ozone/platform/wayland/wayland_keyboard.cc b/ui/ozone/platform/wayland/wayland_keyboard.cc
index a033e2dc..570a346 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard.cc
+++ b/ui/ozone/platform/wayland/wayland_keyboard.cc
@@ -95,32 +95,17 @@
                           uint32_t key,
                           uint32_t state) {
   WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
+  DCHECK(keyboard);
+
   keyboard->connection_->set_serial(serial);
 
-  DomCode dom_code =
-      KeycodeConverter::NativeKeycodeToDomCode(key + kXkbKeycodeOffset);
-  if (dom_code == ui::DomCode::NONE)
-    return;
-
-  uint8_t flags = keyboard->event_modifiers_.GetModifierFlags();
-  DomKey dom_key;
-  KeyboardCode key_code;
-  if (!KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup(
-          dom_code, flags, &dom_key, &key_code))
-    return;
-
   bool down = state == WL_KEYBOARD_KEY_STATE_PRESSED;
 
-  // TODO(tonikitoo,msisov): only the two lines below if not handling repeat.
-  int flag = ModifierDomKeyToEventFlag(dom_key);
-  keyboard->UpdateModifier(flag, down);
-
-  ui::KeyEvent event(
-      down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code, dom_code,
-      keyboard->event_modifiers_.GetModifierFlags(), dom_key,
-      base::TimeTicks() + base::TimeDelta::FromMilliseconds(time));
-  event.set_source_device_id(keyboard->obj_.id());
-  keyboard->callback_.Run(&event);
+  // TODO(tonikitoo,msisov): Handler 'repeat' parameter below.
+  keyboard->DispatchKey(
+      key, down, false /*repeat*/,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(time),
+      keyboard->obj_.id());
 }
 
 void WaylandKeyboard::Modifiers(void* data,
@@ -145,6 +130,35 @@
   NOTIMPLEMENTED();
 }
 
+void WaylandKeyboard::DispatchKey(uint32_t key,
+                                  bool down,
+                                  bool repeat,
+                                  base::TimeTicks timestamp,
+                                  int device_id) {
+  DomCode dom_code =
+      KeycodeConverter::NativeKeycodeToDomCode(key + kXkbKeycodeOffset);
+  if (dom_code == ui::DomCode::NONE)
+    return;
+
+  uint8_t flags = event_modifiers_.GetModifierFlags();
+  DomKey dom_key;
+  KeyboardCode key_code;
+  if (!KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup(
+          dom_code, flags, &dom_key, &key_code))
+    return;
+
+  if (!repeat) {
+    int flag = ModifierDomKeyToEventFlag(dom_key);
+    UpdateModifier(flag, down);
+  }
+
+  ui::KeyEvent event(down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code,
+                     dom_code, event_modifiers_.GetModifierFlags(), dom_key,
+                     timestamp);
+  event.set_source_device_id(device_id);
+  callback_.Run(&event);
+}
+
 void WaylandKeyboard::UpdateModifier(int modifier_flag, bool down) {
   if (modifier_flag == EF_NONE)
     return;
diff --git a/ui/ozone/platform/wayland/wayland_keyboard.h b/ui/ozone/platform/wayland/wayland_keyboard.h
index 727a993..70251f6d 100644
--- a/ui/ozone/platform/wayland/wayland_keyboard.h
+++ b/ui/ozone/platform/wayland/wayland_keyboard.h
@@ -60,6 +60,12 @@
 
   void UpdateModifier(int modifier_flag, bool down);
 
+  void DispatchKey(unsigned int key,
+                   bool down,
+                   bool repeat,
+                   base::TimeTicks timestamp,
+                   int device_id);
+
   WaylandConnection* connection_ = nullptr;
   wl::Object<wl_keyboard> obj_;
   EventDispatchCallback callback_;
diff --git a/ui/views/win/hwnd_message_handler_delegate.h b/ui/views/win/hwnd_message_handler_delegate.h
index 2168aed..16b1032 100644
--- a/ui/views/win/hwnd_message_handler_delegate.h
+++ b/ui/views/win/hwnd_message_handler_delegate.h
@@ -5,12 +5,16 @@
 #ifndef UI_VIEWS_WIN_HWND_MESSAGE_HANDLER_DELEGATE_H_
 #define UI_VIEWS_WIN_HWND_MESSAGE_HANDLER_DELEGATE_H_
 
+#include "base/win/windows_types.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/gfx/native_widget_types.h"
 #include "ui/views/views_export.h"
 
 namespace gfx {
 class Insets;
 class Path;
 class Point;
+class Rect;
 class Size;
 }
 
@@ -19,6 +23,8 @@
 class InputMethod;
 class KeyEvent;
 class MouseEvent;
+class PointerEvent;
+class ScrollEvent;
 class TouchEvent;
 }
 
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js
index a886a12..32371d4 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -365,12 +365,13 @@
 
     var propertiesToSet = this.getPropertiesToSet_();
     if (!this.guid || this.getSource_() == CrOnc.Source.NONE) {
-      // New network configurations default to 'AutoConnect' unless prohibited
-      // by policy.
+      // New non VPN network configurations default to 'AutoConnect' unless
+      // prohibited by policy.
+      var prohibitAutoConnect = this.globalPolicy &&
+          this.globalPolicy.AllowOnlyPolicyNetworksToConnect;
       CrOnc.setTypeProperty(
           propertiesToSet, 'AutoConnect',
-          !(this.globalPolicy &&
-            this.globalPolicy.AllowOnlyPolicyNetworksToConnect));
+          this.type != CrOnc.Type.VPN && !prohibitAutoConnect);
 
       // Create the configuration, then connect to it in the callback.
       this.networkingPrivate.createNetwork(