diff --git a/DEPS b/DEPS
index 96267a9..ec1a3f7 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'ac44d69a7dba219efc6ead5d76ad364ab79bddab',
+  'skia_revision': '87185f7539f4e55fbf2e5eea458b8980c34a8d1d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java
index ddee6f6..97dc2ff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java
@@ -12,6 +12,7 @@
 import android.os.AsyncTask;
 import android.os.Build;
 import android.support.v4.app.NotificationManagerCompat;
+import android.text.TextUtils;
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
@@ -94,8 +95,9 @@
                 Class[] args = {String.class, String.class, boolean.class, String.class,
                         String.class, long.class, boolean.class, Uri.class, Uri.class};
                 Method method = c.getMethod("addCompletedDownload", args);
-                Uri originalUri = Uri.parse(originalUrl);
-                Uri refererUri = referer == null ? Uri.EMPTY : Uri.parse(referer);
+                // OriginalUri has to be null or non-empty.
+                Uri originalUri = TextUtils.isEmpty(originalUrl) ? null : Uri.parse(originalUrl);
+                Uri refererUri = TextUtils.isEmpty(referer) ? null : Uri.parse(referer);
                 downloadId = (Long) method.invoke(manager, fileName, description, true, mimeType,
                         path, length, useSystemNotification, originalUri, refererUri);
             } catch (SecurityException e) {
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index de8d3c9..f24005e 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6321,12 +6321,6 @@
         This is to be used in conjunction with the trace-upload-url flag.
         WARNING: When enabled, Chrome will record performance data for every navigation and upload it to the URL specified by the trace-upload-url flag. The trace may include personally identifiable information (PII) such as the titles and URLs of websites you visit.
       </message>
-      <message name="IDS_FLAGS_ENABLE_NON_VALIDATING_RELOAD_ON_NORMAL_RELOAD_NAME" desc="Name of the flag to enable non-validating reload">
-        Enable non-validating reload
-      </message>
-      <message name="IDS_FLAGS_ENABLE_NON_VALIDATING_RELOAD_ON_NORMAL_RELOAD_DESCRIPTION" desc="Description of the flag to enable non-validating reload">
-        Forces reload UIs trigger non-validating reload (while it usually means regular, cache-validating reload when the flag is disabled).
-      </message>
       <message name="IDS_FLAGS_TRACE_UPLOAD_URL" desc="Name of the flag to set the trace upload url">
         Trace label for navigation tracing
       </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 53b0a78..d7725b1 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1060,10 +1060,6 @@
     {"enable-navigation-tracing", IDS_FLAGS_ENABLE_NAVIGATION_TRACING,
      IDS_FLAGS_ENABLE_NAVIGATION_TRACING_DESCRIPTION, kOsAll,
      SINGLE_VALUE_TYPE(switches::kEnableNavigationTracing)},
-    {"enable-non-validating-reload-on-normal-reload",
-     IDS_FLAGS_ENABLE_NON_VALIDATING_RELOAD_ON_NORMAL_RELOAD_NAME,
-     IDS_FLAGS_ENABLE_NON_VALIDATING_RELOAD_ON_NORMAL_RELOAD_DESCRIPTION,
-     kOsAll, FEATURE_VALUE_TYPE(features::kNonValidatingReloadOnNormalReload)},
     {"trace-upload-url", IDS_FLAGS_TRACE_UPLOAD_URL,
      IDS_FLAGS_TRACE_UPLOAD_URL_DESCRIPTION, kOsAll,
      MULTI_VALUE_TYPE(kTraceUploadURL)},
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
index 02a56b1..01429006 100644
--- a/chrome/browser/android/download/download_manager_service.cc
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -93,7 +93,8 @@
 
   base::TimeDelta time_delta;
   item->TimeRemaining(&time_delta);
-
+  std::string original_url = item->GetOriginalUrl().SchemeIs(url::kDataScheme)
+      ? std::string() : item->GetOriginalUrl().spec();
   return Java_DownloadInfo_createDownloadInfo(
       env,
       ConvertUTF8ToJavaString(env, item->GetGuid()),
@@ -109,7 +110,7 @@
       item->IsPaused(),
       has_user_gesture,
       item->CanResume(),
-      ConvertUTF8ToJavaString(env, item->GetOriginalUrl().spec()),
+      ConvertUTF8ToJavaString(env, original_url),
       ConvertUTF8ToJavaString(env, item->GetReferrerUrl().spec()),
       time_delta.InMilliseconds());
 }
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html
index 5e7314a1..31eef10 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -89,9 +89,11 @@
             <span class="list-item"
                 hidden="[[isHelpTextHidden_(languages.enabled.*)]]">
               <span>$i18n{orderLanguagesInstructions}</span>
+<if expr="chromeos">
               <a href="$i18n{languagesLearnMoreURL}" target="_blank">
                 $i18n{learnMore}
               </a>
+</if>
             </span>
             <template is="dom-repeat" items="[[languages.enabled]]">
               <div class$="list-item [[getLanguageItemClass_(
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 01f24cd..5843541 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -917,9 +917,13 @@
   AddLocalizedStringsBulk(html_source, localized_strings,
                           arraysize(localized_strings));
 
+#if defined(OS_CHROMEOS)
+  // Only the Chrome OS help article explains how language order affects website
+  // language.
   html_source->AddString(
       "languagesLearnMoreURL",
       base::ASCIIToUTF16(chrome::kLanguageSettingsLearnMoreUrl));
+#endif
 }
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 2b04d80..b703ab75 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -619,6 +619,7 @@
 // Add hosts here to be included in chrome://chrome-urls (about:about).
 // These hosts will also be suggested by BuiltinProvider.
 const char* const kChromeHostURLs[] = {
+    kChromeUIAboutHost,
     kChromeUIBluetoothInternalsHost,
     kChromeUICacheHost,
     kChromeUIChromeURLsHost,
@@ -644,6 +645,7 @@
     kChromeUIPredictorsHost,
     kChromeUIProfilerHost,
     kChromeUISignInInternalsHost,
+    kChromeUISiteEngagementHost,
     kChromeUISuggestionsHost,
     kChromeUISupervisedUserInternalsHost,
     kChromeUISyncInternalsHost,
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 58e4470..8b623619 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -581,6 +581,7 @@
 extern const char kMediaAccessLearnMoreUrl[];
 
 // The URL for the "Learn more" link in the language settings.
+// TODO(michaelpg): Compile on Chrome OS only when Options is removed.
 extern const char kLanguageSettingsLearnMoreUrl[];
 
 #if defined(GOOGLE_CHROME_BUILD) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc
index 42432411..c2d7a37d 100644
--- a/chrome/renderer/net/net_error_helper.cc
+++ b/chrome/renderer/net/net_error_helper.cc
@@ -315,7 +315,7 @@
 void NetErrorHelper::ReloadPage(bool bypass_cache) {
   render_frame()->GetWebFrame()->reload(
       bypass_cache ? blink::WebFrameLoadType::ReloadBypassingCache
-                   : blink::WebFrameLoadType::Reload);
+                   : blink::WebFrameLoadType::ReloadMainResource);
 }
 
 void NetErrorHelper::LoadPageFromCache(const GURL& page_url) {
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 96d224c..60baf186 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-9038.0.0
\ No newline at end of file
+9041.0.0
\ No newline at end of file
diff --git a/components/subresource_filter/content/renderer/document_subresource_filter.cc b/components/subresource_filter/content/renderer/document_subresource_filter.cc
index f17a1ca..8e326a9e 100644
--- a/components/subresource_filter/content/renderer/document_subresource_filter.cc
+++ b/components/subresource_filter/content/renderer/document_subresource_filter.cc
@@ -12,6 +12,7 @@
 #include "base/trace_event/trace_event.h"
 #include "components/subresource_filter/core/common/first_party_origin.h"
 #include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
+#include "components/subresource_filter/core/common/scoped_timers.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
 
 namespace subresource_filter {
@@ -87,6 +88,11 @@
                                    ? std::string()
                                    : ancestor_document_urls[0].spec());
 
+  SCOPED_UMA_HISTOGRAM_MICRO_TIMER(
+      "SubresourceFilter.DocumentLoad.Activation.WallDuration");
+  SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER(
+      "SubresourceFilter.DocumentLoad.Activation.CPUDuration");
+
   DCHECK_NE(activation_state_, ActivationState::DISABLED);
   DCHECK(ruleset);
 
@@ -124,6 +130,19 @@
   TRACE_EVENT1("loader", "DocumentSubresourceFilter::allowLoad", "url",
                resourceUrl.string().utf8());
 
+  auto wall_duration_exporter = [this](base::TimeDelta delta) {
+    statistics_.evaluation_total_wall_duration += delta;
+    UMA_HISTOGRAM_MICRO_TIMES(
+        "SubresourceFilter.SubresourceLoad.Evaluation.WallDuration", delta);
+  };
+  auto cpu_duration_exporter = [this](base::TimeDelta delta) {
+    statistics_.evaluation_total_cpu_duration += delta;
+    UMA_HISTOGRAM_MICRO_TIMES(
+        "SubresourceFilter.SubresourceLoad.Evaluation.CPUDuration", delta);
+  };
+  SCOPED_TIMER(wall_duration_exporter);
+  SCOPED_THREAD_TIMER(cpu_duration_exporter);
+
   ++statistics_.num_loads_total;
 
   if (filtering_disabled_for_document_)
diff --git a/components/subresource_filter/content/renderer/document_subresource_filter.h b/components/subresource_filter/content/renderer/document_subresource_filter.h
index fb72370..3858131 100644
--- a/components/subresource_filter/content/renderer/document_subresource_filter.h
+++ b/components/subresource_filter/content/renderer/document_subresource_filter.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "components/subresource_filter/core/common/activation_state.h"
 #include "components/subresource_filter/core/common/indexed_ruleset.h"
 #include "third_party/WebKit/public/platform/WebDocumentSubresourceFilter.h"
@@ -29,7 +30,6 @@
     : public blink::WebDocumentSubresourceFilter,
       public base::SupportsWeakPtr<DocumentSubresourceFilter> {
  public:
-  // TODO(pkalinnikov): Add total evaluation time metrics.
   struct Statistics {
     // The number of subresource loads that went through the allowLoad method.
     size_t num_loads_total = 0;
@@ -40,6 +40,10 @@
     size_t num_loads_evaluated = 0;
     size_t num_loads_matching_rules = 0;
     size_t num_loads_disallowed = 0;
+
+    // Total time spent in allowLoad() calls while evaluating subresource loads.
+    base::TimeDelta evaluation_total_wall_duration;
+    base::TimeDelta evaluation_total_cpu_duration;
   };
 
   // Constructs a new filter that will:
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
index 3eb3a21..6e6c1aa 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent.cc
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -7,10 +7,12 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
 #include "components/subresource_filter/content/common/subresource_filter_messages.h"
 #include "components/subresource_filter/content/renderer/document_subresource_filter.h"
 #include "components/subresource_filter/content/renderer/ruleset_dealer.h"
 #include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
+#include "components/subresource_filter/core/common/scoped_timers.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/renderer/render_frame.h"
 #include "ipc/ipc_message.h"
@@ -93,6 +95,22 @@
   UMA_HISTOGRAM_COUNTS_1000(
       "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Disallowed",
       statistics.num_loads_disallowed);
+
+  UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(
+      "SubresourceFilter.DocumentLoad.SubresourceEvaluation."
+      "TotalWallDuration",
+      statistics.evaluation_total_wall_duration,
+      base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(10),
+      50);
+
+  // If ThreadTicks is not supported, then no measurements have been collected.
+  if (base::ThreadTicks::IsSupported()) {
+    UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(
+        "SubresourceFilter.DocumentLoad.SubresourceEvaluation.TotalCPUDuration",
+        statistics.evaluation_total_cpu_duration,
+        base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(10),
+        50);
+  }
 }
 
 void SubresourceFilterAgent::OnDestruct() {
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
index 0911fd9c..992053a3 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
 #include "base/test/histogram_tester.h"
+#include "base/time/time.h"
 #include "components/subresource_filter/content/common/subresource_filter_messages.h"
 #include "components/subresource_filter/content/renderer/ruleset_dealer.h"
 #include "components/subresource_filter/core/common/test_ruleset_creator.h"
@@ -83,6 +84,10 @@
     "SubresourceFilter.DocumentLoad.NumSubresourceLoads.MatchedRules";
 constexpr const char kSubresourcesDisallowed[] =
     "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Disallowed";
+constexpr const char kEvaluationTotalWallDuration[] =
+    "SubresourceFilter.DocumentLoad.SubresourceEvaluation.TotalWallDuration";
+constexpr const char kEvaluationTotalCPUDuration[] =
+    "SubresourceFilter.DocumentLoad.SubresourceEvaluation.TotalCPUDuration";
 
 }  // namespace
 
@@ -321,6 +326,9 @@
   histogram_tester.ExpectTotalCount(kSubresourcesEvaluated, 0);
   histogram_tester.ExpectTotalCount(kSubresourcesMatchedRules, 0);
   histogram_tester.ExpectTotalCount(kSubresourcesDisallowed, 0);
+
+  histogram_tester.ExpectTotalCount(kEvaluationTotalWallDuration, 0);
+  histogram_tester.ExpectTotalCount(kEvaluationTotalCPUDuration, 0);
 }
 
 TEST_F(SubresourceFilterAgentTest,
@@ -338,6 +346,9 @@
   histogram_tester.ExpectTotalCount(kSubresourcesEvaluated, 0);
   histogram_tester.ExpectTotalCount(kSubresourcesMatchedRules, 0);
   histogram_tester.ExpectTotalCount(kSubresourcesDisallowed, 0);
+
+  histogram_tester.ExpectTotalCount(kEvaluationTotalWallDuration, 0);
+  histogram_tester.ExpectTotalCount(kEvaluationTotalCPUDuration, 0);
 }
 
 TEST_F(SubresourceFilterAgentTest, Enabled_HistogramSamples) {
@@ -376,6 +387,11 @@
               ::testing::ElementsAre(base::Bucket(1, 1), base::Bucket(2, 1)));
   EXPECT_THAT(histogram_tester.GetAllSamples(kSubresourcesDisallowed),
               ::testing::ElementsAre(base::Bucket(1, 1), base::Bucket(2, 1)));
+
+  histogram_tester.ExpectTotalCount(kEvaluationTotalWallDuration, 2);
+  const base::HistogramBase::Count total_count =
+      base::ThreadTicks::IsSupported() ? 2 : 0;
+  histogram_tester.ExpectTotalCount(kEvaluationTotalCPUDuration, total_count);
 }
 
 TEST_F(SubresourceFilterAgentTest, DryRun_HistogramSamples) {
@@ -403,6 +419,11 @@
   histogram_tester.ExpectUniqueSample(kSubresourcesEvaluated, 3, 1);
   histogram_tester.ExpectUniqueSample(kSubresourcesMatchedRules, 2, 1);
   histogram_tester.ExpectUniqueSample(kSubresourcesDisallowed, 0, 1);
+
+  histogram_tester.ExpectTotalCount(kEvaluationTotalWallDuration, 1);
+  const base::HistogramBase::Count total_count =
+      base::ThreadTicks::IsSupported() ? 1 : 0;
+  histogram_tester.ExpectTotalCount(kEvaluationTotalCPUDuration, total_count);
 }
 
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/core/browser/ruleset_service.cc b/components/subresource_filter/core/browser/ruleset_service.cc
index 3a0c5fcb..031a1f08 100644
--- a/components/subresource_filter/core/browser/ruleset_service.cc
+++ b/components/subresource_filter/core/browser/ruleset_service.cc
@@ -28,6 +28,7 @@
 #include "components/subresource_filter/core/common/copying_file_stream.h"
 #include "components/subresource_filter/core/common/indexed_ruleset.h"
 #include "components/subresource_filter/core/common/proto/rules.pb.h"
+#include "components/subresource_filter/core/common/scoped_timers.h"
 #include "components/subresource_filter/core/common/unindexed_ruleset.h"
 #include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
 
