diff --git a/AUTHORS b/AUTHORS
index 8ed2917..3a3ca7a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -203,6 +203,7 @@
 Diego Ferreiro Val <elfogris@gmail.com>
 Dillon Sellars <dill.sellars@gmail.com>
 Divya Bansal <divya.bansal@samsung.com>
+Dominic Farolino <domfarolino@gmail.com>
 Dominic Jodoin <dominic.jodoin@gmail.com>
 Dominik Röttsches <dominik.rottsches@intel.com>
 Don Woodward <woodward@adobe.com>
diff --git a/DEPS b/DEPS
index eb63c7e..a945a12 100644
--- a/DEPS
+++ b/DEPS
@@ -130,7 +130,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': '035dfdbc3ead397e90d3d66bfca3a2232351dbd9',
+  'catapult_revision': 'e3b4c57dcbbb729558d5d41fc2154d6f6a69ceae',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -636,10 +636,10 @@
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
 
   'src/third_party/webgl/src':
-    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '1a8ed15c9c25f2b1ccd97149c94ea245ab982252',
+    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd458ada06171a85af00367251a4ed55db7fe2018',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'd5247510dc9cf1b1f8eb1f79310bef702b7804c1', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + '9106fb6d23603d47bb8f3d63b45c278ff138d119', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/build/fuchsia/runner_common.py b/build/fuchsia/runner_common.py
index ba81b0e..a1dac34 100755
--- a/build/fuchsia/runner_common.py
+++ b/build/fuchsia/runner_common.py
@@ -330,20 +330,19 @@
   for arg in child_args:
     autorun_file.write(' "%s"' % arg);
   autorun_file.write('\n')
-  autorun_file.write('echo \"%s\"\n' % ALL_DONE_MESSAGE)
 
   if shutdown_machine:
     autorun_file.write('echo Sleeping and shutting down...\n')
 
     # A delay is required to give the guest OS or remote device a chance to
     # flush its output before it terminates.
+    autorun_file.write('msleep 8000\n')
     if use_device:
-      autorun_file.write('msleep 8000\n')
       autorun_file.write('dm reboot\n')
     else:
-      autorun_file.write('msleep 3000\n')
       autorun_file.write('dm poweroff\n')
 
+  autorun_file.write('echo \"%s\"\n' % ALL_DONE_MESSAGE)
 
   autorun_file.flush()
   os.chmod(autorun_file.name, 0750)
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 5405abb..8b7dae57d 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1403,6 +1403,8 @@
     "ssl/ssl_error_navigation_throttle.h",
     "ssl/ssl_error_tab_helper.cc",
     "ssl/ssl_error_tab_helper.h",
+    "ssl/typed_navigation_timing_throttle.cc",
+    "ssl/typed_navigation_timing_throttle.h",
     "status_icons/status_icon.cc",
     "status_icons/status_icon.h",
     "status_icons/status_icon_menu_model.cc",
@@ -3271,6 +3273,8 @@
         "printing/pdf_to_emf_converter.cc",
         "printing/pdf_to_emf_converter.h",
       ]
+    }
+    if (is_win || enable_print_preview) {
       deps += [ "//chrome/services/printing/public/interfaces" ]
     }
     if (enable_print_preview) {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 731f448..2e07721 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -96,6 +96,7 @@
 #include "chrome/browser/ssl/ssl_client_certificate_selector.h"
 #include "chrome/browser/ssl/ssl_error_handler.h"
 #include "chrome/browser/ssl/ssl_error_navigation_throttle.h"
+#include "chrome/browser/ssl/typed_navigation_timing_throttle.h"
 #include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
 #include "chrome/browser/tab_contents/tab_util.h"
@@ -3517,6 +3518,11 @@
         base::Bind(&SSLErrorHandler::HandleSSLError)));
   }
 
+  std::unique_ptr<content::NavigationThrottle> https_upgrade_timing_throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(handle);
+  if (https_upgrade_timing_throttle)
+    throttles.push_back(std::move(https_upgrade_timing_throttle));
+
   return throttles;
 }
 
diff --git a/chrome/browser/ssl/typed_navigation_timing_throttle.cc b/chrome/browser/ssl/typed_navigation_timing_throttle.cc
new file mode 100644
index 0000000..240e1a1
--- /dev/null
+++ b/chrome/browser/ssl/typed_navigation_timing_throttle.cc
@@ -0,0 +1,76 @@
+// 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 "chrome/browser/ssl/typed_navigation_timing_throttle.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "content/public/common/browser_side_navigation_policy.h"
+#include "ui/base/page_transition_types.h"
+#include "url/url_constants.h"
+
+// static
+std::unique_ptr<content::NavigationThrottle>
+TypedNavigationTimingThrottle::MaybeCreateThrottleFor(
+    content::NavigationHandle* handle) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (!handle->GetURL().SchemeIs(url::kHttpScheme))
+    return nullptr;
+
+  return base::WrapUnique(new TypedNavigationTimingThrottle(handle));
+}
+
+TypedNavigationTimingThrottle::~TypedNavigationTimingThrottle() {}
+
+content::NavigationThrottle::ThrottleCheckResult
+TypedNavigationTimingThrottle::WillStartRequest() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  url::Replacements<char> remove_port;
+  remove_port.ClearPort();
+  initial_url_ = navigation_handle()->GetURL().ReplaceComponents(remove_port);
+  return content::NavigationThrottle::PROCEED;
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+TypedNavigationTimingThrottle::WillRedirectRequest() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (recorded_ ||
+      !ui::PageTransitionCoreTypeIs(navigation_handle()->GetPageTransition(),
+                                    ui::PAGE_TRANSITION_TYPED)) {
+    return content::NavigationThrottle::PROCEED;
+  }
+
+  // Check if the URL is the same as the original but upgraded to HTTPS.
+  // We ignore the port numbers (in case of non-standard HTTP or HTTPS ports)
+  // and allow adding or dropping of a "www." prefix.
+  url::Replacements<char> remove_port;
+  remove_port.ClearPort();
+  const GURL& redirect_url =
+      navigation_handle()->GetURL().ReplaceComponents(remove_port);
+  if (redirect_url.SchemeIs(url::kHttpsScheme) &&
+      (redirect_url.GetContent() == initial_url_.GetContent() ||
+       redirect_url.GetContent() == "www." + initial_url_.GetContent() ||
+       "www." + redirect_url.GetContent() == initial_url_.GetContent())) {
+    UMA_HISTOGRAM_TIMES(
+        "Omnibox.URLNavigationTimeToRedirectToHTTPS",
+        base::TimeTicks::Now() - navigation_handle()->NavigationStart());
+    recorded_ = true;
+  }
+
+  return content::NavigationThrottle::PROCEED;
+}
+
+const char* TypedNavigationTimingThrottle::GetNameForLogging() {
+  return "TypedNavigationTimingThrottle";
+}
+
+TypedNavigationTimingThrottle::TypedNavigationTimingThrottle(
+    content::NavigationHandle* handle)
+    : content::NavigationThrottle(handle) {}
diff --git a/chrome/browser/ssl/typed_navigation_timing_throttle.h b/chrome/browser/ssl/typed_navigation_timing_throttle.h
new file mode 100644
index 0000000..11bc874
--- /dev/null
+++ b/chrome/browser/ssl/typed_navigation_timing_throttle.h
@@ -0,0 +1,42 @@
+// 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 CHROME_BROWSER_SSL_TYPED_NAVIGATION_TIMING_THROTTLE_H_
+#define CHROME_BROWSER_SSL_TYPED_NAVIGATION_TIMING_THROTTLE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "url/gurl.h"
+
+namespace content {
+class NavigationHandle;
+}
+
+// A TypedNavigationTimingThrottle tracks the timings of a navigation caused by
+// a typed URL navigation for an HTTP URL which was then redirected to HTTPS.
+class TypedNavigationTimingThrottle : public content::NavigationThrottle {
+ public:
+  static std::unique_ptr<content::NavigationThrottle> MaybeCreateThrottleFor(
+      content::NavigationHandle* handle);
+
+  ~TypedNavigationTimingThrottle() override;
+
+  // content::NavigationThrottle:
+  content::NavigationThrottle::ThrottleCheckResult WillStartRequest() override;
+  content::NavigationThrottle::ThrottleCheckResult WillRedirectRequest()
+      override;
+  const char* GetNameForLogging() override;
+
+ private:
+  explicit TypedNavigationTimingThrottle(content::NavigationHandle* handle);
+
+  GURL initial_url_;
+  bool recorded_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(TypedNavigationTimingThrottle);
+};
+
+#endif  // CHROME_BROWSER_SSL_TYPED_NAVIGATION_TIMING_THROTTLE_H_
diff --git a/chrome/browser/ssl/typed_navigation_timing_throttle_browsertest.cc b/chrome/browser/ssl/typed_navigation_timing_throttle_browsertest.cc
new file mode 100644
index 0000000..e5e86ff
--- /dev/null
+++ b/chrome/browser/ssl/typed_navigation_timing_throttle_browsertest.cc
@@ -0,0 +1,73 @@
+// 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 "base/logging.h"
+#include "base/test/histogram_tester.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "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"
+
+// Sets up two test servers, one on HTTP and one on HTTPS, where the HTTP
+// server redirects requests to the HTTPS server. This lets the tests exercise
+// the start and redirect cases of the TypedNavigationTimingThrottle in a real
+// browsing navigation context.
+class TypedNavigationTimingThrottleBrowserTest : public InProcessBrowserTest {
+ public:
+  TypedNavigationTimingThrottleBrowserTest()
+      : http_server_(net::EmbeddedTestServer::TYPE_HTTP),
+        https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
+
+  void SetUpOnMainThread() override {
+    http_server_.RegisterRequestHandler(base::BindRepeating(
+        &TypedNavigationTimingThrottleBrowserTest::RedirectRequestToHTTPS,
+        base::Unretained(this)));
+    https_server_.RegisterRequestHandler(base::BindRepeating(
+        &TypedNavigationTimingThrottleBrowserTest::DefaultRequestHandler,
+        base::Unretained(this)));
+    ASSERT_TRUE(http_server_.Start());
+    ASSERT_TRUE(https_server_.Start());
+  }
+
+  std::unique_ptr<net::test_server::HttpResponse> RedirectRequestToHTTPS(
+      const net::test_server::HttpRequest& request) {
+    std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
+        new net::test_server::BasicHttpResponse);
+    http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
+    http_response->AddCustomHeader(
+        "Location", "https://" + https_server_.GetURL("/").GetContent());
+    return std::move(http_response);
+  }
+
+  std::unique_ptr<net::test_server::HttpResponse> DefaultRequestHandler(
+      const net::test_server::HttpRequest& request) {
+    std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
+        new net::test_server::BasicHttpResponse);
+    http_response->set_code(net::HTTP_OK);
+    http_response->set_content("Success");
+    return std::move(http_response);
+  }
+
+ protected:
+  const net::EmbeddedTestServer& http_server() { return http_server_; }
+  const net::EmbeddedTestServer& https_server() { return https_server_; }
+
+ private:
+  net::EmbeddedTestServer http_server_;
+  net::EmbeddedTestServer https_server_;
+
+  DISALLOW_COPY_AND_ASSIGN(TypedNavigationTimingThrottleBrowserTest);
+};
+
+// Tests that the navigation throttle is correctly installed by navigating to a
+// URL which will be redirected to HTTPS, updating the histogram.
+IN_PROC_BROWSER_TEST_F(TypedNavigationTimingThrottleBrowserTest,
+                       HistogramUpdatedWhenRedirected) {
+  base::HistogramTester tester;
+  // By default this will trigger a navigation with type PAGE_TRANSITION_TYPED.
+  ui_test_utils::NavigateToURL(browser(), http_server().GetURL("/"));
+  tester.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
+}
diff --git a/chrome/browser/ssl/typed_navigation_timing_throttle_unittest.cc b/chrome/browser/ssl/typed_navigation_timing_throttle_unittest.cc
new file mode 100644
index 0000000..3efa30b
--- /dev/null
+++ b/chrome/browser/ssl/typed_navigation_timing_throttle_unittest.cc
@@ -0,0 +1,321 @@
+// 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 "chrome/browser/ssl/typed_navigation_timing_throttle.h"
+
+#include "base/test/histogram_tester.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+class TypedNavigationTimingThrottleTest
+    : public ChromeRenderViewHostTestHarness {};
+
+// Tests that the throttle is created for navigations to HTTP URLs.
+TEST_F(TypedNavigationTimingThrottleTest, IsCreatedForHTTP) {
+  GURL http_url("http://example.test");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
+                                                                  main_rfh());
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(handle.get());
+  EXPECT_TRUE(throttle);
+}
+
+// Tests that the throttle is not created if the URL is HTTPS.
+TEST_F(TypedNavigationTimingThrottleTest, NotCreatedForHTTPS) {
+  GURL https_url("https://example.test");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(https_url,
+                                                                  main_rfh());
+  std::unique_ptr<content::NavigationThrottle> throttle =
+      TypedNavigationTimingThrottle::MaybeCreateThrottleFor(handle.get());
+  EXPECT_FALSE(throttle);
+}
+
+// Tests that the timing histogram is correctly updated.
+TEST_F(TypedNavigationTimingThrottleTest, URLUpgraded) {
+  base::HistogramTester test;
+
+  GURL http_url("http://example.test");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
+                                                                  main_rfh());
+
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillStartRequestForTesting(
+                    false,                     /* is_post */
+                    content::Referrer(), true, /* has_user_gesture */
+                    ui::PAGE_TRANSITION_TYPED, false /* is_external_protocol */)
+                .action());
+
+  GURL https_url("https://example.test");
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    https_url, false, /* new_method_is_post */
+                    http_url,         /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+
+  test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
+}
+
+// Tests that the histogram is not updated if the URL was never upgraded.
+TEST_F(TypedNavigationTimingThrottleTest, URLNotUpgraded) {
+  base::HistogramTester test;
+
+  GURL http_url("http://example.test");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
+                                                                  main_rfh());
+
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillStartRequestForTesting(
+                    false,                     /* is_post */
+                    content::Referrer(), true, /* has_user_gesture */
+                    ui::PAGE_TRANSITION_TYPED, false /* is_external_protocol */)
+                .action());
+
+  test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 0);
+}
+
+// Tests that the histogram is not updated if the URL is redirected to a
+// different URL (not an HTTPS upgrade).
+TEST_F(TypedNavigationTimingThrottleTest, NonHTTPSRedirect) {
+  base::HistogramTester test;
+
+  GURL http_url("http://example.test");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
+                                                                  main_rfh());
+
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillStartRequestForTesting(
+                    false,                     /* is_post */
+                    content::Referrer(), true, /* has_user_gesture */
+                    ui::PAGE_TRANSITION_TYPED, false /* is_external_protocol */)
+                .action());
+
+  GURL other_url("http://nonexample.test");
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    other_url, false, /* new_method_is_post */
+                    http_url,         /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+
+  test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 0);
+}
+
+// Tests that the histogram is not updated if the URL is redirected to a
+// different URL _with_ HTTPS.
+TEST_F(TypedNavigationTimingThrottleTest, CrossSiteHTTPSRedirect) {
+  base::HistogramTester test;
+
+  GURL http_url("http://example.test");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
+                                                                  main_rfh());
+
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillStartRequestForTesting(
+                    false,                     /* is_post */
+                    content::Referrer(), true, /* has_user_gesture */
+                    ui::PAGE_TRANSITION_TYPED, false /* is_external_protocol */)
+                .action());
+
+  GURL other_url("https://nonexample.test");
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    other_url, false, /* new_method_is_post */
+                    http_url,         /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+
+  test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 0);
+}
+
+// Tests that the histogram is not updated if the navigation isn't of type
+// PAGE_TRANSITION_TYPED.
+TEST_F(TypedNavigationTimingThrottleTest, NonTypedNavigation) {
+  base::HistogramTester test;
+
+  GURL http_url("http://example.test");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
+                                                                  main_rfh());
+
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillStartRequestForTesting(
+                    false,                     /* is_post */
+                    content::Referrer(), true, /* has_user_gesture */
+                    ui::PAGE_TRANSITION_LINK, false /* is_external_protocol */)
+                .action());
+
+  GURL https_url("https://example.test");
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    https_url, false, /* new_method_is_post */
+                    http_url,         /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+
+  test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 0);
+}
+
+// Tests that the histogram is updated only once for a long chain of redirects
+// which include the same-URL HTTP->HTTPS upgrade at the beginning.
+TEST_F(TypedNavigationTimingThrottleTest, ManyRedirects) {
+  base::HistogramTester test;
+
+  GURL http_url("http://example.test");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
+                                                                  main_rfh());
+
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillStartRequestForTesting(
+                    false,                     /* is_post */
+                    content::Referrer(), true, /* has_user_gesture */
+                    ui::PAGE_TRANSITION_TYPED, false /* is_external_protocol */)
+                .action());
+
+  // Redirecting to the "upgraded" URL twice in a row should result in only one
+  // activation of the histogram trigger.
+  GURL https_url("https://example.test");
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    https_url, false, /* new_method_is_post */
+                    http_url,         /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    https_url, false, /* new_method_is_post */
+                    http_url,         /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+
+  // Other redirects should also not affect the histogram.
+  GURL other_http_url("http://nonexample.test");
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    other_http_url, false, /* new_method_is_post */
+                    https_url,             /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+
+  GURL other_https_url("https://nonexample.test");
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    other_https_url, false, /* new_method_is_post */
+                    other_http_url,         /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+
+  test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
+}
+
+// Tests that the histogram is updated when the new URL adds "www.".
+TEST_F(TypedNavigationTimingThrottleTest, AddWWW) {
+  base::HistogramTester test;
+
+  GURL http_url("http://example.test");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
+                                                                  main_rfh());
+
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillStartRequestForTesting(
+                    false,                     /* is_post */
+                    content::Referrer(), true, /* has_user_gesture */
+                    ui::PAGE_TRANSITION_TYPED, false /* is_external_protocol */)
+                .action());
+
+  GURL https_url("https://www.example.test");
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    https_url, false, /* new_method_is_post */
+                    http_url,         /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+
+  test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
+}
+
+// Tests that the histogram is updated when the new URL removed "www."
+TEST_F(TypedNavigationTimingThrottleTest, RemoveWWW) {
+  base::HistogramTester test;
+
+  GURL http_url("http://www.example.test");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
+                                                                  main_rfh());
+
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillStartRequestForTesting(
+                    false,                     /* is_post */
+                    content::Referrer(), true, /* has_user_gesture */
+                    ui::PAGE_TRANSITION_TYPED, false /* is_external_protocol */)
+                .action());
+
+  GURL https_url("https://example.test");
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    https_url, false, /* new_method_is_post */
+                    http_url,         /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+
+  test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
+}
+
+// Tests that the histogram is updated when the URLs have different ports.
+TEST_F(TypedNavigationTimingThrottleTest, NonstandardPorts) {
+  base::HistogramTester test;
+
+  GURL http_url("http://example.test:8080");
+  std::unique_ptr<content::NavigationHandle> handle =
+      content::NavigationHandle::CreateNavigationHandleForTesting(http_url,
+                                                                  main_rfh());
+
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillStartRequestForTesting(
+                    false,                     /* is_post */
+                    content::Referrer(), true, /* has_user_gesture */
+                    ui::PAGE_TRANSITION_TYPED, false /* is_external_protocol */)
+                .action());
+
+  GURL https_url("https://example.test:4443");
+  EXPECT_EQ(content::NavigationThrottle::PROCEED,
+            handle
+                ->CallWillRedirectRequestForTesting(
+                    https_url, false, /* new_method_is_post */
+                    http_url,         /* new_referrer_url */
+                    false /* new_is_external_protocol */)
+                .action());
+
+  test.ExpectTotalCount("Omnibox.URLNavigationTimeToRedirectToHTTPS", 1);
+}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 39d64e256..41381b0 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -695,6 +695,7 @@
       "../browser/ssl/ssl_browsertest.cc",
       "../browser/ssl/ssl_client_certificate_selector_test.cc",
       "../browser/ssl/ssl_client_certificate_selector_test.h",
+      "../browser/ssl/typed_navigation_timing_throttle_browsertest.cc",
       "../browser/storage/durable_storage_browsertest.cc",
       "../browser/subresource_filter/subresource_filter_browser_test_harness.cc",
       "../browser/subresource_filter/subresource_filter_browser_test_harness.h",
@@ -2454,6 +2455,7 @@
     "../browser/ssl/ssl_error_handler_unittest.cc",
     "../browser/ssl/ssl_error_navigation_throttle_unittest.cc",
     "../browser/ssl/ssl_error_tab_helper_unittest.cc",
+    "../browser/ssl/typed_navigation_timing_throttle_unittest.cc",
     "../browser/status_icons/status_icon_menu_model_unittest.cc",
     "../browser/status_icons/status_icon_unittest.cc",
     "../browser/status_icons/status_tray_unittest.cc",
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index c6da5d8..5d59846 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10225.0.0
\ No newline at end of file
+10228.0.0
\ No newline at end of file
diff --git a/content/browser/loader/cross_site_document_resource_handler.cc b/content/browser/loader/cross_site_document_resource_handler.cc
index 293fb28..c5b9ffb 100644
--- a/content/browser/loader/cross_site_document_resource_handler.cc
+++ b/content/browser/loader/cross_site_document_resource_handler.cc
@@ -35,31 +35,57 @@
                             CrossSiteDocumentResourceHandler::Action::kCount);
 }
 
+// An IOBuffer to enable writing into a existing IOBuffer at a given offset.
+class LocalIoBufferWithOffset : public net::WrappedIOBuffer {
+ public:
+  LocalIoBufferWithOffset(net::IOBuffer* buf, int offset)
+      : net::WrappedIOBuffer(buf->data() + offset), buf_(buf) {}
+
+ private:
+  ~LocalIoBufferWithOffset() override {}
+
+  scoped_refptr<net::IOBuffer> buf_;
+};
+
+// Helper for the text/plain case.
+CrossSiteDocumentClassifier::Result SniffForHtmlXmlOrJson(
+    base::StringPiece data) {
+  DCHECK_LT(CrossSiteDocumentClassifier::kNo,
+            CrossSiteDocumentClassifier::kMaybe);
+  auto result = CrossSiteDocumentClassifier::SniffForHTML(data);
+  if (result != CrossSiteDocumentClassifier::kYes)
+    result = std::max(CrossSiteDocumentClassifier::SniffForXML(data), result);
+  if (result != CrossSiteDocumentClassifier::kYes)
+    result = std::max(CrossSiteDocumentClassifier::SniffForJSON(data), result);
+  return result;
+}
+
 }  // namespace
 
-// ResourceController used in OnWillRead in cases that sniffing will happen.
-// When invoked, it runs the corresponding method on the ResourceHandler.
-class CrossSiteDocumentResourceHandler::OnWillReadController
-    : public ResourceController {
+// ResourceController that runs a closure on Resume(), and forwards failures
+// back to CrossSiteDocumentHandler. The closure can optionally be run as
+// a PostTask.
+class CrossSiteDocumentResourceHandler::Controller : public ResourceController {
  public:
-  // Keeps track of the addresses of the ResourceLoader's buffer and size,
-  // which will be populated by the downstream ResourceHandler by the time that
-  // Resume() is called.
-  explicit OnWillReadController(
-      CrossSiteDocumentResourceHandler* document_handler,
-      scoped_refptr<net::IOBuffer>* buf,
-      int* buf_size)
-      : document_handler_(document_handler), buf_(buf), buf_size_(buf_size) {}
+  explicit Controller(CrossSiteDocumentResourceHandler* document_handler,
+                      bool post_task,
+                      base::OnceClosure resume_callback)
+      : document_handler_(document_handler),
+        resume_callback_(std::move(resume_callback)),
+        post_task_(post_task) {}
 
-  ~OnWillReadController() override {}
+  ~Controller() override {}
 
   // ResourceController implementation:
   void Resume() override {
     MarkAsUsed();
 
-    // Now that |buf_| has a buffer written into it by the downstream handler,
-    // set up sniffing in the CrossSiteDocumentResourceHandler.
-    document_handler_->ResumeOnWillRead(buf_, buf_size_);
+    if (post_task_) {
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, std::move(resume_callback_));
+    } else {
+      std::move(resume_callback_).Run();
+    }
   }
 
   void Cancel() override {
@@ -86,14 +112,11 @@
 
   CrossSiteDocumentResourceHandler* document_handler_;
 
-  // Address of the ResourceLoader's buffer, which will be populated by the
-  // downstream handler before Resume() is called.
-  scoped_refptr<net::IOBuffer>* buf_;
+  // Runs on Resume().
+  base::OnceClosure resume_callback_;
+  bool post_task_;
 
-  // Address of the size of |buf_|, similarly populated downstream.
-  int* buf_size_;
-
-  DISALLOW_COPY_AND_ASSIGN(OnWillReadController);
+  DISALLOW_COPY_AND_ASSIGN(Controller);
 };
 
 CrossSiteDocumentResourceHandler::CrossSiteDocumentResourceHandler(
@@ -101,7 +124,9 @@
     net::URLRequest* request,
     bool is_nocors_plugin_request)
     : LayeredResourceHandler(request, std::move(next_handler)),
-      is_nocors_plugin_request_(is_nocors_plugin_request) {}
+      weak_next_handler_(next_handler_.get()),
+      is_nocors_plugin_request_(is_nocors_plugin_request),
+      weak_this_(this) {}
 
 CrossSiteDocumentResourceHandler::~CrossSiteDocumentResourceHandler() {}
 
@@ -122,6 +147,15 @@
     std::unique_ptr<ResourceController> controller) {
   DCHECK(has_response_started_);
 
+  if (local_buffer_) {
+    // If |local_buffer_| exists, continue buffering data into the end of it.
+    *buf = new LocalIoBufferWithOffset(local_buffer_.get(),
+                                       local_buffer_bytes_read_);
+    *buf_size = next_handler_buffer_size_ - local_buffer_bytes_read_;
+    controller->Resume();
+    return;
+  }
+
   // On the next read attempt after the response was blocked, either cancel the
   // rest of the request or allow it to proceed in a detached state.
   if (blocked_read_completed_) {
@@ -147,7 +181,10 @@
   // downstream handler has called Resume on it.
   if (should_block_based_on_headers_ && !allow_based_on_sniffing_) {
     HoldController(std::move(controller));
-    controller = std::make_unique<OnWillReadController>(this, buf, buf_size);
+    controller = std::make_unique<Controller>(
+        this, false /* post_task */,
+        base::BindOnce(&CrossSiteDocumentResourceHandler::ResumeOnWillRead,
+                       weak_this_.GetWeakPtr(), buf, buf_size));
   }
 
   // Have the downstream handler(s) allocate the real buffer to use.
@@ -198,22 +235,31 @@
   // response is empty and complete), or copy the sniffed data to the next
   // handler's buffer and resume the response without blocking.
   if (should_block_based_on_headers_ && !allow_based_on_sniffing_) {
-    bool confirmed_blockable = false;
+    auto confirmed_blockable = CrossSiteDocumentClassifier::kNo;
     if (!needs_sniffing_) {
       // TODO(creis): Also consider the MIME type confirmed if |bytes_read| is
       // too small to do sniffing, or restructure to allow buffering enough.
       // For now, responses with small initial reads may be allowed through.
-      confirmed_blockable = true;
+      confirmed_blockable = CrossSiteDocumentClassifier::kYes;
+    } else if (bytes_read == 0) {
+      // We haven't blocked the response yet (because previous reads yielded a
+      // kMaybe result), and there is no more data. Allow the response.
+      confirmed_blockable = CrossSiteDocumentClassifier::kNo;
     } else {
       // Sniff the data to see if it likely matches the MIME type that caused us
       // to decide to block it.  If it doesn't match, it may be JavaScript,
       // JSONP, or another allowable data type and we should let it through.
       // Record how many bytes were read to see how often it's too small.  (This
       // will typically be under 100,000.)
-      UMA_HISTOGRAM_COUNTS("SiteIsolation.XSD.Browser.BytesReadForSniffing",
-                           bytes_read);
-      DCHECK_LE(bytes_read, next_handler_buffer_size_);
-      base::StringPiece data(local_buffer_->data(), bytes_read);
+      local_buffer_bytes_read_ += bytes_read;
+      DCHECK_LE(local_buffer_bytes_read_, next_handler_buffer_size_);
+
+      // To ensure determinism with respect to network packet ordering and
+      // sizing, never examine more than kMaxBytesToSniff bytes, even if more
+      // are available.
+      size_t bytes_to_sniff =
+          std::min(local_buffer_bytes_read_, net::kMaxBytesToSniff);
+      base::StringPiece data(local_buffer_->data(), bytes_to_sniff);
 
       // Confirm whether the data is HTML, XML, or JSON.
       if (canonical_mime_type_ == CROSS_SITE_DOCUMENT_MIME_TYPE_HTML) {
@@ -225,13 +271,25 @@
       } else if (canonical_mime_type_ == CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN) {
         // For responses labeled as plain text, only block them if the data
         // sniffs as one of the formats we would block in the first place.
-        confirmed_blockable = CrossSiteDocumentClassifier::SniffForHTML(data) ||
-                              CrossSiteDocumentClassifier::SniffForXML(data) ||
-                              CrossSiteDocumentClassifier::SniffForJSON(data);
+        confirmed_blockable = SniffForHtmlXmlOrJson(data);
+      }
+
+      // If sniffing didn't yield a conclusive response, and we haven't read too
+      // many bytes yet, buffer up some more data.
+      if (confirmed_blockable == CrossSiteDocumentClassifier::kMaybe &&
+          local_buffer_bytes_read_ < net::kMaxBytesToSniff &&
+          local_buffer_bytes_read_ < next_handler_buffer_size_) {
+        controller->Resume();
+        return;
       }
     }
 
-    if (confirmed_blockable) {
+    if (needs_sniffing_) {
+      UMA_HISTOGRAM_COUNTS("SiteIsolation.XSD.Browser.BytesReadForSniffing",
+                           local_buffer_bytes_read_);
+    }
+
+    if (confirmed_blockable == CrossSiteDocumentClassifier::kYes) {
       // Block the response and throw away the data.  Report zero bytes read.
       bytes_read = 0;
       blocked_read_completed_ = true;
@@ -280,16 +338,48 @@
           NOTREACHED();
       }
     } else {
-      // Allow the response through instead and proceed with reading more.
-      // Copy sniffed data into the next handler's buffer before proceeding.
-      // Note that the size of the two buffers is the same (see OnWillRead).
-      DCHECK_LE(bytes_read, next_handler_buffer_size_);
-      memcpy(next_handler_buffer_->data(), local_buffer_->data(), bytes_read);
+      // Choose not block this response. Pass the contents of |local_buffer_|
+      // onto the next handler. Note that the size of the two buffers is the
+      // same (see OnWillRead).
+      DCHECK_LE(local_buffer_bytes_read_, next_handler_buffer_size_);
+      memcpy(next_handler_buffer_->data(), local_buffer_->data(),
+             local_buffer_bytes_read_);
       allow_based_on_sniffing_ = true;
+
+      if (bytes_read == 0 && local_buffer_bytes_read_ != 0) {
+        // |bytes_read == 0| indicates the end-of-stream. In this case, we need
+        // to synthesize an additional OnWillRead() and OnReadCompleted(0) on
+        // |next_handler_|, so that |next_handler_| sees both the full response
+        // and the end-of-stream marker. The resulting operations are as
+        // follows:
+        //
+        //  1. next_handler_->OnReadCompleted(bytes_read = contentLength)
+        //  2. next_handler_->OnWillRead()  [via PostTask]
+        //  3. next_handler_->OnReadCompleted(bytes_read = 0) [via PostTask]
+        //  4. controller->Resume()
+        HoldController(std::move(controller));
+        controller = std::make_unique<Controller>(
+            this, true /* post_task */,
+            base::BindOnce(
+                &ResourceHandler::OnWillRead, weak_next_handler_.GetWeakPtr(),
+                &next_handler_buffer_, &next_handler_buffer_size_,
+                std::make_unique<Controller>(
+                    this, true /* post_task */,
+                    base::BindOnce(
+                        &ResourceHandler::OnReadCompleted,
+                        weak_next_handler_.GetWeakPtr(), 0 /* bytes_read */,
+                        std::make_unique<Controller>(
+                            this, false /* post_task */,
+                            base::BindOnce(
+                                &CrossSiteDocumentResourceHandler::Resume,
+                                weak_this_.GetWeakPtr()))))));
+      }
+      bytes_read = local_buffer_bytes_read_;
     }
 
     // Clean up, whether we'll cancel or proceed from here.
     local_buffer_ = nullptr;
+    local_buffer_bytes_read_ = 0;
     next_handler_buffer_ = nullptr;
     next_handler_buffer_size_ = 0;
   }
@@ -344,6 +434,8 @@
 
   // Look up MIME type.  If it doesn't claim to be a blockable type (i.e., HTML,
   // XML, JSON, or plain text), don't block it.
+  // TODO(nick): What if the mime type is omitted? Should that be treated the
+  // same as text/plain? https://crbug.com/795971
   canonical_mime_type_ = CrossSiteDocumentClassifier::GetCanonicalMimeType(
       response->head.mime_type);
   if (canonical_mime_type_ == CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS)
diff --git a/content/browser/loader/cross_site_document_resource_handler.h b/content/browser/loader/cross_site_document_resource_handler.h
index 4dd1d4a..1164c503 100644
--- a/content/browser/loader/cross_site_document_resource_handler.h
+++ b/content/browser/loader/cross_site_document_resource_handler.h
@@ -9,6 +9,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "content/browser/loader/layered_resource_handler.h"
 #include "content/common/cross_site_document_classifier.h"
 #include "content/public/common/resource_type.h"
@@ -86,9 +87,8 @@
   FRIEND_TEST_ALL_PREFIXES(CrossSiteDocumentResourceHandlerTest,
                            OnWillReadDefer);
 
-  // ResourceController that manages the read buffer if a downstream handler
-  // defers during OnWillRead.
-  class OnWillReadController;
+  // A ResourceController subclass for running deferred operations.
+  class Controller;
 
   // Computes whether this response contains a cross-site document that needs to
   // be blocked from the renderer process.  This is a first approximation based
@@ -100,6 +100,9 @@
   // Called by the OnWillReadController.
   void ResumeOnWillRead(scoped_refptr<net::IOBuffer>* buf, int* buf_size);
 
+  // WeakPtrFactory for |next_handler_|.
+  base::WeakPtrFactory<ResourceHandler> weak_next_handler_;
+
   // A local buffer for sniffing content and using for throwaway reads.
   // This is not shared with the renderer process.
   scoped_refptr<net::IOBuffer> local_buffer_;
@@ -108,6 +111,9 @@
   // if sniffing determines that we should proceed with the response.
   scoped_refptr<net::IOBuffer> next_handler_buffer_;
 
+  // The number of bytes written into |local_buffer_| by previous reads.
+  int local_buffer_bytes_read_ = 0;
+
   // The size of |next_handler_buffer_|.
   int next_handler_buffer_size_ = 0;
 
@@ -148,6 +154,8 @@
   // completed, and thus it is safe to cancel or detach on the next read.
   bool blocked_read_completed_ = false;
 
+  base::WeakPtrFactory<CrossSiteDocumentResourceHandler> weak_this_;
+
   DISALLOW_COPY_AND_ASSIGN(CrossSiteDocumentResourceHandler);
 };
 
diff --git a/content/browser/loader/cross_site_document_resource_handler_unittest.cc b/content/browser/loader/cross_site_document_resource_handler_unittest.cc
index 7f278e8f..cb74681 100644
--- a/content/browser/loader/cross_site_document_resource_handler_unittest.cc
+++ b/content/browser/loader/cross_site_document_resource_handler_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 
+#include <initializer_list>
 #include <memory>
 #include <string>
 #include <utility>
@@ -53,10 +54,8 @@
 };
 
 enum class Verdict {
-  kAllowWithoutSniffing,
-  kBlockWithoutSniffing,
-  kAllowAfterSniffing,
-  kBlockAfterSniffing
+  kAllow,
+  kBlock,
 };
 
 // This struct is used to describe each test case in this file.  It's passed as
@@ -77,10 +76,25 @@
   CrossSiteDocumentMimeType canonical_mime_type;
   bool include_no_sniff_header;
   AccessControlAllowOriginHeader cors_response;
-  const char* first_chunk;
+  // |packets| specifies the response data which may arrive over the course of
+  // several writes.
+  std::initializer_list<const char*> packets;
+
+  std::string data() const {
+    std::string data;
+    for (const char* packet : packets) {
+      data += packet;
+    }
+    return data;
+  }
 
   // Expected result.
   Verdict verdict;
+  // The packet number during which the verdict is decided. -1 means
+  // that the verdict can be decided before the first packet's data
+  // is available. |packets.size()| means that the verdict is decided
+  // during the end-of-stream call.
+  int verdict_packet;
 };
 
 // Stream operator to let GetParam() print a useful result if any tests fail.
@@ -102,28 +116,32 @@
     case AccessControlAllowOriginHeader::kAllowExampleDotCom:
       cors_response = "AccessControlAllowOriginHeader::kAllowExampleDotCom";
       break;
-    default:
-      NOTREACHED();
   }
 
   std::string verdict;
   switch (scenario.verdict) {
-    case Verdict::kAllowWithoutSniffing:
+    case Verdict::kAllow:
       verdict = "Verdict::kAllowWithoutSniffing";
       break;
-    case Verdict::kBlockWithoutSniffing:
+    case Verdict::kBlock:
       verdict = "Verdict::kBlockWithoutSniffing";
       break;
-    case Verdict::kAllowAfterSniffing:
-      verdict = "Verdict::kAllowAfterSniffing";
-      break;
-    case Verdict::kBlockAfterSniffing:
-      verdict = "Verdict::kBlockAfterSniffing";
-      break;
-    default:
-      NOTREACHED();
   }
 
+  std::string packets;
+  for (std::string packet : scenario.packets) {
+    base::ReplaceChars(packet, "\\", "\\\\", &packet);
+    base::ReplaceChars(packet, "\"", "\\\"", &packet);
+    base::ReplaceChars(packet, "\n", "\\n", &packet);
+    base::ReplaceChars(packet, "\t", "\\t", &packet);
+    base::ReplaceChars(packet, "\r", "\\r", &packet);
+    packets += packets.empty() ? "{" : ", ";
+    packets += "\"";
+    packets += packet;
+    packets += "\"";
+  }
+  packets += "}";
+
   return os << "\n  description         = " << scenario.description
             << "\n  target_url          = " << scenario.target_url
             << "\n  resource_type       = " << scenario.resource_type