@@ -344,6 +345,8 @@
 bool RulesetService::IndexRuleset(base::File unindexed_ruleset_file,
                                   RulesetIndexer* indexer) {
   SCOPED_UMA_HISTOGRAM_TIMER("SubresourceFilter.IndexRuleset.WallDuration");
+  SCOPED_UMA_HISTOGRAM_THREAD_TIMER(
+      "SubresourceFilter.IndexRuleset.CPUDuration");
 
   int64_t unindexed_ruleset_size = unindexed_ruleset_file.GetLength();
   CopyingFileInputStream copying_stream(std::move(unindexed_ruleset_file));
diff --git a/components/subresource_filter/core/common/BUILD.gn b/components/subresource_filter/core/common/BUILD.gn
index 1b065d6..7708731c 100644
--- a/components/subresource_filter/core/common/BUILD.gn
+++ b/components/subresource_filter/core/common/BUILD.gn
@@ -23,6 +23,7 @@
     "memory_mapped_ruleset.cc",
     "memory_mapped_ruleset.h",
     "ngram_extractor.h",
+    "scoped_timers.h",
     "string_splitter.h",
     "uint64_hasher.h",
     "unindexed_ruleset.cc",
@@ -69,6 +70,7 @@
     "indexed_ruleset_unittest.cc",
     "knuth_morris_pratt_unittest.cc",
     "ngram_extractor_unittest.cc",
+    "scoped_timers_unittest.cc",
     "string_splitter_unittest.cc",
     "unindexed_ruleset_unittest.cc",
     "url_pattern_matching_unittest.cc",
@@ -76,6 +78,7 @@
   deps = [
     ":common",
     "//base",
+    "//base/test:test_support",
     "//testing/gtest",
     "//third_party/protobuf:protobuf_lite",
     "//url",
diff --git a/components/subresource_filter/core/common/scoped_timers.h b/components/subresource_filter/core/common/scoped_timers.h
new file mode 100644
index 0000000..58a834c2
--- /dev/null
+++ b/components/subresource_filter/core/common/scoped_timers.h
@@ -0,0 +1,248 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides tools for measuring time intervals and reporting them to
+// UMA histograms or via custom functors. It is possible to measure time both
+// with base::TimeTicks and base::ThreadTicks.
+// WARNING: *UMA_HISTOGRAM_* macros in this file are not thread-safe.
+// See also: "base/metrics/histogram_macros*.h".
+//
+// TODO(pkalinnikov): Consider moving content of this file to "base/metrics/*"
+// after some refactoring. Note that most of the code generated by the macros
+// below is not thread-safe.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_
+
+#include <type_traits>
+
+#include "base/macros.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
+
+namespace subresource_filter {
+
+// Creates a scoped object that measures its lifetime using base::TimeTicks, and
+// reports the result as base::TimeDelta via provided |export_functor|. The
+// functor is copied if passed in by value.
+//
+// Example:
+//   void Function() {
+//     auto export_time = [](base::TimeDelta delta) {
+//       LOG(INFO) << "Duration: " << delta.InMicroseconds();
+//     };
+//     SCOPED_TIMER(export_time);
+//     ... Useful things happen here ...
+//   }  // |export_time| will be triggered here.
+//
+// This is recommended for when you want to measure the time it takes for a
+// method/scope to execute, including, possibly, the time spent by the thread on
+// being blocked and/or descheduled.
+#define SCOPED_TIMER(export_functor)                                  \
+  IMPL_SCOPED_TIMER_EXPANDER(impl::TimeTicksProvider, export_functor, \
+                             __COUNTER__)
+
+// Similar to SCOPED_TIMER, but uses base::ThreadTicks for measuring time.
+//
+// This is recommended for when you want to measure the time it takes for a
+// method/scope to do actual work, i.e. excluding the time spent by the thread
+// on being blocked and/or descheduled.
+#define SCOPED_THREAD_TIMER(export_functor)                             \
+  IMPL_SCOPED_TIMER_EXPANDER(impl::ThreadTicksProvider, export_functor, \
+                             __COUNTER__)
+
+// Creates a scoped object that measures its lifetime using base::ThreadTicks,
+// and reports the result in milliseconds as a UMA statistic to a histogram with
+// the provided |name| which is expected to be a runtime constant. The histogram
+// collects times up to 10 seconds in 50 buckets.
+//
+// Under the hood there is a static base::HistogramBase* pointer initialized
+// right before the scoped object. The pointer is used by a specific
+// |export_functor| passed in to a SCOPED_THREAD_TIMER (see it above).
+//
+// Example:
+//   void Function() {
+//     SCOPED_UMA_HISTOGRAM_THREAD_TIMER("Component.FunctionTime");
+//     ... Useful things happen here ...
+//   }
+//
+// WARNING: The generated code is not thread-safe.
+#define SCOPED_UMA_HISTOGRAM_THREAD_TIMER(name)                             \
+  IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(                                 \
+      name, impl::ThreadTicksProvider, impl::ExportMillisecondsToHistogram, \
+      10 * 1000, __COUNTER__)
+
+// Similar to SCOPED_UMA_HISTOGRAM_THREAD_TIMER above, but the histogram
+// collects times in microseconds, up to 1 second, and using 50 buckets.
+//
+// WARNING: The generated code is not thread-safe.
+#define SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER(name)                       \
+  IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(                                 \
+      name, impl::ThreadTicksProvider, impl::ExportMicrosecondsToHistogram, \
+      1000 * 1000, __COUNTER__)
+
+// Similar to SCOPED_UMA_HISTOGRAM_TIMER in "base/metrics/histogram_macros.h",
+// but the histogram stores times in microseconds, up to 1 second, in 50
+// buckets.
+//
+// WARNING: The generated code is not thread-safe.
+#define SCOPED_UMA_HISTOGRAM_MICRO_TIMER(name)                            \
+  IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(                               \
+      name, impl::TimeTicksProvider, impl::ExportMicrosecondsToHistogram, \
+      1000 * 1000, __COUNTER__)
+
+// Similar to UMA_HISTOGRAM_TIMES in "base/metrics/histogram_macros.h", but
+// the histogram stores times in microseconds, up to 1 second, in 50 buckets.
+//
+// WARNING: The generated code is not thread-safe.
+#define UMA_HISTOGRAM_MICRO_TIMES(name, sample)                          \
+  UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(name, sample,                         \
+                                   base::TimeDelta::FromMicroseconds(1), \
+                                   base::TimeDelta::FromSeconds(1), 50)
+
+// This can be used when the default ranges are not sufficient. This macro lets
+// the metric developer customize the min and max of the sampled range, as well
+// as the number of buckets recorded.
+#define UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(name, sample, min, max, bucket_count) \
+  IMPL_UMA_HISTOGRAM_ADD(name, sample.InMicroseconds(), min.InMicroseconds(),  \
+                         max.InMicroseconds(), bucket_count)
+
+// -----------------------------------------------------------------------------
+// Below are helpers used by other macros. Shouldn't be used directly. ---------
+
+// This is necessary to expand __COUNTER__ to an actual value.
+#define IMPL_SCOPED_TIMER_EXPANDER(time_provider, export_functor, suffix) \
+  IMPL_SCOPED_TIMER_UNIQUE(time_provider, export_functor, suffix)
+
+// Creates a scoped timer, which uses |time_provider| to measure time, and
+// |export_functor| to report it.
+#define IMPL_SCOPED_TIMER_UNIQUE(time_provider, export_functor, suffix) \
+  impl::ScopedTimer<time_provider, decltype(export_functor)>            \
+      scoped_timer_##suffix(export_functor);
+
+// This is necessary to expand __COUNTER__ to an actual value.
+#define IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(               \
+    name, time_provider, histogram_exporter, max_value, suffix) \
+  IMPL_SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE(                       \
+      name, time_provider, histogram_exporter, max_value, suffix)
+
+// Creates a static histogram pointer and a scoped object referring to it
+// throught the |histogram_exporter| functor. Both the pointer and the scoped
+// object are uniquely-named, using the unique |suffix| passed in.
+#define IMPL_SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE(                            \
+    name, time_provider, histogram_exporter, max_value, suffix)            \
+  IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, 1, max_value, 50, suffix) \
+  IMPL_SCOPED_TIMER_UNIQUE(time_provider,                                  \
+                           (histogram_exporter(histogram_##suffix)), suffix)
+
+// This is necessary to expand __COUNTER__ to an actual value.
+#define IMPL_UMA_HISTOGRAM_MICRO_TIMES_EXPANDER(name, max_value, suffix, \
+                                                sample)                  \
+  IMPL_UMA_HISTOGRAM_MICRO_TIMES_UNIQUE(name, max_value, suffix, sample)
+
+// Defines a static UMA histogram pointer and writes a |sample| to it.
+#define IMPL_UMA_HISTOGRAM_ADD(name, sample, min, max, bucket_count)          \
+  do {                                                                        \
+    IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, min, max, bucket_count, 0) \
+    histogram_0->Add(sample);                                                 \
+  } while (0)
+
+// Defines a static pointer to a UMA histogram.
+//
+// WARNING: Static local variable initialization is deliberately *not*
+// thread-safe in Chrome builds. See the "-fno-threadsafe-statics" flag in
+// "build/config/compiler/BUILD.gn" and "/Zc:threadSafeInit-" in
+// "build/config/win/BUILD.gn" for details.
+#define IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, min, max, bucket_count, \
+                                                 suffix)                       \
+  static base::HistogramBase* histogram_##suffix =                             \
+      base::Histogram::FactoryGet(                                             \
+          name, min, max, bucket_count,                                        \
+          base::HistogramBase::kUmaTargetedHistogramFlag);
+
+namespace impl {
+
+// ScopedTimer is a multi-purpose scoped timer. It measures time delta from its
+// construction till destruction. For example, by putting an instance of this
+// class to the beginning of a scope it is possible to measure how long the
+// scope is being executed.
+//
+// The obtained time measurement is reported via ExportFunctor, which takes
+// base::TimeDelta as a parameter.
+//
+// Time is obtained by means of the TimeProvider static interface:
+//  * static bool IsSupported();
+//    - Idempotently returns whether the system supports such type of provider.
+//  * static void WaitUntilInitialized();
+//    - Waits until the provider can be used.
+//  * static TimeType Now();
+//    - Returns the current time of some TimeType, e.g., base::TimeTicks.
+//
+// Time measurement is exported exactly once, unless TimeProvider::IsSupported()
+// is false. In the latter case ExportFunctor is never called.
+template <typename TimeProvider, typename ExportFunctor>
+class ScopedTimer {
+ public:
+  ScopedTimer(ExportFunctor export_functor) : export_functor_(export_functor) {
+    if (TimeProvider::IsSupported()) {
+      TimeProvider::WaitUntilInitialized();
+      construction_time_ = TimeProvider::Now();
+    }
+  }
+
+  ~ScopedTimer() {
+    if (TimeProvider::IsSupported()) {
+      const base::TimeDelta delta = TimeProvider::Now() - construction_time_;
+      export_functor_(delta);
+    }
+  }
+
+ private:
+  using TimeType =
+      typename std::remove_reference<decltype(TimeProvider::Now())>::type;
+
+  ExportFunctor export_functor_;
+  TimeType construction_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTimer);
+};
+
+// TimeProvider implementations ------------------------------------------------
+
+class TimeTicksProvider {
+ public:
+  static bool IsSupported() { return true; }
+  static void WaitUntilInitialized() {}
+  static base::TimeTicks Now() { return base::TimeTicks::Now(); }
+};
+
+using ThreadTicksProvider = base::ThreadTicks;
+
+// ExportFunctor implementations -----------------------------------------------
+
+template <bool is_microsec_precision>
+class ExportTimeDeltaToHistogram {
+ public:
+  ExportTimeDeltaToHistogram(base::HistogramBase* histogram)
+      : histogram_(histogram) {}
+
+  void operator()(base::TimeDelta delta) {
+    if (is_microsec_precision)
+      histogram_->Add(delta.InMicroseconds());
+    else
+      histogram_->Add(delta.InMilliseconds());
+  }
+
+ private:
+  base::HistogramBase* histogram_;
+};
+
+using ExportMillisecondsToHistogram = ExportTimeDeltaToHistogram<false>;
+using ExportMicrosecondsToHistogram = ExportTimeDeltaToHistogram<true>;
+
+}  // namespace impl
+
+}  // namespace subresource_filter
+
+#endif  // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_
diff --git a/components/subresource_filter/core/common/scoped_timers_unittest.cc b/components/subresource_filter/core/common/scoped_timers_unittest.cc
new file mode 100644
index 0000000..80cc66c
--- /dev/null
+++ b/components/subresource_filter/core/common/scoped_timers_unittest.cc
@@ -0,0 +1,121 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/core/common/scoped_timers.h"
+
+#include "base/test/histogram_tester.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class ExportFunctorForTests {
+ public:
+  int number_of_calls() const { return number_of_calls_; }
+  void operator()(base::TimeDelta) { ++number_of_calls_; }
+
+ private:
+  int number_of_calls_ = 0;
+};
+
+// Casts an l-value parameter to a reference to it.
+template <typename T>
+T& reference(T& value) {
+  return value;
+}
+
+}  // namespace
+
+namespace subresource_filter {
+
+TEST(ScopedTimersTest, ScopedTimerCallsFunctor) {
+  ExportFunctorForTests export_functor;
+  {
+    // Reference is needed to bypass object copying.
+    SCOPED_TIMER(reference(export_functor));
+    EXPECT_EQ(0, export_functor.number_of_calls());
+  }
+  EXPECT_EQ(1, export_functor.number_of_calls());
+}
+
+TEST(ScopedTimersTest, ScopedThreadTimerCallsFunctor) {
+  ExportFunctorForTests export_functor;
+  {
+    // Reference is needed to bypass functor copying.
+    SCOPED_THREAD_TIMER(reference(export_functor));
+    EXPECT_EQ(0, export_functor.number_of_calls());
+  }
+  const int expected_number_of_calls = base::ThreadTicks::IsSupported() ? 1 : 0;
+  EXPECT_EQ(expected_number_of_calls, export_functor.number_of_calls());
+}
+
+TEST(ScopedTimersTest, ScopedTimersCopyFunctor) {
+  ExportFunctorForTests export_functor;
+  {
+    SCOPED_TIMER(export_functor);
+    SCOPED_THREAD_TIMER(export_functor);
+    EXPECT_EQ(0, export_functor.number_of_calls());
+  }
+  EXPECT_EQ(0, export_functor.number_of_calls());
+}
+
+TEST(ScopedTimersTest, ScopedThreadTimerCallsStoredLambdaFunctor) {
+  bool export_is_called = false;
+  auto export_functor = [&export_is_called](base::TimeDelta) {
+    EXPECT_FALSE(export_is_called);
+    export_is_called = true;
+  };
+
+  {
+    SCOPED_THREAD_TIMER(export_functor);
+    EXPECT_FALSE(export_is_called);
+  }
+  EXPECT_EQ(base::ThreadTicks::IsSupported(), export_is_called);
+}
+
+TEST(ScopedTimersTest, ScopedTimerCallsStoredLambdaFunctor) {
+  bool export_is_called = false;
+  auto export_functor = [&export_is_called](base::TimeDelta) {
+    export_is_called = true;
+  };
+
+  {
+    SCOPED_TIMER(export_functor);
+    EXPECT_FALSE(export_is_called);
+  }
+  EXPECT_TRUE(export_is_called);
+}
+
+TEST(ScopedTimersTest, ScopedUmaHistogramMacros) {
+  base::HistogramTester tester;
+  {
+    SCOPED_UMA_HISTOGRAM_THREAD_TIMER("ScopedTimers.ThreadTimer");
+    SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER("ScopedTimers.MicroThreadTimer");
+    SCOPED_UMA_HISTOGRAM_MICRO_TIMER("ScopedTimers.MicroTimer");
+
+    tester.ExpectTotalCount("ScopedTimers.ThreadTimer", 0);
+    tester.ExpectTotalCount("ScopedTimers.MicroThreadTimer", 0);
+    tester.ExpectTotalCount("ScopedTimers.MicroTimer", 0);
+  }
+
+  const int expected_count = base::ThreadTicks::IsSupported() ? 1 : 0;
+  tester.ExpectTotalCount("ScopedTimers.ThreadTimer", expected_count);
+  tester.ExpectTotalCount("ScopedTimers.MicroThreadTimer", expected_count);
+
+  tester.ExpectTotalCount("ScopedTimers.MicroTimer", 1);
+}
+
+TEST(ScopedTimersTest, UmaHistogramMicroTimesFromExportFunctor) {
+  base::HistogramTester tester;
+  auto export_functor = [](base::TimeDelta delta) {
+    UMA_HISTOGRAM_MICRO_TIMES("ScopedTimers.MicroTimes", delta);
+  };
+  {
+    SCOPED_TIMER(export_functor);
+    tester.ExpectTotalCount("ScopedTimers.MicroTimes", 0);
+  }
+  tester.ExpectTotalCount("ScopedTimers.MicroTimes", 1);
+}
+
+}  // namespace subresource_filter
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 42d6032..d2ddcae22 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -265,12 +265,7 @@
 }
 
 void NavigationControllerImpl::Reload(bool check_for_repost) {
-  ReloadType type = ReloadType::NORMAL;
-  if (base::FeatureList::IsEnabled(
-        features::kNonValidatingReloadOnNormalReload)) {
-    type = ReloadType::MAIN_RESOURCE;
-  }
-  ReloadInternal(check_for_repost, type);
+  ReloadInternal(check_for_repost, ReloadType::MAIN_RESOURCE);
 }
 void NavigationControllerImpl::ReloadToRefreshContent(bool check_for_repost) {
   ReloadInternal(check_for_repost, ReloadType::MAIN_RESOURCE);
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h
index bbba71b..d288764 100644
--- a/content/browser/frame_host/navigation_controller_impl.h
+++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -84,6 +84,7 @@
   bool IsInitialNavigation() const override;
   bool IsInitialBlankNavigation() const override;
   void Reload(bool check_for_repost) override;
+  // TODO(toyoshim): Merge ReloadToRefreshContent() to Reload().
   void ReloadToRefreshContent(bool check_for_repost) override;
   void ReloadBypassingCache(bool check_for_repost) override;
   void ReloadOriginalRequestURL(bool check_for_repost) override;
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc
index 5f681a9..a956d53b 100644
--- a/content/browser/frame_host/navigator_impl_unittest.cc
+++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -834,15 +834,8 @@
   // A NavigationRequest should have been generated.
   NavigationRequest* main_request = node->navigation_request();
   ASSERT_TRUE(main_request != NULL);
-  // TODO(toyoshim): Modify following checks once the feature is enabled.
-  if (base::FeatureList::IsEnabled(
-          features::kNonValidatingReloadOnNormalReload)) {
-    EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD_MAIN_RESOURCE,
-              main_request->common_params().navigation_type);
-  } else {
-    EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD,
-              main_request->common_params().navigation_type);
-  }
+  EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD_MAIN_RESOURCE,
+            main_request->common_params().navigation_type);
   main_test_rfh()->PrepareForCommit();
   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
 
diff --git a/content/browser/loader/reload_cache_control_browsertest.cc b/content/browser/loader/reload_cache_control_browsertest.cc
index 98352d5..5affe69 100644
--- a/content/browser/loader/reload_cache_control_browsertest.cc
+++ b/content/browser/loader/reload_cache_control_browsertest.cc
@@ -6,9 +6,6 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/files/file_path.h"
-#include "base/test/scoped_feature_list.h"
-#include "content/public/common/content_features.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
@@ -39,12 +36,7 @@
 
 class ReloadCacheControlBrowserTest : public ContentBrowserTest {
  protected:
-  ReloadCacheControlBrowserTest() {
-    // TODO(toyoshim): Tests in this file depend on current reload behavior,
-    // and should be modified when we enable the new reload behavior.
-    scoped_feature_list_.InitAndDisableFeature(
-        features::kNonValidatingReloadOnNormalReload);
-  }
+  ReloadCacheControlBrowserTest() {}
   ~ReloadCacheControlBrowserTest() override = default;
 
   void SetUpOnMainThread() override {
@@ -77,29 +69,9 @@
     request_log_.push_back(log);
   }
 
-  base::test::ScopedFeatureList scoped_feature_list_;
-
   DISALLOW_COPY_AND_ASSIGN(ReloadCacheControlBrowserTest);
 };
 
-class ReloadCacheControlWithAnExperimentBrowserTest
-    : public ReloadCacheControlBrowserTest {
- protected:
-  ReloadCacheControlWithAnExperimentBrowserTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kNonValidatingReloadOnNormalReload);
-  }
-  ~ReloadCacheControlWithAnExperimentBrowserTest() override = default;
-
-  void SetUpOnMainThread() override {
-    SetUpTestServerOnMainThread();
-  }
-
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(ReloadCacheControlWithAnExperimentBrowserTest);
-};
-
 IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, NormalReload) {
   GURL url(embedded_test_server()->GetURL(kReloadTestPath));
 
@@ -115,7 +87,7 @@
   EXPECT_EQ(kReloadTestPath, request_log_[2].relative_url);
   EXPECT_EQ(kMaxAgeCacheControl, request_log_[2].cache_control);
   EXPECT_EQ(kReloadImagePath, request_log_[3].relative_url);
-  EXPECT_EQ(kMaxAgeCacheControl, request_log_[3].cache_control);
+  EXPECT_EQ(kNoCacheControl, request_log_[3].cache_control);
 }
 
 IN_PROC_BROWSER_TEST_F(ReloadCacheControlBrowserTest, BypassingReload) {
@@ -136,25 +108,6 @@
   EXPECT_EQ(kNoCacheCacheControl, request_log_[3].cache_control);
 }
 
-IN_PROC_BROWSER_TEST_F(ReloadCacheControlWithAnExperimentBrowserTest,
-                       ReloadMainResource) {
-  GURL url(embedded_test_server()->GetURL(kReloadTestPath));
-
-  EXPECT_TRUE(NavigateToURL(shell(), url));
-  ReloadBlockUntilNavigationsComplete(shell(), 1);
-
-  ASSERT_EQ(4UL, request_log_.size());
-  EXPECT_EQ(kReloadTestPath, request_log_[0].relative_url);
-  EXPECT_EQ(kNoCacheControl, request_log_[0].cache_control);
-  EXPECT_EQ(kReloadImagePath, request_log_[1].relative_url);
-  EXPECT_EQ(kNoCacheControl, request_log_[1].cache_control);
-
-  EXPECT_EQ(kReloadTestPath, request_log_[2].relative_url);
-  EXPECT_EQ(kMaxAgeCacheControl, request_log_[2].cache_control);
-  EXPECT_EQ(kReloadImagePath, request_log_[3].relative_url);
-  EXPECT_EQ(kNoCacheControl, request_log_[3].cache_control);
-}
-
 // TODO(toyoshim): Add another set of reload tests with DevTools open.
 
 }  // namespace
diff --git a/content/browser/memory/memory_coordinator.cc b/content/browser/memory/memory_coordinator.cc
index 4317e5cd..dc9d0a9 100644
--- a/content/browser/memory/memory_coordinator.cc
+++ b/content/browser/memory/memory_coordinator.cc
@@ -122,7 +122,8 @@
 
 void MemoryCoordinator::RecordMemoryPressure(
     base::MemoryPressureMonitor::MemoryPressureLevel level) {
-  int state = static_cast<int>(GetCurrentMemoryState());
+  DCHECK(GetGlobalMemoryState() != base::MemoryState::UNKNOWN);
+  int state = static_cast<int>(GetGlobalMemoryState());
   switch (level) {
     case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
       UMA_HISTOGRAM_ENUMERATION(
@@ -139,6 +140,10 @@
   }
 }
 
+base::MemoryState MemoryCoordinator::GetGlobalMemoryState() const {
+  return base::MemoryState::UNKNOWN;
+}
+
 base::MemoryState MemoryCoordinator::GetCurrentMemoryState() const {
   return base::MemoryState::UNKNOWN;
 }
diff --git a/content/browser/memory/memory_coordinator.h b/content/browser/memory/memory_coordinator.h
index 7d2cbd76..8ed1951 100644
--- a/content/browser/memory/memory_coordinator.h
+++ b/content/browser/memory/memory_coordinator.h
@@ -59,7 +59,15 @@
   // Called when ChildMemoryCoordinator calls AddChild().
   virtual void OnChildAdded(int render_process_id) {}
 
+  // Returns the global memory state.
+  virtual base::MemoryState GetGlobalMemoryState() const;
+
+  // Returns the browser's current memory state. Note that the current state
+  // could be different from the global memory state as the browser won't be
+  // suspended.
   virtual base::MemoryState GetCurrentMemoryState() const;
+
+  // Sets the global memory state for testing.
   virtual void SetCurrentMemoryStateForTesting(base::MemoryState memory_state);
 
  protected:
diff --git a/content/browser/memory/memory_coordinator_impl.cc b/content/browser/memory/memory_coordinator_impl.cc
index 66f6a9b4..27b222e 100644
--- a/content/browser/memory/memory_coordinator_impl.cc
+++ b/content/browser/memory/memory_coordinator_impl.cc
@@ -188,6 +188,10 @@
   SetChildMemoryState(render_process_id, ToMojomMemoryState(current_state_));
 }
 
+base::MemoryState MemoryCoordinatorImpl::GetGlobalMemoryState() const {
+  return current_state_;
+}
+
 base::MemoryState MemoryCoordinatorImpl::GetCurrentMemoryState() const {
   // SUSPENDED state may not make sense to the browser process. Use THROTTLED
   // instead when the global state is SUSPENDED.
diff --git a/content/browser/memory/memory_coordinator_impl.h b/content/browser/memory/memory_coordinator_impl.h
index 7dbe5c6f..5787e251 100644
--- a/content/browser/memory/memory_coordinator_impl.h
+++ b/content/browser/memory/memory_coordinator_impl.h
@@ -50,6 +50,7 @@
 
   MemoryMonitor* memory_monitor() { return memory_monitor_.get(); }
 
+  base::MemoryState GetGlobalMemoryState() const override;
   base::MemoryState GetCurrentMemoryState() const override;
   void SetCurrentMemoryStateForTesting(base::MemoryState memory_state) override;
 
diff --git a/content/browser/memory/memory_monitor_android.cc b/content/browser/memory/memory_monitor_android.cc
index ba73f736..9d144d05 100644
--- a/content/browser/memory/memory_monitor_android.cc
+++ b/content/browser/memory/memory_monitor_android.cc
@@ -72,7 +72,7 @@
                          const base::android::JavaParamRef<jclass>& jcaller,
                          jint level) {
   DCHECK(level >= 0 && level <= kTrimMemoryLevelMax);
-  auto state = MemoryCoordinator::GetInstance()->GetCurrentMemoryState();
+  auto state = MemoryCoordinator::GetInstance()->GetGlobalMemoryState();
   switch (state) {
     case base::MemoryState::NORMAL:
       UMA_HISTOGRAM_ENUMERATION("Memory.Coordinator.TrimMemoryLevel.Normal",
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index e1b1f531..4ed80f9 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -594,9 +594,9 @@
   run_loop2.Run();
 }
 
-// Test that we can generate streams where a mandatory sourceId is specified in
+// Test that we can generate streams where a sourceId is specified in
 // the request.
-TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithMandatorySourceId) {
+TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithSourceId) {
   ASSERT_GE(physical_audio_devices_.size(), 1u);
   ASSERT_GE(physical_video_devices_.size(), 1u);
 
@@ -609,7 +609,7 @@
         audio_it->unique_id);
     ASSERT_FALSE(source_id.empty());
     StreamControls controls(true, true);
-    controls.audio.device_ids.push_back(source_id);
+    controls.audio.device_id = source_id;
 
     SetupFakeUI(true);
     GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
@@ -624,7 +624,7 @@
         video_it->device_id);
     ASSERT_FALSE(source_id.empty());
     StreamControls controls(true, true);
-    controls.video.device_ids.push_back(source_id);
+    controls.video.device_id = source_id;
 
     SetupFakeUI(true);
     GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
@@ -632,86 +632,24 @@
   }
 }
 
-// Test that we can generate streams where a optional sourceId is specified in
-// the request.
-TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithOptionalSourceId) {
-  ASSERT_GE(physical_audio_devices_.size(), 1u);
-  ASSERT_GE(physical_video_devices_.size(), 1u);
-
-  media::AudioDeviceNames::const_iterator audio_it =
-      physical_audio_devices_.begin();
-  for (; audio_it != physical_audio_devices_.end(); ++audio_it) {
-    std::string source_id = content::GetHMACForMediaDeviceID(
-        browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(),
-        origin_,
-        audio_it->unique_id);
-    ASSERT_FALSE(source_id.empty());
-    StreamControls controls(true, true);
-    controls.audio.device_ids.push_back(source_id);
-
-    SetupFakeUI(true);
-    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
-    EXPECT_EQ(host_->audio_devices_[0].device.id, source_id);
-  }
-
-  media::VideoCaptureDeviceDescriptors::const_iterator video_it =
-      physical_video_devices_.begin();
-  for (; video_it != physical_video_devices_.end(); ++video_it) {
-    std::string source_id = content::GetHMACForMediaDeviceID(
-        browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(), origin_,
-        video_it->device_id);
-    ASSERT_FALSE(source_id.empty());
-    StreamControls controls(true, true);
-    controls.video.device_ids.push_back(source_id);
-
-    SetupFakeUI(true);
-    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
-    EXPECT_EQ(host_->video_devices_[0].device.id, source_id);
-  }
-}
-
-// Test that generating a stream with an invalid mandatory video source id fail.
-TEST_F(MediaStreamDispatcherHostTest,
-       GenerateStreamsWithInvalidMandatoryVideoSourceId) {
+// Test that generating a stream with an invalid video source id fail.
+TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithInvalidVideoSourceId) {
   StreamControls controls(true, true);
-  controls.video.device_ids.push_back("invalid source id");
+  controls.video.device_id = "invalid source id";
 
   GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, controls,
                                   MEDIA_DEVICE_NO_HARDWARE);
 }
 
-// Test that generating a stream with an invalid mandatory audio source id fail.
-TEST_F(MediaStreamDispatcherHostTest,
-       GenerateStreamsWithInvalidMandatoryAudioSourceId) {
+// Test that generating a stream with an invalid audio source id fail.
+TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithInvalidAudioSourceId) {
   StreamControls controls(true, true);
-  controls.audio.device_ids.push_back("invalid source id");
+  controls.audio.device_id = "invalid source id";
 
   GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, controls,
                                   MEDIA_DEVICE_NO_HARDWARE);
 }
 
-// Test that generating a stream with an invalid optional video source id
-// succeed.
-TEST_F(MediaStreamDispatcherHostTest,
-       GenerateStreamsWithInvalidOptionalVideoSourceId) {
-  StreamControls controls(true, true);
-  controls.video.alternate_device_ids.push_back("invalid source id");
-
-  SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
-}
-
-// Test that generating a stream with an invalid optional audio source id
-// succeed.
-TEST_F(MediaStreamDispatcherHostTest,
-       GenerateStreamsWithInvalidOptionalAudioSourceId) {
-  StreamControls controls(true, true);
-  controls.video.alternate_device_ids.push_back("invalid source id");
-
-  SetupFakeUI(true);
-  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, controls);
-}
-
 TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsNoAvailableVideoDevice) {
   physical_video_devices_.clear();
   video_capture_device_factory_->set_number_of_devices(0);
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 5cdb6233..0da58a4d 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -704,10 +704,10 @@
   StreamControls controls;
   if (IsAudioInputMediaType(type)) {
     controls.audio.requested = true;
-    controls.audio.device_ids.push_back(device_id);
+    controls.audio.device_id = device_id;
   } else if (IsVideoMediaType(type)) {
     controls.video.requested = true;
-    controls.video.device_ids.push_back(device_id);
+    controls.video.device_id = device_id;
   } else {
     NOTREACHED();
   }
@@ -793,29 +793,15 @@
                                       const TrackControls& controls,
                                       const MediaDeviceInfoArray& devices,
                                       std::string* device_id) const {
-  if (!controls.device_ids.empty()) {
-    if (controls.device_ids.size() > 1) {
-      LOG(ERROR) << "Only one required device ID is supported";
-      return false;
-    }
-    const std::string& candidate_id = controls.device_ids[0];
-    if (!GetDeviceIDFromHMAC(salt, security_origin, candidate_id, devices,
-                             device_id)) {
-      LOG(WARNING) << "Invalid mandatory capture ID = " << candidate_id;
-      return false;
-    }
+  if (controls.device_id.empty())
     return true;
+
+  if (!GetDeviceIDFromHMAC(salt, security_origin, controls.device_id, devices,
+                           device_id)) {
+    LOG(WARNING) << "Invalid device ID = " << controls.device_id;
+    return false;
   }
-  // We don't have a required ID. Look at the alternates.
-  for (const std::string& candidate_id : controls.alternate_device_ids) {
-    if (GetDeviceIDFromHMAC(salt, security_origin, candidate_id, devices,
-                            device_id)) {
-      return true;
-    } else {
-      LOG(WARNING) << "Invalid optional capture ID = " << candidate_id;
-    }
-  }
-  return true;  // If we get here, device_id is empty.
+  return true;
 }
 
 bool MediaStreamManager::GetRequestedDeviceCaptureId(
@@ -1062,10 +1048,10 @@
          request->video_type() == MEDIA_TAB_VIDEO_CAPTURE);
 
   std::string capture_device_id;
-  if (!request->controls.audio.device_ids.empty()) {
-    capture_device_id = request->controls.audio.device_ids[0];
-  } else if (!request->controls.video.device_ids.empty()) {
-    capture_device_id = request->controls.video.device_ids[0];
+  if (!request->controls.audio.device_id.empty()) {
+    capture_device_id = request->controls.audio.device_id;
+  } else if (!request->controls.video.device_id.empty()) {
+    capture_device_id = request->controls.video.device_id;
   } else {
     return false;
   }
@@ -1117,8 +1103,8 @@
         request->controls.video.stream_source;
 
     if (video_stream_source == kMediaStreamSourceDesktop &&
-        !request->controls.video.device_ids.empty()) {
-      video_device_id = request->controls.video.device_ids[0];
+        !request->controls.video.device_id.empty()) {
+      video_device_id = request->controls.video.device_id;
     }
   }
 
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 682f15d8..286c6276 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -247,11 +247,6 @@
   if (command_line.HasSwitch(switches::kEnableSlimmingPaintV2))
     WebRuntimeFeatures::enableSlimmingPaintV2(true);
 
-  if (base::FeatureList::IsEnabled(
-          features::kNonValidatingReloadOnNormalReload)) {
-    WebRuntimeFeatures::enableReloadwithoutSubResourceCacheRevalidation(true);
-  }
-
   if (base::FeatureList::IsEnabled(features::kDocumentWriteEvaluator))
     WebRuntimeFeatures::enableDocumentWriteEvaluator(true);
 
diff --git a/content/common/media/media_stream_messages.h b/content/common/media/media_stream_messages.h
index 31a2137..601b2c0 100644
--- a/content/common/media/media_stream_messages.h
+++ b/content/common/media/media_stream_messages.h
@@ -29,8 +29,7 @@
 IPC_STRUCT_TRAITS_BEGIN(content::TrackControls)
   IPC_STRUCT_TRAITS_MEMBER(requested)
   IPC_STRUCT_TRAITS_MEMBER(stream_source)
-  IPC_STRUCT_TRAITS_MEMBER(device_ids)
-  IPC_STRUCT_TRAITS_MEMBER(alternate_device_ids)
+  IPC_STRUCT_TRAITS_MEMBER(device_id)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(content::StreamControls)
diff --git a/content/common/media/media_stream_options.h b/content/common/media/media_stream_options.h
index 2eb56283..55f5687 100644
--- a/content/common/media/media_stream_options.h
+++ b/content/common/media/media_stream_options.h
@@ -33,17 +33,13 @@
   // Consider replacing with MediaStreamType enum variables.
   std::string stream_source;  // audio.kMediaStreamSource
 
-  // Device ID requests.
-  // The first set represents required devices - either grab one or fail.
-  // The second set represents optional devices - if we can't get one of
-  // these, we will grab the default device (if possible).
-  // The constraint names are "sourceId" and "chromeMediaSourceId".
-  std::vector<std::string> device_ids;
-  std::vector<std::string> alternate_device_ids;
+  // An empty string represents the default device.
+  // A nonempty string represents a specific device.
+  std::string device_id;
 };
 
 // StreamControls describes what is sent to the browser process
-// to the renderer process in order to control the opening of a device
+// from the renderer process in order to control the opening of a device
 // pair. This may result in opening one audio and/or one video device.
 // This has to be a struct with public members in order to allow it to
 // be sent in the IPC of media_stream_messages.h
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 0933f23..1bea0d7 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -111,11 +111,6 @@
   "MemoryCoordinator", base::FEATURE_DISABLED_BY_DEFAULT
 };
 
-// Non-validating reload for desktop.
-// See https://crbug.com/591245
-const base::Feature kNonValidatingReloadOnNormalReload{
-    "NonValidatingReloadOnNormalReload", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Kill switch for Web Notification content images.
 const base::Feature kNotificationContentImage{"NotificationContentImage",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 597d1b09..4230595 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -35,7 +35,6 @@
 CONTENT_EXPORT extern const base::Feature kLazyParseCSS;
 CONTENT_EXPORT extern const base::Feature kMediaDocumentDownloadButton;
 CONTENT_EXPORT extern const base::Feature kMemoryCoordinator;
-CONTENT_EXPORT extern const base::Feature kNonValidatingReloadOnNormalReload;
 CONTENT_EXPORT extern const base::Feature kNotificationContentImage;
 CONTENT_EXPORT extern const base::Feature kOptimizeLoadingIPCForSmallResources;
 CONTENT_EXPORT extern const base::Feature kOriginTrials;
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc
index 766ca8c7..2381c46 100644
--- a/content/renderer/media/user_media_client_impl.cc
+++ b/content/renderer/media/user_media_client_impl.cc
@@ -6,12 +6,13 @@
 
 #include <stddef.h>
 
+#include <algorithm>
 #include <utility>
-#include <vector>
 
 #include "base/hash.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -36,78 +37,141 @@
 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
 #include "third_party/WebKit/public/platform/WebMediaDeviceInfo.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 
 namespace content {
 namespace {
 
-void CopyVector(const blink::WebVector<blink::WebString>& source,
-                std::vector<std::string>* destination) {
-  for (const auto& web_string : source) {
-    destination->push_back(web_string.utf8());
-  }
-}
-
-void CopyFirstString(const blink::WebVector<blink::WebString>& source,
+void CopyFirstString(const blink::StringConstraint& constraint,
                      std::string* destination) {
-  if (!source.isEmpty())
-    *destination = source[0].utf8();
+  if (!constraint.exact().isEmpty())
+    *destination = constraint.exact()[0].utf8();
 }
 
-void CopyBlinkRequestToStreamControls(const blink::WebUserMediaRequest& request,
-                                      StreamControls* controls) {
-  if (request.isNull()) {
-    return;
-  }
-  if (!request.audioConstraints().isNull()) {
-    const blink::WebMediaTrackConstraintSet& audio_basic =
-        request.audioConstraints().basic();
-    CopyFirstString(audio_basic.mediaStreamSource.exact(),
-                    &controls->audio.stream_source);
-    CopyVector(audio_basic.deviceId.exact(), &(controls->audio.device_ids));
-    // Optionals. They may be either in ideal or in advanced.exact.
-    CopyVector(audio_basic.deviceId.ideal(),
-               &controls->audio.alternate_device_ids);
-    for (const auto& constraint : request.audioConstraints().advanced()) {
-      CopyVector(constraint.deviceId.exact(),
-                 &controls->audio.alternate_device_ids);
-      CopyVector(constraint.deviceId.ideal(),
-                 &controls->audio.alternate_device_ids);
+bool FindDeviceId(const blink::WebVector<blink::WebString> candidates,
+                  const MediaDeviceInfoArray& device_infos,
+                  std::string* device_id) {
+  for (const auto& candidate : candidates) {
+    auto it = std::find_if(device_infos.begin(), device_infos.end(),
+                           [&candidate](const MediaDeviceInfo& info) {
+                             return info.device_id == candidate.utf8();
+                           });
+
+    if (it != device_infos.end()) {
+      *device_id = it->device_id;
+      return true;
     }
-    if (audio_basic.hotwordEnabled.hasExact()) {
-      controls->hotword_enabled = audio_basic.hotwordEnabled.exact();
-    } else {
-      for (const auto& audio_advanced : request.audioConstraints().advanced()) {
-        if (audio_advanced.hotwordEnabled.hasExact()) {
-          controls->hotword_enabled = audio_advanced.hotwordEnabled.exact();
-          break;
-        }
+  }
+
+  return false;
+}
+
+// If a device ID requested as exact basic constraint in |constraints| is found
+// in |device_infos|, it is copied to |*device_id|, and the function returns
+// false. If such a device is not found in |device_infos|, the function returns
+// false and |*device_id| is left unmodified.
+// If more than one device ID is requested as an exact basic constraint in
+// |constraint|, the function returns false and |*device_id| is left unmodified.
+// If no device ID is requested as an exact basic constraint, and at least one
+// device ID requested as an ideal basic constraint or as an exact or ideal
+// advanced constraint in |constraints| is found in |device_infos|, the first
+// such device ID is copied to |*device_id| and the function returns true.
+// If no such device ID is found, |*device_id| is left unmodified and the
+// function returns true.
+// TODO(guidou): Replace with a spec-compliant selection algorithm. See
+// http://crbug.com/657733.
+bool PickDeviceId(const blink::WebMediaConstraints& constraints,
+                  const MediaDeviceInfoArray& device_infos,
+                  std::string* device_id) {
+  DCHECK(!constraints.isNull());
+  DCHECK(device_id->empty());
+
+  if (constraints.basic().deviceId.exact().size() > 1) {
+    LOG(ERROR) << "Only one required device ID is supported";
+    return false;
+  }
+
+  if (constraints.basic().deviceId.exact().size() == 1 &&
+      !FindDeviceId(constraints.basic().deviceId.exact(), device_infos,
+                    device_id)) {
+    LOG(ERROR) << "Invalid mandatory device ID = "
+               << constraints.basic().deviceId.exact()[0].utf8();
+    return false;
+  }
+
+  // There is no required device ID. Look at the alternates.
+  if (FindDeviceId(constraints.basic().deviceId.ideal(), device_infos,
+                   device_id)) {
+    return true;
+  }
+
+  for (const auto& advanced : constraints.advanced()) {
+    if (FindDeviceId(advanced.deviceId.exact(), device_infos, device_id)) {
+      return true;
+    }
+    if (FindDeviceId(advanced.deviceId.ideal(), device_infos, device_id)) {
+      return true;
+    }
+  }
+
+  // No valid alternate device ID found. Select default device.
+  return true;
+}
+
+bool IsDeviceSource(const std::string& source) {
+  return source.empty();
+}
+
+void CopyConstraintsToTrackControls(
+    const blink::WebMediaConstraints& constraints,
+    TrackControls* track_controls,
+    bool* request_devices) {
+  DCHECK(!constraints.isNull());
+  track_controls->requested = true;
+  CopyFirstString(constraints.basic().mediaStreamSource,
+                  &track_controls->stream_source);
+  if (IsDeviceSource(track_controls->stream_source)) {
+    bool request_devices_advanced = false;
+    for (const auto& advanced : constraints.advanced()) {
+      if (!advanced.deviceId.isEmpty()) {
+        request_devices_advanced = true;
+        break;
       }
     }
+    *request_devices =
+        request_devices_advanced || !constraints.basic().deviceId.isEmpty();
+  } else {
+    CopyFirstString(constraints.basic().deviceId, &track_controls->device_id);
+    *request_devices = false;
+  }
+}
 
-    if (request.audioConstraints().basic().disableLocalEcho.hasExact()) {
-      controls->disable_local_echo =
-          request.audioConstraints().basic().disableLocalEcho.exact();
-    } else {
-      controls->disable_local_echo =
-          controls->audio.stream_source != kMediaStreamSourceDesktop;
+void CopyHotwordAndLocalEchoToStreamControls(
+    const blink::WebMediaConstraints& audio_constraints,
+    StreamControls* controls) {
+  if (audio_constraints.isNull())
+    return;
+
+  if (audio_constraints.basic().hotwordEnabled.hasExact()) {
+    controls->hotword_enabled =
+        audio_constraints.basic().hotwordEnabled.exact();
+  } else {
+    for (const auto& audio_advanced : audio_constraints.advanced()) {
+      if (audio_advanced.hotwordEnabled.hasExact()) {
+        controls->hotword_enabled = audio_advanced.hotwordEnabled.exact();
+        break;
+      }
     }
   }
-  if (!request.videoConstraints().isNull()) {
-    const blink::WebMediaTrackConstraintSet& video_basic =
-        request.videoConstraints().basic();
-    CopyFirstString(video_basic.mediaStreamSource.exact(),
-                    &(controls->video.stream_source));
-    CopyVector(video_basic.deviceId.exact(), &(controls->video.device_ids));
-    CopyVector(video_basic.deviceId.ideal(),
-               &(controls->video.alternate_device_ids));
-    for (const auto& constraint : request.videoConstraints().advanced()) {
-      CopyVector(constraint.deviceId.exact(),
-                 &controls->video.alternate_device_ids);
-      CopyVector(constraint.deviceId.ideal(),
-                 &controls->video.alternate_device_ids);
-    }
+
+  if (audio_constraints.basic().disableLocalEcho.hasExact()) {
+    controls->disable_local_echo =
+        audio_constraints.basic().disableLocalEcho.exact();
+  } else {
+    controls->disable_local_echo =
+        controls->audio.stream_source != kMediaStreamSourceDesktop;
   }
 }
 
@@ -183,19 +247,34 @@
   }
 
   int request_id = g_next_request_id++;
-  StreamControls controls;
-  url::Origin security_origin;
-  bool enable_automatic_output_device_selection = false;
+  std::unique_ptr<StreamControls> controls = base::MakeUnique<StreamControls>();
 
   // |user_media_request| can't be mocked. So in order to test at all we check
   // if it isNull.
+  // TODO(guidou): Remove this test-specific code path.
   if (user_media_request.isNull()) {
     // We are in a test.
-    controls.audio.requested = true;
-    controls.video.requested = true;
+    controls->audio.requested = true;
+    controls->video.requested = true;
+    FinalizeRequestUserMedia(
+        request_id, user_media_request, std::move(controls),
+        false /* automatic_output_device_selection */, url::Origin());
   } else {
+    // ownerDocument may be null if we are in a test.
+    // In that case, it's OK to not check frame().
+    DCHECK(user_media_request.ownerDocument().isNull() ||
+           render_frame()->GetWebFrame() ==
+               static_cast<blink::WebFrame*>(
+                   user_media_request.ownerDocument().frame()));
+
+    bool enable_automatic_output_device_selection = false;
+    bool request_audio_input_devices = false;
     if (user_media_request.audio()) {
-      controls.audio.requested = true;
+      CopyConstraintsToTrackControls(user_media_request.audioConstraints(),
+                                     &controls->audio,
+                                     &request_audio_input_devices);
+      CopyHotwordAndLocalEchoToStreamControls(
+          user_media_request.audioConstraints(), controls.get());
       // Check if this input device should be used to select a matching output
       // device for audio rendering.
       GetConstraintValueAsBoolean(
@@ -203,52 +282,88 @@
           &blink::WebMediaTrackConstraintSet::renderToAssociatedSink,
           &enable_automatic_output_device_selection);
     }
+    bool request_video_input_devices = false;
     if (user_media_request.video()) {
-      controls.video.requested = true;
+      CopyConstraintsToTrackControls(user_media_request.videoConstraints(),
+                                     &controls->video,
+                                     &request_video_input_devices);
     }
-    CopyBlinkRequestToStreamControls(user_media_request, &controls);
-    security_origin = user_media_request.getSecurityOrigin();
-    // ownerDocument may be null if we are in a test.
-    // In that case, it's OK to not check frame().
-    DCHECK(user_media_request.ownerDocument().isNull() ||
-           render_frame()->GetWebFrame() ==
-               static_cast<blink::WebFrame*>(
-                   user_media_request.ownerDocument().frame()));
+
+    url::Origin security_origin = user_media_request.getSecurityOrigin();
+    if (request_audio_input_devices || request_video_input_devices) {
+      GetMediaDevicesDispatcher()->EnumerateDevices(
+          request_audio_input_devices, request_video_input_devices,
+          false /* request_audio_output_devices */, security_origin,
+          base::Bind(&UserMediaClientImpl::SelectUserMediaDevice,
+                     weak_factory_.GetWeakPtr(), request_id, user_media_request,
+                     base::Passed(&controls),
+                     enable_automatic_output_device_selection,
+                     security_origin));
+    } else {
+      FinalizeRequestUserMedia(
+          request_id, user_media_request, std::move(controls),
+          enable_automatic_output_device_selection, security_origin);
+    }
+  }
+}
+
+void UserMediaClientImpl::SelectUserMediaDevice(
+    int request_id,
+    const blink::WebUserMediaRequest& user_media_request,
+    std::unique_ptr<StreamControls> controls,
+    bool enable_automatic_output_device_selection,
+    const url::Origin& security_origin,
+    const EnumerationResult& device_enumeration) {
+  DCHECK(CalledOnValidThread());
+
+  if (controls->audio.requested &&
+      IsDeviceSource(controls->audio.stream_source)) {
+    if (!PickDeviceId(user_media_request.audioConstraints(),
+                      device_enumeration[MEDIA_DEVICE_TYPE_AUDIO_INPUT],
+                      &controls->audio.device_id)) {
+      GetUserMediaRequestFailed(user_media_request, MEDIA_DEVICE_NO_HARDWARE,
+                                "");
+      return;
+    }
   }
 
-  DVLOG(1) << "UserMediaClientImpl::requestUserMedia(" << request_id << ", [ "
-           << "audio=" << (controls.audio.requested)
-           << " select associated sink: "
-           << enable_automatic_output_device_selection
-           << ", video=" << (controls.video.requested) << " ], "
-           << security_origin << ")";
-
-  std::string audio_device_id;
-  if (!user_media_request.isNull() && user_media_request.audio()) {
-    GetConstraintValueAsString(user_media_request.audioConstraints(),
-                               &blink::WebMediaTrackConstraintSet::deviceId,
-                               &audio_device_id);
+  if (controls->video.requested &&
+      IsDeviceSource(controls->video.stream_source)) {
+    if (!PickDeviceId(user_media_request.videoConstraints(),
+                      device_enumeration[MEDIA_DEVICE_TYPE_VIDEO_INPUT],
+                      &controls->video.device_id)) {
+      GetUserMediaRequestFailed(user_media_request, MEDIA_DEVICE_NO_HARDWARE,
+                                "");
+      return;
+    }
   }
 
-  std::string video_device_id;
-  if (!user_media_request.isNull() && user_media_request.video()) {
-    GetConstraintValueAsString(user_media_request.videoConstraints(),
-                               &blink::WebMediaTrackConstraintSet::deviceId,
-                               &video_device_id);
-  }
+  FinalizeRequestUserMedia(request_id, user_media_request, std::move(controls),
+                           enable_automatic_output_device_selection,
+                           security_origin);
+}
 
-  WebRtcLogMessage(base::StringPrintf(
-      "MSI::requestUserMedia. request_id=%d"
-      ", audio source id=%s"
-      ", video source id=%s",
-      request_id, audio_device_id.c_str(), video_device_id.c_str()));
+void UserMediaClientImpl::FinalizeRequestUserMedia(
+    int request_id,
+    const blink::WebUserMediaRequest& user_media_request,
+    std::unique_ptr<StreamControls> controls,
+    bool enable_automatic_output_device_selection,
+    const url::Origin& security_origin) {
+  DCHECK(CalledOnValidThread());
+
+  WebRtcLogMessage(
+      base::StringPrintf("MSI::requestUserMedia. request_id=%d"
+                         ", audio source id=%s"
+                         ", video source id=%s",
+                         request_id, controls->audio.device_id.c_str(),
+                         controls->video.device_id.c_str()));
 
   user_media_requests_.push_back(
       new UserMediaRequestInfo(request_id, user_media_request,
                                enable_automatic_output_device_selection));
 
   media_stream_dispatcher_->GenerateStream(
-      request_id, weak_factory_.GetWeakPtr(), controls, security_origin);
+      request_id, weak_factory_.GetWeakPtr(), *controls, security_origin);
 }
 
 void UserMediaClientImpl::cancelUserMediaRequest(
diff --git a/content/renderer/media/user_media_client_impl.h b/content/renderer/media/user_media_client_impl.h
index e9202d6..2492ccc 100644
--- a/content/renderer/media/user_media_client_impl.h
+++ b/content/renderer/media/user_media_client_impl.h
@@ -242,6 +242,20 @@
 
   const ::mojom::MediaDevicesDispatcherHostPtr& GetMediaDevicesDispatcher();
 
+  void SelectUserMediaDevice(
+      int request_id,
+      const blink::WebUserMediaRequest& user_media_request,
+      std::unique_ptr<StreamControls> controls,
+      bool enable_automatic_output_device_selection,
+      const url::Origin& security_origin,
+      const EnumerationResult& device_enumeration);
+  void FinalizeRequestUserMedia(
+      int request_id,
+      const blink::WebUserMediaRequest& user_media_request,
+      std::unique_ptr<StreamControls> controls,
+      bool enable_automatic_output_device_selection,
+      const url::Origin& security_origin);
+
   // Callback invoked by MediaDevicesEventDispatcher when a device-change
   // notification arrives.
   void DevicesChanged(MediaDeviceType device_type,
diff --git a/content/renderer/media/user_media_client_impl_unittest.cc b/content/renderer/media/user_media_client_impl_unittest.cc
index c0de733a..437f3c2c 100644
--- a/content/renderer/media/user_media_client_impl_unittest.cc
+++ b/content/renderer/media/user_media_client_impl_unittest.cc
@@ -110,6 +110,7 @@
   void RequestUserMedia(const blink::WebUserMediaRequest& user_media_request) {
     state_ = REQUEST_NOT_COMPLETE;
     requestUserMedia(user_media_request);
+    base::RunLoop().RunUntilIdle();
   }
 
   void RequestUserMedia() {
diff --git a/ios/chrome/BUILD.gn b/ios/chrome/BUILD.gn
index 1c9fef6..5044c7b 100644
--- a/ios/chrome/BUILD.gn
+++ b/ios/chrome/BUILD.gn
@@ -48,7 +48,6 @@
     "//ios/chrome/browser/update_client:unit_tests",
     "//ios/chrome/browser/voice:unit_tests",
     "//ios/chrome/browser/web_resource:unit_tests",
-    "//ios/chrome/browser/webp_transcode:unit_tests",
     "//ios/chrome/common:unit_tests",
     "//ios/chrome/test:unit_tests",
   ]
diff --git a/ios/chrome/browser/net/BUILD.gn b/ios/chrome/browser/net/BUILD.gn
index 4919747..b548450 100644
--- a/ios/chrome/browser/net/BUILD.gn
+++ b/ios/chrome/browser/net/BUILD.gn
@@ -44,9 +44,9 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browsing_data",
-    "//ios/chrome/browser/webp_transcode",
     "//ios/net",
     "//ios/web",
+    "//ios/web/public/image_fetcher",
     "//net",
     "//net:extras",
     "//url",
@@ -74,7 +74,6 @@
   testonly = true
   sources = [
     "cookie_util_unittest.mm",
-    "image_fetcher_unittest.mm",
     "metrics_network_client_unittest.mm",
     "retryable_url_fetcher_unittest.mm",
   ]
diff --git a/ios/chrome/browser/net/image_fetcher.mm b/ios/chrome/browser/net/image_fetcher.mm
index de591c0..4ad0f02 100644
--- a/ios/chrome/browser/net/image_fetcher.mm
+++ b/ios/chrome/browser/net/image_fetcher.mm
@@ -11,7 +11,7 @@
 #include "base/location.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/task_runner.h"
-#include "ios/chrome/browser/webp_transcode/webp_decoder.h"
+#include "ios/web/public/image_fetcher/webp_decoder.h"
 #include "ios/web/public/web_thread.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_response_headers.h"
diff --git a/ios/chrome/browser/net/image_fetcher_unittest.mm b/ios/chrome/browser/net/image_fetcher_unittest.mm
deleted file mode 100644
index de2d2c9..0000000
--- a/ios/chrome/browser/net/image_fetcher_unittest.mm
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/net/image_fetcher.h"
-
-#import <UIKit/UIKit.h>
-
-#include "base/ios/ios_util.h"
-#include "base/mac/scoped_block.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/run_loop.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "net/http/http_response_headers.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-static unsigned char kJPGImage[] = {
-    255,216,255,224,0,16,74,70,73,70,0,1,1,1,0,72,0,72,0,0,255,254,0,19,67,
-    114,101,97,116,101,100,32,119,105,116,104,32,71,73,77,80,255,219,0,67,
-    0,5,3,4,4,4,3,5,4,4,4,5,5,5,6,7,12,8,7,7,7,7,15,11,11,9,12,17,15,18,18,
-    17,15,17,17,19,22,28,23,19,20,26,21,17,17,24,33,24,26,29,29,31,31,31,
-    19,23,34,36,34,30,36,28,30,31,30,255,219,0,67,1,5,5,5,7,6,7,14,8,8,14,
-    30,20,17,20,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,
-    30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,
-    30,30,30,30,30,30,30,30,255,192,0,17,8,0,1,0,1,3,1,34,0,2,17,1,3,17,1,
-    255,196,0,21,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,255,196,0,20,16,1,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,196,0,20,1,1,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,255,196,0,20,17,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,218,
-    0,12,3,1,0,2,17,3,17,0,63,0,178,192,7,255,217
-};
-
-static unsigned char kPNGImage[] = {
-    137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,1,0,0,0,1,1,0,0,0,
-    0,55,110,249,36,0,0,0,2,98,75,71,68,0,1,221,138,19,164,0,0,0,9,112,72,
-    89,115,0,0,11,18,0,0,11,18,1,210,221,126,252,0,0,0,9,118,112,65,103,0,
-    0,0,1,0,0,0,1,0,199,149,95,237,0,0,0,10,73,68,65,84,8,215,99,104,0,0,
-    0,130,0,129,221,67,106,244,0,0,0,25,116,69,88,116,99,111,109,109,101,
-    110,116,0,67,114,101,97,116,101,100,32,119,105,116,104,32,71,73,77,80,
-    231,175,64,203,0,0,0,37,116,69,88,116,100,97,116,101,58,99,114,101,97,
-    116,101,0,50,48,49,49,45,48,54,45,50,50,84,49,54,58,49,54,58,52,54,43,
-    48,50,58,48,48,31,248,231,223,0,0,0,37,116,69,88,116,100,97,116,101,58,
-    109,111,100,105,102,121,0,50,48,49,49,45,48,54,45,50,50,84,49,54,58,49,
-    54,58,52,54,43,48,50,58,48,48,110,165,95,99,0,0,0,17,116,69,88,116,106,
-    112,101,103,58,99,111,108,111,114,115,112,97,99,101,0,50,44,117,85,159,
-    0,0,0,32,116,69,88,116,106,112,101,103,58,115,97,109,112,108,105,110,
-    103,45,102,97,99,116,111,114,0,50,120,50,44,49,120,49,44,49,120,49,73,
-    250,166,180,0,0,0,0,73,69,78,68,174,66,96,130
-};
-
-static unsigned char kWEBPImage[] = {
-    82,73,70,70,74,0,0,0,87,69,66,80,86,80,56,88,10,0,0,0,16,0,0,0,0,0,0,0,0,0,
-    65,76,80,72,12,0,0,0,1,7,16,17,253,15,68,68,255,3,0,0,86,80,56,32,24,0,0,0,
-    48,1,0,157,1,42,1,0,1,0,3,0,52,37,164,0,3,112,0,254,251,253,80,0
-};
-
-static const char kTestUrl[] = "http://www.img.com";
-
-static const char kWEBPHeaderResponse[] =
-    "HTTP/1.1 200 OK\0Content-type: image/webp\0\0";
-
-}  // namespace
-
-class ImageFetcherTest : public PlatformTest {
- protected:
-  ImageFetcherTest()
-      : worker_thread_("TestThread"),
-        callback_([^(const GURL& original_url,
-                     int http_response_code,
-                     NSData * data) {
-          result_ = [UIImage imageWithData:data];
-          called_ = true;
-        } copy]) {
-    worker_thread_.Start();
-
-    image_fetcher_ =
-        base::MakeUnique<ImageFetcher>(worker_thread_.task_runner());
-    image_fetcher_->SetRequestContextGetter(
-        new net::TestURLRequestContextGetter(
-            base::ThreadTaskRunnerHandle::Get()));
-  }
-
-  net::TestURLFetcher* SetupFetcher() {
-    image_fetcher_->StartDownload(GURL(kTestUrl), callback_);
-    EXPECT_EQ(nil, result_);
-    EXPECT_EQ(false, called_);
-    net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
-    DCHECK(fetcher);
-    DCHECK(fetcher->delegate());
-    return fetcher;
-  }
-
-  // Message loop for the main test thread.
-  base::MessageLoop loop_;
-
-  // Worker thread used for ImageFetcher's asynchronous work.
-  base::Thread worker_thread_;
-
-  base::mac::ScopedBlock<ImageFetchedCallback> callback_;
-  net::TestURLFetcherFactory factory_;
-  std::unique_ptr<ImageFetcher> image_fetcher_;
-  UIImage* result_ = nil;
-  bool called_ = false;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ImageFetcherTest);
-};
-
-TEST_F(ImageFetcherTest, TestError) {
-  net::TestURLFetcher* fetcher = SetupFetcher();
-  fetcher->set_response_code(404);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
-  EXPECT_EQ(nil, result_);
-  EXPECT_TRUE(called_);
-}
-
-TEST_F(ImageFetcherTest, TestJpg) {
-  net::TestURLFetcher* fetcher = SetupFetcher();
-  fetcher->set_response_code(200);
-  fetcher->SetResponseString(std::string((char*)kJPGImage, sizeof(kJPGImage)));
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
-  EXPECT_NE(nil, result_);
-  EXPECT_TRUE(called_);
-}
-
-TEST_F(ImageFetcherTest, TestPng) {
-  net::TestURLFetcher* fetcher = SetupFetcher();
-  fetcher->set_response_code(200);
-  fetcher->SetResponseString(std::string((char*)kPNGImage, sizeof(kPNGImage)));
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
-  EXPECT_NE(nil, result_);
-  EXPECT_TRUE(called_);
-}
-
-TEST_F(ImageFetcherTest, TestGoodWebP) {
-// TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
-#if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
-  if (base::ios::IsRunningOnIOS9OrLater())
-    return;
-#endif
-  net::TestURLFetcher* fetcher = SetupFetcher();
-  fetcher->set_response_code(200);
-  fetcher->SetResponseString(
-      std::string((char*)kWEBPImage, sizeof(kWEBPImage)));
-  scoped_refptr<net::HttpResponseHeaders> headers(new net::HttpResponseHeaders(
-      std::string(kWEBPHeaderResponse, arraysize(kWEBPHeaderResponse))));
-  fetcher->set_response_headers(headers);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
-  worker_thread_.FlushForTesting();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_NE(nil, result_);
-  EXPECT_TRUE(called_);
-}
-
-TEST_F(ImageFetcherTest, TestBadWebP) {
-  net::TestURLFetcher* fetcher = SetupFetcher();
-  fetcher->set_response_code(200);
-  fetcher->SetResponseString("This is not a valid WebP image");
-  scoped_refptr<net::HttpResponseHeaders> headers(new net::HttpResponseHeaders(
-      std::string(kWEBPHeaderResponse, arraysize(kWEBPHeaderResponse))));
-  fetcher->set_response_headers(headers);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
-  worker_thread_.FlushForTesting();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(nil, result_);
-  EXPECT_TRUE(called_);
-}
-
-TEST_F(ImageFetcherTest, DeleteDuringWebPDecoding) {
-  net::TestURLFetcher* fetcher = SetupFetcher();
-  fetcher->set_response_code(200);
-  fetcher->SetResponseString(
-      std::string((char*)kWEBPImage, sizeof(kWEBPImage)));
-  scoped_refptr<net::HttpResponseHeaders> headers(new net::HttpResponseHeaders(
-      std::string(kWEBPHeaderResponse, arraysize(kWEBPHeaderResponse))));
-  fetcher->set_response_headers(headers);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
-  // Delete the image fetcher, and check that the callback is not called.
-  image_fetcher_.reset();
-  worker_thread_.FlushForTesting();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(nil, result_);
-  EXPECT_FALSE(called_);
-}
-
-TEST_F(ImageFetcherTest, TestCallbacksNotCalledDuringDeletion) {
-  image_fetcher_->StartDownload(GURL(kTestUrl), callback_);
-  image_fetcher_.reset();
-  EXPECT_FALSE(called_);
-}
-
diff --git a/ios/chrome/browser/providers/BUILD.gn b/ios/chrome/browser/providers/BUILD.gn
index 1db5454..2a6e7c7c 100644
--- a/ios/chrome/browser/providers/BUILD.gn
+++ b/ios/chrome/browser/providers/BUILD.gn
@@ -10,6 +10,8 @@
     "chromium_browser_provider.mm",
     "chromium_logo_controller.h",
     "chromium_logo_controller.mm",
+    "chromium_spotlight_provider.h",
+    "chromium_spotlight_provider.mm",
     "chromium_voice_search_provider.h",
     "chromium_voice_search_provider.mm",
   ]
@@ -21,6 +23,7 @@
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/distribution",
     "//ios/public/provider/chrome/browser/signin",
+    "//ios/public/provider/chrome/browser/spotlight",
     "//ios/public/provider/chrome/browser/ui",
     "//ios/public/provider/chrome/browser/user_feedback",
     "//ios/public/provider/chrome/browser/voice",
diff --git a/ios/chrome/browser/providers/chromium_browser_provider.h b/ios/chrome/browser/providers/chromium_browser_provider.h
index 5a237e6..cc5c31b1 100644
--- a/ios/chrome/browser/providers/chromium_browser_provider.h
+++ b/ios/chrome/browser/providers/chromium_browser_provider.h
@@ -29,6 +29,7 @@
   UserFeedbackProvider* GetUserFeedbackProvider() const override;
   AppDistributionProvider* GetAppDistributionProvider() const override;
   BrandedImageProvider* GetBrandedImageProvider() const override;
+  SpotlightProvider* GetSpotlightProvider() const override;
 
  private:
   std::unique_ptr<AppDistributionProvider> app_distribution_provider_;
@@ -38,6 +39,7 @@
   std::unique_ptr<ios::ChromeIdentityService> chrome_identity_service_;
   std::unique_ptr<UserFeedbackProvider> user_feedback_provider_;
   std::unique_ptr<VoiceSearchProvider> voice_search_provider_;
+  std::unique_ptr<SpotlightProvider> spotlight_provider_;
 };
 
 #endif  // IOS_CHROME_BROWSER_PROVIDERS_CHROMIUM_BROWSER_PROVIDER_H_
diff --git a/ios/chrome/browser/providers/chromium_browser_provider.mm b/ios/chrome/browser/providers/chromium_browser_provider.mm
index 1cd9d9f..3d5ed08 100644
--- a/ios/chrome/browser/providers/chromium_browser_provider.mm
+++ b/ios/chrome/browser/providers/chromium_browser_provider.mm
@@ -7,6 +7,7 @@
 #include "base/memory/ptr_util.h"
 #import "ios/chrome/browser/providers/chromium_logo_controller.h"
 #import "ios/chrome/browser/providers/chromium_voice_search_provider.h"
+#import "ios/chrome/browser/providers/chromium_spotlight_provider.h"
 #import "ios/chrome/browser/providers/images/chromium_branded_image_provider.h"
 #include "ios/chrome/browser/providers/signin/chromium_signin_resources_provider.h"
 #include "ios/chrome/browser/providers/ui/chromium_styled_text_field.h"
@@ -26,7 +27,8 @@
       signin_resources_provider_(
           base::MakeUnique<ChromiumSigninResourcesProvider>()),
       user_feedback_provider_(base::MakeUnique<UserFeedbackProvider>()),
-      voice_search_provider_(base::MakeUnique<ChromiumVoiceSearchProvider>()) {}
+      voice_search_provider_(base::MakeUnique<ChromiumVoiceSearchProvider>()),
+      spotlight_provider_(base::MakeUnique<ChromiumSpotlightProvider>()) {}
 
 ChromiumBrowserProvider::~ChromiumBrowserProvider() {}
 
@@ -84,3 +86,7 @@
 BrandedImageProvider* ChromiumBrowserProvider::GetBrandedImageProvider() const {
   return branded_image_provider_.get();
 }
+
+SpotlightProvider* ChromiumBrowserProvider::GetSpotlightProvider() const {
+  return spotlight_provider_.get();
+}
diff --git a/ios/chrome/browser/providers/chromium_spotlight_provider.h b/ios/chrome/browser/providers/chromium_spotlight_provider.h
new file mode 100644
index 0000000..c0484b8
--- /dev/null
+++ b/ios/chrome/browser/providers/chromium_spotlight_provider.h
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_PROVIDERS_CHROMIUM_SPOTLIGHT_PROVIDER_H_
+#define IOS_CHROME_BROWSER_PROVIDERS_CHROMIUM_SPOTLIGHT_PROVIDER_H_
+
+#import <Foundation/Foundation.h>
+
+#import "ios/public/provider/chrome/browser/spotlight/spotlight_provider.h"
+
+class ChromiumSpotlightProvider : public SpotlightProvider {
+ public:
+  bool IsSpotlightEnabled() override;
+  NSString* GetBookmarkDomain() override;
+  NSString* GetTopSitesDomain() override;
+  NSString* GetActionsDomain() override;
+  NSString* GetCustomAttributeItemID() override;
+  NSArray* GetAdditionalKeywords() override;
+};
+
+#endif  // IOS_CHROME_BROWSER_PROVIDERS_CHROMIUM_SPOTLIGHT_PROVIDER_H_
diff --git a/ios/chrome/browser/providers/chromium_spotlight_provider.mm b/ios/chrome/browser/providers/chromium_spotlight_provider.mm
new file mode 100644
index 0000000..8fa6cf4
--- /dev/null
+++ b/ios/chrome/browser/providers/chromium_spotlight_provider.mm
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/providers/chromium_spotlight_provider.h"
+
+bool ChromiumSpotlightProvider::IsSpotlightEnabled() {
+  return true;
+}
+
+NSString* ChromiumSpotlightProvider::GetBookmarkDomain() {
+  return @"org.chromium.bookmarks";
+}
+
+NSString* ChromiumSpotlightProvider::GetTopSitesDomain() {
+  return @"org.chromium.topsites";
+}
+
+NSString* ChromiumSpotlightProvider::GetActionsDomain() {
+  return @"org.chromium.actions";
+}
+
+NSString* ChromiumSpotlightProvider::GetCustomAttributeItemID() {
+  return @"OrgChromiumItemID";
+}
+
+NSArray* ChromiumSpotlightProvider::GetAdditionalKeywords() {
+  return @[ @"chromium" ];
+}
diff --git a/ios/chrome/browser/suggestions/BUILD.gn b/ios/chrome/browser/suggestions/BUILD.gn
index da48938..216bf04 100644
--- a/ios/chrome/browser/suggestions/BUILD.gn
+++ b/ios/chrome/browser/suggestions/BUILD.gn
@@ -20,11 +20,10 @@
     "//components/signin/core/browser",
     "//components/suggestions",
     "//ios/chrome/browser/browser_state",
-    "//ios/chrome/browser/net",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/sync",
-    "//ios/chrome/browser/webp_transcode",
     "//ios/web",
+    "//ios/web/public/image_fetcher",
     "//net",
     "//skia",
     "//ui/gfx",
diff --git a/ios/chrome/browser/suggestions/image_fetcher_impl.h b/ios/chrome/browser/suggestions/image_fetcher_impl.h
index a6902d5..dfa1ae5 100644
--- a/ios/chrome/browser/suggestions/image_fetcher_impl.h
+++ b/ios/chrome/browser/suggestions/image_fetcher_impl.h
@@ -13,7 +13,6 @@
 #include "components/image_fetcher/image_fetcher.h"
 
 class GURL;
-class ImageFetcher;
 
 namespace base {
 class SequencedWorkerPool;
@@ -31,6 +30,10 @@
 class URLRequestContextGetter;
 }
 
+namespace web {
+class ImageDataFetcher;
+}
+
 namespace suggestions {
 
 // A class used to fetch server images asynchronously.
@@ -52,7 +55,7 @@
       override;
 
  private:
-  std::unique_ptr<::ImageFetcher> imageFetcher_;
+  std::unique_ptr<web::ImageDataFetcher> image_fetcher_;
 
   image_fetcher::ImageFetcherDelegate* delegate_;
 
diff --git a/ios/chrome/browser/suggestions/image_fetcher_impl.mm b/ios/chrome/browser/suggestions/image_fetcher_impl.mm
index 70d93428..9920987f 100644
--- a/ios/chrome/browser/suggestions/image_fetcher_impl.mm
+++ b/ios/chrome/browser/suggestions/image_fetcher_impl.mm
@@ -6,9 +6,10 @@
 
 #include <UIKit/UIKit.h>
 
+#include "base/memory/ptr_util.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "components/image_fetcher/image_fetcher_delegate.h"
-#include "ios/chrome/browser/net/image_fetcher.h"
+#import "ios/web/public/image_fetcher/image_data_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "skia/ext/skia_utils_ios.h"
 #include "ui/gfx/image/image.h"
@@ -17,9 +18,9 @@
 
 ImageFetcherImpl::ImageFetcherImpl(
     net::URLRequestContextGetter* url_request_context,
-    base::SequencedWorkerPool* blocking_pool) {
-  imageFetcher_.reset(new ::ImageFetcher(blocking_pool));
-  imageFetcher_->SetRequestContextGetter(url_request_context);
+    base::SequencedWorkerPool* blocking_pool)
+    : image_fetcher_(base::MakeUnique<web::ImageDataFetcher>(blocking_pool)) {
+  image_fetcher_->SetRequestContextGetter(url_request_context);
 }
 
 ImageFetcherImpl::~ImageFetcherImpl() {
@@ -52,27 +53,29 @@
   }
   // Copy string reference so it's retained.
   const std::string fetch_id(id);
-  ImageFetchedCallback fetcher_callback =
+  // If image_fetcher_ is destroyed the request will be cancelled and this block
+  // will never be called. A reference to delegate_ can be kept.
+  web::ImageFetchedCallback fetcher_callback =
       ^(const GURL& original_url, int response_code, NSData* data) {
-      if (data) {
-        // Most likely always returns 1x images.
-        UIImage* ui_image = [UIImage imageWithData:data scale:1];
-        if (ui_image) {
-          gfx::Image gfx_image(ui_image);
-          callback.Run(fetch_id, gfx_image);
-          if (delegate_) {
-            delegate_->OnImageFetched(fetch_id, gfx_image);
+        if (data) {
+          // Most likely always returns 1x images.
+          UIImage* ui_image = [UIImage imageWithData:data scale:1];
+          if (ui_image) {
+            gfx::Image gfx_image(ui_image);
+            callback.Run(fetch_id, gfx_image);
+            if (delegate_) {
+              delegate_->OnImageFetched(fetch_id, gfx_image);
+            }
+            return;
           }
-          return;
         }
-      }
-      gfx::Image empty_image;
-      callback.Run(fetch_id, empty_image);
-      if (delegate_) {
-        delegate_->OnImageFetched(fetch_id, empty_image);
-      }
-  };
-  imageFetcher_->StartDownload(image_url, fetcher_callback);
+        gfx::Image empty_image;
+        callback.Run(fetch_id, empty_image);
+        if (delegate_) {
+          delegate_->OnImageFetched(fetch_id, empty_image);
+        }
+      };
+  image_fetcher_->StartDownload(image_url, fetcher_callback);
 }
 
 }  // namespace suggestions
diff --git a/ios/chrome/browser/suggestions/ios_image_decoder_impl.mm b/ios/chrome/browser/suggestions/ios_image_decoder_impl.mm
index 52fc5507..e3525d13 100644
--- a/ios/chrome/browser/suggestions/ios_image_decoder_impl.mm
+++ b/ios/chrome/browser/suggestions/ios_image_decoder_impl.mm
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
-#include "ios/chrome/browser/webp_transcode/webp_decoder.h"
+#import "ios/web/public/image_fetcher/webp_decoder.h"
 #include "ios/web/public/web_thread.h"
 #include "ui/gfx/image/image.h"
 
diff --git a/ios/chrome/browser/webp_transcode/README b/ios/chrome/browser/webp_transcode/README
deleted file mode 100644
index 4484825..0000000
--- a/ios/chrome/browser/webp_transcode/README
+++ /dev/null
@@ -1,2 +0,0 @@
-webp_transcode is used to convert WebP images to other formats supported by the
-iOS web views.
diff --git a/ios/public/provider/chrome/browser/BUILD.gn b/ios/public/provider/chrome/browser/BUILD.gn
index 72e0c31..9de14fb 100644
--- a/ios/public/provider/chrome/browser/BUILD.gn
+++ b/ios/public/provider/chrome/browser/BUILD.gn
@@ -38,6 +38,7 @@
     "//ios/public/provider/chrome/browser/omaha:test_support",
     "//ios/public/provider/chrome/browser/sessions:test_support",
     "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/public/provider/chrome/browser/spotlight:test_support",
     "//ios/public/provider/chrome/browser/ui",
     "//ios/public/provider/chrome/browser/ui:test_support",
     "//ios/public/provider/chrome/browser/user_feedback:test_support",
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.h b/ios/public/provider/chrome/browser/chrome_browser_provider.h
index eb577ab..92db0be 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.h
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.h
@@ -25,6 +25,7 @@
 class OmahaServiceProvider;
 class PrefRegistrySimple;
 class PrefService;
+class SpotlightProvider;
 class UserFeedbackProvider;
 class VoiceSearchProvider;
 
@@ -192,6 +193,9 @@
   // Logs if any modals created by this provider are still presented. It does
   // not dismiss them.
   virtual void LogIfModalViewsArePresented() const;
+
+  // Returns an instance of the spotlight provider.
+  virtual SpotlightProvider* GetSpotlightProvider() const;
 };
 
 }  // namespace ios
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.mm b/ios/public/provider/chrome/browser/chrome_browser_provider.mm
index dc5fb2e..95d9aec 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.mm
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.mm
@@ -146,6 +146,10 @@
   return nullptr;
 }
 
+SpotlightProvider* ChromeBrowserProvider::GetSpotlightProvider() const {
+  return nullptr;
+}
+
 BrandedImageProvider* ChromeBrowserProvider::GetBrandedImageProvider() const {
   return nullptr;
 }
diff --git a/ios/public/provider/chrome/browser/spotlight/BUILD.gn b/ios/public/provider/chrome/browser/spotlight/BUILD.gn
new file mode 100644
index 0000000..816bf722
--- /dev/null
+++ b/ios/public/provider/chrome/browser/spotlight/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("spotlight") {
+  sources = [
+    "spotlight_provider.h",
+    "spotlight_provider.mm",
+  ]
+  deps = [
+    "//base",
+  ]
+  libs = [ "Foundation.framework" ]
+}
+
+source_set("test_support") {
+  testonly = true
+  sources = [
+    "test_spotlight_provider.h",
+    "test_spotlight_provider.mm",
+  ]
+  deps = [
+    ":spotlight",
+  ]
+}
diff --git a/ios/public/provider/chrome/browser/spotlight/spotlight_provider.h b/ios/public/provider/chrome/browser/spotlight/spotlight_provider.h
new file mode 100644
index 0000000..9e9c5f20
--- /dev/null
+++ b/ios/public/provider/chrome/browser/spotlight/spotlight_provider.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SPOTLIGHT_SPOTLIGHT_PROVIDER_H
+#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SPOTLIGHT_SPOTLIGHT_PROVIDER_H
+
+#import <Foundation/Foundation.h>
+
+#import "base/macros.h"
+
+class SpotlightProvider {
+ public:
+  SpotlightProvider() {}
+  virtual ~SpotlightProvider() {}
+
+  // Returns if the provider provides valid values on all other methods.
+  virtual bool IsSpotlightEnabled();
+
+  // Returns the spotlight domain for bookmarks items.
+  virtual NSString* GetBookmarkDomain();
+
+  // Returns the spotlight domain for top sites items.
+  virtual NSString* GetTopSitesDomain();
+
+  // Returns the spotlight domain for action items.
+  virtual NSString* GetActionsDomain();
+
+  // Returns the id for the custom item containing item ID in Spotlight index.
+  virtual NSString* GetCustomAttributeItemID();
+
+  // Returns additional keywords that are added to all Spotlight items.
+  virtual NSArray* GetAdditionalKeywords();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SpotlightProvider);
+};
+
+#endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SPOTLIGHT_SPOTLIGHT_PROVIDER_H
diff --git a/ios/public/provider/chrome/browser/spotlight/spotlight_provider.mm b/ios/public/provider/chrome/browser/spotlight/spotlight_provider.mm
new file mode 100644
index 0000000..2a9c2da
--- /dev/null
+++ b/ios/public/provider/chrome/browser/spotlight/spotlight_provider.mm
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/public/provider/chrome/browser/spotlight/spotlight_provider.h"
+
+bool SpotlightProvider::IsSpotlightEnabled() {
+  return false;
+}
+
+NSString* SpotlightProvider::GetBookmarkDomain() {
+  return nil;
+}
+
+NSString* SpotlightProvider::GetTopSitesDomain() {
+  return nil;
+}
+
+NSString* SpotlightProvider::GetActionsDomain() {
+  return nil;
+}
+
+NSString* SpotlightProvider::GetCustomAttributeItemID() {
+  return nil;
+}
+
+NSArray* SpotlightProvider::GetAdditionalKeywords() {
+  return nil;
+}
diff --git a/ios/public/provider/chrome/browser/spotlight/test_spotlight_provider.h b/ios/public/provider/chrome/browser/spotlight/test_spotlight_provider.h
new file mode 100644
index 0000000..11eff13d
--- /dev/null
+++ b/ios/public/provider/chrome/browser/spotlight/test_spotlight_provider.h
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SPOTLIGHT_TEST_SPOTLIGHT_PROVIDER_H
+#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SPOTLIGHT_TEST_SPOTLIGHT_PROVIDER_H
+
+#import <Foundation/Foundation.h>
+
+#import "ios/public/provider/chrome/browser/spotlight/spotlight_provider.h"
+
+class TestSpotlightProvider : public SpotlightProvider {
+ public:
+  bool IsSpotlightEnabled() override;
+  NSString* GetBookmarkDomain() override;
+  NSString* GetTopSitesDomain() override;
+  NSString* GetActionsDomain() override;
+  NSString* GetCustomAttributeItemID() override;
+  NSArray* GetAdditionalKeywords() override;
+};
+
+#endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SPOTLIGHT_TEST_SPOTLIGHT_PROVIDER_H
diff --git a/ios/public/provider/chrome/browser/spotlight/test_spotlight_provider.mm b/ios/public/provider/chrome/browser/spotlight/test_spotlight_provider.mm
new file mode 100644
index 0000000..4dcdac2d
--- /dev/null
+++ b/ios/public/provider/chrome/browser/spotlight/test_spotlight_provider.mm
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/public/provider/chrome/browser/spotlight/test_spotlight_provider.h"
+
+bool TestSpotlightProvider::IsSpotlightEnabled() {
+  return true;
+}
+
+NSString* TestSpotlightProvider::GetBookmarkDomain() {
+  return @"org.chromium.bookmarks";
+}
+
+NSString* TestSpotlightProvider::GetTopSitesDomain() {
+  return @"org.chromium.topsites";
+}
+
+NSString* TestSpotlightProvider::GetActionsDomain() {
+  return @"org.chromium.actions";
+}
+
+NSString* TestSpotlightProvider::GetCustomAttributeItemID() {
+  return @"OrgChromiumItemID";
+}
+
+NSArray* TestSpotlightProvider::GetAdditionalKeywords() {
+  return @[ @"chromium" ];
+}
diff --git a/ios/public/provider/chrome/browser/test_chrome_browser_provider.h b/ios/public/provider/chrome/browser/test_chrome_browser_provider.h
index 62de8bf..22ddbea7 100644
--- a/ios/public/provider/chrome/browser/test_chrome_browser_provider.h
+++ b/ios/public/provider/chrome/browser/test_chrome_browser_provider.h
@@ -36,6 +36,7 @@
   AppDistributionProvider* GetAppDistributionProvider() const override;
   OmahaServiceProvider* GetOmahaServiceProvider() const override;
   UserFeedbackProvider* GetUserFeedbackProvider() const override;
+  SpotlightProvider* GetSpotlightProvider() const override;
   std::unique_ptr<sync_sessions::SyncedWindowDelegatesGetter>
   CreateSyncedWindowDelegatesGetter(
       ios::ChromeBrowserState* browser_state) override;
@@ -51,6 +52,7 @@
   std::unique_ptr<SigninResourcesProvider> signin_resources_provider_;
   std::unique_ptr<VoiceSearchProvider> voice_search_provider_;
   std::unique_ptr<UserFeedbackProvider> user_feedback_provider_;
+  std::unique_ptr<SpotlightProvider> spotlight_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(TestChromeBrowserProvider);
 };
diff --git a/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm b/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm
index e097404..be379676 100644
--- a/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm
+++ b/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm
@@ -16,6 +16,7 @@
 #include "ios/public/provider/chrome/browser/sessions/test_synced_window_delegates_getter.h"
 #include "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
 #include "ios/public/provider/chrome/browser/signin/test_signin_resources_provider.h"
+#import "ios/public/provider/chrome/browser/spotlight/test_spotlight_provider.h"
 #import "ios/public/provider/chrome/browser/ui/test_infobar_view.h"
 #import "ios/public/provider/chrome/browser/ui/test_styled_text_field.h"
 #import "ios/public/provider/chrome/browser/user_feedback/test_user_feedback_provider.h"
@@ -34,7 +35,8 @@
       signin_resources_provider_(
           base::MakeUnique<TestSigninResourcesProvider>()),
       voice_search_provider_(base::MakeUnique<TestVoiceSearchProvider>()),
-      user_feedback_provider_(base::MakeUnique<TestUserFeedbackProvider>()) {}
+      user_feedback_provider_(base::MakeUnique<TestUserFeedbackProvider>()),
+      spotlight_provider_(base::MakeUnique<TestSpotlightProvider>()) {}
 
 TestChromeBrowserProvider::~TestChromeBrowserProvider() {}
 
@@ -96,6 +98,10 @@
   return user_feedback_provider_.get();
 }
 
+SpotlightProvider* TestChromeBrowserProvider::GetSpotlightProvider() const {
+  return spotlight_provider_.get();
+}
+
 std::unique_ptr<sync_sessions::SyncedWindowDelegatesGetter>
 TestChromeBrowserProvider::CreateSyncedWindowDelegatesGetter(
     ios::ChromeBrowserState* browser_state) {
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 8c6aa55..6a6ba6fe 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -363,6 +363,7 @@
     "//ios/testing:ios_test_support",
     "//ios/testing:ocmock_support",
     "//ios/third_party/gcdwebserver",
+    "//ios/web/public/image_fetcher",
     "//ios/web/test:mojo_bindings",
     "//net:test_support",
     "//testing/gmock",
@@ -380,6 +381,8 @@
     "public/test/http_server_util.mm",
     "public/test/js_test_util.h",
     "public/test/js_test_util.mm",
+    "public/test/mock_image_data_fetcher.h",
+    "public/test/mock_image_data_fetcher.mm",
     "public/test/native_controller_test_util.h",
     "public/test/native_controller_test_util.mm",
     "public/test/navigation_test_util.h",
@@ -478,6 +481,7 @@
     "//base/test:test_support",
     "//ios/net",
     "//ios/testing:ocmock_support",
+    "//ios/web/public/image_fetcher:unit_tests",
     "//ios/web/test:mojo_bindings",
     "//net:test_support",
     "//services/service_manager/public/cpp",
diff --git a/ios/chrome/browser/webp_transcode/BUILD.gn b/ios/web/public/image_fetcher/BUILD.gn
similarity index 62%
rename from ios/chrome/browser/webp_transcode/BUILD.gn
rename to ios/web/public/image_fetcher/BUILD.gn
index f52fbfc9..7c93ce1d 100644
--- a/ios/chrome/browser/webp_transcode/BUILD.gn
+++ b/ios/web/public/image_fetcher/BUILD.gn
@@ -2,14 +2,17 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-source_set("webp_transcode") {
+source_set("image_fetcher") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "image_data_fetcher.h",
+    "image_data_fetcher.mm",
     "webp_decoder.h",
     "webp_decoder.mm",
   ]
   deps = [
     "//base",
+    "//net",
     "//third_party/libwebp:libwebp_dec",
   ]
 }
@@ -18,12 +21,15 @@
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
+    "image_data_fetcher_unittest.mm",
     "webp_decoder_unittest.mm",
   ]
   deps = [
-    ":webp_transcode",
+    ":image_fetcher",
     ":webp_transcode_unit_tests_bundle_data",
     "//base",
+    "//net",
+    "//net:test_support",
     "//testing/gmock",
     "//testing/gtest",
   ]