@@ -137,30 +155,56 @@
             << "\n  include_no_sniff    = "
             << (scenario.include_no_sniff_header ? "true" : "false")
             << "\n  cors_response       = " << cors_response
-            << "\n  first_chunk         = " << scenario.first_chunk
-            << "\n  verdict             = " << verdict;
+            << "\n  packets             = " << packets
+            << "\n  verdict             = " << verdict
+            << "\n  verdict_packet      = " << scenario.verdict_packet;
 }
 
+// An HTML response with an HTML comment that's longer than the sniffing
+// threshhold. We don't sniff past net::kMaxBytesToSniff, so these are not
+// protected
+const char kHTMLWithTooLongComment[] =
+    "<!--.............................................................72 chars"
+    "................................................................144 chars"
+    "................................................................216 chars"
+    "................................................................288 chars"
+    "................................................................360 chars"
+    "................................................................432 chars"
+    "................................................................504 chars"
+    "................................................................576 chars"
+    "................................................................648 chars"
+    "................................................................720 chars"
+    "................................................................792 chars"
+    "................................................................864 chars"
+    "................................................................936 chars"
+    "...............................................................1008 chars"
+    "...............................................................1080 chars"
+    "--><html><head>";
+
 // A set of test cases that verify CrossSiteDocumentResourceHandler correctly
 // classifies network responses as allowed or blocked.  These TestScenarios are
 // passed to the TEST_P tests below as test parameters.
 const TestScenario kScenarios[] = {
-    // Allowed responses:
+
+    // Allowed responses (without sniffing):
     {
-        "Allowed: Same-site XHR to HTML", __LINE__,
-        "http://www.a.com/resource.html",         // target_url
-        RESOURCE_TYPE_XHR,                        // resource_type
-        "http://www.a.com/",                      // initiator_origin
-        OriginHeader::kOmit,                      // cors_request
-        "text/html",                              // response_mime_type
-        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,       // canonical_mime_type
-        false,                                    // include_no_sniff_header
-        AccessControlAllowOriginHeader::kOmit,    // cors_response
-        "<html><head>this should sniff as HTML",  // first_chunk
-        Verdict::kAllowWithoutSniffing,           // verdict
+        "Allowed: Same-site XHR to HTML",
+        __LINE__,
+        "http://www.a.com/resource.html",           // target_url
+        RESOURCE_TYPE_XHR,                          // resource_type
+        "http://www.a.com/",                        // initiator_origin
+        OriginHeader::kOmit,                        // cors_request
+        "text/html",                                // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,         // canonical_mime_type
+        false,                                      // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,      // cors_response
+        {"<html><head>this should sniff as HTML"},  // packets
+        Verdict::kAllow,                            // verdict
+        -1,                                         // verdict_packet
     },
     {
-        "Allowed: Cross-site script", __LINE__,
+        "Allowed: Cross-site script",
+        __LINE__,
         "http://www.b.com/resource.html",       // target_url
         RESOURCE_TYPE_SCRIPT,                   // resource_type
         "http://www.a.com/",                    // initiator_origin
@@ -169,11 +213,13 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS,   // canonical_mime_type
         false,                                  // include_no_sniff_header
         AccessControlAllowOriginHeader::kOmit,  // cors_response
-        "var x=3;",                             // first_chunk
-        Verdict::kAllowWithoutSniffing,         // verdict
+        {"var x=3;"},                           // packets
+        Verdict::kAllow,                        // verdict
+        -1,                                     // verdict_packet
     },
     {
-        "Allowed: Cross-site XHR to HTML with CORS for origin", __LINE__,
+        "Allowed: Cross-site XHR to HTML with CORS for origin",
+        __LINE__,
         "http://www.b.com/resource.html",    // target_url
         RESOURCE_TYPE_XHR,                   // resource_type
         "http://www.a.com/",                 // initiator_origin
@@ -182,11 +228,13 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,  // canonical_mime_type
         false,                               // include_no_sniff_header
         AccessControlAllowOriginHeader::kAllowInitiatorOrigin,  // cors_response
-        "<html><head>this should sniff as HTML",                // first_chunk
-        Verdict::kAllowWithoutSniffing,                         // verdict
+        {"<html><head>this should sniff as HTML"},              // packets
+        Verdict::kAllow,                                        // verdict
+        -1,  // verdict_packet
     },
     {
-        "Allowed: Cross-site XHR to XML with CORS for any", __LINE__,
+        "Allowed: Cross-site XHR to XML with CORS for any",
+        __LINE__,
         "http://www.b.com/resource.html",           // target_url
         RESOURCE_TYPE_XHR,                          // resource_type
         "http://www.a.com/",                        // initiator_origin
@@ -195,11 +243,13 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_XML,          // canonical_mime_type
         false,                                      // include_no_sniff_header
         AccessControlAllowOriginHeader::kAllowAny,  // cors_response
-        "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>",  // first_chunk
-        Verdict::kAllowWithoutSniffing,                 // verdict
+        {"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"},  // packets
+        Verdict::kAllow,                                  // verdict
+        -1,                                               // verdict_packet
     },
     {
-        "Allowed: Cross-site XHR to JSON with CORS for null", __LINE__,
+        "Allowed: Cross-site XHR to JSON with CORS for null",
+        __LINE__,
         "http://www.b.com/resource.html",            // target_url
         RESOURCE_TYPE_XHR,                           // resource_type
         "http://www.a.com/",                         // initiator_origin
@@ -208,50 +258,58 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_JSON,          // canonical_mime_type
         false,                                       // include_no_sniff_header
         AccessControlAllowOriginHeader::kAllowNull,  // cors_response
-        "{\"x\" : 3}",                               // first_chunk
-        Verdict::kAllowWithoutSniffing,              // verdict
+        {"{\"x\" : 3}"},                             // packets
+        Verdict::kAllow,                             // verdict
+        -1,                                          // verdict_packet
     },
     {
-        "Allowed: Cross-site XHR to HTML over FTP", __LINE__,
-        "ftp://www.b.com/resource.html",          // target_url
-        RESOURCE_TYPE_XHR,                        // resource_type
-        "http://www.a.com/",                      // initiator_origin
-        OriginHeader::kOmit,                      // cors_request
-        "text/html",                              // response_mime_type
-        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,       // canonical_mime_type
-        false,                                    // include_no_sniff_header
-        AccessControlAllowOriginHeader::kOmit,    // cors_response
-        "<html><head>this should sniff as HTML",  // first_chunk
-        Verdict::kAllowWithoutSniffing,           // verdict
+        "Allowed: Cross-site XHR to HTML over FTP",
+        __LINE__,
+        "ftp://www.b.com/resource.html",            // target_url
+        RESOURCE_TYPE_XHR,                          // resource_type
+        "http://www.a.com/",                        // initiator_origin
+        OriginHeader::kOmit,                        // cors_request
+        "text/html",                                // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,         // canonical_mime_type
+        false,                                      // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,      // cors_response
+        {"<html><head>this should sniff as HTML"},  // packets
+        Verdict::kAllow,                            // verdict
+        -1,                                         // verdict_packet
     },
     {
-        "Allowed: Cross-site XHR to HTML from file://", __LINE__,
-        "file:///foo/resource.html",              // target_url
-        RESOURCE_TYPE_XHR,                        // resource_type
-        "http://www.a.com/",                      // initiator_origin
-        OriginHeader::kOmit,                      // cors_request
-        "text/html",                              // response_mime_type
-        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,       // canonical_mime_type
-        false,                                    // include_no_sniff_header
-        AccessControlAllowOriginHeader::kOmit,    // cors_response
-        "<html><head>this should sniff as HTML",  // first_chunk
-        Verdict::kAllowWithoutSniffing,           // verdict
+        "Allowed: Cross-site XHR to HTML from file://",
+        __LINE__,
+        "file:///foo/resource.html",                // target_url
+        RESOURCE_TYPE_XHR,                          // resource_type
+        "http://www.a.com/",                        // initiator_origin
+        OriginHeader::kOmit,                        // cors_request
+        "text/html",                                // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,         // canonical_mime_type
+        false,                                      // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,      // cors_response
+        {"<html><head>this should sniff as HTML"},  // packets
+        Verdict::kAllow,                            // verdict
+        -1,                                         // verdict_packet
     },
     {
-        "Allowed: Cross-site fetch HTML from Flash without CORS", __LINE__,
-        "http://www.b.com/plugin.html",           // target_url
-        RESOURCE_TYPE_PLUGIN_RESOURCE,            // resource_type
-        "http://www.a.com/",                      // initiator_origin
-        OriginHeader::kOmit,                      // cors_request
-        "text/html",                              // response_mime_type
-        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,       // canonical_mime_type
-        false,                                    // include_no_sniff_header
-        AccessControlAllowOriginHeader::kOmit,    // cors_response
-        "<html><head>this should sniff as HTML",  // first_chunk
-        Verdict::kAllowWithoutSniffing,           // verdict
+        "Allowed: Cross-site fetch HTML from Flash without CORS",
+        __LINE__,
+        "http://www.b.com/plugin.html",             // target_url
+        RESOURCE_TYPE_PLUGIN_RESOURCE,              // resource_type
+        "http://www.a.com/",                        // initiator_origin
+        OriginHeader::kOmit,                        // cors_request
+        "text/html",                                // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,         // canonical_mime_type
+        false,                                      // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,      // cors_response
+        {"<html><head>this should sniff as HTML"},  // packets
+        Verdict::kAllow,                            // verdict
+        -1,                                         // verdict_packet
     },
     {
-        "Allowed: Cross-site fetch HTML from NaCl with CORS response", __LINE__,
+        "Allowed: Cross-site fetch HTML from NaCl with CORS response",
+        __LINE__,
         "http://www.b.com/plugin.html",      // target_url
         RESOURCE_TYPE_PLUGIN_RESOURCE,       // resource_type
         "http://www.a.com/",                 // initiator_origin
@@ -260,13 +318,60 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,  // canonical_mime_type
         false,                               // include_no_sniff_header
         AccessControlAllowOriginHeader::kAllowInitiatorOrigin,  // cors_response
-        "<html><head>this should sniff as HTML",                // first_chunk
-        Verdict::kAllowWithoutSniffing,                         // verdict
+        {"<html><head>this should sniff as HTML"},              // first_chunk
+        Verdict::kAllow,                                        // verdict
+        -1,  // verdict_packet
+    },
+    {
+        "Allowed: JSON labeled as JavaScript with a no-sniff header",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_SCRIPT,                   // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "application/javascript",               // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS,   // canonical_mime_type
+        true,                                   // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {"{ \"key\": true }"},                  // packets
+        Verdict::kAllow,                        // verdict
+        -1,                                     // verdict_packet
+    },
+    {
+        "Allowed: Empty response with PNG mime type",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                      // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "image/png",                            // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS,   // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {},                                     // packets
+        Verdict::kAllow,                        // verdict
+        -1,                                     // verdict_packet
+    },
+    {
+        "Allowed: Empty response with PNG mime type and nosniff header",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                      // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "image/png",                            // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS,   // canonical_mime_type
+        true,                                   // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {},                                     // packets
+        Verdict::kAllow,                        // verdict
+        -1,                                     // verdict_packet
     },
 
     // Allowed responses due to sniffing:
     {
-        "Allowed: Cross-site script to JSONP labeled as HTML", __LINE__,
+        "Allowed: Cross-site script to JSONP labeled as HTML",
+        __LINE__,
         "http://www.b.com/resource.html",       // target_url
         RESOURCE_TYPE_SCRIPT,                   // resource_type
         "http://www.a.com/",                    // initiator_origin
@@ -275,11 +380,13 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,     // canonical_mime_type
         false,                                  // include_no_sniff_header
         AccessControlAllowOriginHeader::kOmit,  // cors_response
-        "foo({\"x\" : 3})",                     // first_chunk
-        Verdict::kAllowAfterSniffing,           // verdict
+        {"foo({\"x\" : 3})"},                   // packets
+        Verdict::kAllow,                        // verdict
+        0,                                      // verdict_packet
     },
     {
-        "Allowed: Cross-site script to JavaScript labeled as text", __LINE__,
+        "Allowed: Cross-site script to JavaScript labeled as text",
+        __LINE__,
         "http://www.b.com/resource.html",       // target_url
         RESOURCE_TYPE_SCRIPT,                   // resource_type
         "http://www.a.com/",                    // initiator_origin
@@ -288,11 +395,75 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN,    // canonical_mime_type
         false,                                  // include_no_sniff_header
         AccessControlAllowOriginHeader::kOmit,  // cors_response
-        "var x = 3;",                           // first_chunk
-        Verdict::kAllowAfterSniffing,           // verdict
+        {"var x = 3;"},                         // packets
+        Verdict::kAllow,                        // verdict
+        0,                                      // verdict_packet
     },
     {
-        "Allowed: Cross-site XHR to nonsense labeled as XML", __LINE__,
+        "Allowed: JSON-like JavaScript labeled as text",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_SCRIPT,                   // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "text/plain",                           // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN,    // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {"{", "    \n", "var x = 3;\n", "console.log('hello');"},  // packets
+        Verdict::kAllow,                                           // verdict
+        2,  // verdict_packet
+    },
+
+    {
+        "Allowed: JSONP labeled as JSON",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_SCRIPT,                   // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "text/json",                            // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_JSON,     // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {"invoke({ \"key\": true });"},         // packets
+        Verdict::kAllow,                        // verdict
+        0,                                      // verdict_packet
+    },
+    {
+        "Allowed (for now): JSON array literal labeled as text/plain",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_SCRIPT,                   // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "text/plain",                           // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN,    // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {"[1, 2, {}, true, false, \"yay\"]"},   // packets
+        Verdict::kAllow,                        // verdict
+        0,                                      // verdict_packet
+    },
+    {
+        "Allowed: JSON array literal on which a function is called.",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_SCRIPT,                   // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "text/plain",                           // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN,    // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {"[1, 2, {}, true, false, \"yay\"]", ".map(x => console.log(x))",
+         ".map(x => console.log(x));"},  // packets
+        Verdict::kAllow,                 // verdict
+        0,                               // verdict_packet
+    },
+    {
+        "Allowed: Cross-site XHR to nonsense labeled as XML",
+        __LINE__,
         "http://www.b.com/resource.html",       // target_url
         RESOURCE_TYPE_XHR,                      // resource_type
         "http://www.a.com/",                    // initiator_origin
@@ -301,11 +472,13 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_XML,      // canonical_mime_type
         false,                                  // include_no_sniff_header
         AccessControlAllowOriginHeader::kOmit,  // cors_response
-        "Won't sniff as XML",                   // first_chunk
-        Verdict::kAllowAfterSniffing,           // verdict
+        {"Won't sniff as XML"},                 // packets
+        Verdict::kAllow,                        // verdict
+        0,                                      // verdict_packet
     },
     {
-        "Allowed: Cross-site XHR to nonsense labeled as JSON", __LINE__,
+        "Allowed: Cross-site XHR to nonsense labeled as JSON",
+        __LINE__,
         "http://www.b.com/resource.html",       // target_url
         RESOURCE_TYPE_XHR,                      // resource_type
         "http://www.a.com/",                    // initiator_origin
@@ -314,13 +487,12 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_JSON,     // canonical_mime_type
         false,                                  // include_no_sniff_header
         AccessControlAllowOriginHeader::kOmit,  // cors_response
-        "Won't sniff as JSON",                  // first_chunk
-        Verdict::kAllowAfterSniffing,           // verdict
+        {"Won't sniff as JSON"},                // packets
+        Verdict::kAllow,                        // verdict
+        0,                                      // verdict_packet
     },
-    // TODO(creis): We should block the following response since there isn't
-    // enough data to confirm it as HTML by sniffing.
     {
-        "Allowed for now: Cross-site XHR to HTML with small first read",
+        "Allowed: Cross-site XHR to partial match for <HTML> tag",
         __LINE__,
         "http://www.b.com/resource.html",       // target_url
         RESOURCE_TYPE_XHR,                      // resource_type
@@ -330,79 +502,60 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,     // canonical_mime_type
         false,                                  // include_no_sniff_header
         AccessControlAllowOriginHeader::kOmit,  // cors_response
-        "<htm",                                 // first_chunk
-        Verdict::kAllowAfterSniffing,           // verdict
+        {"<htm"},                               // packets
+        Verdict::kAllow,                        // verdict
+        1,                                      // verdict_packet
+    },
+    {
+        "Allowed: HTML tag appears only after net::kMaxBytesToSniff",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                      // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "text/html",                            // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,     // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {kHTMLWithTooLongComment},              // packets
+        Verdict::kAllow,                        // verdict
+        0,                                      // verdict_packet
+    },
+    {
+        "Allowed: Empty response with html mime type",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                      // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "text/html",                            // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,     // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {},                                     // packets
+        Verdict::kAllow,                        // verdict
+        0,                                      // verdict_packet
     },
 
-    // Blocked responses:
+    // Blocked responses (without sniffing):
     {
-        "Blocked: Cross-site XHR to HTML without CORS", __LINE__,
-        "http://www.b.com/resource.html",         // target_url
-        RESOURCE_TYPE_XHR,                        // resource_type
-        "http://www.a.com/",                      // initiator_origin
-        OriginHeader::kOmit,                      // cors_request
-        "text/html",                              // response_mime_type
-        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,       // canonical_mime_type
-        false,                                    // include_no_sniff_header
-        AccessControlAllowOriginHeader::kOmit,    // cors_response
-        "<html><head>this should sniff as HTML",  // first_chunk
-        Verdict::kBlockAfterSniffing,             // verdict
-    },
-    {
-        "Blocked: Cross-site XHR to XML without CORS", __LINE__,
-        "http://www.b.com/resource.html",       // target_url
-        RESOURCE_TYPE_XHR,                      // resource_type
-        "http://www.a.com/",                    // initiator_origin
-        OriginHeader::kOmit,                    // cors_request
-        "application/xml",                      // response_mime_type
-        CROSS_SITE_DOCUMENT_MIME_TYPE_XML,      // canonical_mime_type
-        false,                                  // include_no_sniff_header
-        AccessControlAllowOriginHeader::kOmit,  // cors_response
-        "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>",  // first_chunk
-        Verdict::kBlockAfterSniffing,                   // verdict
-    },
-    {
-        "Blocked: Cross-site XHR to JSON without CORS", __LINE__,
-        "http://www.b.com/resource.html",       // target_url
-        RESOURCE_TYPE_XHR,                      // resource_type
-        "http://www.a.com/",                    // initiator_origin
-        OriginHeader::kOmit,                    // cors_request
-        "application/json",                     // response_mime_type
-        CROSS_SITE_DOCUMENT_MIME_TYPE_JSON,     // canonical_mime_type
-        false,                                  // include_no_sniff_header
-        AccessControlAllowOriginHeader::kOmit,  // cors_response
-        "{\"x\" : 3}",                          // first_chunk
-        Verdict::kBlockAfterSniffing,           // verdict
-    },
-    {
-        "Blocked: Cross-site XHR to HTML labeled as text without CORS",
+        "Blocked: Cross-site XHR to nosniff HTML without CORS",
         __LINE__,
-        "http://www.b.com/resource.html",         // target_url
-        RESOURCE_TYPE_XHR,                        // resource_type
-        "http://www.a.com/",                      // initiator_origin
-        OriginHeader::kOmit,                      // cors_request
-        "text/plain",                             // response_mime_type
-        CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN,      // canonical_mime_type
-        false,                                    // include_no_sniff_header
-        AccessControlAllowOriginHeader::kOmit,    // cors_response
-        "<html><head>this should sniff as HTML",  // first_chunk
-        Verdict::kBlockAfterSniffing,             // verdict
+        "http://www.b.com/resource.html",           // target_url
+        RESOURCE_TYPE_XHR,                          // resource_type
+        "http://www.a.com/",                        // initiator_origin
+        OriginHeader::kOmit,                        // cors_request
+        "text/html",                                // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,         // canonical_mime_type
+        true,                                       // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,      // cors_response
+        {"<html><head>this should sniff as HTML"},  // packets
+        Verdict::kBlock,                            // verdict
+        -1,                                         // verdict_packet
     },
     {
-        "Blocked: Cross-site XHR to nosniff HTML without CORS", __LINE__,
-        "http://www.b.com/resource.html",         // target_url
-        RESOURCE_TYPE_XHR,                        // resource_type
-        "http://www.a.com/",                      // initiator_origin
-        OriginHeader::kOmit,                      // cors_request
-        "text/html",                              // response_mime_type
-        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,       // canonical_mime_type
-        true,                                     // include_no_sniff_header
-        AccessControlAllowOriginHeader::kOmit,    // cors_response
-        "<html><head>this should sniff as HTML",  // first_chunk
-        Verdict::kBlockWithoutSniffing,           // verdict
-    },
-    {
-        "Blocked: Cross-site XHR to nosniff response without CORS", __LINE__,
+        "Blocked: Cross-site XHR to nosniff response without CORS",
+        __LINE__,
         "http://www.b.com/resource.html",       // target_url
         RESOURCE_TYPE_XHR,                      // resource_type
         "http://www.a.com/",                    // initiator_origin
@@ -411,8 +564,151 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,     // canonical_mime_type
         true,                                   // include_no_sniff_header
         AccessControlAllowOriginHeader::kOmit,  // cors_response
-        "Wouldn't sniff as HTML",               // first_chunk
-        Verdict::kBlockWithoutSniffing,         // verdict
+        {"Wouldn't sniff as HTML"},             // packets
+        Verdict::kBlock,                        // verdict
+        -1,                                     // verdict_packet
+    },
+
+    {
+        // This scenario is unusual, since there's no difference between
+        // a blocked response and a non-blocked response; the CSDRH doesn't
+        // actually have a chance to cancel the connection.
+        "Blocked(-ish?): Nosniff header + empty response",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                      // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kInclude,                 // cors_request
+        "text/html",                            // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,     // canonical_mime_type
+        true,                                   // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {},                                     // packets
+        Verdict::kBlock,                        // verdict
+        -1,                                     // verdict_packet
+    },
+
+    // Blocked responses due to sniffing:
+    {
+        "Blocked: Cross-site XHR to HTML without CORS",
+        __LINE__,
+        "http://www.b.com/resource.html",           // target_url
+        RESOURCE_TYPE_XHR,                          // resource_type
+        "http://www.a.com/",                        // initiator_origin
+        OriginHeader::kOmit,                        // cors_request
+        "text/html",                                // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,         // canonical_mime_type
+        false,                                      // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,      // cors_response
+        {"<html><head>this should sniff as HTML"},  // packets
+        Verdict::kBlock,                            // verdict
+        0,                                          // verdict_packet
+    },
+    {
+        "Blocked: Cross-site XHR to XML without CORS",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                      // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "application/xml",                      // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_XML,      // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"},  // packets
+        Verdict::kBlock,                                  // verdict
+        0,                                                // verdict_packet
+    },
+    {
+        "Blocked: Cross-site XHR to JSON without CORS",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                      // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "application/json",                     // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_JSON,     // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {"{\"x\" : 3}"},                        // packets
+        Verdict::kBlock,                        // verdict
+        0,                                      // verdict_packet
+    },
+    {
+        "Blocked: slow-arriving JSON labeled as text/plain",
+        __LINE__,
+        "http://www.b.com/resource.html",             // target_url
+        RESOURCE_TYPE_XHR,                            // resource_type
+        "http://www.a.com/",                          // initiator_origin
+        OriginHeader::kOmit,                          // cors_request
+        "text/plain",                                 // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN,          // canonical_mime_type
+        false,                                        // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,        // cors_response
+        {"    ", "\t", "{", "\"x\" ", "  ", ": 3}"},  // packets
+        Verdict::kBlock,                              // verdict
+        5,                                            // verdict_packet
+    },
+    {
+        "Blocked: slow-arriving xml labeled as text/plain",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                      // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "text/plain",                           // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN,    // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {"    ", "\t", "<", "?", "x", "m", "l", ">"},  // packets
+        Verdict::kBlock,                               // verdict
+        6,                                             // verdict_packet
+    },
+    {
+        "Blocked: slow-arriving html labeled as text/plain",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                      // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "text/plain",                           // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN,    // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {"    <!--", "\t -", "-", "->", "<", "s", "c", "r", "i", "p",
+         "t"},            // packets
+        Verdict::kBlock,  // verdict
+        10,               // verdict_packet
+    },
+    {
+        "Blocked: slow-arriving html with commented-out xml tag",
+        __LINE__,
+        "http://www.b.com/resource.html",       // target_url
+        RESOURCE_TYPE_XHR,                      // resource_type
+        "http://www.a.com/",                    // initiator_origin
+        OriginHeader::kOmit,                    // cors_request
+        "text/plain",                           // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN,    // canonical_mime_type
+        false,                                  // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,  // cors_response
+        {"    <!--", " <?xml ", "-->", "<", "h", "e", "a", "d"},  // packets
+        Verdict::kBlock,                                          // verdict
+        7,  // verdict_packet
+    },
+    {
+        "Blocked: Cross-site XHR to HTML labeled as text without CORS",
+        __LINE__,
+        "http://www.b.com/resource.html",           // target_url
+        RESOURCE_TYPE_XHR,                          // resource_type
+        "http://www.a.com/",                        // initiator_origin
+        OriginHeader::kOmit,                        // cors_request
+        "text/plain",                               // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN,        // canonical_mime_type
+        false,                                      // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,      // cors_response
+        {"<html><head>this should sniff as HTML"},  // packets
+        Verdict::kBlock,                            // verdict
+        0,                                          // verdict_packet
     },
     {
         "Blocked: Cross-site <script> inclusion of HTML w/ DTD without CORS",
@@ -425,13 +721,15 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,     // canonical_mime_type
         false,                                  // include_no_sniff_header
         AccessControlAllowOriginHeader::kOmit,  // cors_response
-        "<!doctype html><html itemscope=\"\" "
-        "itemtype=\"http://schema.org/SearchResultsPage\" "
-        "lang=\"en\"><head>",          // first_chunk
-        Verdict::kBlockAfterSniffing,  // verdict
+        {"<!doc", "type html><html itemscope=\"\" ",
+         "itemtype=\"http://schema.org/SearchResultsPage\" ",
+         "lang=\"en\"><head>"},  // packets
+        Verdict::kBlock,         // verdict
+        1,                       // verdict_packet
     },
     {
-        "Blocked: Cross-site XHR to HTML with wrong CORS", __LINE__,
+        "Blocked: Cross-site XHR to HTML with wrong CORS",
+        __LINE__,
         "http://www.b.com/resource.html",    // target_url
         RESOURCE_TYPE_XHR,                   // resource_type
         "http://www.a.com/",                 // initiator_origin
@@ -440,22 +738,24 @@
         CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,  // canonical_mime_type
         false,                               // include_no_sniff_header
         AccessControlAllowOriginHeader::kAllowExampleDotCom,  // cors_response
-        "<html><head>this should sniff as HTML",              // first_chunk
-        Verdict::kBlockAfterSniffing,                         // verdict
+        {"<hTmL><head>this should sniff as HTML"},            // packets
+        Verdict::kBlock,                                      // verdict
+        0,                                                    // verdict_packet
     },
     {
         "Blocked: Cross-site fetch HTML from NaCl without CORS response",
         __LINE__,
-        "http://www.b.com/plugin.html",           // target_url
-        RESOURCE_TYPE_PLUGIN_RESOURCE,            // resource_type
-        "http://www.a.com/",                      // initiator_origin
-        OriginHeader::kInclude,                   // cors_request
-        "text/html",                              // response_mime_type
-        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,       // canonical_mime_type
-        false,                                    // include_no_sniff_header
-        AccessControlAllowOriginHeader::kOmit,    // cors_response
-        "<html><head>this should sniff as HTML",  // first_chunk
-        Verdict::kBlockAfterSniffing,             // verdict
+        "http://www.b.com/plugin.html",             // target_url
+        RESOURCE_TYPE_PLUGIN_RESOURCE,              // resource_type
+        "http://www.a.com/",                        // initiator_origin
+        OriginHeader::kInclude,                     // cors_request
+        "text/html",                                // response_mime_type
+        CROSS_SITE_DOCUMENT_MIME_TYPE_HTML,         // canonical_mime_type
+        false,                                      // include_no_sniff_header
+        AccessControlAllowOriginHeader::kOmit,      // cors_response
+        {"<html><head>this should sniff as HTML"},  // first_chunk
+        Verdict::kBlock,                            // verdict
+        0,                                          // verdict_packet
     },
 };
 
@@ -552,6 +852,36 @@
     return response;
   }
 
+  // Determines the number of times that OnWillRead should be called on
+  // |stream_sink_| at the point in the test indicated by |current_packet|.
+  int GetExpectedNumberOfOnWillReadCalls(int current_packet) {
+    TestScenario scenario = GetParam();
+
+    // In all block scenarios, OnWillRead is called only once.
+    if (scenario.verdict == Verdict::kBlock)
+      return 1;
+
+    // If we're not yet at the point of the verdict packet, OnWillRead has only
+    // been called only once, since the resource handler doesn't yet know if
+    // we're blocking or allowing yet.
+    if (current_packet < scenario.verdict_packet)
+      return 1;
+
+    // If we are streaming from the start, we'll call |stream_sink_|'s
+    // OnWillRead every time.
+    if (scenario.verdict_packet <= 0)
+      return current_packet + 1;
+
+    // When the verdict is decided on the last packet (and the response was not
+    // empty), OnWillRead should be called exactly twice.
+    if (scenario.verdict_packet == static_cast<int>(scenario.packets.size()))
+      return 2;
+
+    // Otherwise, we buffer up until the verdict_packet, and then stream
+    // thereafter.
+    return 1 + (current_packet - scenario.verdict_packet);
+  }
+
  protected:
   TestBrowserThreadBundle thread_bundle_;
   net::TestURLRequestContext context_;
@@ -604,77 +934,161 @@
   EXPECT_EQ(scenario.canonical_mime_type,
             document_blocker_->canonical_mime_type_);
 
-  // Verify that we correctly decide whether to block based on headers.  Note
-  // that this includes cases that will later be allowed after sniffing.
-  bool expected_to_block_based_on_headers =
-      scenario.verdict == Verdict::kBlockWithoutSniffing ||
-      scenario.verdict == Verdict::kBlockAfterSniffing ||
-      scenario.verdict == Verdict::kAllowAfterSniffing;
-  EXPECT_EQ(expected_to_block_based_on_headers,
-            document_blocker_->should_block_based_on_headers_);
-
   // Verify that we will sniff content into a different buffer if sniffing is
   // needed.  Note that the different buffer is used even for blocking cases
   // where no sniffing is needed, to avoid complexity in the handler.  The
   // handler doesn't look at the data in that case, but there's no way to verify
   // it in the test.
-  bool expected_to_sniff = scenario.verdict == Verdict::kAllowAfterSniffing ||
-                           scenario.verdict == Verdict::kBlockAfterSniffing;
+  bool expected_to_sniff = scenario.verdict_packet >= 0;
   EXPECT_EQ(expected_to_sniff, document_blocker_->needs_sniffing_);
 
-  // Tell the ResourceHandlers to allocate the buffer for reading.  In this
-  // test, the buffer will be allocated immediately by the downstream handler
-  // and possibly replaced by a different buffer for sniffing.
-  ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead());
-  EXPECT_EQ(1, stream_sink_->on_will_read_called());
-  EXPECT_NE(nullptr, mock_loader_->io_buffer());
-  if (expected_to_sniff || scenario.verdict == Verdict::kBlockWithoutSniffing) {
-    EXPECT_EQ(mock_loader_->io_buffer(), document_blocker_->local_buffer_.get())
-        << "Should have used a different IOBuffer for sniffing";
-  } else {
-    EXPECT_EQ(mock_loader_->io_buffer(), stream_sink_->buffer())
-        << "Should have used original IOBuffer when sniffing not needed";
+  // Verify that we correctly decide whether to block based on headers.  Note
+  // that this includes cases that will later be allowed after sniffing.
+  bool expected_to_block_based_on_headers =
+      expected_to_sniff || scenario.verdict == Verdict::kBlock;
+  EXPECT_EQ(expected_to_block_based_on_headers,
+            document_blocker_->should_block_based_on_headers_);
+
+  // This vector holds the packets to be delivered.
+  std::vector<const char*> packets_vector(scenario.packets);
+  packets_vector.push_back("");  // End-of-stream is marked by an empty packet.
+
+  bool should_be_blocked = scenario.verdict == Verdict::kBlock;
+  int eof_packet = static_cast<int>(scenario.packets.size());
+  int effective_verdict_packet = scenario.verdict_packet;
+  if (should_be_blocked) {
+    // Our implementation currently only blocks at the second OnWillRead.
+    effective_verdict_packet = std::max(0, effective_verdict_packet);
   }
 
-  // Deliver the first chunk of the response body; this allows sniffing to
-  // occur.
-  ASSERT_EQ(MockResourceLoader::Status::IDLE,
-            mock_loader_->OnReadCompleted(scenario.first_chunk));
-  EXPECT_EQ(nullptr, mock_loader_->io_buffer());
+  int i = 0;
+  for (const base::StringPiece packet : packets_vector) {
+    SCOPED_TRACE(testing::Message() << "While delivering packet #" << i);
+    bool should_be_streaming =
+        scenario.verdict == Verdict::kAllow && i > scenario.verdict_packet;
 
-  // Verify that the response is blocked or allowed as expected.
-  bool should_be_blocked = scenario.verdict == Verdict::kBlockWithoutSniffing ||
-                           scenario.verdict == Verdict::kBlockAfterSniffing;
-  if (should_be_blocked) {
-    EXPECT_EQ("", stream_sink_body_)
-        << "Response should not have been delivered to the renderer.";
-    EXPECT_TRUE(document_blocker_->blocked_read_completed_);
-    EXPECT_FALSE(document_blocker_->allow_based_on_sniffing_);
-  } else {
-    EXPECT_EQ(scenario.first_chunk, stream_sink_body_)
-        << "Response should have been delivered to the renderer.";
-    EXPECT_FALSE(document_blocker_->blocked_read_completed_);
-    if (scenario.verdict == Verdict::kAllowAfterSniffing)
+    if (i <= effective_verdict_packet) {
+      EXPECT_FALSE(document_blocker_->blocked_read_completed_);
+      EXPECT_FALSE(document_blocker_->allow_based_on_sniffing_);
+    } else {
+      ASSERT_EQ(should_be_blocked, document_blocker_->blocked_read_completed_);
+      EXPECT_EQ(!should_be_blocked && expected_to_sniff,
+                document_blocker_->allow_based_on_sniffing_);
+    }
+
+    // Tell the ResourceHandlers to allocate the buffer for reading. On the
+    // first read, and after an 'allow' verdict, this will request a buffer from
+    // the downstream handler. Otherwise, it'll ask for more space in the local
+    // buffer used for sniffing.
+    mock_loader_->OnWillRead();
+
+    if (should_be_blocked && i == effective_verdict_packet + 1) {
+      // The Cancel() occurs during the OnWillRead subsequent to the block
+      // decision.
+      EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
+      break;
+    }
+
+    EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status());
+    EXPECT_NE(nullptr, mock_loader_->io_buffer());
+    if (!should_be_streaming) {
+      EXPECT_EQ(mock_loader_->io_buffer()->data(),
+                document_blocker_->local_buffer_->data() +
+                    document_blocker_->local_buffer_bytes_read_)
+          << "Should have used a different IOBuffer for sniffing";
+      EXPECT_NE(stream_sink_->buffer(), mock_loader_->io_buffer());
+    } else {
+      EXPECT_FALSE(should_be_blocked);
+      EXPECT_EQ(mock_loader_->io_buffer(), stream_sink_->buffer())
+          << "Should have used original IOBuffer when sniffing not needed";
+    }
+
+    // Deliver the next packet of the response body; this allows sniffing to
+    // occur.
+    mock_loader_->OnReadCompleted(packet);
+    if (mock_loader_->status() ==
+        MockResourceLoader::Status::CALLBACK_PENDING) {
+      // CALLBACK_PENDING is only expected in the case where an allow decision
+      // is made during the final empty packet.
+      EXPECT_FALSE(should_be_blocked);
+      EXPECT_EQ(i, eof_packet);
+      EXPECT_EQ(eof_packet, scenario.verdict_packet);
+      EXPECT_EQ("", packet);
+
+      // Waits for CrossSiteDocumentResourceHandler::Resume().
+      mock_loader_->WaitUntilIdleOrCanceled();
+    }
+    EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status());
+    EXPECT_EQ(nullptr, mock_loader_->io_buffer());
+
+    // mock_loader->OnWillRead() should only result in calls through to
+    // stream_sink_->OnWillRead() for the first packet, or for packets after an
+    // "allow" decision.
+    EXPECT_EQ(GetExpectedNumberOfOnWillReadCalls(i),
+              stream_sink_->on_will_read_called());
+
+    if (should_be_blocked) {
+      EXPECT_FALSE(document_blocker_->allow_based_on_sniffing_);
+      EXPECT_EQ("", stream_sink_body_)
+          << "Response should not have been delivered to the renderer.";
+      EXPECT_LE(i, effective_verdict_packet);
+      EXPECT_EQ(i == effective_verdict_packet,
+                document_blocker_->blocked_read_completed_);
+    } else if (expected_to_sniff && i >= scenario.verdict_packet) {
       EXPECT_TRUE(document_blocker_->allow_based_on_sniffing_);
+      EXPECT_FALSE(document_blocker_->blocked_read_completed_);
+    } else {
+      EXPECT_FALSE(document_blocker_->allow_based_on_sniffing_);
+      EXPECT_FALSE(document_blocker_->blocked_read_completed_);
+    }
+    if (should_be_streaming) {
+      EXPECT_EQ(packet, stream_sink_body_.substr(stream_sink_body_.size() -
+                                                 packet.size()))
+          << "Response should be streamed to the renderer.";
+    }
+
+    // Increment our packet counter.
+    i++;
   }
 
+  // All packets are now sent. Validate our final expectations, and send
+  // OnResponseCompleted.
+  EXPECT_EQ(GetExpectedNumberOfOnWillReadCalls(eof_packet),
+            stream_sink_->on_will_read_called());
+
+  // Check the final block/no-block decision.
+  EXPECT_EQ(document_blocker_->blocked_read_completed_, should_be_blocked);
+  EXPECT_EQ(document_blocker_->allow_based_on_sniffing_,
+            !should_be_blocked && expected_to_sniff);
+
+  // Simulate an OnResponseCompleted from the ResourceLoader.
   if (should_be_blocked) {
-    // The next OnWillRead should cancel and complete the response.
-    ASSERT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->OnWillRead());
+    if (!scenario.data().empty()) {
+      // TODO(nick): We may be left in an inconsistent state when blocking an
+      // empty nosniff response. Remove the above 'if'.
+      EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
+    }
     net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
                                  net::ERR_ABORTED);