@@ -34,12 +40,12 @@
   visibility = [ ":unit_tests" ]
   testonly = true
   sources = [
-    "//ios/chrome/test/data/webp_transcode/test.jpg",
-    "//ios/chrome/test/data/webp_transcode/test.webp",
-    "//ios/chrome/test/data/webp_transcode/test_alpha.png",
-    "//ios/chrome/test/data/webp_transcode/test_alpha.webp",
-    "//ios/chrome/test/data/webp_transcode/test_small.tiff",
-    "//ios/chrome/test/data/webp_transcode/test_small.webp",
+    "//ios/web/test/data/webp_transcode/test.jpg",
+    "//ios/web/test/data/webp_transcode/test.webp",
+    "//ios/web/test/data/webp_transcode/test_alpha.png",
+    "//ios/web/test/data/webp_transcode/test_alpha.webp",
+    "//ios/web/test/data/webp_transcode/test_small.tiff",
+    "//ios/web/test/data/webp_transcode/test_small.webp",
   ]
   outputs = [
     "{{bundle_resources_dir}}/{{source_root_relative_dir}}/" +
diff --git a/ios/chrome/browser/webp_transcode/DEPS b/ios/web/public/image_fetcher/DEPS
similarity index 100%
rename from ios/chrome/browser/webp_transcode/DEPS
rename to ios/web/public/image_fetcher/DEPS
diff --git a/ios/chrome/browser/webp_transcode/OWNERS b/ios/web/public/image_fetcher/OWNERS
similarity index 100%
rename from ios/chrome/browser/webp_transcode/OWNERS
rename to ios/web/public/image_fetcher/OWNERS
diff --git a/ios/web/public/image_fetcher/image_data_fetcher.h b/ios/web/public/image_fetcher/image_data_fetcher.h
new file mode 100644
index 0000000..797a2d3e9
--- /dev/null
+++ b/ios/web/public/image_fetcher/image_data_fetcher.h
@@ -0,0 +1,96 @@
+// Copyright 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_IMAGE_FETCHER_IMAGE_DATA_FETCHER_H_
+#define IOS_WEB_PUBLIC_IMAGE_FETCHER_IMAGE_DATA_FETCHER_H_
+
+#include <map>
+
+#include "base/mac/scoped_block.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request.h"
+
+class GURL;
+@class NSData;
+
+namespace base {
+class TaskRunner;
+}
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace web {
+
+// Callback that informs of the download of an image encoded in |data|,
+// downloaded from |url|, and with the http status |http_response_code|. If the
+// url is a data URL, |http_response_code| is always 200.
+using ImageFetchedCallback = void (^)(const GURL& url,
+                                      int http_response_code,
+                                      NSData* data);
+
+// Utility class that will retrieve an image from an URL. The image is returned
+// as NSData which can be used with +[UIImage imageWithData:]. This class
+// usually returns the raw bytes retrieved from the network without any
+// processing, with the exception of WebP encoded images. Those are decoded and
+// then reencoded in a format suitable for UIImage.
+// An instance of this class can download a number of images at the same time.
+class ImageDataFetcher : public net::URLFetcherDelegate {
+ public:
+  // The TaskRunner is used to eventually decode the image.
+  explicit ImageDataFetcher(const scoped_refptr<base::TaskRunner>& task_runner);
+  ~ImageDataFetcher() override;
+
+  // Start downloading the image at the given |url|. The |callback| will be
+  // called with the downloaded image, or nil if any error happened. The
+  // |referrer| and |referrer_policy| will be passed on to the underlying
+  // URLFetcher.
+  // This method assumes the request context getter has been set.
+  // (virtual for testing)
+  virtual void StartDownload(const GURL& url,
+                             ImageFetchedCallback callback,
+                             const std::string& referrer,
+                             net::URLRequest::ReferrerPolicy referrer_policy);
+
+  // Helper method to call StartDownload without a referrer.
+  // (virtual for testing)
+  virtual void StartDownload(const GURL& url, ImageFetchedCallback callback);
+
+  // A valid request context getter is required before starting the download.
+  // (virtual for testing)
+  virtual void SetRequestContextGetter(
+      const scoped_refptr<net::URLRequestContextGetter>&
+          request_context_getter);
+
+  // net::URLFetcherDelegate:
+  void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+ private:
+  // Runs the callback with the given arguments.
+  void RunCallback(const base::mac::ScopedBlock<ImageFetchedCallback>& callback,
+                   const GURL& url,
+                   const int http_response_code,
+                   NSData* data);
+
+  // Tracks open download requests.  The key is the URLFetcher object doing the
+  // fetch; the value is the callback to use when the download request
+  // completes. When a download request completes, the URLFetcher must be
+  // deleted and the callback called and released.
+  std::map<const net::URLFetcher*, ImageFetchedCallback> downloads_in_progress_;
+  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+
+  // The task runner used to decode images if necessary.
+  const scoped_refptr<base::TaskRunner> task_runner_;
+
+  // The WeakPtrFactory is used to cancel callbacks if ImageDataFetcher is
+  // destroyed during WebP decoding.
+  base::WeakPtrFactory<ImageDataFetcher> weak_factory_;
+};
+
+#endif  // IOS_WEB_PUBLIC_IMAGE_FETCHER_IMAGE_DATA_FETCHER_H_
+
+}  // namespace web
diff --git a/ios/web/public/image_fetcher/image_data_fetcher.mm b/ios/web/public/image_fetcher/image_data_fetcher.mm
new file mode 100644
index 0000000..cc7167db
--- /dev/null
+++ b/ios/web/public/image_fetcher/image_data_fetcher.mm
@@ -0,0 +1,179 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/public/image_fetcher/image_data_fetcher.h"
+
+#import <Foundation/Foundation.h>
+#include <stddef.h>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+#include "ios/web/public/image_fetcher/webp_decoder.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_context_getter.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+class WebpDecoderDelegate : public webp_transcode::WebpDecoder::Delegate {
+ public:
+  NSData* data() const { return decoded_image_; }
+
+  // WebpDecoder::Delegate methods
+  void OnFinishedDecoding(bool success) override {
+    if (!success)
+      decoded_image_.reset();
+  }
+  void SetImageFeatures(
+      size_t total_size,
+      webp_transcode::WebpDecoder::DecodedImageFormat format) override {
+    decoded_image_.reset([[NSMutableData alloc] initWithCapacity:total_size]);
+  }
+  void OnDataDecoded(NSData* data) override {
+    DCHECK(decoded_image_);
+    [decoded_image_ appendData:data];
+  }
+
+ private:
+  ~WebpDecoderDelegate() override {}
+  base::scoped_nsobject<NSMutableData> decoded_image_;
+};
+
+// Content-type header for WebP images.
+static const char kWEBPMimeType[] = "image/webp";
+
+// Returns a NSData object containing the decoded image.
+// Returns nil in case of failure.
+base::scoped_nsobject<NSData> DecodeWebpImage(
+    const base::scoped_nsobject<NSData>& webp_image) {
+  scoped_refptr<WebpDecoderDelegate> delegate(new WebpDecoderDelegate);
+  scoped_refptr<webp_transcode::WebpDecoder> decoder(
+      new webp_transcode::WebpDecoder(delegate.get()));
+  decoder->OnDataReceived(webp_image);
+  DLOG_IF(ERROR, !delegate->data()) << "WebP image decoding failed.";
+  return base::scoped_nsobject<NSData>(delegate->data());
+}
+
+}  // namespace
+
+namespace web {
+
+ImageDataFetcher::ImageDataFetcher(
+    const scoped_refptr<base::TaskRunner>& task_runner)
+    : request_context_getter_(nullptr),
+      task_runner_(task_runner),
+      weak_factory_(this) {
+  DCHECK(task_runner_.get());
+}
+
+ImageDataFetcher::~ImageDataFetcher() {
+  // Delete all the entries in the |downloads_in_progress_| map.  This will in
+  // turn cancel all of the requests.
+  for (const auto& pair : downloads_in_progress_) {
+    delete pair.first;
+  }
+}
+
+void ImageDataFetcher::StartDownload(
+    const GURL& url,
+    ImageFetchedCallback callback,
+    const std::string& referrer,
+    net::URLRequest::ReferrerPolicy referrer_policy) {
+  DCHECK(request_context_getter_.get());
+  net::URLFetcher* fetcher =
+      net::URLFetcher::Create(url, net::URLFetcher::GET, this).release();
+  downloads_in_progress_[fetcher] = [callback copy];
+  fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+                        net::LOAD_DO_NOT_SAVE_COOKIES |
+                        net::LOAD_DO_NOT_SEND_AUTH_DATA);
+  fetcher->SetRequestContext(request_context_getter_.get());
+  fetcher->SetReferrer(referrer);
+  fetcher->SetReferrerPolicy(referrer_policy);
+  fetcher->Start();
+}
+
+void ImageDataFetcher::StartDownload(const GURL& url,
+                                     ImageFetchedCallback callback) {
+  ImageDataFetcher::StartDownload(url, callback, std::string(),
+                                  net::URLRequest::NEVER_CLEAR_REFERRER);
+}
+
+// Delegate callback that is called when URLFetcher completes.  If the image
+// was fetched successfully, creates a new NSData and returns it to the
+// callback, otherwise returns nil to the callback.
+void ImageDataFetcher::OnURLFetchComplete(const net::URLFetcher* fetcher) {
+  if (downloads_in_progress_.find(fetcher) == downloads_in_progress_.end()) {
+    LOG(ERROR) << "Received callback for unknown URLFetcher " << fetcher;
+    return;
+  }
+
+  // Ensures that |fetcher| will be deleted in the event of early return.
+  std::unique_ptr<const net::URLFetcher> fetcher_deleter(fetcher);
+
+  // Retrieves the callback and ensures that it will be deleted in the event
+  // of early return.
+  base::mac::ScopedBlock<ImageFetchedCallback> callback(
+      downloads_in_progress_[fetcher]);
+
+  // Remove |fetcher| from the map.
+  downloads_in_progress_.erase(fetcher);
+
+  // Make sure the request was successful. For "data" requests, the response
+  // code has no meaning, because there is no actual server (data is encoded
+  // directly in the URL). In that case, set the response code to 200 (OK).
+  const GURL& original_url = fetcher->GetOriginalURL();
+  const int http_response_code =
+      original_url.SchemeIs("data") ? 200 : fetcher->GetResponseCode();
+  if (http_response_code != 200) {
+    (callback.get())(original_url, http_response_code, nil);
+    return;
+  }
+
+  std::string response;
+  if (!fetcher->GetResponseAsString(&response)) {
+    (callback.get())(original_url, http_response_code, nil);
+    return;
+  }
+
+  // Create a NSData from the returned data and notify the callback.
+  base::scoped_nsobject<NSData> data([[NSData alloc]
+      initWithBytes:reinterpret_cast<const unsigned char*>(response.data())
+             length:response.size()]);
+
+  if (fetcher->GetResponseHeaders()) {
+    std::string mime_type;
+    fetcher->GetResponseHeaders()->GetMimeType(&mime_type);
+    if (mime_type == kWEBPMimeType) {
+      base::PostTaskAndReplyWithResult(
+          task_runner_.get(), FROM_HERE, base::Bind(&DecodeWebpImage, data),
+          base::Bind(&ImageDataFetcher::RunCallback, weak_factory_.GetWeakPtr(),
+                     callback, original_url, http_response_code));
+      return;
+    }
+  }
+  (callback.get())(original_url, http_response_code, data);
+}
+
+void ImageDataFetcher::RunCallback(
+    const base::mac::ScopedBlock<ImageFetchedCallback>& callback,
+    const GURL& url,
+    int http_response_code,
+    NSData* data) {
+  (callback.get())(url, http_response_code, data);
+}
+
+void ImageDataFetcher::SetRequestContextGetter(
+    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) {
+  request_context_getter_ = request_context_getter;
+}
+
+}  // namespace web
diff --git a/ios/web/public/image_fetcher/image_data_fetcher_unittest.mm b/ios/web/public/image_fetcher/image_data_fetcher_unittest.mm
new file mode 100644
index 0000000..06412ec
--- /dev/null
+++ b/ios/web/public/image_fetcher/image_data_fetcher_unittest.mm
@@ -0,0 +1,217 @@
+// Copyright 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/public/image_fetcher/image_data_fetcher.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/ios/ios_util.h"
+#include "base/mac/scoped_block.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+static unsigned char kJPGImage[] = {
+    255, 216, 255, 224, 0,   16,  74,  70, 73, 70, 0,   1,   1,   1,   0,
+    72,  0,   72,  0,   0,   255, 254, 0,  19, 67, 114, 101, 97,  116, 101,
+    100, 32,  119, 105, 116, 104, 32,  71, 73, 77, 80,  255, 219, 0,   67,
+    0,   5,   3,   4,   4,   4,   3,   5,  4,  4,  4,   5,   5,   5,   6,
+    7,   12,  8,   7,   7,   7,   7,   15, 11, 11, 9,   12,  17,  15,  18,
+    18,  17,  15,  17,  17,  19,  22,  28, 23, 19, 20,  26,  21,  17,  17,
+    24,  33,  24,  26,  29,  29,  31,  31, 31, 19, 23,  34,  36,  34,  30,
+    36,  28,  30,  31,  30,  255, 219, 0,  67, 1,  5,   5,   5,   7,   6,
+    7,   14,  8,   8,   14,  30,  20,  17, 20, 30, 30,  30,  30,  30,  30,
+    30,  30,  30,  30,  30,  30,  30,  30, 30, 30, 30,  30,  30,  30,  30,
+    30,  30,  30,  30,  30,  30,  30,  30, 30, 30, 30,  30,  30,  30,  30,
+    30,  30,  30,  30,  30,  30,  30,  30, 30, 30, 30,  30,  30,  30,  255,
+    192, 0,   17,  8,   0,   1,   0,   1,  3,  1,  34,  0,   2,   17,  1,
+    3,   17,  1,   255, 196, 0,   21,  0,  1,  1,  0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,  0,  0,  8,   255, 196, 0,   20,
+    16,  1,   0,   0,   0,   0,   0,   0,  0,  0,  0,   0,   0,   0,   0,
+    0,   0,   0,   255, 196, 0,   20,  1,  1,  0,  0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,  0,  0,  255, 196, 0,   20,  17,
+    1,   0,   0,   0,   0,   0,   0,   0,  0,  0,  0,   0,   0,   0,   0,
+    0,   0,   255, 218, 0,   12,  3,   1,  0,  2,  17,  3,   17,  0,   63,
+    0,   178, 192, 7,   255, 217};
+
+static unsigned char kPNGImage[] = {
+    137, 80,  78,  71,  13,  10,  26,  10,  0,   0,   0,   13,  73,  72,  68,
+    82,  0,   0,   0,   1,   0,   0,   0,   1,   1,   0,   0,   0,   0,   55,
+    110, 249, 36,  0,   0,   0,   2,   98,  75,  71,  68,  0,   1,   221, 138,
+    19,  164, 0,   0,   0,   9,   112, 72,  89,  115, 0,   0,   11,  18,  0,
+    0,   11,  18,  1,   210, 221, 126, 252, 0,   0,   0,   9,   118, 112, 65,
+    103, 0,   0,   0,   1,   0,   0,   0,   1,   0,   199, 149, 95,  237, 0,
+    0,   0,   10,  73,  68,  65,  84,  8,   215, 99,  104, 0,   0,   0,   130,
+    0,   129, 221, 67,  106, 244, 0,   0,   0,   25,  116, 69,  88,  116, 99,
+    111, 109, 109, 101, 110, 116, 0,   67,  114, 101, 97,  116, 101, 100, 32,
+    119, 105, 116, 104, 32,  71,  73,  77,  80,  231, 175, 64,  203, 0,   0,
+    0,   37,  116, 69,  88,  116, 100, 97,  116, 101, 58,  99,  114, 101, 97,
+    116, 101, 0,   50,  48,  49,  49,  45,  48,  54,  45,  50,  50,  84,  49,
+    54,  58,  49,  54,  58,  52,  54,  43,  48,  50,  58,  48,  48,  31,  248,
+    231, 223, 0,   0,   0,   37,  116, 69,  88,  116, 100, 97,  116, 101, 58,
+    109, 111, 100, 105, 102, 121, 0,   50,  48,  49,  49,  45,  48,  54,  45,
+    50,  50,  84,  49,  54,  58,  49,  54,  58,  52,  54,  43,  48,  50,  58,
+    48,  48,  110, 165, 95,  99,  0,   0,   0,   17,  116, 69,  88,  116, 106,
+    112, 101, 103, 58,  99,  111, 108, 111, 114, 115, 112, 97,  99,  101, 0,
+    50,  44,  117, 85,  159, 0,   0,   0,   32,  116, 69,  88,  116, 106, 112,
+    101, 103, 58,  115, 97,  109, 112, 108, 105, 110, 103, 45,  102, 97,  99,
+    116, 111, 114, 0,   50,  120, 50,  44,  49,  120, 49,  44,  49,  120, 49,
+    73,  250, 166, 180, 0,   0,   0,   0,   73,  69,  78,  68,  174, 66,  96,
+    130};
+
+static unsigned char kWEBPImage[] = {
+    82, 73, 70, 70, 74,  0, 0,  0,   87,  69,  66,  80,  86,  80, 56, 88, 10,
+    0,  0,  0,  16, 0,   0, 0,  0,   0,   0,   0,   0,   0,   65, 76, 80, 72,
+    12, 0,  0,  0,  1,   7, 16, 17,  253, 15,  68,  68,  255, 3,  0,  0,  86,
+    80, 56, 32, 24, 0,   0, 0,  48,  1,   0,   157, 1,   42,  1,  0,  1,  0,
+    3,  0,  52, 37, 164, 0, 3,  112, 0,   254, 251, 253, 80,  0};
+
+static const char kTestUrl[] = "http://www.img.com";
+
+static const char kWEBPHeaderResponse[] =
+    "HTTP/1.1 200 OK\0Content-type: image/webp\0\0";
+
+}  // namespace
+
+namespace web {
+
+class ImageDataFetcherTest : public PlatformTest {
+ protected:
+  ImageDataFetcherTest()
+      : worker_thread_("TestThread"),
+        callback_(
+            [^(const GURL& original_url, int http_response_code, NSData* data) {
+              result_ = [UIImage imageWithData:data];
+              called_ = true;
+            } copy]) {
+    worker_thread_.Start();
+
+    image_fetcher_ =
+        base::MakeUnique<ImageDataFetcher>(worker_thread_.task_runner());
+    image_fetcher_->SetRequestContextGetter(
+        new net::TestURLRequestContextGetter(
+            base::ThreadTaskRunnerHandle::Get()));
+  }
+
+  net::TestURLFetcher* SetupFetcher() {
+    image_fetcher_->StartDownload(GURL(kTestUrl), callback_);
+    EXPECT_EQ(nil, result_);
+    EXPECT_EQ(false, called_);
+    net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+    DCHECK(fetcher);
+    DCHECK(fetcher->delegate());
+    return fetcher;
+  }
+
+  // Message loop for the main test thread.
+  base::MessageLoop loop_;
+
+  // Worker thread used for ImageFetcher's asynchronous work.
+  base::Thread worker_thread_;
+
+  base::mac::ScopedBlock<ImageFetchedCallback> callback_;
+  net::TestURLFetcherFactory factory_;
+  std::unique_ptr<ImageDataFetcher> image_fetcher_;
+  UIImage* result_ = nil;
+  bool called_ = false;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ImageDataFetcherTest);
+};
+
+TEST_F(ImageDataFetcherTest, TestError) {
+  net::TestURLFetcher* fetcher = SetupFetcher();
+  fetcher->set_response_code(404);
+  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  EXPECT_EQ(nil, result_);
+  EXPECT_TRUE(called_);
+}
+
+TEST_F(ImageDataFetcherTest, TestJpg) {
+  net::TestURLFetcher* fetcher = SetupFetcher();
+  fetcher->set_response_code(200);
+  fetcher->SetResponseString(std::string((char*)kJPGImage, sizeof(kJPGImage)));
+  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  EXPECT_NE(nil, result_);
+  EXPECT_TRUE(called_);
+}
+
+TEST_F(ImageDataFetcherTest, TestPng) {
+  net::TestURLFetcher* fetcher = SetupFetcher();
+  fetcher->set_response_code(200);
+  fetcher->SetResponseString(std::string((char*)kPNGImage, sizeof(kPNGImage)));
+  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  EXPECT_NE(nil, result_);
+  EXPECT_TRUE(called_);
+}
+
+TEST_F(ImageDataFetcherTest, TestGoodWebP) {
+// TODO(droger): This test fails on iOS 9 x64 devices. http://crbug.com/523235
+#if defined(OS_IOS) && defined(ARCH_CPU_ARM64) && !TARGET_IPHONE_SIMULATOR
+  if (base::ios::IsRunningOnIOS9OrLater())
+    return;
+#endif
+  net::TestURLFetcher* fetcher = SetupFetcher();
+  fetcher->set_response_code(200);
+  fetcher->SetResponseString(
+      std::string((char*)kWEBPImage, sizeof(kWEBPImage)));
+  scoped_refptr<net::HttpResponseHeaders> headers(new net::HttpResponseHeaders(
+      std::string(kWEBPHeaderResponse, arraysize(kWEBPHeaderResponse))));
+  fetcher->set_response_headers(headers);
+  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  worker_thread_.FlushForTesting();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_NE(nil, result_);
+  EXPECT_TRUE(called_);
+}
+
+TEST_F(ImageDataFetcherTest, TestBadWebP) {
+  net::TestURLFetcher* fetcher = SetupFetcher();
+  fetcher->set_response_code(200);
+  fetcher->SetResponseString("This is not a valid WebP image");
+  scoped_refptr<net::HttpResponseHeaders> headers(new net::HttpResponseHeaders(
+      std::string(kWEBPHeaderResponse, arraysize(kWEBPHeaderResponse))));
+  fetcher->set_response_headers(headers);
+  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  worker_thread_.FlushForTesting();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(nil, result_);
+  EXPECT_TRUE(called_);
+}
+
+TEST_F(ImageDataFetcherTest, DeleteDuringWebPDecoding) {
+  net::TestURLFetcher* fetcher = SetupFetcher();
+  fetcher->set_response_code(200);
+  fetcher->SetResponseString(
+      std::string((char*)kWEBPImage, sizeof(kWEBPImage)));
+  scoped_refptr<net::HttpResponseHeaders> headers(new net::HttpResponseHeaders(
+      std::string(kWEBPHeaderResponse, arraysize(kWEBPHeaderResponse))));
+  fetcher->set_response_headers(headers);
+  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  // Delete the image fetcher, and check that the callback is not called.
+  image_fetcher_.reset();
+  worker_thread_.FlushForTesting();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(nil, result_);
+  EXPECT_FALSE(called_);
+}
+
+TEST_F(ImageDataFetcherTest, TestCallbacksNotCalledDuringDeletion) {
+  image_fetcher_->StartDownload(GURL(kTestUrl), callback_);
+  image_fetcher_.reset();
+  EXPECT_FALSE(called_);
+}
+
+}  // namespace web
diff --git a/ios/chrome/browser/webp_transcode/webp_decoder.h b/ios/web/public/image_fetcher/webp_decoder.h
similarity index 92%
rename from ios/chrome/browser/webp_transcode/webp_decoder.h
rename to ios/web/public/image_fetcher/webp_decoder.h
index e2f5714..1ab4d6c5 100644
--- a/ios/chrome/browser/webp_transcode/webp_decoder.h
+++ b/ios/web/public/image_fetcher/webp_decoder.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_WEBP_TRANSCODE_WEBP_DECODER_H_
-#define IOS_CHROME_BROWSER_WEBP_TRANSCODE_WEBP_DECODER_H_
+#ifndef IOS_WEB_PUBLIC_IMAGE_FETCHER_WEBP_DECODER_H_
+#define IOS_WEB_PUBLIC_IMAGE_FETCHER_WEBP_DECODER_H_
 
 #import <Foundation/Foundation.h>
 #include <stddef.h>