+    EXPECT_EQ(stream_sink_body_, "");
+
     ASSERT_EQ(MockResourceLoader::Status::IDLE,
               mock_loader_->OnResponseCompleted(status));
   } else {
-    // Simulate the next read being empty to end the response.
-    ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead());
-    ASSERT_EQ(MockResourceLoader::Status::IDLE,
-              mock_loader_->OnReadCompleted(""));
+    EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status());
+    EXPECT_EQ(stream_sink_body_, scenario.data());
+
     ASSERT_EQ(MockResourceLoader::Status::IDLE,
               mock_loader_->OnResponseCompleted(
                   net::URLRequestStatus::FromError(net::OK)));
   }
 
+  // Ensure that all or none of the data arrived.
+  if (should_be_blocked)
+    EXPECT_EQ(stream_sink_body_, "");
+  else
+    EXPECT_EQ(stream_sink_body_, scenario.data());
+
   // Verify that histograms are correctly incremented.
   base::HistogramTester::CountsMap expected_counts;
   std::string histogram_base = "SiteIsolation.XSD.Browser";
@@ -702,25 +1116,20 @@
   int start_action = static_cast<int>(
       CrossSiteDocumentResourceHandler::Action::kResponseStarted);
   int end_action = -1;
-  switch (scenario.verdict) {
-    case Verdict::kBlockWithoutSniffing:
-      end_action = static_cast<int>(
-          CrossSiteDocumentResourceHandler::Action::kBlockedWithoutSniffing);
-      break;
-    case Verdict::kBlockAfterSniffing:
-      end_action = static_cast<int>(
-          CrossSiteDocumentResourceHandler::Action::kBlockedAfterSniffing);
-      break;
-    case Verdict::kAllowWithoutSniffing:
-      end_action = static_cast<int>(
-          CrossSiteDocumentResourceHandler::Action::kAllowedWithoutSniffing);
-      break;
-    case Verdict::kAllowAfterSniffing:
-      end_action = static_cast<int>(
-          CrossSiteDocumentResourceHandler::Action::kAllowedAfterSniffing);
-      break;
-    default:
-      NOTREACHED();
+  if (should_be_blocked && expected_to_sniff) {
+    end_action = static_cast<int>(
+        CrossSiteDocumentResourceHandler::Action::kBlockedAfterSniffing);
+  } else if (should_be_blocked && !expected_to_sniff) {
+    end_action = static_cast<int>(
+        CrossSiteDocumentResourceHandler::Action::kBlockedWithoutSniffing);
+  } else if (!should_be_blocked && expected_to_sniff) {
+    end_action = static_cast<int>(
+        CrossSiteDocumentResourceHandler::Action::kAllowedAfterSniffing);
+  } else if (!should_be_blocked && !expected_to_sniff) {
+    end_action = static_cast<int>(
+        CrossSiteDocumentResourceHandler::Action::kAllowedWithoutSniffing);
+  } else {
+    NOTREACHED();
   }
   // Expecting two actions: ResponseStarted and one of the outcomes.
   expected_counts[histogram_base + ".Action"] = 2;
@@ -731,11 +1140,16 @@
   // Expect to hear the number of bytes in the first read when sniffing is
   // required.
   if (expected_to_sniff) {
-    std::string first_chunk = scenario.first_chunk;
     expected_counts[histogram_base + ".BytesReadForSniffing"] = 1;
+
+    // Only the packets up to verdict_packet are sniffed.
+    int expected_sniff_bytes = 0;
+    for (int i = 0; i <= effective_verdict_packet; i++) {
+      expected_sniff_bytes += strlen(packets_vector[i]);
+    }
     EXPECT_EQ(
         1, histograms.GetBucketCount(histogram_base + ".BytesReadForSniffing",
-                                     first_chunk.size()));
+                                     expected_sniff_bytes));
   }
   if (should_be_blocked) {
     expected_counts[histogram_base + ".Blocked"] = 1;
@@ -780,53 +1194,97 @@
   // where no sniffing is needed, to avoid complexity in the handler.  The
   // handler doesn't look at the data in that case, but there's no way to verify
   // it in the test.
-  bool expected_to_sniff = scenario.verdict == Verdict::kAllowAfterSniffing ||
-                           scenario.verdict == Verdict::kBlockAfterSniffing;
+  bool expected_to_sniff = (scenario.verdict_packet != -1);
   EXPECT_EQ(expected_to_sniff, document_blocker_->needs_sniffing_);
 
   // Cause the TestResourceHandler to defer when OnWillRead is called, to make
   // sure the test scenarios still work when the downstream handler's buffer
   // isn't allocated in the same call.
-  stream_sink_->set_defer_on_will_read(true);
-  ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
-            mock_loader_->OnWillRead());
-  EXPECT_EQ(1, stream_sink_->on_will_read_called());
+  size_t bytes_delivered = 0;
+  int buffer_requests = 0;
+  int packets = 0;
+  std::vector<const char*> packets_vector(scenario.packets);
+  packets_vector.push_back("");
+  for (base::StringPiece packet : packets_vector) {
+    bool should_be_streaming = scenario.verdict == Verdict::kAllow &&
+                               packets > scenario.verdict_packet;
+    stream_sink_->set_defer_on_will_read(true);
+    mock_loader_->OnWillRead();
+    if (bytes_delivered == 0 || should_be_streaming) {
+      EXPECT_EQ(++buffer_requests, stream_sink_->on_will_read_called());
+      ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
+                mock_loader_->status());
 
-  // No buffers have been allocated yet.
-  EXPECT_EQ(nullptr, mock_loader_->io_buffer());
-  EXPECT_EQ(nullptr, document_blocker_->local_buffer_.get());
+      // No buffers have been allocated yet.
+      EXPECT_EQ(nullptr, mock_loader_->io_buffer());
+      EXPECT_EQ(nullptr, document_blocker_->local_buffer_.get());
 
-  // Resume the downstream handler, which should establish a buffer for the
-  // ResourceLoader (either the downstream one or a local one for sniffing).
-  stream_sink_->Resume();
-  EXPECT_NE(nullptr, mock_loader_->io_buffer());
-  if (expected_to_sniff || scenario.verdict == Verdict::kBlockWithoutSniffing) {
-    EXPECT_EQ(mock_loader_->io_buffer(), document_blocker_->local_buffer_.get())
-        << "Should have used a different IOBuffer for sniffing";
-  } else {
-    EXPECT_EQ(mock_loader_->io_buffer(), stream_sink_->buffer())
-        << "Should have used original IOBuffer when sniffing not needed";
+      // Resume the downstream handler, which should establish a buffer for the
+      // ResourceLoader (either the downstream one or a local one for sniffing).
+      stream_sink_->WaitUntilDeferred();
+      stream_sink_->Resume();
+    } else {
+      if (document_blocker_->blocked_read_completed_) {
+        // We've decided to block.
+        EXPECT_EQ(Verdict::kBlock, scenario.verdict);
+        EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader_->status());
+        break;
+      } else {
+        EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status());
+      }
+    }
+    ASSERT_NE(nullptr, mock_loader_->io_buffer());
+
+    if (!should_be_streaming) {
+      ASSERT_NE(nullptr, document_blocker_->local_buffer_.get());
+      EXPECT_EQ(mock_loader_->io_buffer()->data(),
+                document_blocker_->local_buffer_->data() + bytes_delivered)
+          << "Should have used a different IOBuffer for sniffing";
+    } else {
+      EXPECT_EQ(nullptr, document_blocker_->local_buffer_.get());
+      EXPECT_EQ(mock_loader_->io_buffer(), stream_sink_->buffer())
+          << "Should have used original IOBuffer when sniffing not needed";
+    }
+    // Deliver the next packet of the response body.
+    mock_loader_->OnReadCompleted(packet);
+    if (packet.empty() && (packets == scenario.verdict_packet) &&
+        (bytes_delivered > 0)) {
+      ASSERT_EQ(MockResourceLoader::Status::CALLBACK_PENDING,
+                mock_loader_->status());
+      // This case will result in CrossSiteDocumentResourceHandler having to
+      // synthesize an extra OnWillRead.
+      stream_sink_->set_defer_on_will_read(true);
+      stream_sink_->WaitUntilDeferred();
+      stream_sink_->Resume();
+      mock_loader_->WaitUntilIdleOrCanceled();
+    } else {
+      ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->status());
+    }
+
+    if (document_blocker_->blocked_read_completed_) {
+      EXPECT_EQ(Verdict::kBlock, scenario.verdict);
+      ASSERT_EQ(packets, std::max(0, scenario.verdict_packet));
+    }
+
+    bytes_delivered += packet.size();
+    packets++;
+
+    EXPECT_EQ(nullptr, mock_loader_->io_buffer());
   }
 
-  // Deliver the first chunk of the response body; this allows sniffing to
-  // occur.
-  ASSERT_EQ(MockResourceLoader::Status::IDLE,
-            mock_loader_->OnReadCompleted(scenario.first_chunk));
-  EXPECT_EQ(nullptr, mock_loader_->io_buffer());
-
   // Verify that the response is blocked or allowed as expected.
-  if (scenario.verdict == Verdict::kBlockWithoutSniffing ||
-      scenario.verdict == Verdict::kBlockAfterSniffing) {
+  if (scenario.verdict == Verdict::kBlock) {
     EXPECT_EQ("", stream_sink_body_)
         << "Response should not have been delivered to the renderer.";
+
     EXPECT_TRUE(document_blocker_->blocked_read_completed_);
     EXPECT_FALSE(document_blocker_->allow_based_on_sniffing_);
   } else {
-    EXPECT_EQ(scenario.first_chunk, stream_sink_body_)
+    // Make sure that the response was delivered.
+    EXPECT_EQ(scenario.data(), stream_sink_body_)
         << "Response should have been delivered to the renderer.";
     EXPECT_FALSE(document_blocker_->blocked_read_completed_);
-    if (scenario.verdict == Verdict::kAllowAfterSniffing)
-      EXPECT_TRUE(document_blocker_->allow_based_on_sniffing_);
+    EXPECT_EQ(expected_to_sniff, document_blocker_->allow_based_on_sniffing_);
   }
 }
 
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 7735f9e..a3b1844 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -413,6 +413,7 @@
   friend class ChildProcessLauncherBrowserTest_ChildSpawnFail_Test;
   friend class VisitRelayingRenderProcessHost;
   friend class StoragePartitonInterceptor;
+  friend class SecurityExploitBrowserTest;
   class ConnectionFilterController;
   class ConnectionFilterImpl;
 
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index cd00757..9d81c70 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -15,13 +15,14 @@
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
 #include "content/browser/frame_host/navigator.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/loader/resource_message_filter.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame.mojom.h"
 #include "content/common/frame_messages.h"
 #include "content/common/render_message_filter.mojom.h"
-#include "content/common/resource_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
@@ -36,10 +37,12 @@
 #include "content/public/common/file_chooser_params.h"
 #include "content/public/common/resource_request.h"
 #include "content/public/common/resource_request_body.h"
+#include "content/public/common/url_loader.mojom.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
+#include "content/public/test/test_url_loader_client.h"
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test_utils_internal.h"
@@ -59,9 +62,9 @@
 
 namespace {
 
-// This request id is used by tests that craft a
-// ResourceHostMsg_RequestResource. The id is sufficiently large that it doesn't
-// collide with ids used by previous navigation requests.
+// This request id is used by tests that call CreateLoaderAndStart. The id is
+// sufficiently large that it doesn't collide with ids used by previous
+// navigation requests.
 const int kRequestIdNotPreviouslyUsed = 10000;
 
 // This is a helper function for the tests which attempt to create a
@@ -144,40 +147,6 @@
   return request;
 }
 
-void TryCreateDuplicateRequestIds(Shell* shell, bool block_loaders) {
-  NavigateToURL(shell, GURL("http://foo.com/simple_page.html"));
-  RenderFrameHost* rfh = shell->web_contents()->GetMainFrame();
-
-  if (block_loaders) {
-    // Test the case where loaders are placed into blocked_loaders_map_.
-    rfh->BlockRequestsForFrame();
-  }
-
-  // URLRequestSlowDownloadJob waits for another request to kFinishDownloadUrl
-  // to finish all pending requests. It is never sent, so the following URL
-  // blocks indefinitely, which is good because the request stays alive and the
-  // test can try to reuse the request id without a race.
-  const char* blocking_url = net::URLRequestSlowDownloadJob::kUnknownSizeUrl;
-  ResourceRequest request(CreateXHRRequest(blocking_url));
-
-  // Use the same request id twice.
-  RenderProcessHostWatcher process_killed(
-      rfh->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-  IPC::IpcSecurityTestUtil::PwnMessageReceived(
-      rfh->GetProcess()->GetChannel(),
-      ResourceHostMsg_RequestResource(rfh->GetRoutingID(),
-                                      kRequestIdNotPreviouslyUsed, request,
-                                      net::MutableNetworkTrafficAnnotationTag(
-                                          TRAFFIC_ANNOTATION_FOR_TESTS)));
-  IPC::IpcSecurityTestUtil::PwnMessageReceived(
-      rfh->GetProcess()->GetChannel(),
-      ResourceHostMsg_RequestResource(rfh->GetRoutingID(),
-                                      kRequestIdNotPreviouslyUsed, request,
-                                      net::MutableNetworkTrafficAnnotationTag(
-                                          TRAFFIC_ANNOTATION_FOR_TESTS)));
-  process_killed.Wait();
-}
-
 }  // namespace
 
 // The goal of these tests will be to "simulate" exploited renderer processes,
@@ -216,6 +185,58 @@
         base::BindOnce(&net::URLRequestSlowDownloadJob::AddUrlHandler));
   }
 
+  static void CreateLoaderAndStartOnIOThread(
+      scoped_refptr<ResourceMessageFilter> filter,
+      int route_id,
+      int request_id,
+      const ResourceRequest& request) {
+    mojom::URLLoaderPtr loader;
+    TestURLLoaderClient client;
+    filter->CreateLoaderAndStart(
+        mojo::MakeRequest(&loader), route_id, request_id,
+        mojom::kURLLoadOptionNone, request, client.CreateInterfacePtr(),
+        net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+  }
+
+  static void CreateLoaderAndStart(RenderProcessHost* process,
+                                   int route_id,
+                                   int request_id,
+                                   const ResourceRequest& request) {
+    RenderProcessHostImpl* impl = static_cast<RenderProcessHostImpl*>(process);
+    auto filter = impl->resource_message_filter_;
+
+    process->GetChannel()->ipc_task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(CreateLoaderAndStartOnIOThread, filter,
+                                  route_id, request_id, request));
+  }
+
+  void TryCreateDuplicateRequestIds(Shell* shell, bool block_loaders) {
+    NavigateToURL(shell, GURL("http://foo.com/simple_page.html"));
+    RenderFrameHost* rfh = shell->web_contents()->GetMainFrame();
+
+    if (block_loaders) {
+      // Test the case where loaders are placed into blocked_loaders_map_.
+      rfh->BlockRequestsForFrame();
+    }
+
+    // URLRequestSlowDownloadJob waits for another request to kFinishDownloadUrl
+    // to finish all pending requests. It is never sent, so the following URL
+    // blocks indefinitely, which is good because the request stays alive and
+    // the test can try to reuse the request id without a race.
+    const char* blocking_url = net::URLRequestSlowDownloadJob::kUnknownSizeUrl;
+    ResourceRequest request(CreateXHRRequest(blocking_url));
+
+    // Use the same request id twice.
+    RenderProcessHostWatcher process_killed(
+        rfh->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+
+    CreateLoaderAndStart(rfh->GetProcess(), rfh->GetRoutingID(),
+                         kRequestIdNotPreviouslyUsed, request);
+    CreateLoaderAndStart(rfh->GetProcess(), rfh->GetRoutingID(),
+                         kRequestIdNotPreviouslyUsed, request);
+    process_killed.Wait();
+  }
+
  protected:
   // Tests that a given file path sent in a FrameHostMsg_RunFileChooser will
   // cause renderer to be killed.
@@ -448,13 +469,9 @@
     RenderProcessHostWatcher web_process_killed(
         web_rfh->GetProcess(),
         RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-    IPC::IpcSecurityTestUtil::PwnMessageReceived(
-        web_rfh->GetProcess()->GetChannel(),
-        ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
-                                        kRequestIdNotPreviouslyUsed,
-                                        chrome_origin_msg,
-                                        net::MutableNetworkTrafficAnnotationTag(
-                                            TRAFFIC_ANNOTATION_FOR_TESTS)));
+
+    CreateLoaderAndStart(web_rfh->GetProcess(), web_rfh->GetRoutingID(),
+                         kRequestIdNotPreviouslyUsed, chrome_origin_msg);
     web_process_killed.Wait();
   }
 
@@ -470,13 +487,9 @@
     RenderProcessHostWatcher web_process_killed(
         web_rfh->GetProcess(),
         RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-    IPC::IpcSecurityTestUtil::PwnMessageReceived(
-        web_rfh->GetProcess()->GetChannel(),
-        ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
-                                        kRequestIdNotPreviouslyUsed,
-                                        embedder_isolated_origin_msg,
-                                        net::MutableNetworkTrafficAnnotationTag(
-                                            TRAFFIC_ANNOTATION_FOR_TESTS)));
+    CreateLoaderAndStart(web_rfh->GetProcess(), web_rfh->GetRoutingID(),
+                         kRequestIdNotPreviouslyUsed,
+                         embedder_isolated_origin_msg);
     web_process_killed.Wait();
   }
 
@@ -486,13 +499,8 @@
     RenderProcessHostWatcher web_process_killed(
         web_rfh->GetProcess(),
         RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-    IPC::IpcSecurityTestUtil::PwnMessageReceived(
-        web_rfh->GetProcess()->GetChannel(),
-        ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
-                                        kRequestIdNotPreviouslyUsed,
-                                        invalid_origin_msg,
-                                        net::MutableNetworkTrafficAnnotationTag(
-                                            TRAFFIC_ANNOTATION_FOR_TESTS)));
+    CreateLoaderAndStart(web_rfh->GetProcess(), web_rfh->GetRoutingID(),
+                         kRequestIdNotPreviouslyUsed, invalid_origin_msg);
     web_process_killed.Wait();
   }
 
@@ -502,13 +510,9 @@
     RenderProcessHostWatcher web_process_killed(
         web_rfh->GetProcess(),
         RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-    IPC::IpcSecurityTestUtil::PwnMessageReceived(
-        web_rfh->GetProcess()->GetChannel(),
-        ResourceHostMsg_RequestResource(web_rfh->GetRoutingID(),
-                                        kRequestIdNotPreviouslyUsed,
-                                        invalid_scheme_origin_msg,
-                                        net::MutableNetworkTrafficAnnotationTag(
-                                            TRAFFIC_ANNOTATION_FOR_TESTS)));
+    CreateLoaderAndStart(web_rfh->GetProcess(), web_rfh->GetRoutingID(),
+                         kRequestIdNotPreviouslyUsed,
+                         invalid_scheme_origin_msg);
     web_process_killed.Wait();
   }
 }
diff --git a/content/common/cross_site_document_classifier.cc b/content/common/cross_site_document_classifier.cc
index 3518d84f..d676d7a9 100644
--- a/content/common/cross_site_document_classifier.cc
+++ b/content/common/cross_site_document_classifier.cc
@@ -34,21 +34,44 @@
 const char kTextXjson[] = "text/x-json";
 const char kTextPlain[] = "text/plain";
 
-bool MatchesSignature(StringPiece data,
-                      const StringPiece signatures[],
-                      size_t arr_size) {
-  size_t offset = data.find_first_not_of(" \t\r\n");
-  // There is no not-whitespace character in this document.
-  if (offset == base::StringPiece::npos)
-    return false;
-
-  data.remove_prefix(offset);
-  for (size_t sig_index = 0; sig_index < arr_size; ++sig_index) {
-    if (base::StartsWith(data, signatures[sig_index],
-                         base::CompareCase::INSENSITIVE_ASCII))
-      return true;
+void AdvancePastWhitespace(StringPiece* data) {
+  size_t offset = data->find_first_not_of(" \t\r\n");
+  if (offset == base::StringPiece::npos) {
+    // |data| was entirely whitespace.
+    data->clear();
+  } else {
+    data->remove_prefix(offset);
   }
-  return false;
+}
+
+// Returns kYes if |data| starts with one of the string patterns in
+// |signatures|, kMaybe if |data| is a prefix of one of the patterns in
+// |signatures|, and kNo otherwise.
+//
+// When kYes is returned, the matching prefix is erased from |data|.
+CrossSiteDocumentClassifier::Result MatchesSignature(
+    StringPiece* data,
+    const StringPiece signatures[],
+    size_t arr_size) {
+  for (size_t i = 0; i < arr_size; ++i) {
+    if (signatures[i].length() <= data->length()) {
+      if (base::StartsWith(*data, signatures[i],
+                           base::CompareCase::INSENSITIVE_ASCII)) {
+        // When |signatures[i]| is a prefix of |data|, it constitutes a match.
+        // Strip the matching characters, and return.
+        data->remove_prefix(signatures[i].length());
+        return CrossSiteDocumentClassifier::kYes;
+      }
+    } else {
+      if (base::StartsWith(signatures[i], *data,
+                           base::CompareCase::INSENSITIVE_ASCII)) {
+        // When |data| is a prefix of |signatures[i]|, that means that
+        // subsequent bytes in the stream could cause a match to occur.
+        return CrossSiteDocumentClassifier::kMaybe;
+      }
+    }
+  }
+  return CrossSiteDocumentClassifier::kNo;
 }
 
 }  // namespace
@@ -124,28 +147,23 @@
   if (access_control_origin == "*" || access_control_origin == "null")
     return true;
 
-  // TODO(dsjang): The CORS spec only treats a fully specified URL, except for
-  // "*", but many websites are using just a domain for access_control_origin,
-  // and this is blocked by Webkit's CORS logic here :
-  // CrossOriginAccessControl::passesAccessControlCheck(). GURL is set
-  // is_valid() to false when it is created from a URL containing * in the
-  // domain part.
-
-  GURL cors_origin(access_control_origin);
-  return IsSameSite(frame_origin, cors_origin);
+  return IsSameSite(frame_origin, GURL(access_control_origin));
 }
 
 // This function is a slight modification of |net::SniffForHTML|.
-bool CrossSiteDocumentClassifier::SniffForHTML(StringPiece data) {
-  // The content sniffer used by Chrome and Firefox are using "<!--"
-  // as one of the HTML signatures, but it also appears in valid
-  // JavaScript, considered as well-formed JS by the browser.  Since
-  // we do not want to block any JS, we exclude it from our HTML
-  // signatures. This can weaken our document block policy, but we can
-  // break less websites.
-  // TODO(dsjang): parameterize |net::SniffForHTML| with an option
-  // that decides whether to include <!-- or not, so that we can
-  // remove this function.
+CrossSiteDocumentClassifier::Result CrossSiteDocumentClassifier::SniffForHTML(
+    StringPiece data) {
+  // The content sniffers used by Chrome and Firefox are using "<!--" as one of
+  // the HTML signatures, but it also appears in valid JavaScript, considered as
+  // well-formed JS by the browser.  Since we do not want to block any JS, we
+  // exclude it from our HTML signatures. This can weaken our document block
+  // policy, but we can break less websites.
+  //
+  // Note that <body> and <br> are not included below, since <b is a prefix of
+  // them.
+  //
+  // TODO(dsjang): parameterize |net::SniffForHTML| with an option that decides
+  // whether to include <!-- or not, so that we can remove this function.
   // TODO(dsjang): Once CrossSiteDocumentClassifier is moved into the browser
   // process, we should do single-thread checking here for the static
   // initializer.
@@ -162,36 +180,40 @@
       StringPiece("<a"),              // Mozilla
       StringPiece("<style"),          // Mozilla
       StringPiece("<title"),          // Mozilla
-      StringPiece("<b"),              // Mozilla
-      StringPiece("<body"),           // Mozilla
-      StringPiece("<br"),             // Mozilla
+      StringPiece("<b"),              // Mozilla (note: subsumes <body>, <br>)
       StringPiece("<p")               // Mozilla
   };
 
   while (data.length() > 0) {
-    if (MatchesSignature(data, kHtmlSignatures, arraysize(kHtmlSignatures)))
-      return true;
+    AdvancePastWhitespace(&data);
 
-    // If we cannot find "<!--", we fail sniffing this as HTML.
-    static const StringPiece kCommentBegins[] = {StringPiece("<!--")};
-    if (!MatchesSignature(data, kCommentBegins, arraysize(kCommentBegins)))
-      break;
+    Result signature_match =
+        MatchesSignature(&data, kHtmlSignatures, arraysize(kHtmlSignatures));
+    if (signature_match != kNo)
+      return signature_match;
 
-    // Search for --> and do SniffForHTML after that. If we can find the
-    // comment's end, we start HTML sniffing from there again.
-    static const char kEndComment[] = "-->";
-    size_t offset = data.find(kEndComment);
-    if (offset == base::StringPiece::npos)
-      break;
+    // "<!--" (the HTML comment syntax) is a special case, since it's valid JS
+    // as well. Skip over them.
+    static const StringPiece kBeginCommentSignature[] = {"<!--"};
+    Result comment_match = MatchesSignature(&data, kBeginCommentSignature,
+                                            arraysize(kBeginCommentSignature));
+    if (comment_match != kYes)
+      return comment_match;
 
-    // Proceed to the index next to the ending comment (-->).
-    data.remove_prefix(offset + strlen(kEndComment));
+    // Look for an end comment.
+    static const StringPiece kEndComment = "-->";
+    size_t comment_end = data.find(kEndComment);
+    if (comment_end == base::StringPiece::npos)
+      return kMaybe;  // Hit end of data with open comment.
+    data.remove_prefix(comment_end + kEndComment.length());
   }
 
-  return false;
+  // All of |data| was consumed, without a clear determination.
+  return kMaybe;
 }
 
-bool CrossSiteDocumentClassifier::SniffForXML(base::StringPiece data) {
+CrossSiteDocumentClassifier::Result CrossSiteDocumentClassifier::SniffForXML(
+    base::StringPiece data) {
   // TODO(dsjang): Chrome's mime_sniffer is using strncasecmp() for
   // this signature. However, XML is case-sensitive. Don't we have to
   // be more lenient only to block documents starting with the exact
@@ -199,27 +221,30 @@
   // TODO(dsjang): Once CrossSiteDocumentClassifier is moved into the browser
   // process, we should do single-thread checking here for the static
   // initializer.
+  AdvancePastWhitespace(&data);
   static const StringPiece kXmlSignatures[] = {StringPiece("<?xml")};
-  return MatchesSignature(data, kXmlSignatures, arraysize(kXmlSignatures));
+  return MatchesSignature(&data, kXmlSignatures, arraysize(kXmlSignatures));
 }
 
-bool CrossSiteDocumentClassifier::SniffForJSON(base::StringPiece data) {
-  // TODO(dsjang): We have to come up with a better way to sniff
-  // JSON. However, even RE cannot help us that much due to the fact
-  // that we don't do full parsing.  This DFA starts with state 0, and
-  // finds {, "/' and : in that order. We're avoiding adding a
-  // dependency on a regular expression library.
+CrossSiteDocumentClassifier::Result CrossSiteDocumentClassifier::SniffForJSON(
+    base::StringPiece data) {
+  // Currently this function just looks for '{', '"', and ':', in that order.
+  //
+  // TODO(nick): We have to come up with a better way to sniff JSON. The
+  // following are known limitations of this function:
+  // https://crbug.com/795467/ Don't allow single quotes.
+  // https://crbug.com/795465/ Fully parse the string literals.
+  // https://crbug.com/795470/ Support non-dictionary values (e.g. lists)
+  // https://crbug.com/795476/ Support parser-breaker prefixes.
   enum {
     kStartState,
     kLeftBraceState,
     kLeftQuoteState,
-    kColonState,
-    kTerminalState,
   } state = kStartState;
 
-  size_t length = data.length();
-  for (size_t i = 0; i < length && state < kColonState; ++i) {
+  for (size_t i = 0; i < data.length(); ++i) {
     const char c = data[i];
+    // Whitespace is ignored (outside of string literals)
     if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
       continue;
 
@@ -228,25 +253,21 @@
         if (c == '{')
           state = kLeftBraceState;
         else
-          state = kTerminalState;
+          return kNo;
         break;
       case kLeftBraceState:
-        if (c == '\"' || c == '\'')
+        if (c == '"' || c == '\'')
           state = kLeftQuoteState;
         else
-          state = kTerminalState;
+          return kNo;
         break;
       case kLeftQuoteState:
         if (c == ':')
-          state = kColonState;
-        break;
-      case kColonState:
-      case kTerminalState:
-        NOTREACHED();
+          return kYes;
         break;
     }
   }
-  return state == kColonState;
+  return kMaybe;
 }
 
 }  // namespace content
diff --git a/content/common/cross_site_document_classifier.h b/content/common/cross_site_document_classifier.h
index 5c9bafe2..de0c6a6 100644
--- a/content/common/cross_site_document_classifier.h
+++ b/content/common/cross_site_document_classifier.h
@@ -30,6 +30,19 @@
 
 class CONTENT_EXPORT CrossSiteDocumentClassifier {
  public:
+  // Three conclusions are possible from sniffing a byte sequence:
+  //  - No: meaning that the data definitively doesn't match the indicated type.
+  //  - Yes: meaning that the data definitive does match the indicated type.
+  //  - Maybe: meaning that if more bytes are appended to the stream, it's
+  //    possible to get a Yes result. For example, if we are sniffing for a tag
+  //    like "<html", a kMaybe result would occur if the data contains just
+  //    "<ht".
+  enum Result {
+    kNo,
+    kMaybe,
+    kYes,
+  };
+
   // Returns the representative mime type enum value of the mime type of
   // response. For example, this returns the same value for all text/xml mime
   // type families such as application/xml, application/rss+xml.
@@ -56,9 +69,9 @@
                                    const GURL& website_origin,
                                    const std::string& access_control_origin);
 
-  static bool SniffForHTML(base::StringPiece data);
-  static bool SniffForXML(base::StringPiece data);
-  static bool SniffForJSON(base::StringPiece data);
+  static Result SniffForHTML(base::StringPiece data);
+  static Result SniffForXML(base::StringPiece data);
+  static Result SniffForJSON(base::StringPiece data);
 
  private:
   CrossSiteDocumentClassifier();  // Not instantiable.
diff --git a/content/common/cross_site_document_classifier_unittest.cc b/content/common/cross_site_document_classifier_unittest.cc
index 18ae2db..fcb36f74 100644
--- a/content/common/cross_site_document_classifier_unittest.cc
+++ b/content/common/cross_site_document_classifier_unittest.cc
@@ -7,6 +7,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::StringPiece;
+using Result = content::CrossSiteDocumentClassifier::Result;
 
 namespace content {
 
@@ -78,23 +79,36 @@
   StringPiece comment_html_data(" <!-- this is comment --> <html><body>");
   StringPiece two_comments_html_data(
       "<!-- this is comment -->\n<!-- this is comment --><html><body>");
+  StringPiece commented_out_html_tag_data("<!-- <html> <?xml> \n<html>--><b");
   StringPiece mixed_comments_html_data(
       "<!-- this is comment <!-- --> <script></script>");
   StringPiece non_html_data("        var name=window.location;\nadfadf");
-  StringPiece comment_js_data(" <!-- this is comment -> document.write(1); ");
+  StringPiece comment_js_data(
+      " <!-- this is comment\n document.write(1);\n// -->window.open()");
   StringPiece empty_data("");
 
-  EXPECT_TRUE(CrossSiteDocumentClassifier::SniffForHTML(html_data));
-  EXPECT_TRUE(CrossSiteDocumentClassifier::SniffForHTML(comment_html_data));
-  EXPECT_TRUE(
-      CrossSiteDocumentClassifier::SniffForHTML(two_comments_html_data));
-  EXPECT_TRUE(
-      CrossSiteDocumentClassifier::SniffForHTML(mixed_comments_html_data));
-  EXPECT_FALSE(CrossSiteDocumentClassifier::SniffForHTML(non_html_data));
-  EXPECT_FALSE(CrossSiteDocumentClassifier::SniffForHTML(comment_js_data));
+  EXPECT_EQ(Result::kYes, CrossSiteDocumentClassifier::SniffForHTML(html_data));
+  EXPECT_EQ(Result::kYes,
+            CrossSiteDocumentClassifier::SniffForHTML(comment_html_data));
+  EXPECT_EQ(Result::kYes,
+            CrossSiteDocumentClassifier::SniffForHTML(two_comments_html_data));
+  EXPECT_EQ(Result::kYes, CrossSiteDocumentClassifier::SniffForHTML(
+                              commented_out_html_tag_data));
+  EXPECT_EQ(Result::kYes, CrossSiteDocumentClassifier::SniffForHTML(
+                              mixed_comments_html_data));
+  EXPECT_EQ(Result::kNo,
+            CrossSiteDocumentClassifier::SniffForHTML(non_html_data));
+  EXPECT_EQ(Result::kNo,
+            CrossSiteDocumentClassifier::SniffForHTML(comment_js_data));
 
-  // Basic bounds check.
-  EXPECT_FALSE(CrossSiteDocumentClassifier::SniffForHTML(empty_data));
+  // Prefixes of |commented_out_html_tag_data| should be indeterminate.
+  StringPiece almost_html = commented_out_html_tag_data;
+  while (!almost_html.empty()) {
+    almost_html.remove_suffix(1);
+    EXPECT_EQ(Result::kMaybe,
+              CrossSiteDocumentClassifier::SniffForHTML(almost_html))
+        << almost_html;
+  }
 }
 
 TEST(CrossSiteDocumentClassifierTest, SniffForXML) {
@@ -102,25 +116,44 @@
   StringPiece non_xml_data("        var name=window.location;\nadfadf");
   StringPiece empty_data("");
 
-  EXPECT_TRUE(CrossSiteDocumentClassifier::SniffForXML(xml_data));
-  EXPECT_FALSE(CrossSiteDocumentClassifier::SniffForXML(non_xml_data));
+  EXPECT_EQ(Result::kYes, CrossSiteDocumentClassifier::SniffForXML(xml_data));
+  EXPECT_EQ(Result::kNo,
+            CrossSiteDocumentClassifier::SniffForXML(non_xml_data));
 
-  // Basic bounds check.
-  EXPECT_FALSE(CrossSiteDocumentClassifier::SniffForXML(empty_data));
+  // Empty string should be indeterminate.
+  EXPECT_EQ(Result::kMaybe,
+            CrossSiteDocumentClassifier::SniffForXML(empty_data));
 }
 
 TEST(CrossSiteDocumentClassifierTest, SniffForJSON) {
   StringPiece json_data("\t\t\r\n   { \"name\" : \"chrome\", ");
+  StringPiece json_corrupt_after_first_key(
+      "\t\t\r\n   { \"name\" :^^^^!!@#\1\", ");
+  StringPiece json_data2("{ \"key   \\\"  \"          \t\t\r\n:");
   StringPiece non_json_data0("\t\t\r\n   { name : \"chrome\", ");
   StringPiece non_json_data1("\t\t\r\n   foo({ \"name\" : \"chrome\", ");
   StringPiece empty_data("");
 
-  EXPECT_TRUE(CrossSiteDocumentClassifier::SniffForJSON(json_data));
-  EXPECT_FALSE(CrossSiteDocumentClassifier::SniffForJSON(non_json_data0));
-  EXPECT_FALSE(CrossSiteDocumentClassifier::SniffForJSON(non_json_data1));
+  EXPECT_EQ(Result::kYes, CrossSiteDocumentClassifier::SniffForJSON(json_data));
+  EXPECT_EQ(Result::kYes, CrossSiteDocumentClassifier::SniffForJSON(
+                              json_corrupt_after_first_key));
 
-  // Basic bounds check.
-  EXPECT_FALSE(CrossSiteDocumentClassifier::SniffForJSON(empty_data));
+  EXPECT_EQ(Result::kYes,
+            CrossSiteDocumentClassifier::SniffForJSON(json_data2));
+
+  // All prefixes prefixes of |json_data2| ought to be indeterminate.
+  StringPiece almost_json = json_data2;
+  while (!almost_json.empty()) {
+    almost_json.remove_suffix(1);
+    EXPECT_EQ(Result::kMaybe,
+              CrossSiteDocumentClassifier::SniffForJSON(almost_json))
+        << almost_json;
+  }
+
+  EXPECT_EQ(Result::kNo,
+            CrossSiteDocumentClassifier::SniffForJSON(non_json_data0));
+  EXPECT_EQ(Result::kNo,
+            CrossSiteDocumentClassifier::SniffForJSON(non_json_data1));
 }
 
 }  // namespace content
diff --git a/content/common/fileapi/file_system_messages.h b/content/common/fileapi/file_system_messages.h
index db4d87b3..dfd43e63 100644
--- a/content/common/fileapi/file_system_messages.h
+++ b/content/common/fileapi/file_system_messages.h
@@ -14,7 +14,7 @@
 #include "storage/common/fileapi/directory_entry.h"
 #include "storage/common/fileapi/file_system_info.h"
 #include "storage/common/fileapi/file_system_types.h"
-#include "storage/common/quota/quota_types.h"
+#include "storage/common/quota/quota_limit_type.h"
 #include "url/gurl.h"
 
 #undef IPC_MESSAGE_EXPORT
diff --git a/content/renderer/device_sensors/device_motion_event_pump_unittest.cc b/content/renderer/device_sensors/device_motion_event_pump_unittest.cc
index a56aec09..e01146a 100644
--- a/content/renderer/device_sensors/device_motion_event_pump_unittest.cc
+++ b/content/renderer/device_sensors/device_motion_event_pump_unittest.cc
@@ -28,6 +28,7 @@
 #include "services/device/public/interfaces/sensor_provider.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceMotionListener.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 namespace {
 
@@ -353,7 +354,7 @@
   motion_pump()->set_stop_on_fire_event(false);
   motion_pump()->StartFireEvent();
 
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+  blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostDelayedTask(
       FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
       base::TimeDelta::FromMilliseconds(100));
   base::RunLoop().Run();