@@ -75,4 +75,4 @@
 
 }  // namespace webp_transcode
 
-#endif  // IOS_CHROME_BROWSER_WEBP_TRANSCODE_WEBP_DECODER_H_
+#endif  // IOS_WEB_PUBLIC_IMAGE_FETCHER_WEBP_DECODER_H_
diff --git a/ios/chrome/browser/webp_transcode/webp_decoder.mm b/ios/web/public/image_fetcher/webp_decoder.mm
similarity index 79%
rename from ios/chrome/browser/webp_transcode/webp_decoder.mm
rename to ios/web/public/image_fetcher/webp_decoder.mm
index 16f2b4a7..935deee 100644
--- a/ios/chrome/browser/webp_transcode/webp_decoder.mm
+++ b/ios/web/public/image_fetcher/webp_decoder.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/chrome/browser/webp_transcode/webp_decoder.h"
+#include "ios/web/public/image_fetcher/webp_decoder.h"
 
 #import <Foundation/Foundation.h>
 #include <stdint.h>
@@ -45,34 +45,34 @@
   const uint8_t num_ifd_entries =
       has_alpha ? kNumIfdEntries : kNumIfdEntries - 1;
   uint8_t tiff_header[kHeaderSize] = {
-    0x49, 0x49, 0x2a, 0x00,   // little endian signature
-    8, 0, 0, 0,               // offset to the unique IFD that follows
-    // IFD (offset = 8). Entries must be written in increasing tag order.
-    num_ifd_entries, 0,       // Number of entries in the IFD (12 bytes each).
-    0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0,    //  10: Width  (TBD)
-    0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0,    //  22: Height (TBD)
-    0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0,     //  34: BitsPerSample: 8888
-        kExtraDataOffset + 0, 0, 0, 0,
-    0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0,    //  46: Compression: none
-    0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0,    //  58: Photometric: RGB
-    0x11, 0x01, 4, 0, 1, 0, 0, 0,                //  70: Strips offset:
-        kHeaderSize, 0, 0, 0,                    //      data follows header
-    0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0,    //  82: Orientation: topleft
-    0x15, 0x01, 3, 0, 1, 0, 0, 0,                //  94: SamplesPerPixels
-        bytes_per_px, 0, 0, 0,
-    0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0,    // 106: Rows per strip (TBD)
-    0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0,    // 118: StripByteCount (TBD)
-    0x1a, 0x01, 5, 0, 1, 0, 0, 0,                // 130: X-resolution
-        kExtraDataOffset + 8, 0, 0, 0,
-    0x1b, 0x01, 5, 0, 1, 0, 0, 0,                // 142: Y-resolution
-        kExtraDataOffset + 8, 0, 0, 0,
-    0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0,    // 154: PlanarConfiguration
-    0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0,    // 166: ResolutionUnit (inch)
-    0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0,    // 178: ExtraSamples: rgbA
-    0, 0, 0, 0,                                  // 190: IFD terminator
-    // kExtraDataOffset:
-    8, 0, 8, 0, 8, 0, 8, 0,      // BitsPerSample
-    72, 0, 0, 0, 1, 0, 0, 0      // 72 pixels/inch, for X/Y-resolution
+      0x49, 0x49, 0x2a, 0x00,  // little endian signature
+      8, 0, 0, 0,              // offset to the unique IFD that follows
+      // IFD (offset = 8). Entries must be written in increasing tag order.
+      num_ifd_entries, 0,  // Number of entries in the IFD (12 bytes each).
+      0x00, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0,  //  10: Width  (TBD)
+      0x01, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0,  //  22: Height (TBD)
+      0x02, 0x01, 3, 0, bytes_per_px, 0, 0, 0,   //  34: BitsPerSample: 8888
+      kExtraDataOffset + 0, 0, 0, 0, 0x03, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0,
+      0,                                         //  46: Compression: none
+      0x06, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0,  //  58: Photometric: RGB
+      0x11, 0x01, 4, 0, 1, 0, 0, 0,              //  70: Strips offset:
+      kHeaderSize, 0, 0, 0,                      //      data follows header
+      0x12, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0,  //  82: Orientation: topleft
+      0x15, 0x01, 3, 0, 1, 0, 0, 0,              //  94: SamplesPerPixels
+      bytes_per_px, 0, 0, 0, 0x16, 0x01, 3, 0, 1, 0, 0, 0, 0, 0, 0,
+      0,                                         // 106: Rows per strip (TBD)
+      0x17, 0x01, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0,  // 118: StripByteCount (TBD)
+      0x1a, 0x01, 5, 0, 1, 0, 0, 0,              // 130: X-resolution
+      kExtraDataOffset + 8, 0, 0, 0, 0x1b, 0x01, 5, 0, 1, 0, 0,
+      0,  // 142: Y-resolution
+      kExtraDataOffset + 8, 0, 0, 0, 0x1c, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0,
+      0,                                         // 154: PlanarConfiguration
+      0x28, 0x01, 3, 0, 1, 0, 0, 0, 2, 0, 0, 0,  // 166: ResolutionUnit (inch)
+      0x52, 0x01, 3, 0, 1, 0, 0, 0, 1, 0, 0, 0,  // 178: ExtraSamples: rgbA
+      0, 0, 0, 0,                                // 190: IFD terminator
+      // kExtraDataOffset:
+      8, 0, 8, 0, 8, 0, 8, 0,  // BitsPerSample
+      72, 0, 0, 0, 1, 0, 0, 0  // 72 pixels/inch, for X/Y-resolution
   };
 
   // Fill placeholders in IFD:
diff --git a/ios/chrome/browser/webp_transcode/webp_decoder_unittest.mm b/ios/web/public/image_fetcher/webp_decoder_unittest.mm
similarity index 98%
rename from ios/chrome/browser/webp_transcode/webp_decoder_unittest.mm
rename to ios/web/public/image_fetcher/webp_decoder_unittest.mm
index e7b67f7..9efbe75 100644
--- a/ios/chrome/browser/webp_transcode/webp_decoder_unittest.mm
+++ b/ios/web/public/image_fetcher/webp_decoder_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/chrome/browser/webp_transcode/webp_decoder.h"
+#include "ios/web/public/image_fetcher/webp_decoder.h"
 
 #import <CoreGraphics/CoreGraphics.h>
 #import <Foundation/Foundation.h>
@@ -59,8 +59,8 @@
   NSData* LoadImage(const base::FilePath& filename) {
     base::FilePath path;
     PathService::Get(base::DIR_SOURCE_ROOT, &path);
-    path = path.AppendASCII("ios/chrome/test/data/webp_transcode")
-               .Append(filename);
+    path =
+        path.AppendASCII("ios/web/test/data/webp_transcode").Append(filename);
     return
         [NSData dataWithContentsOfFile:base::SysUTF8ToNSString(path.value())];
   }
diff --git a/ios/web/public/test/mock_image_data_fetcher.h b/ios/web/public/test/mock_image_data_fetcher.h
new file mode 100644
index 0000000..196b68f2
--- /dev/null
+++ b/ios/web/public/test/mock_image_data_fetcher.h
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_IMAGE_FETCHER_MOCK_IMAGE_DATA_FETCHER_H_
+#define IOS_WEB_PUBLIC_IMAGE_FETCHER_MOCK_IMAGE_DATA_FETCHER_H_
+
+#import "ios/web/public/image_fetcher/image_data_fetcher.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace web {
+
+// Mocks the ImageDataFetcher utility class, which can be used to asynchronously
+// retrieve an image from an URL.
+class MockImageDataFetcher : public ImageDataFetcher {
+ public:
+  explicit MockImageDataFetcher(
+      const scoped_refptr<base::TaskRunner>& task_runner);
+  ~MockImageDataFetcher() override;
+
+  MOCK_METHOD4(StartDownload,
+               void(const GURL& url,
+                    ImageFetchedCallback callback,
+                    const std::string& referrer,
+                    net::URLRequest::ReferrerPolicy referrer_policy));
+  MOCK_METHOD2(StartDownload,
+               void(const GURL& url, ImageFetchedCallback callback));
+  MOCK_METHOD1(SetRequestContextGetter,
+               void(const scoped_refptr<net::URLRequestContextGetter>&
+                        request_context_getter));
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_PUBLIC_IMAGE_FETCHER_MOCK_IMAGE_DATA_FETCHER_H_
diff --git a/ios/web/public/test/mock_image_data_fetcher.mm b/ios/web/public/test/mock_image_data_fetcher.mm
new file mode 100644
index 0000000..fbdfd57
--- /dev/null
+++ b/ios/web/public/test/mock_image_data_fetcher.mm
@@ -0,0 +1,15 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/public/test/mock_image_data_fetcher.h"
+
+namespace web {
+
+MockImageDataFetcher::MockImageDataFetcher(
+    const scoped_refptr<base::TaskRunner>& task_runner)
+    : ImageDataFetcher(task_runner) {}
+
+MockImageDataFetcher::~MockImageDataFetcher() {}
+
+}  // namespace web
diff --git a/ios/chrome/test/data/webp_transcode/OWNERS b/ios/web/test/data/webp_transcode/OWNERS
similarity index 100%
rename from ios/chrome/test/data/webp_transcode/OWNERS
rename to ios/web/test/data/webp_transcode/OWNERS
diff --git a/ios/chrome/test/data/webp_transcode/test.jpg b/ios/web/test/data/webp_transcode/test.jpg
similarity index 100%
rename from ios/chrome/test/data/webp_transcode/test.jpg
rename to ios/web/test/data/webp_transcode/test.jpg
Binary files differ
diff --git a/ios/chrome/test/data/webp_transcode/test.webp b/ios/web/test/data/webp_transcode/test.webp
similarity index 100%
rename from ios/chrome/test/data/webp_transcode/test.webp
rename to ios/web/test/data/webp_transcode/test.webp
Binary files differ
diff --git a/ios/chrome/test/data/webp_transcode/test_alpha.png b/ios/web/test/data/webp_transcode/test_alpha.png
similarity index 100%
rename from ios/chrome/test/data/webp_transcode/test_alpha.png
rename to ios/web/test/data/webp_transcode/test_alpha.png
Binary files differ
diff --git a/ios/chrome/test/data/webp_transcode/test_alpha.webp b/ios/web/test/data/webp_transcode/test_alpha.webp
similarity index 100%
rename from ios/chrome/test/data/webp_transcode/test_alpha.webp
rename to ios/web/test/data/webp_transcode/test_alpha.webp
Binary files differ
diff --git a/ios/chrome/test/data/webp_transcode/test_small.tiff b/ios/web/test/data/webp_transcode/test_small.tiff
similarity index 100%
rename from ios/chrome/test/data/webp_transcode/test_small.tiff
rename to ios/web/test/data/webp_transcode/test_small.tiff
Binary files differ
diff --git a/ios/chrome/test/data/webp_transcode/test_small.webp b/ios/web/test/data/webp_transcode/test_small.webp
similarity index 100%
rename from ios/chrome/test/data/webp_transcode/test_small.webp
rename to ios/web/test/data/webp_transcode/test_small.webp
Binary files differ
diff --git a/net/log/trace_net_log_observer.cc b/net/log/trace_net_log_observer.cc
index 4c7b7dc..bae83a5a 100644
--- a/net/log/trace_net_log_observer.cc
+++ b/net/log/trace_net_log_observer.cc
@@ -90,6 +90,10 @@
   DCHECK(!net_log_to_watch_);
   DCHECK(!net_log());
   net_log_to_watch_ = netlog;
+  // Tracing can start before the observer is even created, for instance for
+  // startup tracing.
+  if (base::trace_event::TraceLog::GetInstance()->IsEnabled())
+    OnTraceLogEnabled();
   base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
 }
 
diff --git a/net/log/trace_net_log_observer_unittest.cc b/net/log/trace_net_log_observer_unittest.cc
index 60c54ee0..2cd4f01 100644
--- a/net/log/trace_net_log_observer_unittest.cc
+++ b/net/log/trace_net_log_observer_unittest.cc
@@ -319,6 +319,31 @@
   TestNetLogEntry::List entries;
   net_log()->GetEntries(&entries);
   EXPECT_EQ(3u, entries.size());
+  EXPECT_EQ(1u, trace_events()->GetSize());
+}
+
+TEST_F(TraceNetLogObserverTest,
+       CreateObserverAfterTracingStartsDisabledCategory) {
+  set_trace_net_log_observer(nullptr);
+
+  std::string disabled_netlog_category =
+      std::string("-") + kNetLogTracingCategory;
+  TraceLog::GetInstance()->SetEnabled(
+      base::trace_event::TraceConfig(disabled_netlog_category, ""),
+      TraceLog::RECORDING_MODE);
+
+  set_trace_net_log_observer(new TraceNetLogObserver());
+  trace_net_log_observer()->WatchForTraceStart(net_log());
+  net_log()->AddGlobalEntry(NetLogEventType::CANCELLED);
+  trace_net_log_observer()->StopWatchForTraceStart();
+  net_log()->AddGlobalEntry(NetLogEventType::REQUEST_ALIVE);
+  net_log()->AddGlobalEntry(NetLogEventType::URL_REQUEST_START_JOB);
+
+  EndTraceAndFlush();
+
+  TestNetLogEntry::List entries;
+  net_log()->GetEntries(&entries);
+  EXPECT_EQ(3u, entries.size());
   EXPECT_EQ(0u, trace_events()->GetSize());
 }
 
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 06a773a..cc4bd23 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1183,24 +1183,6 @@
             ]
         }
     ],
-    "NonValidatingReloadOnNormalReload": [
-        {
-            "platforms": [
-                "android",
-                "linux",
-                "mac",
-                "win"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "NonValidatingReloadOnNormalReload"
-                    ]
-                }
-            ]
-        }
-    ],
     "OfferUploadCreditCards": [
         {
             "platforms": [
diff --git a/third_party/WebKit/Source/bindings/IDLExtendedAttributes.md b/third_party/WebKit/Source/bindings/IDLExtendedAttributes.md
index aa42702..ee8567e 100644
--- a/third_party/WebKit/Source/bindings/IDLExtendedAttributes.md
+++ b/third_party/WebKit/Source/bindings/IDLExtendedAttributes.md
@@ -550,21 +550,18 @@
 
 Summary: `[CallWith]` indicates that the bindings code calls the Blink implementation with additional information.
 
-Each value changes the signature of the Blink methods by adding an additional parameter to the head of the parameter list, such as `&state` for `[CallWith=ScriptState]`.
-
-Multiple values can be specified e.g. `[CallWith=ScriptState|ScriptArguments]`. The order of the values in the IDL file doesn't matter: the generated parameter list is always in a fixed order (specifically `&state`, `scriptContext`, `scriptArguments.release()`, if present, corresponding to `ScriptState`, `ScriptExecutionContext`, `ScriptArguments`, respectively).
+Each value changes the signature of the Blink methods by adding an additional parameter to the head of the parameter list, such as `ScriptState*` for `[CallWith=ScriptState]`.
 
 There are also three rarely used values: `CurrentWindow`, `EnteredWindow`, `ThisValue`.
 
 `[SetterCallWith]` applies to attributes, and only affects the signature of the setter; this is only used in Location.idl, with `CurrentWindow&EnteredWindow`.
 
-Syntax:
-`CallWith=ScriptState|ScriptExecutionContext|ScriptArguments|CurrentWindow|EnteredWindow|ThisValue`
-
 #### [CallWith=ScriptState] _(m, a*)_
-`[CallWith=ScriptState]` is used in a number of places for methods.
 
-`[CallWith=ScriptState]` _can_ be used for attributes, but is not used in real IDL files.
+`[CallWith=ScriptState]` is used in a number of places for methods.
+ScriptState holds all information about script execution.
+You can retrieve Frame, ExcecutionContext, v8::Context, v8::Isolate etc
+from ScriptState.
 
 IDL example:
 
@@ -582,7 +579,18 @@
 String Example::func(ScriptState* state, bool a, bool b);
 ```
 
-#### [CallWith=ExecutionContext] _(m,a)_
+Be careful when you use `[CallWith=ScriptState]`.
+You should not store the passed-in ScriptState on a DOM object (using RefPtr<ScriptState>).
+This is because if the stored ScriptState is used by some method called by a different
+world (note that the DOM object is shared among multiple worlds), it leaks the ScriptState
+to the world. ScriptState must be carefully maintained in a way that doesn't leak
+to another world.
+
+#### [CallWith=ExecutionContext] _(m,a)_  _deprecated_
+
+`[CallWith=ExecutionContext]` is a less convenient version of `[CallWith=ScriptState]`
+because you can just retrieve ExecutionContext from ScriptState.
+Use `[CallWith=ScriptState]` instead.
 
 IDL example:
 
@@ -600,24 +608,6 @@
 String Example::func(ExecutionContext* context, bool a, bool b);
 ```
 
-You can retrieve the document and frame from a `ExecutionContext*`.
-
-#### [CallWith=ScriptArguments] _(m)_
-
-IDL example:
-
-```webidl
-interface Example {
-    [CallWith=ScriptState] DOMString func(boolean a, boolean b);
-};
-```
-
-C++ Blink function signature:
-
-```c++
-String Example::func(ScriptArguments* arguments, bool a, bool b);
-```
-
 _(rare CallWith values)_
 
 #### [CallWith=CurrentWindow&EnteredWindow] _(m, a)_
@@ -655,7 +645,7 @@
 ```webidl
 [
     Constructor(float x, float y, DOMString str),
-    ConstructorCallWith=Document|ExecutionContext,
+    ConstructorCallWith=ExecutionContext,
 ]
 interface XXX {
     ...
@@ -669,13 +659,18 @@
 ***
 
 ```c++
-PassRefPtr<XXX> XXX::create(ScriptExecutionContext* context, ScriptState* state, float x, float y, String str)
+PassRefPtr<XXX> XXX::create(ExecutionContext* context, float x, float y, String str)
 {
     ...;
 }
 ```
 
-You can retrieve document or frame from ScriptExecutionContext.
+Be careful when you use `[ConstructorCallWith=ScriptState]`.
+You should not store the passed-in ScriptState on a DOM object (using RefPtr<ScriptState>).
+This is because if the stored ScriptState is used by some method called by a different
+world (note that the DOM object is shared among multiple worlds), it leaks the ScriptState
+to the world. ScriptState must be carefully maintained in a way that doesn't leak
+to another world.
 
 ### [Custom] _(i, m, s, a, f)_
 
@@ -827,7 +822,7 @@
 }
 ```
 
-#### [Custom=LegacyCallAsFunction] _(i) _deprecated__
+#### [Custom=LegacyCallAsFunction] _(i) _deprecated_
 
 Summary: `[Custom=LegacyCallAsFunction]` allows you to write custom bindings for call(...) of a given interface.
 
@@ -1384,7 +1379,7 @@
 }
 
 // Called by generated binding code if no value cached or isAttributeDirty() returns true
-ScriptValue Object::attribute(ScriptExecutionContext* context)
+ScriptValue Object::attribute(ExecutionContext* context)
 {
     m_attributeDirty = false;
     return convertDataToScriptValue(m_data);
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index ed97200c..fca88932 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -5738,11 +5738,6 @@
   m_taskRunner->postTask(location, std::move(task), taskNameForInstrumentation);
 }
 
-void Document::postInspectorTask(const WebTraceLocation& location,
-                                 std::unique_ptr<ExecutionContextTask> task) {
-  m_taskRunner->postInspectorTask(location, std::move(task));
-}
-
 void Document::tasksWereSuspended() {
   scriptRunner()->suspend();
 
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 907fb50..38cbd58e 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -996,8 +996,6 @@
                 std::unique_ptr<ExecutionContextTask>,
                 const String& taskNameForInstrumentation = emptyString())
       override;  // Executes the task on context's thread asynchronously.
-  void postInspectorTask(const WebTraceLocation&,
-                         std::unique_ptr<ExecutionContextTask>);
 
   void tasksWereSuspended() final;
   void tasksWereResumed() final;
diff --git a/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.cpp b/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.cpp
index e8e1ac08..91ec2dc 100644
--- a/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.cpp
+++ b/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.cpp
@@ -44,17 +44,6 @@
 
 MainThreadTaskRunner::~MainThreadTaskRunner() {}
 
-void MainThreadTaskRunner::postTaskInternal(
-    const WebTraceLocation& location,
-    std::unique_ptr<ExecutionContextTask> task,
-    bool isInspectorTask,
-    bool instrumenting) {
-  Platform::current()->mainThread()->getWebTaskRunner()->postTask(
-      location,
-      crossThreadBind(&MainThreadTaskRunner::perform, m_weakPtr,
-                      passed(std::move(task)), isInspectorTask, instrumenting));
-}
-
 void MainThreadTaskRunner::postTask(const WebTraceLocation& location,
                                     std::unique_ptr<ExecutionContextTask> task,
                                     const String& taskNameForInstrumentation) {
@@ -62,17 +51,12 @@
     InspectorInstrumentation::asyncTaskScheduled(
         m_context, taskNameForInstrumentation, task.get());
   const bool instrumenting = !taskNameForInstrumentation.isEmpty();
-  postTaskInternal(location, std::move(task), false, instrumenting);
-}
-
-void MainThreadTaskRunner::postInspectorTask(
-    const WebTraceLocation& location,
-    std::unique_ptr<ExecutionContextTask> task) {
-  postTaskInternal(location, std::move(task), true, false);
+  Platform::current()->mainThread()->getWebTaskRunner()->postTask(
+      location, crossThreadBind(&MainThreadTaskRunner::perform, m_weakPtr,
+                                passed(std::move(task)), instrumenting));
 }
 
 void MainThreadTaskRunner::perform(std::unique_ptr<ExecutionContextTask> task,
-                                   bool isInspectorTask,
                                    bool instrumenting) {
   // If the owner m_context is about to be swept then it
   // is no longer safe to access.
@@ -80,7 +64,7 @@
     return;
 
   InspectorInstrumentation::AsyncTask asyncTask(m_context, task.get(),
-                                                !isInspectorTask);
+                                                instrumenting);
   task->performTask(m_context);
 }
 
diff --git a/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.h b/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.h
index 8be7056..5b8a2f6 100644
--- a/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.h
+++ b/third_party/WebKit/Source/core/dom/MainThreadTaskRunner.h
@@ -58,20 +58,12 @@
                 std::unique_ptr<ExecutionContextTask>,
                 const String& taskNameForInstrumentation = emptyString());
 
-  void postInspectorTask(const WebTraceLocation&,
-                         std::unique_ptr<ExecutionContextTask>);
   void perform(std::unique_ptr<ExecutionContextTask>,
-               bool isInspectorTask,
                bool instrumenting);
 
  private:
   explicit MainThreadTaskRunner(ExecutionContext*);
 
-  void postTaskInternal(const WebTraceLocation&,
-                        std::unique_ptr<ExecutionContextTask>,
-                        bool isInspectorTask,
-                        bool instrumenting);
-
   // Untraced back reference to the owner Document;
   // this object has identical lifetime to it.
   UntracedMember<ExecutionContext> m_context;
diff --git a/third_party/WebKit/Source/core/events/PromiseRejectionEvent.cpp b/third_party/WebKit/Source/core/events/PromiseRejectionEvent.cpp
index d923902..7653df1f 100644
--- a/third_party/WebKit/Source/core/events/PromiseRejectionEvent.cpp
+++ b/third_party/WebKit/Source/core/events/PromiseRejectionEvent.cpp
@@ -13,7 +13,7 @@
     const AtomicString& type,
     const PromiseRejectionEventInit& initializer)
     : Event(type, initializer),
-      m_scriptState(state),
+      m_world(state->world()),
       m_promise(this),
       m_reason(this) {
   ThreadState::current()->registerPreFinalizer(this);
@@ -33,28 +33,23 @@
   // (and touch the ScopedPersistents) after Oilpan starts lazy sweeping.
   m_promise.clear();
   m_reason.clear();
-  m_scriptState.clear();
+  m_world.clear();
 }
 
-ScriptPromise PromiseRejectionEvent::promise(ScriptState* state) const {
+ScriptPromise PromiseRejectionEvent::promise(ScriptState* scriptState) const {
   // Return null when the promise is accessed by a different world than the
   // world that created the promise.
-  if (!m_scriptState || !m_scriptState->contextIsValid() ||
-      m_scriptState->world().worldId() != state->world().worldId())
+  if (!canBeDispatchedInWorld(scriptState->world()))
     return ScriptPromise();
-  return ScriptPromise(m_scriptState.get(),
-                       m_promise.newLocal(m_scriptState->isolate()));
+  return ScriptPromise(scriptState, m_promise.newLocal(scriptState->isolate()));
 }
 
-ScriptValue PromiseRejectionEvent::reason(ScriptState* state) const {
+ScriptValue PromiseRejectionEvent::reason(ScriptState* scriptState) const {
   // Return null when the value is accessed by a different world than the world
   // that created the value.
-  if (m_reason.isEmpty() || !m_scriptState ||
-      !m_scriptState->contextIsValid() ||
-      m_scriptState->world().worldId() != state->world().worldId())
-    return ScriptValue(state, v8::Undefined(state->isolate()));
-  return ScriptValue(m_scriptState.get(),
-                     m_reason.newLocal(m_scriptState->isolate()));
+  if (m_reason.isEmpty() || !canBeDispatchedInWorld(scriptState->world()))
+    return ScriptValue(scriptState, v8::Undefined(scriptState->isolate()));
+  return ScriptValue(scriptState, m_reason.newLocal(scriptState->isolate()));
 }
 
 void PromiseRejectionEvent::setWrapperReference(
@@ -76,8 +71,7 @@
 
 bool PromiseRejectionEvent::canBeDispatchedInWorld(
     const DOMWrapperWorld& world) const {
-  return m_scriptState && m_scriptState->contextIsValid() &&
-         m_scriptState->world().worldId() == world.worldId();
+  return m_world && m_world->worldId() == world.worldId();
 }
 
 DEFINE_TRACE(PromiseRejectionEvent) {
diff --git a/third_party/WebKit/Source/core/events/PromiseRejectionEvent.h b/third_party/WebKit/Source/core/events/PromiseRejectionEvent.h
index 48833ee..0ea862c 100644
--- a/third_party/WebKit/Source/core/events/PromiseRejectionEvent.h
+++ b/third_party/WebKit/Source/core/events/PromiseRejectionEvent.h
@@ -50,7 +50,7 @@
   ~PromiseRejectionEvent() override;
   void dispose();
 
-  RefPtr<ScriptState> m_scriptState;
+  RefPtr<DOMWrapperWorld> m_world;
   TraceWrapperV8Reference<v8::Value> m_promise;
   TraceWrapperV8Reference<v8::Value> m_reason;
 };
diff --git a/third_party/WebKit/Source/core/fetch/BUILD.gn b/third_party/WebKit/Source/core/fetch/BUILD.gn
index 44f33a0..87979fa 100644
--- a/third_party/WebKit/Source/core/fetch/BUILD.gn
+++ b/third_party/WebKit/Source/core/fetch/BUILD.gn
@@ -42,8 +42,6 @@
     "ResourceLoaderOptions.h",
     "ResourceLoadingLog.h",
     "SubstituteData.h",
-    "TextResource.cpp",
-    "TextResource.h",
     "UniqueIdentifier.cpp",
     "UniqueIdentifier.h",
   ]
diff --git a/third_party/WebKit/Source/core/fetch/DEPS b/third_party/WebKit/Source/core/fetch/DEPS
index 84251e0f..f2a592e7 100644
--- a/third_party/WebKit/Source/core/fetch/DEPS
+++ b/third_party/WebKit/Source/core/fetch/DEPS
@@ -6,6 +6,5 @@
     # core/fetch/ shouldn't depend on anything else in core/,
     # but has not been fully isolated yet.
     # Do not add to this list.
-    "!core/html/parser/TextResourceDecoder.h",
     "!core/svg/graphics/SVGImage.h",
 ]
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
index 38f3f95d..cb7b2ccc 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
@@ -1272,14 +1272,6 @@
                                     encodedDataLength);
 }
 
-void ResourceFetcher::acceptDataFromThreadedReceiver(unsigned long identifier,
-                                                     const char* data,
-                                                     int dataLength,
-                                                     int encodedDataLength) {
-  context().dispatchDidReceiveData(identifier, data, dataLength,
-                                   encodedDataLength);
-}
-
 void ResourceFetcher::moveResourceLoaderToNonBlocking(ResourceLoader* loader) {
   DCHECK(loader);
   // TODO(yoav): Convert CHECK to DCHECK if no crash reports come in.
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcher.h b/third_party/WebKit/Source/core/fetch/ResourceFetcher.h
index 10991d5..4f67343 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceFetcher.h
+++ b/third_party/WebKit/Source/core/fetch/ResourceFetcher.h
@@ -137,11 +137,6 @@
   bool defersLoading() const;
   bool isControlledByServiceWorker() const;
 
-  void acceptDataFromThreadedReceiver(unsigned long identifier,
-                                      const char* data,
-                                      int dataLength,
-                                      int encodedDataLength);
-
   enum ResourceLoadStartType {
     ResourceLoadingFromNetwork,
     ResourceLoadingFromCache
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPSource.h b/third_party/WebKit/Source/core/frame/csp/CSPSource.h
index b599e78..3a4739cf 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPSource.h
+++ b/third_party/WebKit/Source/core/frame/csp/CSPSource.h
@@ -57,6 +57,7 @@
                            GetIntersectCSPSourcesSchemes);
   FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, GetSourceVector);
   FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, OperativeDirectiveGivenType);
+  FRIEND_TEST_ALL_PREFIXES(SourceListDirectiveTest, SubsumesWithSelf);
 
   bool schemeMatches(const String&) const;
   bool hostMatches(const String&) const;
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
index ad42feb..3336811 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
@@ -341,6 +341,8 @@
 
   bool shouldSendCSPHeader(Resource::Type) const;
 
+  CSPSource* getSelfSource() const { return m_selfSource; }
+
   static bool shouldBypassMainWorld(const ExecutionContext*);
 
   static bool isNonceableElement(const Element*);
diff --git a/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp b/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp
index ef1173e..223967d 100644
--- a/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp
@@ -585,12 +585,17 @@
   if (!m_list.size() || !other.size())
     return !m_list.size();
 
-  HeapVector<Member<CSPSource>> normalizedA = other[0]->m_list;
-  for (size_t i = 1; i < other.size(); i++) {
-    normalizedA = other[i]->getIntersectCSPSources(normalizedA);
-  }
+  HeapVector<Member<CSPSource>> normalizedA = m_list;
+  if (m_allowSelf && other[0]->m_policy->getSelfSource())
+    normalizedA.append(other[0]->m_policy->getSelfSource());
 
-  return CSPSource::firstSubsumesSecond(m_list, normalizedA);
+  HeapVector<Member<CSPSource>> normalizedB = other[0]->m_list;
+  if (other[0]->m_allowSelf && other[0]->m_policy->getSelfSource())
+    normalizedB.append(other[0]->m_policy->getSelfSource());
+  for (size_t i = 1; i < other.size(); i++)
+    normalizedB = other[i]->getIntersectCSPSources(normalizedB);
+
+  return CSPSource::firstSubsumesSecond(normalizedA, normalizedB);
 }
 
 HashMap<String, CSPSource*> SourceListDirective::getIntersectSchemesOnly(
@@ -630,7 +635,10 @@
     }
   }
 
-  for (const auto& sourceA : m_list) {
+  HeapVector<Member<CSPSource>> thisVector = m_list;
+  if (m_allowSelf)
+    thisVector.append(m_policy->getSelfSource());
+  for (const auto& sourceA : thisVector) {
     if (schemesMap.contains(sourceA->getScheme()))
       continue;
 
diff --git a/third_party/WebKit/Source/core/frame/csp/SourceListDirectiveTest.cpp b/third_party/WebKit/Source/core/frame/csp/SourceListDirectiveTest.cpp
index fabecda3..acfecf8 100644
--- a/third_party/WebKit/Source/core/frame/csp/SourceListDirectiveTest.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/SourceListDirectiveTest.cpp
@@ -37,6 +37,16 @@
     csp->bindToExecutionContext(document.get());
   }
 
+  ContentSecurityPolicy* SetUpWithOrigin(const String& origin) {
+    KURL url(ParsedURLString, origin);
+    RefPtr<SecurityOrigin> secureOrigin(SecurityOrigin::create(url));
+    Document* document = Document::create();
+    document->setSecurityOrigin(secureOrigin);
+    ContentSecurityPolicy* csp = ContentSecurityPolicy::create();
+    csp->bindToExecutionContext(document);
+    return csp;
+  }
+
   bool equalSources(const Source& a, const Source& b) {
     return a.scheme == b.scheme && a.host == b.host && a.port == b.port &&
            a.path == b.path && a.hostWildcard == b.hostWildcard &&
@@ -437,4 +447,121 @@
   }
 }
 