diff --git a/content/renderer/device_sensors/device_orientation_event_pump_unittest.cc b/content/renderer/device_sensors/device_orientation_event_pump_unittest.cc
index 129e874..d5fcce55 100644
--- a/content/renderer/device_sensors/device_orientation_event_pump_unittest.cc
+++ b/content/renderer/device_sensors/device_orientation_event_pump_unittest.cc
@@ -25,6 +25,7 @@
 #include "services/device/public/interfaces/sensor_provider.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationListener.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 namespace {
 
@@ -378,7 +379,7 @@
       2 /* beta */, 3 /* gamma */);
   listener()->set_did_change_device_orientation(false);
 
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
+  blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
       FROM_HERE,
       base::BindOnce(&DeviceOrientationEventPumpForTesting::StartFireEvent,
                      base::Unretained(orientation_pump())));
@@ -405,7 +406,7 @@
       2 /* beta */, 3 /* gamma */);
   listener()->set_did_change_device_orientation(false);
 
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
+  blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
       FROM_HERE,
       base::BindOnce(&DeviceOrientationEventPumpForTesting::StartFireEvent,
                      base::Unretained(orientation_pump())));
diff --git a/content/renderer/fileapi/file_system_dispatcher.h b/content/renderer/fileapi/file_system_dispatcher.h
index 88e9378c..39ac857 100644
--- a/content/renderer/fileapi/file_system_dispatcher.h
+++ b/content/renderer/fileapi/file_system_dispatcher.h
@@ -17,7 +17,7 @@
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_platform_file.h"
 #include "storage/common/fileapi/file_system_types.h"
-#include "storage/common/quota/quota_types.h"
+#include "storage/common/quota/quota_limit_type.h"
 
 namespace base {
 class FilePath;
diff --git a/content/renderer/gpu/render_widget_compositor_unittest.cc b/content/renderer/gpu/render_widget_compositor_unittest.cc
index 9ac77a98..457e8ef 100644
--- a/content/renderer/gpu/render_widget_compositor_unittest.cc
+++ b/content/renderer/gpu/render_widget_compositor_unittest.cc
@@ -27,6 +27,7 @@
 #include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 using testing::AllOf;
 using testing::Field;
@@ -182,7 +183,7 @@
     } else {
       // Post the synchronous composite task so that it is not called
       // reentrantly as a part of RequestNewLayerTreeFrameSink.
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
           FROM_HERE,
           base::BindOnce(&RenderWidgetLayerTreeFrameSink::SynchronousComposite,
                          base::Unretained(this)));
@@ -273,7 +274,7 @@
     render_widget_compositor_.SetUp(expected_successes, kTries, failure_mode,
                                     &run_loop);
     render_widget_compositor_.SetVisible(true);
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
         FROM_HERE,
         base::BindOnce(&RenderWidgetLayerTreeFrameSink::SynchronousComposite,
                        base::Unretained(&render_widget_compositor_)));
diff --git a/content/renderer/indexed_db/webidbcursor_impl_unittest.cc b/content/renderer/indexed_db/webidbcursor_impl_unittest.cc
index fcce315a..fa4f4916 100644
--- a/content/renderer/indexed_db/webidbcursor_impl_unittest.cc
+++ b/content/renderer/indexed_db/webidbcursor_impl_unittest.cc
@@ -22,6 +22,7 @@
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebData.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 using blink::WebBlobInfo;
 using blink::WebData;
@@ -125,7 +126,8 @@
     mock_cursor_ = std::make_unique<MockCursorImpl>(
         mojo::MakeRequestAssociatedWithDedicatedPipe(&ptr));
     cursor_ = std::make_unique<WebIDBCursorImpl>(
-        ptr.PassInterface(), 1, base::ThreadTaskRunnerHandle::Get());
+        ptr.PassInterface(), 1,
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting());
   }
 
  protected:
diff --git a/content/renderer/indexed_db/webidbdatabase_impl_unittest.cc b/content/renderer/indexed_db/webidbdatabase_impl_unittest.cc
index 016c384..9dd9597c 100644
--- a/content/renderer/indexed_db/webidbdatabase_impl_unittest.cc
+++ b/content/renderer/indexed_db/webidbdatabase_impl_unittest.cc
@@ -17,6 +17,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebBlobInfo.h"
 #include "third_party/WebKit/public/platform/WebData.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 
 using blink::WebBlobInfo;
@@ -58,8 +59,8 @@
   StrictMock<MockWebIDBCallbacks> callbacks;
   EXPECT_CALL(callbacks, OnError(_)).Times(1);
 
-  WebIDBDatabaseImpl database_impl(nullptr,
-                                   base::ThreadTaskRunnerHandle::Get());
+  WebIDBDatabaseImpl database_impl(
+      nullptr, blink::scheduler::GetSingleThreadTaskRunnerForTesting());
   database_impl.max_put_value_size_ = kMaxValueSizeForTesting;
   database_impl.Put(transaction_id, object_store_id, value, web_blob_info,
                     WebIDBKey::CreateNumber(0),
@@ -85,8 +86,8 @@
   StrictMock<MockWebIDBCallbacks> callbacks;
   EXPECT_CALL(callbacks, OnError(_)).Times(1);
 
-  WebIDBDatabaseImpl database_impl(nullptr,
-                                   base::ThreadTaskRunnerHandle::Get());
+  WebIDBDatabaseImpl database_impl(
+      nullptr, blink::scheduler::GetSingleThreadTaskRunnerForTesting());
   database_impl.max_put_value_size_ = kMaxValueSizeForTesting;
   database_impl.Put(transaction_id, object_store_id, value, web_blob_info, key,
                     blink::kWebIDBPutModeAddOrUpdate, &callbacks,
diff --git a/content/renderer/loader/shared_memory_data_consumer_handle_unittest.cc b/content/renderer/loader/shared_memory_data_consumer_handle_unittest.cc
index fe6d2cdf..9a8f620 100644
--- a/content/renderer/loader/shared_memory_data_consumer_handle_unittest.cc
+++ b/content/renderer/loader/shared_memory_data_consumer_handle_unittest.cc
@@ -26,6 +26,7 @@
 #include "content/public/renderer/fixed_received_data.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 namespace content {
 
@@ -208,8 +209,8 @@
 
 void RunPostedTasks() {
   base::RunLoop run_loop;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                run_loop.QuitClosure());
+  blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
+      FROM_HERE, run_loop.QuitClosure());
   run_loop.Run();
 }
 
diff --git a/content/renderer/loader/site_isolation_stats_gatherer.cc b/content/renderer/loader/site_isolation_stats_gatherer.cc
index 49fce4e..1571532 100644
--- a/content/renderer/loader/site_isolation_stats_gatherer.cc
+++ b/content/renderer/loader/site_isolation_stats_gatherer.cc
@@ -22,6 +22,10 @@
 // only activated in renderer processes.
 static bool g_stats_gathering_enabled = false;
 
+bool IsYes(CrossSiteDocumentClassifier::Result result) {
+  return result == CrossSiteDocumentClassifier::Result::kYes;
+}
+
 bool IsRenderableStatusCode(int status_code) {
   // Chrome only uses the content of a response with one of these status codes
   // for CSS/JavaScript. For images, Chrome just ignores status code.
@@ -190,17 +194,17 @@
     if (resp_data->canonical_mime_type == CROSS_SITE_DOCUMENT_MIME_TYPE_HTML) {
       bucket_prefix = "SiteIsolation.XSD.HTML";
       sniffed_as_target_document =
-          CrossSiteDocumentClassifier::SniffForHTML(data);
+          IsYes(CrossSiteDocumentClassifier::SniffForHTML(data));
     } else if (resp_data->canonical_mime_type ==
                CROSS_SITE_DOCUMENT_MIME_TYPE_XML) {
       bucket_prefix = "SiteIsolation.XSD.XML";
       sniffed_as_target_document =
-          CrossSiteDocumentClassifier::SniffForXML(data);
+          IsYes(CrossSiteDocumentClassifier::SniffForXML(data));
     } else if (resp_data->canonical_mime_type ==
                CROSS_SITE_DOCUMENT_MIME_TYPE_JSON) {
       bucket_prefix = "SiteIsolation.XSD.JSON";
       sniffed_as_target_document =
-          CrossSiteDocumentClassifier::SniffForJSON(data);
+          IsYes(CrossSiteDocumentClassifier::SniffForJSON(data));
     } else {
       NOTREACHED() << "Not a blockable mime type: "
                    << resp_data->canonical_mime_type;
@@ -222,11 +226,11 @@
     // and JSON sniffer to a text document in the order, and block it
     // if any of them succeeds in sniffing.
     std::string bucket_prefix;
-    if (CrossSiteDocumentClassifier::SniffForHTML(data))
+    if (IsYes(CrossSiteDocumentClassifier::SniffForHTML(data)))
       bucket_prefix = "SiteIsolation.XSD.Plain.HTML";
-    else if (CrossSiteDocumentClassifier::SniffForXML(data))
+    else if (IsYes(CrossSiteDocumentClassifier::SniffForXML(data)))
       bucket_prefix = "SiteIsolation.XSD.Plain.XML";
-    else if (CrossSiteDocumentClassifier::SniffForJSON(data))
+    else if (IsYes(CrossSiteDocumentClassifier::SniffForJSON(data)))
       bucket_prefix = "SiteIsolation.XSD.Plain.JSON";
 
     if (bucket_prefix.size() > 0) {
diff --git a/content/renderer/loader/url_loader_client_impl.cc b/content/renderer/loader/url_loader_client_impl.cc
index e2d628e..5d756db 100644
--- a/content/renderer/loader/url_loader_client_impl.cc
+++ b/content/renderer/loader/url_loader_client_impl.cc
@@ -83,7 +83,7 @@
       : current_(current), total_(total) {}
 
   void HandleMessage(ResourceDispatcher* dispatcher, int request_id) override {
-    dispatcher->OnDownloadedData(request_id, current_, total_);
+    dispatcher->OnUploadProgress(request_id, current_, total_);
   }
   bool IsCompletionMessage() const override { return false; }
 
diff --git a/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc b/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc
index 5faab10..4d774e4 100644
--- a/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc
+++ b/content/renderer/loader/web_data_consumer_handle_impl_unittest.cc
@@ -23,6 +23,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 namespace content {
 
@@ -50,7 +51,7 @@
       : operation_(operation) {}
 
   void DidGetReadable() override {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
         FROM_HERE, base::BindOnce(&ReadDataOperationBase::ReadMore,
                                   base::Unretained(operation_)));
   }
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc
index 7d8f6ba..56f2b34 100644
--- a/content/renderer/loader/web_url_loader_impl_unittest.cc
+++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -42,6 +42,7 @@
 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -161,9 +162,10 @@
 class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
  public:
   TestWebURLLoaderClient(ResourceDispatcher* dispatcher)
-      : loader_(new WebURLLoaderImpl(dispatcher,
-                                     base::ThreadTaskRunnerHandle::Get(),
-                                     &fake_url_loader_factory_)),
+      : loader_(new WebURLLoaderImpl(
+            dispatcher,
+            blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
+            &fake_url_loader_factory_)),
         delete_on_receive_redirect_(false),
         delete_on_receive_response_(false),
         delete_on_receive_data_(false),
diff --git a/content/renderer/media/android/stream_texture_wrapper_impl_unittest.cc b/content/renderer/media/android/stream_texture_wrapper_impl_unittest.cc
index 195379db..51f9e45 100644
--- a/content/renderer/media/android/stream_texture_wrapper_impl_unittest.cc
+++ b/content/renderer/media/android/stream_texture_wrapper_impl_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 namespace content {
 
@@ -15,7 +16,7 @@
  public:
   StreamTextureWrapperImplTest() {}
 
-  // Necessary, or else base::ThreadTaskRunnerHandle::Get() fails.
+  // Necessary, or else GetSingleThreadTaskRunnerForTesting() fails.
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 
  private:
@@ -26,8 +27,9 @@
 // be destroyed via StreamTextureWrapper::Deleter.
 TEST_F(StreamTextureWrapperImplTest, ConstructionDestruction_ShouldSucceed) {
   media::ScopedStreamTextureWrapper stream_texture_wrapper =
-      StreamTextureWrapperImpl::Create(false, nullptr,
-                                       base::ThreadTaskRunnerHandle::Get());
+      StreamTextureWrapperImpl::Create(
+          false, nullptr,
+          blink::scheduler::GetSingleThreadTaskRunnerForTesting());
 }
 
 }  // Content
diff --git a/content/renderer/media/gpu/rtc_video_decoder_unittest.cc b/content/renderer/media/gpu/rtc_video_decoder_unittest.cc
index 7b821e6..1f0a97e 100644
--- a/content/renderer/media/gpu/rtc_video_decoder_unittest.cc
+++ b/content/renderer/media/gpu/rtc_video_decoder_unittest.cc
@@ -16,6 +16,7 @@
 #include "media/video/mock_gpu_video_accelerator_factories.h"
 #include "media/video/mock_video_decode_accelerator.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 #if defined(OS_WIN)
 #include "base/command_line.h"
@@ -99,7 +100,8 @@
 
   int32_t Decoded(webrtc::VideoFrame& decoded_image) override {
     DVLOG(2) << "Decoded";
-    EXPECT_EQ(vda_task_runner_, base::ThreadTaskRunnerHandle::Get());
+    EXPECT_EQ(vda_task_runner_,
+              blink::scheduler::GetSingleThreadTaskRunnerForTesting());
     return WEBRTC_VIDEO_CODEC_OK;
   }
 
diff --git a/content/renderer/media/media_stream_audio_processor_unittest.cc b/content/renderer/media/media_stream_audio_processor_unittest.cc
index d302a53..cd4e7f50 100644
--- a/content/renderer/media/media_stream_audio_processor_unittest.cc
+++ b/content/renderer/media/media_stream_audio_processor_unittest.cc
@@ -28,6 +28,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/webrtc/api/mediastreaminterface.h"
 #include "third_party/webrtc/rtc_base/refcountedobject.h"
 
@@ -309,8 +310,9 @@
 // filter will be created.
 TEST_F(MediaStreamAudioProcessorTest, GetAecDumpMessageFilter) {
   scoped_refptr<AecDumpMessageFilter> aec_dump_message_filter_(
-      new AecDumpMessageFilter(base::ThreadTaskRunnerHandle::Get(),
-                               base::ThreadTaskRunnerHandle::Get()));
+      new AecDumpMessageFilter(
+          blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
+          blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
 
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
       new rtc::RefCountedObject<WebRtcAudioDeviceImpl>());
diff --git a/content/renderer/media/media_stream_video_capturer_source_unittest.cc b/content/renderer/media/media_stream_video_capturer_source_unittest.cc
index c79a9f7..c754679 100644
--- a/content/renderer/media/media_stream_video_capturer_source_unittest.cc
+++ b/content/renderer/media/media_stream_video_capturer_source_unittest.cc
@@ -18,6 +18,7 @@
 #include "media/base/bind_to_current_loop.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 
 using ::testing::_;
@@ -51,7 +52,7 @@
     SetRunning(false);
   }
   void SetRunning(bool is_running) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
+    blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
         FROM_HERE, base::Bind(running_cb_, is_running));
   }
   const media::VideoCaptureParams& capture_params() const {
diff --git a/content/renderer/media/peer_connection_tracker_unittest.cc b/content/renderer/media/peer_connection_tracker_unittest.cc
index da3b215..021c78b 100644
--- a/content/renderer/media/peer_connection_tracker_unittest.cc
+++ b/content/renderer/media/peer_connection_tracker_unittest.cc
@@ -15,6 +15,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
 #include "third_party/WebKit/public/platform/WebRTCOfferOptions.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 using ::testing::_;
 
@@ -46,9 +47,10 @@
 class MockPeerConnectionHandler : public RTCPeerConnectionHandler {
  public:
   MockPeerConnectionHandler()
-      : RTCPeerConnectionHandler(&client_,
-                                 &dependency_factory_,
-                                 base::ThreadTaskRunnerHandle::Get()) {}
+      : RTCPeerConnectionHandler(
+            &client_,
+            &dependency_factory_,
+            blink::scheduler::GetSingleThreadTaskRunnerForTesting()) {}
   MOCK_METHOD0(CloseClientPeerConnection, void());
 
  private:
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
index a22486e..8137066c 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -49,6 +49,9 @@
   // consider all pre-KitKat devices to be potentially buggy.
   is_jelly_bean_ |= base::android::BuildInfo::GetInstance()->sdk_int() <= 18;
 #endif
+
+  idle_cleanup_timer_.SetTaskRunner(
+      render_frame->GetTaskRunner(blink::TaskType::kUnthrottled));
 }
 
 RendererWebMediaPlayerDelegate::~RendererWebMediaPlayerDelegate() {}
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
index 2eae16d..f5d3145 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
@@ -19,6 +19,7 @@
 #include "content/renderer/render_process.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 using testing::NiceMock;
 using testing::Return;
@@ -92,8 +93,8 @@
 
   void RunLoopOnce() {
     base::RunLoop run_loop;
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  run_loop.QuitClosure());
+    blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
+        FROM_HERE, run_loop.QuitClosure());
     run_loop.Run();
   }
 
diff --git a/content/renderer/media/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
index 42f23e0a..d62f3cc 100644
--- a/content/renderer/media/rtc_peer_connection_handler_unittest.cc
+++ b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
@@ -54,6 +54,7 @@
 #include "third_party/WebKit/public/platform/WebRTCStatsRequest.h"
 #include "third_party/WebKit/public/platform/WebRTCVoidRequest.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 #include "third_party/webrtc/api/peerconnectioninterface.h"
 #include "third_party/webrtc/api/rtpreceiverinterface.h"
@@ -211,7 +212,8 @@
  public:
   explicit MockRTCStatsReportCallback(
       std::unique_ptr<blink::WebRTCStatsReport>* result)
-      : main_thread_(base::ThreadTaskRunnerHandle::Get()), result_(result) {
+      : main_thread_(blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
+        result_(result) {
     DCHECK(result_);
   }
 
@@ -245,9 +247,10 @@
   RTCPeerConnectionHandlerUnderTest(
       WebRTCPeerConnectionHandlerClient* client,
       PeerConnectionDependencyFactory* dependency_factory)
-      : RTCPeerConnectionHandler(client,
-                                 dependency_factory,
-                                 base::ThreadTaskRunnerHandle::Get()) {}
+      : RTCPeerConnectionHandler(
+            client,
+            dependency_factory,
+            blink::scheduler::GetSingleThreadTaskRunnerForTesting()) {}
 
   MockPeerConnectionImpl* native_peer_connection() {
     return static_cast<MockPeerConnectionImpl*>(
diff --git a/content/renderer/media/user_media_client_impl_unittest.cc b/content/renderer/media/user_media_client_impl_unittest.cc
index dfb657f6..5b3560de6 100644
--- a/content/renderer/media/user_media_client_impl_unittest.cc
+++ b/content/renderer/media/user_media_client_impl_unittest.cc
@@ -35,6 +35,7 @@
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 
 using testing::_;
@@ -363,7 +364,7 @@
 
     if (!create_source_that_fails_) {
       // RunUntilIdle is required for this task to complete.
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
+      blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
           FROM_HERE,
           base::BindOnce(&UserMediaProcessorUnderTest::SignalSourceReady,
                          source_ready, source));
diff --git a/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc b/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc
index 498ca20..9694e426 100644
--- a/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc
+++ b/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc
@@ -19,6 +19,7 @@
 #include "content/renderer/media/webrtc/track_observer.h"
 #include "media/base/video_frame.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 #include "third_party/webrtc/api/video/i420_buffer.h"
 
@@ -52,7 +53,7 @@
 
   void SetUp() override {
     scoped_refptr<base::SingleThreadTaskRunner> main_thread =
-        base::ThreadTaskRunnerHandle::Get();
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting();
 
     base::WaitableEvent waitable_event(
         base::WaitableEvent::ResetPolicy::MANUAL,
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory_unittest.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory_unittest.cc
index e86dddd..975f2aa 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory_unittest.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory_unittest.cc
@@ -7,6 +7,7 @@
 #include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandler.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 namespace content {
 
@@ -25,7 +26,8 @@
   MockWebRTCPeerConnectionHandlerClient client_jsep;
   std::unique_ptr<blink::WebRTCPeerConnectionHandler> pc_handler(
       dependency_factory_->CreateRTCPeerConnectionHandler(
-          &client_jsep, base::ThreadTaskRunnerHandle::Get()));
+          &client_jsep,
+          blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   EXPECT_TRUE(pc_handler.get() != nullptr);
 }
 
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_adapter_map_unittest.cc b/content/renderer/media/webrtc/webrtc_media_stream_adapter_map_unittest.cc
index ba2402a1..9a01fa4 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_adapter_map_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_adapter_map_unittest.cc
@@ -26,6 +26,7 @@
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 
 using ::testing::_;
@@ -36,7 +37,7 @@
  public:
   void SetUp() override {
     dependency_factory_.reset(new MockPeerConnectionDependencyFactory());
-    main_thread_ = base::ThreadTaskRunnerHandle::Get();
+    main_thread_ = blink::scheduler::GetSingleThreadTaskRunnerForTesting();
     map_ = new WebRtcMediaStreamAdapterMap(
         dependency_factory_.get(),
         new WebRtcMediaStreamTrackAdapterMap(dependency_factory_.get()));
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc b/content/renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc
index dbbe22f..ec72f9a 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_adapter_unittest.cc
@@ -29,6 +29,7 @@
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 
 using ::testing::_;
@@ -139,7 +140,8 @@
             &RemoteWebRtcMediaStreamAdapterTest::
                 CreateRemoteStreamAdapterOnSignalingThread,
             base::Unretained(this),
-            base::Unretained(base::ThreadTaskRunnerHandle::Get().get()),
+            base::Unretained(
+                blink::scheduler::GetSingleThreadTaskRunnerForTesting().get()),
             base::Unretained(webrtc_stream), base::Unretained(&adapter)));
     RunMessageLoopsUntilIdle();
     DCHECK(adapter);
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc
index bd82e5d..5ea62f9 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc
@@ -17,6 +17,7 @@
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
 #include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 
 namespace content {
@@ -25,7 +26,7 @@
  public:
   void SetUp() override {
     dependency_factory_.reset(new MockPeerConnectionDependencyFactory());
-    main_thread_ = base::ThreadTaskRunnerHandle::Get();
+    main_thread_ = blink::scheduler::GetSingleThreadTaskRunnerForTesting();
     map_ = new WebRtcMediaStreamTrackAdapterMap(dependency_factory_.get());
   }
 
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc
index 8d13e68..75163bf 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc
@@ -21,6 +21,7 @@
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
 #include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 
 namespace content {
@@ -29,7 +30,7 @@
  public:
   void SetUp() override {
     dependency_factory_.reset(new MockPeerConnectionDependencyFactory());
-    main_thread_ = base::ThreadTaskRunnerHandle::Get();
+    main_thread_ = blink::scheduler::GetSingleThreadTaskRunnerForTesting();
   }
 
   void TearDown() override {
diff --git a/content/renderer/media/webrtc/webrtc_set_remote_description_observer_unittest.cc b/content/renderer/media/webrtc/webrtc_set_remote_description_observer_unittest.cc
index 0c12cb2..64ceefae 100644
--- a/content/renderer/media/webrtc/webrtc_set_remote_description_observer_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_set_remote_description_observer_unittest.cc
@@ -19,6 +19,7 @@
 #include "content/renderer/media/webrtc/webrtc_media_stream_adapter_map.h"
 #include "content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 #include "third_party/webrtc/api/peerconnectioninterface.h"
 #include "third_party/webrtc/media/base/fakemediaengine.h"
@@ -64,7 +65,7 @@
         std::unique_ptr<cricket::MediaEngineInterface>(
             new cricket::FakeMediaEngine())));
     dependency_factory_.reset(new MockPeerConnectionDependencyFactory());
-    main_thread_ = base::ThreadTaskRunnerHandle::Get();
+    main_thread_ = blink::scheduler::GetSingleThreadTaskRunnerForTesting();
     scoped_refptr<WebRtcMediaStreamAdapterMap> map =
         new WebRtcMediaStreamAdapterMap(
             dependency_factory_.get(),
diff --git a/content/renderer/media_capture_from_element/html_audio_element_capturer_source_unittest.cc b/content/renderer/media_capture_from_element/html_audio_element_capturer_source_unittest.cc
index 170683a..939aa40 100644
--- a/content/renderer/media_capture_from_element/html_audio_element_capturer_source_unittest.cc
+++ b/content/renderer/media_capture_from_element/html_audio_element_capturer_source_unittest.cc
@@ -17,6 +17,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
 
 using ::testing::_;
@@ -68,7 +69,8 @@
   HTMLAudioElementCapturerSourceTest()
       : fake_callback_(0.1, kAudioTrackSampleRate),
         audio_source_(new media::WebAudioSourceProviderImpl(
-            new media::NullAudioSink(base::ThreadTaskRunnerHandle::Get()),
+            new media::NullAudioSink(
+                blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
             &media_log_)) {}
 
   void SetUp() final {
diff --git a/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc b/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc
index a5ea6eaf..4e9e40e0 100644
--- a/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc
+++ b/content/renderer/media_capture_from_element/html_video_element_capturer_source_unittest.cc
@@ -13,6 +13,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebMediaPlayer.h"
 #include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 using ::testing::_;
 using ::testing::InSequence;
@@ -91,8 +92,8 @@
         web_media_player_(new MockWebMediaPlayer()),
         html_video_capturer_(new HtmlVideoElementCapturerSource(
             web_media_player_->AsWeakPtr(),
-            base::ThreadTaskRunnerHandle::Get(),
-            base::ThreadTaskRunnerHandle::Get())) {}
+            blink::scheduler::GetSingleThreadTaskRunnerForTesting(),
+            blink::scheduler::GetSingleThreadTaskRunnerForTesting())) {}
 
   // Necessary callbacks and MOCK_METHODS for them.
   MOCK_METHOD2(DoOnDeliverFrame,
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc
index 8fdae8b..28957f2 100644
--- a/content/renderer/render_thread_impl_browsertest.cc
+++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -51,6 +51,7 @@
 #include "mojo/edk/embedder/outgoing_broker_client_invitation.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/gfx/buffer_format_util.h"
 
@@ -141,7 +142,8 @@
 class QuitOnTestMsgFilter : public IPC::MessageFilter {
  public:
   explicit QuitOnTestMsgFilter(base::OnceClosure quit_closure)
-      : origin_task_runner_(base::SequencedTaskRunnerHandle::Get()),
+      : origin_task_runner_(
+            blink::scheduler::GetSequencedTaskRunnerForTesting()),
         quit_closure_(std::move(quit_closure)) {}
 
   // IPC::MessageFilter overrides:
@@ -180,7 +182,7 @@
     browser_threads_.reset(
         new TestBrowserThreadBundle(TestBrowserThreadBundle::IO_MAINLOOP));
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
-        base::ThreadTaskRunnerHandle::Get();
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting();
 
     InitializeMojo();
     shell_context_.reset(new TestServiceManagerContext);
@@ -200,8 +202,9 @@
     channel_ = IPC::ChannelProxy::Create(
         IPC::ChannelMojo::CreateServerFactory(
             std::move(pipe.handle0), io_task_runner,
-            base::ThreadTaskRunnerHandle::Get()),
-        nullptr, io_task_runner, base::ThreadTaskRunnerHandle::Get());
+            blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
+        nullptr, io_task_runner,
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting());
 
     mock_process_.reset(new MockRenderProcess);
     test_task_counter_ = base::MakeRefCounted<TestTaskCounter>();
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index e453583..25923f7 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -69,6 +69,7 @@
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
 #include "third_party/WebKit/public/web/WebDocumentLoader.h"
 #include "third_party/WebKit/public/web/WebFrameContentDumper.h"
@@ -1411,7 +1412,7 @@
 
   scoped_refptr<content::MessageLoopRunner> message_loop_runner =
       new content::MessageLoopRunner;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
+  blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
       FROM_HERE, message_loop_runner->QuitClosure());
 
   EXPECT_FALSE(render_thread_->sink().GetUniqueMessageMatching(
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index b2bdc5b..413e70b6 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -27,6 +27,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebCoalescedInputEvent.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/blink/web_input_event_traits.h"
@@ -137,7 +138,7 @@
                      false,
                      false,
                      false,
-                     base::ThreadTaskRunnerHandle::Get()),
+                     blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
         always_overscroll_(false) {
     Init(RenderWidget::ShowCallback(), mock_webwidget());
 
@@ -379,7 +380,7 @@
                      false,
                      false,
                      false,
-                     base::ThreadTaskRunnerHandle::Get()) {
+                     blink::scheduler::GetSingleThreadTaskRunnerForTesting()) {
     Init(RenderWidget::ShowCallback(), mock_webwidget());
     did_show_ = true;
   }
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 0c580b9..6c57da2 100644
--- a/content/renderer/service_worker/service_worker_provider_context_unittest.cc
+++ b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
@@ -28,6 +28,7 @@
 #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"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/WebKit/public/platform/web_feature.mojom.h"
 
 namespace content {
@@ -451,7 +452,7 @@
   // the refcounts.
   scoped_refptr<WebServiceWorkerRegistrationImpl> registration =
       provider_context->TakeRegistrationForServiceWorkerGlobalScope(
-          base::ThreadTaskRunnerHandle::Get());
+          blink::scheduler::GetSingleThreadTaskRunnerForTesting());
   EXPECT_TRUE(registration);
   EXPECT_EQ(registration_id, registration->RegistrationId());
   EXPECT_EQ(1, remote_registration_object_host().GetBindingCount());
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
index c94a12bb..cd36fd0 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
+++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@
 # AUTOGENERATED FILE - DO NOT EDIT
 # SEE roll_webgl_conformance.py
-Current webgl revision 1a8ed15c9c25f2b1ccd97149c94ea245ab982252
+Current webgl revision d458ada06171a85af00367251a4ed55db7fe2018
diff --git a/ios/chrome/browser/ui/download/pass_kit_coordinator.h b/ios/chrome/browser/ui/download/pass_kit_coordinator.h
index c628c5dc0..08b5e86 100644
--- a/ios/chrome/browser/ui/download/pass_kit_coordinator.h
+++ b/ios/chrome/browser/ui/download/pass_kit_coordinator.h
@@ -14,6 +14,33 @@
 class WebState;
 }  // namespace web
 
+// Key of the UMA Download.IOSPresentAddPassesDialogResult histogram. Exposed
+// only for testing.
+extern const char kUmaPresentAddPassesDialogResult[];
+
+// Enum for the Download.IOSPresentAddPassesDialogResult UMA histogram
+// to report the results of the add passes dialog presentation. The presentation
+// can be successful or unsuccessful if another view controller is currently
+// presented. Unsuccessful presentation is a bug and if the number of
+// unsuccessful presentations is high, it means that Chrome has to queue the
+// dialogs to present those dialogs for every downloaded pkpass (PassKit file).
+// Currently Chrome simply ignores the download if the dialog is already
+// presented. Exposed only for testing.
+// Note: This enum is used to back an UMA histogram, and should be treated as
+// append-only.
+enum class PresentAddPassesDialogResult {
+  // The dialog was sucessesfully presented.
+  kSuccessful = 0,
+  // The dialog cannot be presented, because another PKAddPassesViewController
+  // is already presented.
+  kAnotherAddPassesViewControllerIsPresented = 1,
+  // The dialog cannot be presented, because another view controller is already
+  // presented. Does not include items already counted in the more specific
+  // bucket (kAnotherAddPassesViewControllerIsPresented).
+  kAnotherViewControllerIsPresented = 2,
+  kCount
+};
+
 // Coordinates presentation of "Add pkpass UI" and "failed to add pkpass UI".
 @interface PassKitCoordinator : ChromeCoordinator<PassKitTabHelperDelegate>
 
diff --git a/ios/chrome/browser/ui/download/pass_kit_coordinator.mm b/ios/chrome/browser/ui/download/pass_kit_coordinator.mm
index fff487e..7fee990 100644
--- a/ios/chrome/browser/ui/download/pass_kit_coordinator.mm
+++ b/ios/chrome/browser/ui/download/pass_kit_coordinator.mm
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/metrics/histogram_macros.h"
 #include "components/infobars/core/infobar_manager.h"
 #include "components/infobars/core/simple_alert_infobar_delegate.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
@@ -17,6 +18,28 @@
 #error "This file requires ARC support."
 #endif
 
+const char kUmaPresentAddPassesDialogResult[] =
+    "Download.IOSPresentAddPassesDialogResult";
+
+namespace {
+
+// Returns PresentAddPassesDialogResult for the given base view
+// controller.
+PresentAddPassesDialogResult GetUmaResult(
+    UIViewController* base_view_controller) {
+  if (!base_view_controller.presentedViewController)
+    return PresentAddPassesDialogResult::kSuccessful;
+
+  if ([base_view_controller.presentedViewController
+          isKindOfClass:[PKAddPassesViewController class]])
+    return PresentAddPassesDialogResult::
+        kAnotherAddPassesViewControllerIsPresented;
+
+  return PresentAddPassesDialogResult::kAnotherViewControllerIsPresented;
+}
+
+}  // namespace
+
 @interface PassKitCoordinator ()<CRWWebStateObserver,
                                  PKAddPassesViewControllerDelegate> {
   // Present the "Add pkpass UI".
@@ -75,6 +98,11 @@
     [self stop];
     return;
   }
+
+  UMA_HISTOGRAM_ENUMERATION(kUmaPresentAddPassesDialogResult,
+                            GetUmaResult(self.baseViewController),
+                            PresentAddPassesDialogResult::kCount);
+
   _viewController = [[PKAddPassesViewController alloc] initWithPass:self.pass];
   _viewController.delegate = self;
   [self.baseViewController presentViewController:_viewController
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 4c4bbc6..73195c0 100644
--- a/ios/chrome/browser/ui/download/pass_kit_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/download/pass_kit_coordinator_unittest.mm
@@ -6,6 +6,7 @@
 
 #import <PassKit/PassKit.h>
 
+#include "base/test/histogram_tester.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "components/infobars/core/infobar.h"
 #import "ios/chrome/browser/download/pass_kit_tab_helper.h"
@@ -47,12 +48,17 @@
     [scoped_key_window_.Get() setRootViewController:base_view_controller_];
   }
 
+  PassKitTabHelper* tab_helper() {
+    return PassKitTabHelper::FromWebState(web_state_.get());
+  }
+
   UIViewController* base_view_controller_;
   PassKitCoordinator* coordinator_;
   std::unique_ptr<web::TestWebState> web_state_;
   FakePassKitTabHelperDelegate* delegate_;
   ScopedKeyWindow scoped_key_window_;
   std::unique_ptr<web::NavigationManager> test_navigation_manager_;
+  base::HistogramTester histogram_tester_;
 };
 
 // Tests that PassKitCoordinator presents PKAddPassesViewController for the
@@ -63,10 +69,9 @@
   PKPass* pass = [[PKPass alloc] initWithData:nsdata error:nil];
   ASSERT_TRUE(pass);
 
-  [coordinator_
-          passKitTabHelper:PassKitTabHelper::FromWebState(web_state_.get())
-      presentDialogForPass:pass
-                  webState:web_state_.get()];
+  [coordinator_ passKitTabHelper:tab_helper()
+            presentDialogForPass:pass
+                        webState:web_state_.get()];
 
   if (IsIPadIdiom()) {
     // Wallet app is not supported on iPads.
@@ -81,19 +86,109 @@
     EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{
       return base_view_controller_.presentedViewController == nil;
     }));
+
+    histogram_tester_.ExpectUniqueSample(
+        kUmaPresentAddPassesDialogResult,
+        static_cast<base::HistogramBase::Sample>(
+            PresentAddPassesDialogResult::kSuccessful),
+        1);
   }
 
   EXPECT_FALSE(coordinator_.webState);
   EXPECT_FALSE(coordinator_.pass);
 }
 
+// Tests presenting multiple valid PKPass objects.
+TEST_F(PassKitCoordinatorTest, MultiplePassKitObjects) {
+  if (IsIPadIdiom()) {
+    // Wallet app is not supported on iPads.
+    return;
+  }
+
+  std::string data = testing::GetTestPass();
+  NSData* nsdata = [NSData dataWithBytes:data.c_str() length:data.size()];
+  PKPass* pass = [[PKPass alloc] initWithData:nsdata error:nil];
+  ASSERT_TRUE(pass);
+
+  [coordinator_ passKitTabHelper:tab_helper()
+            presentDialogForPass:pass
+                        webState:web_state_.get()];
+
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForUIElementTimeout, ^{
+    return [base_view_controller_.presentedViewController class] ==
+           [PKAddPassesViewController class];
+  }));
+
+  histogram_tester_.ExpectUniqueSample(
+      kUmaPresentAddPassesDialogResult,
+      static_cast<base::HistogramBase::Sample>(
+          PresentAddPassesDialogResult::kSuccessful),
+      1);
+
+  UIViewController* presented_controller =
+      base_view_controller_.presentedViewController;
+
+  [coordinator_ passKitTabHelper:tab_helper()
+            presentDialogForPass:pass
+                        webState:web_state_.get()];
+
+  // New UI presentation is ignored.
+  EXPECT_EQ(presented_controller,
+            base_view_controller_.presentedViewController);
+
+  histogram_tester_.ExpectBucketCount(
+      kUmaPresentAddPassesDialogResult,
+      static_cast<base::HistogramBase::Sample>(
+          PresentAddPassesDialogResult::
+              kAnotherAddPassesViewControllerIsPresented),
+      1);
+}
+
+// Tests presenting valid PKPass object, while another view controller is
+// already presented.
+TEST_F(PassKitCoordinatorTest, AnotherViewControllerIsPresented) {
+  if (IsIPadIdiom()) {
+    // Wallet app is not supported on iPads.
+    return;
+  }
+
+  // Present another view controller.
+  UIViewController* presented_controller = [[UIViewController alloc] init];
+  [base_view_controller_ presentViewController:presented_controller
+                                      animated:YES
+                                    completion:nil];
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForUIElementTimeout, ^{
+    return presented_controller ==
+           base_view_controller_.presentedViewController;
+  }));
+
+  // Attempt to present "Add pkpass UI".
+  std::string data = testing::GetTestPass();
+  NSData* nsdata = [NSData dataWithBytes:data.c_str() length:data.size()];
+  PKPass* pass = [[PKPass alloc] initWithData:nsdata error:nil];
+  ASSERT_TRUE(pass);
+
+  [coordinator_ passKitTabHelper:tab_helper()
+            presentDialogForPass:pass
+                        webState:web_state_.get()];
+
+  // New UI presentation is ignored.
+  EXPECT_EQ(presented_controller,
+            base_view_controller_.presentedViewController);
+
+  histogram_tester_.ExpectBucketCount(
+      kUmaPresentAddPassesDialogResult,
+      static_cast<base::HistogramBase::Sample>(
+          PresentAddPassesDialogResult::kAnotherViewControllerIsPresented),
+      1);
+}
+
 // Tests that PassKitCoordinator presents error infobar for invalid PKPass
 // object.
 TEST_F(PassKitCoordinatorTest, InvalidPassKitObject) {
-  [coordinator_
-          passKitTabHelper:PassKitTabHelper::FromWebState(web_state_.get())
-      presentDialogForPass:nil
-                  webState:web_state_.get()];
+  [coordinator_ passKitTabHelper:tab_helper()
+            presentDialogForPass:nil
+                        webState:web_state_.get()];
 
   infobars::InfoBarManager* infobar_manager =
       InfoBarManagerImpl::FromWebState(web_state_.get());
@@ -106,6 +201,8 @@
             delegate->GetMessageText());
   EXPECT_FALSE(coordinator_.webState);
   EXPECT_FALSE(coordinator_.pass);
+
+  histogram_tester_.ExpectTotalCount(kUmaPresentAddPassesDialogResult, 0);
 }
 
 // Tests that destroying web state nulls out webState property.
diff --git a/media/blink/video_decode_stats_reporter_unittest.cc b/media/blink/video_decode_stats_reporter_unittest.cc
index abb71a7..82b5b97 100644
--- a/media/blink/video_decode_stats_reporter_unittest.cc
+++ b/media/blink/video_decode_stats_reporter_unittest.cc
@@ -16,6 +16,7 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "ui/gfx/geometry/rect.h"
 
 using ::testing::Invoke;
@@ -170,8 +171,8 @@
         std::move(recorder_ptr),
         base::Bind(&VideoDecodeStatsReporterTest::GetPipelineStatsCB,
                    base::Unretained(this)),
-        MakeDefaultVideoConfig(), base::ThreadTaskRunnerHandle::Get(),
-        clock_.get());
+        MakeDefaultVideoConfig(),
+        blink::scheduler::GetSingleThreadTaskRunnerForTesting(), clock_.get());
   }
 
   // Fast forward the task runner (and associated tick clock) by |milliseconds|.
diff --git a/storage/browser/fileapi/file_system_operation_context.h b/storage/browser/fileapi/file_system_operation_context.h
index ba4aa97..5e8b111 100644
--- a/storage/browser/fileapi/file_system_operation_context.h
+++ b/storage/browser/fileapi/file_system_operation_context.h
@@ -13,7 +13,7 @@
 #include "base/threading/thread_checker.h"
 #include "storage/browser/fileapi/task_runner_bound_observer_list.h"
 #include "storage/browser/storage_browser_export.h"
-#include "storage/common/quota/quota_types.h"
+#include "storage/common/quota/quota_limit_type.h"
 
 namespace base {
 class SequencedTaskRunner;
diff --git a/storage/common/BUILD.gn b/storage/common/BUILD.gn
index 3328336..6e4253d7 100644
--- a/storage/common/BUILD.gn
+++ b/storage/common/BUILD.gn
@@ -29,6 +29,7 @@
     "fileapi/file_system_types.h",
     "fileapi/file_system_util.cc",
     "fileapi/file_system_util.h",
+    "quota/quota_limit_type.h",
     "quota/quota_types.h",
     "storage_common_export.h",
     "storage_histograms.cc",
diff --git a/storage/common/quota/quota_limit_type.h b/storage/common/quota/quota_limit_type.h
new file mode 100644
index 0000000..67d7791
--- /dev/null
+++ b/storage/common/quota/quota_limit_type.h
@@ -0,0 +1,19 @@
+// 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 STORAGE_COMMON_QUOTA_QUOTA_LIMIT_TYPE_H_
+#define STORAGE_COMMON_QUOTA_QUOTA_LIMIT_TYPE_H_
+
+namespace storage {
+
+enum QuotaLimitType {
+  kQuotaLimitTypeUnknown,
+  kQuotaLimitTypeLimited,
+  kQuotaLimitTypeUnlimited,
+  kQuotaLimitTypeLast = kQuotaLimitTypeUnlimited
+};
+
+}  // namespace storage
+
+#endif  // STORAGE_COMMON_QUOTA_QUOTA_LIMIT_TYPE_H_
diff --git a/storage/common/quota/quota_types.h b/storage/common/quota/quota_types.h
index 1c164382..96da498 100644
--- a/storage/common/quota/quota_types.h
+++ b/storage/common/quota/quota_types.h
@@ -16,13 +16,6 @@
   kStorageTypeLast = kStorageTypeUnknown
 };
 
-enum QuotaLimitType {
-  kQuotaLimitTypeUnknown,
-  kQuotaLimitTypeLimited,
-  kQuotaLimitTypeUnlimited,
-  kQuotaLimitTypeLast = kQuotaLimitTypeUnlimited
-};
-
 }  // namespace storage
 
 #endif  // STORAGE_COMMON_QUOTA_QUOTA_TYPES_H_
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 8541284..91b1439 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2318,6 +2318,21 @@
             ]
         }
     ],
+    "OfflinePagesCctV2": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "OfflinePagesCTV2"
+                    ]
+                }
+            ]
+        }
+    ],
     "OfflinePagesPrefetchingSuggestions": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index d553c4b..5d2cab2 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -685,17 +685,13 @@
 # ====== IncrementalShadowDOM-only failures from here ======
 
 crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/HTMLSlotElement-interface.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/MouseEvent-prototype-offsetX-offsetY.html [ Failure ]
 crbug.com/788608 virtual/incremental-shadow-dom/external/wpt/shadow-dom/leaktests/html-collection.html [ Failure Crash ]
 crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/slots-fallback-in-document.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/slots-fallback.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/slots.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-event-interface/event-path-001.html [ Failure ]
 crbug.com/788635 virtual/incremental-shadow-dom/external/wpt/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-002.html [ Failure Crash ]
-crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/untriaged/shadow-trees/reprojection/reprojection-001.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/untriaged/shadow-trees/shadow-root-002.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/untriaged/styles/test-003.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/external/wpt/shadow-dom/untriaged/user-interaction/ranges-and-selections/test-002.html [ Failure ]
 crbug.com/788608 virtual/incremental-shadow-dom/fast/dom/shadow/adopt-node-with-shadow-root.html [ Failure Crash ]
 crbug.com/788610 virtual/incremental-shadow-dom/fast/dom/shadow/content-child-whitespace-between-span.html [ Failure Crash ]
 crbug.com/788635 virtual/incremental-shadow-dom/fast/dom/shadow/custom-pseudo-scope.html [ Failure Crash ]
@@ -707,7 +703,6 @@
 crbug.com/788625 virtual/incremental-shadow-dom/fast/dom/shadow/make-marquee-bold-by-exec-command-crash.html [ Failure Crash ]
 crbug.com/788625 virtual/incremental-shadow-dom/fast/dom/shadow/marquee-and-link-element-crash.html [ Failure Crash ]
 crbug.com/788625 virtual/incremental-shadow-dom/fast/dom/shadow/move-marquee-crossing-treescope-crash.html [ Failure Crash ]
-crbug.com/788635 virtual/incremental-shadow-dom/fast/dom/shadow/no-renderers-for-light-children.html [ Failure Crash ]
 crbug.com/787717 virtual/incremental-shadow-dom/fast/dom/shadow/normalize-progress-element-crash.html [ Failure Crash ]
 crbug.com/787717 virtual/incremental-shadow-dom/fast/dom/shadow/querySelector-for-useragent-shadowroot.html [ Failure Crash ]
 crbug.com/788610 virtual/incremental-shadow-dom/fast/dom/shadow/remove-details-in-exec-command-crash.html [ Failure Crash ]
@@ -717,36 +712,21 @@
 crbug.com/788635 virtual/incremental-shadow-dom/fast/dom/shadow/tree-scope-crash.html [ Failure Crash ]
 crbug.com/788610 virtual/incremental-shadow-dom/fast/dom/shadow/user-modify-in-datalist-crash.html [ Failure Crash ]
 crbug.com/776656 virtual/incremental-shadow-dom/fast/dom/shadow/user-modify-inheritance.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/active-element.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/css-cascade-outer-scope2.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/css-cascade-slot-distributed.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/css-style-inherit.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-slot-fallback-default-tabindex.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-slot-fallback.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-slot-nested-2levels.html [ Failure Crash ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-slot-nested-delegatesFocus.html [ Failure Crash ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-slot-nested-fallback.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-slot-nested.html [ Failure Crash ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-slot-shadow-in-fallback.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-slot-shadow-in-slot.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-slot-with-tabindex.html [ Failure Crash ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-slots.html [ Failure Crash ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/focus-navigation.html [ Failure Crash ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/host-pseudo-elements.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/layout.html [ Failure ]
 # Solving crbug.com/787717 would fix the crash of nodetree-radio-node-list.html
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/nodetree-radio-node-list.html [ Failure Crash ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/offsetParent.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slots-1.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slots-2.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slots-dynamic.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slots-fallback-1.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slots-fallback-2.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slots-fallback-3.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slots-text-nodes.html [ Failure ]
 crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slotted-pseudo-element-dynamic-attribute-change.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slotted-pseudo-element-shared-style.html [ Failure ]
-crbug.com/776656 virtual/incremental-shadow-dom/shadow-dom/slotted-pseudo-element.html [ Failure ]
 
 # ====== IncrementalShadowDOM-only failures until here ======
 
@@ -3222,7 +3202,6 @@
 crbug.com/v8/4958 http/tests/devtools/console/console-format-es6.js [ NeedsManualRebaseline Timeout ]
 
 # For V8 roll
-crbug.com/791334 http/tests/devtools/sources/debugger/debugger-es6-harmony-scopes.js [ NeedsManualRebaseline ]
 crbug.com/v8/7172 fast/events/window-onerror-10.html [ NeedsManualRebaseline ]
 crbug.com/v8/7172 fast/frames/sandboxed-iframe-forms.html [ NeedsManualRebaseline ]
 crbug.com/v8/7172 http/tests/devtools/domdebugger/domdebugger-getEventListeners.js [ NeedsManualRebaseline ]
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/resources/v8-cache-script.js b/third_party/WebKit/LayoutTests/http/tests/devtools/resources/v8-cache-script.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/resources/v8-cache-script.js
rename to third_party/WebKit/LayoutTests/http/tests/devtools/resources/v8-cache-script.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/security/origin-view-then-interstitial-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/security/origin-view-then-interstitial-expected.txt
index 41cc7a7..b525227 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/security/origin-view-then-interstitial-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/security/origin-view-then-interstitial-expected.txt
@@ -35,15 +35,38 @@
     <STYLE type=text/css >
     </STYLE>
     <DIV class=title-section >
+        <DIV class=title-section-header >
+Origin
+        </DIV>
         <DIV class=origin-display >
             <SPAN class=security-property security-property-secure >
             </SPAN>
-            <SPAN class=origin >
-https://foo.test
+            <SPAN is=url-text >
+                <SPAN class=url-scheme-secure >
+https
+                </SPAN>
+                <SPAN class=url-scheme-separator >
+://
+                </SPAN>
+                <SPAN >
+foo.test
+                </SPAN>
             </SPAN>
         </DIV>
-        <DIV class=link >
+        <DIV class=view-network-button >
+            <BUTTON is=text-button type=button class=origin-button >
 View requests in Network Panel
+                <#document-fragment >
+                    <STYLE type=text/css >
+                    </STYLE>
+                    <STYLE type=text/css >
+                    </STYLE>
+                    <STYLE type=text/css >
+                    </STYLE>
+                    <CONTENT >
+                    </CONTENT>
+                </#document-fragment>
+            </BUTTON>
         </DIV>
     </DIV>
     <DIV class=origin-view-section >
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/security/security-details-updated-with-security-state-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/security/security-details-updated-with-security-state-expected.txt
index 48f096a6..5638d88 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/security/security-details-updated-with-security-state-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/security/security-details-updated-with-security-state-expected.txt
@@ -51,15 +51,38 @@
     <STYLE type=text/css >
     </STYLE>
     <DIV class=title-section >
+        <DIV class=title-section-header >
+Origin
+        </DIV>
         <DIV class=origin-display >
             <SPAN class=security-property security-property-secure >
             </SPAN>
-            <SPAN class=origin >
-https://foo.test
+            <SPAN is=url-text >
+                <SPAN class=url-scheme-secure >
+https
+                </SPAN>
+                <SPAN class=url-scheme-separator >
+://
+                </SPAN>
+                <SPAN >
+foo.test
+                </SPAN>
             </SPAN>
         </DIV>
-        <DIV class=link >
+        <DIV class=view-network-button >
+            <BUTTON is=text-button type=button class=origin-button >
 View requests in Network Panel
+                <#document-fragment >
+                    <STYLE type=text/css >
+                    </STYLE>
+                    <STYLE type=text/css >
+                    </STYLE>
+                    <STYLE type=text/css >
+                    </STYLE>
+                    <CONTENT >
+                    </CONTENT>
+                </#document-fragment>
+            </BUTTON>
         </DIV>
     </DIV>
     <DIV class=origin-view-section >
@@ -149,7 +172,7 @@
                 <DIV >
                 </DIV>
                 <DIV >
-                    <BUTTON is=text-button type=button class=security-certificate-button >
+                    <BUTTON is=text-button type=button class=origin-button >
 Open full certificate details
                         <#document-fragment >
                             <STYLE type=text/css >
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/resources/v8-cache-worker.js b/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/resources/v8-cache-worker.js
index 65ff773f..7cae9da 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/resources/v8-cache-worker.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/resources/v8-cache-worker.js
@@ -1,5 +1,5 @@
 const cacheName = 'c8-cache-test';
-const scriptName = 'v8-cache-script.js';
+const scriptName = '/devtools/resources/v8-cache-script.js';
 
 self.addEventListener('install', (event) => {
     event.waitUntil(
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 db34a61b8..d0d1b8b 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
@@ -24,7 +24,7 @@
         lineNumber : 0
         producedCacheSize : <number>
         streamed : <boolean>
-        url : .../devtools/service-workers/resources/v8-cache-script.js
+        url : .../devtools/resources/v8-cache-script.js
     }
     endTime : <number>
     startTime : <number>
@@ -40,7 +40,7 @@
         consumedCacheSize : <number>
         lineNumber : 0
         streamed : <boolean>
-        url : .../devtools/service-workers/resources/v8-cache-script.js
+        url : .../devtools/resources/v8-cache-script.js
     }
     endTime : <number>
     startTime : <number>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache.js b/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache.js
index 17fc2d1..706eea6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache.js
@@ -19,7 +19,7 @@
           .then(() => waitForActivated(scope));
       }
       function loadScript() {
-        const url = 'v8-cache-script.js';
+        const url = '/devtools/resources/v8-cache-script.js';
         const frameId = 'frame_id';
         let iframeWindow = document.getElementById(frameId).contentWindow;
         return iframeWindow.loadScript(url)
diff --git a/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/append.html b/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/append.html
index f06f394..aa50bcb 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/append.html
+++ b/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/append.html
@@ -27,14 +27,24 @@
 test(() => {
   let styleMap = newDivWithStyle().attributeStyleMap;
 
-  styleMap.append('transition-duration', CSS.s(1), CSS.s(2));
+  styleMap.append('transition-duration', CSS.s(1), '2s');
   assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
 
-  styleMap.append('transition-duration', '3s', '4s');
+  styleMap.append('transition-duration', '3s', CSS.s(4));
   assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2), CSS.s(3), CSS.s(4)]);
 }, 'Appending a list-valued property with CSSStyleValue or String updates its values');
 
 test(() => {
+  let styleMap = newDivWithStyle().attributeStyleMap;
+
+  styleMap.append('transition-duration', '1s, 2s');
+  assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+
+  styleMap.append('transition-duration', '3s, 4s');
+  assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2), CSS.s(3), CSS.s(4)]);
+}, 'Appending a list-valued property with list-valued string updates its values');
+
+test(() => {
   let styleMap = newDivWithStyle('transition-duration: 5s, 10s').attributeStyleMap;
 
   styleMap.append('tRaNsItIoN-dUrAtIoN', '1s', CSS.s(2));
diff --git a/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/set-expected.txt b/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/set-expected.txt
index dccebf58..048f392 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/set-expected.txt
+++ b/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/set-expected.txt
@@ -4,8 +4,10 @@
 PASS Setting a StylePropertyMap with an invalid CSSStyleValue throws TypeError
 PASS Setting a StylePropertyMap with an invalid String throws TypeError
 PASS Setting a non list-valued property with multiple arguments throws TypeError
+PASS Setting a non list-valued property with list-valued string throws TypeError
 PASS Setting a property with CSSStyleValue or String updates its value
 PASS Setting a list-valued property with CSSStyleValue or String updates its values
+PASS Setting a list-valued property with a list-valued string updates its value
 FAIL Setting a custom property with CSSStyleValue or String updates its value Failed to execute 'set' on 'StylePropertyMap': Invalid propertyName: --foo
 PASS StylePropertyMap.set is case-insensitive
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/set.html b/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/set.html
index d0ba3f1..cc48016 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/set.html
+++ b/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/inline/set.html
@@ -29,6 +29,11 @@
 
 test(() => {
   let styleMap = newDivWithStyle().attributeStyleMap;
+  assert_throws(new TypeError(), () => styleMap.set('width', '1s, 2s'));
+}, 'Setting a non list-valued property with list-valued string throws TypeError');
+
+test(() => {
+  let styleMap = newDivWithStyle().attributeStyleMap;
 
   styleMap.set('width', CSS.px(10));
   assert_style_value_array_equals(styleMap.get('width'), CSS.px(10));
@@ -40,16 +45,23 @@
 test(() => {
   let styleMap = newDivWithStyle().attributeStyleMap;
 
-  styleMap.set('transition-duration', CSS.s(1), CSS.s(2));
+  styleMap.set('transition-duration', CSS.s(1), '2s');
   assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
 
-  styleMap.set('transition-duration', '3s', '4s');
+  styleMap.set('transition-duration', '3s', CSS.s(4));
   assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(3), CSS.s(4)]);
 }, 'Setting a list-valued property with CSSStyleValue or String updates its values');
 
 test(() => {
   let styleMap = newDivWithStyle().attributeStyleMap;
 
+  styleMap.set('transition-duration', '1s, 2s');
+  assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+}, 'Setting a list-valued property with a list-valued string updates its value');
+
+test(() => {
+  let styleMap = newDivWithStyle().attributeStyleMap;
+
   styleMap.set('--foo', CSS.px(10));
   assert_style_value_array_equals(styleMap.get('--foo'), CSS.px(10));
 
diff --git a/third_party/WebKit/LayoutTests/virtual/pwa-full-code-cache/http/tests/devtools/service-workers/service-worker-v8-cache-expected.txt b/third_party/WebKit/LayoutTests/virtual/pwa-full-code-cache/http/tests/devtools/service-workers/service-worker-v8-cache-expected.txt
index 8441497..d712dee 100644
--- a/third_party/WebKit/LayoutTests/virtual/pwa-full-code-cache/http/tests/devtools/service-workers/service-worker-v8-cache-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/pwa-full-code-cache/http/tests/devtools/service-workers/service-worker-v8-cache-expected.txt
@@ -22,7 +22,7 @@
         lineNumber : 0
         producedCacheSize : <number>
         streamed : <boolean>
-        url : .../devtools/service-workers/resources/v8-cache-script.js
+        url : .../devtools/resources/v8-cache-script.js
     }
     endTime : <number>
     startTime : <number>
@@ -40,7 +40,7 @@
         consumedCacheSize : <number>
         lineNumber : 0
         streamed : <boolean>
-        url : .../devtools/service-workers/resources/v8-cache-script.js
+        url : .../devtools/resources/v8-cache-script.js
     }
     endTime : <number>
     startTime : <number>
@@ -56,7 +56,7 @@
         consumedCacheSize : <number>
         lineNumber : 0
         streamed : <boolean>
-        url : .../devtools/service-workers/resources/v8-cache-script.js
+        url : .../devtools/resources/v8-cache-script.js
     }
     endTime : <number>
     startTime : <number>
diff --git a/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.cpp b/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.cpp
index 01933a8..162d090 100644
--- a/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.cpp
@@ -40,26 +40,62 @@
   return style_value.ToCSSValueWithProperty(property_id, secure_context_mode);
 }
 
-const CSSValue* CoerceStyleValueOrStringToCSSValue(
+const CSSValue* CoerceStyleValuesOrStringsToCSSValues(
     CSSPropertyID property_id,
-    const CSSStyleValueOrString& value,
+    const HeapVector<CSSStyleValueOrString>& values,
     const CSSParserContext* parser_context) {
-  if (value.IsCSSStyleValue()) {
-    if (!value.GetAsCSSStyleValue())
-      return nullptr;
+  DCHECK(!values.IsEmpty());
 
-    return StyleValueToCSSValue(property_id, *value.GetAsCSSStyleValue(),
-                                parser_context->GetSecureContextMode());
+  const bool is_repeated = CSSProperty::Get(property_id).IsRepeated();
+  CSSValueList* result = nullptr;
+  if (is_repeated) {
+    result = CssValueListForPropertyID(property_id);
+  } else {
+    result = CSSValueList::CreateCommaSeparated();
   }
 
-  const auto values = StyleValueFactory::FromString(
-      property_id, value.GetAsString(), parser_context);
-  // TODO(https://github.com/w3c/css-houdini-drafts/issues/512):
-  // What is the correct behaviour here?
-  if (values.size() != 1)
-    return nullptr;
-  return StyleValueToCSSValue(property_id, *values[0],
-                              parser_context->GetSecureContextMode());
+  for (const auto& value : values) {
+    if (value.IsCSSStyleValue()) {
+      if (!value.GetAsCSSStyleValue())
+        return nullptr;
+
+      const CSSValue* css_value =
+          StyleValueToCSSValue(property_id, *value.GetAsCSSStyleValue(),
+                               parser_context->GetSecureContextMode());
+      if (!css_value)
+        return nullptr;
+
+      result->Append(*css_value);
+    } else {
+      DCHECK(value.IsString());
+      const auto subvalues = StyleValueFactory::FromString(
+          property_id, value.GetAsString(), parser_context);
+      if (subvalues.IsEmpty())
+        return nullptr;
+
+      for (const auto& subvalue : subvalues) {
+        const CSSValue* css_value = StyleValueToCSSValue(
+            property_id, *subvalue, parser_context->GetSecureContextMode());
+        if (!css_value)
+          return nullptr;
+
+        result->Append(*css_value);
+      }
+    }
+  }
+
+  const bool contains_wide_keyword =
+      std::any_of(result->begin(), result->end(),
+                  [](const auto& value) { return value->IsCSSWideKeyword(); });
+  if (!is_repeated || contains_wide_keyword) {
+    if (result->length() > 1)
+      return nullptr;
+
+    DCHECK_NE(result->length(), 0U);
+    return &result->Item(0);
+  }
+
+  return result;
 }
 
 }  // namespace
@@ -79,39 +115,14 @@
     return;
   }
 
-  if (CSSProperty::Get(property_id).IsRepeated()) {
-    CSSValueList* result = CssValueListForPropertyID(property_id);
-    for (const auto& value : values) {
-      const CSSValue* css_value = CoerceStyleValueOrStringToCSSValue(
-          property_id, value, CSSParserContext::Create(*execution_context));
-      if (!css_value || (css_value->IsCSSWideKeyword() && values.size() > 1)) {
-        exception_state.ThrowTypeError("Invalid type for property");
-        return;
-      }
-      result->Append(*css_value);
-    }
-
-    if (result->length() == 1 && result->Item(0).IsCSSWideKeyword())
-      SetProperty(property_id, &result->Item(0));
-    else
-      SetProperty(property_id, result);
-  } else {
-    if (values.size() != 1) {
-      exception_state.ThrowTypeError(
-          "Cannot set " + property_name +
-          " with multiple values as it is not list-valued");
-      return;
-    }
-
-    const CSSValue* result = CoerceStyleValueOrStringToCSSValue(
-        property_id, values[0], CSSParserContext::Create(*execution_context));
-    if (!result) {
-      exception_state.ThrowTypeError("Invalid type for property");
-      return;
-    }
-
-    SetProperty(property_id, result);
+  const CSSValue* result = CoerceStyleValuesOrStringsToCSSValues(
+      property_id, values, CSSParserContext::Create(*execution_context));
+  if (!result) {
+    exception_state.ThrowTypeError("Invalid type for property");
+    return;
   }
+
+  SetProperty(property_id, result);
 }
 
 void StylePropertyMap::append(const ExecutionContext* execution_context,
@@ -134,31 +145,27 @@
     return;
   }
 
-  const CSSValue* css_value = GetProperty(property_id);
-
-  CSSValueList* css_value_list = nullptr;
-  if (!css_value) {
-    css_value_list = CssValueListForPropertyID(property_id);
-  } else if (css_value->IsValueList()) {
-    css_value_list = ToCSSValueList(css_value)->Copy();
+  CSSValueList* current_value = nullptr;
+  if (const CSSValue* css_value = GetProperty(property_id)) {
+    DCHECK(css_value->IsValueList());
+    current_value = ToCSSValueList(css_value)->Copy();
   } else {
-    // TODO(meade): Figure out what the correct behaviour here is.
-    NOTREACHED();
-    exception_state.ThrowTypeError("Property is not already list valued");
+    current_value = CssValueListForPropertyID(property_id);
+  }
+
+  const CSSValue* result = CoerceStyleValuesOrStringsToCSSValues(
+      property_id, values, CSSParserContext::Create(*execution_context));
+  if (!result) {
+    exception_state.ThrowTypeError("Invalid type for property");
     return;
   }
 
-  for (auto& value : values) {
-    const CSSValue* css_value = CoerceStyleValueOrStringToCSSValue(
-        property_id, value, CSSParserContext::Create(*execution_context));
-    if (!css_value) {
-      exception_state.ThrowTypeError("Invalid type for property");
-      return;
-    }
-    css_value_list->Append(*css_value);
+  DCHECK(result->IsValueList());
+  for (const auto& value : *ToCSSValueList(result)) {
+    current_value->Append(*value);
   }
 
-  SetProperty(property_id, css_value_list);
+  SetProperty(property_id, current_value);
 }
 
 void StylePropertyMap::remove(const String& property_name,
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp
index 638d818..56c17442 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp
@@ -185,7 +185,7 @@
   }
 
   // Note: "conditions" referred in Step 8 is implemented in
-  // WasModuleLoadSuccessful() in ModuleScriptFetcher.cpp.
+  // WasModuleLoadSuccessful() in DocumentModuleScriptFetcher.cpp.
   // Step 8. "If any of the following conditions are met, set moduleMap[url] to
   // null, asynchronously complete this algorithm with null, and abort these
   // steps." [spec text]
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index e53b5f3f..01c224c 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -562,11 +562,6 @@
     return ToIntSize(-ScrollOrigin());
 
   IntSize content_size = ContentsSize();
-  IntSize visible_size =
-      PixelSnappedIntRect(
-          Box().OverflowClipRect(Box().Location(),
-                                 kIgnorePlatformAndCSSOverlayScrollbarSize))
-          .Size();
 
   Page* page = GetLayoutBox()->GetDocument().GetPage();
   DCHECK(page);
@@ -576,8 +571,16 @@
   // The global root scroller should be clipped by the top LocalFrameView rather
   // than it's overflow clipping box. This is to ensure that content exposed by
   // hiding the URL bar at the bottom of the screen is visible.
-  if (this == controller.RootScrollerArea())
+  IntSize visible_size;
+  if (this == controller.RootScrollerArea()) {
     visible_size = controller.RootScrollerVisibleArea();
+  } else {
+    visible_size =
+        PixelSnappedIntRect(
+            Box().OverflowClipRect(Box().Location(),
+                                   kIgnorePlatformAndCSSOverlayScrollbarSize))
+            .Size();
+  }
 
   // TODO(skobes): We should really ASSERT that contentSize >= visibleSize
   // when we are not the root layer, but we can't because contentSize is
diff --git a/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js b/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
index 8a241d6..c37fa0d 100644
--- a/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
@@ -47,7 +47,7 @@
       e.consume();
       var names = await SDK.multitargetNetworkManager.getCertificate(origin);
       InspectorFrontendHost.showCertificateViewer(names);
-    }, 'security-certificate-button');
+    }, 'origin-button');
   }
 
   /**
@@ -781,21 +781,23 @@
     this.registerRequiredCSS('security/lockIcon.css');
 
     var titleSection = this.element.createChild('div', 'title-section');
+    titleSection.createChild('div', 'title-section-header').textContent = ls`Origin`;
+
     var originDisplay = titleSection.createChild('div', 'origin-display');
     this._originLockIcon = originDisplay.createChild('span', 'security-property');
     this._originLockIcon.classList.add('security-property-' + originState.securityState);
-    // TODO(lgarron): Highlight the origin scheme. https://crbug.com/523589
-    originDisplay.createChild('span', 'origin').textContent = origin;
-    var originNetworkLink = titleSection.createChild('div', 'link');
-    originNetworkLink.textContent = Common.UIString('View requests in Network Panel');
-    function showOriginRequestsInNetworkPanel() {
+
+    originDisplay.appendChild(Security.SecurityPanel.createHighlightedUrl(origin, originState.securityState));
+
+    var originNetworkButton = titleSection.createChild('div', 'view-network-button');
+    originNetworkButton.appendChild(UI.createTextButton('View requests in Network Panel', e => {
+      e.consume();
       var parsedURL = new Common.ParsedURL(origin);
       Network.NetworkPanel.revealAndFilter([
         {filterType: Network.NetworkLogView.FilterType.Domain, filterValue: parsedURL.host},
         {filterType: Network.NetworkLogView.FilterType.Scheme, filterValue: parsedURL.scheme}
       ]);
-    }
-    originNetworkLink.addEventListener('click', showOriginRequestsInNetworkPanel, false);
+    }, 'origin-button'));
 
     if (originState.securityDetails) {
       var connectionSection = this.element.createChild('div', 'origin-view-section');
@@ -886,8 +888,7 @@
       }
       toggleSctsDetailsLink.addEventListener('click', toggleSctDetailsDisplay, false);
 
-      var noteSection = this.element.createChild('div', 'origin-view-section');
-      // TODO(lgarron): Fix the issue and then remove this section. See comment in SecurityPanel._processRequest().
+      var noteSection = this.element.createChild('div', 'origin-view-section origin-view-notes');
       noteSection.createChild('div').textContent =
           Common.UIString('The security details above are from the first inspected response.');
     } else if (originState.securityState !== Protocol.Security.SecurityState.Unknown) {
diff --git a/third_party/WebKit/Source/devtools/front_end/security/originView.css b/third_party/WebKit/Source/devtools/front_end/security/originView.css
index 23336d1d..8f33025 100644
--- a/third_party/WebKit/Source/devtools/front_end/security/originView.css
+++ b/third_party/WebKit/Source/devtools/front_end/security/originView.css
@@ -4,10 +4,16 @@
  */
 
 .title-section {
-    padding: 12px 0;
+    padding: 16px 0 24px 0;
     border-bottom: 1px solid rgb(230, 230, 230);
 }
 