+TEST_F(SourceListDirectiveTest, SubsumesWithSelf) {
+  SourceListDirective A("script-src",
+                        "http://example1.com/foo/ http://*.example2.com/bar/ "
+                        "http://*.example3.com:*/bar/ 'self'",
+                        csp.get());
+
+  struct TestCase {
+    std::vector<const char*> sourcesB;
+    const char* originB;
+    bool expected;
+  } cases[] = {
+      // "https://example.test/" is a secure origin for both A and B.
+      {{"'self'"}, "https://example.test/", true},
+      {{"'self' 'self' 'self'"}, "https://example.test/", true},
+      {{"'self'", "'self'", "'self'"}, "https://example.test/", true},
+      {{"'self'", "'self'", "https://*.example.test/"},
+       "https://example.test/",
+       true},
+      {{"'self'", "'self'", "https://*.example.test/bar/"},
+       "https://example.test/",
+       true},
+      {{"'self' https://another.test/bar", "'self' http://*.example.test/bar",
+        "https://*.example.test/bar/"},
+       "https://example.test/",
+       true},
+      {{"http://example1.com/foo/ 'self'"}, "https://example.test/", true},
+      {{"http://example1.com/foo/ https://example.test/"},
+       "https://example.test/",
+       true},
+      {{"http://example1.com/foo/ http://*.example2.com/bar/"},
+       "https://example.test/",
+       true},
+      {{"http://example1.com/foo/ http://*.example2.com/bar/ "
+        "http://*.example3.com:*/bar/ https://example.test/"},
+       "https://example.test/",
+       true},
+      {{"http://example1.com/foo/ http://*.example2.com/bar/ "
+        "http://*.example3.com:*/bar/ 'self'"},
+       "https://example.test/",
+       true},
+      {{"'self'", "'self'", "https://example.test/"},
+       "https://example.test/",
+       true},
+      {{"'self'", "https://example.test/folder/"},
+       "https://example.test/",
+       true},
+      {{"'self'", "http://example.test/folder/"},
+       "https://example.test/",
+       true},
+      {{"'self' https://example.com/", "https://example.com/"},
+       "https://example.test/",
+       false},
+      {{"http://example1.com/foo/ http://*.example2.com/bar/",
+        "http://example1.com/foo/ http://*.example2.com/bar/ 'self'"},
+       "https://example.test/",
+       true},
+      {{"http://*.example1.com/foo/", "http://*.example1.com/foo/ 'self'"},
+       "https://example.test/",
+       false},
+      {{"https://*.example.test/", "https://*.example.test/ 'self'"},
+       "https://example.test/",
+       false},
+      {{"http://example.test/"}, "https://example.test/", false},
+      {{"https://example.test/"}, "https://example.test/", true},
+      // Origins of A and B do not match.
+      {{"https://example.test/"}, "https://other-origin.test/", false},
+      {{"'self'"}, "https://other-origin.test/", true},
+      {{"http://example1.com/foo/ http://*.example2.com/bar/ "
+        "http://*.example3.com:*/bar/ 'self'"},
+       "https://other-origin.test/",
+       true},
+      {{"http://example1.com/foo/ http://*.example2.com/bar/ "
+        "http://*.example3.com:*/bar/ https://other-origin.test/"},
+       "https://other-origin.test/",
+       true},
+      {{"http://example1.com/foo/ 'self'"}, "https://other-origin.test/", true},
+      {{"'self'", "https://example.test/"}, "https://other-origin.test/", true},
+      {{"'self' https://example.test/", "https://example.test/"},
+       "https://other-origin.test/",
+       false},
+      {{"https://example.test/", "http://example.test/"},
+       "https://other-origin.test/",
+       false},
+      {{"'self'", "http://other-origin.test/"},
+       "https://other-origin.test/",
+       true},
+      {{"'self'", "https://non-example.test/"},
+       "https://other-origin.test/",
+       true},
+      // B's origin matches one of sources in the source list of A.
+      {{"'self'", "http://*.example1.com/foo/"}, "http://example1.com/", true},
+      {{"http://*.example2.com/bar/", "'self'"},
+       "http://example2.com/bar/",
+       true},
+      {{"'self' http://*.example1.com/foo/", "http://*.example1.com/foo/"},
+       "http://example1.com/",
+       false},
+      {{"http://*.example2.com/bar/ http://example1.com/",
+        "'self' http://example1.com/"},
+       "http://example2.com/bar/",
+       false},
+  };
+
+  for (const auto& test : cases) {
+    ContentSecurityPolicy* cspB = SetUpWithOrigin(String(test.originB));
+
+    HeapVector<Member<SourceListDirective>> vectorB;
+    for (const auto& sources : test.sourcesB) {
+      SourceListDirective* member =
+          new SourceListDirective("script-src", sources, cspB);
+      vectorB.append(member);
+    }
+
+    EXPECT_EQ(test.expected, A.subsumes(vectorB));
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
index 4eff1b4c..f5cad31 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
@@ -397,6 +397,10 @@
 void HTMLDocumentParser::validateSpeculations(
     std::unique_ptr<TokenizedChunk> chunk) {
   ASSERT(chunk);
+  // TODO(kouhei): We should simplify codepath here by disallowing
+  // validateSpeculations
+  // while isWaitingForScripts, and m_lastChunkBeforeScript can simply be
+  // pushed to m_speculations.
   if (isWaitingForScripts()) {
     // We're waiting on a network script, just save the chunk, we'll get a
     // second validateSpeculations call after the script completes. This call
@@ -1056,14 +1060,18 @@
   ASSERT(!isWaitingForScripts());
 
   if (m_haveBackgroundParser) {
-    validateSpeculations(std::move(m_lastChunkBeforeScript));
-    ASSERT(!m_lastChunkBeforeScript);
-    pumpPendingSpeculations();
+    if (m_lastChunkBeforeScript) {
+      validateSpeculations(std::move(m_lastChunkBeforeScript));
+      DCHECK(!m_lastChunkBeforeScript);
+      pumpPendingSpeculations();
+    }
     return;
   }
 
   m_insertionPreloadScanner.reset();
-  pumpTokenizerIfPossible();
+  if (m_tokenizer) {
+    pumpTokenizerIfPossible();
+  }
   endIfDelayed();
 }
 
@@ -1092,14 +1100,11 @@
 }
 
 void HTMLDocumentParser::executeScriptsWaitingForResources() {
+  DCHECK(document()->isScriptExecutionReady());
+
   // Document only calls this when the Document owns the DocumentParser so this
   // will not be called in the DocumentFragment case.
-  ASSERT(m_scriptRunner);
-  // Ignore calls unless we have a script blocking the parser waiting on a
-  // stylesheet load.  Otherwise we are currently parsing and this is a
-  // re-entrant call from encountering a </ style> tag.
-  if (!m_scriptRunner->hasScriptsWaitingForResources())
-    return;
+  DCHECK(m_scriptRunner);
   m_scriptRunner->executeScriptsWaitingForResources();
   if (!isWaitingForScripts())
     resumeParsingAfterScriptExecution();
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
index 1f130d3c..899dd1d 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
@@ -154,8 +154,7 @@
     : m_reentryPermit(reentryPermit),
       m_document(document),
       m_host(host),
-      m_parserBlockingScript(PendingScript::create(nullptr, nullptr)),
-      m_hasScriptsWaitingForResources(false) {
+      m_parserBlockingScript(PendingScript::create(nullptr, nullptr)) {
   ASSERT(m_host);
   ThreadState::current()->registerPreFinalizer(this);
 }
@@ -181,18 +180,17 @@
   // detached.
 }
 
-bool HTMLScriptRunner::isPendingScriptReady(const PendingScript* script) {
-  m_hasScriptsWaitingForResources = !m_document->isScriptExecutionReady();
-  if (m_hasScriptsWaitingForResources)
+bool HTMLScriptRunner::isPendingScriptReady() {
+  if (!m_document->isScriptExecutionReady())
     return false;
-  return script->isReady();
+  return m_parserBlockingScript->isReady();
 }
 
 void HTMLScriptRunner::executeParsingBlockingScript() {
-  ASSERT(m_document);
-  ASSERT(!isExecutingScript());
-  ASSERT(m_document->isScriptExecutionReady());
-  ASSERT(isPendingScriptReady(m_parserBlockingScript.get()));
+  DCHECK(m_document);
+  DCHECK(!isExecutingScript());
+  DCHECK(m_document->isScriptExecutionReady());
+  DCHECK(isPendingScriptReady());
 
   InsertionPointRecord insertionPointRecord(m_host->inputStream());
   executePendingScriptAndDispatchEvent(m_parserBlockingScript.get(),
@@ -215,10 +213,9 @@
   if (!isExecutingScript()) {
     Microtask::performCheckpoint(V8PerIsolateData::mainThreadIsolate());
     if (pendingScriptType == ScriptStreamer::ParsingBlocking) {
-      m_hasScriptsWaitingForResources = !m_document->isScriptExecutionReady();
       // The parser cannot be unblocked as a microtask requested another
       // resource
-      if (m_hasScriptsWaitingForResources)
+      if (!m_document->isScriptExecutionReady())
         return;
     }
   }
@@ -373,8 +370,7 @@
 }
 
 void HTMLScriptRunner::executeParsingBlockingScripts() {
-  while (hasParserBlockingScript() &&
-         isPendingScriptReady(m_parserBlockingScript.get()))
+  while (hasParserBlockingScript() && isPendingScriptReady())
     executeParsingBlockingScript();
 }
 
@@ -390,9 +386,6 @@
 void HTMLScriptRunner::executeScriptsWaitingForResources() {
   TRACE_EVENT0("blink", "HTMLScriptRunner::executeScriptsWaitingForResources");
   ASSERT(m_document);
-  // Callers should check hasScriptsWaitingForResources() before calling
-  // to prevent parser or script re-entry during </style> parsing.
-  ASSERT(hasScriptsWaitingForResources());
   ASSERT(!isExecutingScript());
   ASSERT(m_document->isScriptExecutionReady());
   executeParsingBlockingScripts();
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.h b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.h
index 2c251c8f..938c9ee 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.h
+++ b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.h
@@ -64,9 +64,6 @@
                const TextPosition& scriptStartPosition);
 
   void executeScriptsWaitingForLoad(Resource*);
-  bool hasScriptsWaitingForResources() const {
-    return m_hasScriptsWaitingForResources;
-  }
   void executeScriptsWaitingForResources();
   bool executeScriptsWaitingForParsing();
 
@@ -95,7 +92,7 @@
 
   void runScript(Element*, const TextPosition& scriptStartPosition);
 
-  bool isPendingScriptReady(const PendingScript*);
+  bool isPendingScriptReady();
 
   void stopWatchingResourceForLoad(Resource*);
 
@@ -107,12 +104,6 @@
   Member<PendingScript> m_parserBlockingScript;
   // http://www.whatwg.org/specs/web-apps/current-work/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing
   HeapDeque<Member<PendingScript>> m_scriptsToExecuteAfterParsing;
-
-  // We only want stylesheet loads to trigger script execution if script
-  // execution is currently stopped due to stylesheet loads, otherwise we'd
-  // cause nested script execution when parsing <style> tags since </style>
-  // tags can cause Document to call executeScriptsWaitingForResources.
-  bool m_hasScriptsWaitingForResources;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLViewSourceParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLViewSourceParser.cpp
index edf1862..024c9cd 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLViewSourceParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLViewSourceParser.cpp
@@ -74,6 +74,7 @@
 }
 
 void HTMLViewSourceParser::finish() {
+  flush();
   if (!m_input.haveSeenEndOfFile())
     m_input.markEndOfFile();
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
index 861a88d..a91810f 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
@@ -447,13 +447,9 @@
       optionalScriptToEvaluateOnLoad.fromMaybe("");
   m_v8Session->setSkipAllPauses(true);
   m_reloading = true;
-  FrameLoadType reloadType = FrameLoadTypeReload;
-  if (optionalBypassCache.fromMaybe(false))
-    reloadType = FrameLoadTypeReloadBypassingCache;
-  else if (RuntimeEnabledFeatures::
-               reloadwithoutSubResourceCacheRevalidationEnabled())
-    reloadType = FrameLoadTypeReloadMainResource;
-  m_inspectedFrames->root()->reload(reloadType,
+  m_inspectedFrames->root()->reload(optionalBypassCache.fromMaybe(false)
+                                        ? FrameLoadTypeReloadBypassingCache
+                                        : FrameLoadTypeReloadMainResource,
                                     ClientRedirectPolicy::NotClientRedirect);
   return Response::OK();
 }
diff --git a/third_party/WebKit/Source/core/loader/BUILD.gn b/third_party/WebKit/Source/core/loader/BUILD.gn
index e388b3b..33c258a 100644
--- a/third_party/WebKit/Source/core/loader/BUILD.gn
+++ b/third_party/WebKit/Source/core/loader/BUILD.gn
@@ -72,6 +72,8 @@
     "resource/ScriptResource.h",
     "resource/StyleSheetResource.h",
     "resource/StyleSheetResourceClient.h",
+    "resource/TextResource.cpp",
+    "resource/TextResource.h",
     "resource/XSLStyleSheetResource.cpp",
     "resource/XSLStyleSheetResource.h",
   ]
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.h b/third_party/WebKit/Source/core/loader/DocumentLoader.h
index 21af6601..fd1ebf4 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.h
@@ -139,9 +139,6 @@
 
   void startLoadingMainResource();
 
-  void acceptDataFromThreadedReceiver(const char* data,
-                                      int dataLength,
-                                      int encodedDataLength);
   DocumentLoadTiming& timing() { return m_documentLoadTiming; }
   const DocumentLoadTiming& timing() const { return m_documentLoadTiming; }
 
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 59426dd81..29d7a9eb 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -121,10 +121,6 @@
 }
 
 static bool needsHistoryItemRestore(FrameLoadType type) {
-  if (!RuntimeEnabledFeatures::
-          reloadwithoutSubResourceCacheRevalidationEnabled() &&
-      type == FrameLoadTypeReloadMainResource)
-    return false;
   // TODO(toyoshim): Shall we return true for FrameLoadTypeInitialHistoryLoad
   // too?
   return type == FrameLoadTypeBackForward || isReloadLoadType(type);
diff --git a/third_party/WebKit/Source/core/loader/resource/DocumentResource.h b/third_party/WebKit/Source/core/loader/resource/DocumentResource.h
index 0340f0b..5019a12 100644
--- a/third_party/WebKit/Source/core/loader/resource/DocumentResource.h
+++ b/third_party/WebKit/Source/core/loader/resource/DocumentResource.h
@@ -25,8 +25,8 @@
 
 #include "core/fetch/Resource.h"
 #include "core/fetch/ResourceClient.h"
-#include "core/fetch/TextResource.h"
 #include "core/html/parser/TextResourceDecoder.h"
+#include "core/loader/resource/TextResource.h"
 #include "platform/heap/Handle.h"
 #include <memory>
 
diff --git a/third_party/WebKit/Source/core/loader/resource/ScriptResource.h b/third_party/WebKit/Source/core/loader/resource/ScriptResource.h
index b0dced7..ebf3d3a6 100644
--- a/third_party/WebKit/Source/core/loader/resource/ScriptResource.h
+++ b/third_party/WebKit/Source/core/loader/resource/ScriptResource.h
@@ -29,7 +29,7 @@
 #include "core/CoreExport.h"
 #include "core/fetch/IntegrityMetadata.h"
 #include "core/fetch/ResourceClient.h"
-#include "core/fetch/TextResource.h"
+#include "core/loader/resource/TextResource.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/loader/resource/StyleSheetResource.h b/third_party/WebKit/Source/core/loader/resource/StyleSheetResource.h
index 4ffa8f226..5953a52 100644
--- a/third_party/WebKit/Source/core/loader/resource/StyleSheetResource.h
+++ b/third_party/WebKit/Source/core/loader/resource/StyleSheetResource.h
@@ -32,7 +32,7 @@
 #define StyleSheetResource_h
 
 #include "core/CoreExport.h"
-#include "core/fetch/TextResource.h"
+#include "core/loader/resource/TextResource.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/fetch/TextResource.cpp b/third_party/WebKit/Source/core/loader/resource/TextResource.cpp
similarity index 96%
rename from third_party/WebKit/Source/core/fetch/TextResource.cpp
rename to third_party/WebKit/Source/core/loader/resource/TextResource.cpp
index bcfbfc8c..f734340 100644
--- a/third_party/WebKit/Source/core/fetch/TextResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/TextResource.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/fetch/TextResource.h"
+#include "core/loader/resource/TextResource.h"
 
 #include "core/html/parser/TextResourceDecoder.h"
 #include "platform/SharedBuffer.h"
diff --git a/third_party/WebKit/Source/core/fetch/TextResource.h b/third_party/WebKit/Source/core/loader/resource/TextResource.h
similarity index 100%
rename from third_party/WebKit/Source/core/fetch/TextResource.h
rename to third_party/WebKit/Source/core/loader/resource/TextResource.h
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl
index 711e5e4..2c4bf04 100644
--- a/third_party/WebKit/Source/core/testing/Internals.idl
+++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -26,7 +26,6 @@
 
 [
     DoNotCheckConstants,
-    ConstructorCallWith=ScriptState,
 ] interface Internals {
     DOMString address(Node node);
 
diff --git a/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp b/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp
index 615bb9a..bc60b0f 100644
--- a/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/InProcessWorkerObjectProxy.cpp
@@ -140,16 +140,15 @@
 
 void InProcessWorkerObjectProxy::postMessageToPageInspector(
     const String& message) {
-  ExecutionContext* context = getExecutionContext();
-  if (context->isDocument()) {
-    // TODO(hiroshige): consider using getParentFrameTaskRunners() here
-    // too.
-    toDocument(context)->postInspectorTask(
-        BLINK_FROM_HERE,
-        createCrossThreadTask(
-            &InProcessWorkerMessagingProxy::postMessageToPageInspector,
-            m_messagingProxyWeakPtr, message));
-  }
+  DCHECK(getExecutionContext()->isDocument());
+  // The TaskType of Inspector tasks need to be Unthrottled because they need to
+  // run even on a suspended page.
+  getParentFrameTaskRunners()
+      ->get(TaskType::Unthrottled)
+      ->postTask(BLINK_FROM_HERE,
+                 crossThreadBind(
+                     &InProcessWorkerMessagingProxy::postMessageToPageInspector,
+                     m_messagingProxyWeakPtr, message));
 }
 
 ParentFrameTaskRunners*
diff --git a/third_party/WebKit/Source/core/workers/ParentFrameTaskRunners.cpp b/third_party/WebKit/Source/core/workers/ParentFrameTaskRunners.cpp
index f6bfe61..f3099795 100644
--- a/third_party/WebKit/Source/core/workers/ParentFrameTaskRunners.cpp
+++ b/third_party/WebKit/Source/core/workers/ParentFrameTaskRunners.cpp
@@ -20,7 +20,7 @@
   // For now we only support very limited task types.
   for (auto type :
        {TaskType::Internal, TaskType::Networking, TaskType::PostedMessage,
-        TaskType::CanvasBlobSerialization}) {
+        TaskType::CanvasBlobSerialization, TaskType::Unthrottled}) {
     m_taskRunners.add(type, TaskRunnerHelper::get(type, frame));
   }
 }
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp
index 33a8c62..37f2e08f 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp
@@ -10,6 +10,7 @@
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/ExecutionContextTask.h"
 #include "core/inspector/ConsoleMessage.h"
+#include "core/workers/ParentFrameTaskRunners.h"
 #include "core/workers/ThreadedWorkletMessagingProxy.h"
 #include "wtf/Functional.h"
 #include "wtf/PtrUtil.h"
@@ -44,14 +45,14 @@
 void ThreadedWorkletObjectProxy::postMessageToPageInspector(
     const String& message) {
   DCHECK(getExecutionContext()->isDocument());
-  // TODO(nhiroki): Replace this with getParentFrameTaskRunners().
-  // (https://crbug.com/667310)
-  toDocument(getExecutionContext())
-      ->postInspectorTask(
-          BLINK_FROM_HERE,
-          createCrossThreadTask(
-              &ThreadedWorkletMessagingProxy::postMessageToPageInspector,
-              m_messagingProxyWeakPtr, message));
+  // The TaskType of Inspector tasks need to be Unthrottled because they need to
+  // run even on a suspended page.
+  getParentFrameTaskRunners()
+      ->get(TaskType::Unthrottled)
+      ->postTask(BLINK_FROM_HERE,
+                 crossThreadBind(
+                     &ThreadedWorkletMessagingProxy::postMessageToPageInspector,
+                     m_messagingProxyWeakPtr, message));
 }
 
 ParentFrameTaskRunners*
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp
index 6e77abc4..9cd65c6 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.cpp
@@ -71,7 +71,6 @@
                        WaitUntilObserver* waitUntilObserver,
                        bool navigationPreloadSent)
     : ExtendableEvent(type, initializer, waitUntilObserver),
-      m_scriptState(scriptState),
       m_observer(respondWithObserver),
       m_preloadResponseProperty(new PreloadResponseProperty(
           scriptState->getExecutionContext(),
@@ -110,17 +109,17 @@
 }
 
 void FetchEvent::onNavigationPreloadResponse(
+    ScriptState* scriptState,
     std::unique_ptr<WebServiceWorkerResponse> response,
     std::unique_ptr<WebDataConsumerHandle> dataConsumeHandle) {
-  if (!m_scriptState->contextIsValid())
+  if (!scriptState->contextIsValid())
     return;
   DCHECK(m_preloadResponseProperty);
-  ScriptState::Scope scope(m_scriptState.get());
-  FetchResponseData* responseData =
-      FetchResponseData::createWithBuffer(new BodyStreamBuffer(
-          m_scriptState.get(), new BytesConsumerForDataConsumerHandle(
-                                   m_scriptState->getExecutionContext(),
-                                   std::move(dataConsumeHandle))));
+  ScriptState::Scope scope(scriptState);
+  FetchResponseData* responseData = FetchResponseData::createWithBuffer(
+      new BodyStreamBuffer(scriptState, new BytesConsumerForDataConsumerHandle(
+                                            scriptState->getExecutionContext(),
+                                            std::move(dataConsumeHandle))));
   responseData->setURL(response->url());
   responseData->setStatus(response->status());
   responseData->setStatusMessage(response->statusText());
@@ -130,12 +129,13 @@
   FetchResponseData* taintedResponse =
       responseData->createBasicFilteredResponse();
   m_preloadResponseProperty->resolve(
-      Response::create(m_scriptState->getExecutionContext(), taintedResponse));
+      Response::create(scriptState->getExecutionContext(), taintedResponse));
 }
 
 void FetchEvent::onNavigationPreloadError(
+    ScriptState* scriptState,
     std::unique_ptr<WebServiceWorkerError> error) {
-  if (!m_scriptState->contextIsValid())
+  if (!scriptState->contextIsValid())
     return;
   DCHECK(m_preloadResponseProperty);
   m_preloadResponseProperty->reject(
diff --git a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h
index e7a5e13..cf6f254 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/FetchEvent.h
@@ -54,9 +54,11 @@
   void respondWith(ScriptState*, ScriptPromise, ExceptionState&);
   ScriptPromise preloadResponse(ScriptState*);
 
-  void onNavigationPreloadResponse(std::unique_ptr<WebServiceWorkerResponse>,
+  void onNavigationPreloadResponse(ScriptState*,
+                                   std::unique_ptr<WebServiceWorkerResponse>,
                                    std::unique_ptr<WebDataConsumerHandle>);
-  void onNavigationPreloadError(std::unique_ptr<WebServiceWorkerError>);
+  void onNavigationPreloadError(ScriptState*,
+                                std::unique_ptr<WebServiceWorkerError>);
 
   const AtomicString& interfaceName() const override;
 
@@ -71,7 +73,6 @@
              bool navigationPreloadSent);
 
  private:
-  RefPtr<ScriptState> m_scriptState;
   Member<RespondWithObserver> m_observer;
   Member<Request> m_request;
   Member<PreloadResponseProperty> m_preloadResponseProperty;
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index 6ec91c97..1716f622 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -193,7 +193,6 @@
 PushMessaging status=stable
 QuotaPromise status=experimental
 ReducedReferrerGranularity
-ReloadwithoutSubResourceCacheRevalidation
 RemotePlayback status=stable
 RenderingPipelineThrottling status=stable
 RenderingPipelineThrottlingLoadingIframes status=stable
@@ -212,7 +211,7 @@
 Sensor status=experimental
 ServiceWorkerNavigationPreload
 SetRootScroller status=experimental
-ShadowPiercingDescendantCombinator status=test
+ShadowPiercingDescendantCombinator status=experimental
 ShapeDetection status=experimental
 SharedArrayBuffer
 SharedWorker status=stable
@@ -272,4 +271,4 @@
 ParseHTMLOnMainThread status=test
 SendBeaconThrowForBlobWithNonSimpleType status=experimental
 PerformanceNavigationTiming2 status=test
-BackgroundVideoTrackOptimization status=stable
\ No newline at end of file
+BackgroundVideoTrackOptimization status=stable
diff --git a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
index 7f6f81b..50364d3 100644
--- a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
+++ b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
@@ -199,8 +199,9 @@
     std::unique_ptr<WebDataConsumerHandle> dataConsumeHandle) {
   FetchEvent* fetchEvent = m_pendingPreloadFetchEvents.take(fetchEventID);
   DCHECK(fetchEvent);
-  fetchEvent->onNavigationPreloadResponse(std::move(response),
-                                          std::move(dataConsumeHandle));
+  fetchEvent->onNavigationPreloadResponse(
+      workerGlobalScope()->scriptController()->getScriptState(),
+      std::move(response), std::move(dataConsumeHandle));
 }
 
 void ServiceWorkerGlobalScopeProxy::onNavigationPreloadError(
@@ -208,7 +209,9 @@
     std::unique_ptr<WebServiceWorkerError> error) {
   FetchEvent* fetchEvent = m_pendingPreloadFetchEvents.take(fetchEventID);
   DCHECK(fetchEvent);
-  fetchEvent->onNavigationPreloadError(std::move(error));
+  fetchEvent->onNavigationPreloadError(
+      workerGlobalScope()->scriptController()->getScriptState(),
+      std::move(error));
 }
 
 void ServiceWorkerGlobalScopeProxy::dispatchForeignFetchEvent(
@@ -353,10 +356,14 @@
 void ServiceWorkerGlobalScopeProxy::postMessageToPageInspector(
     const String& message) {
   DCHECK(m_embeddedWorker);
-  document().postInspectorTask(
-      BLINK_FROM_HERE,
-      createCrossThreadTask(&WebEmbeddedWorkerImpl::postMessageToPageInspector,
-                            crossThreadUnretained(m_embeddedWorker), message));
+  // The TaskType of Inspector tasks need to be Unthrottled because they need to
+  // run even on a suspended page.
+  getParentFrameTaskRunners()
+      ->get(TaskType::Unthrottled)
+      ->postTask(
+          BLINK_FROM_HERE,
+          crossThreadBind(&WebEmbeddedWorkerImpl::postMessageToPageInspector,
+                          crossThreadUnretained(m_embeddedWorker), message));
 }
 
 ParentFrameTaskRunners*
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index e0108fad..7c317d7 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -853,8 +853,7 @@
   // TODO(clamy): Remove this function once RenderFrame calls load for all
   // requests.
   DCHECK(frame());
-  DCHECK(loadType == WebFrameLoadType::Reload ||
-         loadType == WebFrameLoadType::ReloadBypassingCache);
+  DCHECK(isReloadLoadType(static_cast<FrameLoadType>(loadType)));
   WebURLRequest request = requestForReload(loadType, overrideUrl);
   if (request.isNull())
     return;
diff --git a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
index 5e44f8a..5d947a1 100644
--- a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
+++ b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
@@ -282,12 +282,6 @@
   RuntimeEnabledFeatures::setReducedReferrerGranularityEnabled(enable);
 }
 
-void WebRuntimeFeatures::enableReloadwithoutSubResourceCacheRevalidation(
-    bool enable) {
-  RuntimeEnabledFeatures::setReloadwithoutSubResourceCacheRevalidationEnabled(
-      enable);
-}
-
 void WebRuntimeFeatures::enablePushMessaging(bool enable) {
   RuntimeEnabledFeatures::setPushMessagingEnabled(enable);
 }
diff --git a/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp b/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
index 0167d8c..f1984dd 100644
--- a/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
@@ -238,11 +238,15 @@
 }
 
 void WebSharedWorkerImpl::postMessageToPageInspector(const String& message) {
-  m_mainFrame->frame()->document()->postInspectorTask(
-      BLINK_FROM_HERE,
-      createCrossThreadTask(
-          &WebSharedWorkerImpl::postMessageToPageInspectorOnMainThread,
-          crossThreadUnretained(this), message));
+  // The TaskType of Inspector tasks need to be Unthrottled because they need to
+  // run even on a suspended page.
+  getParentFrameTaskRunners()
+      ->get(TaskType::Unthrottled)
+      ->postTask(
+          BLINK_FROM_HERE,
+          crossThreadBind(
+              &WebSharedWorkerImpl::postMessageToPageInspectorOnMainThread,
+              crossThreadUnretained(this), message));
 }
 
 void WebSharedWorkerImpl::postMessageToPageInspectorOnMainThread(
diff --git a/third_party/WebKit/public/web/WebRuntimeFeatures.h b/third_party/WebKit/public/web/WebRuntimeFeatures.h
index 1865a63..fe4b0e0 100644
--- a/third_party/WebKit/public/web/WebRuntimeFeatures.h
+++ b/third_party/WebKit/public/web/WebRuntimeFeatures.h
@@ -105,8 +105,6 @@
   BLINK_EXPORT static void enablePresentationAPI(bool);
   BLINK_EXPORT static void enablePushMessaging(bool);
   BLINK_EXPORT static void enableReducedReferrerGranularity(bool);
-  BLINK_EXPORT static void enableReloadwithoutSubResourceCacheRevalidation(
-      bool);
   BLINK_EXPORT static void enableRenderingPipelineThrottling(bool);
   BLINK_EXPORT static void enableRemotePlaybackAPI(bool);
   BLINK_EXPORT static void enableRootLayerScrolling(bool);
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 5d8f1ea6..589b88cf 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -4148,7 +4148,7 @@
   <summary>Image codec inferred during decode.</summary>
 </histogram>
 
-<histogram name="Blink.Fetch.RequestResourceTime" units="us">
+<histogram name="Blink.Fetch.RequestResourceTime" units="microseconds">
   <owner>csharrison@chromium.org</owner>
   <summary>
     The total microseconds spent in ResourceFetcher::requestResource.
@@ -48379,7 +48379,7 @@
   </summary>
 </histogram>
 
-<histogram name="PreloadScanner.ExternalCSS.ScanTime" units="us">
+<histogram name="PreloadScanner.ExternalCSS.ScanTime" units="microseconds">
   <owner>csharrison@chromium.org</owner>
   <summary>
     Microseconds it took to scan the first chunk of external CSS for preloads.
@@ -63632,18 +63632,36 @@
   </summary>
 </histogram>
 
-<histogram name="Style.AuthorStyleSheet.ParseTime" units="us">
+<histogram name="Style.AuthorStyleSheet.ParseTime" units="microseconds">
   <owner>csharrison@chromium.org</owner>
   <summary>
     Microseconds spent in StyleSheetContents::parseAuthorStyleSheet.
   </summary>
 </histogram>
 
-<histogram name="Style.UpdateTime" units="us">
+<histogram name="Style.UpdateTime" units="microseconds">
   <owner>csharrison@chromium.org</owner>
   <summary>Microseconds spent in Document::updateStyle.</summary>
 </histogram>
 
+<histogram name="SubresourceFilter.DocumentLoad.Activation.CPUDuration"
+    units="microseconds">
+  <owner>pkalinnikov@chromium.org</owner>
+  <summary>
+    Records how much thread CPU time it takes to decide whether subresource
+    filtering should be activated for a main frame or subframe.
+  </summary>
+</histogram>
+
+<histogram name="SubresourceFilter.DocumentLoad.Activation.WallDuration"
+    units="microseconds">
+  <owner>pkalinnikov@chromium.org</owner>
+  <summary>
+    Records how long it takes to decide whether subresource filtering should be
+    activated for a main frame or subframe.
+  </summary>
+</histogram>
+
 <histogram name="SubresourceFilter.DocumentLoad.ActivationState"
     enum="SubresourceFilterActivationState">
   <owner>engedy@chromium.org</owner>
@@ -63707,6 +63725,39 @@
   </summary>
 </histogram>
 
+<histogram
+    name="SubresourceFilter.DocumentLoad.SubresourceEvaluation.TotalCPUDuration"
+    units="microseconds">
+  <owner>pkalinnikov@chromium.org</owner>
+  <summary>
+    Whenever a document load is finished in a main frame or subframe with
+    subresource filtering activated, records the total thread CPU time spent on
+    processing subresource requests in allowLoad.
+  </summary>
+</histogram>
+
+<histogram
+    name="SubresourceFilter.DocumentLoad.SubresourceEvaluation.TotalWallDuration"
+    units="microseconds">
+  <owner>pkalinnikov@chromium.org</owner>
+  <summary>
+    Whenever a document load is finished in a main frame or subframe with
+    subresource filtering activated, records the total real time spent on
+    processing subresource requests in allowLoad, including the time spent on
+    waiting or being descheduled.
+  </summary>
+</histogram>
+
+<histogram name="SubresourceFilter.IndexRuleset.CPUDuration" units="ms">
+  <owner>pkalinnikov@chromium.org</owner>
+  <summary>
+    The total CPU time it took to parse and index all rules. Does not include
+    time when the indexing thread was not doing actual work, e.g. waiting for
+    I/O or being descheduled. Recorded every time the RulesetService kicks off a
+    ruleset indexing process.
+  </summary>
+</histogram>
+
 <histogram name="SubresourceFilter.IndexRuleset.NumUnsupportedRules"
     units="rules">
   <owner>engedy@chromium.org</owner>
@@ -63761,6 +63812,26 @@
   </summary>
 </histogram>
 
+<histogram name="SubresourceFilter.SubresourceLoad.Evaluation.CPUDuration"
+    units="microseconds">
+  <owner>pkalinnikov@chromium.org</owner>
+  <summary>
+    Whenever a subresource of a document is evaluated against the ruleset,
+    records the thread CPU time spent on calculating whether it should be
+    allowed to load.
+  </summary>
+</histogram>
+
+<histogram name="SubresourceFilter.SubresourceLoad.Evaluation.WallDuration"
+    units="microseconds">
+  <owner>pkalinnikov@chromium.org</owner>
+  <summary>
+    Whenever a subresource of a document is evaluated against the ruleset,
+    records how much time was spent on calculating whether it should be allowed
+    to load.
+  </summary>
+</histogram>
+
 <histogram name="SubresourceFilter.WriteRuleset.ReplaceFileError"
     enum="PlatformFileError">
   <owner>engedy@chromium.org</owner>
diff --git a/tools/metrics/histograms/pretty_print.py b/tools/metrics/histograms/pretty_print.py
index 7e07427..d6bb862 100755
--- a/tools/metrics/histograms/pretty_print.py
+++ b/tools/metrics/histograms/pretty_print.py
@@ -32,6 +32,8 @@
 
 
 UNIT_REWRITES = {
+  'microsecond': 'microseconds',
+  'us': 'microseconds',
   'millisecond': 'ms',
   'milliseconds': 'ms',
   'kb': 'KB',
diff --git a/tools/perf/benchmarks/page_cycler_v2.py b/tools/perf/benchmarks/page_cycler_v2.py
index 4e5b4aa..43a10e9 100644
--- a/tools/perf/benchmarks/page_cycler_v2.py
+++ b/tools/perf/benchmarks/page_cycler_v2.py
@@ -167,6 +167,7 @@
           cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM])
 
 
+@benchmark.Enabled('android')
 class PageCyclerV2Top10Mobile(_PageCyclerV2):
   """Page load time benchmark for the top 10 mobile web pages.