+.title-section-header {
+    padding-left: 16px;
+    padding-bottom: 10px;
+    font-size: 14px;
+}
+
 .security-origin-view {
     overflow-x: hidden;
     overflow-y: scroll;
@@ -17,30 +23,37 @@
 
 .security-origin-view .origin-view-section {
     border-bottom: 1px solid rgb(230, 230, 230);
-    padding: 12px 6px 12px 18px;
+    padding: 12px 6px 12px  24px;
+    font-size:12px;
+}
+
+.origin-view-notes {
+    margin-top: 2px;
+    color: #8c8c8c;
 }
 
 .security-origin-view .origin-display {
-    font-size: 15px;
+    font-size: 12px;
     padding-left: 38px;
     display: flex;
     align-items: center;
 }
 
-.title-section > .link {
-    padding: 6px 0 0 39px
+.title-section > .view-network-button {
+    padding: 6px 0 0 16px
 }
 
 .security-origin-view .origin-display .security-property {
     display: inline-block;
     vertical-align: middle;
     position: absolute;
-    left: 18px;
+    left: 16px;
 }
 
 .security-origin-view .origin-view-section-title {
-    margin-bottom: 10px;
-    padding-left: 18px;
+    margin-top: 4px;
+    margin-bottom: 4px;
+    font-weight: bold;
 }
 
 .security-origin-view .details-table-row {
@@ -56,7 +69,7 @@
 
 .security-origin-view .details-table-row > div:first-child {
     color: rgb(140, 140, 140);
-    width: 128px;
+    width: 110px;
     margin-right: 1em;
     flex: none;
     display: flex;
@@ -94,6 +107,10 @@
     display: none;
 }
 
-.security-certificate-button {
+.origin-button {
     margin-top: 4px;
 }
+
+.origin-view-section:last-child  {
+    border-bottom:none;
+}
diff --git a/third_party/WebKit/Source/modules/fetch/FetchManager.cpp b/third_party/WebKit/Source/modules/fetch/FetchManager.cpp
index f6c8181d..f530b43 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchManager.cpp
+++ b/third_party/WebKit/Source/modules/fetch/FetchManager.cpp
@@ -598,7 +598,6 @@
   if ((SecurityOrigin::Create(request_->Url())
            ->IsSameSchemeHostPortAndSuborigin(request_->Origin().get())) ||
       (request_->Url().ProtocolIsData() && request_->SameOriginDataURLFlag()) ||
-      (request_->Url().ProtocolIsAbout()) ||
       (request_->Mode() == network::mojom::FetchRequestMode::kNavigate)) {
     // "The result of performing a scheme fetch using request."
     PerformSchemeFetch();
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
index 6890881..36fcdc0 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoadScheduler.cpp
@@ -517,10 +517,6 @@
       ("Blink.ResourceLoadScheduler.PeakRequests.MainframeNotThrottled", 0,
        kMaximumReportSize10K, kReportBucketCount));
   DEFINE_STATIC_LOCAL(
-      CustomCountHistogram, main_frame_partially_throttled,
-      ("Blink.ResourceLoadScheduler.PeakRequests.MainframePartiallyThrottled",
-       0, kMaximumReportSize10K, kReportBucketCount));
-  DEFINE_STATIC_LOCAL(
       CustomCountHistogram, sub_frame_throttled,
       ("Blink.ResourceLoadScheduler.PeakRequests.SubframeThrottled", 0,
        kMaximumReportSize10K, kReportBucketCount));
@@ -528,10 +524,6 @@
       CustomCountHistogram, sub_frame_not_throttled,
       ("Blink.ResourceLoadScheduler.PeakRequests.SubframeNotThrottled", 0,
        kMaximumReportSize10K, kReportBucketCount));
-  DEFINE_STATIC_LOCAL(
-      CustomCountHistogram, sub_frame_partially_throttled,
-      ("Blink.ResourceLoadScheduler.PeakRequests.SubframePartiallyThrottled", 0,
-       kMaximumReportSize10K, kReportBucketCount));
 
   switch (throttling_history_) {
     case ThrottlingHistory::kInitial:
@@ -548,10 +540,6 @@
         sub_frame_throttled.Count(maximum_running_requests_seen_);
       break;
     case ThrottlingHistory::kPartiallyThrottled:
-      if (context_->IsMainFrame())
-        main_frame_partially_throttled.Count(maximum_running_requests_seen_);
-      else
-        sub_frame_partially_throttled.Count(maximum_running_requests_seen_);
       break;
     case ThrottlingHistory::kStopped:
       break;
diff --git a/third_party/WebKit/Source/platform/scheduler/BUILD.gn b/third_party/WebKit/Source/platform/scheduler/BUILD.gn
index 2ba8af3..07466ea 100644
--- a/third_party/WebKit/Source/platform/scheduler/BUILD.gn
+++ b/third_party/WebKit/Source/platform/scheduler/BUILD.gn
@@ -207,6 +207,7 @@
     "//components/viz/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
+    "//third_party/WebKit/public:test_support",
   ]
 
   configs += [ "//third_party/WebKit/Source/platform:blink_platform_config" ]
diff --git a/third_party/WebKit/Source/platform/scheduler/DEPS b/third_party/WebKit/Source/platform/scheduler/DEPS
index 4139e92..b106a03 100644
--- a/third_party/WebKit/Source/platform/scheduler/DEPS
+++ b/third_party/WebKit/Source/platform/scheduler/DEPS
@@ -27,6 +27,7 @@
   "+base/synchronization/cancellation_flag.h",
   "+base/synchronization/lock.h",
   "+base/threading/platform_thread.h",
+  "+base/threading/sequenced_task_runner_handle.h",
   "+base/threading/thread.h",
   "+base/threading/thread_checker.h",
 ]
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
index dde0fa2..272ffe7 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
@@ -31,6 +31,7 @@
 #include "platform/scheduler/base/work_queue_sets.h"
 #include "platform/scheduler/test/test_task_queue.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 using ::testing::AnyNumber;
 using ::testing::Contains;
@@ -125,7 +126,7 @@
     now_src_.Advance(base::TimeDelta::FromMicroseconds(1000));
     manager_ = std::make_unique<TaskQueueManagerForTest>(
         std::make_unique<ThreadControllerForTest>(
-            message_loop_.get(), base::ThreadTaskRunnerHandle::Get(),
+            message_loop_.get(), GetSingleThreadTaskRunnerForTesting(),
             &now_src_));
 
     for (size_t i = 0; i < num_queues; i++)
@@ -225,7 +226,7 @@
 
   manager_ = std::make_unique<TaskQueueManagerForTest>(
       std::make_unique<ThreadControllerForTest>(
-          nullptr, base::ThreadTaskRunnerHandle::Get(),
+          nullptr, GetSingleThreadTaskRunnerForTesting(),
           &test_count_uses_time_source));
   manager_->SetWorkBatchSize(6);
   manager_->AddTaskTimeObserver(&test_task_time_observer_);
diff --git a/third_party/WebKit/Source/platform/scheduler/test/lazy_thread_controller_for_test.cc b/third_party/WebKit/Source/platform/scheduler/test/lazy_thread_controller_for_test.cc
index 1e8ec0dd..2da5a42f 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/lazy_thread_controller_for_test.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/lazy_thread_controller_for_test.cc
@@ -54,7 +54,7 @@
   //       -> LazySchedulerMessageLoopDelegateForTests::AddNestingObserver()
   //   2) Any test framework with a base::MessageLoop member (and not caring
   //      about the blink scheduler) does:
-  //        ThreadTaskRunnerHandle::Get()->PostTask(
+  //        ThreadTaskRunnerHandle::GetForTesting()->PostTask(
   //            FROM_HERE, an_init_task_with_a_nested_loop);
   //        RunLoop.RunUntilIdle();
   //   3) |a_task_with_a_nested_loop| triggers
diff --git a/third_party/WebKit/Source/platform/scheduler/test/renderer_scheduler_test_support.cc b/third_party/WebKit/Source/platform/scheduler/test/renderer_scheduler_test_support.cc
index 7e9d577..0000935 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/renderer_scheduler_test_support.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/renderer_scheduler_test_support.cc
@@ -6,6 +6,8 @@
 
 #include <memory>
 
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "platform/scheduler/renderer/renderer_scheduler_impl.h"
 #include "platform/scheduler/test/lazy_thread_controller_for_test.h"
 
@@ -36,5 +38,14 @@
   scheduler_impl->RunIdleTasksForTesting(callback);
 }
 
+scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunnerForTesting() {
+  return base::SequencedTaskRunnerHandle::Get();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+GetSingleThreadTaskRunnerForTesting() {
+  return base::ThreadTaskRunnerHandle::Get();
+}
+
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h b/third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h
index 6e99ee31..18cc3f7 100644
--- a/third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h
+++ b/third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h
@@ -8,6 +8,11 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 
+namespace base {
+class SequencedTaskRunner;
+class SingleThreadTaskRunner;
+}  // namespace base
+
 namespace blink {
 namespace scheduler {
 
@@ -18,6 +23,17 @@
 void RunIdleTasksForTesting(RendererScheduler* scheduler,
                             const base::Closure& callback);
 
+// Returns a SequencedTaskRunner. This implementation is same as
+// SequencedTaskRunnerHandle::Get(), but this is intended to be used for
+// testing. See crbug.com/794123.
+scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunnerForTesting();
+
+// Returns the SingleThreadTaskRunner for the current thread for testing. This
+// implementation is same as ThreadTaskRunnerHandle::Get(), but this is intended
+// to be used for testing. See crbug.com/794123.
+scoped_refptr<base::SingleThreadTaskRunner>
+GetSingleThreadTaskRunnerForTesting();
+
 }  // namespace scheduler
 }  // namespace blink
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 3a2515d..6a88bbe 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -34473,6 +34473,30 @@
   <int value="10" label="Login action added, Subframe, pw empty"/>
 </enum>
 
+<enum name="PresentAddPassesDialogResult">
+  <summary>
+    Defines the result of Add Passes dialog presentation. The presentation can
+    be successful or unsuccessful if another view controller is currently
+    presented. Unsuccessful presentation is a bug and if the number of
+    unsuccessful presentations is high, it means that Chrome has to queue the
+    dialogs to present those dialogs for every downloaded pkpass (PassKit file).
+    Currently Chrome simply ignores the download if the dialog is already
+    presented.
+  </summary>
+  <int value="0" label="Successful">
+    The dialog was sucessesfully presented.
+  </int>
+  <int value="1" label="Another Add Passes View Controller Is Presented">
+    The dialog cannot be presented, because another PKAddPassesViewController is
+    already presented.
+  </int>
+  <int value="2" label="Another View Controller Is Presented">
+    The dialog cannot be presented, because another view controller is already
+    presented. Does not include items already counted in the more specific
+    bucket (Another Add Passes View Controller Is Presented).
+  </int>
+</enum>
+
 <enum name="PresentationUrlType">
   <int value="0" label="Other"/>
   <int value="1" label="Cast"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 10623c5..21e74403 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -7000,6 +7000,15 @@
   </summary>
 </histogram>
 
+<histogram name="Blink.ResourceLoadScheduler.ThrottlingStateChangeCount"
+    units="changes">
+  <owner>toyoshim@chromium.org</owner>
+  <summary>
+    Count how many times the scheduler has changed throttling status from the
+    frame creation until network activity quiets.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Blink.ResourceLoadScheduler.TotalDecodedBytes"
     units="bytes">
 <!-- Name completed by histogram_suffixes name="ResourceLoadScheduler.FrameType" -->
@@ -17431,11 +17440,16 @@
     enum="DownloadPassKitResult">
   <owner>gchatz@chromium.org</owner>
   <summary>
-    Result when a user attempts to download a PassKit file on iOS with
-    WKWebView.
+    Result when a user attempts to download a PassKit file on iOS.
   </summary>
 </histogram>
 
+<histogram name="Download.IOSPresentAddPassesDialogResult"
+    enum="PresentAddPassesDialogResult">
+  <owner>eugenebut@chromium.org</owner>
+  <summary>Result of an attempt to present Add Passes dialog on iOS.</summary>
+</histogram>
+
 <histogram name="Download.MaliciousDownloadClassified"
     enum="DownloadItem.DangerType">
   <owner>asanka@chromium.org</owner>
@@ -56103,6 +56117,22 @@
   </summary>
 </histogram>
 
+<histogram name="Omnibox.URLNavigationTimeToRedirectToHTTPS" units="ms">
+  <owner>cthomp@chromium.org</owner>
+  <summary>
+    The amount of time, in milliseconds, between the start of a typed URL
+    navigation in the omnibox (the user typing a URL to completion, or selecting
+    a URL from the inline autocomplete or dropdown) and the start of a redirect
+    upgrading the URL to HTTPS. This is only recorded when the upgraded URL is
+    the same except for the scheme and the addition/removal of a
+    &quot;www.&quot; prefix.
+
+    To calculate the percentage of HTTP URL navigations that have been upgraded
+    in this way, divide the count of this histogram by the count for HTTP in
+    Omnibox.URLNavigationScheme.
+  </summary>
+</histogram>
+
 <histogram name="Omnibox.UserTextCleared" enum="OmniboxUserTextCleared">
   <owner>kenjibaheux@chromium.org</owner>
   <owner>mpearson@chromium.org</owner>
@@ -108715,11 +108745,19 @@
   <suffix name="MainframeThrottled" label="Main frame, throttled"/>
   <suffix name="MainframeNotThrottled" label="Main frame, not throttled"/>
   <suffix name="MainframePartiallyThrottled"
-      label="Main frame, partially throttled"/>
+      label="Main frame, partially throttled">
+    <obsolete>
+      This experiment was turned down, see https://crbug.com/768325.
+    </obsolete>
+  </suffix>
   <suffix name="SubframeThrottled" label="Sub frame, throttled"/>
   <suffix name="SubframeNotThrottled" label="Sub frame, not throttled"/>
   <suffix name="SubframePartiallyThrottled"
-      label="Sub frame, partially throttled"/>
+      label="Sub frame, partially throttled">
+    <obsolete>
+      This experiment was turned down, see https://crbug.com/768325.
+    </obsolete>
+  </suffix>
   <affected-histogram name="Blink.ResourceLoadScheduler.DecodedBytes"/>
   <affected-histogram name="Blink.ResourceLoadScheduler.PeakRequests"/>
   <affected-histogram name="Blink.ResourceLoadScheduler.TotalDecodedBytes"/>
diff --git a/tools/perf/benchmarks/battor.py b/tools/perf/benchmarks/battor.py
index a10ae7d8..9ba586c1 100644
--- a/tools/perf/benchmarks/battor.py
+++ b/tools/perf/benchmarks/battor.py
@@ -41,12 +41,6 @@
   def Name(cls):
     return 'battor.trivial_pages'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['charliea@chromium.org'])
 class BattOrSteadyStatePages(_BattOrBenchmark):
@@ -59,10 +53,3 @@
   @classmethod
   def Name(cls):
     return 'battor.steady_state'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('http://abcnews.go.com/', [story.expectations.ALL],
-                          'crbug.com/505990')
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 5f9bcbe..dee404e 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -356,39 +356,11 @@
   tag = 'bindings'
   subdir = 'Bindings'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-            'structured-clone-long-string-serialize.html',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/764868')
-        self.DisableStory(
-            'structured-clone-json-serialize.html',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/764868')
-        self.DisableStory(
-            'structured-clone-long-string-deserialize.html',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/764868')
-        self.DisableStory(
-            'structured-clone-json-deserialize.html',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/764868')
-    return StoryExpectations()
-
-
 @benchmark.Owner(emails=['rune@opera.com'])
 class BlinkPerfCSS(_BlinkPerfBenchmark):
   tag = 'css'
   subdir = 'CSS'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['junov@chromium.org'])
 class BlinkPerfCanvas(_BlinkPerfBenchmark):
@@ -407,27 +379,6 @@
       page.skipped_gpus = []
     return story_set
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark([story.expectations.ANDROID_SVELTE],
-                              'crbug.com/593973')
-        self.DisableStory('putImageData.html',
-            [story.expectations.ANDROID_NEXUS6], 'crbug.com/738453')
-        # pylint: disable=line-too-long
-        self.DisableStory('draw-static-canvas-2d-to-hw-accelerated-canvas-2d.html',
-            [story.expectations.ANDROID_NEXUS6], 'crbug.com/765799')
-        self.DisableStory(
-            'draw-static-canvas-2d-to-hw-accelerated-canvas-2d.html',
-            [story.expectations.ANDROID_NEXUS5,
-             story.expectations.ANDROID_NEXUS5X],
-            'crbug.com/784540')
-        self.DisableStory(
-            'draw-dynamic-canvas-2d-to-hw-accelerated-canvas-2d.html',
-            [story.expectations.ANDROID_NEXUS5,
-             story.expectations.ANDROID_NEXUS5X],
-            'crbug.com/784540')
-    return StoryExpectations()
 
 @benchmark.Owner(emails=['jbroman@chromium.org',
                          'yukishiino@chromium.org',
@@ -436,24 +387,12 @@
   tag = 'dom'
   subdir = 'DOM'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['hayato@chromium.org'])
 class BlinkPerfEvents(_BlinkPerfBenchmark):
   tag = 'events'
   subdir = 'Events'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['cblume@chromium.org'])
 class BlinkPerfImageDecoder(_BlinkPerfBenchmark):
@@ -465,50 +404,24 @@
         '--enable-blink-features=JSImageDecode',
     ])
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['eae@chromium.org'])
 class BlinkPerfLayout(_BlinkPerfBenchmark):
   tag = 'layout'
   subdir = 'Layout'
 
-  def GetExpectations(self):
-    class Expectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark([story.expectations.ANDROID_SVELTE],
-                              'crbug.com/551950')
-    return Expectations()
-
 
 @benchmark.Owner(emails=['dmurph@chromium.org'])
 class BlinkPerfOWPStorage(_BlinkPerfBenchmark):
   tag = 'owp_storage'
   subdir = 'OWPStorage'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['wangxianzhu@chromium.org'])
 class BlinkPerfPaint(_BlinkPerfBenchmark):
   tag = 'paint'
   subdir = 'Paint'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark([story.expectations.ANDROID_SVELTE],
-                              'crbug.com/574483')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['jbroman@chromium.org',
                          'yukishiino@chromium.org',
@@ -517,51 +430,14 @@
   tag = 'parser'
   subdir = 'Parser'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['kouhei@chromium.org', 'fs@opera.com'])
 class BlinkPerfSVG(_BlinkPerfBenchmark):
   tag = 'svg'
   subdir = 'SVG'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('Debian.html', [story.expectations.ANDROID_NEXUS5X],
-                          'crbug.com/736817')
-        self.DisableStory('FlowerFromMyGarden.html',
-                          [story.expectations.ANDROID_NEXUS5X],
-                          'crbug.com/736817')
-        self.DisableStory('HarveyRayner.html',
-                          [story.expectations.ANDROID_NEXUS5X],
-                          'crbug.com/736817')
-        self.DisableStory('SvgCubics.html',
-                          [story.expectations.ANDROID_NEXUS5X],
-                          'crbug.com/736817')
-        self.DisableStory('SvgNestedUse.html',
-                          [story.expectations.ANDROID_NEXUS5X],
-                          'crbug.com/736817')
-        self.DisableStory('Worldcup.html', [story.expectations.ANDROID_NEXUS5X],
-                          'crbug.com/736817')
-        self.DisableStory('CrawFishGanson.html',
-                          [story.expectations.ANDROID_NEXUS5X],
-                          'crbug.com/736817')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['hayato@chromium.org'])
 class BlinkPerfShadowDOM(_BlinkPerfBenchmark):
   tag = 'shadow_dom'
   subdir = 'ShadowDOM'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark([story.expectations.ANDROID_NEXUS5X],
-                              'crbug.com/702319')
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/dummy_benchmark.py b/tools/perf/benchmarks/dummy_benchmark.py
index 3a5bac49..e47de0d3 100644
--- a/tools/perf/benchmarks/dummy_benchmark.py
+++ b/tools/perf/benchmarks/dummy_benchmark.py
@@ -13,7 +13,6 @@
 from core import perf_benchmark
 
 from telemetry import benchmark
-from telemetry import story
 from telemetry.value import scalar
 from telemetry.page import legacy_page_test
 from telemetry.web_perf import timeline_based_measurement
@@ -52,12 +51,6 @@
   def Name(cls):
     return 'dummy_benchmark.stable_benchmark_1'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['nednguyen@google.com'])
 class DummyBenchmarkTwo(_DummyBenchmark):
@@ -70,12 +63,6 @@
   def Name(cls):
     return 'dummy_benchmark.noisy_benchmark_1'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['eakuefner@chromium.org', 'simonhatch@chromium.org'])
 class DummyBenchmarkThree(perf_benchmark.PerfBenchmark):
@@ -91,9 +78,3 @@
   @classmethod
   def Name(cls):
     return 'dummy_benchmark.histogram_benchmark_1'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark([story.expectations.ALL], 'crbug.com/756210')
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/jetstream.py b/tools/perf/benchmarks/jetstream.py
index ca321c2..7ca80257 100644
--- a/tools/perf/benchmarks/jetstream.py
+++ b/tools/perf/benchmarks/jetstream.py
@@ -93,9 +93,3 @@
         make_javascript_deterministic=False,
         name='http://browserbench.org/JetStream/'))
     return ps
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # http://browserbench.org/JetStream/ not disabled.
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/kraken.py b/tools/perf/benchmarks/kraken.py
index cb66aa7..bfa6854c 100644
--- a/tools/perf/benchmarks/kraken.py
+++ b/tools/perf/benchmarks/kraken.py
@@ -124,9 +124,3 @@
         ps, ps.base_dir,
         name='http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html'))
     return ps
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # http://krakenbenchmark.mozilla.org/kraken-1.1/ not disabled
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/loading.py b/tools/perf/benchmarks/loading.py
index f153acff1..f25efc9 100644
--- a/tools/perf/benchmarks/loading.py
+++ b/tools/perf/benchmarks/loading.py
@@ -51,49 +51,6 @@
                                     cache_temperature.HOT],
         traffic_settings=[traffic_setting.NONE, traffic_setting.REGULAR_3G])
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark(
-            [story.expectations.ANDROID_NEXUS6_WEBVIEW], 'crbug.com/676612')
-        self.DisableStory('GFK', [story.expectations.ALL],
-                          'N5X Timeout issue: crbug.com/702175')
-        self.DisableStory('MLSMatrix', [story.expectations.ALL],
-                          'N5XTimeout issue: crbug.com/702175')
-        self.DisableStory('EBS', [story.expectations.ALL],
-                          'N5XTimeout issue: crbug.com/702175')
-        self.DisableStory('IBI', [story.expectations.ALL],
-                          'N5XTimeout issue: crbug.com/702175')
-        self.DisableStory('SBS', [story.expectations.ALL],
-                          'N5XTimeout issue: crbug.com/702175')
-        self.DisableStory('FuturaSciences', [story.expectations.ALL],
-                          'N5XTimeout issue: crbug.com/702175')
-        self.DisableStory('HashOcean', [story.expectations.ALL],
-                          'N5XTimeout issue: crbug.com/702175')
-        self.DisableStory('163', [story.expectations.ALL],
-                          'N5XTimeout issue: crbug.com/702175')
-        self.DisableStory('G1', [story.expectations.ALL], 'crbug.com/656861')
-        self.DisableStory('Dramaq', [story.expectations.ANDROID_NEXUS5X],
-                          'Test Failure: crbug.com/750747')
-        self.DisableStory('Hongkiat', [story.expectations.ANDROID_NEXUS5X],
-                          'Test Failure: crbug.com/750747')
-        self.DisableStory('Facebook', [story.expectations.ANDROID_NEXUS7],
-                          'Nexus7v2 Timeout: crbug.com/759861')
-        self.DisableStory('GoogleRedirectToGoogleJapan',
-                          [story.expectations.ANDROID_ONE], 'crbug.com/776092')
-        # TODO(rnephew): Uncomment Disablings. crbug.com/728882
-        # self.DisableStory(
-        #     'AirHorner', [story.expectations.ALL], 'crbug.com/653775')
-        # self.DisableStory(
-        #     'BusRouter', [story.expectations.ALL], 'crbug.com/653775')
-        # self.DisableStory('WikiOffline', [story.expectations.ALL],
-        #                   'crbug.com/653775')
-        # self.DisableStory(
-        #     'Detik', [story.expectations.ALL], 'crbug.com/653775')
-        # self.DisableStory(
-        #     'Blogspot', [story.expectations.ALL], 'crbug.com/653775')
-    return StoryExpectations()
-
   @classmethod
   def Name(cls):
     return 'loading.mobile'
diff --git a/tools/perf/benchmarks/media.py b/tools/perf/benchmarks/media.py
index 31d33dd..04643254 100644
--- a/tools/perf/benchmarks/media.py
+++ b/tools/perf/benchmarks/media.py
@@ -76,12 +76,6 @@
   def Name(cls):
     return 'media.desktop'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-    return StoryExpectations()
-
 
 # If any story is failing on svelte, please only disable on svelte.
 @benchmark.Owner(emails=['johnchen@chromium.org', 'crouleau@chromium.org'],
@@ -97,12 +91,6 @@
   def Name(cls):
     return 'media.mobile'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-    return StoryExpectations()
-
   def SetExtraBrowserOptions(self, options):
     # By default, Chrome on Android does not allow autoplay
     # of media: it requires a user gesture event to start a video.
diff --git a/tools/perf/benchmarks/memory.py b/tools/perf/benchmarks/memory.py
index 21b0f3c..6c858bd 100644
--- a/tools/perf/benchmarks/memory.py
+++ b/tools/perf/benchmarks/memory.py
@@ -105,12 +105,6 @@
   def ValueCanBeAddedPredicate(cls, value, is_first_result):
     return DefaultValueCanBeAddedPredicateForMemoryMeasurement(value)
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['perezju@chromium.org'])
 class MemoryBenchmarkTop10Mobile(_MemoryInfra):
@@ -131,12 +125,6 @@
   def ValueCanBeAddedPredicate(cls, value, is_first_result):
     return DefaultValueCanBeAddedPredicateForMemoryMeasurement(value)
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-    return StoryExpectations()
-
 
 class _MemoryV8Benchmark(_MemoryInfra):
 
@@ -181,14 +169,6 @@
   def Name(cls):
     return 'memory.long_running_idle_gmail_tbmv2'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark(
-            [story.expectations.ANDROID_SVELTE],
-            'Requires a lot of memory: crbug.com/611167')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['ulan@chromium.org'])
 class MemoryLongRunningIdleGmailBackground(_MemoryV8Benchmark):
@@ -203,11 +183,3 @@
   @classmethod
   def Name(cls):
     return 'memory.long_running_idle_gmail_background_tbmv2'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark(
-            [story.expectations.ANDROID_SVELTE],
-            'Requires a lot of memory: crbug.com/616530')
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/octane.py b/tools/perf/benchmarks/octane.py
index 03b7154..e4de4b67 100644
--- a/tools/perf/benchmarks/octane.py
+++ b/tools/perf/benchmarks/octane.py
@@ -139,11 +139,3 @@
         ps, ps.base_dir, make_javascript_deterministic=False,
         name='http://chromium.github.io/octane/index.html?auto=1'))
     return ps
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-            'http://chromium.github.io/octane/index.html?auto=1',
-            [story.expectations.ANDROID_ONE], 'http://crbug.com/764875')
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/oortonline.py b/tools/perf/benchmarks/oortonline.py
index 1265fde..81698448 100644
--- a/tools/perf/benchmarks/oortonline.py
+++ b/tools/perf/benchmarks/oortonline.py
@@ -8,7 +8,6 @@
 
 from core import perf_benchmark
 from telemetry import benchmark
-from telemetry import story
 from telemetry.timeline import chrome_trace_category_filter
 from telemetry.timeline import chrome_trace_config
 from telemetry.web_perf import timeline_based_measurement
@@ -29,12 +28,6 @@
 
   page_set = page_sets.OortOnlineTBMPageSet
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # http://oortonline.gl/#run not disabled.
-    return StoryExpectations()
-
   def CreateCoreTimelineBasedMeasurementOptions(self):
     categories = [
       # Implicitly disable all categories.
diff --git a/tools/perf/benchmarks/power.py b/tools/perf/benchmarks/power.py
index 2b3d259..d2c37b0b 100644
--- a/tools/perf/benchmarks/power.py
+++ b/tools/perf/benchmarks/power.py
@@ -26,12 +26,6 @@
   def Name(cls):
     return 'power.typical_10_mobile'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['charliea@chromium.org', 'rnephew@chromium.org'])
 class IdlePlatformBenchmark(perf_benchmark.PerfBenchmark):
@@ -62,13 +56,3 @@
   @classmethod
   def Name(cls):
     return 'power.idle_platform'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark(
-            [story.expectations.ANDROID_NEXUS5,
-             story.expectations.ANDROID_NEXUS6,
-             story.expectations.ANDROID_NEXUS7,
-             story.expectations.ANDROID_ONE], 'crbug.com/773949')
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/rasterize_and_record_micro.py b/tools/perf/benchmarks/rasterize_and_record_micro.py
index f6e09e0..5737d350a6 100644
--- a/tools/perf/benchmarks/rasterize_and_record_micro.py
+++ b/tools/perf/benchmarks/rasterize_and_record_micro.py
@@ -7,7 +7,6 @@
 from measurements import rasterize_and_record_micro
 import page_sets
 from telemetry import benchmark
-from telemetry import story
 
 
 class _RasterizeAndRecordMicro(perf_benchmark.PerfBenchmark):
@@ -57,24 +56,6 @@
   def Name(cls):
     return 'rasterize_and_record_micro.top_25'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        # Should a story need to be disabled, note that story names
-        # for the static top 25 page set used by this benchmark are of
-        # the format "file://static_top_25/page.html" where
-        # "page.html" is substituted with the actual story's static
-        # html filename as found under
-        # tools/perf/page_sets/static_top_25.
-        self.DisableStory(
-            'file://static_top_25/wikipedia.html', [story.expectations.ALL],
-            'crbug.com/764543')
-        self.DisableStory(
-            'file://static_top_25/espn.html', [story.expectations.ANDROID_ONE],
-            'crbug.com/768010')
-
-    return StoryExpectations()
-
 
 @benchmark.Owner(
     emails=['vmpstr@chromium.org', 'wkorman@chromium.org'],
@@ -88,9 +69,3 @@
   @classmethod
   def Name(cls):
     return 'rasterize_and_record_micro.partial_invalidation'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
index ad43ff1..57731120 100644
--- a/tools/perf/benchmarks/smoothness.py
+++ b/tools/perf/benchmarks/smoothness.py
@@ -48,35 +48,6 @@
   def Name(cls):
     return 'smoothness.top_25_smooth'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('http://www.cnn.com', [story_module.expectations.ALL],
-                          'crbug.com/528474')
-        self.DisableStory('http://www.amazon.com',
-                          [story_module.expectations.ALL],
-                          'crbug.com/667432')
-        self.DisableStory('https://mail.google.com/mail/',
-                          [story_module.expectations.ALL_WIN],
-                          'crbug.com/750147')
-        self.DisableStory('Docs_(1_open_document_tab)',
-                          [story_module.expectations.ALL_WIN],
-                          'crbug.com/762165')
-        self.DisableStory('http://www.youtube.com',
-                          [story_module.expectations.ALL_WIN],
-                          'crbug.com/762165')
-        self.DisableStory('https://plus.google.com/110031535020051778989/posts',
-                          [story_module.expectations.ALL_WIN],
-                          'crbug.com/762165')
-        self.DisableStory('https://www.google.com/calendar/',
-                          [story_module.expectations.ALL_WIN],
-                          'crbug.com/762165')
-        self.DisableStory('https://www.google.com/search?q=cats&tbm=isch',
-                          [story_module.expectations.ALL_WIN],
-                          'crbug.com/762165')
-
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['senorblanco@chromium.org'])
 class SmoothnessToughFiltersCases(_Smoothness):
@@ -102,12 +73,6 @@
   def Name(cls):
     return 'smoothness.tough_path_rendering_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['junov@chromium.org'])
 class SmoothnessToughCanvasCases(_Smoothness):
@@ -124,34 +89,6 @@
   def Name(cls):
     return 'smoothness.tough_canvas_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        # TODO(rnephew): Uncomment out after story is added back to set after
-        # rerecording.
-        # self.DisableStory(
-        #     'http://ie.microsoft.com/testdrive/Performance/Fireflies/Default.'
-        #     'html', [story_module.expectations.ALL], 'crbug.com/314131')
-
-        # pylint: disable=line-too-long
-        self.DisableStory('http://geoapis.appspot.com/agdnZW9hcGlzchMLEgtFeGFtcGxlQ29kZRjh1wIM',
-                          [story_module.expectations.ANDROID_NEXUS5],
-                          'crbug.com/364248')
-        self.DisableStory('tough_canvas_cases/canvas_toBlob.html',
-                          [story_module.expectations.ANDROID_ONE],
-                          'crbug.com/755657')
-        self.DisableStory('http://www.kevs3d.co.uk/dev/canvask3d/k3d_test.html',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785485')
-        self.DisableStory('http://www.effectgames.com/demos/canvascycle/',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785286')
-        self.DisableStory('http://www.smashcat.org/av/canvas_test/',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785286')
-
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['kbr@chromium.org', 'zmo@chromium.org'])
 class SmoothnessToughWebGLCases(_Smoothness):
@@ -161,12 +98,6 @@
   def Name(cls):
     return 'smoothness.tough_webgl_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['kbr@chromium.org', 'zmo@chromium.org'])
 class SmoothnessMaps(_Smoothness):
@@ -176,15 +107,6 @@
   def Name(cls):
     return 'smoothness.maps'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-            'maps_perf_test',
-            [story_module.expectations.ANDROID_WEBVIEW],
-            'crbug.com/653993')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['ssid@chromium.org'])
 class SmoothnessKeyDesktopMoveCases(_Smoothness):
@@ -195,17 +117,6 @@
   def Name(cls):
     return 'smoothness.key_desktop_move_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('https://mail.google.com/mail/',
-                          [story_module.expectations.ALL_WIN],
-                          'crbug.com/750131')
-        self.DisableStory('https://mail.google.com/mail/',
-                          [story_module.expectations.ALL_MAC],
-                          'crbug.com/770904')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['vmiura@chromium.org', 'tdresser@chromium.org'])
 class SmoothnessKeyMobileSites(_Smoothness):
@@ -220,15 +131,6 @@
   def Name(cls):
     return 'smoothness.key_mobile_sites_smooth'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-            'http://digg.com',
-            [story_module.expectations.ALL_ANDROID],
-            'crbug.com/756119')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['alancutter@chromium.org'])
 class SmoothnessToughAnimationCases(_Smoothness):
@@ -238,26 +140,6 @@
   def Name(cls):
     return 'smoothness.tough_animation_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('robohornetpro', [story_module.expectations.ALL],
-                          'crbug.com/350692')
-        self.DisableStory(
-            'balls_css_keyframe_animations_composited_transform.html',
-            [story_module.expectations.ALL_MOBILE],
-            'crbug.com/755556')
-        self.DisableStory(
-            'mix_blend_mode_animation_difference.html',
-            [story_module.expectations.ALL_MAC],
-            'crbug.com/755556')
-        self.DisableStory(
-            'mix_blend_mode_animation_hue.html',
-            [story_module.expectations.ALL_MAC],
-            'crbug.com/755556')
-
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['ajuma@chromium.org'])
 class SmoothnessKeySilkCases(_Smoothness):
@@ -280,19 +162,6 @@
       stories.RemoveStory(story)
     return stories
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-            'inbox_app.html?slide_drawer', [story_module.expectations.ALL],
-            'Story contains multiple interaction records. Not supported in '
-            'smoothness benchmarks.')
-        self.DisableStory(
-            'https://polymer-topeka.appspot.com/',
-            [story_module.expectations.ALL],
-            'crbug.com/780525')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['vmiura@chromium.org'])
 class SmoothnessGpuRasterizationTop25(_Smoothness):
@@ -310,18 +179,6 @@
   def Name(cls):
     return 'smoothness.gpu_rasterization.top_25_smooth'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('http://www.cnn.com', [story_module.expectations.ALL],
-                          'crbug.com/528474')
-        self.DisableStory('http://www.amazon.com',
-                          [story_module.expectations.ALL],
-                          'crbug.com/667432')
-        self.DisableStory('Pinterest', [story_module.expectations.ALL],
-                          'crbug.com/667432')
-    return StoryExpectations()
-
 
 # Although GPU rasterization is enabled on Mac, it is blacklisted for certain
 # path cases, so it is still valuable to run both the GPU and non-GPU versions
@@ -341,12 +198,6 @@
   def Name(cls):
     return 'smoothness.gpu_rasterization.tough_path_rendering_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['senorblanco@chromium.org'])
 class SmoothnessGpuRasterizationFiltersCases(_Smoothness):
@@ -371,12 +222,6 @@
   def Name(cls):
     return 'smoothness.gpu_rasterization.tough_filters_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['tdresser@chromium.org', 'rbyers@chromium.org'])
 class SmoothnessSyncScrollKeyMobileSites(_Smoothness):
@@ -394,15 +239,6 @@
   def Name(cls):
     return 'smoothness.sync_scroll.key_mobile_sites_smooth'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-            'http://digg.com',
-            [story_module.expectations.ALL],
-            'crbug.com/756119')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['vmiura@chromium.org'])
 class SmoothnessSimpleMobilePages(_Smoothness):
@@ -415,14 +251,6 @@
   def Name(cls):
     return 'smoothness.simple_mobile_sites'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('https://www.flickr.com/',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/750833')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['bokan@chromium.org'])
 class SmoothnessToughPinchZoomCases(_Smoothness):
@@ -436,65 +264,6 @@
   def Name(cls):
     return 'smoothness.tough_pinch_zoom_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('https://www.google.com/#hl=en&q=barack+obama',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('https://mail.google.com/mail/',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('https://www.google.com/calendar/',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('https://www.google.com/search?q=cats&tbm=isch',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('http://www.youtube.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('Blogger',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('Facebook',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('LinkedIn',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('Twitter',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('ESPN',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('http://news.yahoo.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('http://www.cnn.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('Weather.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('http://www.amazon.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('http://www.ebay.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('http://games.yahoo.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('http://booking.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-        self.DisableStory('http://sports.yahoo.com/',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/631015')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['ericrk@chromium.org'])
 class SmoothnessDesktopToughPinchZoomCases(_Smoothness):
@@ -508,12 +277,6 @@
   def Name(cls):
     return 'smoothness.desktop_tough_pinch_zoom_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass  # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['ericrk@chromium.org'])
 class SmoothnessGpuRasterizationToughPinchZoomCases(_Smoothness):
@@ -532,63 +295,6 @@
   def Name(cls):
     return 'smoothness.gpu_rasterization.tough_pinch_zoom_cases'
 
-  def GetExpectations(self):
-
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-
-      def SetExpectations(self):
-        self.DisableStory('https://www.google.com/#hl=en&q=barack+obama',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('https://mail.google.com/mail/',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('https://www.google.com/calendar/',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('https://www.google.com/search?q=cats&tbm=isch',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('http://www.youtube.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('Blogger', [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('Facebook', [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('LinkedIn', [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('Twitter', [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('ESPN', [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('http://news.yahoo.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('http://www.cnn.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('Weather.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('http://www.amazon.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('http://www.ebay.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('http://games.yahoo.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('http://booking.com',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-        self.DisableStory('http://sports.yahoo.com/',
-                          [story_module.expectations.ALL_ANDROID],
-                          'crbug.com/610021')
-
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['vmiura@chromium.org'])
 class SmoothnessGpuRasterizationPolymer(_Smoothness):
@@ -604,14 +310,6 @@
   def Name(cls):
     return 'smoothness.gpu_rasterization.polymer'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark(
-            [story_module.expectations.ALL],
-            'Mobile Benchmark that needs modernization. Crbug.com/750876')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['reveman@chromium.org'])
 class SmoothnessToughScrollingCases(_Smoothness):
@@ -629,41 +327,6 @@
   def Name(cls):
     return 'smoothness.tough_scrolling_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('canvas_05000_pixels_per_second',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785473')
-        self.DisableStory('canvas_10000_pixels_per_second',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785473')
-        self.DisableStory('canvas_15000_pixels_per_second',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785473')
-        self.DisableStory('canvas_20000_pixels_per_second',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785473')
-        self.DisableStory('canvas_30000_pixels_per_second',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785473')
-        self.DisableStory('canvas_40000_pixels_per_second',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785473')
-        self.DisableStory('canvas_50000_pixels_per_second',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785473')
-        self.DisableStory('canvas_60000_pixels_per_second',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785473')
-        self.DisableStory('canvas_75000_pixels_per_second',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785473')
-        self.DisableStory('canvas_90000_pixels_per_second',
-                          [story_module.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/785473')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['ericrk@chromium.org'])
 class SmoothnessGpuRasterizationToughScrollingCases(_Smoothness):
@@ -678,12 +341,6 @@
   def Name(cls):
     return 'smoothness.gpu_rasterization.tough_scrolling_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing.
-    return StoryExpectations()
-
 
 class SmoothnessToughImageDecodeCases(_Smoothness):
   page_set = page_sets.ToughImageDecodeCasesPageSet
@@ -692,12 +349,6 @@
   def Name(cls):
     return 'smoothness.tough_image_decode_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['cblume@chromium.org'])
 class SmoothnessImageDecodingCases(_Smoothness):
@@ -713,12 +364,6 @@
   def Name(cls):
     return 'smoothness.image_decoding_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['cblume@chromium.org'])
 class SmoothnessGpuImageDecodingCases(_Smoothness):
@@ -736,12 +381,6 @@
   def Name(cls):
     return 'smoothness.gpu_rasterization_and_decoding.image_decoding_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['picksi@chromium.org'])
 class SmoothnessPathologicalMobileSites(_Smoothness):
@@ -754,13 +393,6 @@
   def Name(cls):
     return 'smoothness.pathological_mobile_sites'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark([story_module.expectations.ANDROID_NEXUS7],
-                              'crbug.com/685342')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['vmiura@chromium.org'])
 class SmoothnessToughTextureUploadCases(_Smoothness):
@@ -770,14 +402,6 @@
   def Name(cls):
     return 'smoothness.tough_texture_upload_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('extra_large_texture_uploads.html',
-                          [story_module.expectations.ANDROID_ONE],
-                          'crbug.com/795060')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['skyostil@chromium.org'])
 class SmoothnessToughAdCases(_Smoothness):
@@ -794,13 +418,6 @@
     # These pages don't scroll so it's not necessary to measure input latency.
     return value.name != 'first_gesture_scroll_update_latency'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark([story_module.expectations.ANDROID_SVELTE],
-                              'www.crbug.com/555089')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['skyostil@chromium.org'])
 class SmoothnessToughWebGLAdCases(_Smoothness):
@@ -811,13 +428,6 @@
   def Name(cls):
     return 'smoothness.tough_webgl_ad_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story_module.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark([story_module.expectations.ANDROID_SVELTE],
-                              'crbug.com/574485')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['skyostil@chromium.org', 'brianderson@chromium.org'])
 class SmoothnessToughSchedulingCases(_Smoothness):
diff --git a/tools/perf/benchmarks/speedometer.py b/tools/perf/benchmarks/speedometer.py
index d8cda4a..c51058d 100644
--- a/tools/perf/benchmarks/speedometer.py
+++ b/tools/perf/benchmarks/speedometer.py
@@ -114,12 +114,6 @@
         name='http://browserbench.org/Speedometer/'))
     return ps
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # http://browserbench.org/Speedometer/ not disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['hablich@chromium.org'])
 class V8SpeedometerFuture(Speedometer):
diff --git a/tools/perf/benchmarks/speedometer2.py b/tools/perf/benchmarks/speedometer2.py
index d53858d..81bb0315 100644
--- a/tools/perf/benchmarks/speedometer2.py
+++ b/tools/perf/benchmarks/speedometer2.py
@@ -111,11 +111,3 @@
 
   def SetExtraBrowserOptions(self, options):
     options.AppendExtraBrowserArgs('--enable-features=V8VmFuture')
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('Speedometer2',
-            [story.expectations.ALL_LINUX], 'crbug.com/792495')
-
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index 533c0c0..b04cca2 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -71,9 +71,6 @@
   def Name(cls):
     return 'system_health.common_desktop'
 
-  def GetExpectations(self):
-    return page_sets.SystemHealthDesktopCommonExpectations()
-
 
 @benchmark.Owner(emails=['charliea@chromium.org', 'nednguyen@chromium.org'])
 class MobileCommonSystemHealth(_CommonSystemHealthBenchmark):
@@ -85,9 +82,6 @@
   def Name(cls):
     return 'system_health.common_mobile'
 
-  def GetExpectations(self):
-    return page_sets.SystemHealthMobileCommonExpectations()
-
 
 class _MemorySystemHealthBenchmark(perf_benchmark.PerfBenchmark):
   """Chrome Memory System Health Benchmark.
@@ -175,9 +169,6 @@
   def CreateStorySet(self, options):
     return page_sets.SystemHealthBlankStorySet()
 
-  def GetExpectations(self):
-    return page_sets.SystemHealthWebviewStartupExpectations()
-
   def CreateCoreTimelineBasedMeasurementOptions(self):
     options = timeline_based_measurement.Options()
     options.SetTimelineBasedMetrics(['webviewStartupMetric'])
diff --git a/tools/perf/benchmarks/tab_switching.py b/tools/perf/benchmarks/tab_switching.py
index 0765737..a6fcfa36 100644
--- a/tools/perf/benchmarks/tab_switching.py
+++ b/tools/perf/benchmarks/tab_switching.py
@@ -42,10 +42,3 @@
   @classmethod
   def Name(cls):
     return 'tab_switching.typical_25'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('multitab:misc:typical24',
-                          [story.expectations.ALL_MAC], 'crbug.com/747026')
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/thread_times.py b/tools/perf/benchmarks/thread_times.py
index 4150696..65200a3b 100644
--- a/tools/perf/benchmarks/thread_times.py
+++ b/tools/perf/benchmarks/thread_times.py
@@ -45,23 +45,6 @@
   def Name(cls):
     return 'thread_times.key_silk_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('https://polymer-topeka.appspot.com/',
-                          [story.expectations.ALL], 'crbug.com/507865')
-        self.DisableStory('http://plus.google.com/app/basic/stream',
-                          [story.expectations.ALL], 'crbug.com/338838')
-        self.DisableStory('inbox_app.html?slide_drawer',
-                          [story.expectations.ALL], 'crbug.com/446332')
-        self.DisableStory('http://s.codepen.io/befamous/fullpage/pFsqb?scroll',
-                          [story.expectations.ALL], 'crbug.com/764825')
-        self.DisableStory('inbox_app.html?swipe_to_dismiss',
-                          [story.expectations.ALL], 'crbug.com/764825')
-        self.DisableStory('masonry.html',
-                          [story.expectations.ALL], 'crbug.com/764825')
-    return StoryExpectations()
-
 
 class ThreadTimesKeyHitTestCases(_ThreadTimes):
   """Measure timeline metrics while performing smoothness action on key hit
@@ -75,15 +58,6 @@
   def Name(cls):
     return 'thread_times.key_hit_test_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark(
-            [story.expectations.ALL],
-            'Disabled on all platforms due to use of deprecated web platform '
-            'features. Crbug.com/750876.')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['vmiura@chromium.org'])
 class ThreadTimesKeyMobileSitesSmooth(_ThreadTimes):
@@ -98,21 +72,6 @@
   def Name(cls):
     return 'thread_times.key_mobile_sites_smooth'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-        # TODO(rnephew): Uncomment when these stories is rerecorded.
-        # self.DisableStory(
-        #     'http://forecast.io', [story.expectations.ALL],
-        #     'crbug.com/249736')
-        # self.DisableStory(
-        #    'Twitter', [story.expectations.ALL],
-        #    'Forbidden (Rate Limit Exceeded)')
-        # self.DisableStory('ESPN', [story.expectations.ALL],
-        #                   'crbug.com/249722')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['vmiura@chromium.org'])
 class ThreadTimesSimpleMobileSites(_ThreadTimes):
@@ -125,13 +84,6 @@
   def Name(cls):
     return 'thread_times.simple_mobile_sites'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('https://www.flickr.com/', [story.expectations.ALL],
-                          'crbug.com/752228')
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['vmiura@chromium.org'])
 class ThreadTimesCompositorCases(_ThreadTimes):
@@ -149,12 +101,6 @@
   def Name(cls):
     return 'thread_times.tough_compositor_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['skyostil@chromium.org'])
 class ThreadTimesKeyIdlePowerCases(_ThreadTimes):
@@ -172,12 +118,6 @@
     # Only report per-second metrics.
     return 'per_frame' not in value.name and 'mean_frame' not in value.name
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-    return StoryExpectations()
-
 
 class ThreadTimesKeyNoOpCases(_ThreadTimes):
   """Measures timeline metrics for common interactions and behaviors that should
@@ -194,12 +134,6 @@
     # Only report per-second metrics.
     return 'per_frame' not in value.name and 'mean_frame' not in value.name
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['tdresser@chromium.org'])
 class ThreadTimesToughScrollingCases(_ThreadTimes):
@@ -210,38 +144,3 @@
   @classmethod
   def Name(cls):
     return 'thread_times.tough_scrolling_cases'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('canvas_05000_pixels_per_second',
-                          [story.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/783362')
-        self.DisableStory('canvas_10000_pixels_per_second',
-                          [story.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/783362')
-        self.DisableStory('canvas_15000_pixels_per_second',
-                          [story.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/783362')
-        self.DisableStory('canvas_20000_pixels_per_second',
-                          [story.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/783362')
-        self.DisableStory('canvas_30000_pixels_per_second',
-                          [story.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/783362')
-        self.DisableStory('canvas_40000_pixels_per_second',
-                          [story.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/783362')
-        self.DisableStory('canvas_50000_pixels_per_second',
-                          [story.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/783362')
-        self.DisableStory('canvas_60000_pixels_per_second',
-                          [story.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/783362')
-        self.DisableStory('canvas_75000_pixels_per_second',
-                          [story.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/783362')
-        self.DisableStory('canvas_90000_pixels_per_second',
-                          [story.expectations.ANDROID_WEBVIEW],
-                          'crbug.com/783362')
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/tracing.py b/tools/perf/benchmarks/tracing.py
index eb3d431..092388cc 100644
--- a/tools/perf/benchmarks/tracing.py
+++ b/tools/perf/benchmarks/tracing.py
@@ -5,7 +5,6 @@
 from core import perf_benchmark
 
 from telemetry import benchmark
-from telemetry import story
 from telemetry.timeline import chrome_trace_category_filter
 from telemetry.timeline import chrome_trace_config
 from telemetry.web_perf import timeline_based_measurement
@@ -33,9 +32,3 @@
   @classmethod
   def Name(cls):
     return 'tracing.tracing_with_background_memory_infra'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/v8.py b/tools/perf/benchmarks/v8.py
index 91ca652..f4e807d0 100644
--- a/tools/perf/benchmarks/v8.py
+++ b/tools/perf/benchmarks/v8.py
@@ -8,7 +8,6 @@
 import page_sets
 
 from telemetry import benchmark
-from telemetry import story
 from telemetry.timeline import chrome_trace_category_filter
 from telemetry.web_perf import timeline_based_measurement
 
@@ -25,14 +24,6 @@
   def Name(cls):
     return 'v8.detached_context_age_in_gc'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('Docs_(1_open_document_tab)',
-                          [story.expectations.ALL_WIN],
-                          'crbug.com/770982')
-    return StoryExpectations()
-
 
 class _Top25RuntimeStats(perf_benchmark.PerfBenchmark):
   def SetExtraBrowserOptions(self, options):
@@ -87,11 +78,3 @@
 
   def CreateStorySet(self, options):
     return page_sets.V8Top25StorySet()
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark(
-            [story.expectations.ALL_ANDROID, story.expectations.ALL_WIN],
-            'crbug.com/664318')
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/v8_browsing.py b/tools/perf/benchmarks/v8_browsing.py
index d56565672..e637e51 100644
--- a/tools/perf/benchmarks/v8_browsing.py
+++ b/tools/perf/benchmarks/v8_browsing.py
@@ -107,27 +107,6 @@
   PLATFORM = 'desktop'
   SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP]
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-             'browse:news:hackernews',
-             [story.expectations.ALL_WIN, story.expectations.ALL_MAC],
-             'crbug.com/676336')
-        self.DisableStory(
-             'browse:news:cnn',
-             [story.expectations.ALL_MAC],
-             'mac:crbug.com/728576')
-        self.DisableStory(
-             'browse:tools:maps',
-             [story.expectations.ALL_MAC],
-             'crbug.com/773084')
-        self.DisableStory(
-             'browse:media:imgur',
-             [story.expectations.ALL_LINUX],
-             'crbug.com/788796')
-    return StoryExpectations()
-
   def SetExtraBrowserOptions(self, options):
     options.AppendExtraBrowserArgs(
       '--enable-blink-features=BlinkRuntimeCallStats')
@@ -147,52 +126,6 @@
     options.AppendExtraBrowserArgs(
       '--enable-blink-features=BlinkRuntimeCallStats')
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark(
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/788797')
-        self.DisableStory(
-            'browse:shopping:avito',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/767970')
-        self.DisableStory(
-            'browse:news:cnn',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/767970')
-        self.DisableStory(
-            'browse:tech:discourse_infinite_scroll',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/767970')
-        self.DisableStory(
-            'browse:shopping:lazada',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/768472')
-        self.DisableStory(
-            'browse:shopping:flipkart',
-            [story.expectations.ALL_MOBILE],
-            'crbug.com/767970, crbug.com/708300')
-        self.DisableStory(
-             'browse:news:globo',
-             [story.expectations.ALL_ANDROID],
-             'crbug.com/714650')
-        self.DisableStory(
-             'browse:news:toi',
-             [story.expectations.ALL_ANDROID],
-             'crbug.com/728081')
-        # TODO(rnephew): This disabling should move to CanRunOnBrowser.
-        self.DisableStory(
-             'browse:chrome:omnibox',
-             [story.expectations.ANDROID_WEBVIEW],
-             'Webview does not have omnibox')
-        # TODO(rnephew): This disabling should move to CanRunOnBrowser.
-        self.DisableStory(
-             'browse:chrome:newtab',
-             [story.expectations.ANDROID_WEBVIEW],
-             'Webview does not have NTP')
-    return StoryExpectations()
-
   @classmethod
   def Name(cls):
     return 'v8.browsing_mobile'
@@ -204,27 +137,6 @@
   PLATFORM = 'desktop'
   SUPPORTED_PLATFORMS = [story.expectations.ALL_DESKTOP]
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-             'browse:news:hackernews',
-             [story.expectations.ALL_WIN, story.expectations.ALL_MAC],
-             'crbug.com/676336')
-        self.DisableStory(
-             'browse:news:cnn',
-             [story.expectations.ALL_MAC],
-             'mac:crbug.com/728576')
-        self.DisableStory(
-             'browse:tools:maps',
-             [story.expectations.ALL_MAC],
-             'crbug.com/773084')
-        self.DisableStory(
-             'browse:media:imgur',
-             [story.expectations.ALL_LINUX],
-             'crbug.com/788796')
-    return StoryExpectations()
-
   def SetExtraBrowserOptions(self, options):
     options.AppendExtraBrowserArgs(
       '--enable-blink-features=BlinkRuntimeCallStats')
@@ -247,52 +159,6 @@
     options.AppendExtraBrowserArgs(
       '--enable-features=V8VmFuture')
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableBenchmark(
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/788797')
-        self.DisableStory(
-            'browse:shopping:avito',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/767970')
-        self.DisableStory(
-            'browse:news:cnn',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/767970')
-        self.DisableStory(
-            'browse:tech:discourse_infinite_scroll',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/767970')
-        self.DisableStory(
-            'browse:shopping:lazada',
-            [story.expectations.ANDROID_ONE],
-            'crbug.com/768472')
-        self.DisableStory(
-            'browse:shopping:flipkart',
-            [story.expectations.ALL_MOBILE],
-            'crbug.com/767970, crbug.com/708300')
-        self.DisableStory(
-             'browse:news:globo',
-             [story.expectations.ALL_ANDROID],
-             'crbug.com/714650')
-        self.DisableStory(
-             'browse:news:toi',
-             [story.expectations.ALL_ANDROID],
-             'crbug.com/728081')
-        # TODO(rnephew): This disabling should move to CanRunOnBrowser.
-        self.DisableStory(
-             'browse:chrome:omnibox',
-             [story.expectations.ANDROID_WEBVIEW],
-             'Webview does not have omnibox')
-        # TODO(rnephew): This disabling should move to CanRunOnBrowser.
-        self.DisableStory(
-             'browse:chrome:newtab',
-             [story.expectations.ANDROID_WEBVIEW],
-             'Webview does not have NTP')
-    return StoryExpectations()
-
   @classmethod
   def Name(cls):
     return 'v8.browsing_mobile-future'
diff --git a/tools/perf/benchmarks/wasm.py b/tools/perf/benchmarks/wasm.py
index 2314d6d..4d80f685 100644
--- a/tools/perf/benchmarks/wasm.py
+++ b/tools/perf/benchmarks/wasm.py
@@ -6,7 +6,6 @@
 import page_sets
 
 from telemetry import benchmark
-from telemetry import story
 from telemetry.timeline import chrome_trace_category_filter
 from telemetry.web_perf import timeline_based_measurement
 
@@ -55,14 +54,3 @@
 
   def CreateStorySet(self, options):
     return page_sets.WasmRealWorldPagesStorySet()
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-            'WasmTanks', [story.expectations.ALL_ANDROID],
-            'Unity WebGL in not supported on mobile')
-        self.DisableStory(
-            'WasmSpaceBuggy', [story.expectations.ANDROID_ONE,
-                story.expectations.ANDROID_WEBVIEW], 'crbug.com/788976')
-    return StoryExpectations()
diff --git a/tools/perf/benchmarks/webrtc.py b/tools/perf/benchmarks/webrtc.py
index 2fd494e..ba2336bd 100644
--- a/tools/perf/benchmarks/webrtc.py
+++ b/tools/perf/benchmarks/webrtc.py
@@ -6,7 +6,6 @@
 
 import page_sets
 from telemetry import benchmark
-from telemetry import story
 from telemetry.timeline import chrome_trace_category_filter
 from telemetry.web_perf import timeline_based_measurement
 
@@ -43,23 +42,3 @@
   def SetExtraBrowserOptions(self, options):
     options.AppendExtraBrowserArgs('--use-fake-device-for-media-stream')
     options.AppendExtraBrowserArgs('--use-fake-ui-for-media-stream')
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        # TODO(qyearsley, mcasas): Add webrtc.audio when http://crbug.com/468732
-        # is fixed, or revert https://codereview.chromium.org/1544573002/ when
-        # http://crbug.com/568333 is fixed.
-        self.DisableStory('audio_call_opus_10s',
-                          [story.expectations.ALL],
-                          'crbug.com/468732')
-        self.DisableStory('audio_call_g772_10s',
-                          [story.expectations.ALL],
-                          'crbug.com/468732')
-        self.DisableStory('audio_call_pcmu_10s',
-                          [story.expectations.ALL],
-                          'crbug.com/468732')
-        self.DisableStory('audio_call_isac/1600_10s',
-                          [story.expectations.ALL],
-                          'crbug.com/468732')
-    return StoryExpectations()
diff --git a/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py b/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py
index cac63522..d146e16 100644
--- a/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py
+++ b/tools/perf/contrib/blink_perf_cmdline/blink_perf_cmdline.py
@@ -4,7 +4,7 @@
 import os
 
 from benchmarks import blink_perf
-from telemetry import story
+
 
 # pylint: disable=protected-access
 class BlinkPerfAll(blink_perf._BlinkPerfBenchmark):
@@ -30,9 +30,3 @@
     print
     print 'Running all tests in %s' % path
     return blink_perf.CreateStorySetFromPath(path, blink_perf.SKIPPED_FILE)
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
diff --git a/tools/perf/contrib/blink_perf_xml_http_request/blink_perf_xml_http_request.py b/tools/perf/contrib/blink_perf_xml_http_request/blink_perf_xml_http_request.py
index 1d09193..4422e62 100644
--- a/tools/perf/contrib/blink_perf_xml_http_request/blink_perf_xml_http_request.py
+++ b/tools/perf/contrib/blink_perf_xml_http_request/blink_perf_xml_http_request.py
@@ -2,16 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 from benchmarks import blink_perf
-from telemetry import story
 
 
 # pylint: disable=protected-access
 class BlinkPerfXMLHttpRequest(blink_perf._BlinkPerfBenchmark):
   tag = 'xml_http_request'
   subdir = 'XMLHttpRequest'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
diff --git a/tools/perf/contrib/cluster_telemetry/loading_ct.py b/tools/perf/contrib/cluster_telemetry/loading_ct.py
index eccfa68..5f637e1d 100644
--- a/tools/perf/contrib/cluster_telemetry/loading_ct.py
+++ b/tools/perf/contrib/cluster_telemetry/loading_ct.py
@@ -6,7 +6,6 @@
 from contrib.cluster_telemetry import ct_benchmarks_util
 from contrib.cluster_telemetry import page_set
 
-from telemetry import story
 from telemetry.page import traffic_setting
 
 
@@ -41,9 +40,3 @@
   @classmethod
   def Name(cls):
     return 'loading.cluster_telemetry'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Not tests disabled.
-    return StoryExpectations()
diff --git a/tools/perf/contrib/cluster_telemetry/multipage_skpicture_printer.py b/tools/perf/contrib/cluster_telemetry/multipage_skpicture_printer.py
index feb37bd8..b0076bd 100644
--- a/tools/perf/contrib/cluster_telemetry/multipage_skpicture_printer.py
+++ b/tools/perf/contrib/cluster_telemetry/multipage_skpicture_printer.py
@@ -55,12 +55,6 @@
                                         options.page_set_base_dir)
     return story_set_class()
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Not tests disabled.
-    return StoryExpectations()
-
 
 class MultipageSkpicturePrinterCT(perf_benchmark.PerfBenchmark):
   """Captures mSKPs for Cluster Telemetry."""
@@ -88,9 +82,3 @@
     return page_set.CTPageSet(
         options.urls_list, options.user_agent, options.archive_data_file,
         run_page_interaction_callback=repaint_helpers.WaitThenRepaint)
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Not tests disabled.
-    return StoryExpectations()
diff --git a/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py b/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py
index 64b154608..34ff057 100644
--- a/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py
+++ b/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py
@@ -13,7 +13,6 @@
 
 from benchmarks import loading_metrics_category
 from telemetry import benchmark
-from telemetry import story
 from telemetry.page import cache_temperature
 from telemetry.web_perf import timeline_based_measurement
 
@@ -43,12 +42,6 @@
         cache_temperatures=[
           cache_temperature.COLD, cache_temperature.WARM])
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass  # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org'])
 class PageCyclerV2IntlArFaHe(_PageCyclerV2):
@@ -66,12 +59,6 @@
     return page_sets.IntlArFaHePageSet(cache_temperatures=[
           cache_temperature.COLD, cache_temperature.WARM])
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass  # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org'])
 class PageCyclerV2IntlEsFrPtBr(_PageCyclerV2):
@@ -89,12 +76,6 @@
     return page_sets.IntlEsFrPtBrPageSet(cache_temperatures=[
           cache_temperature.COLD, cache_temperature.WARM])
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass  # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org'])
 class PageCyclerV2IntlHiRu(_PageCyclerV2):
@@ -112,12 +93,6 @@
     return page_sets.IntlHiRuPageSet(cache_temperatures=[
           cache_temperature.COLD, cache_temperature.WARM])
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass  # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org'])
 class PageCyclerV2IntlJaZh(_PageCyclerV2):
@@ -134,12 +109,6 @@
     return page_sets.IntlJaZhPageSet(cache_temperatures=[
           cache_temperature.COLD, cache_temperature.WARM])
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass  # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['kouhei@chromium.org', 'ksakamoto@chromium.org'])
 class PageCyclerV2IntlKoThVi(_PageCyclerV2):
@@ -156,9 +125,3 @@
   def CreateStorySet(self, options):
     return page_sets.IntlKoThViPageSet(cache_temperatures=[
           cache_temperature.COLD, cache_temperature.WARM])
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass  # Nothing disabled.
-    return StoryExpectations()
diff --git a/tools/perf/contrib/cros_benchmarks/tab_switching_bench.py b/tools/perf/contrib/cros_benchmarks/tab_switching_bench.py
index 7d7aa9c..de0a1a0 100644
--- a/tools/perf/contrib/cros_benchmarks/tab_switching_bench.py
+++ b/tools/perf/contrib/cros_benchmarks/tab_switching_bench.py
@@ -59,9 +59,3 @@
   @classmethod
   def Name(cls):
     return 'cros_tab_switching.typical_24'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass  # Nothing disabled.
-    return StoryExpectations()
diff --git a/tools/perf/contrib/dromaeo_extras/dromaeo_extras.py b/tools/perf/contrib/dromaeo_extras/dromaeo_extras.py
index fe6d68b..a470075 100644
--- a/tools/perf/contrib/dromaeo_extras/dromaeo_extras.py
+++ b/tools/perf/contrib/dromaeo_extras/dromaeo_extras.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 from telemetry import benchmark
-from telemetry import story
 
 from benchmarks import dromaeo
 
@@ -29,12 +28,6 @@
   def Name(cls):
     return 'dromaeo.jslibattrjquery'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['yukishiino@chromium.org',
                          'bashi@chromium.org',
@@ -52,12 +45,6 @@
   def Name(cls):
     return 'dromaeo.jslibattrprototype'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['yukishiino@chromium.org',
                          'bashi@chromium.org',
@@ -75,12 +62,6 @@
   def Name(cls):
     return 'dromaeo.jslibeventjquery'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['yukishiino@chromium.org',
                          'bashi@chromium.org',
@@ -98,12 +79,6 @@
   def Name(cls):
     return 'dromaeo.jslibeventprototype'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 # win-ref: http://crbug.com/598705
 # android: http://crbug.com/503138
@@ -124,12 +99,6 @@
   def Name(cls):
     return 'dromaeo.jslibmodifyjquery'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['yukishiino@chromium.org',
                          'bashi@chromium.org',
@@ -147,12 +116,6 @@
   def Name(cls):
     return 'dromaeo.jslibmodifyprototype'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['yukishiino@chromium.org',
                          'bashi@chromium.org',
@@ -170,12 +133,6 @@
   def Name(cls):
     return 'dromaeo.jslibstylejquery'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['yukishiino@chromium.org',
                          'bashi@chromium.org',
@@ -193,12 +150,6 @@
   def Name(cls):
     return 'dromaeo.jslibstyleprototype'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['yukishiino@chromium.org',
                          'bashi@chromium.org',
@@ -217,12 +168,6 @@
   def Name(cls):
     return 'dromaeo.jslibtraversejquery'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['yukishiino@chromium.org',
                          'bashi@chromium.org',
@@ -239,12 +184,6 @@
   def Name(cls):
     return 'dromaeo.jslibtraverseprototype'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 class DromaeoCSSQueryJquery(_BaseDromaeoBenchmark):
   """Dromaeo CSS Query jquery JavaScript benchmark.
@@ -257,9 +196,3 @@
   @classmethod
   def Name(cls):
     return 'dromaeo.cssqueryjquery'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
diff --git a/tools/perf/contrib/heap_profiling/heap_profiling.py b/tools/perf/contrib/heap_profiling/heap_profiling.py
index 2c94799..c60f4c5 100644
--- a/tools/perf/contrib/heap_profiling/heap_profiling.py
+++ b/tools/perf/contrib/heap_profiling/heap_profiling.py
@@ -68,12 +68,6 @@
       args += ['--enable-heap-profiling=native']
     options.AppendExtraBrowserArgs(args)
 
-  def GetExpectations(self):
-    class DefaultExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass  # No stories disabled.
-    return DefaultExpectations()
-
 
 class PseudoHeapProfilingDesktopBenchmark(_HeapProfilingBenchmark):
   PROFILING_MODE = 'pseudo'
diff --git a/tools/perf/contrib/memory_extras/memory_extras.py b/tools/perf/contrib/memory_extras/memory_extras.py
index abc74b5..d65fc4b 100644
--- a/tools/perf/contrib/memory_extras/memory_extras.py
+++ b/tools/perf/contrib/memory_extras/memory_extras.py
@@ -6,7 +6,6 @@
 import page_sets
 
 from telemetry import benchmark
-from telemetry import story
 
 
 # pylint: disable=protected-access
@@ -34,12 +33,6 @@
     # is able to cope with the data load generated by TBMv2 metrics.
     return not memory._IGNORED_STATS_RE.search(value.name)
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['perezju@chromium.org'])
 class LongRunningDualBrowserBenchmark(memory._MemoryInfra):
@@ -64,12 +57,6 @@
     # is able to cope with the data load generated by TBMv2 metrics.
     return not memory._IGNORED_STATS_RE.search(value.name)
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['etienneb@chromium.org'])
 class LongRunningMemoryBenchmarkSitesDesktop(memory._MemoryInfra):
@@ -106,9 +93,3 @@
     # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard
     # is able to cope with the data load generated by TBMv2 metrics.
     return not memory._IGNORED_STATS_RE.search(value.name)
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
diff --git a/tools/perf/contrib/oilpan/oilpan_benchmarks.py b/tools/perf/contrib/oilpan/oilpan_benchmarks.py
index bed8b9a..4b7609b4 100644
--- a/tools/perf/contrib/oilpan/oilpan_benchmarks.py
+++ b/tools/perf/contrib/oilpan/oilpan_benchmarks.py
@@ -29,12 +29,6 @@
     path = os.path.join(blink_perf.BLINK_PERF_BASE_DIR, 'BlinkGC')
     return blink_perf.CreateStorySetFromPath(path, blink_perf.SKIPPED_FILE)
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # No tests disabled.
-    return StoryExpectations()
-
 
 @benchmark.Owner(emails=['peria@chromium.org'])
 class OilpanGCTimesSmoothnessAnimation(perf_benchmark.PerfBenchmark):
@@ -45,12 +39,6 @@
   def Name(cls):
     return 'oilpan_gc_times.tough_animation_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # Nothing disabled.
-    return StoryExpectations()
-
 
 class OilpanGCTimesKeySilkCases(perf_benchmark.PerfBenchmark):
   test = oilpan_gc_times.OilpanGCTimesForSmoothness
@@ -61,17 +49,6 @@
   def Name(cls):
     return 'oilpan_gc_times.key_silk_cases'
 
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory('https://polymer-topeka.appspot.com/',
-                          [story.expectations.ALL], 'crbug.com/507865')
-        self.DisableStory('http://plus.google.com/app/basic/stream',
-                          [story.expectations.ALL], 'crbug.com/338838')
-        self.DisableStory('inbox_app.html?slide_drawer',
-                          [story.expectations.ALL], 'crbug.com/446332')
-    return StoryExpectations()
-
 
 class OilpanGCTimesSyncScrollKeyMobileSites(perf_benchmark.PerfBenchmark):
   tag = 'sync_scroll'
@@ -85,12 +62,3 @@
   @classmethod
   def Name(cls):
     return 'oilpan_gc_times.sync_scroll.key_mobile_sites_smooth'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        self.DisableStory(
-            'http://digg.com',
-            [story.expectations.ALL],
-            'crbug.com/756119')
-    return StoryExpectations()
diff --git a/tools/perf/contrib/tracing/tracing.py b/tools/perf/contrib/tracing/tracing.py
index a5adcb2e..75d2dbe 100644
--- a/tools/perf/contrib/tracing/tracing.py
+++ b/tools/perf/contrib/tracing/tracing.py
@@ -4,7 +4,6 @@
 
 from core import perf_benchmark
 
-from telemetry import story
 from telemetry.web_perf import timeline_based_measurement
 
 import page_sets
@@ -23,9 +22,3 @@
   @classmethod
   def Name(cls):
     return 'tracing.tracing_with_debug_overhead'
-
-  def GetExpectations(self):
-    class StoryExpectations(story.expectations.StoryExpectations):
-      def SetExpectations(self):
-        pass # No tests disabled.
-    return StoryExpectations()
diff --git a/tools/perf/core/system_health_csv_generator.py b/tools/perf/core/system_health_csv_generator.py
index a1c2325..90aa3f51 100644
--- a/tools/perf/core/system_health_csv_generator.py
+++ b/tools/perf/core/system_health_csv_generator.py
@@ -11,9 +11,8 @@
 path_util.AddPyUtilsToPath()
 path_util.AddTelemetryToPath()
 import page_sets
-from page_sets.system_health import expectations
 from py_utils import expectations_parser
-from telemetry.story import expectations as expectations_module
+from telemetry.story import expectations as expectations
 
 def IterAllSystemHealthStories():
   for s in page_sets.SystemHealthStorySet(platform='desktop'):
@@ -55,7 +54,7 @@
 def GenerateSystemHealthCSV(file_path):
   system_health_stories = list(IterAllSystemHealthStories())
 
-  e = expectations_module.StoryExpectations()
+  e = expectations.StoryExpectations()
   with open(path_util.GetExpectationsPath()) as fp:
     parser = expectations_parser.TestExpectationParser(fp.read())
 
@@ -64,15 +63,8 @@
   for benchmark in benchmarks:
     e.GetBenchmarkExpectationsFromParser(parser.expectations, benchmark)
 
-  all_expectations = [
-      e.AsDict()['stories'],
-      # TODO(rnephew): Delete these when system health uses file.
-      expectations.SystemHealthDesktopCommonExpectations().AsDict()['stories'],
-      expectations.SystemHealthDesktopMemoryExpectations().AsDict()['stories'],
-      expectations.SystemHealthMobileCommonExpectations().AsDict()['stories'],
-      expectations.SystemHealthMobileMemoryExpectations().AsDict()['stories'],]
+  disabed_platforms = PopulateExpectations([e.AsDict()['stories']])
 
-  disabed_platforms = PopulateExpectations(all_expectations)
   system_health_stories.sort(key=lambda s: s.name)
   with open(file_path, 'w') as f:
     csv_writer = csv.writer(f)
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 0462dfb9..ec2ed12 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -5,10 +5,235 @@
 # tags: Nexus_7 Cherry_Mobile_Android_One Mac_10.11 Mac_10.12 Nexus6_Webview
 # tags: Nexus5X_Webview
 
+# Benchmark: battor.steady_state
+crbug.com/505990 [ All ] battor.steady_state/http://abcnews.go.com/ [ Skip ]
+
+# Benchmark: blink_perf.bindings
+crbug.com/764868 [ Cherry_Mobile_Android_One ] blink_perf.bindings/structured-clone-long-string-deserialize.html [ Skip ]
+crbug.com/764868 [ Cherry_Mobile_Android_One ] blink_perf.bindings/structured-clone-json-serialize.html [ Skip ]
+crbug.com/764868 [ Cherry_Mobile_Android_One ] blink_perf.bindings/structured-clone-long-string-serialize.html [ Skip ]
+crbug.com/764868 [ Cherry_Mobile_Android_One ] blink_perf.bindings/structured-clone-json-deserialize.html [ Skip ]
+
+# Benchmark: blink_perf.canvas
+crbug.com/593973 [ Android_Svelte ] blink_perf.canvas/* [ Skip ]
+crbug.com/765799 [ Nexus_6 ] blink_perf.canvas/draw-static-canvas-2d-to-hw-accelerated-canvas-2d.html [ Skip ]
+crbug.com/784540 [ Nexus_5 ] blink_perf.canvas/draw-static-canvas-2d-to-hw-accelerated-canvas-2d.html [ Skip ]
+crbug.com/784540 [ Nexus_5X ] blink_perf.canvas/draw-static-canvas-2d-to-hw-accelerated-canvas-2d.html [ Skip ]
+crbug.com/784540 [ Nexus_5 ] blink_perf.canvas/draw-dynamic-canvas-2d-to-hw-accelerated-canvas-2d.html [ Skip ]
+crbug.com/784540 [ Nexus_5X ] blink_perf.canvas/draw-dynamic-canvas-2d-to-hw-accelerated-canvas-2d.html [ Skip ]
+crbug.com/738453 [ Nexus_6 ] blink_perf.canvas/putImageData.html [ Skip ]
+
+# Benchmark: blink_perf.layout
+crbug.com/551950 [ Android_Svelte ] blink_perf.layout/* [ Skip ]
+
+# Benchmark: blink_perf.paint
+crbug.com/574483 [ Android_Svelte ] blink_perf.paint/* [ Skip ]
+
+# Benchmark: blink_perf.shadow_dom
+crbug.com/702319 [ Nexus_5X ] blink_perf.shadow_dom/* [ Skip ]
+
+# Benchmark: blink_perf.svg
+crbug.com/736817 [ Nexus_5X ] blink_perf.svg/SvgCubics.html [ Skip ]
+crbug.com/736817 [ Nexus_5X ] blink_perf.svg/Debian.html [ Skip ]
+crbug.com/736817 [ Nexus_5X ] blink_perf.svg/HarveyRayner.html [ Skip ]
+crbug.com/736817 [ Nexus_5X ] blink_perf.svg/CrawFishGanson.html [ Skip ]
+crbug.com/736817 [ Nexus_5X ] blink_perf.svg/Worldcup.html [ Skip ]
+crbug.com/736817 [ Nexus_5X ] blink_perf.svg/FlowerFromMyGarden.html [ Skip ]
+crbug.com/736817 [ Nexus_5X ] blink_perf.svg/SvgNestedUse.html [ Skip ]
+
+# Benchmark: kraken
+crbug.com/624411 [ Android_Svelte ] kraken/http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html [ Skip ]
+
 # Benchmark: loading.desktop
 crbug.com/723783 [ Win ] loading.desktop/Orange [ Skip ]
 crbug.com/752611 [ Linux ] loading.desktop/uol.com.br [ Skip ]
 
+# Benchmark: loading.mobile
+crbug.com/676612 [ Nexus6_Webview ] loading.mobile/* [ Skip ]
+[ All ] loading.mobile/IBI [ Skip ]
+[ All ] loading.mobile/HashOcean [ Skip ]
+crbug.com/776092 [ Cherry_Mobile_Android_One ] loading.mobile/GoogleRedirectToGoogleJapan [ Skip ]
+crbug.com/656861 [ All ] loading.mobile/G1 [ Skip ]
+[ All ] loading.mobile/SBS [ Skip ]
+[ All ] loading.mobile/MLSMatrix [ Skip ]
+[ Nexus_5X ] loading.mobile/Hongkiat [ Skip ]
+[ All ] loading.mobile/GFK [ Skip ]
+[ All ] loading.mobile/FuturaSciences [ Skip ]
+[ Nexus_5X ] loading.mobile/Dramaq [ Skip ]
+[ All ] loading.mobile/EBS [ Skip ]
+[ Nexus_7 ] loading.mobile/Facebook [ Skip ]
+[ All ] loading.mobile/163 [ Skip ]
+
+# Benchmark: memory.long_running_idle_gmail_tbmv2
+crbug.com/611167 [ Android_Svelte ] memory.long_running_idle_gmail_tbmv2/* [ Skip ]
+
+# Benchmark: memory.long_running_idle_gmail_background_tbmv2
+crbug.com/611167 [ Android_Svelte ] memory.long_running_idle_gmail_background_tbmv2/* [ Skip ]
+
+# Benchmark: octane
+[ Cherry_Mobile_Android_One ] octane/http://chromium.github.io/octane/index.html?auto=1 [ Skip ]
+
+# Benchmark: oilpan_gc_times.key_silk_cases
+crbug.com/446332 [ All ] oilpan_gc_times.key_silk_cases/inbox_app.html?slide_drawer [ Skip ]
+crbug.com/507865 [ All ] oilpan_gc_times.key_silk_cases/https://polymer-topeka.appspot.com/ [ Skip ]
+crbug.com/338838 [ All ] oilpan_gc_times.key_silk_cases/http://plus.google.com/app/basic/stream [ Skip ]
+
+# Benchmark: oilpan_gc_times.sync_scroll.key_mobile_sites_smooth
+crbug.com/756119 [ All ] oilpan_gc_times.sync_scroll.key_mobile_sites_smooth/http://digg.com [ Skip ]
+
+# Benchmark: power.idle_platform
+crbug.com/773949 [ Nexus_5 ] power.idle_platform/* [ Skip ]
+crbug.com/773949 [ Nexus_6 ] power.idle_platform/* [ Skip ]
+crbug.com/773949 [ Nexus_7 ] power.idle_platform/* [ Skip ]
+crbug.com/773949 [ Cherry_Mobile_Android_One ] power.idle_platform/* [ Skip ]
+
+
+# Benchmark: smoothness.gpu_rasterization.polymer
+[ All ] smoothness.gpu_rasterization.polymer/* [ Skip ] # Test needs to be modernized.
+
+# Benchmark: rasterize_and_record_micro.top_25
+crbug.com/768010 [ Cherry_Mobile_Android_One ] rasterize_and_record_micro.top_25/file://static_top_25/espn.html [ Skip ]
+crbug.com/764543 [ All ] rasterize_and_record_micro.top_25/file://static_top_25/wikipedia.html [ Skip ]
+
+# Benchmark: smoothness.gpu_rasterization.top_25_smooth
+crbug.com/667432 [ All ] smoothness.gpu_rasterization.top_25_smooth/Pinterest [ Skip ]
+crbug.com/667432 [ All ] smoothness.gpu_rasterization.top_25_smooth/http://www.amazon.com [ Skip ]
+crbug.com/528474 [ All ] smoothness.gpu_rasterization.top_25_smooth/http://www.cnn.com [ Skip ]
+
+# Benchmark: smoothness.gpu_rasterization.tough_pinch_zoom_cases
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/https://www.google.com/calendar/ [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/http://games.yahoo.com [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/https://www.google.com/#hl=en&q=barack+obama [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/ESPN [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/https://mail.google.com/mail/ [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/Blogger [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/Twitter [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/http://sports.yahoo.com/ [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/LinkedIn [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/http://www.youtube.com [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/Facebook [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/http://www.amazon.com [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/Weather.com [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/http://www.cnn.com [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/http://www.ebay.com [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/https://www.google.com/search?q=cats&tbm=isch [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/http://booking.com [ Skip ]
+crbug.com/610021 [ Android ] smoothness.gpu_rasterization.tough_pinch_zoom_cases/http://news.yahoo.com [ Skip ]
+
+# Benchmark: smoothness.key_desktop_move_cases
+crbug.com/750131 [ Win ] smoothness.key_desktop_move_cases/https://mail.google.com/mail/ [ Skip ]
+crbug.com/770904 [ Mac ] smoothness.key_desktop_move_cases/https://mail.google.com/mail/ [ Skip ]
+
+# Benchmark: smoothness.key_mobile_sites_smooth
+crbug.com/756119 [ Android ] smoothness.key_mobile_sites_smooth/http://digg.com [ Skip ]
+
+# Benchmark: smoothness.key_silk_cases
+[ All ] smoothness.key_silk_cases/inbox_app.html?slide_drawer [ Skip ]
+crbug.com/780525 [ All ] smoothness.key_silk_cases/https://polymer-topeka.appspot.com/ [ Skip ]
+
+# Benchmark: smoothness.maps
+crbug.com/653993 [ Android_Webview ] smoothness.maps/maps_perf_test [ Skip ]
+
+# Benchmark: smoothness.pathological_mobile_sites
+crbug.com/685342 [ Nexus_7 ] smoothness.pathological_mobile_sites/* [ Skip ]
+
+# Benchmark: smoothness.simple_mobile_sites
+crbug.com/750833 [ Android_Webview ] smoothness.simple_mobile_sites/https://www.flickr.com/ [ Skip ]
+
+# Benchmark: smoothness.sync_scroll.key_mobile_sites_smooth
+crbug.com/756119 [ All ] smoothness.sync_scroll.key_mobile_sites_smooth/http://digg.com [ Skip ]
+
+# Benchmark: smoothness.top_25_smooth
+crbug.com/762165 [ Win ] smoothness.top_25_smooth/https://www.google.com/calendar/ [ Skip ]
+crbug.com/762165 [ Win ] smoothness.top_25_smooth/http://www.youtube.com [ Skip ]
+crbug.com/667432 [ All ] smoothness.top_25_smooth/http://www.amazon.com [ Skip ]
+crbug.com/528474 [ All ] smoothness.top_25_smooth/http://www.cnn.com [ Skip ]
+crbug.com/762165 [ Win ] smoothness.top_25_smooth/https://plus.google.com/110031535020051778989/posts [ Skip ]
+crbug.com/762165 [ Win ] smoothness.top_25_smooth/https://www.google.com/search?q=cats&tbm=isch [ Skip ]
+crbug.com/762165 [ Win ] smoothness.top_25_smooth/Docs_(1_open_document_tab) [ Skip ]
+
+# Benchmark: smoothness.tough_ad_cases
+crbug.com/555089 [ Android_Svelte ] smoothness.tough_ad_cases/* [ Skip ]
+
+# Benchmark: smoothness.tough_animation_cases
+crbug.com/350692 [ All ] smoothness.tough_animation_cases/robohornetpro [ Skip ]
+crbug.com/755556 [ Mobile ] smoothness.tough_animation_cases/balls_css_keyframe_animations_composited_transform.html [ Skip ]
+crbug.com/755556 [ Mac ] smoothness.tough_animation_cases/mix_blend_mode_animation_difference.html [ Skip ]
+crbug.com/755556 [ Mac ] smoothness.tough_animation_cases/mix_blend_mode_animation_hue.html [ Skip ]
+
+# Benchmark: smoothness.tough_canvas_cases
+crbug.com/785485 [ Android_Webview ] smoothness.tough_canvas_cases/http://www.kevs3d.co.uk/dev/canvask3d/k3d_test.html [ Skip ]
+crbug.com/755657 [ Cherry_Mobile_Android_One ] smoothness.tough_canvas_cases/tough_canvas_cases/canvas_toBlob.html [ Skip ]
+crbug.com/785286 [ Android_Webview ] smoothness.tough_canvas_cases/http://www.smashcat.org/av/canvas_test/ [ Skip ]
+crbug.com/785286 [ Android_Webview ] smoothness.tough_canvas_cases/http://www.effectgames.com/demos/canvascycle/ [ Skip ]
+crbug.com/364248 [ Nexus_5 ] smoothness.tough_canvas_cases/http://geoapis.appspot.com/agdnZW9hcGlzchMLEgtFeGFtcGxlQ29kZRjh1wIM [ Skip ]
+
+# Benchmark: smoothness.tough_pinch_zoom_cases
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/https://www.google.com/calendar/ [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/http://games.yahoo.com [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/https://www.google.com/#hl=en&q=barack+obama [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/ESPN [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/https://mail.google.com/mail/ [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/Blogger [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/Twitter [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/http://sports.yahoo.com/ [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/LinkedIn [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/http://www.youtube.com [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/Facebook [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/http://www.amazon.com [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/Weather.com [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/http://www.cnn.com [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/http://www.ebay.com [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/https://www.google.com/search?q=cats&tbm=isch [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/http://booking.com [ Skip ]
+crbug.com/631015 [ Android ] smoothness.tough_pinch_zoom_cases/http://news.yahoo.com [ Skip ]
+
+# Benchmark: smoothness.tough_scrolling_cases
+crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_15000_pixels_per_second [ Skip ]
+crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_20000_pixels_per_second [ Skip ]
+crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_40000_pixels_per_second [ Skip ]
+crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_50000_pixels_per_second [ Skip ]
+crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_10000_pixels_per_second [ Skip ]
+crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_05000_pixels_per_second [ Skip ]
+crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_30000_pixels_per_second [ Skip ]
+crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_75000_pixels_per_second [ Skip ]
+crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_60000_pixels_per_second [ Skip ]
+crbug.com/785473 [ Android_Webview ] smoothness.tough_scrolling_cases/canvas_90000_pixels_per_second [ Skip ]
+
+# Benchmark: smoothness.tough_texture_upload_cases
+crbug.com/795060 [ Cherry_Mobile_Android_One ] smoothness.tough_texture_upload_cases/extra_large_texture_uploads.html [ Skip ]
+
+# Benchmark: smoothness.tough_webgl_ad_cases
+crbug.com/574485 [ Android_Svelte ] smoothness.tough_webgl_ad_cases/* [ Skip ]
+
+# Benchmark: speedometer2-future
+crbug.com/792495 [ Linux ] speedometer2-future/Speedometer2 [ Skip ]
+
+# Benchmark: system_health.common_desktop
+crbug.com/728576 [ Mac ] system_health.common_desktop/browse:news:cnn [ Skip ]
+crbug.com/64939 [ All ] system_health.common_desktop/play:media:pandora [ Skip ]
+crbug.com/676336 [ Win ] system_health.common_desktop/browse:news:hackernews [ Skip ]
+crbug.com/676336 [ Mac ] system_health.common_desktop/browse:news:hackernews [ Skip ]
+crbug.com/649392 [ Win ] system_health.common_desktop/play:media:soundcloud [ Skip ]
+crbug.com/649392 [ All ] system_health.common_desktop/play:media:google_play_music [ Skip ]
+crbug.com/773084 [ Mac ] system_health.common_desktop/browse:tools:maps [ Skip ]
+crbug.com/769809 [ All ] system_health.common_desktop/browse_accessibility:tools:gmail_compose [ Skip ]
+crbug.com/673775 [ Win ] system_health.common_desktop/browse:search:google [ Skip ]
+crbug.com/773393 [ Win ] system_health.common_desktop/browse:media:tumblr [ Skip ]
+
+# Benchmark: system_health.common_mobile
+[ Android_Webview ] system_health.common_mobile/browse:chrome:omnibox [ Skip ]
+crbug.com/736497 [ Nexus_6 ] system_health.common_mobile/browse:shopping:avito [ Skip ]
+crbug.com/657433 [ Android ] system_health.common_mobile/load:tools:gmail [ Skip ]
+crbug.com/714650 [ Android ] system_health.common_mobile/browse:news:globo [ Skip ]
+crbug.com/728081 [ Android ] system_health.common_mobile/browse:news:toi [ Skip ]
+[ Android_Webview ] system_health.common_mobile/long_running:tools:gmail-background [ Skip ]
+crbug.com/787001 [ Android_Webview ] system_health.common_mobile/load:media:soundcloud [ Skip ]
+crbug.com/708300 [ Android ] system_health.common_mobile/browse:shopping:flipkart [ Skip ]
+[ Android_Webview ] system_health.common_mobile/browse:chrome:newtab [ Skip ]
+crbug.com/738854 [ Nexus_5X ] system_health.common_mobile/load:tools:drive [ Skip ]
+crbug.com/738854 [ Android_Webview ] system_health.common_mobile/load:tools:drive [ Skip ]
+
 # Benchmark: system_health.memory_desktop
 crbug.com/728576 [ Mac ] system_health.memory_desktop/browse:news:cnn [ Skip ]
 crbug.com/64939 [ All ] system_health.memory_desktop/play:media:pandora [ Skip ]
@@ -38,9 +263,94 @@
 crbug.com/738854 [ Nexus_5X ] system_health.memory_mobile/load:tools:drive [ Skip ]
 crbug.com/738854 [ Android_Webview ] system_health.memory_mobile/load:tools:drive [ Skip ]
 
+# Benchmark: tab_switching.typical_25
+crbug.com/747026 [ Mac ] tab_switching.typical_25/multitab:misc:typical24 [ Skip ]
+
+# Benchmark: thread_times.key_hit_test_cases
+crbug.com/750876 [ All ] thread_times.key_hit_test_cases/* [ Skip ]
+
+# Benchmark: thread_times.key_silk_cases
+crbug.com/446332 [ All ] thread_times.key_silk_cases/inbox_app.html?slide_drawer [ Skip ]
+crbug.com/764825 [ All ] thread_times.key_silk_cases/inbox_app.html?swipe_to_dismiss [ Skip ]
+crbug.com/507865 [ All ] thread_times.key_silk_cases/https://polymer-topeka.appspot.com/ [ Skip ]
+crbug.com/764825 [ All ] thread_times.key_silk_cases/http://s.codepen.io/befamous/fullpage/pFsqb?scroll [ Skip ]
+crbug.com/764825 [ All ] thread_times.key_silk_cases/masonry.html [ Skip ]
+crbug.com/338838 [ All ] thread_times.key_silk_cases/http://plus.google.com/app/basic/stream [ Skip ]
+
+# Benchmark: thread_times.simple_mobile_sites
+crbug.com/752228 [ All ] thread_times.simple_mobile_sites/https://www.flickr.com/ [ Skip ]
+
+# Benchmark: thread_times.tough_scrolling_cases
+crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_15000_pixels_per_second [ Skip ]
+crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_20000_pixels_per_second [ Skip ]
+crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_40000_pixels_per_second [ Skip ]
+crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_50000_pixels_per_second [ Skip ]
+crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_10000_pixels_per_second [ Skip ]
+crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_05000_pixels_per_second [ Skip ]
+crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_30000_pixels_per_second [ Skip ]
+crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_75000_pixels_per_second [ Skip ]
+crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_60000_pixels_per_second [ Skip ]
+crbug.com/783362 [ Android_Webview ] thread_times.tough_scrolling_cases/canvas_90000_pixels_per_second [ Skip ]
+
+# Benchmark: v8.browsing_desktop
+crbug.com/773084 [ Mac ] v8.browsing_desktop/browse:tools:maps [ Skip ]
+crbug.com/788796 [ Linux ] v8.browsing_desktop/browse:media:imgur [ Skip ]
+crbug.com/676336 [ Win ] v8.browsing_desktop/browse:news:hackernews [ Skip ]
+crbug.com/676336 [ Mac ] v8.browsing_desktop/browse:news:hackernews [ Skip ]
+[ Mac ] v8.browsing_desktop/browse:news:cnn [ Skip ]
+
+# Benchmark: v8.browsing_desktop-future
+crbug.com/773084 [ Mac ] v8.browsing_desktop-future/browse:tools:maps [ Skip ]
+crbug.com/788796 [ Linux ] v8.browsing_desktop-future/browse:media:imgur [ Skip ]
+crbug.com/676336 [ Win ] v8.browsing_desktop-future/browse:news:hackernews [ Skip ]
+crbug.com/676336 [ Mac ] v8.browsing_desktop-future/browse:news:hackernews [ Skip ]
+crbug.com/728576 [ Mac ] v8.browsing_desktop-future/browse:news:cnn [ Skip ]
+
+# Benchmark: v8.browsing_mobile
+crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/* [ Skip ]
+crbug.com/768472 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:shopping:lazada [ Skip ]
+crbug.com/714650 [ Android ] v8.browsing_mobile/browse:news:globo [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:tech:discourse_infinite_scroll [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:shopping:avito [ Skip ]
+[ Android_Webview ] v8.browsing_mobile/browse:chrome:omnibox [ Skip ]
+crbug.com/728081 [ Android ] v8.browsing_mobile/browse:news:toi [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:news:cnn [ Skip ]
+crbug.com/767970 [ Mobile ] v8.browsing_mobile/browse:shopping:flipkart [ Skip ]
+crbug.com/708300 [ Mobile ] v8.browsing_mobile/browse:shopping:flipkart [ Skip ]
+[ Android_Webview ] v8.browsing_mobile/browse:chrome:newtab [ Skip ]
+
+# Benchmark: v8.browsing_mobile-future
+crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/* [ Skip ]
+crbug.com/768472 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:shopping:lazada [ Skip ]
+crbug.com/714650 [ Android ] v8.browsing_mobile-future/browse:news:globo [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:tech:discourse_infinite_scroll [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:shopping:avito [ Skip ]
+[ Android_Webview ] v8.browsing_mobile-future/browse:chrome:omnibox [ Skip ]
+crbug.com/728081 [ Android ] v8.browsing_mobile-future/browse:news:toi [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:news:cnn [ Skip ]
+crbug.com/767970 [ Mobile ] v8.browsing_mobile-future/browse:shopping:flipkart [ Skip ]
+crbug.com/708300 [ Mobile ] v8.browsing_mobile-future/browse:shopping:flipkart [ Skip ]
+[ Android_Webview ] v8.browsing_mobile-future/browse:chrome:newtab [ Skip ]
+
+# Benchmark: v8.detached_context_age_in_gc
+crbug.com/770982 [ Win ] v8.detached_context_age_in_gc/Docs_(1_open_document_tab) [ Skip ]
+
+# Benchmark: v8.runtime_stats.top_25
+crbug.com/664318 [ Android ] v8.runtime_stats.top_25/* [ Skip ]
+crbug.com/664318 [ Win ] v8.runtime_stats.top_25/* [ Skip ]
+
+# Benchmark: wasm
+[ Android ] wasm/WasmTanks [ Skip ]
+crbug.com/788976 [ Cherry_Mobile_Android_One ] wasm/WasmSpaceBuggy [ Skip ]
+crbug.com/788976 [ Android_Webview ] wasm/WasmSpaceBuggy [ Skip ]
+
+# Benchmark: webrtc
+crbug.com/468732 [ All ] webrtc/audio_call_opus_10s [ Skip ]
+crbug.com/468732 [ All ] webrtc/audio_call_g772_10s [ Skip ]
+crbug.com/468732 [ All ] webrtc/audio_call_isac/1600_10s [ Skip ]
+crbug.com/468732 [ All ] webrtc/audio_call_pcmu_10s [ Skip ]
+
 ##### Perf FYI benchmarks go after here #####
 # Benchmark: loading.desktop.network_service
 crbug.com/723783 [ Win ] loading.desktop.network_service/Orange [ Skip ]
 crbug.com/752611 [ Linux ] loading.desktop.network_service/uol.com.br [ Skip ]
-
-
diff --git a/tools/perf/page_sets/system_health/expectations.py b/tools/perf/page_sets/system_health/expectations.py
deleted file mode 100644
index e6fccab..0000000
--- a/tools/perf/page_sets/system_health/expectations.py
+++ /dev/null
@@ -1,66 +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.
-from telemetry.story import expectations
-
-
-class SystemHealthDesktopCommonExpectations(expectations.StoryExpectations):
-  def SetExpectations(self):
-    self.DisableStory('browse:news:hackernews',
-                      [expectations.ALL_WIN, expectations.ALL_MAC],
-                      'crbug.com/676336')
-    self.DisableStory('browse:search:google', [expectations.ALL_WIN],
-                      'crbug.com/673775')
-    self.DisableStory('play:media:google_play_music', [expectations.ALL],
-                      'crbug.com/649392')
-    self.DisableStory('play:media:soundcloud', [expectations.ALL_WIN],
-                      'crbug.com/649392')
-    self.DisableStory('play:media:pandora', [expectations.ALL],
-                      'crbug.com/64939')
-    self.DisableStory('browse:media:tumblr',
-                      [expectations.ALL_WIN], 'crbug.com/773393')
-    self.DisableStory('browse:news:cnn',
-                      [expectations.ALL_MAC], 'crbug.com/728576')
-    self.DisableStory('browse_accessibility:tools:gmail_compose',
-                      [expectations.ALL], 'crbug.com/769809')
-    self.DisableStory('browse:tools:maps', [expectations.ALL_MAC],
-                      'crbug.com/773084')
-    self.DisableStory('load:media:youtube', [expectations.ALL_MAC],
-                      'crbug.com/795585')
-
-
-class SystemHealthMobileCommonExpectations(expectations.StoryExpectations):
-  def SetExpectations(self):
-    self.DisableStory('browse:shopping:flipkart', [expectations.ALL_ANDROID],
-                      'crbug.com/708300')
-    self.DisableStory('browse:news:globo', [expectations.ALL_ANDROID],
-                      'crbug.com/714650')
-    self.DisableStory('load:tools:gmail', [expectations.ALL_ANDROID],
-                      'crbug.com/657433')
-    self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID],
-                      'crbug.com/728081')
-    self.DisableStory(
-        'load:tools:drive',
-        [expectations.ANDROID_NEXUS5X, expectations.ANDROID_WEBVIEW],
-        'crbug.com/738854')
-    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
-    self.DisableStory('browse:chrome:omnibox',
-                      [expectations.ANDROID_WEBVIEW],
-                      'Webview does not have omnibox')
-    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
-    self.DisableStory('browse:chrome:newtab',
-                      [expectations.ANDROID_WEBVIEW],
-                      'Webview does not have NTP')
-    # TODO(rnephew): This disabling should move to CanRunOnBrowser.
-    self.DisableStory('long_running:tools:gmail-background',
-                      [expectations.ANDROID_WEBVIEW],
-                      'Webview does not have tabs')
-    self.DisableStory('browse:shopping:avito',
-                      [expectations.ANDROID_NEXUS6], 'crbug.com/736497')
-    self.DisableStory('load:media:soundcloud',
-                      [expectations.ANDROID_WEBVIEW], 'crbug.com/787001')
-
-
-class SystemHealthWebviewStartupExpectations(expectations.StoryExpectations):
-  def SetExpectations(self):
-    pass
diff --git a/tools/perf/system_health_stories.csv b/tools/perf/system_health_stories.csv
index 06de7f9..5791bd0 100644
--- a/tools/perf/system_health_stories.csv
+++ b/tools/perf/system_health_stories.csv
@@ -3,19 +3,19 @@
 background:news:nytimes,mobile,"Load http://www.nytimes.com/2016/10/04/us/politics/vice-presidential-debate.html?_r=0, then put the browser into the background.", 

 background:search:google,mobile,"Load https://www.google.co.uk/#q=tom+cruise+movies, then put the browser into the background.", 

 background:social:facebook,mobile,"Load https://www.facebook.com/rihanna, then put the browser into the background.", 

-background:tools:gmail,mobile,Load https://mail.google.com/mail/,Nexus 5

+background:tools:gmail,mobile,Load https://mail.google.com/mail/,Nexus_5

 browse:chrome:newtab,mobile,"Story that loads new tab page and performs searches.
 
   Given a list of typical search queries, this story does for each of them:
    - enter the search query on the new tab page search box
    - read results
    - navigates back to new tab page
-  ",Android Webview

+  ",Android_Webview

 browse:chrome:omnibox,mobile,"Story that peforms search by using omnibox search provider
 
   Loads a website and enters a search query on omnibox and navigates to default
   search provider (google).
-  ",Android Webview

+  ",Android_Webview

 browse:media:facebook_photos,mobile,"Load a photo page from Rihanna's facebook page then navigate a few next
   photos.
   ", 

@@ -67,10 +67,10 @@
 
   ", 

 browse:shopping:amazon,mobile,Load https://www.amazon.co.in/s/?field-keywords=Mobile and navigate to some items/articles., 

-browse:shopping:avito,mobile,Load https://www.avito.ru/rossiya and navigate to some items/articles.,Nexus 6

+browse:shopping:avito,mobile,Load https://www.avito.ru/rossiya and navigate to some items/articles.,Nexus_6

 browse:shopping:flipkart,mobile,Load https://flipkart.com/search?q=Sunglasses and navigate to some items/articles.,Android

 browse:shopping:lazada,mobile,Load https://www.lazada.co.id/catalog/?q=Wrist+watch and navigate to some items/articles., 

-browse:social:facebook,mobile,Load https://www.facebook.com/rihanna and navigate to some items/articles.,Nexus 5

+browse:social:facebook,mobile,Load https://www.facebook.com/rihanna and navigate to some items/articles.,Nexus_5

 browse:social:facebook_infinite_scroll,desktop,Load https://www.facebook.com/shakira then make a very long scroll., 

 browse:social:facebook_infinite_scroll,mobile,Load https://m.facebook.com/shakira then make a very long scroll., 

 browse:social:instagram,mobile,Load https://www.instagram.com/badgalriri/ and navigate to some items/articles., 

@@ -114,7 +114,7 @@
 load:media:facebook_photos,mobile,Load a page of rihanna's facebook with a photo., 

 load:media:google_images,all,Load https://www.google.co.uk/search?tbm=isch&q=love, 

 load:media:imgur,all,Load http://imgur.com/gallery/5UlBN, 

-load:media:soundcloud,all,Load https://soundcloud.com/lifeofdesiigner/desiigner-panda,Android Webview

+load:media:soundcloud,all,Load https://soundcloud.com/lifeofdesiigner/desiigner-panda,Android_Webview

 load:media:youtube,all,Load https://www.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false, 

 load:news:bbc,desktop,Load https://www.bbc.co.uk/news/world-asia-china-36189636, 

 load:news:cnn,all,Load http://edition.cnn.com, 

@@ -141,7 +141,7 @@
 load:social:twitter,mobile,Load https://www.twitter.com/nasa, 

 load:social:vk,desktop,Load https://vk.com/sbeatles, 

 load:tools:docs,all,Load a typical google doc page., 

-load:tools:drive,all,Load https://drive.google.com/drive/my-drive,"Nexus 5X, Android Webview"

+load:tools:drive,all,Load https://drive.google.com/drive/my-drive,"Nexus_5X, Android_Webview"

 load:tools:dropbox,all,Load https://www.dropbox.com, 

 load:tools:gmail,desktop,Load https://mail.google.com/mail/,Android

 load:tools:gmail,mobile,Load https://mail.google.com/mail/,Android

@@ -149,8 +149,8 @@
 load:tools:weather,all,Load https://weather.com/en-GB/weather/today/l/USCA0286:1:US, 

 load_accessibility:media:wikipedia,desktop,"Wikipedia page on Accessibility. Long, but very simple, clean layout.", 

 load_accessibility:shopping:amazon,desktop,Amazon results page. Good example of a site with a data table., 

-long_running:tools:gmail-background,desktop,Load https://mail.google.com/mail/ then open a new blank tab and let the loaded page stay in background for 100 seconds.,"Android Webview, Android Svelte"

-long_running:tools:gmail-background,mobile,Load https://mail.google.com/mail/ then open a new blank tab and let the loaded page stay in background for 100 seconds.,"Android Webview, Android Svelte"

+long_running:tools:gmail-background,desktop,Load https://mail.google.com/mail/ then open a new blank tab and let the loaded page stay in background for 100 seconds.,"Android_Webview, Android_Svelte"

+long_running:tools:gmail-background,mobile,Load https://mail.google.com/mail/ then open a new blank tab and let the loaded page stay in background for 100 seconds.,"Android_Webview, Android_Svelte"

 long_running:tools:gmail-foreground,desktop,Load https://mail.google.com/mail/ then let it stay in foreground for 100 seconds., 

 long_running:tools:gmail-foreground,mobile,Load https://mail.google.com/mail/ then let it stay in foreground for 100 seconds., 

 multitab:misc:typical24,desktop,"Load 24 different web sites in 24 tabs, then cycle through each tab.",Mac

diff --git a/ui/message_center/views/message_view.h b/ui/message_center/views/message_view.h
index 79d73e8..48d4d5a3 100644
--- a/ui/message_center/views/message_view.h
+++ b/ui/message_center/views/message_view.h
@@ -70,7 +70,7 @@
   virtual void OnContainerAnimationEnded();
 
   void OnCloseButtonPressed();
-  void OnSettingsButtonPressed();
+  virtual void OnSettingsButtonPressed();
 
   // views::View
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index cda4aa0..a5bb0478 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -33,6 +33,7 @@
 #include "ui/views/animation/ink_drop_highlight.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
+#include "ui/views/controls/button/radio_button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/progress_bar.h"
@@ -64,6 +65,9 @@
 constexpr gfx::Insets kLeftContentPadding(2, 4, 0, 4);
 constexpr gfx::Insets kLeftContentPaddingWithIcon(2, 4, 0, 12);
 constexpr gfx::Insets kNotificationInputPadding(0, 16, 0, 16);
+constexpr gfx::Insets kSettingsRowPadding(8, 0, 0, 0);
+constexpr gfx::Insets kSettingsRadioButtonPadding(14, 18, 14, 18);
+constexpr gfx::Insets kSettingsButtonRowPadding(8);
 
 // Background of inline actions area.
 const SkColor kActionsRowBackgroundColor = SkColorSetRGB(0xee, 0xee, 0xee);
@@ -384,6 +388,17 @@
   }
 }
 
+// InlineSettingsRadioButton ///////////////////////////////////////////////////
+
+class InlineSettingsRadioButton : public views::RadioButton {
+ public:
+  InlineSettingsRadioButton(const base::string16& label_text)
+      : views::RadioButton(label_text, 1 /* group */, true /* force_md */) {
+    label()->SetFontList(GetTextFontList());
+    label()->SetEnabledColor(kRegularTextColorMD);
+  }
+};
+
 // ////////////////////////////////////////////////////////////
 // NotificationViewMD
 // ////////////////////////////////////////////////////////////
@@ -410,6 +425,11 @@
   }
   if (inline_reply_->visible())
     buttons.push_back(inline_reply_);
+  if (settings_row_) {
+    buttons.push_back(block_all_button_);
+    buttons.push_back(dont_block_button_);
+    buttons.push_back(settings_done_button_);
+  }
 
   for (size_t i = 0; i < buttons.size(); ++i) {
     gfx::Point point_in_child = point;
@@ -432,6 +452,7 @@
   CreateOrUpdateIconView(notification);
   CreateOrUpdateSmallIconView(notification);
   CreateOrUpdateImageView(notification);
+  CreateOrUpdateInlineSettingsViews(notification);
   UpdateViewForExpandedState(expanded_);
   // Should be called at the last because SynthesizeMouseMoveEvent() requires
   // everything is in the right location when called.
@@ -505,10 +526,9 @@
 
   click_activator_ = std::make_unique<ClickActivator>(this);
   // Reasons to use pretarget handler instead of OnMousePressed:
+  // - NotificationViewMD::OnMousePresssed would not fire on the inline reply
+  //   textfield click in native notification.
   // - To make it look similar to ArcNotificationContentView::EventForwarder.
-  // - If we're going to support inline reply feature in native notification,
-  //   then NotificationViewMD::OnMousePresssed would not fire anymore on the
-  //   Textfield click.
   AddPreTargetHandler(click_activator_.get());
 }
 
@@ -568,6 +588,10 @@
       return views::View::GetCursor(event);
   }
 
+  // Do not change the cursor when inline settings is shown.
+  if (settings_row_ && settings_row_->visible())
+    return views::View::GetCursor(event);
+
   return views::GetNativeHandCursor();
 }
 
@@ -594,6 +618,10 @@
       return true;
   }
 
+  // Ignore clicks of outside region when inline settings is shown.
+  if (settings_row_ && settings_row_->visible())
+    return true;
+
   return MessageView::OnMousePressed(event);
 }
 
@@ -625,10 +653,12 @@
 
   // Tapping anywhere on |header_row_| can expand the notification, though only
   // |expand_button| can be focused by TAB.
-  if (IsExpandable() && sender == header_row_) {
-    ToggleExpanded();
-    Layout();
-    SchedulePaint();
+  if (sender == header_row_) {
+    if (IsExpandable()) {
+      ToggleExpanded();
+      Layout();
+      SchedulePaint();
+    }
     return;
   }
 
@@ -648,6 +678,13 @@
     }
     return;
   }
+
+  if (sender == settings_done_button_) {
+    if (block_all_button_->checked())
+      MessageCenter::Get()->DisableNotification(id);
+    ToggleInlineSettings();
+    return;
+  }
 }
 
 void NotificationViewMD::OnNotificationInputSubmit(size_t index,
@@ -956,6 +993,56 @@
   }
 }
 
+void NotificationViewMD::CreateOrUpdateInlineSettingsViews(
+    const Notification& notification) {
+  if (settings_row_) {
+    DCHECK_EQ(SettingsButtonHandler::TRAY,
+              notification.rich_notification_data().settings_button_handler);
+    return;
+  }
+
+  if (notification.rich_notification_data().settings_button_handler !=
+      SettingsButtonHandler::TRAY) {
+    return;
+  }
+
+  // |settings_row_| contains inline settings.
+  settings_row_ = new views::View();
+  settings_row_->SetLayoutManager(new views::BoxLayout(
+      views::BoxLayout::kVertical, kSettingsRowPadding, 0));
+  settings_row_->SetBackground(
+      views::CreateSolidBackground(kActionsRowBackgroundColor));
+
+  block_all_button_ = new InlineSettingsRadioButton(
+      l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS));
+  block_all_button_->set_listener(this);
+  block_all_button_->SetBorder(
+      views::CreateEmptyBorder(kSettingsRadioButtonPadding));
+  settings_row_->AddChildView(block_all_button_);
+
+  dont_block_button_ = new InlineSettingsRadioButton(
+      l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_DONT_BLOCK_NOTIFICATIONS));
+  dont_block_button_->set_listener(this);
+  dont_block_button_->SetBorder(
+      views::CreateEmptyBorder(kSettingsRadioButtonPadding));
+  settings_row_->AddChildView(dont_block_button_);
+  settings_row_->SetVisible(false);
+
+  settings_done_button_ = new NotificationButtonMD(
+      this, false, l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_SETTINGS_DONE),
+      base::EmptyString16());
+  auto* settings_button_row = new views::View;
+  auto* settings_button_layout = new views::BoxLayout(
+      views::BoxLayout::kHorizontal, kSettingsButtonRowPadding, 0);
+  settings_button_layout->set_main_axis_alignment(
+      views::BoxLayout::MAIN_AXIS_ALIGNMENT_END);
+  settings_button_row->SetLayoutManager(settings_button_layout);
+  settings_button_row->AddChildView(settings_done_button_);
+  settings_row_->AddChildView(settings_button_row);
+
+  AddChildViewAt(settings_row_, GetIndexOf(actions_row_));
+}
+
 bool NotificationViewMD::IsExpandable() {
   // Expandable if the message exceeds one line.
   if (message_view_ && message_view_->visible() &&
@@ -1028,6 +1115,29 @@
   }
 }
 
+void NotificationViewMD::ToggleInlineSettings() {
+  DCHECK(settings_row_);
+
+  bool inline_settings_visible = !settings_row_->visible();
+
+  settings_row_->SetVisible(inline_settings_visible);
+  content_row_->SetVisible(!inline_settings_visible);
+  actions_row_->SetVisible(expanded_ && !inline_settings_visible);
+
+  // When inline settings is shown, the background color of the entire
+  // notification should be |kActionsRowBackgroundColor|.
+  header_row_->SetBackground(views::CreateSolidBackground(
+      inline_settings_visible ? kActionsRowBackgroundColor
+                              : kNotificationBackgroundColor));
+
+  // Always check "Don't block" when inline settings is shown.
+  // If it's already blocked, users should not see inline settings.
+  // Toggling should reset the state.
+  dont_block_button_->SetChecked(true);
+
+  PreferredSizeChanged();
+}
+
 // TODO(yoshiki): Move this to the parent class (MessageView) and share the code
 // among NotificationView and ArcNotificationView.
 void NotificationViewMD::UpdateControlButtonsVisibility() {
@@ -1057,6 +1167,13 @@
   PreferredSizeChanged();
 }
 
+void NotificationViewMD::OnSettingsButtonPressed() {
+  if (settings_row_)
+    ToggleInlineSettings();
+  else
+    MessageView::OnSettingsButtonPressed();
+}
+
 void NotificationViewMD::Activate() {
   GetWidget()->widget_delegate()->set_can_activate(true);
   GetWidget()->Activate();
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h
index 4f6f9433..fff3695 100644
--- a/ui/message_center/views/notification_view_md.h
+++ b/ui/message_center/views/notification_view_md.h
@@ -21,6 +21,7 @@
 class Label;
 class LabelButton;
 class ProgressBar;
+class RadioButton;
 }
 
 namespace message_center {
@@ -196,6 +197,7 @@
   NotificationControlButtonsView* GetControlButtonsView() const override;
   bool IsExpanded() const override;
   void SetExpanded(bool expanded) override;
+  void OnSettingsButtonPressed() override;
 
   // Overridden from NotificationInputDelegate:
   void OnNotificationInputSubmit(size_t index,
@@ -214,6 +216,7 @@
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, ExpandLongMessage);
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestAccentColor);
   FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UseImageAsIcon);
+  FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, InlineSettings);
 
   friend class NotificationViewMDTest;
 
@@ -233,10 +236,12 @@
   void CreateOrUpdateSmallIconView(const Notification& notification);
   void CreateOrUpdateImageView(const Notification& notification);
   void CreateOrUpdateActionButtonViews(const Notification& notification);
+  void CreateOrUpdateInlineSettingsViews(const Notification& notification);
 
   bool IsExpandable();
   void ToggleExpanded();
   void UpdateViewForExpandedState(bool expanded);
+  void ToggleInlineSettings();
 
   // View containing close and settings buttons
   std::unique_ptr<NotificationControlButtonsView> control_buttons_view_;
@@ -257,12 +262,13 @@
   NotificationHeaderView* header_row_ = nullptr;
   views::View* content_row_ = nullptr;
   views::View* actions_row_ = nullptr;
+  views::View* settings_row_ = nullptr;
 
   // Containers for left and right side on |content_row_|
   views::View* left_content_ = nullptr;
   views::View* right_content_ = nullptr;
 
-  // Views which are dinamicallly created inside view hierarchy.
+  // Views which are dynamically created inside view hierarchy.
   views::Label* title_view_ = nullptr;
   BoundedLabel* message_view_ = nullptr;
   views::Label* status_view_ = nullptr;
@@ -275,6 +281,11 @@
   views::View* action_buttons_row_ = nullptr;
   NotificationInputMD* inline_reply_ = nullptr;
 
+  // Views for inline settings.
+  views::RadioButton* block_all_button_ = nullptr;
+  views::RadioButton* dont_block_button_ = nullptr;
+  views::LabelButton* settings_done_button_ = nullptr;
+
   std::unique_ptr<ui::EventHandler> click_activator_;
 
   DISALLOW_COPY_AND_ASSIGN(NotificationViewMD);
diff --git a/ui/message_center/views/notification_view_md_unittest.cc b/ui/message_center/views/notification_view_md_unittest.cc
index 58171ef..b1e4f05 100644
--- a/ui/message_center/views/notification_view_md_unittest.cc
+++ b/ui/message_center/views/notification_view_md_unittest.cc
@@ -22,6 +22,7 @@
 #include "ui/message_center/views/proportional_image_view.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/radio_button.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/test/widget_test.h"
 
@@ -53,10 +54,13 @@
     submitted_reply_string_ = reply;
   }
 
+  void DisableNotification() override { disable_notification_called_ = true; }
+
   int clicked_button_index() const { return clicked_button_index_; }
   const base::string16& submitted_reply_string() const {
     return submitted_reply_string_;
   }
+  bool disable_notification_called() { return disable_notification_called_; }
   void set_expecting_button_click(bool expecting) {
     expecting_button_click_ = expecting;
   }
@@ -71,6 +75,7 @@
   base::string16 submitted_reply_string_;
   bool expecting_button_click_ = false;
   bool expecting_reply_submission_ = false;
+  bool disable_notification_called_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(NotificationTestDelegate);
 };
@@ -137,6 +142,7 @@
   // Create a dummy notification.
   delegate_ = new NotificationTestDelegate();
   data_.reset(new RichNotificationData());
+  data_->settings_button_handler = SettingsButtonHandler::TRAY;
   notification_.reset(new Notification(
       NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"),
       base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"),
@@ -703,4 +709,49 @@
   EXPECT_FALSE(notification_view()->icon_view_->visible());
 }
 
+TEST_F(NotificationViewMDTest, InlineSettings) {
+  notification()->set_type(NOTIFICATION_TYPE_SIMPLE);
+  UpdateNotificationViews();
+
+  // Inline settings will be shown by clicking settings button.
+  EXPECT_FALSE(notification_view()->settings_row_->visible());
+  notification_view()->OnSettingsButtonPressed();
+  EXPECT_TRUE(notification_view()->settings_row_->visible());
+
+  // By clicking settings button again, it will toggle.
+  notification_view()->OnSettingsButtonPressed();
+  EXPECT_FALSE(notification_view()->settings_row_->visible());
+
+  // Show inline settings again.
+  notification_view()->OnSettingsButtonPressed();
+  EXPECT_TRUE(notification_view()->settings_row_->visible());
+
+  // Construct a mouse click event 1 pixel inside the done button.
+  gfx::Point done_cursor_location(1, 1);
+  views::View::ConvertPointToScreen(notification_view()->settings_done_button_,
+                                    &done_cursor_location);
+  ui::test::EventGenerator generator(widget()->GetNativeWindow());
+  generator.MoveMouseTo(done_cursor_location);
+  generator.ClickLeftButton();
+
+  // Just clicking Done button should not change the setting.
+  EXPECT_FALSE(notification_view()->settings_row_->visible());
+  EXPECT_FALSE(delegate_->disable_notification_called());
+
+  notification_view()->OnSettingsButtonPressed();
+  EXPECT_TRUE(notification_view()->settings_row_->visible());
+
+  // Construct a mouse click event 1 pixel inside the block all button.
+  gfx::Point block_cursor_location(1, 1);
+  views::View::ConvertPointToScreen(notification_view()->block_all_button_,
+                                    &block_cursor_location);
+  generator.MoveMouseTo(block_cursor_location);
+  generator.ClickLeftButton();
+  generator.MoveMouseTo(done_cursor_location);
+  generator.ClickLeftButton();
+
+  EXPECT_FALSE(notification_view()->settings_row_->visible());
+  EXPECT_TRUE(delegate_->disable_notification_called());
+}
+
 }  // namespace message_center
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd
index 63f1060..a43a030 100644
--- a/ui/strings/ui_strings.grd
+++ b/ui/strings/ui_strings.grd
@@ -655,6 +655,15 @@
       <message name="IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST" desc="Phrase describing a time duration using years that is as short as possible, preferrably one character. Should be same as AndroidPlatform msgId 7848711145196397042. (frameworks/base/core/res/res/values/strings.xml:plurals:duration_years_shortest) [ICU Syntax]">
         {YEARS, plural, =1 {1y} other {#y}}
       </message>
+      <message name="IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS" desc="The label for the radio button to block all the notifications from this notification origin.">
+        Block all notifications
+      </message>
+      <message name="IDS_MESSAGE_CENTER_DONT_BLOCK_NOTIFICATIONS" desc="The label for the radio button to allow all the notifications from this notification origin.">
+        Don't block
+      </message>
+      <message name="IDS_MESSAGE_CENTER_SETTINGS_DONE" desc="The caption of the button to finish inline notification settings.">
+        Done
+      </message>
       <message name="IDS_MESSAGE_CENTER_CLOSE_NOTIFICATION_BUTTON_ACCESSIBLE_NAME" desc="The spoken feedback text for the close button in a notification. Usually 'button' is suffixed to this text automatically.">
         Notification close
       </message>