diff --git a/DEPS b/DEPS
index 366d55a..b5f52ae 100644
--- a/DEPS
+++ b/DEPS
@@ -90,7 +90,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '2b7bbc2822805fc29d19ba93a365d8e02e84d045',
+  'angle_revision': '06f8637740116fa3bc4c30b513fc3ae4a0534521',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -102,7 +102,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '891aaf63b3490989a189bcc51b18647073f988d4',
+  'pdfium_revision': '05dcbc931eacb72f1a11835ae282fc8434b7a434',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
diff --git a/ash/app_list/model/search/search_box_model.cc b/ash/app_list/model/search/search_box_model.cc
index 3487d599..42ddcb0b 100644
--- a/ash/app_list/model/search/search_box_model.cc
+++ b/ash/app_list/model/search/search_box_model.cc
@@ -20,8 +20,7 @@
 
 SearchBoxModel::SpeechButtonProperty::~SpeechButtonProperty() = default;
 
-SearchBoxModel::SearchBoxModel()
-    : is_voice_query_(false), is_tablet_mode_(false) {}
+SearchBoxModel::SearchBoxModel() : is_tablet_mode_(false) {}
 
 SearchBoxModel::~SearchBoxModel() = default;
 
@@ -74,9 +73,8 @@
 }
 
 void SearchBoxModel::Update(const base::string16& text,
-                            bool is_voice_query,
                             bool initiated_by_user) {
-  if (text_ == text && is_voice_query_ == is_voice_query)
+  if (text_ == text)
     return;
 
   if (initiated_by_user) {
@@ -88,7 +86,6 @@
     }
   }
   text_ = text;
-  is_voice_query_ = is_voice_query;
   for (auto& observer : observers_)
     observer.Update();
 }
diff --git a/ash/app_list/model/search/search_box_model.h b/ash/app_list/model/search/search_box_model.h
index 9d302205..74b50cf4 100644
--- a/ash/app_list/model/search/search_box_model.h
+++ b/ash/app_list/model/search/search_box_model.h
@@ -75,10 +75,8 @@
   // Sets/gets the text for the search box's Textfield and the voice search
   // flag.
   void Update(const base::string16& text,
-              bool is_voice_query,
               bool initiated_by_user);
   const base::string16& text() const { return text_; }
-  bool is_voice_query() const { return is_voice_query_; }
 
   void AddObserver(SearchBoxModelObserver* observer);
   void RemoveObserver(SearchBoxModelObserver* observer);
@@ -91,7 +89,6 @@
   base::string16 accessible_name_;
   gfx::SelectionModel selection_model_;
   base::string16 text_;
-  bool is_voice_query_;
   bool is_tablet_mode_;
 
   base::ObserverList<SearchBoxModelObserver> observers_;
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index d6d046b..b4e8c25 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -232,7 +232,6 @@
   app_list::SpeechUIModel* GetSpeechUI() override { return &speech_ui_; }
 
   void OpenSearchResult(app_list::SearchResult* result,
-                        bool auto_launch,
                         int event_flags) override {
     const ExampleSearchResult* example_result =
         static_cast<const ExampleSearchResult*>(result);
@@ -245,10 +244,6 @@
     NOTIMPLEMENTED();
   }
 
-  base::TimeDelta GetAutoLaunchTimeout() override { return base::TimeDelta(); }
-
-  void AutoLaunchCanceled() override {}
-
   void StartSearch() override {
     base::string16 query;
     base::TrimWhitespace(search_model_->search_box()->text(), base::TRIM_ALL,
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 853c849..b8d515426 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -525,9 +525,6 @@
   "//build/config/compiler:default_optimization",
   "//build/config/compiler:default_stack_frames",
   "//build/config/compiler:default_symbols",
-
-  # TODO(crbug.com/795158): Remove once libwidevinecdmadapter.so is fixed.
-  "//build/config/compiler:default_fatal_linker_warnings",
   "//build/config/compiler:no_exceptions",
   "//build/config/compiler:no_rtti",
   "//build/config/compiler:runtime_library",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 5154ead..a894a39 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -265,6 +265,16 @@
         cflags += [ "-fstack-protector" ]
       }
     }
+
+    # Linker warnings.
+    if (fatal_linker_warnings && !(is_chromeos && current_cpu == "arm") &&
+        !(is_android && use_order_profiling) && !is_mac && !is_ios &&
+        current_os != "aix") {
+      # TODO(jochen): Enable this on chromeos on arm. http://crbug.com/356580
+      # TODO(lizeb,pasko): Fix link errors when linking with order_profiling=1
+      # crbug.com/485542
+      ldflags += [ "-Wl,--fatal-warnings" ]
+    }
   }
 
   # Eliminate build metadata (__DATE__, __TIME__ and __TIMESTAMP__) for
@@ -2040,19 +2050,3 @@
     cflags_objcc = common_flags
   }
 }
-
-# Default linker warnings.
-config("default_fatal_linker_warnings") {
-  ldflags = []
-
-  # Linker warnings.
-  if (!is_win && fatal_linker_warnings &&
-      !(is_chromeos && current_cpu == "arm") &&
-      !(is_android && use_order_profiling) && !is_mac && !is_ios &&
-      current_os != "aix") {
-    # TODO(jochen): Enable this on chromeos on arm. http://crbug.com/356580
-    # TODO(lizeb,pasko): Fix link errors when linking with order_profiling=1
-    # crbug.com/485542
-    ldflags += [ "-Wl,--fatal-warnings" ]
-  }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
index 1cc44bb..37b1479 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -627,10 +627,24 @@
 
     @Override
     public void setWebVrModeEnabled(boolean enabled, boolean showToast) {
-        if (!enabled && !mPendingVSyncPause) mContentVrWindowAndroid.setVSyncPaused(false);
-        // TODO(mthiesse, crbug.com/760970) We shouldn't have to wait for the controls to be hidden
-        // before pausing VSync. Something is going wrong in the controls code and should be fixed.
-        mPendingVSyncPause = enabled;
+        if (enabled) {
+            // Use showToast as a proxy for whether we were in VR before switching to WebVR mode
+            // (and the controls are already hidden). We can't check whether the controls are hidden
+            // directly due to bug mentioned below. This will all be fixed and cleaned up with the
+            // fallback UI path (https://crbug.com/793430).
+            if (showToast) {
+                mContentVrWindowAndroid.setVSyncPaused(true);
+                mPendingVSyncPause = false;
+            } else {
+                // TODO(mthiesse, https://crbug.com/760970) We shouldn't have to wait for the
+                // controls to be hidden before pausing VSync. Something is going wrong in the
+                // controls code and should be fixed.
+                mPendingVSyncPause = true;
+            }
+        } else {
+            mContentVrWindowAndroid.setVSyncPaused(false);
+            mPendingVSyncPause = false;
+        }
 
         nativeSetWebVrMode(mNativeVrShell, enabled, showToast);
     }
diff --git a/chrome/browser/android/voice_search_tab_helper.cc b/chrome/browser/android/voice_search_tab_helper.cc
index 2ee429e..7389c448 100644
--- a/chrome/browser/android/voice_search_tab_helper.cc
+++ b/chrome/browser/android/voice_search_tab_helper.cc
@@ -48,9 +48,8 @@
     // TODO(mlamouri): this is even more wrong because it makes assumptions with
     // regards to the default autoplay policy.
     prefs.autoplay_policy =
-        gesture_required
-            ? content::AutoplayPolicy::kDocumentUserActivationRequired
-            : content::AutoplayPolicy::kNoUserGestureRequired;
+        gesture_required ? content::AutoplayPolicy::kUserGestureRequired
+                         : content::AutoplayPolicy::kNoUserGestureRequired;
     host->UpdateWebkitPreferences(prefs);
   }
 }
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 106a6ea9..ac2d8d5 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -1082,10 +1082,6 @@
 }
 
 IN_PROC_BROWSER_TEST_P(WebViewTest, AudioStateJavascriptAPI) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kAutoplayPolicy,
-      switches::autoplay::kNoUserGestureRequiredPolicy);
-
   ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
   ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/audio_state_api"))
       << message_;
diff --git a/chrome/browser/media/media_engagement_browsertest.cc b/chrome/browser/media/media_engagement_browsertest.cc
index 737a0806..10b26b63 100644
--- a/chrome/browser/media/media_engagement_browsertest.cc
+++ b/chrome/browser/media/media_engagement_browsertest.cc
@@ -95,13 +95,6 @@
     injected_clock_ = false;
   }
 
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitchASCII(
-        switches::kAutoplayPolicy,
-        switches::autoplay::kNoUserGestureRequiredPolicy);
-    InProcessBrowserTest::SetUpCommandLine(command_line);
-  }
-
   void LoadTestPage(const GURL& url) {
     // We can't do this in SetUp as the browser isn't ready yet and we
     // need it before the page navigates.
diff --git a/chrome/browser/metrics/desktop_session_duration/audible_contents_tracker_browsertest.cc b/chrome/browser/metrics/desktop_session_duration/audible_contents_tracker_browsertest.cc
index 37823f0f..1f0854e 100644
--- a/chrome/browser/metrics/desktop_session_duration/audible_contents_tracker_browsertest.cc
+++ b/chrome/browser/metrics/desktop_session_duration/audible_contents_tracker_browsertest.cc
@@ -9,7 +9,6 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/test/browser_test_base.h"
-#include "media/base/media_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -44,13 +43,6 @@
     InProcessBrowserTest::SetUp();
   }
 
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitchASCII(
-        switches::kAutoplayPolicy,
-        switches::autoplay::kNoUserGestureRequiredPolicy);
-    InProcessBrowserTest::SetUpCommandLine(command_line);
-  }
-
   void TearDown() override {
     InProcessBrowserTest::TearDown();
     tracker_.reset();
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 07df9540..a7b9473 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -2574,6 +2574,66 @@
   EXPECT_EQ("error", blacklisted_iframe_load_result);
 }
 
+IN_PROC_BROWSER_TEST_F(PolicyTest, URLBlacklistClientRedirect) {
+  // Checks that a client side redirect to a blacklisted URL is blocked.
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL redirected_url =
+      embedded_test_server()->GetURL("/policy/blacklist-redirect.html");
+  GURL first_url = embedded_test_server()->GetURL("/client-redirect?" +
+                                                  redirected_url.spec());
+
+  ui_test_utils::NavigateToURL(browser(), first_url);
+  content::WaitForLoadStop(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  EXPECT_EQ(base::ASCIIToUTF16("Redirected!"),
+            browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
+
+  base::ListValue blacklist;
+  blacklist.AppendString(redirected_url.spec().c_str());
+  PolicyMap policies;
+  policies.Set(key::kURLBlacklist, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+               POLICY_SOURCE_CLOUD, blacklist.CreateDeepCopy(), nullptr);
+  UpdateProviderPolicy(policies);
+  FlushBlacklistPolicy();
+
+  ui_test_utils::NavigateToURL(browser(), first_url);
+  content::WaitForLoadStop(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  EXPECT_NE(base::ASCIIToUTF16("Redirected!"),
+            browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
+}
+
+IN_PROC_BROWSER_TEST_F(PolicyTest, URLBlacklistServerRedirect) {
+  // Checks that a server side redirect to a blacklisted URL is blocked.
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL redirected_url =
+      embedded_test_server()->GetURL("/policy/blacklist-redirect.html");
+  GURL first_url = embedded_test_server()->GetURL("/server-redirect?" +
+                                                  redirected_url.spec());
+
+  ui_test_utils::NavigateToURL(browser(), first_url);
+  content::WaitForLoadStop(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  EXPECT_EQ(base::ASCIIToUTF16("Redirected!"),
+            browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
+
+  base::ListValue blacklist;
+  blacklist.AppendString(redirected_url.spec().c_str());
+  PolicyMap policies;
+  policies.Set(key::kURLBlacklist, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+               POLICY_SOURCE_CLOUD, blacklist.CreateDeepCopy(), nullptr);
+  UpdateProviderPolicy(policies);
+  FlushBlacklistPolicy();
+
+  ui_test_utils::NavigateToURL(browser(), first_url);
+  content::WaitForLoadStop(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  EXPECT_NE(base::ASCIIToUTF16("Redirected!"),
+            browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
+}
+
 #if defined(OS_MACOSX)
 // http://crbug.com/339240
 #define MAYBE_FileURLBlacklist DISABLED_FileURLBlacklist
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index f0242b8..d5144bb 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -112,7 +112,6 @@
 #include "extensions/common/manifest_handlers/mime_types_handler.h"
 #include "extensions/common/switches.h"
 #include "extensions/test/result_catcher.h"
-#include "media/base/media_switches.h"
 #include "net/base/escape.h"
 #include "net/cert/x509_certificate.h"
 #include "net/dns/mock_host_resolver.h"
@@ -603,14 +602,6 @@
 
   ~PrerenderBrowserTest() override {}
 
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitchASCII(
-        switches::kAutoplayPolicy,
-        switches::autoplay::kNoUserGestureRequiredPolicy);
-
-    test_utils::PrerenderInProcessBrowserTest::SetUpCommandLine(command_line);
-  }
-
   std::unique_ptr<TestPrerender> PrerenderTestURL(
       const std::string& html_file,
       FinalStatus expected_final_status,
diff --git a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
index e13632c9..ce3bfdb 100644
--- a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
+++ b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
@@ -32,7 +32,6 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
-#include "media/base/media_switches.h"
 #include "net/base/filename_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
@@ -606,10 +605,6 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ChromeRenderProcessHostTest::SetUpCommandLine(command_line);
     command_line->AppendSwitch(switches::kProcessPerTab);
-
-    command_line->AppendSwitchASCII(
-        switches::kAutoplayPolicy,
-        switches::autoplay::kNoUserGestureRequiredPolicy);
   }
 
   void SetUpOnMainThread() override {
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 897481bb..54de558 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -2253,8 +2253,8 @@
                      AuthState::DISPLAYED_FORM_WITH_INSECURE_ACTION);
 }
 
-// TODO(crbug.com/795820): Fails in Windows official builds.
-#if defined(OFFICIAL_BUILD) && defined(OS_WIN)
+// TODO(crbug.com/795820): Fails in Windows, Linux and Mac official builds.
+#if defined(OFFICIAL_BUILD)
 #define MAYBE_TestBrokenHTTPSReportingCloseTab \
   DISABLED_TestBrokenHTTPSReportingCloseTab
 #else
diff --git a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
index e9be86f..45fc5b5 100644
--- a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
@@ -146,7 +146,6 @@
   // Ensure a search finds the extension.
   EXPECT_FALSE(observed_result_);
   model->search_box()->Update(base::ASCIIToUTF16("minimal"),
-                              false /* is_voice_query */,
                               true /* initiated_by_user */);
   EXPECT_TRUE(observed_result_);
 
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc
index 0ffc5f6f..f7a119e 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -56,8 +56,6 @@
 
 namespace {
 
-const int kAutoLaunchDefaultTimeoutMilliSec = 50;
-
 // The UMA histogram that logs which state search results are opened from.
 const char kAppListSearchResultOpenSourceHistogram[] =
     "Apps.AppListSearchResultOpenedSource";
@@ -189,7 +187,7 @@
   OnTemplateURLServiceChanged();
 
   // Clear search query.
-  search_model_->search_box()->Update(base::string16(), false,
+  search_model_->search_box()->Update(base::string16(),
                                       false /* initiated_by_user */);
 }
 
@@ -250,11 +248,7 @@
 }
 
 void AppListViewDelegate::OpenSearchResult(app_list::SearchResult* result,
-                                           bool auto_launch,
                                            int event_flags) {
-  if (auto_launch)
-    base::RecordAction(base::UserMetricsAction("AppList_AutoLaunched"));
-
   // Record the search metric if the SearchResult is not a suggested app.
   if (result->display_type() != app_list::SearchResult::DISPLAY_RECOMMENDATION)
     RecordHistogram(model_updater_->TabletMode(),
@@ -270,17 +264,6 @@
   search_controller_->InvokeResultAction(result, action_index, event_flags);
 }
 
-base::TimeDelta AppListViewDelegate::GetAutoLaunchTimeout() {
-  return auto_launch_timeout_;
-}
-
-void AppListViewDelegate::AutoLaunchCanceled() {
-  if (search_model_ && search_model_->search_box()->is_voice_query()) {
-    base::RecordAction(base::UserMetricsAction("AppList_AutoLaunchCanceled"));
-  }
-  auto_launch_timeout_ = base::TimeDelta();
-}
-
 void AppListViewDelegate::ViewInitialized() {
   app_list::StartPageService* service =
       app_list::StartPageService::Get(profile_);
@@ -333,17 +316,6 @@
   }
 }
 
-void AppListViewDelegate::OnSpeechResult(const base::string16& result,
-                                         bool is_final) {
-  speech_ui_->SetSpeechResult(result, is_final);
-  if (is_final) {
-    auto_launch_timeout_ =
-        base::TimeDelta::FromMilliseconds(kAutoLaunchDefaultTimeoutMilliSec);
-    search_model_->search_box()->Update(result, true,
-                                        true /* initiated_by_user */);
-  }
-}
-
 void AppListViewDelegate::OnSpeechSoundLevelChanged(int16_t level) {
   speech_ui_->UpdateSoundLevel(level);
 }
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.h b/chrome/browser/ui/app_list/app_list_view_delegate.h
index 5224d67..d577e2b2 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.h
@@ -71,13 +71,10 @@
   app_list::SpeechUIModel* GetSpeechUI() override;
   void StartSearch() override;
   void OpenSearchResult(app_list::SearchResult* result,
-                        bool auto_launch,
                         int event_flags) override;
   void InvokeSearchResultAction(app_list::SearchResult* result,
                                 int action_index,
                                 int event_flags) override;
-  base::TimeDelta GetAutoLaunchTimeout() override;
-  void AutoLaunchCanceled() override;
   void ViewInitialized() override;
   void Dismiss() override;
   void ViewClosing() override;
@@ -100,7 +97,6 @@
   void SetUpSearchUI();
 
   // Overridden from app_list::StartPageObserver:
-  void OnSpeechResult(const base::string16& result, bool is_final) override;
   void OnSpeechSoundLevelChanged(int16_t level) override;
   void OnSpeechRecognitionStateChanged(
       app_list::SpeechRecognitionState new_state) override;
@@ -134,8 +130,6 @@
   std::unique_ptr<app_list::SearchResourceManager> search_resource_manager_;
   std::unique_ptr<app_list::SearchController> search_controller_;
 
-  base::TimeDelta auto_launch_timeout_;
-
   std::unique_ptr<AppSyncUIStateWatcher> app_sync_ui_state_watcher_;
 
   ScopedObserver<TemplateURLService, AppListViewDelegate>
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc
index 4e0d93d..ad12826d 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc
@@ -78,14 +78,12 @@
 AnswerCardSearchProvider::~AnswerCardSearchProvider() {
 }
 
-void AnswerCardSearchProvider::Start(bool is_voice_query,
-                                     const base::string16& query) {
+void AnswerCardSearchProvider::Start(const base::string16& query) {
   // Reset the state.
   current_request_url_ = GURL();
   server_request_start_time_ = answer_loaded_time_ = base::TimeTicks();
 
-  if (query.empty() || is_voice_query ||
-      !model_updater_->SearchEngineIsGoogle()) {
+  if (query.empty() || !model_updater_->SearchEngineIsGoogle()) {
     DeleteCurrentResult();
     return;
   }
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h
index a0b7735..efd325c 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h
@@ -33,7 +33,7 @@
   ~AnswerCardSearchProvider() override;
 
   // SearchProvider overrides:
-  void Start(bool is_voice_query, const base::string16& query) override;
+  void Start(const base::string16& query) override;
 
   // AnswerCardContents::Delegate overrides:
   void UpdatePreferredSize(const AnswerCardContents* source) override;
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc
index 946c336e..d0f686e6 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc
@@ -88,7 +88,7 @@
     MockAnswerCardContents* const contents =
         contents_number == 0 ? contents0_ : contents1_;
     EXPECT_CALL(*contents, LoadURL(GetSearchUrl(kCatQuery)));
-    provider()->Start(false, base::UTF8ToUTF16(kCatQuery));
+    provider()->Start(base::UTF8ToUTF16(kCatQuery));
 
     provider()->DidFinishNavigation(contents, GetSearchUrl(kCatQuery),
                                     has_error, has_answer_card, title,
@@ -185,7 +185,7 @@
 // Basic event sequence.
 TEST_F(AnswerCardSearchProviderTest, Basic) {
   EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kCatQuery));
+  provider()->Start(base::UTF8ToUTF16(kCatQuery));
   provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
                                   true, kCatCardTitle, kCatQuery);
   provider()->DidStopLoading(contents1());
@@ -194,28 +194,22 @@
 
   // Now an empty query.
   EXPECT_CALL(*contents0(), LoadURL(_)).Times(0);
-  provider()->Start(false, base::UTF8ToUTF16(""));
+  provider()->Start(base::UTF8ToUTF16(""));
   EXPECT_EQ(0UL, results().size());
 }
 
-// Voice queries are ignored.
-TEST_F(AnswerCardSearchProviderTest, VoiceQuery) {
-  EXPECT_CALL(*contents1(), LoadURL(_)).Times(0);
-  provider()->Start(true, base::UTF8ToUTF16(kCatQuery));
-}
-
 // Queries to non-Google search engines are ignored.
 TEST_F(AnswerCardSearchProviderTest, NotGoogle) {
   GetModelUpdater()->SetSearchEngineIsGoogle(false);
   EXPECT_CALL(*contents1(), LoadURL(_)).Times(0);
-  provider()->Start(false, base::UTF8ToUTF16(kCatQuery));
+  provider()->Start(base::UTF8ToUTF16(kCatQuery));
 }
 
 // Three queries in a row.
 TEST_F(AnswerCardSearchProviderTest, ThreeQueries) {
   // 1. Fetch for cat.
   EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kCatQuery));
+  provider()->Start(base::UTF8ToUTF16(kCatQuery));
   provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
                                   true, kCatCardTitle, kCatQuery);
   provider()->DidStopLoading(contents1());
@@ -225,7 +219,7 @@
   // 2. Fetch for dog.
   // Starting another (dog) search doesn't dismiss the cat card.
   EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kDogQuery));
+  provider()->Start(base::UTF8ToUTF16(kDogQuery));
 
   VerifyResult("Cat Result 2", kCatCardId, view1(), kCatCardTitle);
 
@@ -243,7 +237,7 @@
   // 3. Fetch for shark.
   // The third query will use contents1/view1 again.
   EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kSharkQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kSharkQuery));
+  provider()->Start(base::UTF8ToUTF16(kSharkQuery));
 
   VerifyResult("Dog Result 2", kDogCardId, view0(), kDogCardTitle);
 
@@ -261,7 +255,7 @@
 TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondErrors) {
   // 1. Fetch for cat.
   EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kCatQuery));
+  provider()->Start(base::UTF8ToUTF16(kCatQuery));
   provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
                                   true, kCatCardTitle, kCatQuery);
   provider()->DidStopLoading(contents1());
@@ -270,7 +264,7 @@
 
   // 2. Fetch for dog. This will fail with an error.
   EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kDogQuery));
+  provider()->Start(base::UTF8ToUTF16(kDogQuery));
 
   VerifyResult("Cat Result 2", kCatCardId, view1(), kCatCardTitle);
 
@@ -285,7 +279,7 @@
 
   // 3. Fetch for shark.
   EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kSharkQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kSharkQuery));
+  provider()->Start(base::UTF8ToUTF16(kSharkQuery));
 
   EXPECT_EQ(0UL, results().size());
 
@@ -304,7 +298,7 @@
 TEST_F(AnswerCardSearchProviderTest, ThreeQueriesSecondNoCard) {
   // 1. Fetch for cat.
   EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kCatQuery));
+  provider()->Start(base::UTF8ToUTF16(kCatQuery));
   provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
                                   true, kCatCardTitle, kCatQuery);
   provider()->DidStopLoading(contents1());
@@ -313,7 +307,7 @@
 
   // 2. Fetch for dog. This will fail with an error.
   EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kDogQuery));
+  provider()->Start(base::UTF8ToUTF16(kDogQuery));
 
   VerifyResult("Cat Result 2", kCatCardId, view1(), kCatCardTitle);
 
@@ -328,7 +322,7 @@
 
   // 3. Fetch for shark.
   EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kSharkQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kSharkQuery));
+  provider()->Start(base::UTF8ToUTF16(kSharkQuery));
 
   EXPECT_EQ(0UL, results().size());
 
@@ -347,15 +341,15 @@
 // query should produce a result.
 TEST_F(AnswerCardSearchProviderTest, InterruptedRequest) {
   EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl("c")));
-  provider()->Start(false, base::UTF8ToUTF16("c"));
+  provider()->Start(base::UTF8ToUTF16("c"));
   EXPECT_EQ(0UL, results().size());
 
   EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl("ca")));
-  provider()->Start(false, base::UTF8ToUTF16("ca"));
+  provider()->Start(base::UTF8ToUTF16("ca"));
   EXPECT_EQ(0UL, results().size());
 
   EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kCatQuery));
+  provider()->Start(base::UTF8ToUTF16(kCatQuery));
   EXPECT_EQ(0UL, results().size());
 
   provider()->DidFinishNavigation(contents1(), GetSearchUrl("c"), false, true,
@@ -379,7 +373,7 @@
 // result will stay until we get an uninterrupted answer.
 TEST_F(AnswerCardSearchProviderTest, InterruptedRequestAfterResult) {
   EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl(kCatQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kCatQuery));
+  provider()->Start(base::UTF8ToUTF16(kCatQuery));
   provider()->DidFinishNavigation(contents1(), GetSearchUrl(kCatQuery), false,
                                   true, kCatCardTitle, kCatQuery);
   provider()->DidStopLoading(contents1());
@@ -387,17 +381,17 @@
   VerifyResult("Cat Result 1", kCatCardId, view1(), kCatCardTitle);
 
   EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl("d")));
-  provider()->Start(false, base::UTF8ToUTF16("d"));
+  provider()->Start(base::UTF8ToUTF16("d"));
 
   VerifyResult("Cat Result 2", kCatCardId, view1(), kCatCardTitle);
 
   EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl("do")));
-  provider()->Start(false, base::UTF8ToUTF16("do"));
+  provider()->Start(base::UTF8ToUTF16("do"));
 
   VerifyResult("Cat Result 3", kCatCardId, view1(), kCatCardTitle);
 
   EXPECT_CALL(*contents0(), LoadURL(GetSearchUrl(kDogQuery)));
-  provider()->Start(false, base::UTF8ToUTF16(kDogQuery));
+  provider()->Start(base::UTF8ToUTF16(kDogQuery));
 
   VerifyResult("Cat Result 4", kCatCardId, view1(), kCatCardTitle);
 
@@ -430,7 +424,7 @@
 // Escaping a query with a special character.
 TEST_F(AnswerCardSearchProviderTest, QueryEscaping) {
   EXPECT_CALL(*contents1(), LoadURL(GetSearchUrl("cat%26dog")));
-  provider()->Start(false, base::UTF8ToUTF16("cat&dog"));
+  provider()->Start(base::UTF8ToUTF16("cat&dog"));
 }
 
 }  // namespace test
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc
index 53c8ead..eb24f71 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -314,8 +314,7 @@
 
 AppSearchProvider::~AppSearchProvider() {}
 
-void AppSearchProvider::Start(bool /*is_voice_query*/,
-                              const base::string16& query) {
+void AppSearchProvider::Start(const base::string16& query) {
   query_ = query;
   const bool show_recommendations = query.empty();
   // Refresh list of apps to ensure we have the latest launch time information.
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.h b/chrome/browser/ui/app_list/search/app_search_provider.h
index 5a3364d..002eeac 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.h
+++ b/chrome/browser/ui/app_list/search/app_search_provider.h
@@ -36,7 +36,7 @@
   ~AppSearchProvider() override;
 
   // SearchProvider overrides:
-  void Start(bool is_voice_query, const base::string16& query) override;
+  void Start(const base::string16& query) override;
 
   // Refresh indexed app data and update search results. When |force_inline| is
   // set to true, search results is updated before returning from the function.
diff --git a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
index dbac8db..2996f8c0 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
@@ -76,7 +76,7 @@
   }
 
   std::string RunQuery(const std::string& query) {
-    app_search_->Start(false, base::UTF8ToUTF16(query));
+    app_search_->Start(base::UTF8ToUTF16(query));
 
     // Sort results by relevance.
     std::vector<SearchResult*> sorted_results;
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc
index 7c5e7f5..93dce1b 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.cc
@@ -93,9 +93,7 @@
 
 ArcPlayStoreSearchProvider::~ArcPlayStoreSearchProvider() = default;
 
-void ArcPlayStoreSearchProvider::Start(bool is_voice_query,
-                                       const base::string16& query) {
-  DCHECK(!is_voice_query);
+void ArcPlayStoreSearchProvider::Start(const base::string16& query) {
   arc::mojom::AppInstance* app_instance =
       arc::ArcServiceManager::Get()
           ? ARC_GET_INSTANCE_FOR_METHOD(
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h
index 4ba0cfe..1eade87 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h
+++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider.h
@@ -28,7 +28,7 @@
   ~ArcPlayStoreSearchProvider() override;
 
   // SearchProvider:
-  void Start(bool is_voice_query, const base::string16& query) override;
+  void Start(const base::string16& query) override;
 
  private:
   void OnResults(base::TimeTicks query_start_time,
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc
index 933ced6..37f98857 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc
@@ -79,7 +79,7 @@
   AddExtension(CreateExtension(extension_misc::kGmailAppId).get());
 
   // Check that the result size of a query doesn't exceed the |kMaxResults|.
-  provider->Start(false, base::UTF8ToUTF16(kQuery));
+  provider->Start(base::UTF8ToUTF16(kQuery));
   const app_list::SearchProvider::Results& results = provider->results();
   ASSERT_GT(results.size(), 0u);
   // Play Store returns |kMaxResults| results, but the first one (GMail) already
diff --git a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc
index ab738074..9c517fe 100644
--- a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc
@@ -28,8 +28,7 @@
 LauncherSearchProvider::~LauncherSearchProvider() {
 }
 
-void LauncherSearchProvider::Start(bool /*is_voice_query*/,
-                                   const base::string16& query) {
+void LauncherSearchProvider::Start(const base::string16& query) {
   query_timer_.Stop();
 
   // Clear all search results of the previous query. Since results are
diff --git a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h
index e5bc070..098ccd6 100644
--- a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h
+++ b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h
@@ -27,7 +27,7 @@
   explicit LauncherSearchProvider(Profile* profile);
   ~LauncherSearchProvider() override;
 
-  void Start(bool is_voice_query, const base::string16& query) override;
+  void Start(const base::string16& query) override;
   void SetSearchResults(
       const extensions::ExtensionId& extension_id,
       std::vector<std::unique_ptr<LauncherSearchResult>> extension_results);
diff --git a/chrome/browser/ui/app_list/search/omnibox_provider.cc b/chrome/browser/ui/app_list/search/omnibox_provider.cc
index 6371754..e4a079d 100644
--- a/chrome/browser/ui/app_list/search/omnibox_provider.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_provider.cc
@@ -28,14 +28,12 @@
           base::WrapUnique(new ChromeAutocompleteProviderClient(profile)),
           this,
           AutocompleteClassifier::DefaultOmniboxProviders() &
-              ~AutocompleteProvider::TYPE_ZERO_SUGGEST)),
-      is_voice_query_(false) {}
+              ~AutocompleteProvider::TYPE_ZERO_SUGGEST)) {}
 
 OmniboxProvider::~OmniboxProvider() {}
 
-void OmniboxProvider::Start(bool is_voice_query, const base::string16& query) {
+void OmniboxProvider::Start(const base::string16& query) {
   controller_->Stop(false);
-  is_voice_query_ = is_voice_query;
   AutocompleteInput input =
       AutocompleteInput(query, metrics::OmniboxEventProto::INVALID_SPEC,
                         ChromeAutocompleteSchemeClassifier(profile_));
@@ -50,7 +48,7 @@
       continue;
 
     new_results.emplace_back(base::MakeUnique<OmniboxResult>(
-        profile_, list_controller_, controller_.get(), is_voice_query_, match));
+        profile_, list_controller_, controller_.get(), match));
   }
   SwapResults(&new_results);
 }
diff --git a/chrome/browser/ui/app_list/search/omnibox_provider.h b/chrome/browser/ui/app_list/search/omnibox_provider.h
index 6f71d89..1ef6f34 100644
--- a/chrome/browser/ui/app_list/search/omnibox_provider.h
+++ b/chrome/browser/ui/app_list/search/omnibox_provider.h
@@ -27,7 +27,7 @@
   ~OmniboxProvider() override;
 
   // SearchProvider overrides:
-  void Start(bool is_voice_query, const base::string16& query) override;
+  void Start(const base::string16& query) override;
 
  private:
   // Populates result list from AutocompleteResult.
@@ -43,9 +43,6 @@
   // eliminates the results as they come in.
   std::unique_ptr<AutocompleteController> controller_;
 
-  // Whether the current query is a voice query.
-  bool is_voice_query_;
-
   DISALLOW_COPY_AND_ASSIGN(OmniboxProvider);
 };
 
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc
index 7bcc8be3..2090230 100644
--- a/chrome/browser/ui/app_list/search/omnibox_result.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -73,39 +73,6 @@
   }
 }
 
-// Returns true if |url| is on a Google Search domain. May return false
-// positives.
-bool IsUrlGoogleSearch(const GURL& url) {
-  // Just return true if the second or third level domain is "google". This may
-  // result in false positives (e.g. "google.example.com"), but since we are
-  // only using this to decide when to add the spoken feedback query parameter,
-  // this doesn't have any bad consequences.
-  const char kGoogleDomainLabel[] = "google";
-
-  std::vector<std::string> pieces = base::SplitString(
-      url.host(), ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-
-  size_t num_pieces = pieces.size();
-
-  if (num_pieces >= 2 && pieces[num_pieces - 2] == kGoogleDomainLabel)
-    return true;
-
-  if (num_pieces >= 3 && pieces[num_pieces - 3] == kGoogleDomainLabel)
-    return true;
-
-  return false;
-}
-
-// Converts a Google Search URL into a spoken feedback URL, by adding query
-// parameters. |search_url| must be a Google Search URL.
-GURL MakeGoogleSearchSpokenFeedbackUrl(const GURL& search_url) {
-  std::string query = search_url.query();
-  query += "&gs_ivs=1";
-  GURL::Replacements replacements;
-  replacements.SetQueryStr(query);
-  return search_url.ReplaceComponents(replacements);
-}
-
 // AutocompleteMatchType::Type to vector icon, used for app list.
 const gfx::VectorIcon& TypeToVectorIcon(AutocompleteMatchType::Type type) {
   switch (type) {
@@ -154,12 +121,10 @@
 OmniboxResult::OmniboxResult(Profile* profile,
                              AppListControllerDelegate* list_controller,
                              AutocompleteController* autocomplete_controller,
-                             bool is_voice_query,
                              const AutocompleteMatch& match)
     : profile_(profile),
       list_controller_(list_controller),
       autocomplete_controller_(autocomplete_controller),
-      is_voice_query_(is_voice_query),
       match_(match) {
   if (match_.search_terms_args && autocomplete_controller_) {
     match_.search_terms_args->from_app_list = true;
@@ -197,18 +162,13 @@
 
 void OmniboxResult::Open(int event_flags) {
   RecordHistogram(OMNIBOX_SEARCH_RESULT);
-  GURL url = match_.destination_url;
-  if (is_voice_query_ && IsUrlGoogleSearch(url)) {
-    url = MakeGoogleSearchSpokenFeedbackUrl(url);
-  }
-  list_controller_->OpenURL(profile_, url, match_.transition,
+  list_controller_->OpenURL(profile_, match_.destination_url, match_.transition,
                             ui::DispositionFromEventFlags(event_flags));
 }
 
 std::unique_ptr<SearchResult> OmniboxResult::Duplicate() const {
-  return std::unique_ptr<SearchResult>(
-      new OmniboxResult(profile_, list_controller_, autocomplete_controller_,
-                        is_voice_query_, match_));
+  return std::unique_ptr<SearchResult>(new OmniboxResult(
+      profile_, list_controller_, autocomplete_controller_, match_));
 }
 
 void OmniboxResult::UpdateIcon() {
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.h b/chrome/browser/ui/app_list/search/omnibox_result.h
index 11cdbba..f1578fb1 100644
--- a/chrome/browser/ui/app_list/search/omnibox_result.h
+++ b/chrome/browser/ui/app_list/search/omnibox_result.h
@@ -22,7 +22,6 @@
   OmniboxResult(Profile* profile,
                 AppListControllerDelegate* list_controller,
                 AutocompleteController* autocomplete_controller,
-                bool is_voice_query,
                 const AutocompleteMatch& match);
   ~OmniboxResult() override;
 
@@ -43,7 +42,6 @@
   Profile* profile_;
   AppListControllerDelegate* list_controller_;
   AutocompleteController* autocomplete_controller_;
-  bool is_voice_query_;
   AutocompleteMatch match_;
 
   DISALLOW_COPY_AND_ASSIGN(OmniboxResult);
diff --git a/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc b/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc
index 186ffb7c..5c31175 100644
--- a/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc
@@ -28,16 +28,7 @@
 const int kRelevance = 750;
 const double kAppListRelevance = 0.5;
 
-const char kWeatherQuery[] = "weather";
 const char kExampleKeyword[] = "example.com";
-const char kExampleWeatherUrl[] = "http://example.com/weather";
-// Typically, this would be "google", "google.com" or "google.com.<country>",
-// but users can change it to whatever they want, so we assume they have.
-const char kGoogleKeyword[] = "mygoog";
-const char kGoogleDescription[] = "Google Search";
-const char kGoogleWeatherUrl[] = "http://google.com/search?q=weather";
-const char kGoogleInternationalWeatherUrl[] =
-    "http://google.com.au/search?q=weather";
 
 }  // namespace
 
@@ -61,8 +52,7 @@
       const std::string& contents,
       const std::string& description,
       AutocompleteMatchType::Type type,
-      const std::string& keyword,
-      bool is_voice_query) {
+      const std::string& keyword) {
     AutocompleteMatch match;
     match.search_terms_args.reset(
         new TemplateURLRef::SearchTermsArgs(base::UTF8ToUTF16(original_query)));
@@ -74,9 +64,8 @@
     match.type = type;
     match.keyword = base::UTF8ToUTF16(keyword);
 
-    return std::unique_ptr<OmniboxResult>(
-        new OmniboxResult(profile_.get(), app_list_controller_delegate_.get(),
-                          nullptr, is_voice_query, match));
+    return std::unique_ptr<OmniboxResult>(new OmniboxResult(
+        profile_.get(), app_list_controller_delegate_.get(), nullptr, match));
   }
 
   const GURL& GetLastOpenedUrl() const {
@@ -93,7 +82,7 @@
 TEST_F(OmniboxResultTest, Basic) {
   std::unique_ptr<OmniboxResult> result = CreateOmniboxResult(
       kFullQuery, kRelevance, kExampleUrl, kFullQuery, kExampleDescription,
-      AutocompleteMatchType::HISTORY_URL, kExampleKeyword, false);
+      AutocompleteMatchType::HISTORY_URL, kExampleKeyword);
 
   EXPECT_EQ(base::ASCIIToUTF16(kExampleDescription), result->title());
   EXPECT_EQ(base::ASCIIToUTF16(kFullQuery), result->details());
@@ -112,7 +101,7 @@
     std::unique_ptr<OmniboxResult> result = CreateOmniboxResult(
         kPartialQuery, kRelevance, kExampleUrl, kPartialQuery,
         kExampleDescription, AutocompleteMatchType::HISTORY_URL,
-        kExampleKeyword, false);
+        kExampleKeyword);
     EXPECT_FALSE(result->voice_result());
   }
 
@@ -122,7 +111,7 @@
     std::unique_ptr<OmniboxResult> result = CreateOmniboxResult(
         kPartialQuery, kRelevance, kExampleUrl, kPartialQuery,
         kExampleDescription, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
-        kExampleKeyword, false);
+        kExampleKeyword);
     EXPECT_TRUE(result->voice_result());
   }
 
@@ -132,7 +121,7 @@
     std::unique_ptr<OmniboxResult> result = CreateOmniboxResult(
         kPartialQuery, kRelevance, kExampleUrl, kPartialQuery,
         kExampleDescription, AutocompleteMatchType::SEARCH_HISTORY,
-        kExampleKeyword, false);
+        kExampleKeyword);
     EXPECT_TRUE(result->voice_result());
   }
 
@@ -142,56 +131,10 @@
   {
     std::unique_ptr<OmniboxResult> result = CreateOmniboxResult(
         kPartialQuery, kRelevance, kExampleUrl, kFullQuery, kExampleDescription,
-        AutocompleteMatchType::SEARCH_HISTORY, kExampleKeyword, false);
+        AutocompleteMatchType::SEARCH_HISTORY, kExampleKeyword);
     EXPECT_FALSE(result->voice_result());
   }
 }
 
-TEST_F(OmniboxResultTest, VoiceQuery) {
-  // A voice query to a random domain. URL should not change.
-  {
-    std::unique_ptr<OmniboxResult> result = CreateOmniboxResult(
-        kWeatherQuery, kRelevance, kExampleWeatherUrl, kWeatherQuery,
-        kExampleDescription, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
-        kExampleKeyword, true);
-    result->Open(0);
-    EXPECT_EQ(kExampleWeatherUrl, GetLastOpenedUrl().spec());
-  }
-
-  // A voice query to a Google domain. URL should have magic "speak back" query
-  // parameter appended.
-  {
-    std::unique_ptr<OmniboxResult> result = CreateOmniboxResult(
-        kWeatherQuery, kRelevance, kGoogleWeatherUrl, kWeatherQuery,
-        kGoogleDescription, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
-        kGoogleKeyword, true);
-    result->Open(0);
-    EXPECT_EQ("http://google.com/search?q=weather&gs_ivs=1",
-              GetLastOpenedUrl().spec());
-  }
-
-  // A voice query to a Google international domain. URL should have magic
-  // "speak back" query parameter appended.
-  {
-    std::unique_ptr<OmniboxResult> result = CreateOmniboxResult(
-        kWeatherQuery, kRelevance, kGoogleInternationalWeatherUrl,
-        kWeatherQuery, kGoogleDescription,
-        AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, kGoogleKeyword, true);
-    result->Open(0);
-    EXPECT_EQ("http://google.com.au/search?q=weather&gs_ivs=1",
-              GetLastOpenedUrl().spec());
-  }
-
-  // A non-voice query to a Google domain. URL should not change.
-  {
-    std::unique_ptr<OmniboxResult> result = CreateOmniboxResult(
-        kWeatherQuery, kRelevance, kGoogleWeatherUrl, kWeatherQuery,
-        kGoogleDescription, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
-        kGoogleKeyword, false);
-    result->Open(0);
-    EXPECT_EQ(kGoogleWeatherUrl, GetLastOpenedUrl().spec());
-  }
-}
-
 }  // namespace test
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.cc b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.cc
index 23de575..f96dfe5 100644
--- a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.cc
@@ -36,8 +36,7 @@
 SuggestionsSearchProvider::~SuggestionsSearchProvider() {
 }
 
-void SuggestionsSearchProvider::Start(bool /*is_voice_query*/,
-                                      const base::string16& query) {
+void SuggestionsSearchProvider::Start(const base::string16& query) {
   ClearResults();
 
   // Only return suggestions on an empty query.
diff --git a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.h b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.h
index c5727fa..b6fcb2e2 100644
--- a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.h
+++ b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.h
@@ -30,7 +30,7 @@
   ~SuggestionsSearchProvider() override;
 
   // SearchProvider overrides:
-  void Start(bool is_voice_query, const base::string16& query) override;
+  void Start(const base::string16& query) override;
 
  private:
   // Called when suggestions are available from the SuggestionsService.
diff --git a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc
index a6bc2049..e3e64815 100644
--- a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc
@@ -73,7 +73,7 @@
   }
 
   std::string RunQuery(const std::string& query) {
-    suggestions_search_->Start(false, base::UTF8ToUTF16(query));
+    suggestions_search_->Start(base::UTF8ToUTF16(query));
 
     // Sort results from most to least relevant.
     std::vector<SearchResult*> sorted_results;
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc b/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
index a25a23d1..9cb1e37 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
@@ -65,8 +65,7 @@
 
 WebstoreProvider::~WebstoreProvider() {}
 
-void WebstoreProvider::Start(bool /*is_voice_query*/,
-                             const base::string16& query) {
+void WebstoreProvider::Start(const base::string16& query) {
   if (webstore_search_)
     webstore_search_->Stop();
 
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_provider.h b/chrome/browser/ui/app_list/search/webstore/webstore_provider.h
index 7459f62..978afb946 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_provider.h
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_provider.h
@@ -36,7 +36,7 @@
   ~WebstoreProvider() override;
 
   // SearchProvider overrides:
-  void Start(bool is_voice_query, const base::string16& query) override;
+  void Start(const base::string16& query) override;
 
  private:
   friend class app_list::test::WebstoreProviderTest;
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc b/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc
index cae5956..6d90261 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc
@@ -188,7 +188,7 @@
   void RunQuery(const std::string& query,
                 const std::string& mock_server_response) {
     mock_server_response_ = mock_server_response;
-    webstore_provider_->Start(false, base::UTF8ToUTF16(query));
+    webstore_provider_->Start(base::UTF8ToUTF16(query));
 
     if (webstore_provider_->query_pending_ && !mock_server_response.empty()) {
       DCHECK(!run_loop_);
diff --git a/chrome/browser/ui/app_list/start_page_observer.h b/chrome/browser/ui/app_list/start_page_observer.h
index 585a743..3dc55fc 100644
--- a/chrome/browser/ui/app_list/start_page_observer.h
+++ b/chrome/browser/ui/app_list/start_page_observer.h
@@ -14,9 +14,6 @@
 
 class StartPageObserver {
  public:
-  // Invoked when a search query happens from the start page.
-  virtual void OnSpeechResult(const base::string16& query, bool is_final) = 0;
-
   // Invoked when a sound level of speech recognition is changed.
   virtual void OnSpeechSoundLevelChanged(int16_t level) = 0;
 
diff --git a/chrome/browser/ui/app_list/start_page_service.cc b/chrome/browser/ui/app_list/start_page_service.cc
index 6aecfd39..3aebf385 100644
--- a/chrome/browser/ui/app_list/start_page_service.cc
+++ b/chrome/browser/ui/app_list/start_page_service.cc
@@ -439,8 +439,6 @@
     speech_result_obtained_ = true;
     RecordAction(UserMetricsAction("AppList_SearchedBySpeech"));
   }
-  for (auto& observer : observers_)
-    observer.OnSpeechResult(query, is_final);
 }
 
 void StartPageService::OnSpeechSoundLevelChanged(int16_t level) {
diff --git a/chrome/test/data/policy/blacklist-redirect.html b/chrome/test/data/policy/blacklist-redirect.html
new file mode 100644
index 0000000..277c86d
--- /dev/null
+++ b/chrome/test/data/policy/blacklist-redirect.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>Redirected!</title>
+</head>
+<body>
+<p id="nope">This should not have been loaded.</p>
+</body>
+</html>
diff --git a/components/autofill/core/common/autofill_regex_constants.cc b/components/autofill/core/common/autofill_regex_constants.cc
index 014c096..057578c4 100644
--- a/components/autofill/core/common/autofill_regex_constants.cc
+++ b/components/autofill/core/common/autofill_regex_constants.cc
@@ -146,6 +146,7 @@
     "|카드";                    // ko-KR
 const char kCardCvcRe[] =
     "verification|card.?identification|security.?code|card.?code"
+    "|security.?value"
     "|security.?number|card.?pin|c-v-v"
     "|(cvn|cvv|cvc|csc|cvd|cid|ccv)(field)?"
     "|\\bcid\\b";
diff --git a/components/test/data/autofill/heuristics/input/148_payment_dickblick.com.html b/components/test/data/autofill/heuristics/input/148_payment_dickblick.com.html
new file mode 100644
index 0000000..2e8316d
--- /dev/null
+++ b/components/test/data/autofill/heuristics/input/148_payment_dickblick.com.html
@@ -0,0 +1,1474 @@
+<html lang="en-US" class="k-webkit k-webkit65 "><head id="Head"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><title>Checkout - Billing &amp; Contact Information - BLICK Art Materials</title><meta id="MetaRobots" name="ROBOTS" content="INDEX, FOLLOW"><link href="/DependencyHandler.axd/L1Jlc291cmNlcy9TaGFyZWQvc3R5bGVzaGVldHMvZG5uZGVmYXVsdC83LjAuMC9kZWZhdWx0LmNzczsvRGVza3RvcE1vZHVsZXMvQmxpY2tDaGVja291dC9tb2R1bGUuY3NzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NhcnRTdWJ0b3RhbC9tb2R1bGUuY3NzOy9Qb3J0YWxzL19kZWZhdWx0L3NraW5zL2JsaWNrZWNvbW1l/cmNlL3NraW4uY3NzOy9Qb3J0YWxzLzAvcG9ydGFsLmNzczsvRGVza3RvcE1vZHVsZXMvQmxpY2tDYXJ0L0NvbnRlbnQvdGhlbWVzL0NhcnRTdWJ0b3RhbC5jc3M7L0Rlc2t0b3BNb2R1bGVzL0JsaWNrSW5zdGFudFNlYXJjaC9Db250ZW50L3N0eWxlcy91bmJ4ZFNlYXJjaC5jc3M7L1BvcnRhbHMvX2RlZmF1bHQvU2tp/bnMvQmxpY2tFY29tbWVyY2UvYm9vdHN0cmFwLTMuMy43L2Nzcy9ib290c3RyYXAubWluLmNzczsvUG9ydGFscy9fZGVmYXVsdC9Ta2lucy9CbGlja0Vjb21tZXJjZS9jc3Mvc2Nzcy9iYXNlLmNzczsvUG9ydGFscy9fZGVmYXVsdC9Ta2lucy9CbGlja0Vjb21tZXJjZS9jc3Mvc2xpY2suY3NzOy9Qb3J0YWxzL19kZWZh/dWx0L1NraW5zL0JsaWNrRWNvbW1lcmNlL2Nzcy9zbGljay10aGVtZS5jc3M7L1BvcnRhbHMvX2RlZmF1bHQvU2tpbnMvQmxpY2tFY29tbWVyY2UvY3NzL3NraW4uY3NzOy9Qb3J0YWxzL19kZWZhdWx0L1NraW5zL0JsaWNrRWNvbW1lcmNlL2Nzcy9zcGVjaWFsb2ZmZXIuY3NzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0No/ZWNrb3V0L0NvbnRlbnQvU3R5bGUvQ2hlY2tvdXQuY3NzOy9Qb3J0YWxzL19kZWZhdWx0L1NraW5zL0JsaWNrRWNvbW1lcmNlL2Nzcy9pbmRleGVzLmNzczsvRGVza3RvcE1vZHVsZXMvQmxpY2tDaGVja291dC9Db250ZW50L1N0eWxlL1NpdGUuY3NzOy9Qb3J0YWxzL19kZWZhdWx0L1NraW5zL0JsaWNrRWNvbW1lcmNl/L2Nzcy9jdXN0b21lcnNlcnZpY2UuY3NzOy9Qb3J0YWxzL19kZWZhdWx0L1NraW5zL0JsaWNrRWNvbW1lcmNlL2Nzcy9zb2NpYWxwYWludGluZy5jc3M7L0Rlc2t0b3BNb2R1bGVzL0JsaWNrQ2hlY2tvdXQvQ29udGVudC9TdHlsZS9qcXVlcnktdWktdGhlbWVzL2Jhc2UvanF1ZXJ5LXVpLmNzczs/2555/css" type="text/css" rel="stylesheet"><link href="/DependencyHandler.axd/L0Rlc2t0b3BNb2R1bGVzL0JsaWNrQ2hlY2tvdXQvQ29udGVudC9TdHlsZS90ZWxlcmlrL3RlbGVyaWsuZGVmYXVsdC5taW4uY3NzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NoZWNrb3V0L0NvbnRlbnQvU3R5bGUvdGVsZXJpay90ZWxlcmlrLmNvbW1vbi5taW4uY3NzOw/2555/css" type="text/css" rel="stylesheet"><script type="text/javascript" src="//s.thebrighttag.com/tag?site=qrEjfzB&amp;H=1p2z8zo&amp;referrer=https%3A%2F%2Fwww.dickblick.com%2Fv2%2Fcheckout%3Fstep%3DBillingAndContact&amp;docReferrer=https%3A%2F%2Fwww.dickblick.com%2Fcart%2F&amp;mode=v2&amp;cf=5824064"></script><script type="text/javascript" src="https://bam.nr-data.net/1/5b40ecf0b9?a=29480082&amp;sa=1&amp;v=998.365d633&amp;t=Unnamed%20Transaction&amp;rst=1199&amp;ref=https://www.dickblick.com/v2/checkout&amp;be=803&amp;fe=383&amp;af=err,xhr,stn,ins&amp;perf=%7B%22timing%22:%7B%22of%22:1513977155127,%22n%22:0,%22f%22:4,%22dn%22:4,%22dne%22:4,%22c%22:4,%22ce%22:4,%22rq%22:6,%22rp%22:6,%22rpe%22:65,%22dl%22:67,%22di%22:553,%22ds%22:553,%22de%22:772,%22dc%22:1180,%22l%22:1180,%22le%22:1189%7D,%22navigation%22:%7B%22ty%22:2%7D%7D&amp;jsonp=NREUM.setToken"></script><script src="https://js-agent.newrelic.com/nr-998.min.js"></script><script src="https://connect.facebook.net/signals/config/1615018795465034?v=2.8.6&amp;r=stable" async=""></script><script async="" src="https://connect.facebook.net/en_US/fbevents.js"></script><script type="text/javascript" async="" src="https://ssl.google-analytics.com/ga.js"></script><script src="https://s.yimg.com/wi/ytc.js" async=""></script><script src="//bat.bing.com/bat.js" async=""></script><script type="text/javascript" src="https://www.googleadservices.com/pagead/conversion_async.js"></script><script type="text/javascript" async="" id="_casrc" src="//t.channeladvisor.com/v2/52001053.js"></script><script type="text/javascript" src="https://www.dickblick.com/DesktopModules/BlickResources/Content/scripts/Blick/SignalTagManagement/SignalTagDataDictionaryHelper.js?v=11"></script><script type="text/javascript" src="//s.thebrighttag.com/tag?site=qrEjfzB&amp;docReferrer=https%3A%2F%2Fwww.dickblick.com%2Fcart%2F&amp;H=1p2z8zo"></script><script async="" src="https://s.btstatic.com/tag.js">{'site':'qrEjfzB'}</script><script src="/DependencyHandler.axd/L1Jlc291cmNlcy9saWJyYXJpZXMvalF1ZXJ5LzAxXzA5XzAxL2pxdWVyeS5qczsvUmVzb3VyY2VzL2xpYnJhcmllcy9qUXVlcnktVUkvMDFfMTFfMDMvanF1ZXJ5LXVpLmpzOw/2555/js" type="text/javascript"></script><meta http-equiv="X-UA-Compatible" content="IE=Edge"><link rel="SHORTCUT ICON" href="/Portals/0/favicon.ico?ver=2015-07-31-163843-373" type="image/x-icon"><link href="https://www.dickblick.com/v2/checkout?step=BillingAndContact" rel="canonical"><meta name="viewport" content="width=device-width,initial-scale=1"><script type="text/javascript" async="" src="//d21gpk1vhmjuf5.cloudfront.net/unbxdAnalytics.js"></script><script src="https://googleads.g.doubleclick.net/pagead/viewthroughconversion/1072717809/?random=1513977155940&amp;cv=8&amp;fst=1513977155940&amp;num=1&amp;label=dXs7CL6UPxDxv8H_Aw&amp;guid=ON&amp;eid=659238991&amp;u_h=2160&amp;u_w=3840&amp;u_ah=2160&amp;u_aw=3840&amp;u_cd=24&amp;u_his=5&amp;u_tz=-300&amp;u_java=false&amp;u_nplug=3&amp;u_nmime=4&amp;frm=0&amp;url=https%3A%2F%2Fwww.dickblick.com%2Fv2%2Fcheckout%3Fstep%3DBillingAndContact&amp;ref=https%3A%2F%2Fwww.dickblick.com%2Fcart%2F&amp;tiba=Welcome%20to%20Checkout%20-%20BLICK%20Art%20Materials&amp;async=1&amp;rfmt=3&amp;fmt=4"></script></head>

+<body id="Body">

+

+    <form method="post" action="/v2/checkout?step=BillingAndContact" id="Form" enctype="multipart/form-data" novalidate="novalidate">

+<div class="aspNetHidden">

+<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="">

+<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="">

+<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="mcY2QTXO19++R5r9XI/jPNTHrNZN8VLUMdz+bWK9dcFKedjlJjZ0t2iB12lLW/4dQQoU2Znl7vxqt33mtHEvu+eSEjCkw0iIdVt6L2RSE97LP+9HgxoHV7DwKc9CRg/0CAMSGDIkk7FE/7eEbbRm0Q5T5lvQ7Ra1JYxW/mi0Q9/nasxZAz0KmIgA5xyYQUJU5GkSlxhdT85kDpr7njI0dyC/qiBbs18uhDkFQGBDzDKiIDABz5yw5d+Q6PA//DOT37S+TNeO/AW9D0gkzxks7s+SEvMhF72mw/8tDIpSnBW6wIOUfd9glXPTKHlTT97trfjtdg==">

+</div>

+

+<script type="text/javascript">

+//<![CDATA[

+var theForm = document.forms['Form'];

+if (!theForm) {

+    theForm = document.Form;

+}

+function __doPostBack(eventTarget, eventArgument) {

+    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {

+        theForm.__EVENTTARGET.value = eventTarget;

+        theForm.__EVENTARGUMENT.value = eventArgument;

+        theForm.submit();

+    }

+}

+//]]>

+</script>

+

+

+<script src="/WebResource.axd?d=pynGkmcFUV2E3ljPYkfOKV-ccpAjq__ieFCKn21B-LYIFPCCS5YWwO7Q6v41&amp;t=636160624665894255" type="text/javascript"></script>

+

+

+<script src="/ScriptResource.axd?d=NJmAwtEo3Iqw7ikZdRsqz1fio_bim-8Hh2uDwT6Y-r2VslPipwQsfoXHQkahnjThO-nECFG9R84MSJA3nv_VWuJJfgsbSDTPubBgQOSi3aDKFGjDyU7zbaBy21VqRWA9y-yOHg2&amp;t=2a48f442" type="text/javascript"></script>

+<script src="/ScriptResource.axd?d=dwY9oWetJoLK_DDb11JqDf0gNPnZyKeRbIh4jRlvmxnAkwGv8Tm_jIEaUvzajqI4DkzJg8xV-RAUHKnb9UDwjyo8Pc3dWqOEEm5SWI7M0GJyBy78KFASE7pQNPVuGBGyxILrwatXjIVJ53pu0&amp;t=2a48f442" type="text/javascript"></script>

+<div class="aspNetHidden">

+

+    <input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="CA0B0334">

+    <input type="hidden" name="__VIEWSTATEENCRYPTED" id="__VIEWSTATEENCRYPTED" value="">

+    <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="NETK0cDf5W7PLrOpaxvfb1WaUSdZlSee0OWDd8CS0REbUlA8GfdpKtUl3zX8GeknEK++ENye7zjkzuCFBfmz/uDAYTP88VTGf40xqEyszR2BgToB">

+</div><script src="/DependencyHandler.axd/L2pzL2Rubi5qczsvanMvZG5uLm1vZGFscG9wdXAuanM7L0Rlc2t0b3BNb2R1bGVzL0JsaWNrQ2FydC9Db250ZW50L3NjcmlwdHMvZnJhbWV3b3JrL2tub2Nrb3V0LTMuMC4wLmpzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NoZWNrb3V0L0NvbnRlbnQvU2NyaXB0cy9mcmFtZXdvcmsva25vY2tvdXQtMy4wLjAuanM7L2pz/L2RubmNvcmUuanM7L2pzL2Rubi5zZXJ2aWNlc2ZyYW1ld29yay5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tSZXNvdXJjZXMvQ29udGVudC9zY3JpcHRzL0JsaWNrL2ZyYW1ld29yay9hbXBsaWZ5Lm1pbi5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tSZXNvdXJjZXMvQ29udGVudC9zY3JpcHRzL0JsaWNrL2ZyYW1ld29y/ay9ibGljay5jcmVhdGVuYW1lc3BhY2VzLmpzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NoZWNrb3V0L0NvbnRlbnQvU2NyaXB0cy9rZW5kby9rZW5kby53ZWIubWluLmpzOy9Qb3J0YWxzL19kZWZhdWx0L1NraW5zL0JsaWNrRWNvbW1lcmNlL2Jvb3RzdHJhcC0zLjMuNy9qcy9ib290c3RyYXAubWluLmpzOy9Qb3J0YWxz/L19kZWZhdWx0L1NraW5zL0JsaWNrRWNvbW1lcmNlL2pzL3NsaWNrLm1pbi5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tSZXNvdXJjZXMvQ29udGVudC9zY3JpcHRzL0JsaWNrL2ZyYW1ld29yay9ibGljay5tZXNzYWdlYnVzLmpzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NoZWNrb3V0L0NvbnRlbnQvU2NyaXB0cy9mcmFt/ZXdvcmsvaGFuZGxlYmFycy5qczsvUG9ydGFscy9fZGVmYXVsdC9Ta2lucy9CbGlja0Vjb21tZXJjZS9qcy9zY3JpcHRzLmpzOy9Qb3J0YWxzL19kZWZhdWx0L1NraW5zL0JsaWNrRWNvbW1lcmNlL2pzL2hvbWVwYWdlLmpzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NoZWNrb3V0L0NvbnRlbnQvU2NyaXB0cy9mcmFtZXdv/cmsvcmVxdWlyZS0yLjEuOS5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tSZXNvdXJjZXMvQ29udGVudC9zY3JpcHRzL0JsaWNrLzIwMTUtMTItMDEvanF1ZXJ5LmhvdmVySW50ZW50Lm1pbmlmaWVkLmpzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NoZWNrb3V0L0NvbnRlbnQvU2NyaXB0cy9qcXVlcnktbWlncmF0ZS0xLjIu/MS5taW4uanM7/2555/js" type="text/javascript"></script><script src="/DependencyHandler.axd/L0Rlc2t0b3BNb2R1bGVzL0JsaWNrQ2hlY2tvdXQvQ29udGVudC9TY3JpcHRzL2pxdWVyeS11aS5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tSZXNvdXJjZXMvQ29udGVudC9zY3JpcHRzL0JsaWNrLzIwMTUtMTItMDEvYmxpY2suanM7L0Rlc2t0b3BNb2R1bGVzL0JsaWNrQ2hlY2tvdXQvQ29udGVudC9TY3JpcHRzL2px/dWVyeS52YWxpZGF0ZS5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tSZXNvdXJjZXMvQ29udGVudC9zY3JpcHRzL0JsaWNrLzIwMTUtMTItMDEvanF1ZXJ5LnRvb2xzLm1pbi5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tDaGVja291dC9Db250ZW50L1NjcmlwdHMvanF1ZXJ5Lmhpc3RvcnkuanM7L0Rlc2t0b3BNb2R1bGVz/L0JsaWNrQ2hlY2tvdXQvQ29udGVudC9TY3JpcHRzL2pxdWVyeS52YWxpZGF0ZS51bm9idHJ1c2l2ZS5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tSZXNvdXJjZXMvQ29udGVudC9zY3JpcHRzL0JsaWNrLzIwMTUtMTItMDEvanF1ZXJ5LmNvb2tpZS5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tDaGVja291dC9Db250ZW50/L1NjcmlwdHMvanF1ZXJ5LmV4dGVuc2lvbnMuanM7L0Rlc2t0b3BNb2R1bGVzL0JsaWNrUmVzb3VyY2VzL0NvbnRlbnQvc2NyaXB0cy9CbGljay8yMDE1LTEyLTAxL2pzb24yLmpzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NoZWNrb3V0L0NvbnRlbnQvU2NyaXB0cy9qcXVlcnkuc2hvd0xvYWRpbmcubWluLmpzOy9Qb3J0/YWxzL19kZWZhdWx0L1NraW5zL0JsaWNrRWNvbW1lcmNlL2pzL21vZGVybml6ci1jdXN0b20uanM7L0Rlc2t0b3BNb2R1bGVzL0JsaWNrQ2hlY2tvdXQvQ29udGVudC9TY3JpcHRzL2JsaWNrLmpzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NoZWNrb3V0L0NvbnRlbnQvU2NyaXB0cy9ibGljay51dGlsaXRpZXMuanM7L0Rl/c2t0b3BNb2R1bGVzL0JsaWNrQ2hlY2tvdXQvQ29udGVudC9TY3JpcHRzL2JsaWNrLmdvb2dsZWFuYWx5dGljcy51dGlsaXRpZXMuanM7L0Rlc2t0b3BNb2R1bGVzL0JsaWNrQ2hlY2tvdXQvQ29udGVudC9TY3JpcHRzL2JsaWNrLnBhZ2VzLmpzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NoZWNrb3V0L0NvbnRlbnQvU2Ny/aXB0cy9ibGljay5zZXJ2aWNlcy5wYWdlLmpzOw/2555/js" type="text/javascript"></script><script src="/DependencyHandler.axd/L0Rlc2t0b3BNb2R1bGVzL0JsaWNrQ2FydC9Db250ZW50L3NjcmlwdHMvYXBwLnN0b3JhZ2UuanM7L0Rlc2t0b3BNb2R1bGVzL0JsaWNrQ2hlY2tvdXQvQ29udGVudC9TY3JpcHRzL2JsaWNrLnNlcnZpY2VzLmNoZWNrb3V0LmpzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NoZWNrb3V0L0NvbnRlbnQvU2NyaXB0cy9ibGlj/ay5wYWdlcy5jaGVja291dC5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tDYXJ0L0NvbnRlbnQvc2NyaXB0cy9mcmFtZXdvcmsvYW1wbGlmeS5taW4uanM7L0Rlc2t0b3BNb2R1bGVzL0JsaWNrQ2FydC9Db250ZW50L3NjcmlwdHMvc2VydmljZXMvc2VydmljZS5zaG9wcGluZy5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tD/YXJ0L0NvbnRlbnQvc2NyaXB0cy9hcHAubWVzc2FnZWJ1cy5qczsvRGVza3RvcE1vZHVsZXMvQmxpY2tDYXJ0U3VidG90YWwvQ29udGVudC9zY3JpcHRzL3dpZGdldHMvY2FydHN1YnRvdGFsL21vZGVscy5jYXJ0LnN1YnRvdGFsLmpzOy9EZXNrdG9wTW9kdWxlcy9CbGlja0NhcnRTdWJ0b3RhbC9Db250ZW50L3Njcmlw/dHMvd2lkZ2V0cy9jYXJ0c3VidG90YWwvY29udHJvbGxlci5jYXJ0c3VidG90YWwuanM7/2555/js" type="text/javascript"></script>

+<script type="text/javascript">

+//<![CDATA[

+Sys.WebForms.PageRequestManager._initialize('ScriptManager', 'Form', [], [], [], 90, '');

+//]]>

+</script>

+

+

+

+

+

+<!--Google Analytic Tracking: Start-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/framework/amplify.min.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/framework/blick.createnamespaces.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/framework/blick.messagebus.js)-->

+<!--Google Analytic Tracking: End-->

+

+<!--CDF(Javascript|/Portals/_default/Skins/BlickEcommerce/bootstrap-3.3.7/js/bootstrap.min.js)-->

+<!--CDF(Javascript|/Portals/_default/Skins/BlickEcommerce/js/scripts.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/2015-12-01/jquery.hoverIntent.minified.js)-->

+<!--CDF(Javascript|/Portals/_default/Skins/BlickEcommerce/js/homepage.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/2015-12-01/blick.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/2015-12-01/jquery.tools.min.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/2015-12-01/jquery.cookie.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/2015-12-01/json2.js)-->

+<!--CDF(Javascript|/Portals/_default/Skins/BlickEcommerce/js/modernizr-custom.js)-->

+<!--CDF(Javascript|/Portals/_default/Skins/BlickEcommerce/js/slick.min.js)-->

+

+<!--CDF(Css|/Portals/_default/Skins/BlickEcommerce/bootstrap-3.3.7/css/bootstrap.min.css)-->

+<!--CDF(Css|/Portals/_default/Skins/BlickEcommerce/css/scss/base.css)-->

+<!--CDF(Css|/Portals/_default/Skins/BlickEcommerce/css/slick.css)-->

+<!--CDF(Css|/Portals/_default/Skins/BlickEcommerce/css/slick-theme.css)-->

+<!--CDF(Css|/Portals/_default/Skins/BlickEcommerce/css/skin.css)-->

+<!--CDF(Css|/Portals/_default/Skins/BlickEcommerce/css/specialoffer.css)-->

+<!--CDF(Css|/Portals/_default/Skins/BlickEcommerce/css/indexes.css)-->

+<!--CDF(Css|/Portals/_default/Skins/BlickEcommerce/css/customerservice.css)-->

+<!--CDF(Css|/Portals/_default/Skins/BlickEcommerce/css/socialpainting.css)-->

+

+

+

+<div id="wrapper">

+    <div id="header">

+        <div id="dnn_testEnvironmentBanner" class="col-xs-12 DNNEmptyPane"></div>

+        <div id="dnn_headerTop" class="col-xs-12 DNNEmptyPane"></div>

+        <div id="top">

+            <div id="dnn_topLogo" class="col-xs-3"><div class="DnnModule DnnModule-DNN_HTML DnnModule-2426 DnnVersionableControl"><a name="2426"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr2426_ContentPane"><!-- Start_Module_2426 --><div id="dnn_ctr2426_ModuleContent" class="DNNModuleContent ModDNNHTMLC">

+    <div id="dnn_ctr2426_HtmlModule_lblContent"><div>

+    <a href="/" title="Blick Homepage"><img alt="Blick Logo" id="blickLogo" src="https://cdn.dick-blick.com/images/header/BlickLogo.jpg"></a>

+</div>

+<input type="hidden" id="DNNServerDateTime" value="12/22/2017 11:48 AM"></div>

+

+

+

+

+</div><!-- End_Module_2426 --></div>

+    <div class="clear"></div>

+</div>

+

+</div></div>

+            <div id="dnn_topMiddle" class="col-xs-6"><div class="DnnModule DnnModule-DNN_HTML DnnModule-2427 DnnVersionableControl"><a name="2427"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr2427_ContentPane"><!-- Start_Module_2427 --><div id="dnn_ctr2427_ModuleContent" class="DNNModuleContent ModDNNHTMLC">

+    <div id="dnn_ctr2427_HtmlModule_lblContent"><div id="topHeaderLinks">

+    <div id="findAStore">

+        <a href="https://www.dickblick.com/stores/"><strong>Find A Store</strong></a>

+    </div>

+

+    <div id="welcome">

+        <div class="signIn" data-bind="visible: !isUserLogin()">

+            <p><a href="https://www.dickblick.com/secure/userlogin/"><strong>Sign In</strong></a></p>

+        </div>

+

+        <div class="signOut" data-bind="visible: isUserLogin()" style="display:none;">

+            <p><a class="changeUser" href="https://www.dickblick.com/logout/"><strong>Sign Out</strong></a>&nbsp;<strong>|</strong>&nbsp;<span class="usersName" data-bind="text:'Hello, ' + userFirstName()">Hello, null</span></p>

+        </div>

+    </div>

+</div></div>

+

+

+

+

+</div><!-- End_Module_2427 --></div>

+    <div class="clear"></div>

+</div>

+

+</div></div>

+            <div id="dnn_headerMiddleCart" class="col-xs-3"><div class="DnnModule DnnModule-BlickCartSubtotal DnnModule-2428"><a name="2428"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr2428_ContentPane"><!-- Start_Module_2428 --><div id="dnn_ctr2428_ModuleContent" class="DNNModuleContent ModBlickCartSubtotalC">

+    <!--CDF(Css|/DesktopModules/BlickCart/Content/themes/CartSubtotal.css)-->

+

+<!--CDF(Javascript|/DesktopModules/BlickCart/Content/scripts/framework/knockout-3.0.0.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/framework/amplify.min.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/framework/blick.createnamespaces.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickResources/Content/scripts/Blick/framework/blick.messagebus.js)-->

+

+<!--CDF(Javascript|/DesktopModules/BlickCart/Content/scripts/app.storage.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickCart/Content/scripts/services/service.shopping.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickCartSubtotal/Content/scripts/widgets/cartsubtotal/models.cart.subtotal.js)-->

+<!--CDF(Javascript|/DesktopModules/BlickCartSubtotal/Content/scripts/widgets/cartsubtotal/controller.cartsubtotal.js)-->

+

+

+

+                <div class="cartSubtotalContainer">

+                    <ul>

+                         <li class="cartnav cartHeaderListItem">

+                         <a class="SubtotalCartUrlPath" title="View / Check Out" data-bind="html: cartSubTotalLabel" href="https://www.dickblick.com/cart/">cart:2&nbsp;<small>($36.83)</small></a>

+                        </li>

+                    </ul>

+                </div>

+

+<script type="text/javascript">

+

+    $(document).ready(function () {

+        // adds the Cart Link to the HTML

+        $(".SubtotalCartUrlPath").attr("href", "https://www.dickblick.com/cart/");

+

+        // Initialize the Subtotal component.

+        window.BlickWebCommerceScript.Cart.SubTotalComponent.Controller.Initialize({

+            Settings: {

+                CartSubtotalContainer: ".cartSubtotalContainer",

+                AlternateContainer: "#welcome",

+                GlobalChannelName: "Shopping"

+            }

+        });

+    });

+</script>

+</div><!-- End_Module_2428 --></div>

+    <div class="clear"></div>

+</div>

+

+</div><div class="DnnModule DnnModule-DNN_HTML DnnModule-2429 DnnVersionableControl"><a name="2429"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr2429_ContentPane"><!-- Start_Module_2429 --><div id="dnn_ctr2429_ModuleContent" class="DNNModuleContent ModDNNHTMLC">

+    <div id="dnn_ctr2429_HtmlModule_lblContent"><div id="phone">

+    <p><strong>ORDER BY PHONE 1-800-828-4548</strong>

+    </p>

+</div></div>

+

+

+

+

+</div><!-- End_Module_2429 --></div>

+    <div class="clear"></div>

+</div>

+

+</div></div>

+        </div>

+        <div class="headerMiddle row">

+            <div id="dnn_headerMiddleNav" class="col-xs-12"><div class="DnnModule DnnModule-DNN_HTML DnnModule-2430 DnnVersionableControl"><a name="2430"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr2430_ContentPane"><!-- Start_Module_2430 --><div id="dnn_ctr2430_ModuleContent" class="DNNModuleContent ModDNNHTMLC">

+    <div id="dnn_ctr2430_HtmlModule_lblContent"><ul class="mainNav">

+    <li id="departments" class="dropdown"><a class="dropdown-toggle" title="Departments" data-toggle="dropdown">departments</a>

+        <div class="dropdown-menu">

+            <div class="col-md-6">

+                <ul>

+                    <li class="newProducts"><a href="https://www.dickblick.com/newproducts/" title="New Products"><strong>New Products</strong></a></li>

+                    <li><a href="https://www.dickblick.com/categories/adhesives/" title="Adhesives">Adhesives</a></li>

+                    <li><a href="https://www.dickblick.com/categories/airbrush/" title="Airbrushing">Airbrushing</a></li>

+                    <li><a href="https://www.dickblick.com/categories/conservation/" title="Archival Supplies">Archival Supplies</a></li>

+                    <li><a href="https://www.dickblick.com/books/" title="Books/Media">Books/Media</a></li>

+                    <li><a href="https://www.dickblick.com/categories/brushes/" title="Brushes">Brushes</a></li>

+                    <li><a href="https://www.dickblick.com/categories/canvas/" title="Canvas/Surfaces">Canvas/Surfaces</a></li>

+                    <li><a href="https://www.dickblick.com/categories/ceramics/" title="Ceramics">Ceramics</a></li>

+                    <li><a href="https://www.dickblick.com/categories/cleaningmaterials/" title="Cleaning Materials">Cleaning Materials</a></li>

+                    <li><a href="https://www.dickblick.com/categories/crafts/" title="Crafts">Crafts</a></li>

+                    <li><a href="https://www.dickblick.com/categories/cuttingtools/" title="Cutting Tools">Cutting Tools</a></li>

+                    <li><a href="https://www.dickblick.com/drafting/architecture/" title="Drafting/Architecture">Drafting/Architecture</a></li>

+                    <li><a href="https://www.dickblick.com/categories/drawing/" title="Drawing/Illustration">Drawing/Illustration</a></li>

+                    <li><a href="https://www.dickblick.com/categories/easels/" title="Easels">Easels</a></li>

+                    <li><a href="https://www.dickblick.com/categories/educationalmaterials/" title="Educational Materials">Educational Materials</a></li>

+                    <li><a href="https://www.dickblick.com/categories/framing/" title="Framing">Framing</a></li>

+                    <li><a href="https://www.dickblick.com/categories/furniture/" title="Furniture">Furniture</a></li>

+                </ul>

+            </div>

+            <div class="col-md-6">

+                <ul>

+                    <li><a href="https://www.dickblick.com/categories/mosaics/" title="Mosaics">Mosaics</a></li>

+                    <li><a href="https://www.dickblick.com/categories/outdoorstudio/" title="Outdoor Studio">Outdoor Studio</a></li>

+                    <li><a href="https://www.dickblick.com/categories/painting/" title="Painting">Painting</a></li>

+                    <li><a href="https://www.dickblick.com/categories/papers/" title="Papers/Boards">Papers/Boards</a></li>

+                    <li><a href="https://www.dickblick.com/categories/pastels/" title="Pastels">Pastels</a></li>

+                    <li><a href="https://www.dickblick.com/categories/portfolios/" title="Portfolios">Portfolios</a></li>

+                    <li><a href="https://www.dickblick.com/categories/presentation/" title="Presentation/Display">Presentation/Display</a></li>

+                    <li><a href="https://www.dickblick.com/categories/printmaking/" title="Printmaking">Printmaking</a></li>

+                    <li><a href="https://www.dickblick.com/categories/safety/" title="Safety/Health">Safety/Health</a></li>

+                    <li><a href="https://www.dickblick.com/categories/photoalbums/" title="Scrapbooking">Scrapbooking</a></li>

+                    <li><a href="https://www.dickblick.com/categories/screenprinting/" title="Screen Printing">Screen Printing</a></li>

+                    <li><a href="https://www.dickblick.com/categories/sculpture/" title="Sculpture/Modeling">Sculpture/Modeling</a></li>

+                    <li><a href="https://www.dickblick.com/categories/signmaking/" title="Signmaking">Signmaking</a></li>

+                    <li><a href="https://www.dickblick.com/categories/specialneeds/" title="Special Needs">Special Needs</a></li>

+                    <li><a href="https://www.dickblick.com/categories/storage/" title="Storing/Organizing">Storing/Organizing</a></li>

+                    <li><a href="https://www.dickblick.com/categories/studioenvironment/" title="Studio Environment">Studio Environment</a></li>

+                    <li><a href="https://www.dickblick.com/categories/transport/" title="Transporting/Carrying">Transporting/Carrying</a></li>

+                    <li class="clearance"><a href="https://www.dickblick.com/clearance/" title="Clearance"><strong>Clearance</strong></a></li>

+                </ul>

+            </div>

+            <div id="departmentsLink"><a href="https://www.dickblick.com/categories/">all departments...</a></div>

+        </div>

+    </li>

+    <li id="alphabet">

+        <ul>

+            <li><a href="https://www.dickblick.com/index/a/">a</a></li>

+            <li><a href="https://www.dickblick.com/index/b/">b</a></li>

+            <li><a href="https://www.dickblick.com/index/c/">c</a></li>

+            <li><a href="https://www.dickblick.com/index/d/">d</a></li>

+            <li><a href="https://www.dickblick.com/index/e/">e</a></li>

+            <li><a href="https://www.dickblick.com/index/f/">f</a></li>

+            <li><a href="https://www.dickblick.com/index/g/">g</a></li>

+            <li><a href="https://www.dickblick.com/index/h/">h</a></li>

+            <li><a href="https://www.dickblick.com/index/i/">i</a></li>

+            <li><a href="https://www.dickblick.com/index/j/">j</a></li>

+            <li><a href="https://www.dickblick.com/index/k/">k</a></li>

+            <li><a href="https://www.dickblick.com/index/l/">l</a></li>

+            <li><a href="https://www.dickblick.com/index/m/">m</a></li>

+            <li><a href="https://www.dickblick.com/index/n/">n</a></li>

+            <li><a href="https://www.dickblick.com/index/o/">o</a></li>

+            <li><a href="https://www.dickblick.com/index/p/">p</a></li>

+            <li><a href="https://www.dickblick.com/index/q/">q</a></li>

+            <li><a href="https://www.dickblick.com/index/r/">r</a></li>

+            <li><a href="https://www.dickblick.com/index/s/">s</a></li>

+            <li><a href="https://www.dickblick.com/index/t/">t</a></li>

+            <li><a href="https://www.dickblick.com/index/u/">u</a></li>

+            <li><a href="https://www.dickblick.com/index/v/">v</a></li>

+            <li><a href="https://www.dickblick.com/index/w/">w</a></li>

+            <li><a href="https://www.dickblick.com/index/xyz/">x</a></li>

+            <li><a href="https://www.dickblick.com/index/xyz/">y</a></li>

+            <li><a href="https://www.dickblick.com/index/xyz/">z</a></li>

+        </ul>

+    </li>

+    <li id="gifts" class="dropdown"><a class="dropdown-toggle" title="Gifts" data-toggle="dropdown">gifts</a>

+        <div class="dropdown-menu">

+            <ul>

+                <li><a href="https://www.dickblick.com/categories/giftideas/" title="Gift Ideas">Gift Ideas</a></li>

+                <li><a href="https://www.dickblick.com/products/blick-gift-cards/" title="Gift Cards">Gift Cards</a></li>

+            </ul>

+        </div>

+    </li>

+    <li id="deals" class="dropdown"><a class="dropdown-toggle" title="Deals" data-toggle="dropdown">deals</a>

+        <div class="dropdown-menu">

+            <ul>

+                <li><a href="https://www.dickblick.com/clearance/" title="Clearance">Clearance</a></li>

+                <li><a href="https://www.dickblick.com/landing/deals/" title="Deals &amp; Free Offers">Deals &amp; Free Offers</a></li>

+                <li><a href="https://www.dickblick.com/freeshippingdeals/" title="Free Shipping Deals">Free Shipping Deals</a></li>

+                <li><a href="https://www.dickblick.com/landing/specialoffer/" title="Today's Special Offers">Today's Special Offer</a></li>

+            </ul>

+        </div>

+    </li>

+    <li id="forArtists" class="dropdown"><a href="/artists/" class="dropdown-toggle" title="For Artists">for artists</a>

+        <div class="dropdown-menu">

+            <ul>

+                <li><a href="https://www.dickblick.com/newproducts/" title="New Products">New Products</a></li>

+                <li><a href="https://www.dickblick.com/ProjectIdeas/" title="Project Ideas">Project Ideas</a></li>

+                <li><a href="https://www.dickblick.com/lists/find-wishlist/" title="Wish Lists">Wish Lists</a></li>

+                <li><a href="https://www.dickblick.com/connect/" title="Blick Connects">Blick Connects</a></li>

+                <li><a href="https://www.dickblick.com/FeaturedArtists/" title="Featured Artists">Featured Artists</a></li>

+                <li><a href="https://www.dickblick.com/links/" title="Featured Links">Featured Links</a></li>

+                <li><a target="_blank" href="http://www.wetcanvas.com/forums/" title="Artists' Forum">Artists' Forum</a></li>

+                <li><a href="https://www.dickblick.com/landing/winwithblick" title="Win with Blick">Win with Blick</a></li>

+                <li><a href="https://www.dickblick.com/paintingparties/" title="Painting Parties">Painting Parties</a></li>

+            </ul>

+        </div>

+    </li>

+    <li id="forEducators" class="dropdown"><a href="/educators/" class="dropdown-toggle" title="For Educators">for educators</a>

+        <div class="dropdown-menu">

+            <ul>

+                <li><a href="https://www.dickblick.com/educators/" title="BLICK for Educators">Blick for Educators</a></li>

+                <li><a href="https://www.dickblick.com/lesson-plans/" title="Lesson Plans">Lesson Plans</a></li>

+                <li><a href="https://www.dickblick.com/lists/find-wishlist/" title="Wish Lists">Wish Lists</a></li>

+                <li id="educatorResourceHeaderLinksArtRoomAid"><a href="https://www.dickblick.com/ara/" title="Art Room Aid">Art Room Aid</a></li>

+                <li id="educatorResourceHeaderLinksBlickU"><a href="https://www.dickblick.com/blicku/" title="Blick U">Blick U</a></li>

+                <li><a href="https://www.dickblick.com/customerservice/onaccount/" title="School Discounts">School Discounts</a></li>

+                <li><a href="https://www.dickblick.com/landing/teachernews/" title="Teacher News">Teacher News</a></li>

+                <li id="educatorResourceHeaderLinksEducatorForum"><a target="_blank" href="http://www.wetcanvas.com/forums/channels.php?s=&amp;channel_id=29" title="Educator Forum">Educator Forum</a></li>

+            </ul>

+        </div>

+    </li>

+</ul></div>

+

+

+

+

+</div><!-- End_Module_2430 --></div>

+    <div class="clear"></div>

+</div>

+

+</div></div>

+        </div>

+        <div class="headerBottom row">

+            <div id="dnn_headerbottomleft" class="col-xs-6"><div class="DnnModule DnnModule-BlickInstantSearch DnnModule-2168"><a name="2168"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr2168_ContentPane"><!-- Start_Module_2168 --><div id="dnn_ctr2168_ModuleContent" class="DNNModuleContent ModBlickInstantSearchC">

+    <!--CDF(Css|/DesktopModules/BlickInstantSearch/Content/styles/unbxdSearch.css)-->

+

+        <div id="unbxdSearch" class="unbxdNew unbxdSearchBarContainer unbxdSearch">

+            <div id="unbxdSearchContainer" class="unbxdSearchContainer unbxd-yui-skin-sam">

+                <input type="text" id="unbxd_q" class="unbxd_q" name="unbxd_q" value="enter keyword or item number..." autocomplete="off" data-search-url="/search">

+                <img id="unbxdSubmit" class="unbxdHeaderSearchButton" alt="search" src="https://cdn.dick-blick.com/images/header/search-magnifier_optimized.png">

+                <input type="hidden" name="unbxd_x" value="0">

+                <input type="hidden" name="unbxd_y" value="0">

+                <input type="hidden" name="unbxd_sp_cs" value="UTF-8">

+                <input type="hidden" name="unbxd_s" value="unbxd">

+            </div>

+        </div>

+

+        <link rel="stylesheet" href="https://cdn.dick-blick.com/unbxd/prod_dickblick-com80037-1489385476_autosuggest.css">

+        <script src="https://cdn.dick-blick.com/unbxd/prod_dickblick-com80037-1489385476_checkout_autosuggest.js"></script>

+

+</div><!-- End_Module_2168 --></div>

+    <div class="clear"></div>

+</div>

+

+</div></div>

+            <div id="dnn_headerbottomright" class="col-xs-6"><div class="DnnModule DnnModule-DNN_HTML DnnModule-2847 DnnVersionableControl"><a name="2847"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr2847_ContentPane"><!-- Start_Module_2847 --><div id="dnn_ctr2847_ModuleContent" class="DNNModuleContent ModDNNHTMLC">

+    <div id="dnn_ctr2847_HtmlModule_lblContent"><div class="ticker slick-initialized slick-slider">

+    <div aria-live="polite" class="slick-list draggable"><div class="slick-track" style="opacity: 1; width: 2250px; transform: translate3d(-1350px, 0px, 0px);"><div class="slick-slide slick-cloned" data-slick-index="-1" aria-hidden="true" style="width: 450px;"><a href="/holiday2017/">HOLIDAY RESOURCE CENTER â–º</a></div><div class="slick-slide" data-slick-index="0" aria-hidden="true" style="width: 450px;"><a href="/requests/mailinglist/">JOIN OUR EMAIL LIST â–º</a></div><div class="slick-slide" data-slick-index="1" aria-hidden="true" style="width: 450px;"><a href="/ProjectIdeas/">EXPLORE PROJECT IDEAS â–º</a></div><div class="slick-slide slick-current slick-active" data-slick-index="2" aria-hidden="false" style="width: 450px;"><a href="/holiday2017/">HOLIDAY RESOURCE CENTER â–º</a></div><div class="slick-slide slick-cloned" data-slick-index="3" aria-hidden="true" style="width: 450px;"><a href="/requests/mailinglist/">JOIN OUR EMAIL LIST â–º</a></div></div></div>

+

+

+</div></div>

+

+

+

+

+</div><!-- End_Module_2847 --></div>

+    <div class="clear"></div>

+</div>

+

+</div></div>

+        </div>

+        <div id="headerSpecialOffer">

+            <div id="dnn_specialOfferFullPanel" class="col-xs-12"><div class="DnnModule DnnModule-DNN_HTML DnnModule-2434 DnnVersionableControl"><a name="2434"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr2434_ContentPane"><!-- Start_Module_2434 --><div id="dnn_ctr2434_ModuleContent" class="DNNModuleContent ModDNNHTMLC">

+    <div id="dnn_ctr2434_HtmlModule_lblContent"><div class="headeroffers" startdate="12/16/2017 12:01 AM" expdate="12/24/2017 12:01 AM" style="">

+    <a href="https://www.dickblick.com/landing/specialOffer" title="Blick Special Offer"><img alt="Blick Special Offer" src="https://cdn.dick-blick.com/images/promotions/offers2017/121817_CELH.gif"></a>

+</div>

+<div class="headeroffers" startdate="12/24/2017 12:01 AM" expdate="12/30/2020 2:00 AM" style="display: none;">

+    <a href="https://www.dickblick.com/customerservice/shipping/" title="Free Shipping on orders of $35 or more!"><img alt="Free Shipping on orders of $35 or more!" src="https://cdn.dick-blick.com/images/promotions/offers2017/101817_FreeShipping.jpg"></a>

+</div></div>

+

+

+

+

+</div><!-- End_Module_2434 --></div>

+    <div class="clear"></div>

+</div>

+

+</div></div>

+        </div>

+    </div>

+

+    <div id="webPageContent">

+        <div class="row">

+            <div id="dnn_fullContentPaneNoPadding" class="col-xs-12 noPadding DNNEmptyPane"></div>

+        </div>

+        <div class="row">

+            <div id="dnn_ContentPane" class="col-xs-12"><div class="DnnModule DnnModule-BlickCheckout DnnModule-481"><a name="481"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr481_ContentPane"><!-- Start_Module_481 --><div id="dnn_ctr481_ModuleContent" class="DNNModuleContent ModBlickCheckoutC">

+    <!--CDF(Css|/DesktopModules/BlickCheckout/Content/Style/telerik/telerik.common.min.css)-->

+    <!--CDF(Css|/DesktopModules/BlickCheckout/Content/Style/telerik/telerik.default.min.css)-->

+    <!--CDF(Css|/DesktopModules/BlickCheckout/Content/Style/jquery-ui-themes/base/jquery-ui.css)-->

+    <!--CDF(Css|/DesktopModules/BlickCheckout/Content/Style/Site.css)-->

+    <!--CDF(Css|/DesktopModules/BlickCheckout/Content/Style/Checkout.css)-->

+

+

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/framework/knockout-3.0.0.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/kendo/kendo.web.min.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/framework/handlebars.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/framework/require-2.1.9.js)-->

+

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/jquery-migrate-1.2.1.min.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/jquery-ui.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/jquery.validate.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/jquery.history.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/jquery.validate.unobtrusive.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/jquery.extensions.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/jquery.showLoading.min.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/blick.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/blick.utilities.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/blick.googleanalytics.utilities.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/blick.pages.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/blick.services.page.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/blick.services.checkout.js)-->

+

+    <!--CDF(Javascript|/DesktopModules/BlickCheckout/Content/Scripts/blick.pages.checkout.js)-->

+

+    <!--CDF(Javascript|/DesktopModules/BlickCart/Content/scripts/framework/amplify.min.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCart/Content/scripts/app.messagebus.js)-->

+    <!--CDF(Javascript|/DesktopModules/BlickCart/Content/scripts/app.storage.js)-->

+

+

+

+

+

+        <div id="checkoutMainContainer">

+

+

+

+<div id="checkoutWizard">

+    <div class="checkoutContent">

+        <div class="wizardSteps" id="main-content">

+            <!-- Banner Message -->

+

+            <div class="wizardContent" style="display: block;">

+<div id="billing">

+    <ol class="checkoutSteps">

+        <li id="checkoutStep1" class="li_first complete">Shipping &amp; Delivery</li>

+        <li id="checkoutStep2" class="active">Payment &amp; Contact</li>

+        <li id="checkoutStep3" class="">Submit Order</li>

+        <div class="clear"></div>

+    </ol>

+

+

+<div class="submitApplyCouponEntry">

+        <a class="actionButton linkShowSubmitApplyCoupon">Pay for your order using a gift card or coupon</a>

+</div>

+<div class="submitApplyCouponDiscovered" style="display:none">

+<form defaultbutton="linkBillingSubmitApplyCoupon" action="" id="submitApplyCoupon" method="post" name="BillingAndContactApplyCoupon" novalidate="novalidate">        <fieldset>

+            <legend>Apply Coupon</legend>

+            <div class="feedbackMsg ">

+                    <div class="message" style="display:none">

+                        <p><!-- Dynamic message goes here --></p>

+                    </div>

+                    </div>

+

+            <div class="message msg_info">

+                <p>If your gift card has a PIN number provide it in the field below. If there is not a PIN number enter the gift card number only.</p>

+            </div>

+

+            <div class="couponsAppliedList">

+

+            </div>

+            <span class="inputField textboxField">

+                <label for="CouponCode">Enter Your Gift Card or Coupon Number:</label>

+                <input data-val="true" data-val-regex="The coupon must have 1-7 or 19 characters." data-val-regex-pattern="^\d{1,7}$|^\d{19}$" data-val-required="The coupon code is required." id="CouponCode" name="CouponCode" type="text" value="">

+                <span class="field-validation-valid" data-valmsg-for="CouponCode" data-valmsg-replace="true"></span>

+            </span>

+            <span class="inputField textboxField">

+                <label for="CouponPin">Enter Your Gift Card Pin Number:</label>

+                <input data-val="true" data-val-length="The field Enter Your Gift Card Pin Number: must be a string with a minimum length of 4 and a maximum length of 4." data-val-length-max="4" data-val-length-min="4" data-val-regex="The PIN value only accepts digits. Remove letters, special symbols and white spaces." data-val-regex-pattern="\d*" id="CouponPin" maxlength="4" name="CouponPin" type="password">

+                <span class="field-validation-valid" data-valmsg-for="CouponPin" data-valmsg-replace="true"></span>

+            </span>

+            <span class="inputField hiddenField">

+                <input data-val="true" data-val-number="The field CouponToRemove must be a number." data-val-required="The CouponToRemove field is required." id="CouponToRemove" name="CouponToRemove" type="hidden" value="0">

+            </span>

+            <span class="inputField hiddenField">

+                <input type="hidden" id="PaymentRemainder" name="PaymentRemainder" value="$40.14">

+            </span><br>

+            <div style="margin: 10px 0px;"><a id="linkBillingSubmitApplyCoupon" class="actionButton linkSubmitApplyCoupon">Apply to My Total</a>  </div>

+

+            <div style="position: relative; width: 380px;  clear: both; padding-top: 5px;">

+                 <p><a class="openApplyCouponsInformationPopUp">Learn more about paying with gift cards and coupons</a> </p>

+            </div>

+

+        </fieldset>

+        <span class="paymentRemainder"> How will you pay the balance of your total?  ($40.14)</span>

+        <!--<p>

+            <a class="openApplyCouponsInformationPopUp">Learn more about paying with gift cards and coupons</a>

+        </p>-->

+</form></div>

+

+<div id="applyCouponsInformationPopUp" class="blick-popup" width="650" height="450">

+    <a class="backButton headerPopuplink closeApplyCouponsInformationPopUp">Return to Billing &amp; Contact</a>

+    <div class="headerArea">

+        <h3>How can I redeem a Gift Card or Coupon?</h3>

+    </div>

+    <div class="displayArea" style="height: 400px !important;">

+        <p>To use a Gift Card to pay for your order, enter the 19-digit number from the back of the Gift Card.</p>

+            <img src="/DesktopModules/BlickCheckout/Content/images/giftCardHelp.gif" alt="Gift Card Help" title="">

+        <p>To use an e-Gift Card to pay for your order, enter the 19-digit e-Gift Card Number from the e-Gift Card Confirmation e-mail sent to you by Blick.</p>

+            <img src="/DesktopModules/BlickCheckout/Content/images/eGiftCardHelp.gif" alt="E Gift Card Help" title="">

+        <p>To use a Coupon to pay for your order, enter the 7-digit Coupon Number from your coupon.  <strong>Note: If a coupon is not used in its entirety, a credit will not be issued.</strong></p>

+            <img src="/DesktopModules/BlickCheckout/Content/images/couponHelp.gif" alt="Coupon Help" title="">

+        <p>Although Blick no longer sells Gift Certificates, we honor them as a form of payment if they have not expired.</p>

+        <p>To use a Gift Certificate to pay for your order, enter the 7-digit Gift Number from your Gift Certificate. <strong>Note: If a gift certificate is not used in its entirety, a check will be issued to you if the remaining value is $2.00 or more; otherwise, no check or credit will be issued.</strong></p>

+            <img src="/DesktopModules/BlickCheckout/Content/images/giftCertificateHelp.gif" alt="Gift Certificate Help" title="">

+        <br>

+        <a class="backButton closeApplyCouponsInformationPopUp">Return to Billing &amp; Contact</a>

+    </div>

+</div>

+

+

+

+<form defaultbutton="lnkBillingSubmitForm" action="" id="BillingAndContactSubmitBilling" method="post" name="BillingAndContactSubmit" novalidate="novalidate"><input data-val="true" data-val-required="The AllowChangeBillingAddress field is required." id="AllowChangeBillingAddress" name="AllowChangeBillingAddress" type="hidden" value="False"><div class="feedbackMsg ">

+                    <div class="message" style="display:none">

+                        <p><!-- Dynamic message goes here --></p>

+                    </div>

+                    </div>

+

+<div id="paymentMethodsForm" class="securePayment">

+

+

+    <fieldset id="securePayment">

+    <h2>Secure Payment</h2>

+        <ul>

+

+

+            <li>

+                <input id="rdbCreditCardPaymentMethod" type="radio" name="paymentMethod" value="CreditCard" autocomplete="off" checked="checked">

+                <label for="rdbCreditCardPaymentMethod">Credit Card</label>

+                <img src="/DesktopModules/BlickCheckout/Content/images/accepted-credit-cards.gif" alt="We accept Discover, MasterCard, Visa, American Express, Diners Club, and JCB credit cards">

+                <div class="paymentOptionFields creditCardFields" style="display: block;">

+                    <span class="inputField textboxField">

+                        <label for="CreditCardNumber">Credit Card Number:</label>

+                        <input data-val="true" data-val-length="The credit card number should not be more than 19 characters." data-val-length-max="19" data-val-length-min="1" data-val-regex="The credit card number format is not valid. Remove letters, special symbols and white spaces." data-val-regex-pattern="(x{6,12}\d{4})|\d{10,16}" data-val-required="The Credit Card Number: field is required." id="CreditCardNumber" maxlength="19" name="CreditCardNumber" type="text" value="">

+                        <span class="field-validation-valid" data-valmsg-for="CreditCardNumber" data-valmsg-replace="true"></span>

+                    </span>

+                    <span class="inputField textboxField">

+                        <label for="CreditCardHolderName">Name on Card:</label>

+                        <input data-val="true" data-val-length="The credit card holder name is too long." data-val-length-max="32" data-val-required="The Name on Card: field is required." id="CreditCardHolderName" maxlength="32" name="CreditCardHolderName" type="text" value="">

+                        <span class="field-validation-valid" data-valmsg-for="CreditCardHolderName" data-valmsg-replace="true"></span>

+                    </span>

+                    <span class="inputField dropdownfield" id="CreditCardMonthField">

+                        <label for="CreditCardMonth">Month:</label>

+                        <select id="CreditCardMonth" name="CreditCardMonth">

+                            <option value="01">01 - January</option>

+                            <option value="02">02 - February</option>

+                            <option value="03">03 - March</option>

+                            <option value="04">04 - April</option>

+                            <option value="05">05 - May</option>

+                            <option value="06">06 - June</option>

+                            <option value="07">07 - July</option>

+                            <option value="08">08 - August</option>

+                            <option value="09">09 - September</option>

+                            <option value="10">10 - October</option>

+                            <option value="11">11 - November</option>

+                            <option value="12">12 - December</option>

+                        </select>

+

+                    </span>

+                    <span class="inputField dropdownfield" id="CreditCardYearField">

+                        <label for="CreditCardYear">Year:</label>

+                        <select id="CreditCardYear" name="CreditCardYear">

+                            <option value="2017">2017</option>

+                            <option value="2018">2018</option>

+                            <option value="2019">2019</option>

+                            <option value="2020">2020</option>

+                            <option value="2021">2021</option>

+                            <option value="2022">2022</option>

+                            <option value="2023">2023</option>

+                            <option value="2024">2024</option>

+                            <option value="2025">2025</option>

+                            <option value="2026">2026</option>

+                            <option value="2027">2027</option>

+                        </select>

+

+                    </span>

+                    <span class="inputField textboxField" id="CreditCardSecurityValueField">

+                        <label for="CreditCardSecurityValue">Card Security Value:</label>

+                        <input data-val="true" data-val-length="The credit card security value should be of 3 or 4 digits length." data-val-length-max="4" data-val-length-min="3" data-val-regex="The credit card security value only accepts digits. Remove letters, special symbols and white spaces." data-val-regex-pattern="\d*" data-val-required="The Card Security Value: field is required." id="CreditCardSecurityValue" maxlength="4" name="CreditCardSecurityValue" type="text" value="">

+                        <span class="field-validation-valid" data-valmsg-for="CreditCardSecurityValue" data-valmsg-replace="true"></span>

+                    </span>

+                </div>

+            </li>

+

+

+                    <li>

+                        <input id="rdbPaypalPaymentMethod" type="radio" name="paymentMethod" value="PayPal" autocomplete="off">

+                        <label for="rdbPaypalPaymentMethod">PayPal</label>

+                        <img src="/DesktopModules/BlickCheckout/Content/images/paypal.gif" style="vertical-align: middle" alt="Use PayPal for payment ...">

+                        <div class="paymentOptionFields paypalFields" style="display: none;">

+                        <p>When you click the next button, you will be redirected to PayPal to complete your payment.</p>

+                    </div>

+                    </li>

+

+            <li>

+                <input id="rdbCheckOrMoneyPaymentMethod" type="radio" name="paymentMethod" value="CheckOrMoneyOrder" autocomplete="off">

+                <label for="rdbCheckOrMoneyPaymentMethod">Check or Money Order</label>

+                <div class="paymentOptionFields checkOrMoneyOrderFields" style="display: none;">

+                    <p>

+                        We'll give you instructions for paying by check or money order once your order is complete. &nbsp;Please remember, your payment must be received within 10 business days for your order to be processed. Your order will not be shipped until we have received payment.

+                    </p>

+                </div>

+            </li>

+        </ul>

+    </fieldset>

+

+

+

+</div>

+

+<div id="billingAddressForm" style="display: block;">

+<fieldset>

+    <legend>What is your billing address?</legend>

+    <span class="inputField checkboxField">

+        <input type="checkbox" id="UseShippingAddressAsBillingAddress" name="UseShippingAddressAsBillingAddress" value="true" autocomplete="off">

+        <label for="UseShippingAddressAsBillingAddress">My billing address is the same as my shipping address</label>

+    </span>

+    <input data-val="true" data-val-required="The IsBillingAddressInternational field is required." id="IsBillingAddressInternational" name="IsBillingAddressInternational" type="hidden" value="false">

+

+    <div class="billingAddress addressBlock">

+        <span class="inputField required textboxField local international" style="display: block;">

+            <label for="BillingAddressFirstName">First Name:</label>

+            <input data-val="true" data-val-length="The first name can not be longer than 32 characters." data-val-length-max="32" data-val-length-min="1" data-val-regex="the first Name is invalid, please enter valid information" data-val-regex-pattern="^[a-zA-Z\s\-'áÁéÉíÍóÓúÚüÜñÑ®’°]*$" data-val-required="The first name is required." id="BillingAddressFirstName" maxlength="32" name="BillingAddressFirstName" type="text" value="">

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressFirstName" data-valmsg-replace="true"></span>

+        </span>

+        <span class="inputField required textboxField local international" style="display: block;">

+            <label for="BillingAddressLastName">Last Name:</label>

+            <input data-val="true" data-val-length="The last name can not be longer than 32 characters." data-val-length-max="32" data-val-length-min="1" data-val-regex="the last Name is invalid, please enter valid information" data-val-regex-pattern="^[a-zA-Z0-9\s\-#'áÁéÉíÍóÓúÚüÜñÑ®’°]*$" data-val-required="The last name is required." id="BillingAddressLastName" maxlength="32" name="BillingAddressLastName" type="text" value="">

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressLastName" data-valmsg-replace="true"></span>

+        </span>

+        <span class="inputField textboxField local international" style="display: block;">

+            <label for="BillingAddressCompanyName">School or Company Name:</label>

+            <input autocomplete="off" data-val="true" data-val-length="The company name can not be longer than 32 characters." data-val-length-max="32" data-val-length-min="1" id="BillingAddressCompanyName" maxlength="32" name="BillingAddressCompanyName" type="text" value="">

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressCompanyName" data-valmsg-replace="true"></span>

+        </span>

+        <span class="inputField required textboxField local international" style="display: block;">

+            <label for="BillingAddressStreetLine1">Street Address:</label>

+            <input data-val="true" data-val-length="The street line 1 can not be longer than 32 characters." data-val-length-max="32" data-val-length-min="1" data-val-regex="The street address seems to be invalid." data-val-regex-pattern="^[^#]*$" data-val-required="The street address is required." id="BillingAddressStreetLine1" maxlength="32" name="BillingAddressStreetLine1" type="text" value="">

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressStreetLine1" data-valmsg-replace="true"></span>

+        </span>

+        <span class="inputField textboxField local international" style="display: block;">

+            <label for="BillingAddressSuiteNumber">Apt/Suite:</label>

+            <input data-val="true" data-val-length="The suite number can not be longer than 5 characters." data-val-length-max="10" data-val-length-min="1" data-val-regex="Apartment is invalid, please enter valid information." data-val-regex-pattern="^[A-Za-z\d\s\-]*$" id="BillingAddressSuiteNumber" maxlength="10" name="BillingAddressSuiteNumber" type="text" value="">

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressSuiteNumber" data-valmsg-replace="true"></span>

+        </span>

+        <span class="inputField textboxField local international" style="display: block;">

+            <label for="BillingAddressStreetLine2">Street Address Line 2 (optional):</label>

+            <input autocomplete="off" data-val="true" data-val-length="The street line 2 can not be longer than 32 characters." data-val-length-max="32" data-val-length-min="1" data-val-regex="The street line 2 seems to be invalid." data-val-regex-pattern="^[^#]*$" id="BillingAddressStreetLine2" maxlength="32" name="BillingAddressStreetLine2" type="text" value="">

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressStreetLine2" data-valmsg-replace="true"></span>

+        </span>

+        <span class="inputField required textboxField  local international clear" style="display: block;">

+            <label for="BillingAddressCity">City:</label>

+            <input data-val="true" data-val-length="The city can not be longer than 32 characters." data-val-length-max="32" data-val-length-min="1" data-val-regex="the city is invalid, please enter valid information" data-val-regex-pattern="^[a-zA-Z\WáÁéÉíÍóÓúÚüÜñÑ®’°]*$" data-val-required="The city is required." id="BillingAddressCity" maxlength="32" name="BillingAddressCity" type="text" value="">

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressCity" data-valmsg-replace="true"></span>

+        </span>

+        <span class="inputField required textboxField local">

+            <label for="BillingAddressState">State:</label>

+            <select data-val="true" data-val-regex="Please choose a valid state." data-val-regex-pattern="^(?:(?!(0)).)*$" data-val-required="The state is required." id="BillingAddressState" name="BillingAddressState"><option value="0">SELECT A STATE...</option>

+<option value="AL">ALABAMA</option>

+<option value="AK">ALASKA</option>

+<option value="AS">AMERICAN SAMOA</option>

+<option value="AZ">ARIZONA</option>

+<option value="AR">ARKANSAS</option>

+<option value="AA">ARMED FORCES AMERICAS</option>

+<option value="AE">ARMED FORCES EUROPE</option>

+<option value="AP">ARMED FORCES PACIFIC</option>

+<option value="CA">CALIFORNIA</option>

+<option value="CO">COLORADO</option>

+<option value="CT">CONNECTICUT</option>

+<option value="DE">DELAWARE</option>

+<option value="DC">DISTRICT OF COLUMBIA</option>

+<option value="FM">FEDERATED STATE MICONESIA</option>

+<option value="FL">FLORIDA</option>

+<option value="GA">GEORGIA</option>

+<option value="GU">GUAM</option>

+<option value="HI">HAWAII</option>

+<option value="ID">IDAHO</option>

+<option value="IL">ILLINOIS</option>

+<option value="IN">INDIANA</option>

+<option value="IA">IOWA</option>

+<option value="KS">KANSAS</option>

+<option value="KY">KENTUCKY</option>

+<option value="LA">LOUISIANA</option>

+<option value="ME">MAINE</option>

+<option value="MH">MARSHALL ISLANDS</option>

+<option value="MD">MARYLAND</option>

+<option value="MA">MASSACHUSETTS</option>

+<option value="MI">MICHIGAN</option>

+<option value="MN">MINNESOTA</option>

+<option value="MS">MISSISSIPPI</option>

+<option value="MO">MISSOURI</option>

+<option value="MT">MONTANA</option>

+<option value="NE">NEBRASKA</option>

+<option value="NV">NEVADA</option>

+<option value="NH">NEW HAMPSHIRE</option>

+<option value="NJ">NEW JERSEY</option>

+<option value="NM">NEW MEXICO</option>

+<option value="NY">NEW YORK</option>

+<option value="NC">NORTH CAROLINA</option>

+<option value="ND">NORTH DAKOTA</option>

+<option value="MP">NOTHERN MARIANA ISLANDS</option>

+<option value="OH">OHIO</option>

+<option value="OK">OKLAHOMA</option>

+<option value="OR">OREGON</option>

+<option value="PW">PALAU</option>

+<option value="PA">PENNSYLVANIA</option>

+<option value="PR">PUERTO RICO</option>

+<option value="RI">RHODE ISLAND</option>

+<option value="SC">SOUTH CAROLINA</option>

+<option value="SD">SOUTH DAKOTA</option>

+<option value="TN">TENNESSEE</option>

+<option value="TX">TEXAS</option>

+<option value="UT">UTAH</option>

+<option value="VT">VERMONT</option>

+<option value="VI">VIRGIN ISLANDS</option>

+<option value="VA">VIRGINIA</option>

+<option value="WA">WASHINGTON</option>

+<option value="WV">WEST VIRGINIA</option>

+<option value="WI">WISCONSIN</option>

+<option value="WY">WYOMING</option>

+</select>

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressState" data-valmsg-replace="true"></span>

+        </span>

+        <span class="inputField textboxField international" style="display: none;">

+            <label for="BillingAddressNotUsState">State/Province:</label>

+            <input data-val="true" data-val-length="The state can not be longer than 25 characters." data-val-length-max="25" data-val-length-min="1" id="BillingAddressNotUsState" maxlength="25" name="BillingAddressNotUsState" type="text" value="" disabled="disabled">

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressNotUsState" data-valmsg-replace="true"></span>

+        </span>

+        <span class="inputField required textboxField local">

+            <label for="BillingAddressZipCode">Zip Code:</label>

+            <input data-val="true" data-val-length="The zip code cannot be longer than 10 characters." data-val-length-max="10" data-val-length-min="1" data-val-required="The zip code is required." id="BillingAddressZipCode" maxlength="10" name="BillingAddressZipCode" type="text" value="">

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressZipCode" data-valmsg-replace="true"></span>

+        </span>

+        <span class="inputField textboxField international" style="display: none;">

+            <label for="BillingAddressPostalCode">Postal Code:</label>

+            <input data-val="true" data-val-length="The postal code cannot be longer than 10 characters." data-val-length-max="10" data-val-length-min="1" id="BillingAddressPostalCode" maxlength="10" name="BillingAddressPostalCode" type="text" value="" disabled="disabled">

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressPostalCode" data-valmsg-replace="true"></span>

+        </span>

+        <span class="changeBillingInternational">

+            <a class="changeToInternationalBillingAddress local">bill outside the <span class="noTransform">US</span></a>

+            <a class="changeToLocalBillingAddress international" style="display: none;">bill inside the <span class="noTransform">US</span></a>

+        </span>

+        <span class="inputField required textboxField international" style="display: none;">

+            <label for="BillingAddressCountry">Country:</label>

+            <select data-val="true" data-val-regex="Please choose a valid country." data-val-regex-pattern="^(?:(?!(0)).)*$" data-val-required="The country is required." id="BillingAddressCountry" name="BillingAddressCountry" disabled="disabled"><option value="0">SELECT A COUNTRY...</option>

+<option value="AFG">AFGHANISTAN</option>

+<option value="ALB">ALBANIA</option>

+<option value="DZA">ALGERIA</option>

+<option value="ASM">AMERICAN SAMOA</option>

+<option value="AND">ANDORRA</option>

+<option value="AGO">ANGOLA</option>

+<option value="AIA">ANGUILLA</option>

+<option value="ATA">ANTARCTICA</option>

+<option value="ATG">ANTIGUA AND BARBUDA</option>

+<option value="ARG">ARGENTINA</option>

+<option value="ARM">ARMENIA</option>

+<option value="ABW">ARUBA</option>

+<option value="AUS">AUSTRALIA</option>

+<option value="AUT">AUSTRIA</option>

+<option value="AZE">AZERBAIJAN</option>

+<option value="BHS">BAHAMAS</option>

+<option value="BHR">BAHRAIN</option>

+<option value="BGD">BANGLADESH</option>

+<option value="BRB">BARBADOS</option>

+<option value="BLR">BELARUS</option>

+<option value="BEL">BELGIUM</option>

+<option value="BLZ">BELIZE</option>

+<option value="BEN">BENIN</option>

+<option value="BMU">BERMUDA</option>

+<option value="BTN">BHUTAN</option>

+<option value="BOL">BOLIVIA</option>

+<option value="BIH">BOSNIA AND HERZEGOWINA</option>

+<option value="BWA">BOTSWANA</option>

+<option value="BVT">BOUVET ISLAND</option>

+<option value="BRA">BRAZIL</option>

+<option value="IOT">BRITISH INDIAN OCEAN TERR</option>

+<option value="BRN">BRUNEI DARUSSALAM</option>

+<option value="BGR">BULGARIA</option>

+<option value="BFA">BURKINA FASO</option>

+<option value="BDI">BURUNDI</option>

+<option value="KHM">CAMBODIA</option>

+<option value="CMR">CAMEROON</option>

+<option value="CAN">CANADA</option>

+<option value="CPV">CAPE VERDE</option>

+<option value="CYM">CAYMAN ISLANDS</option>

+<option value="CAF">CENTRAL AFRICAN REPUBLIC</option>

+<option value="TCD">CHAD</option>

+<option value="CHL">CHILE</option>

+<option value="CHN">CHINA</option>

+<option value="CXR">CHRISTMAS ISLAND</option>

+<option value="CCK">COCOS (KEELING) ISLANDS</option>

+<option value="COL">COLOMBIA</option>

+<option value="COM">COMOROS</option>

+<option value="COG">CONGO</option>

+<option value="COK">COOK ISLANDS</option>

+<option value="CRI">COSTA RICA</option>

+<option value="CIV">COTE D'IVOIRE</option>

+<option value="HRV">CROATIA</option>

+<option value="CUB">CUBA</option>

+<option value="CYP">CYPRUS</option>

+<option value="CZE">CZECH REPUBLIC</option>

+<option value="DNK">DENMARK</option>

+<option value="DJI">DJIBOUTI</option>

+<option value="DMA">DOMINICA</option>

+<option value="DOM">DOMINICAN REPUBLIC</option>

+<option value="TMP">EAST TIMOR</option>

+<option value="ECU">ECUADOR</option>

+<option value="EGY">EGYPT</option>

+<option value="SLV">EL SALVADOR</option>

+<option value="GNQ">EQUATORIAL GUINEA</option>

+<option value="ERI">ERITREA</option>

+<option value="EST">ESTONIA</option>

+<option value="ETH">ETHIOPIA</option>

+<option value="FLK">FALKLAND ISLANDS</option>

+<option value="FRO">FAROE ISLANDS</option>

+<option value="FJI">FIJI</option>

+<option value="FIN">FINLAND</option>

+<option value="FRA">FRANCE</option>

+<option value="FXX">FRANCE, METROPOLITAN</option>

+<option value="GUF">FRENCH GUIANA</option>

+<option value="PYF">FRENCH POLYNESIA</option>

+<option value="ATF">FRENCH STHRN TERRITORIES</option>

+<option value="FWI">FRENCH WEST INDIES</option>

+<option value="GAB">GABON</option>

+<option value="GMB">GAMBIA</option>

+<option value="GEO">GEORGIA</option>

+<option value="DEU">GERMANY</option>

+<option value="GHA">GHANA</option>

+<option value="GIB">GIBRALTAR</option>

+<option value="GRC">GREECE</option>

+<option value="GRL">GREENLAND</option>

+<option value="GRD">GRENADA</option>

+<option value="GLP">GUADELOUPE</option>

+<option value="GUM">GUAM</option>

+<option value="GTM">GUATEMALA</option>

+<option value="GIN">GUINEA</option>

+<option value="GNB">GUINEA BISSAU</option>

+<option value="GUY">GUYANA</option>

+<option value="HTI">HAITI</option>

+<option value="HMD">HEARD &amp; MC DONALD ISLS</option>

+<option value="VAT">HOLY SEE</option>

+<option value="HND">HONDURAS</option>

+<option value="HKG">HONG KONG</option>

+<option value="HUN">HUNGARY</option>

+<option value="ISL">ICELAND</option>

+<option value="IND">INDIA</option>

+<option value="IDN">INDONESIA</option>

+<option value="IRN">IRAN (ISLAMIC REPUBLIC OF)</option>

+<option value="IRQ">IRAQ</option>

+<option value="IRL">IRELAND</option>

+<option value="ISR">ISRAEL</option>

+<option value="ITA">ITALY</option>

+<option value="JAM">JAMAICA</option>

+<option value="JPN">JAPAN</option>

+<option value="JOR">JORDAN</option>

+<option value="KAZ">KAZAKHSTAN</option>

+<option value="KEN">KENYA</option>

+<option value="KIR">KIRIBATI</option>

+<option value="KWT">KUWAIT</option>

+<option value="KGZ">KYRGYZSTAN</option>

+<option value="LAO">LAO PEOPLE'S DEM REP</option>

+<option value="LVA">LATVIA</option>

+<option value="LBN">LEBANON</option>

+<option value="LSO">LESOTHO</option>

+<option value="LBR">LIBERIA</option>

+<option value="LIE">LIECHTENSTEIN</option>

+<option value="LTU">LITHUANIA</option>

+<option value="LUX">LUXEMBOURG</option>

+<option value="MAC">MACAU</option>

+<option value="MKD">MACEDONIA</option>

+<option value="MDG">MADAGASCAR</option>

+<option value="MWI">MALAWI</option>

+<option value="MYS">MALAYSIA</option>

+<option value="MDV">MALDIVES</option>

+<option value="MLI">MALI</option>

+<option value="MLT">MALTA</option>

+<option value="MHL">MARSHALL ISLANDS</option>

+<option value="MTQ">MARTINIQUE</option>

+<option value="MRT">MAURITANIA</option>

+<option value="MUS">MAURITIUS</option>

+<option value="MYT">MAYOTTE</option>

+<option value="MEX">MEXICO</option>

+<option value="FSM">MICRONESIA</option>

+<option value="MCO">MONACO</option>

+<option value="MNG">MONGOLIA</option>

+<option value="MNE">MONTENEGRO</option>

+<option value="MSR">MONTSERRAT</option>

+<option value="MAR">MOROCCO</option>

+<option value="MOZ">MOZAMBIQUE</option>

+<option value="MMR">MYANMAR</option>

+<option value="NAM">NAMIBIA</option>

+<option value="NRU">NAURU</option>

+<option value="NPL">NEPAL</option>

+<option value="NLD">NETHERLANDS</option>

+<option value="ANT">NETHERLANDS ANTILLES</option>

+<option value="NCL">NEW CALEDONIA</option>

+<option value="NZL">NEW ZEALAND</option>

+<option value="NIC">NICARAGUA</option>

+<option value="NER">NIGER</option>

+<option value="NGA">NIGERIA</option>

+<option value="NIU">NIUE</option>

+<option value="NFK">NORFOLK ISLAND</option>

+<option value="MNP">NORTHERN MARIANA ISLANDS</option>

+<option value="NOR">NORWAY</option>

+<option value="OMN">OMAN</option>

+<option value="PAK">PAKISTAN</option>

+<option value="PLW">PALAU</option>

+<option value="PSE">PALESTINE</option>

+<option value="PAN">PANAMA</option>

+<option value="PNG">PAPUA NEW GUINEA</option>

+<option value="PRY">PARAGUAY</option>

+<option value="PER">PERU</option>

+<option value="PHL">PHILIPPINES</option>

+<option value="PCN">PITCAIRN</option>

+<option value="POL">POLAND</option>

+<option value="PRT">PORTUGAL</option>

+<option value="QAT">QATAR</option>

+<option value="KOR">REPUBLIC OF KOREA</option>

+<option value="MDA">REPUBLIC OF MOLDOVA</option>

+<option value="REU">REUNION</option>

+<option value="ROM">ROMANIA</option>

+<option value="RUS">RUSSIAN FEDERATION</option>

+<option value="RWA">RWANDA</option>

+<option value="SGS">S GEORGIA &amp; THE S SANDWICH ISL</option>

+<option value="KNA">SAINT KITTS AND NEVIS</option>

+<option value="LCA">SAINT LUCIA</option>

+<option value="SVT">SAINT VINCENT</option>

+<option value="WSM">SAMOA</option>

+<option value="SMR">SAN MARINO</option>

+<option value="STP">SAO TOME AND PRINCIPE</option>

+<option value="SAU">SAUDI ARABIA</option>

+<option value="SEN">SENEGAL</option>

+<option value="SRB">SERBIA</option>

+<option value="SYC">SEYCHELLES</option>

+<option value="SLE">SIERRA LEONE</option>

+<option value="SGP">SINGAPORE</option>

+<option value="SVK">SLOVAKIA</option>

+<option value="SVN">SLOVENIA</option>

+<option value="SLB">SOLOMON ISLANDS</option>

+<option value="ZAF">SOUTH AFRICA</option>

+<option value="ESP">SPAIN</option>

+<option value="LKA">SRI LANKA</option>

+<option value="SHN">ST. HELENA</option>

+<option value="SPM">ST. PIERRE AND MIQUELON</option>

+<option value="SDN">SUDAN</option>

+<option value="SUR">SURINAME</option>

+<option value="SJM">SVALBARD &amp; JAN MAYEN ISL</option>

+<option value="SWZ">SWAZILAND</option>

+<option value="SWE">SWEDEN</option>

+<option value="CHE">SWITZERLAND</option>

+<option value="SYR">SYRIAN ARAB REPUBLIC</option>

+<option value="TWN">TAIWAN</option>

+<option value="TJK">TAJIKISTAN</option>

+<option value="TZA">TANZANIA, UNITED REPUBLIC OF</option>

+<option value="THA">THAILAND</option>

+<option value="COD">THE DEM REP OF THE CONGO</option>

+<option value="TGO">TOGO</option>

+<option value="TKL">TOKELAU</option>

+<option value="TON">TONGA</option>

+<option value="TTO">TRINIDAD AND TOBAGO</option>

+<option value="TUN">TUNISIA</option>

+<option value="TUR">TURKEY</option>

+<option value="TKM">TURKMENISTAN</option>

+<option value="TCA">TURKS AND CAICOS ISLANDS</option>

+<option value="TUV">TUVALU</option>

+<option value="UGA">UGANDA</option>

+<option value="UKR">UKRAINE</option>

+<option value="ARE">UNITED ARAB EMIRATES</option>

+<option value="GBR">UNITED KINGDOM</option>

+<option value="URY">URUGUAY</option>

+<option value="UZB">UZBEKISTAN</option>

+<option value="VUT">VANUATU</option>

+<option value="VEN">VENEZUELA</option>

+<option value="VNM">VIET NAM</option>

+<option value="VGB">VIRGIN ISLANDS (BRITISH)</option>

+<option value="WLF">WALLIS AND FUTUNA ISLANDS</option>

+<option value="ESH">WESTERN SAHARA</option>

+<option value="YEM">YEMEN</option>

+<option value="YUG">YUGOSLAVIA</option>

+<option value="ZMB">ZAMBIA</option>

+<option value="ZWE">ZIMBABWE</option>

+</select>

+            <span class="field-validation-valid" data-valmsg-for="BillingAddressCountry" data-valmsg-replace="true"></span>

+        </span>

+    </div>

+</fieldset>

+</div>

+

+

+

+

+<fieldset id="confirmContactInformation">

+    <legend>

+        Please provide your contact information.

+<input id="ShippingDayPhoneNumber" name="ShippingDayPhoneNumber" type="hidden" value="8005550173">    </legend>

+

+    <span class="inputField required textboxField">

+        <span class="inputFieldDetails field4_4">

+        <label for="ContactDaytimePhoneNumber">Daytime Telephone:</label>

+        <input data-val="true" data-val-length="The evening phone cannot be longer than 25 characters and less than 9." data-val-length-max="25" data-val-length-min="9" data-val-regex="The format of the phone is not correct." data-val-regex-pattern="(^(\+)?[-().\d\s]+$)" data-val-required="The daytime telephone is required." id="ContactDaytimePhoneNumber" maxlength="25" name="ContactDaytimePhoneNumber" type="text" value="">

+        <span class="field-validation-valid" data-valmsg-for="ContactDaytimePhoneNumber" data-valmsg-replace="true"></span>

+        </span>

+    </span>

+    <span class="inputField textboxField">

+        <span class="inputFieldDetails field4_4">

+        <label for="ContactEveningPhoneNumber">Evening Telephone:</label>

+        <input data-val="true" data-val-length="The evening phone cannot be longer than 25 characters and less than 9." data-val-length-max="25" data-val-length-min="9" data-val-regex="The format of the phone is not correct." data-val-regex-pattern="(^(\+)?[-().\d\s]+$)" id="ContactEveningPhoneNumber" maxlength="25" name="ContactEveningPhoneNumber" type="text" value="">

+        <span class="field-validation-valid" data-valmsg-for="ContactEveningPhoneNumber" data-valmsg-replace="true"></span>

+        </span>

+    </span>

+    <span class="inputField required textboxField">

+        <span class="inputFieldDetails field4_4">

+        <label for="ContactEmailAddress">Email Address:</label>

+        <input data-val="true" data-val-length="The email can not be more than 50 characters." data-val-length-max="50" data-val-length-min="1" data-val-regex="the email address is invalid, please enter valid information." data-val-regex-pattern="^(([^<>()[\]\\.,;:\s@\&quot;]+(\.[^<>()[\]\\.,;:\s@\&quot;]+)*)|(\&quot;.+\&quot;))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$" data-val-required="The email address is required." id="ContactEmailAddress" maxlength="50" name="ContactEmailAddress" type="text" value="">

+        <span class="field-validation-valid" data-valmsg-for="ContactEmailAddress" data-valmsg-replace="true"></span>

+    </span></span>

+</fieldset>

+ <fieldset class="billingStepSection billingNotifyAboutSpecialOffers">

+

+

+        <input id="SendEmailSpecialSalesMessageCountryRegExp" name="SendEmailSpecialSalesMessageCountryRegExp" type="hidden" value="^CAN$">

+        <div class="showMessageSpecialOfferSelected messageDisclaimer" style="display: none;">

+            <div class="messageBox">

+                    <div class="message msg_info">

+                        <p>Check one or both boxes to Receive Online Promotions (news, sales, and specials), Store Promotions (in-store promotions and events), or both.</p>

+                    </div>

+                    </div>

+        </div>

+

+        <legend>Would you like us to notify you about special offers online or in our stores?</legend>

+     <div class="checkboxField">

+         <input checked="checked" data-val="true" data-val-required="The I want to receive emails about special sales and promotions on Blick's website. field is required." id="SendEmailSpecialSalesBlickWebSite" name="SendEmailSpecialSalesBlickWebSite" type="checkbox" value="true"><input name="SendEmailSpecialSalesBlickWebSite" type="hidden" value="false">

+         <label for="SendEmailSpecialSalesBlickWebSite">I want to receive emails about special sales and promotions on Blick's website.</label>

+         <span class="field-validation-valid" data-valmsg-for="SendEmailSpecialSalesBlickWebSite" data-valmsg-replace="true"></span>

+     </div>

+     <div class="checkboxField">

+         <input checked="checked" data-val="true" data-val-required="The I want to receive emails about special sales and promotions at Blick's retail stores. field is required." id="SendEmailSpecialSalesBlickRetailStores" name="SendEmailSpecialSalesBlickRetailStores" type="checkbox" value="true"><input name="SendEmailSpecialSalesBlickRetailStores" type="hidden" value="false">

+         <label for="SendEmailSpecialSalesBlickRetailStores">I want to receive emails about special sales and promotions at Blick's retail stores.</label>

+         <span class="field-validation-valid" data-valmsg-for="SendEmailSpecialSalesBlickRetailStores" data-valmsg-replace="true"></span>

+     </div>

+     <div class="checkboxField">

+        <input checked="checked" data-val="true" data-val-required="The Please mail me catalogs and flyers. field is required." id="SendCatalogsAndFlyers" name="SendCatalogsAndFlyers" type="checkbox" value="true"><input name="SendCatalogsAndFlyers" type="hidden" value="false">

+        <label for="SendCatalogsAndFlyers">Please mail me catalogs and flyers.</label>

+        <span class="field-validation-valid" data-valmsg-for="SendCatalogsAndFlyers" data-valmsg-replace="true"></span>

+    </div>

+    <div class="checkboxField">

+        <input checked="checked" data-val="true" data-val-required="The Allow my mailing address to be shared. field is required." id="ShareMailingAddress" name="ShareMailingAddress" type="checkbox" value="true"><input name="ShareMailingAddress" type="hidden" value="false">

+        <label for="ShareMailingAddress">Allow my mailing address to be shared.</label>

+        <span class="field-validation-valid" data-valmsg-for="ShareMailingAddress" data-valmsg-replace="true"></span>

+    </div>

+    <p class="emailTerms">

+        These checkboxes will not affect a current email subscription. By submitting, you agree to receive news, sales, and specials from Blick Art Materials.

+        You may unsubscribe any time. View Contact Info and Privacy Policy,

+        by clicking <a href="https://www.dickblick.com/privacy/">here</a>.

+    </p>

+

+

+        <div class="showMessageSpecialOfferSelected messageToggle" style="display: none;">

+            <div class="messageBox">

+                    <div class="message msg_warning">

+                        <p>I agree to receive marketing communications from Blick Art Materials including communications about promotions, products, and services offered by Blick Art Materials and their marketing partners. You can unsubscribe at any time. Read our privacy policy to learn more at <a target="_blank" href="https://www.dickblick.com/privacy/">www.dickblick.com/privacy/</a></p>

+                    </div>

+                    </div>

+        </div>

+</fieldset>

+    <a class="backButton" href="https://www.dickblick.com/cart/">return to my cart</a>

+        <a id="lnkBillingSubmitForm" class="nextButton billingNext">Next</a>

+</form>

+

+        <iframe width="1" height="1" frameborder="0" scrolling="no" src="/DesktopModules/CheckoutServices/API/CheckoutServices/LogoHtm?s=fdb429fac2654af5b61f7fe5b22c4b3d">

+            &lt;img width="1" height="1" src="/DesktopModules/CheckoutServices/API/CheckoutServices/LogoGif?s=fdb429fac2654af5b61f7fe5b22c4b3d" alt="artifact"/&gt;

+        </iframe>

+

+    <script type="text/javascript">

+       $(document).ready(function () {

+           blickPagesCheckout.fn.billingViewLoaded();

+       });

+    </script>

+</div></div>

+            <div class="wizardLoading" style="display: none;">

+                <img src="/DesktopModules/BlickCheckout/Content/images/loading-image-2015.gif" alt="Loading Bar">

+

+            </div>

+        </div>

+        <div class="summaryContent" id="extra-info"><!--

+    Checkout Summary.

+    The content is updated using JS, please refer to the

+    blick.pages.checkout.js file for implementation.

+-->

+<div id="checkoutSummary" class="checkoutSummary">

+        <div class="helpBox">

+          <h2>Can We Help?</h2>

+          <p>1-800-828-4548</p>

+        </div>

+        <div class="orderSection orderTotal">

+            <h2>Order Total</h2>

+            <ul class="order-price">

+                  <li class="field">

+                    <span class="label">Subtotal:</span>

+                    <span class="subtotalPrice value ">$36.83</span>

+                  </li>

+                  <li class="field">

+                    <span class="label">Shipping:</span>

+                    <span class="shippingPrice value ">$0.00</span>

+                  </li>

+                  <li class="field">

+                    <span class="label">Handling:</span>

+                    <span class="handlingPrice value ">$0.00</span>

+                  </li>

+                  <li class="field">

+                    <span class="label">Tax:</span>

+                    <span class="taxPrice value ">$3.31</span>

+                  </li>

+                  <li class="field total">

+                    <span class="label">Total:</span>

+                    <span class="totalPrice value ">$40.14</span>

+                  </li>

+            </ul>

+

+            <p><a id="orderFAQ">Details about these charges</a></p>

+            <div id="summaryDetailsPopUp" class="blick-popup" width="650" height="450">

+                <a class="linkClose closeSummaryDetailsPopUp backButton"></a>

+

+                <div class="headerArea">

+                    <h3>Charges Related to Your Order</h3>

+                </div>

+                <div class="displayArea">

+                    <p>Your order <b>subtotal</b> is the cost of your items after any discounts have been applied.

+                    If you have not applied a discount code and would like to, you will need to return to the Cart.</p>

+

+                    <p><b>Shipping</b> charges are based on the shipping method selected. If your order qualifies for

+                    free shipping with a code and you haven't entered that code, you will need to return to the Cart

+                    to apply it. Note that free shipping may also depend on the contents of your order.</p>

+

+                    <p><b>Handling</b> charges may apply for heavy, oversized, or awkward items included in your order.

+                    They cover any special considerations needed when shipping these items.</p>

+

+                    <p><b>Sales tax</b> is applied to an order to be shipped to a state in which we have a retail store,

+                    unless the customer placing the order has an accounts that has been set up as tax-exempt.</p>

+

+                    <p>Please review the charges applied to your order carefully. If any of them seem incorrect,

+                     you may contact Customer Service for assistance at 1-800-828-4548. </p>

+

+            <p>*Tax amounts are estimated until your order is finalized.  The final tax for your order may differ

+                        slightly from the amount you see here, and will be displayed on the confirmation step.

+                        You will be able to review it prior to submitting your order.</p>

+                </div>

+            </div>

+        </div>

+        <div class="orderSection shippingAndDelivery">

+            <h2>Shipping &amp; Delivery Information</h2>

+                <ul>

+                    <li class="shippingAddress">

+                        <span class="label">Shipping Address:</span>

+                        <span class="value">

+US<span>&nbsp;</span>Chromeguy<br>

+Chromium Org<br>

+1600 Amphitheatre Parkway, #Building 4<br>

+                            Mountain View, CA 94043<br>

+                        </span>

+                    </li>

+                                        <li class="shippingMethod">

+                        <span class="label">Shipping Method:</span>

+                            <span class="value">Best Value <br>

+                                (estimated delivery 01/03/2018)</span>

+                    </li>

+                                                            <li class="giftOptions">

+                        <span class="label">Gift Options:</span>

+                            <span class="value unavailable">(not selected)</span>

+                     </li>

+                </ul>

+                <br>

+                             <a class="linkButton checkoutSummaryMakeChangesToShippingInfoButton"> change</a>

+        </div>

+        <div class="orderSection billingContactInformation">

+            <h2>Billing &amp; Contact Information</h2>

+                <p class="unavailable noBillingAndContact">(entering this now)</p>

+          </div>

+    <script type="text/javascript">

+        $(document).ready(function () {

+            blickPagesCheckout.fn.checkoutSummaryViewLoaded();

+        });

+    </script>

+</div></div>

+        <div class="clearFloat"></div>

+    </div>

+</div>

+<script type="text/javascript" language="javascript">

+    (function(window, undefined) {

+

+        // Prepare

+        var History = window.History; // Note: We are using a capital H instead of a lower h

+        if (!History.enabled) {

+            // History.js is disabled for this browser.

+            // This is because we can optionally choose to support HTML4 browsers or not.

+            return false;

+        }

+

+        // Bind to StateChange Event

+        History.Adapter.bind(window, 'statechange', function() {

+            blickPagesCheckout.fn.pageStateChanged();

+        });

+    })(window);

+

+    $(document).ready(function() {

+        // Call the page loaded event

+        blickPagesCheckout.fn.pageCartURL = "https://www.dickblick.com/cart/";

+        blickPagesCheckout.fn.expiredPageURL = "https://www.dickblick.com/v2/checkout?Render=Expired";

+        blickPagesCheckout.fn.orderNumber = "e6fa33e5f64845888c5cd1b7a3397fd0";

+        blickPagesCheckout.fn.pageLoaded();

+

+        //This function is being called from _StepWelcome.cshtml

+        //var welcomeArgs = {};

+        //blickPagesCheckout.fn.welcomeViewLoaded(welcomeArgs);

+    });

+</script>

+

+

+

+

+

+<div id="ConfirmDialogContainer">

+

+</div>

+

+

+</div>

+

+        <script type="text/javascript" language="javascript">

+

+            jQuery.curCSS = jQuery.css;

+            function getParameterByName(name) {

+                name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");

+                var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),

+                    results = regex.exec(location.search);

+                return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));

+            }

+

+            // Determine if it is necessary to load an specific view "Render" or a wizardView "step, ViewName, etc"

+            var viewName = getParameterByName("Render");

+            if (viewName !== "") {

+                // This method will render an specific view and avoid the wizard logic.

+                // It is being used more specific actions like error pages.

+                blickPagesCheckout.fn.loadView(viewName);

+            } else {

+                // Will render a page that is part of the regular wizard flow.

+                blickPagesCheckout.fn.loadWizardView("Transfer");

+            }

+        </script>

+</div><!-- End_Module_481 --></div>

+    <div class="clear"></div>

+</div>

+

+</div><div class="DnnModule DnnModule-DNN_HTML DnnModule-521 DnnVersionableControl"><a name="521"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr521_ContentPane"><!-- Start_Module_521 --><div id="dnn_ctr521_ModuleContent" class="DNNModuleContent ModDNNHTMLC">

+    <div id="dnn_ctr521_HtmlModule_lblContent"><script type="text/javascript"></script></div>

+

+

+

+

+</div><!-- End_Module_521 --></div>

+    <div class="clear"></div>

+</div>

+

+</div><div class="DnnModule DnnModule-DNN_HTML DnnModule-1324 DnnVersionableControl"><a name="1324"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr1324_ContentPane"><!-- Start_Module_1324 --><div id="dnn_ctr1324_ModuleContent" class="DNNModuleContent ModDNNHTMLC">

+    <div id="dnn_ctr1324_HtmlModule_lblContent"><p><script></script>

+</p></div>

+

+

+

+

+</div><script type="text/javascript">

+    var scheme = (("https:" == document.location.protocol) ? "https://" : "http://");

+    (function () {

+        var tagjs = document.createElement("script");

+        var s = document.getElementsByTagName("script")[0];

+        tagjs.text = "{'site':'qrEjfzB'}";

+        tagjs.async = true;

+        tagjs.src = scheme + "s.btstatic.com/tag.js";

+        s.parentNode.insertBefore(tagjs, s);

+    } ());

+</script>

+<noscript>

+  &lt;iframe src="http://thebrighttag.com/iframe?c=qrEjfzB" width="1" height="1" frameborder="0" scrolling="no" marginheight="0" marginwidth="0"&gt;&lt;/iframe&gt;

+</noscript><!-- End_Module_1324 --></div>

+    <div class="clear"></div>

+</div>

+

+</div></div>

+        </div>

+        <div class="row">

+            <div id="dnn_fullTopContentPane" class="col-xs-12 DNNEmptyPane"></div>

+        </div>

+        <div class="row">

+            <div id="dnn_leftSideBar" class="col-xs-3 DNNEmptyPane"></div>

+            <div id="dnn_contentPaneRight" class="col-xs-9 DNNEmptyPane"></div>

+        </div>

+        <div class="row">

+            <div id="dnn_SixColLeft" class="col-xs-6 DNNEmptyPane"></div>

+            <div id="dnn_halfContentPaneRight" class="col-xs-6 DNNEmptyPane"></div>

+        </div>

+        <div class="row">

+            <div id="dnn_ThreeColLeft" class="col-xs-3 DNNEmptyPane"></div>

+            <div id="dnn_centerContentPane" class="col-xs-6 DNNEmptyPane"></div>

+            <div id="dnn_TwoColRight" class="col-xs-3 DNNEmptyPane"></div>

+        </div>

+        <div class="row">

+            <div id="dnn_contentPaneLeft" class="col-xs-9 DNNEmptyPane"></div>

+            <div id="dnn_ThreeColRight" class="col-xs-3 DNNEmptyPane"></div>

+        </div>

+        <div class="row">

+            <div id="dnn_fullBottomContentPane" class="col-xs-12 DNNEmptyPane"></div>

+        </div>

+    </div>

+

+    <div id="blickFooter">

+        <div class="row">

+            <div id="dnn_footerFullPanel" class="col-xs-12"><div class="DnnModule DnnModule-DNN_HTML DnnModule-2433 DnnVersionableControl"><a name="2433"></a>

+<div class="DNNContainer_noTitle">

+    <div id="dnn_ctr2433_ContentPane"><!-- Start_Module_2433 --><div id="dnn_ctr2433_ModuleContent" class="DNNModuleContent ModDNNHTMLC">

+    <div id="dnn_ctr2433_HtmlModule_lblContent"><div class="row">

+    <div class="footerLinks col-xs-8">

+        <ul>

+            <li class="heading">Account</li>

+            <li><a href="https://www.dickblick.com/myaccount/" title="My Account">My Account</a></li>

+            <li><a href="https://www.dickblick.com/orders/lookup" title="My Orders">My Orders</a></li>

+            <li><a href="https://www.dickblick.com/lists/" title="My Lists">My Lists</a></li>

+        </ul>

+

+        <ul>

+            <li class="heading">Customer Service</li>

+            <li><a href="https://www.dickblick.com/customerservice/" title="General Help">General Help</a></li>

+            <li><a href="https://www.dickblick.com/requests/bigbook/" title="Request A Catalog">Request A Catalog</a></li>

+            <li><a href="https://www.dickblick.com/requests/survey/" title="Take Our Survey">Take Our Survey</a></li>

+            <li><a href="https://www.dickblick.com/customerservice/shipping/" title="Shipping Information">Shipping Information</a></li>

+            <li><a href="https://www.dickblick.com/customerservice/onaccount/" title="On-Account Ordering">On-Account Ordering</a></li>

+            <li><a href="https://www.dickblick.com/customerservice/taxes/" title="Sales Tax">Sales Tax</a></li>

+        </ul>

+

+        <ul>

+            <li class="heading">Product Information</li>

+            <li><a href="https://www.dickblick.com/customerservice/" title="General Help">General Help</a></li>

+            <li><a href="https://www.dickblick.com/videos/" title="Videos">Videos</a></li>

+            <li><a href="https://www.dickblick.com/productinfo/reviews/" title="Product Reviews">Product Reviews</a></li>

+            <li><a href="https://www.dickblick.com/productinfo/swatches/" title="Paint Swatches">Paint Swatches</a></li>

+            <li><a href="https://www.dickblick.com/productinfo/icons/" title="Product Icon Key">Product Icon Key</a></li>

+            <li><a href="https://www.dickblick.com/productinfo/green/" title="Being Green at Blick">Being Green at Blick</a></li>

+            <li><a href="https://www.dickblick.com/productinfo/healthsafety/" title="Health and Safety">Health &amp; Safety</a></li>

+        </ul>

+

+        <ul>

+            <li class="heading">Quick Links</li>

+            <li><a href="https://www.dickblick.com/stores/" title="Find A Store">Find A Store</a></li>

+            <li><a href="https://www.dickblick.com/requests/mailinglist/" title="Join Our Email List">Join Our Email List</a></li>

+            <li><a href="https://www.dickblick.com/aboutblick/" title="About Blick">About Blick</a></li>

+            <li><a href="https://www.dickblick.com/careers/" title="Careers">Careers</a></li>

+            <li><a href="https://www.dickblick.com/affiliates/" title="Affiliate Program">Affiliate Program</a></li>

+            <li><a href="https://www.dickblick.com/links/" title="Link to Us">Link to Us</a></li>

+            <li><a href="https://www.dickblick.com/privacy/" title="Privacy and Security">Privacy &amp; Security</a></li>

+            <li><a href="https://www.dickblick.com/accessibility/" title="Accessibility">Accessibility</a></li>

+        </ul>

+    </div>

+

+    <div class="thirdPartyLinks col-xs-4">

+

+        <div class="left">

+

+            <div id="amazonPayment">

+                <a href="https://www.dickblick.com/landing/AmazonPayments/">

+                    <img src="https://cdn.dick-blick.com/shared/homepage/acceptAmazonPay.jpg" title="You can use your Amazon credentials to check out and pay!" alt="Now Accepting Amazon Payments!">

+                </a>

+            </div>

+

+            <div id="paypalPayment">

+                <a href="https://www.dickblick.com/customerservice/payments/">

+                    <img src="https://cdn.dick-blick.com/shared/homepage/acceptPaypal.png?v=2" title="You can use your PayPal credentials to check out and pay!" alt="Now Accepting PayPal!">

+                </a>

+            </div>

+

+        </div>

+

+        <div class="right">

+

+            <div id="trustwave">

+                <script src="https://sealserver.trustkeeper.net/compliance/seal_js.php?code=23419a66019ebd52eef84e15143e3a88&amp;style=normal&amp;size=105x54&amp;language=en"></script><img id="trustwaveSealImage" src="https://sealserver.trustkeeper.net/seal_image.php?customerId=23419a66019ebd52eef84e15143e3a88&amp;size=105x54&amp;style=normal" border="0" style="cursor:pointer;" onclick="javascript:window.open('https://sealserver.trustkeeper.net/cert.php?customerId=23419a66019ebd52eef84e15143e3a88&amp;size=105x54&amp;style=normal', 'c_TW', 'location=no, toolbar=no, resizable=yes, scrollbars=yes, directories=no, status=no, width=615, height=720'); return false;" oncontextmenu="javascript:alert('Copying Prohibited by Law - Trusted Commerce is a Service Mark of TrustWave Holdings, Inc.'); return false;" alt="This site is protected by Trustwave's Trusted Commerce program" title="This site is protected by Trustwave's Trusted Commerce program"><noscript>&amp;amp;amp;lt;a href="https://sealserver.trustkeeper.net/compliance/cert.php?code=23419a66019ebd52eef84e15143e3a88&amp;amp;amp;amp;style=normal&amp;amp;amp;amp;size=105x54&amp;amp;amp;amp;language=en" target="hATW"&amp;amp;amp;gt;</noscript>

+            </div>

+

+            <div id="goDaddy">

+                <span id="siteseal"><script type="text/javascript" src="https://seal.godaddy.com/getSeal?sealID=s8PCpBBJd5RmVSuz54dUYAXFK5ucRUA1me7s7tsooSeZGA0IzBbFig1xtiXG"></script><img style="cursor:pointer;cursor:hand" src="https://seal.godaddy.com/images/3/en/siteseal_gd_3_h_l_m.gif" onclick="verifySeal();" alt="SSL site seal - click to verify"></span>

+            </div>

+

+        </div>

+

+        <div id="socialIcons">

+            <img src="https://cdn.dick-blick.com/images/homepage/redesign/other/socialIcons.png" width="231" height="29" title="Connect with us!" alt="Connect with us!" usemap="#Map">

+            <map name="Map" id="Map">

+                <area alt="Find us on Facebook!" title="Find us on Facebook!" href="https://www.facebook.com/BlickArtMaterials/" target="_blank" shape="poly" coords="0,0,29,0,28,27,0,26">

+                <area alt="Follow us on Twitter!" title="Follow us on Twitter!" href="https://twitter.com/Blick_Art/" target="_blank" shape="poly" coords="36,0,70,0,70,27,36,27">

+                <area alt="Follow us on Instagram!" title="Follow us on Instagram!" href="https://www.instagram.com/blickartmaterials/" target="_blank" shape="poly" coords="78,0,109,0,112,27,77,28">

+                <area alt="Follow us on Pintrest!" title="Follow us on Pintrest!" href="https://www.pinterest.com/BlickArt/" target="_blank" shape="poly" coords="120,0,152,0,152,28,120,27">

+                <area alt="Watch us on YouTube!" title="Watch us on YouTube!" href="https://www.youtube.com/user/BlickVideos/" target="_blank" shape="poly" coords="158,0,189,0,190,28,160,26">

+                <area alt="Follow us on Google+!" title="Follow us on Google+!" href="https://plus.google.com/110913836987243429157" target="_blank" shape="poly" coords="200,0,224,0,228,27,200,28">

+            </map>

+        </div>

+

+    </div>

+</div>

+

+<div class="row">

+    <div class="col-xs-8">

+        <p id="footercorporate">Dick Blick Art Materials&nbsp;·&nbsp;P.O. Box 1267&nbsp;·&nbsp;Galesburg, IL 61402-1267&nbsp;·&nbsp;Toll-free Phone (800) 828-4548 International Phone +1-309-343-6181 ext. 5402&nbsp;·&nbsp;Fax (800) 621-8293</p>

+        <p id="footertrademarks">Dick Blick Art Materials®, Blick®, Blick Studio®, and Artists Pick Blick® are registered trademarks of<br>Dick Blick Holdings Inc. © Copyright 1999-2017 Dick Blick Holdings Inc. All rights reserved.</p>

+    </div>

+

+    <div class="accessibilityBadge col-xs-4">

+        <a href="http://accessible360.com" target="_blank">

+            <img style="height: 100px;display: block;margin: 0 auto;" src="https://cdn.dick-blick.com/images/homepage/footer/Badge-underreview-rev.png" title="Under Review by Accessible360" alt="Under Review by Accessible360">

+        </a>

+    </div>

+</div></div>

+

+

+

+

+</div><!-- End_Module_2433 --></div>

+    <div class="clear"></div>

+</div>

+

+</div></div>

+        </div>

+        <div class="row">

+            <div id="dnn_Footer" class="col-xs-12 DNNEmptyPane"></div>

+        </div>

+    </div>

+</div>

+

+

+

+

+

+

+

+

+        <input name="ScrollTop" type="hidden" id="ScrollTop">

+        <input name="__dnnVariable" type="hidden" id="__dnnVariable" autocomplete="off" value="`{`trackLinks`:`false`,`__scdoff`:`1`,`sf_siteRoot`:`/`,`sf_tabId`:`112`,`evoq_TabId`:`112`,`evoq_PageLanguage`:`en-US`,`evoq_ContentItemId`:`-1`,`evoq_UrlReferrer`:``,`evoq_UrlPath`:`https%3a%2f%2flocalhost%3a91%2fv2%2fcheckout%3fstep%3dBillingAndContact`,`evoq_UrlQuery`:`%3fTabId%3d112%26%26step%3dBillingAndContact`,`evoq_ContentItemReferrer`:`-1`,`evoq_PersonalizedUrlReferrer`:`-1`,`evoq_DisableAnalytics`:`False`}">

+        <input name="__RequestVerificationToken" type="hidden" value="PzQGtYX8iLgyVtfNpR1BB-QgIIphkolapsEHDSIjVpyzxIv89iZnENurvJv75X251pHHXg2">

+    </form><div class="unbxd-as-wrapper" style="position: absolute; display: none;"></div>

+    <!--CDF(Javascript|/js/dnncore.js)--><!--CDF(Javascript|/js/dnn.modalpopup.js)--><!--CDF(Css|/Resources/Shared/stylesheets/dnndefault/7.0.0/default.css)--><!--CDF(Css|/Portals/_default/skins/blickecommerce/skin.css)--><!--CDF(Css|/DesktopModules/BlickCheckout/module.css)--><!--CDF(Css|/DesktopModules/BlickCheckout/module.css)--><!--CDF(Css|/DesktopModules/BlickCartSubtotal/module.css)--><!--CDF(Css|/DesktopModules/BlickCartSubtotal/module.css)--><!--CDF(Css|/Portals/0/portal.css)--><!--CDF(Javascript|/js/dnn.js)--><!--CDF(Javascript|/js/dnn.servicesframework.js)--><!--CDF(Javascript|/Resources/libraries/jQuery/01_09_01/jquery.js)--><!--CDF(Javascript|/Resources/libraries/jQuery-UI/01_11_03/jquery-ui.js)-->

+

+

+

+

+

+<img src="https://tracking.searchmarketing.com/welcome.asp?SMCID=52001053&amp;x=https://www.dickblick.com/cart/" width="1" height="1"><img src="https://tracking.searchmarketing.com/welcome.asp?SMCID=52001053&amp;x=https://www.dickblick.com/cart/" width="1" height="1">

+      <script type="text/javascript" src="/DesktopModules/BlickResources/Content/scripts/Blick/Analytic/googleanalytic/HeaderSectionListner.js" class="customFileLoader"></script><script type="text/javascript" src="/DesktopModules/BlickResources/Content/scripts/Blick/Analytic/googleanalytic/HeaderSectionTrigger.js" class="customFileLoader"></script>

+

+<div style="width:0px; height:0px; display:none; visibility:hidden;" id="batBeacon0.9276833842748398"><img style="width:0px; height:0px; display:none; visibility:hidden;" id="batBeacon0.5412775683998547" width="0" height="0" alt="" src="https://bat.bing.com/action/0?ti=4004586&amp;Ver=2&amp;mid=692c953e-1bd6-cde7-d688-68fbd2b60555&amp;evt=pageLoad&amp;sid=6eed6e6c-0&amp;lt=772&amp;pi=-2101744299&amp;lg=en-US&amp;sw=3840&amp;sh=2160&amp;sc=24&amp;tl=Welcome to Checkout - BLICK Art Materials&amp;r=https%3A%2F%2Fwww.dickblick.com%2Fcart%2F&amp;p=https%3A%2F%2Fwww.dickblick.com%2Fv2%2Fcheckout%3Fstep%3DBillingAndContact&amp;msclkid=N&amp;rn=715884"></div><script type="application/javascript" id="ywa-1513977155955-494296" class="ywa-1000770211196" defer="" src="https://sp.analytics.yahoo.com/sp.pl?a=1000770211196&amp;jsonp=YAHOO.ywa.I13N.handleJSONResponse&amp;d=Fri%2C%2022%20Dec%202017%2021%3A12%3A35%20GMT&amp;n=5&amp;b=Welcome%20to%20Checkout%20-%20BLICK%20Art%20Materials&amp;.yp=21309&amp;f=https%3A%2F%2Fwww.dickblick.com%2Fv2%2Fcheckout%3Fstep%3DBillingAndContact&amp;e=https%3A%2F%2Fwww.dickblick.com%2Fcart%2F&amp;enc=UTF-8"></script></body></html>

diff --git a/components/test/data/autofill/heuristics/output/148_payment_dickblick.com.out b/components/test/data/autofill/heuristics/output/148_payment_dickblick.com.out
new file mode 100644
index 0000000..a467225
--- /dev/null
+++ b/components/test/data/autofill/heuristics/output/148_payment_dickblick.com.out
@@ -0,0 +1,31 @@
+UNKNOWN_TYPE | unbxd_q | enter keyword or item number... | enter keyword or item number... | unbxd_q_1-default
+UNKNOWN_TYPE | CouponCode | Enter Your Gift Card or Coupon Number: |  | unbxd_q_1-default
+UNKNOWN_TYPE | CouponPin | Enter Your Gift Card Pin Number: |  | unbxd_q_1-default
+UNKNOWN_TYPE | paymentMethod | Credit Card | CreditCard | paymentMethod_1-default
+CREDIT_CARD_NUMBER | CreditCardNumber | Credit Card Number: |  | paymentMethod_1-cc
+CREDIT_CARD_NAME_FULL | CreditCardHolderName | Name on Card: |  | paymentMethod_1-cc
+CREDIT_CARD_EXP_MONTH | CreditCardMonth | Month: | 01 | paymentMethod_1-cc
+CREDIT_CARD_EXP_4_DIGIT_YEAR | CreditCardYear | Year: | 2017 | paymentMethod_1-cc
+CREDIT_CARD_VERIFICATION_CODE | CreditCardSecurityValue | Card Security Value: |  | paymentMethod_1-cc
+UNKNOWN_TYPE | paymentMethod | PayPal | PayPal | paymentMethod_1-default
+UNKNOWN_TYPE | paymentMethod | Check or Money Order | CheckOrMoneyOrder | paymentMethod_1-default
+UNKNOWN_TYPE | UseShippingAddressAsBillingAddress | My billing address is the same as my shipping address | true | paymentMethod_1-default
+NAME_FIRST | BillingAddressFirstName | First Name: |  | paymentMethod_1-default
+NAME_LAST | BillingAddressLastName | Last Name: |  | paymentMethod_1-default
+COMPANY_NAME | BillingAddressCompanyName | School or Company Name: |  | paymentMethod_1-default
+ADDRESS_HOME_LINE1 | BillingAddressStreetLine1 | Street Address: |  | paymentMethod_1-default
+ADDRESS_HOME_LINE2 | BillingAddressSuiteNumber | Apt/Suite: |  | paymentMethod_1-default
+ADDRESS_HOME_LINE3 | BillingAddressStreetLine2 | Street Address Line 2 (optional): |  | paymentMethod_1-default
+ADDRESS_HOME_CITY | BillingAddressCity | City: |  | paymentMethod_1-default
+ADDRESS_HOME_STATE | BillingAddressState | State: | 0 | paymentMethod_1-default
+UNKNOWN_TYPE | BillingAddressNotUsState | State/Province: |  | paymentMethod_1-default
+ADDRESS_HOME_ZIP | BillingAddressZipCode | Zip Code: |  | paymentMethod_1-default
+ADDRESS_HOME_ZIP | BillingAddressPostalCode | Postal Code: |  | paymentMethod_1-default
+ADDRESS_HOME_COUNTRY | BillingAddressCountry | Country: | 0 | paymentMethod_1-default
+PHONE_HOME_WHOLE_NUMBER | ContactDaytimePhoneNumber | Daytime Telephone: |  | paymentMethod_1-default
+PHONE_HOME_WHOLE_NUMBER | ContactEveningPhoneNumber | Evening Telephone: |  | paymentMethod_1-default
+EMAIL_ADDRESS | ContactEmailAddress | Email Address: |  | paymentMethod_1-default
+UNKNOWN_TYPE | SendEmailSpecialSalesBlickWebSite | I want to receive emails about special sales and promotions on Blick's website. | true | paymentMethod_1-default
+UNKNOWN_TYPE | SendEmailSpecialSalesBlickRetailStores | I want to receive emails about special sales and promotions at Blick's retail stores. | true | paymentMethod_1-default
+UNKNOWN_TYPE | SendCatalogsAndFlyers | Please mail me catalogs and flyers. | true | paymentMethod_1-default
+UNKNOWN_TYPE | ShareMailingAddress | Allow my mailing address to be shared. | true | paymentMethod_1-default
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index 8573da5..f49f853d 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -194,7 +194,7 @@
       }
     }
     render_passes_in_frame[pass->id] = {RenderPassTextureSize(pass.get()),
-                                        RenderPassTextureHint(pass.get())};
+                                        pass->generate_mipmap};
   }
   UpdateRenderPassTextures(render_passes_in_draw_order, render_passes_in_frame);
 }
@@ -625,8 +625,8 @@
   enlarged_size.Enlarge(enlarge_pass_texture_amount_.width(),
                         enlarge_pass_texture_amount_.height());
 
-  AllocateRenderPassResourceIfNeeded(render_pass->id, enlarged_size,
-                                     RenderPassTextureHint(render_pass));
+  AllocateRenderPassResourceIfNeeded(
+      render_pass->id, {enlarged_size, render_pass->generate_mipmap});
 
   // TODO(crbug.com/582554): This change applies only when Vulkan is enabled and
   // it will be removed once SkiaRenderer has complete support for Vulkan.
@@ -662,17 +662,6 @@
   return render_pass->output_rect.size();
 }
 
-// static
-ResourceTextureHint DirectRenderer::RenderPassTextureHint(
-    const RenderPass* render_pass) {
-  // TODO(danakj): Pass these as 2 bools instead so subclasses don't have to
-  // worry about new hints being silently added to the field here.
-  ResourceTextureHint hint = ResourceTextureHint::kFramebuffer;
-  if (render_pass->generate_mipmap)
-    hint |= ResourceTextureHint::kMipmap;
-  return hint;
-}
-
 void DirectRenderer::SetCurrentFrameForTesting(const DrawingFrame& frame) {
   current_frame_valid_ = true;
   current_frame_ = frame;
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h
index 926b1812..f6fe330 100644
--- a/components/viz/service/display/direct_renderer.h
+++ b/components/viz/service/display/direct_renderer.h
@@ -107,7 +107,7 @@
 
   struct RenderPassRequirements {
     gfx::Size size;
-    ResourceTextureHint hint;
+    bool mipmap = false;
   };
 
   static gfx::RectF QuadVertexRect();
@@ -132,8 +132,6 @@
   void SetScissorTestRectInDrawSpace(const gfx::Rect& draw_space_rect);
 
   static gfx::Size RenderPassTextureSize(const RenderPass* render_pass);
-  static ResourceTextureHint RenderPassTextureHint(
-      const RenderPass* render_pass);
 
   void FlushPolygons(
       base::circular_deque<std::unique_ptr<DrawPolygon>>* poly_list,
@@ -165,8 +163,7 @@
           render_passes_in_frame) = 0;
   virtual void AllocateRenderPassResourceIfNeeded(
       const RenderPassId& render_pass_id,
-      const gfx::Size& enlarged_size,
-      ResourceTextureHint texturehint) = 0;
+      const RenderPassRequirements& requirements) = 0;
   virtual bool IsRenderPassResourceAllocated(
       const RenderPassId& render_pass_id) const = 0;
   virtual gfx::Size GetRenderPassTextureSize(
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 4300b7d..3296c7e 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -3609,13 +3609,13 @@
       passes_to_delete.push_back(pair.first);
       continue;
     }
-    gfx::Size required_size = render_pass_it->second.size;
-    ResourceTextureHint required_hint = render_pass_it->second.hint;
+    const RenderPassRequirements& requirements = render_pass_it->second;
     const ScopedRenderPassTexture& texture = pair.second;
-    bool size_appropriate = texture.size().width() >= required_size.width() &&
-                            texture.size().height() >= required_size.height();
-    bool hint_appropriate = (texture.hint() & required_hint) == required_hint;
-    if (!size_appropriate || !hint_appropriate)
+    bool size_appropriate =
+        texture.size().width() >= requirements.size.width() &&
+        texture.size().height() >= requirements.size.height();
+    bool mipmap_appropriate = !requirements.mipmap || texture.mipmap();
+    if (!size_appropriate || !mipmap_appropriate)
       passes_to_delete.push_back(pair.first);
   }
   // Delete RenderPass textures from the previous frame that will not be used
@@ -3639,18 +3639,15 @@
 
 void GLRenderer::AllocateRenderPassResourceIfNeeded(
     const RenderPassId& render_pass_id,
-    const gfx::Size& enlarged_size,
-    ResourceTextureHint texturehint) {
-  const auto& caps = output_surface_->context_provider()->ContextCapabilities();
+    const RenderPassRequirements& requirements) {
   auto contents_texture_it = render_pass_textures_.find(render_pass_id);
   if (contents_texture_it != render_pass_textures_.end())
     return;
 
   ScopedRenderPassTexture contents_texture(
-      output_surface_->context_provider()->ContextGL(), enlarged_size,
-      texturehint, BackbufferFormat(),
-      current_frame()->current_render_pass->color_space, caps.texture_usage,
-      caps.texture_storage, caps.texture_npot);
+      output_surface_->context_provider(), requirements.size,
+      BackbufferFormat(), current_frame()->current_render_pass->color_space,
+      requirements.mipmap);
   render_pass_textures_[render_pass_id] = std::move(contents_texture);
 }
 
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h
index 0bc25ce..4f28e3c8 100644
--- a/components/viz/service/display/gl_renderer.h
+++ b/components/viz/service/display/gl_renderer.h
@@ -102,8 +102,7 @@
           render_passes_in_frame) override;
   void AllocateRenderPassResourceIfNeeded(
       const RenderPassId& render_pass_id,
-      const gfx::Size& enlarged_size,
-      ResourceTextureHint texturehint) override;
+      const RenderPassRequirements& requirements) override;
   bool IsRenderPassResourceAllocated(
       const RenderPassId& render_pass_id) const override;
   gfx::Size GetRenderPassTextureSize(
diff --git a/components/viz/service/display/scoped_render_pass_texture.cc b/components/viz/service/display/scoped_render_pass_texture.cc
index 004025b8..b6e5b54 100644
--- a/components/viz/service/display/scoped_render_pass_texture.cc
+++ b/components/viz/service/display/scoped_render_pass_texture.cc
@@ -6,56 +6,65 @@
 
 #include "base/bits.h"
 #include "base/logging.h"
+#include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
 
 namespace viz {
 
-ScopedRenderPassTexture::ScopedRenderPassTexture(
-    gpu::gles2::GLES2Interface* gl,
-    const gfx::Size& size,
-    ResourceTextureHint hint,
-    ResourceFormat format,
-    const gfx::ColorSpace& color_space,
-    bool use_texture_usage_hint,
-    bool use_texture_storage,
-    bool use_texture_npot)
-    : gl_(gl), size_(size), hint_(hint), color_space_(color_space) {
-  DCHECK(gl_);
-  gl_->GenTextures(1, &gl_id_);
-
-  // Create and set texture properties.
-  gl_->BindTexture(GL_TEXTURE_2D, gl_id_);
-  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-  if (use_texture_usage_hint && (hint_ & ResourceTextureHint::kFramebuffer)) {
-    gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE,
-                       GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
-  }
-
-  if (use_texture_storage) {
-    GLint levels = 1;
-    if (use_texture_npot && (hint_ & ResourceTextureHint::kMipmap))
-      levels += base::bits::Log2Floor(std::max(size_.width(), size_.height()));
-
-    gl_->TexStorage2DEXT(GL_TEXTURE_2D, levels, TextureStorageFormat(format),
-                         size_.width(), size_.height());
-  } else {
-    gl_->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(format), size_.width(),
-                    size_.height(), 0, GLDataFormat(format), GLDataType(format),
-                    nullptr);
-  }
-}
-
 ScopedRenderPassTexture::ScopedRenderPassTexture() = default;
 
 ScopedRenderPassTexture::ScopedRenderPassTexture(
+    ContextProvider* context_provider,
+    const gfx::Size& size,
+    ResourceFormat format,
+    const gfx::ColorSpace& color_space,
+    bool mipmap)
+    : context_provider_(context_provider),
+      size_(size),
+      mipmap_(mipmap),
+      color_space_(color_space) {
+  DCHECK(context_provider_);
+  gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+  const gpu::Capabilities& caps = context_provider_->ContextCapabilities();
+  gl->GenTextures(1, &gl_id_);
+
+  gl->BindTexture(GL_TEXTURE_2D, gl_id_);
+  gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+  // This texture will be bound as a framebuffer, so optimize for that.
+  if (caps.texture_usage) {
+    gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE,
+                      GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
+  }
+
+  if (caps.texture_storage) {
+    GLint levels = 1;
+    if (caps.texture_npot && mipmap_)
+      levels += base::bits::Log2Floor(std::max(size_.width(), size_.height()));
+
+    gl->TexStorage2DEXT(GL_TEXTURE_2D, levels, TextureStorageFormat(format),
+                        size_.width(), size_.height());
+  } else {
+    gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(format), size_.width(),
+                   size_.height(), 0, GLDataFormat(format), GLDataType(format),
+                   nullptr);
+  }
+}
+
+ScopedRenderPassTexture::~ScopedRenderPassTexture() {
+  Free();
+}
+
+ScopedRenderPassTexture::ScopedRenderPassTexture(
     ScopedRenderPassTexture&& other) {
-  gl_ = other.gl_;
+  context_provider_ = other.context_provider_;
   size_ = other.size_;
-  hint_ = other.hint_;
+  mipmap_ = other.mipmap_;
   color_space_ = other.color_space_;
   gl_id_ = other.gl_id_;
 
@@ -63,17 +72,13 @@
   other.gl_id_ = 0;
 }
 
-ScopedRenderPassTexture::~ScopedRenderPassTexture() {
-  Free();
-}
-
 ScopedRenderPassTexture& ScopedRenderPassTexture::operator=(
     ScopedRenderPassTexture&& other) {
   if (this != &other) {
     Free();
-    gl_ = other.gl_;
+    context_provider_ = other.context_provider_;
     size_ = other.size_;
-    hint_ = other.hint_;
+    mipmap_ = other.mipmap_;
     color_space_ = other.color_space_;
     gl_id_ = other.gl_id_;
 
@@ -86,7 +91,8 @@
 void ScopedRenderPassTexture::Free() {
   if (!gl_id_)
     return;
-  gl_->DeleteTextures(1, &gl_id_);
+  gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+  gl->DeleteTextures(1, &gl_id_);
   gl_id_ = 0;
 }
 
diff --git a/components/viz/service/display/scoped_render_pass_texture.h b/components/viz/service/display/scoped_render_pass_texture.h
index b8bd90b..addf61a 100644
--- a/components/viz/service/display/scoped_render_pass_texture.h
+++ b/components/viz/service/display/scoped_render_pass_texture.h
@@ -9,48 +9,45 @@
 #include "components/viz/common/resources/resource_format.h"
 #include "components/viz/common/resources/resource_texture_hint.h"
 #include "components/viz/service/viz_service_export.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace viz {
+class ContextProvider;
 
 // ScopedRenderPassTexture is resource used inside the same GL context and will
 // not being sent into another process. So no need to create fence and mailbox
 // for these resources.
 class VIZ_SERVICE_EXPORT ScopedRenderPassTexture {
  public:
-  explicit ScopedRenderPassTexture(gpu::gles2::GLES2Interface* gl,
-                                   const gfx::Size& size,
-                                   ResourceTextureHint hint,
-                                   ResourceFormat format,
-                                   const gfx::ColorSpace& color_space,
-                                   bool use_texture_usage_hint,
-                                   bool use_texture_storage,
-                                   bool use_texture_npot);
-
   ScopedRenderPassTexture();
+  ScopedRenderPassTexture(ContextProvider* context_provider,
+                          const gfx::Size& size,
+                          ResourceFormat format,
+                          const gfx::ColorSpace& color_space,
+                          bool mipmap);
+  ~ScopedRenderPassTexture();
+
   ScopedRenderPassTexture(ScopedRenderPassTexture&& other);
   ScopedRenderPassTexture& operator=(ScopedRenderPassTexture&& other);
-  ~ScopedRenderPassTexture();
 
   GLuint id() const { return gl_id_; }
   const gfx::Size& size() const { return size_; }
-  ResourceTextureHint hint() const { return hint_; }
+  bool mipmap() const { return mipmap_; }
   const gfx::ColorSpace& color_space() const { return color_space_; }
 
  private:
   void Free();
 
-  gpu::gles2::GLES2Interface* gl_;
+  ContextProvider* context_provider_ = nullptr;
   // The GL texture id.
   GLuint gl_id_ = 0;
   // Size of the resource in pixels.
   gfx::Size size_;
-  // A hint for texture-backed resources about how the resource will be used,
-  // that dictates how it should be allocated/used.
-  ResourceTextureHint hint_;
+  // When true, and immutable textures are used, this specifies to
+  // generate mipmaps at powers of 2.
+  bool mipmap_ = false;
   // TODO(xing.xu): Remove this and set the color space when we draw the
   // RenderPassDrawQuad.
   gfx::ColorSpace color_space_;
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 022a2a7..ee33324a 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -767,15 +767,12 @@
       continue;
     }
 
-    gfx::Size required_size = render_pass_it->second.size;
-    ResourceTextureHint required_hint = render_pass_it->second.hint;
-
+    const RenderPassRequirements& requirements = render_pass_it->second;
     const RenderPassBacking& backing = pair.second;
-    bool size_appropriate = backing.size.width() >= required_size.width() &&
-                            backing.size.height() >= required_size.height();
-    bool hint_appropriate =
-        (backing.usage_hint & required_hint) == required_hint;
-    if (!size_appropriate || !hint_appropriate)
+    bool size_appropriate = backing.size.width() >= requirements.size.width() &&
+                            backing.size.height() >= requirements.size.height();
+    bool mipmap_appropriate = !requirements.mipmap || backing.mipmap;
+    if (!size_appropriate || !mipmap_appropriate)
       passes_to_delete.push_back(pair.first);
   }
 
@@ -794,8 +791,7 @@
 
 void SkiaRenderer::AllocateRenderPassResourceIfNeeded(
     const RenderPassId& render_pass_id,
-    const gfx::Size& enlarged_size,
-    ResourceTextureHint texture_hint) {
+    const RenderPassRequirements& requirements) {
 #if BUILDFLAG(ENABLE_VULKAN)
   NOTIMPLEMENTED();
   return;
@@ -816,11 +812,11 @@
   gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+  // This texture will be bound as a framebuffer, so optimize for that.
   if (caps.texture_usage) {
-    if (texture_hint & ResourceTextureHint::kFramebuffer) {
-      gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE,
-                        GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
-    }
+    gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE,
+                      GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
   }
 
   ResourceFormat backbuffer_format;
@@ -843,26 +839,24 @@
     // If |texture_npot| is availble, and mipmaps are desired, we generate a
     // mipmap for each power of 2 size. This is only done when using
     // TexStorage2DEXT.
-    if (caps.texture_npot) {
-      if (texture_hint & ResourceTextureHint::kMipmap) {
-        levels += base::bits::Log2Floor(
-            std::max(enlarged_size.width(), enlarged_size.height()));
-      }
+    if (caps.texture_npot && requirements.mipmap) {
+      levels += base::bits::Log2Floor(
+          std::max(requirements.size.width(), requirements.size.height()));
     }
     gl->TexStorage2DEXT(GL_TEXTURE_2D, levels,
                         TextureStorageFormat(backbuffer_format),
-                        enlarged_size.width(), enlarged_size.height());
+                        requirements.size.width(), requirements.size.height());
   } else {
     gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(backbuffer_format),
-                   enlarged_size.width(), enlarged_size.height(), 0,
+                   requirements.size.width(), requirements.size.height(), 0,
                    GLDataFormat(backbuffer_format),
                    GLDataType(backbuffer_format), nullptr);
   }
 
   RenderPassBacking& backing = render_pass_backings_[render_pass_id];
   backing.gl_id = texture_id;
-  backing.size = enlarged_size;
-  backing.usage_hint = texture_hint;
+  backing.size = requirements.size;
+  backing.mipmap = requirements.mipmap;
   backing.format = backbuffer_format;
   backing.color_space = current_frame()->current_render_pass->color_space;
   gl->BindTexture(GL_TEXTURE_2D, 0);
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index bec5cc8..18358d4 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -48,8 +48,7 @@
           render_passes_in_frame) override;
   void AllocateRenderPassResourceIfNeeded(
       const RenderPassId& render_pass_id,
-      const gfx::Size& enlarged_size,
-      ResourceTextureHint texture_hint) override;
+      const RenderPassRequirements& requirements) override;
   bool IsRenderPassResourceAllocated(
       const RenderPassId& render_pass_id) const override;
   gfx::Size GetRenderPassTextureSize(
@@ -104,7 +103,7 @@
   struct RenderPassBacking {
     uint32_t gl_id;
     gfx::Size size;
-    ResourceTextureHint usage_hint;
+    bool mipmap;
     ResourceFormat format;
     gfx::ColorSpace color_space;
   };
diff --git a/components/viz/service/display/software_renderer.cc b/components/viz/service/display/software_renderer.cc
index 7d7805b..d6512e35 100644
--- a/components/viz/service/display/software_renderer.cc
+++ b/components/viz/service/display/software_renderer.cc
@@ -813,21 +813,22 @@
 
 void SoftwareRenderer::AllocateRenderPassResourceIfNeeded(
     const RenderPassId& render_pass_id,
-    const gfx::Size& enlarged_size,
-    ResourceTextureHint texture_hint) {
+    const RenderPassRequirements& requirements) {
   auto it = render_pass_bitmaps_.find(render_pass_id);
   if (it != render_pass_bitmaps_.end())
     return;
 
-  // The |texture_hint| is only used for gpu-based rendering, so not used here.
+  // The |requirements.mipmap| is only used for gpu-based rendering, so not used
+  // here.
   //
   // ColorSpace correctness for software compositing is a performance nightmare,
   // so we don't do it. If we did, then the color space of the current frame's
   // |current_render_pass| should be stored somewhere, but we should not set it
   // on the bitmap itself. Instead, we'd use it with a SkColorSpaceXformCanvas
   // that wraps the SkCanvas drawing into the bitmap.
-  SkImageInfo info = SkImageInfo::MakeN32(
-      enlarged_size.width(), enlarged_size.height(), kPremul_SkAlphaType);
+  SkImageInfo info =
+      SkImageInfo::MakeN32(requirements.size.width(),
+                           requirements.size.height(), kPremul_SkAlphaType);
   SkBitmap bitmap;
   bitmap.allocPixels(info);
   render_pass_bitmaps_.emplace(render_pass_id, std::move(bitmap));
diff --git a/components/viz/service/display/software_renderer.h b/components/viz/service/display/software_renderer.h
index f4670cf8..adfc0c0 100644
--- a/components/viz/service/display/software_renderer.h
+++ b/components/viz/service/display/software_renderer.h
@@ -46,8 +46,7 @@
           render_passes_in_frame) override;
   void AllocateRenderPassResourceIfNeeded(
       const RenderPassId& render_pass_id,
-      const gfx::Size& enlarged_size,
-      ResourceTextureHint texturehint) override;
+      const RenderPassRequirements& requirements) override;
   bool IsRenderPassResourceAllocated(
       const RenderPassId& render_pass_id) const override;
   gfx::Size GetRenderPassTextureSize(
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 0f8103dc..9285fc7 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -956,6 +956,8 @@
     "keyboard_lock/keyboard_lock_service_impl.h",
     "leveldb_wrapper_impl.cc",
     "leveldb_wrapper_impl.h",
+    "loader/async_resource_handler.cc",
+    "loader/async_resource_handler.h",
     "loader/cross_site_document_resource_handler.cc",
     "loader/cross_site_document_resource_handler.h",
     "loader/detachable_resource_handler.cc",
@@ -1001,6 +1003,8 @@
     "loader/resource_loader.cc",
     "loader/resource_loader.h",
     "loader/resource_loader_delegate.h",
+    "loader/resource_message_delegate.cc",
+    "loader/resource_message_delegate.h",
     "loader/resource_message_filter.cc",
     "loader/resource_message_filter.h",
     "loader/resource_request_info_impl.cc",
@@ -1015,6 +1019,8 @@
     "loader/stream_resource_handler.h",
     "loader/stream_writer.cc",
     "loader/stream_writer.h",
+    "loader/sync_resource_handler.cc",
+    "loader/sync_resource_handler.h",
     "loader/temporary_file_stream.cc",
     "loader/temporary_file_stream.h",
     "loader/throttling_resource_handler.cc",
diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc
new file mode 100644
index 0000000..aeea9dc4
--- /dev/null
+++ b/content/browser/loader/async_resource_handler.cc
@@ -0,0 +1,440 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/loader/async_resource_handler.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/debug/alias.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/shared_memory.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "content/browser/loader/resource_buffer.h"
+#include "content/browser/loader/resource_controller.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_message_filter.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/common/resource_messages.h"
+#include "content/common/view_messages.h"
+#include "content/network/upload_progress_tracker.h"
+#include "content/public/common/resource_response.h"
+#include "ipc/ipc_message_macros.h"
+#include "net/base/io_buffer.h"
+#include "net/base/load_flags.h"
+#include "net/base/upload_progress.h"
+#include "net/url_request/redirect_info.h"
+#include "services/network/public/cpp/url_loader_completion_status.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace content {
+namespace {
+
+static int g_async_loader_buffer_size = 1024 * 512;
+static int g_async_loader_min_buffer_allocation_size = 1024 * 4;
+static int g_async_loader_max_buffer_allocation_size = 1024 * 32;
+
+}  // namespace
+
+// Used to write into an existing IOBuffer at a given offset. This is
+// very similar to DependentIOBufferForRedirectToFile and
+// DependentIOBufferForMimeSniffing but not identical.
+class DependentIOBufferForAsyncLoading : public net::WrappedIOBuffer {
+ public:
+  DependentIOBufferForAsyncLoading(ResourceBuffer* backing, char* memory)
+      : net::WrappedIOBuffer(memory), backing_(backing) {}
+
+ private:
+  ~DependentIOBufferForAsyncLoading() override {}
+  scoped_refptr<ResourceBuffer> backing_;
+};
+
+AsyncResourceHandler::AsyncResourceHandler(net::URLRequest* request,
+                                           ResourceDispatcherHostImpl* rdh)
+    : ResourceHandler(request),
+      ResourceMessageDelegate(request),
+      rdh_(rdh),
+      pending_data_count_(0),
+      allocation_size_(0),
+      total_read_body_bytes_(0),
+      has_checked_for_sufficient_resources_(false),
+      sent_received_response_msg_(false),
+      sent_data_buffer_msg_(false),
+      reported_transfer_size_(0) {
+  DCHECK(GetRequestInfo()->requester_info()->IsRenderer());
+  InitializeResourceBufferConstants();
+}
+
+AsyncResourceHandler::~AsyncResourceHandler() {
+  if (has_checked_for_sufficient_resources_)
+    rdh_->FinishedWithResourcesForRequest(request());
+}
+
+void AsyncResourceHandler::InitializeResourceBufferConstants() {
+  static bool did_init = false;
+  if (did_init)
+    return;
+  did_init = true;
+
+  GetNumericArg("resource-buffer-size", &g_async_loader_buffer_size);
+  GetNumericArg("resource-buffer-min-allocation-size",
+                &g_async_loader_min_buffer_allocation_size);
+  GetNumericArg("resource-buffer-max-allocation-size",
+                &g_async_loader_max_buffer_allocation_size);
+}
+
+bool AsyncResourceHandler::OnMessageReceived(const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(AsyncResourceHandler, message)
+    IPC_MESSAGE_HANDLER(ResourceHostMsg_FollowRedirect, OnFollowRedirect)
+    IPC_MESSAGE_HANDLER(ResourceHostMsg_DataReceived_ACK, OnDataReceivedACK)
+    IPC_MESSAGE_HANDLER(ResourceHostMsg_UploadProgress_ACK, OnUploadProgressACK)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void AsyncResourceHandler::OnFollowRedirect(int request_id) {
+  if (!request()->status().is_success()) {
+    DVLOG(1) << "OnFollowRedirect for invalid request";
+    return;
+  }
+
+  ResumeIfDeferred();
+}
+
+void AsyncResourceHandler::OnDataReceivedACK(int request_id) {
+  if (pending_data_count_) {
+    --pending_data_count_;
+
+    buffer_->RecycleLeastRecentlyAllocated();
+    if (buffer_->CanAllocate())
+      ResumeIfDeferred();
+  }
+}
+
+void AsyncResourceHandler::OnUploadProgressACK(int request_id) {
+  if (upload_progress_tracker_)
+    upload_progress_tracker_->OnAckReceived();
+}
+
+void AsyncResourceHandler::OnRequestRedirected(
+    const net::RedirectInfo& redirect_info,
+    ResourceResponse* response,
+    std::unique_ptr<ResourceController> controller) {
+  ResourceMessageFilter* filter = GetFilter();
+  if (!filter) {
+    controller->Cancel();
+    return;
+  }
+
+  response->head.encoded_data_length = request()->GetTotalReceivedBytes();
+  reported_transfer_size_ = 0;
+  response->head.request_start = request()->creation_time();
+  response->head.response_start = TimeTicks::Now();
+  // TODO(davidben): Is it necessary to pass the new first party URL for
+  // cookies? The only case where it can change is top-level navigation requests
+  // and hopefully those will eventually all be owned by the browser. It's
+  // possible this is still needed while renderer-owned ones exist.
+  if (filter->Send(new ResourceMsg_ReceivedRedirect(
+          GetRequestID(), redirect_info, response->head))) {
+    OnDefer(std::move(controller));
+  } else {
+    controller->Cancel();
+  }
+}
+
+void AsyncResourceHandler::OnResponseStarted(
+    ResourceResponse* response,
+    std::unique_ptr<ResourceController> controller) {
+  // For changes to the main frame, inform the renderer of the new URL's
+  // per-host settings before the request actually commits.  This way the
+  // renderer will be able to set these precisely at the time the
+  // request commits, avoiding the possibility of e.g. zooming the old content
+  // or of having to layout the new content twice.
+  DCHECK(!has_controller());
+
+  response_started_ticks_ = base::TimeTicks::Now();
+
+  // We want to send a final upload progress message prior to sending the
+  // response complete message even if we're waiting for an ack to to a
+  // previous upload progress message.
+  if (upload_progress_tracker_) {
+    upload_progress_tracker_->OnUploadCompleted();
+    upload_progress_tracker_ = nullptr;
+  }
+
+  const ResourceRequestInfoImpl* info = GetRequestInfo();
+  ResourceMessageFilter* filter = GetFilter();
+  if (!filter) {
+    controller->Cancel();
+    return;
+  }
+
+  response->head.encoded_data_length = request()->raw_header_size();
+
+  // If the parent handler downloaded the resource to a file, grant the child
+  // read permissions on it.
+  if (!response->head.download_file_path.empty()) {
+    rdh_->RegisterDownloadedTempFile(
+        info->GetChildID(), info->GetRequestID(),
+        response->head.download_file_path);
+  }
+
+  response->head.request_start = request()->creation_time();
+  response->head.response_start = TimeTicks::Now();
+  filter->Send(
+      new ResourceMsg_ReceivedResponse(GetRequestID(), response->head));
+  sent_received_response_msg_ = true;
+
+  if (request()->response_info().metadata.get()) {
+    std::vector<uint8_t> copy(request()->response_info().metadata->data(),
+                              request()->response_info().metadata->data() +
+                                  request()->response_info().metadata->size());
+    filter->Send(new ResourceMsg_ReceivedCachedMetadata(GetRequestID(), copy));
+  }
+
+  controller->Resume();
+}
+
+void AsyncResourceHandler::OnWillStart(
+    const GURL& url,
+    std::unique_ptr<ResourceController> controller) {
+  ResourceMessageFilter* filter = GetFilter();
+  if (!filter) {
+    controller->Cancel();
+    return;
+  }
+
+  if (GetRequestInfo()->is_upload_progress_enabled() &&
+      request()->has_upload()) {
+    upload_progress_tracker_ = std::make_unique<UploadProgressTracker>(
+        FROM_HERE,
+        base::BindRepeating(&AsyncResourceHandler::SendUploadProgress,
+                            base::Unretained(this)),
+        request());
+  }
+  controller->Resume();
+}
+
+void AsyncResourceHandler::OnWillRead(
+    scoped_refptr<net::IOBuffer>* buf,
+    int* buf_size,
+    std::unique_ptr<ResourceController> controller) {
+  DCHECK(!has_controller());
+
+  if (!CheckForSufficientResource()) {
+    controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
+    return;
+  }
+
+  if (!EnsureResourceBufferIsInitialized()) {
+    controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
+    return;
+  }
+
+  DCHECK(buffer_->CanAllocate());
+  char* memory = buffer_->Allocate(&allocation_size_);
+  CHECK(memory);
+
+  *buf = new DependentIOBufferForAsyncLoading(buffer_.get(), memory);
+  *buf_size = allocation_size_;
+
+  controller->Resume();
+}
+
+void AsyncResourceHandler::OnReadCompleted(
+    int bytes_read,
+    std::unique_ptr<ResourceController> controller) {
+  DCHECK(!has_controller());
+  DCHECK_GE(bytes_read, 0);
+
+  if (!bytes_read) {
+    controller->Resume();
+    return;
+  }
+
+  ResourceMessageFilter* filter = GetFilter();
+  if (!filter) {
+    controller->Cancel();
+    return;
+  }
+
+  int encoded_data_length = CalculateEncodedDataLengthToReport();
+  if (!first_chunk_read_)
+    encoded_data_length -= request()->raw_header_size();
+
+  first_chunk_read_ = true;
+
+  buffer_->ShrinkLastAllocation(bytes_read);
+
+  total_read_body_bytes_ += bytes_read;
+
+  if (!sent_data_buffer_msg_) {
+    base::SharedMemoryHandle handle = base::SharedMemory::DuplicateHandle(
+        buffer_->GetSharedMemory().handle());
+    if (!base::SharedMemory::IsHandleValid(handle)) {
+      controller->Cancel();
+      return;
+    }
+    filter->Send(new ResourceMsg_SetDataBuffer(
+        GetRequestID(), handle, buffer_->GetSharedMemory().mapped_size()));
+    sent_data_buffer_msg_ = true;
+  }
+
+  int data_offset = buffer_->GetLastAllocationOffset();
+
+  filter->Send(new ResourceMsg_DataReceived(GetRequestID(), data_offset,
+                                            bytes_read, encoded_data_length));
+  ++pending_data_count_;
+
+  if (!buffer_->CanAllocate()) {
+    OnDefer(std::move(controller));
+  } else {
+    controller->Resume();
+  }
+}
+
+void AsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) {
+  int encoded_data_length = CalculateEncodedDataLengthToReport();
+
+  ResourceMessageFilter* filter = GetFilter();
+  if (filter) {
+    filter->Send(new ResourceMsg_DataDownloaded(
+        GetRequestID(), bytes_downloaded, encoded_data_length));
+  }
+}
+
+void AsyncResourceHandler::OnResponseCompleted(
+    const net::URLRequestStatus& request_status,
+    std::unique_ptr<ResourceController> controller) {
+  ResourceMessageFilter* filter = GetFilter();
+  if (!filter) {
+    controller->Resume();
+    return;
+  }
+
+  // Ensure sending the final upload progress message here, since
+  // OnResponseCompleted can be called without OnResponseStarted on cancellation
+  // or error cases.
+  if (upload_progress_tracker_) {
+    upload_progress_tracker_->OnUploadCompleted();
+    upload_progress_tracker_ = nullptr;
+  }
+
+  // If we crash here, figure out what URL the renderer was requesting.
+  // http://crbug.com/107692
+  char url_buf[128];
+  base::strlcpy(url_buf, request()->url().spec().c_str(), arraysize(url_buf));
+  base::debug::Alias(url_buf);
+
+  // TODO(gavinp): Remove this CHECK when we figure out the cause of
+  // http://crbug.com/124680 . This check mirrors closely check in
+  // WebURLLoaderImpl::OnCompletedRequest that routes this message to a WebCore
+  // ResourceHandleInternal which asserts on its state and crashes. By crashing
+  // when the message is sent, we should get better crash reports.
+  CHECK(request_status.status() != net::URLRequestStatus::SUCCESS ||
+        sent_received_response_msg_);
+
+  int error_code = request_status.error();
+
+  DCHECK(request_status.status() != net::URLRequestStatus::IO_PENDING);
+
+  network::URLLoaderCompletionStatus loader_status;
+  loader_status.error_code = error_code;
+  loader_status.exists_in_cache = request()->response_info().was_cached;
+  loader_status.completion_time = TimeTicks::Now();
+  loader_status.encoded_data_length = request()->GetTotalReceivedBytes();
+  loader_status.encoded_body_length = request()->GetRawBodyBytes();
+  loader_status.decoded_body_length = total_read_body_bytes_;
+  filter->Send(new ResourceMsg_RequestComplete(GetRequestID(), loader_status));
+
+  if (request_status.is_success())
+    RecordHistogram();
+  controller->Resume();
+}
+
+bool AsyncResourceHandler::EnsureResourceBufferIsInitialized() {
+  DCHECK(has_checked_for_sufficient_resources_);
+
+  if (buffer_.get() && buffer_->IsInitialized())
+    return true;
+
+  buffer_ = new ResourceBuffer();
+  return buffer_->Initialize(g_async_loader_buffer_size,
+                             g_async_loader_min_buffer_allocation_size,
+                             g_async_loader_max_buffer_allocation_size);
+}
+
+void AsyncResourceHandler::ResumeIfDeferred() {
+  if (has_controller()) {
+    request()->LogUnblocked();
+    Resume();
+  }
+}
+
+void AsyncResourceHandler::OnDefer(
+    std::unique_ptr<ResourceController> controller) {
+  HoldController(std::move(controller));
+  request()->LogBlockedBy("AsyncResourceHandler");
+}
+
+bool AsyncResourceHandler::CheckForSufficientResource() {
+  if (has_checked_for_sufficient_resources_)
+    return true;
+  has_checked_for_sufficient_resources_ = true;
+
+  if (rdh_->HasSufficientResourcesForRequest(request()))
+    return true;
+
+  return false;
+}
+
+int AsyncResourceHandler::CalculateEncodedDataLengthToReport() {
+  const auto transfer_size = request()->GetTotalReceivedBytes();
+  const auto difference =  transfer_size - reported_transfer_size_;
+  reported_transfer_size_ = transfer_size;
+  return difference;
+}
+
+void AsyncResourceHandler::RecordHistogram() {
+  int64_t elapsed_time =
+      (base::TimeTicks::Now() - response_started_ticks_).InMicroseconds();
+  int64_t encoded_length = request()->GetTotalReceivedBytes();
+  if (encoded_length < 2 * 1024) {
+    // The resource was smaller than the smallest required buffer size.
+    UMA_HISTOGRAM_CUSTOM_COUNTS("Net.ResourceLoader.ResponseStartToEnd.LT_2kB",
+                                elapsed_time, 1, 100000, 100);
+  } else if (encoded_length < 32 * 1024) {
+    // The resource was smaller than single chunk.
+    UMA_HISTOGRAM_CUSTOM_COUNTS("Net.ResourceLoader.ResponseStartToEnd.LT_32kB",
+                                elapsed_time, 1, 100000, 100);
+  } else if (encoded_length < 512 * 1024) {
+    // The resource was smaller than single chunk.
+    UMA_HISTOGRAM_CUSTOM_COUNTS(
+        "Net.ResourceLoader.ResponseStartToEnd.LT_512kB",
+        elapsed_time, 1, 100000, 100);
+  } else {
+    UMA_HISTOGRAM_CUSTOM_COUNTS(
+        "Net.ResourceLoader.ResponseStartToEnd.Over_512kB",
+        elapsed_time, 1, 100000, 100);
+  }
+}
+
+void AsyncResourceHandler::SendUploadProgress(
+    const net::UploadProgress& progress) {
+  ResourceMessageFilter* filter = GetFilter();
+  if (!filter)
+    return;
+  filter->Send(new ResourceMsg_UploadProgress(
+      GetRequestID(), progress.position(), progress.size()));
+}
+
+}  // namespace content
diff --git a/content/browser/loader/async_resource_handler.h b/content/browser/loader/async_resource_handler.h
new file mode 100644
index 0000000..1ddccd83
--- /dev/null
+++ b/content/browser/loader/async_resource_handler.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_LOADER_ASYNC_RESOURCE_HANDLER_H_
+#define CONTENT_BROWSER_LOADER_ASYNC_RESOURCE_HANDLER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "content/browser/loader/resource_handler.h"
+#include "content/browser/loader/resource_message_delegate.h"
+#include "content/common/content_export.h"
+#include "net/base/io_buffer.h"
+#include "url/gurl.h"
+
+namespace net {
+class URLRequest;
+class UploadProgress;
+}
+
+namespace content {
+class ResourceBuffer;
+class ResourceController;
+class ResourceDispatcherHostImpl;
+class UploadProgressTracker;
+
+// Used to complete an asynchronous resource request in response to resource
+// load events from the resource dispatcher host.
+class CONTENT_EXPORT AsyncResourceHandler : public ResourceHandler,
+                                            public ResourceMessageDelegate {
+ public:
+  AsyncResourceHandler(net::URLRequest* request,
+                       ResourceDispatcherHostImpl* rdh);
+  ~AsyncResourceHandler() override;
+
+  bool OnMessageReceived(const IPC::Message& message) override;
+
+  // ResourceHandler implementation:
+  void OnRequestRedirected(
+      const net::RedirectInfo& redirect_info,
+      ResourceResponse* response,
+      std::unique_ptr<ResourceController> controller) override;
+  void OnResponseStarted(
+      ResourceResponse* response,
+      std::unique_ptr<ResourceController> controller) override;
+  void OnWillStart(const GURL& url,
+                   std::unique_ptr<ResourceController> controller) override;
+  void OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+                  int* buf_size,
+                  std::unique_ptr<ResourceController> controller) override;
+  void OnReadCompleted(int bytes_read,
+                       std::unique_ptr<ResourceController> controller) override;
+  void OnResponseCompleted(
+      const net::URLRequestStatus& status,
+      std::unique_ptr<ResourceController> controller) override;
+  void OnDataDownloaded(int bytes_downloaded) override;
+
+ private:
+  // IPC message handlers:
+  void OnFollowRedirect(int request_id);
+  void OnDataReceivedACK(int request_id);
+  void OnUploadProgressACK(int request_id);
+
+  bool EnsureResourceBufferIsInitialized();
+  void ResumeIfDeferred();
+  void OnDefer(std::unique_ptr<ResourceController> controller);
+  bool CheckForSufficientResource();
+  int CalculateEncodedDataLengthToReport();
+  int CalculateEncodedBodyLengthToReport();
+  void RecordHistogram();
+  void SendUploadProgress(const net::UploadProgress& progress);
+  static void InitializeResourceBufferConstants();
+
+  scoped_refptr<ResourceBuffer> buffer_;
+  ResourceDispatcherHostImpl* rdh_;
+
+  // Number of messages we've sent to the renderer that we haven't gotten an
+  // ACK for. This allows us to avoid having too many messages in flight.
+  int pending_data_count_;
+
+  int allocation_size_;
+
+  // Size of received body. Used for comparison with expected content size,
+  // which is reported to UMA.
+  int64_t total_read_body_bytes_;
+
+  bool first_chunk_read_ = false;
+
+  bool has_checked_for_sufficient_resources_;
+  bool sent_received_response_msg_;
+  bool sent_data_buffer_msg_;
+
+  base::TimeTicks response_started_ticks_;
+
+  std::unique_ptr<UploadProgressTracker> upload_progress_tracker_;
+
+  int64_t reported_transfer_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncResourceHandler);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_LOADER_ASYNC_RESOURCE_HANDLER_H_
diff --git a/content/browser/loader/async_resource_handler_browsertest.cc b/content/browser/loader/async_resource_handler_browsertest.cc
new file mode 100644
index 0000000..4dae1a2
--- /dev/null
+++ b/content/browser/loader/async_resource_handler_browsertest.cc
@@ -0,0 +1,111 @@
+// 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.
+
+#include "content/browser/loader/async_resource_handler.h"
+
+#include <stddef.h>
+#include <string>
+#include <utility>
+
+#include "base/format_macros.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+const char kPostPath[] = "/post";
+const char kRedirectPostPath[] = "/redirect";
+
+// ThreadSanitizer is too slow to perform the full upload, so tests
+// using that build get an easier test which might not show two distinct
+// progress events. See crbug.com/526985. In addition, OSX buildbots have
+// experienced slowdowns on this test (crbug.com/548819), give them the easier
+// test too.
+#if defined(THREAD_SANITIZER) || defined(OS_MACOSX)
+const size_t kPayloadSize = 1062882;  // 2*3^12
+#else
+const size_t kPayloadSize = 28697814;  // 2*3^15
+#endif
+
+std::unique_ptr<net::test_server::HttpResponse> HandlePostAndRedirectURLs(
+    const std::string& request_path,
+    const net::test_server::HttpRequest& request) {
+  std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
+      new net::test_server::BasicHttpResponse());
+  if (base::StartsWith(request.relative_url, kRedirectPostPath,
+                       base::CompareCase::SENSITIVE)) {
+    http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
+    http_response->AddCustomHeader("Location", kPostPath);
+    EXPECT_EQ(request.content.length(), kPayloadSize);
+    return std::move(http_response);
+  } else if (base::StartsWith(request.relative_url, kPostPath,
+                              base::CompareCase::SENSITIVE)) {
+    http_response->set_content("hello");
+    http_response->set_content_type("text/plain");
+    EXPECT_EQ(request.content.length(), kPayloadSize);
+    return std::move(http_response);
+  } else {
+    return std::unique_ptr<net::test_server::HttpResponse>();
+  }
+}
+
+}  // namespace
+
+// https://crbug.com/788748
+#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
+#define MAYBE_AsyncResourceHandlerBrowserTest \
+  DISABLED_AsyncResourceHandlerBrowserTest
+#else
+#define MAYBE_AsyncResourceHandlerBrowserTest AsyncResourceHandlerBrowserTest
+#endif  // defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
+class MAYBE_AsyncResourceHandlerBrowserTest : public ContentBrowserTest {};
+
+IN_PROC_BROWSER_TEST_F(MAYBE_AsyncResourceHandlerBrowserTest, UploadProgress) {
+  net::EmbeddedTestServer* test_server = embedded_test_server();
+  test_server->RegisterRequestHandler(
+      base::Bind(&HandlePostAndRedirectURLs, kPostPath));
+  ASSERT_TRUE(test_server->Start());
+
+  NavigateToURL(shell(),
+                test_server->GetURL("/loader/async_resource_handler.html"));
+
+  std::string js_result;
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      shell(), base::StringPrintf("WaitForAsyncXHR('%s', %" PRIuS ")",
+                                  kPostPath, kPayloadSize),
+      &js_result));
+  EXPECT_EQ(js_result, "success");
+}
+
+IN_PROC_BROWSER_TEST_F(MAYBE_AsyncResourceHandlerBrowserTest,
+                       UploadProgressRedirect) {
+  net::EmbeddedTestServer* test_server = embedded_test_server();
+  test_server->RegisterRequestHandler(
+      base::Bind(&HandlePostAndRedirectURLs, kRedirectPostPath));
+  ASSERT_TRUE(test_server->Start());
+
+  NavigateToURL(shell(),
+                test_server->GetURL("/loader/async_resource_handler.html"));
+
+  std::string js_result;
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      shell(), base::StringPrintf("WaitForAsyncXHR('%s', %" PRIuS ")",
+                                  kRedirectPostPath, kPayloadSize),
+      &js_result));
+  EXPECT_EQ(js_result, "success");
+}
+
+}  // namespace content
diff --git a/content/browser/loader/async_resource_handler_unittest.cc b/content/browser/loader/async_resource_handler_unittest.cc
new file mode 100644
index 0000000..ef8d97c
--- /dev/null
+++ b/content/browser/loader/async_resource_handler_unittest.cc
@@ -0,0 +1,311 @@
+// 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 "content/browser/loader/async_resource_handler.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/process/process.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_loader.h"
+#include "content/browser/loader/resource_loader_delegate.h"
+#include "content/browser/loader/resource_message_filter.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/common/resource_messages.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/previews_state.h"
+#include "content/public/common/resource_request.h"
+#include "content/public/common/resource_type.h"
+#include "content/public/test/mock_resource_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "net/ssl/client_cert_store.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+#include "net/url_request/url_request_test_job.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/common/page/page_visibility_state.mojom.h"
+#include "ui/base/page_transition_types.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+std::string GenerateHeader(size_t response_data_size) {
+  return base::StringPrintf(
+      "HTTP/1.1 200 OK\n"
+      "Content-type: text/html\n"
+      "Content-Length: %" PRIuS "\n",
+      response_data_size);
+}
+
+int64_t TotalReceivedBytes(size_t response_data_size) {
+  return response_data_size + GenerateHeader(response_data_size).size();
+}
+
+std::string GenerateData(size_t response_data_size) {
+  return std::string(response_data_size, 'a');
+}
+
+class TestProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+  TestProtocolHandler(size_t response_data_size)
+      : response_data_size_(response_data_size) {}
+
+  net::URLRequestJob* MaybeCreateJob(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const override {
+    return new net::URLRequestTestJob(request, network_delegate,
+                                      GenerateHeader(response_data_size_),
+                                      GenerateData(response_data_size_), true);
+  }
+
+ private:
+  size_t response_data_size_;
+};
+
+// A subclass of ResourceMessageFilter that records IPC messages that are sent.
+class RecordingResourceMessageFilter : public ResourceMessageFilter {
+ public:
+  RecordingResourceMessageFilter(ResourceContext* resource_context,
+                                 net::URLRequestContext* request_context)
+      : ResourceMessageFilter(
+            0,
+            nullptr,
+            nullptr,
+            nullptr,
+            nullptr,
+            base::Bind(&RecordingResourceMessageFilter::GetContexts,
+                       base::Unretained(this)),
+            BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)),
+        resource_context_(resource_context),
+        request_context_(request_context) {
+    InitializeForTest();
+    set_peer_process_for_testing(base::Process::Current());
+  }
+
+  const std::vector<std::unique_ptr<IPC::Message>>& messages() const {
+    return messages_;
+  }
+
+  // IPC::Sender implementation:
+  bool Send(IPC::Message* message) override {
+    // Unpickle the base::SharedMemoryHandle to avoid warnings about
+    // "MessageAttachmentSet destroyed with unconsumed descriptors".
+    if (message->type() == ResourceMsg_SetDataBuffer::ID) {
+      ResourceMsg_SetDataBuffer::Param params;
+      ResourceMsg_SetDataBuffer::Read(message, &params);
+    }
+    messages_.push_back(base::WrapUnique(message));
+    return true;
+  }
+
+ private:
+  ~RecordingResourceMessageFilter() override {}
+
+  void GetContexts(ResourceType resource_type,
+                   ResourceContext** resource_context,
+                   net::URLRequestContext** request_context) {
+    *resource_context = resource_context_;
+    *request_context = request_context_;
+  }
+
+  ResourceContext* const resource_context_;
+  net::URLRequestContext* const request_context_;
+  std::vector<std::unique_ptr<IPC::Message>> messages_;
+};
+
+class AsyncResourceHandlerTest : public ::testing::Test,
+                                 public ResourceLoaderDelegate {
+ protected:
+  AsyncResourceHandlerTest()
+      : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), context_(true) {}
+
+  void TearDown() override {
+    if (filter_)
+      filter_->OnChannelClosing();
+    // Prevent memory leaks.
+    filter_ = nullptr;
+    rdh_.Shutdown();
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void CreateRequestWithResponseDataSize(size_t response_data_size) {
+    test_job_factory_.SetProtocolHandler(
+        "test", std::make_unique<TestProtocolHandler>(response_data_size));
+    context_.set_job_factory(&test_job_factory_);
+    context_.Init();
+    std::unique_ptr<net::URLRequest> request =
+        context_.CreateRequest(GURL("test:test"), net::DEFAULT_PRIORITY,
+                               nullptr, TRAFFIC_ANNOTATION_FOR_TESTS);
+    resource_context_ = std::make_unique<MockResourceContext>(&context_);
+    filter_ =
+        new RecordingResourceMessageFilter(resource_context_.get(), &context_);
+    ResourceRequestInfoImpl* info = new ResourceRequestInfoImpl(
+        filter_->requester_info_for_test(),
+        0,                                 // route_id
+        -1,                                // frame_tree_node_id
+        0,                                 // origin_pid
+        0,                                 // request_id
+        0,                                 // render_frame_id
+        false,                             // is_main_frame
+        RESOURCE_TYPE_IMAGE,               // resource_type
+        ui::PAGE_TRANSITION_LINK,          // transition_type
+        false,                             // should_replace_current_entry
+        false,                             // is_download
+        false,                             // is_stream
+        false,                             // allow_download
+        false,                             // has_user_gesture
+        false,                             // enable load timing
+        false,                             // enable upload progress
+        false,                             // do_not_prompt_for_login
+        false,                             // keep_alive
+        blink::kWebReferrerPolicyDefault,  // referrer_policy
+        blink::mojom::PageVisibilityState::kVisible,  // visibility_state
+        resource_context_.get(),                      // context
+        false,                                        // report_raw_headers
+        true,                                         // is_async
+        PREVIEWS_OFF,                                 // previews_state
+        nullptr,                                      // body
+        false);  // initiated_in_secure_context
+    info->AssociateWithRequest(request.get());
+    std::unique_ptr<AsyncResourceHandler> handler =
+        std::make_unique<AsyncResourceHandler>(request.get(), &rdh_);
+    loader_ = std::make_unique<ResourceLoader>(std::move(request),
+                                               std::move(handler), this);
+  }
+
+  void StartRequestAndWaitWithResponseDataSize(size_t response_data_size) {
+    CreateRequestWithResponseDataSize(response_data_size);
+    loader_->StartRequest();
+    finish_waiter_.reset(new base::RunLoop);
+    finish_waiter_->Run();
+  }
+
+  scoped_refptr<RecordingResourceMessageFilter> filter_;
+
+ private:
+  // ResourceLoaderDelegate implementation:
+  ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
+      ResourceLoader* loader,
+      net::AuthChallengeInfo* auth_info) override {
+    return nullptr;
+  }
+
+  bool HandleExternalProtocol(ResourceLoader* loader,
+                              const GURL& url) override {
+    return false;
+  }
+  void DidStartRequest(ResourceLoader* loader) override {}
+  void DidReceiveRedirect(ResourceLoader* loader,
+                          const GURL& new_url,
+                          ResourceResponse* response) override {}
+  void DidReceiveResponse(ResourceLoader* loader,
+                          ResourceResponse* response) override {}
+  void DidFinishLoading(ResourceLoader* loader) override {
+    loader_.reset();
+    finish_waiter_->Quit();
+  }
+  std::unique_ptr<net::ClientCertStore> CreateClientCertStore(
+      ResourceLoader* loader) override {
+    return nullptr;
+  }
+
+  TestBrowserThreadBundle thread_bundle_;
+  ResourceDispatcherHostImpl rdh_;
+  net::TestURLRequestContext context_;
+  net::URLRequestJobFactoryImpl test_job_factory_;
+  std::unique_ptr<MockResourceContext> resource_context_;
+  std::unique_ptr<ResourceLoader> loader_;
+  std::unique_ptr<base::RunLoop> finish_waiter_;
+};
+
+TEST_F(AsyncResourceHandlerTest, Construct) {
+  CreateRequestWithResponseDataSize(1);
+}
+
+TEST_F(AsyncResourceHandlerTest, OneChunkLengths) {
+  // Larger than kInlinedLeadingChunkSize and smaller than
+  // kMaxAllocationSize.
+  constexpr auto kDataSize = 4096;
+  StartRequestAndWaitWithResponseDataSize(kDataSize);
+  const auto& messages = filter_->messages();
+  ASSERT_EQ(4u, messages.size());
+  ASSERT_EQ(static_cast<uint32_t>(ResourceMsg_DataReceived::ID),
+            messages[2]->type());
+  ResourceMsg_DataReceived::Param params;
+  ResourceMsg_DataReceived::Read(messages[2].get(), &params);
+
+  int encoded_data_length = std::get<3>(params);
+  EXPECT_EQ(kDataSize, encoded_data_length);
+
+  ASSERT_EQ(static_cast<uint32_t>(ResourceMsg_RequestComplete::ID),
+            messages[3]->type());
+  ResourceMsg_RequestComplete::Param completion_params;
+  ResourceMsg_RequestComplete::Read(messages[3].get(), &completion_params);
+  network::URLLoaderCompletionStatus status = std::get<1>(completion_params);
+
+  EXPECT_EQ(TotalReceivedBytes(kDataSize), status.encoded_data_length);
+  EXPECT_EQ(kDataSize, status.encoded_body_length);
+}
+
+TEST_F(AsyncResourceHandlerTest, TwoChunksLengths) {
+  // Larger than kMaxAllocationSize.
+  constexpr auto kDataSize = 64 * 1024;
+  StartRequestAndWaitWithResponseDataSize(kDataSize);
+  const auto& messages = filter_->messages();
+  ASSERT_EQ(5u, messages.size());
+  ASSERT_EQ(static_cast<uint32_t>(ResourceMsg_DataReceived::ID),
+            messages[2]->type());
+  ResourceMsg_DataReceived::Param params;
+  ResourceMsg_DataReceived::Read(messages[2].get(), &params);
+
+  int encoded_data_length = std::get<3>(params);
+  EXPECT_EQ(32768, encoded_data_length);
+
+  ASSERT_EQ(static_cast<uint32_t>(ResourceMsg_DataReceived::ID),
+            messages[3]->type());
+  ResourceMsg_DataReceived::Read(messages[3].get(), &params);
+
+  encoded_data_length = std::get<3>(params);
+  EXPECT_EQ(32768, encoded_data_length);
+
+  ASSERT_EQ(static_cast<uint32_t>(ResourceMsg_RequestComplete::ID),
+            messages[4]->type());
+  ResourceMsg_RequestComplete::Param completion_params;
+  ResourceMsg_RequestComplete::Read(messages[4].get(), &completion_params);
+  network::URLLoaderCompletionStatus status = std::get<1>(completion_params);
+  EXPECT_EQ(TotalReceivedBytes(kDataSize), status.encoded_data_length);
+  EXPECT_EQ(kDataSize, status.encoded_body_length);
+}
+
+}  // namespace
+
+}  // namespace content
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 74bcb61..d767a79c 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -43,6 +43,7 @@
 #include "content/browser/browsing_data/clear_site_data_throttle.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/frame_host/navigation_request_info.h"
+#include "content/browser/loader/async_resource_handler.h"
 #include "content/browser/loader/cross_site_document_resource_handler.h"
 #include "content/browser/loader/detachable_resource_handler.h"
 #include "content/browser/loader/intercepting_resource_handler.h"
@@ -59,6 +60,7 @@
 #include "content/browser/loader/resource_requester_info.h"
 #include "content/browser/loader/resource_scheduler.h"
 #include "content/browser/loader/stream_resource_handler.h"
+#include "content/browser/loader/sync_resource_handler.h"
 #include "content/browser/loader/throttling_resource_handler.h"
 #include "content/browser/loader/upload_data_stream_builder.h"
 #include "content/browser/loader/wake_lock_resource_throttle.h"
@@ -72,6 +74,7 @@
 #include "content/browser/streams/stream_registry.h"
 #include "content/common/loader_util.h"
 #include "content/common/net/url_request_service_worker_data.h"
+#include "content/common/resource_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_child_process_host.h"
 #include "content/public/browser/browser_thread.h"
@@ -91,6 +94,8 @@
 #include "content/public/common/origin_util.h"
 #include "content/public/common/resource_request.h"
 #include "content/public/common/resource_request_body.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_start.h"
 #include "net/base/auth.h"
 #include "net/base/load_flags.h"
 #include "net/base/mime_util.h"
@@ -128,6 +133,8 @@
 using base::TimeDelta;
 using base::TimeTicks;
 using storage::ShareableFileReference;
+using SyncLoadResultCallback =
+    content::ResourceDispatcherHostImpl::SyncLoadResultCallback;
 
 // ----------------------------------------------------------------------------
 
@@ -170,8 +177,14 @@
 // Aborts a request before an URLRequest has actually been created.
 void AbortRequestBeforeItStarts(
     IPC::Sender* sender,
+    const SyncLoadResultCallback& sync_result_handler,
     int request_id,
     mojom::URLLoaderClientPtr url_loader_client) {
+  if (sync_result_handler) {
+    SyncLoadResult result;
+    result.error_code = net::ERR_ABORTED;
+    sync_result_handler.Run(&result);
+  } else {
     // Tell the renderer that this request was disallowed.
     network::URLLoaderCompletionStatus status;
     status.error_code = net::ERR_ABORTED;
@@ -180,7 +193,12 @@
     status.completion_time = base::TimeTicks();
     status.encoded_data_length = 0;
     status.encoded_body_length = 0;
-    url_loader_client->OnComplete(status);
+    if (url_loader_client) {
+      url_loader_client->OnComplete(status);
+    } else {
+      sender->Send(new ResourceMsg_RequestComplete(request_id, status));
+    }
+  }
 }
 
 void RemoveDownloadFileFromChildSecurityPolicy(int child_id,
@@ -220,6 +238,22 @@
   return previews_state;
 }
 
+// Sends back the result of a synchronous loading result to the renderer through
+// Chrome IPC.
+void HandleSyncLoadResult(base::WeakPtr<ResourceMessageFilter> filter,
+                          std::unique_ptr<IPC::Message> sync_result,
+                          const SyncLoadResult* result) {
+  if (!filter)
+    return;
+
+  if (result) {
+    ResourceHostMsg_SyncLoad::WriteReplyParams(sync_result.get(), *result);
+  } else {
+    sync_result->set_reply_error();
+  }
+  filter->Send(sync_result.release());
+}
+
 bool ValidatePluginChildId(int plugin_child_id) {
   if (plugin_child_id == ChildProcessHost::kInvalidUniqueID)
     return true;
@@ -720,6 +754,60 @@
   scheduler_.reset();
 }
 
+bool ResourceDispatcherHostImpl::OnMessageReceived(
+    const IPC::Message& message,
+    ResourceRequesterInfo* requester_info) {
+  DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
+
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ResourceDispatcherHostImpl, message,
+                                   requester_info)
+    IPC_MESSAGE_HANDLER(ResourceHostMsg_RequestResource, OnRequestResource)
+    IPC_MESSAGE_HANDLER_WITH_PARAM_DELAY_REPLY(ResourceHostMsg_SyncLoad,
+                                               OnSyncLoad)
+    IPC_MESSAGE_HANDLER(ResourceHostMsg_ReleaseDownloadedFile,
+                        OnReleaseDownloadedFile)
+    IPC_MESSAGE_HANDLER(ResourceHostMsg_CancelRequest, OnCancelRequest)
+    IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, OnDidChangePriority)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+
+  if (!handled && IPC_MESSAGE_ID_CLASS(message.type()) == ResourceMsgStart) {
+    base::PickleIterator iter(message);
+    int request_id = -1;
+    bool ok = iter.ReadInt(&request_id);
+    DCHECK(ok);
+    GlobalRequestID id(requester_info->child_id(), request_id);
+    DelegateMap::iterator it = delegate_map_.find(id);
+    if (it != delegate_map_.end()) {
+      for (auto& delegate : *it->second) {
+        if (delegate.OnMessageReceived(message)) {
+          handled = true;
+          break;
+        }
+      }
+    }
+
+    // As the unhandled resource message effectively has no consumer, mark it as
+    // handled to prevent needless propagation through the filter pipeline.
+    handled = true;
+  }
+
+  return handled;
+}
+
+void ResourceDispatcherHostImpl::OnRequestResource(
+    ResourceRequesterInfo* requester_info,
+    int routing_id,
+    int request_id,
+    const ResourceRequest& request_data,
+    net::MutableNetworkTrafficAnnotationTag traffic_annotation) {
+  OnRequestResourceInternal(
+      requester_info, routing_id, request_id, false /* is_sync_load */,
+      request_data, nullptr, nullptr,
+      net::NetworkTrafficAnnotationTag(traffic_annotation));
+}
+
 void ResourceDispatcherHostImpl::OnRequestResourceInternal(
     ResourceRequesterInfo* requester_info,
     int routing_id,
@@ -731,10 +819,31 @@
     const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK(requester_info->IsRenderer() || requester_info->IsNavigationPreload());
   BeginRequest(requester_info, request_id, request_data, is_sync_load,
-               routing_id, std::move(mojo_request),
+               SyncLoadResultCallback(), routing_id, std::move(mojo_request),
                std::move(url_loader_client), traffic_annotation);
 }
 
+// Begins a resource request with the given params on behalf of the specified
+// child process.  Responses will be dispatched through the given receiver. The
+// process ID is used to lookup WebContentsImpl from routing_id's in the case of
+// a request from a renderer.  request_context is the cookie/cache context to be
+// used for this request.
+//
+// If sync_result is non-null, then a SyncLoad reply will be generated, else
+// a normal asynchronous set of response messages will be generated.
+void ResourceDispatcherHostImpl::OnSyncLoad(
+    ResourceRequesterInfo* requester_info,
+    int request_id,
+    const ResourceRequest& request_data,
+    IPC::Message* sync_result) {
+  SyncLoadResultCallback callback =
+      base::Bind(&HandleSyncLoadResult, requester_info->filter()->GetWeakPtr(),
+                 base::Passed(WrapUnique(sync_result)));
+  BeginRequest(requester_info, request_id, request_data,
+               true /* is_sync_load */, callback, sync_result->routing_id(),
+               nullptr, nullptr, GetTrafficAnnotation());
+}
+
 bool ResourceDispatcherHostImpl::IsRequestIDInUse(
     const GlobalRequestID& id) const {
   if (pending_loaders_.find(id) != pending_loaders_.end())
@@ -802,6 +911,17 @@
       blocked_loaders_map_.erase(old_routing_id);
     }
   }
+  if (old_request_id != new_request_id) {
+    DelegateMap::iterator it = delegate_map_.find(old_request_id);
+    if (it != delegate_map_.end()) {
+      // Tell each delegate that the request ID has changed.
+      for (auto& delegate : *it->second)
+        delegate.set_request_id(new_request_id);
+      // Now store the observer list under the new request ID.
+      delegate_map_[new_request_id] = delegate_map_[old_request_id];
+      delegate_map_.erase(old_request_id);
+    }
+  }
 
   AppCacheInterceptor::CompleteCrossSiteTransfer(
       loader_ptr->request(), child_id, request_data.appcache_host_id,
@@ -879,6 +999,7 @@
     int request_id,
     const ResourceRequest& request_data,
     bool is_sync_load,
+    const SyncLoadResultCallback& sync_result_handler,  // only valid for sync
     int route_id,
     mojom::URLLoaderRequest mojo_request,
     mojom::URLLoaderClientPtr url_loader_client,
@@ -945,8 +1066,8 @@
   if (is_shutdown_ ||
       !ShouldServiceRequest(child_id, request_data, request_data.headers,
                             requester_info, resource_context)) {
-    AbortRequestBeforeItStarts(requester_info->filter(), request_id,
-                               std::move(url_loader_client));
+    AbortRequestBeforeItStarts(requester_info->filter(), sync_result_handler,
+                               request_id, std::move(url_loader_client));
     return;
   }
 
@@ -965,7 +1086,8 @@
         // will be used in UploadDataStream and ServiceWorkerURLRequestJob.
         if (!GetBodyBlobDataHandles(request_data.request_body.get(),
                                     resource_context, &blob_handles)) {
-          AbortRequestBeforeItStarts(requester_info->filter(), request_id,
+          AbortRequestBeforeItStarts(requester_info->filter(),
+                                     sync_result_handler, request_id,
                                      std::move(url_loader_client));
           return;
         }
@@ -995,8 +1117,9 @@
               base::Bind(
                   &ResourceDispatcherHostImpl::ContinuePendingBeginRequest,
                   base::Unretained(this), base::WrapRefCounted(requester_info),
-                  request_id, request_data, is_sync_load, route_id,
-                  request_data.headers, base::Passed(std::move(mojo_request)),
+                  request_id, request_data, is_sync_load, sync_result_handler,
+                  route_id, request_data.headers,
+                  base::Passed(std::move(mojo_request)),
                   base::Passed(std::move(url_loader_client)),
                   base::Passed(std::move(blob_handles)), traffic_annotation));
           return;
@@ -1004,11 +1127,12 @@
       }
     }
   }
-  ContinuePendingBeginRequest(
-      requester_info, request_id, request_data, is_sync_load, route_id,
-      request_data.headers, std::move(mojo_request),
-      std::move(url_loader_client), std::move(blob_handles), traffic_annotation,
-      HeaderInterceptorResult::CONTINUE);
+  ContinuePendingBeginRequest(requester_info, request_id, request_data,
+                              is_sync_load, sync_result_handler, route_id,
+                              request_data.headers, std::move(mojo_request),
+                              std::move(url_loader_client),
+                              std::move(blob_handles), traffic_annotation,
+                              HeaderInterceptorResult::CONTINUE);
 }
 
 void ResourceDispatcherHostImpl::ContinuePendingBeginRequest(
@@ -1016,6 +1140,7 @@
     int request_id,
     const ResourceRequest& request_data,
     bool is_sync_load,
+    const SyncLoadResultCallback& sync_result_handler,  // only valid for sync
     int route_id,
     const net::HttpRequestHeaders& headers,
     mojom::URLLoaderRequest mojo_request,
@@ -1024,6 +1149,7 @@
     const net::NetworkTrafficAnnotationTag& traffic_annotation,
     HeaderInterceptorResult interceptor_result) {
   DCHECK(requester_info->IsRenderer() || requester_info->IsNavigationPreload());
+  DCHECK(!sync_result_handler || is_sync_load);
   if (interceptor_result != HeaderInterceptorResult::CONTINUE) {
     if (requester_info->IsRenderer() &&
         interceptor_result == HeaderInterceptorResult::KILL) {
@@ -1033,8 +1159,8 @@
       bad_message::ReceivedBadMessage(requester_info->filter(),
                                       bad_message::RDH_ILLEGAL_ORIGIN);
     }
-    AbortRequestBeforeItStarts(requester_info->filter(), request_id,
-                               std::move(url_loader_client));
+    AbortRequestBeforeItStarts(requester_info->filter(), sync_result_handler,
+                               request_id, std::move(url_loader_client));
     return;
   }
   int child_id = requester_info->child_id();
@@ -1057,8 +1183,8 @@
                                                   request_data.url,
                                                   request_data.resource_type,
                                                   resource_context)) {
-    AbortRequestBeforeItStarts(requester_info->filter(), request_id,
-                               std::move(url_loader_client));
+    AbortRequestBeforeItStarts(requester_info->filter(), sync_result_handler,
+                               request_id, std::move(url_loader_client));
     return;
   }
 
@@ -1263,10 +1389,10 @@
         new_request.get(), requester_info->appcache_service(), child_id,
         request_data.appcache_host_id, request_data.resource_type,
         request_data.should_reset_appcache);
-    handler = CreateResourceHandler(requester_info.get(), new_request.get(),
-                                    request_data, route_id, child_id,
-                                    resource_context, std::move(mojo_request),
-                                    std::move(url_loader_client));
+    handler = CreateResourceHandler(
+        requester_info.get(), new_request.get(), request_data,
+        sync_result_handler, route_id, child_id, resource_context,
+        std::move(mojo_request), std::move(url_loader_client));
   }
   if (handler)
     BeginRequestInternal(std::move(new_request), std::move(handler));
@@ -1277,6 +1403,7 @@
     ResourceRequesterInfo* requester_info,
     net::URLRequest* request,
     const ResourceRequest& request_data,
+    const SyncLoadResultCallback& sync_result_handler,
     int route_id,
     int child_id,
     ResourceContext* resource_context,
@@ -1285,21 +1412,36 @@
   DCHECK(requester_info->IsRenderer() || requester_info->IsNavigationPreload());
   // Construct the IPC resource handler.
   std::unique_ptr<ResourceHandler> handler;
-  handler = CreateBaseResourceHandler(request, std::move(mojo_request),
-                                      std::move(url_loader_client),
-                                      request_data.resource_type);
+  if (sync_result_handler) {
+    // download_to_file is not supported for synchronous requests.
+    if (request_data.download_to_file) {
+      DCHECK(requester_info->IsRenderer());
+      bad_message::ReceivedBadMessage(requester_info->filter(),
+                                      bad_message::RDH_BAD_DOWNLOAD);
+      return std::unique_ptr<ResourceHandler>();
+    }
 
-  // The RedirectToFileResourceHandler depends on being next in the chain.
-  if (request_data.download_to_file) {
-    handler.reset(
-        new RedirectToFileResourceHandler(std::move(handler), request));
+    DCHECK(!mojo_request.is_pending());
+    DCHECK(!url_loader_client);
+    handler.reset(new SyncResourceHandler(request, sync_result_handler, this));
+  } else {
+    handler = CreateBaseResourceHandler(request, std::move(mojo_request),
+                                        std::move(url_loader_client),
+                                        request_data.resource_type);
+
+    // The RedirectToFileResourceHandler depends on being next in the chain.
+    if (request_data.download_to_file) {
+      handler.reset(
+          new RedirectToFileResourceHandler(std::move(handler), request));
+    }
   }
 
   bool start_detached = request_data.download_to_network_cache_only;
 
   // Prefetches and <a ping> requests outlive their child process.
-  if (start_detached || request_data.resource_type == RESOURCE_TYPE_PREFETCH ||
-      request_data.keepalive) {
+  if (!sync_result_handler &&
+      (start_detached || request_data.resource_type == RESOURCE_TYPE_PREFETCH ||
+       request_data.keepalive)) {
     auto timeout =
         base::TimeDelta::FromMilliseconds(kDefaultDetachableCancelDelayMs);
     int timeout_set_by_finch_in_sec = base::GetFieldTrialParamByFeatureAsInt(
@@ -1333,10 +1475,14 @@
     mojom::URLLoaderClientPtr url_loader_client,
     ResourceType resource_type) {
   std::unique_ptr<ResourceHandler> handler;
-  handler.reset(
-      new MojoAsyncResourceHandler(request, this, std::move(mojo_request),
-                                   std::move(url_loader_client), resource_type,
-                                   false));  // defer_on_response_started.
+  if (mojo_request.is_pending()) {
+    handler.reset(new MojoAsyncResourceHandler(
+        request, this, std::move(mojo_request), std::move(url_loader_client),
+        resource_type,
+        false));  // defer_on_response_started.
+  } else {
+    handler.reset(new AsyncResourceHandler(request, this));
+  }
   return handler;
 }
 
@@ -1450,6 +1596,27 @@
   return handler;
 }
 
+void ResourceDispatcherHostImpl::OnReleaseDownloadedFile(
+    ResourceRequesterInfo* requester_info,
+    int request_id) {
+  UnregisterDownloadedTempFile(requester_info->child_id(), request_id);
+}
+
+void ResourceDispatcherHostImpl::OnDidChangePriority(
+    ResourceRequesterInfo* requester_info,
+    int request_id,
+    net::RequestPriority new_priority,
+    int intra_priority_value) {
+  ResourceLoader* loader = GetLoader(requester_info->child_id(), request_id);
+  // The request may go away before processing this message, so |loader| can
+  // legitimately be null.
+  if (!loader)
+    return;
+
+  scheduler_->ReprioritizeRequest(loader->request(), new_priority,
+                                  intra_priority_value);
+}
+
 void ResourceDispatcherHostImpl::RegisterDownloadedTempFile(
     int child_id, int request_id, const base::FilePath& file_path) {
   scoped_refptr<ShareableFileReference> reference =
@@ -1486,6 +1653,18 @@
   // when all file refs are deleted (see RegisterDownloadedTempFile).
 }
 
+bool ResourceDispatcherHostImpl::Send(IPC::Message* message) {
+  delete message;
+  return false;
+}
+
+void ResourceDispatcherHostImpl::OnCancelRequest(
+    ResourceRequesterInfo* requester_info,
+    int request_id) {
+  CancelRequestFromRenderer(
+      GlobalRequestID(requester_info->child_id(), request_id));
+}
+
 ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
     int child_id,
     int render_view_route_id,
@@ -2455,6 +2634,31 @@
   return GetLoader(GlobalRequestID(child_id, request_id));
 }
 
+void ResourceDispatcherHostImpl::RegisterResourceMessageDelegate(
+    const GlobalRequestID& id, ResourceMessageDelegate* delegate) {
+  DelegateMap::iterator it = delegate_map_.find(id);
+  if (it == delegate_map_.end()) {
+    it = delegate_map_.insert(
+                           std::make_pair(
+                               id,
+                               new base::ObserverList<ResourceMessageDelegate>))
+             .first;
+  }
+  it->second->AddObserver(delegate);
+}
+
+void ResourceDispatcherHostImpl::UnregisterResourceMessageDelegate(
+    const GlobalRequestID& id, ResourceMessageDelegate* delegate) {
+  DCHECK(base::ContainsKey(delegate_map_, id));
+  DelegateMap::iterator it = delegate_map_.find(id);
+  DCHECK(it->second->HasObserver(delegate));
+  it->second->RemoveObserver(delegate);
+  if (!it->second->might_have_observers()) {
+    delete it->second;
+    delegate_map_.erase(it);
+  }
+}
+
 bool ResourceDispatcherHostImpl::ShouldServiceRequest(
     int child_id,
     const ResourceRequest& request_data,
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index d92a4e3..19b8912 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -38,6 +38,7 @@
 #include "content/public/common/request_context_type.h"
 #include "content/public/common/resource_type.h"
 #include "content/public/common/url_loader.mojom.h"
+#include "ipc/ipc_message.h"
 #include "net/base/load_states.h"
 #include "net/base/request_priority.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -86,6 +87,11 @@
     : public ResourceDispatcherHost,
       public ResourceLoaderDelegate {
  public:
+  // Used to handle the result of SyncLoad IPC. |result| is null if it's
+  // unavailable due to an error.
+  using SyncLoadResultCallback =
+      base::Callback<void(const SyncLoadResult* result)>;
+
   // This constructor should be used if we want downloads to work correctly.
   // TODO(ananta)
   // Work on moving creation of download handlers out of
@@ -120,6 +126,10 @@
   // for it are dead.
   void CancelRequestsForContext(ResourceContext* context);
 
+  // Returns true if the message was a resource message that was processed.
+  bool OnMessageReceived(const IPC::Message& message,
+                         ResourceRequesterInfo* requester_info);
+
   // Cancels the given request if it still exists.
   void CancelRequest(int child_id, int request_id);
 
@@ -198,6 +208,9 @@
       const base::FilePath& file_path);
   void UnregisterDownloadedTempFile(int child_id, int request_id);
 
+  // Needed for the sync IPC message dispatcher macros.
+  bool Send(IPC::Message* message);
+
   // Indicates whether third-party sub-content can pop-up HTTP basic auth
   // dialog boxes.
   bool allow_cross_origin_auth_prompt();
@@ -522,6 +535,13 @@
       const GlobalFrameRoutingId& global_routing_id,
       bool cancel_requests);
 
+  void OnRequestResource(
+      ResourceRequesterInfo* requester_info,
+      int routing_id,
+      int request_id,
+      const ResourceRequest& request_data,
+      net::MutableNetworkTrafficAnnotationTag traffic_annotation);
+
   void OnRequestResourceInternal(
       ResourceRequesterInfo* requester_info,
       int routing_id,
@@ -532,6 +552,11 @@
       mojom::URLLoaderClientPtr url_loader_client,
       const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
+  void OnSyncLoad(ResourceRequesterInfo* requester_info,
+                  int request_id,
+                  const ResourceRequest& request_data,
+                  IPC::Message* sync_result);
+
   bool IsRequestIDInUse(const GlobalRequestID& id) const;
 
   // Update the ResourceRequestInfo and internal maps when a request is
@@ -558,6 +583,7 @@
       int request_id,
       const ResourceRequest& request_data,
       bool is_sync_load,
+      const SyncLoadResultCallback& sync_result_handler,  // only valid for sync
       int route_id,
       mojom::URLLoaderRequest mojo_request,
       mojom::URLLoaderClientPtr url_loader_client,
@@ -576,6 +602,7 @@
       int request_id,
       const ResourceRequest& request_data,
       bool is_sync_load,
+      const SyncLoadResultCallback& sync_result_handler,  // only valid for sync
       int route_id,
       const net::HttpRequestHeaders& headers,
       mojom::URLLoaderRequest mojo_request,
@@ -590,6 +617,7 @@
       ResourceRequesterInfo* requester_info,
       net::URLRequest* request,
       const ResourceRequest& request_data,
+      const SyncLoadResultCallback& sync_result_handler,
       int route_id,
       int child_id,
       ResourceContext* resource_context,
@@ -623,6 +651,14 @@
       NavigationURLLoaderImplCore* navigation_loader_core,
       std::unique_ptr<StreamHandle> stream_handle);
 
+  void OnCancelRequest(ResourceRequesterInfo* requester_info, int request_id);
+  void OnReleaseDownloadedFile(ResourceRequesterInfo* requester_info,
+                               int request_id);
+  void OnDidChangePriority(ResourceRequesterInfo* requester_info,
+                           int request_id,
+                           net::RequestPriority new_priority,
+                           int intra_priority_value);
+
   // Creates ResourceRequestInfoImpl for a download or page save.
   // |download| should be true if the request is a file download.
   ResourceRequestInfoImpl* CreateRequestInfo(
@@ -655,6 +691,13 @@
   ResourceLoader* GetLoader(const GlobalRequestID& id) const;
   ResourceLoader* GetLoader(int child_id, int request_id) const;
 
+  // Registers |delegate| to receive resource IPC messages targeted to the
+  // specified |id|.
+  void RegisterResourceMessageDelegate(const GlobalRequestID& id,
+                                       ResourceMessageDelegate* delegate);
+  void UnregisterResourceMessageDelegate(const GlobalRequestID& id,
+                                         ResourceMessageDelegate* delegate);
+
   // Consults the RendererSecurity policy to determine whether the
   // ResourceDispatcherHostImpl should service this request.  A request might
   // be disallowed if the renderer is not authorized to retrieve the request
@@ -785,6 +828,10 @@
 
   bool allow_cross_origin_auth_prompt_;
 
+  typedef std::map<GlobalRequestID,
+                   base::ObserverList<ResourceMessageDelegate>*> DelegateMap;
+  DelegateMap delegate_map_;
+
   std::unique_ptr<ResourceScheduler> scheduler_;
 
   // Used to invoke an interceptor for the HTTP header.
diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc
index 3c27727..f8f3b77 100644
--- a/content/browser/loader/resource_loader_unittest.cc
+++ b/content/browser/loader/resource_loader_unittest.cc
@@ -33,6 +33,7 @@
 #include "content/public/test/test_renderer_host.h"
 #include "content/test/test_content_browser_client.h"
 #include "content/test/test_web_contents.h"
+#include "ipc/ipc_message.h"
 #include "net/base/chunked_upload_data_stream.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
diff --git a/content/browser/loader/resource_message_delegate.cc b/content/browser/loader/resource_message_delegate.cc
new file mode 100644
index 0000000..01d3595
--- /dev/null
+++ b/content/browser/loader/resource_message_delegate.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/loader/resource_message_delegate.h"
+
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "net/url_request/url_request.h"
+
+namespace content {
+
+ResourceMessageDelegate::ResourceMessageDelegate(const net::URLRequest* request)
+    : id_(ResourceRequestInfoImpl::ForRequest(request)->GetGlobalRequestID()) {
+  ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
+  rdh->RegisterResourceMessageDelegate(id_, this);
+}
+
+ResourceMessageDelegate::~ResourceMessageDelegate() {
+  ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
+  rdh->UnregisterResourceMessageDelegate(id_, this);
+}
+
+}  // namespace content
diff --git a/content/browser/loader/resource_message_delegate.h b/content/browser/loader/resource_message_delegate.h
new file mode 100644
index 0000000..f007f1c
--- /dev/null
+++ b/content/browser/loader/resource_message_delegate.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_H_
+#define CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_H_
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/global_request_id.h"
+
+namespace IPC {
+class Message;
+}
+
+namespace net {
+class URLRequest;
+}
+
+namespace content {
+
+// A ResourceMessageDelegate receives IPC ResourceMsg_* messages for a specified
+// URLRequest. The delegate should implement its own IPC handler. It will
+// receive the message _after_ the ResourceDispatcherHost has handled it.
+class CONTENT_EXPORT ResourceMessageDelegate {
+ public:
+  ResourceMessageDelegate(const net::URLRequest* request);
+  virtual ~ResourceMessageDelegate();
+
+  // Called when the ResourceDispatcherHostImpl receives a message specifically
+  // for this delegate.
+  virtual bool OnMessageReceived(const IPC::Message& message) = 0;
+
+  void set_request_id(const GlobalRequestID& new_request_id) {
+    id_ = new_request_id;
+  }
+
+ private:
+  GlobalRequestID id_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ResourceMessageDelegate);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_H_
diff --git a/content/browser/loader/resource_message_filter.cc b/content/browser/loader/resource_message_filter.cc
index 99d348a..88f35647 100644
--- a/content/browser/loader/resource_message_filter.cc
+++ b/content/browser/loader/resource_message_filter.cc
@@ -72,7 +72,10 @@
 
 bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) {
   DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
-  return false;
+  // Check if InitializeOnIOThread() has been called.
+  DCHECK_EQ(this, requester_info_->filter());
+  return ResourceDispatcherHostImpl::Get()->OnMessageReceived(
+      message, requester_info_.get());
 }
 
 void ResourceMessageFilter::OnDestruct() const {
diff --git a/content/browser/loader/sync_resource_handler.cc b/content/browser/loader/sync_resource_handler.cc
new file mode 100644
index 0000000..e65d9e5
--- /dev/null
+++ b/content/browser/loader/sync_resource_handler.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/loader/sync_resource_handler.h"
+
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "content/browser/loader/resource_controller.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/common/resource_messages.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
+#include "content/public/browser/resource_request_info.h"
+#include "net/base/io_buffer.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/redirect_info.h"
+
+namespace content {
+
+SyncResourceHandler::SyncResourceHandler(
+    net::URLRequest* request,
+    const SyncLoadResultCallback& result_handler,
+    ResourceDispatcherHostImpl* resource_dispatcher_host)
+    : ResourceHandler(request),
+      read_buffer_(new net::IOBuffer(kReadBufSize)),
+      result_handler_(result_handler),
+      rdh_(resource_dispatcher_host),
+      total_transfer_size_(0) {
+  result_.final_url = request->url();
+}
+
+SyncResourceHandler::~SyncResourceHandler() {
+  if (result_handler_)
+    result_handler_.Run(nullptr);
+}
+
+void SyncResourceHandler::OnRequestRedirected(
+    const net::RedirectInfo& redirect_info,
+    ResourceResponse* response,
+    std::unique_ptr<ResourceController> controller) {
+  if (rdh_->delegate()) {
+    rdh_->delegate()->OnRequestRedirected(
+        redirect_info.new_url, request(), GetRequestInfo()->GetContext(),
+        response);
+  }
+
+  // TODO(darin): It would be much better if this could live in WebCore, but
+  // doing so requires API changes at all levels.  Similar code exists in
+  // WebCore/platform/network/cf/ResourceHandleCFNet.cpp :-(
+  if (redirect_info.new_url.GetOrigin() != result_.final_url.GetOrigin()) {
+    LOG(ERROR) << "Cross origin redirect denied";
+    controller->Cancel();
+    return;
+  }
+  result_.final_url = redirect_info.new_url;
+
+  total_transfer_size_ += request()->GetTotalReceivedBytes();
+  controller->Resume();
+}
+
+void SyncResourceHandler::OnResponseStarted(
+    ResourceResponse* response,
+    std::unique_ptr<ResourceController> controller) {
+  ResourceRequestInfoImpl* info = GetRequestInfo();
+  DCHECK(info->requester_info()->IsRenderer());
+  if (!info->requester_info()->filter()) {
+    controller->Cancel();
+    return;
+  }
+
+  if (rdh_->delegate()) {
+    rdh_->delegate()->OnResponseStarted(request(), info->GetContext(),
+                                        response);
+  }
+
+  // We don't care about copying the status here.
+  result_.headers = response->head.headers;
+  result_.mime_type = response->head.mime_type;
+  result_.charset = response->head.charset;
+  result_.download_file_path = response->head.download_file_path;
+  result_.request_time = response->head.request_time;
+  result_.response_time = response->head.response_time;
+  result_.load_timing = response->head.load_timing;
+  result_.devtools_info = response->head.devtools_info;
+  result_.socket_address = response->head.socket_address;
+  controller->Resume();
+}
+
+void SyncResourceHandler::OnWillStart(
+    const GURL& url,
+    std::unique_ptr<ResourceController> controller) {
+  controller->Resume();
+}
+
+void SyncResourceHandler::OnWillRead(
+    scoped_refptr<net::IOBuffer>* buf,
+    int* buf_size,
+    std::unique_ptr<ResourceController> controller) {
+  *buf = read_buffer_.get();
+  *buf_size = kReadBufSize;
+  controller->Resume();
+}
+
+void SyncResourceHandler::OnReadCompleted(
+    int bytes_read,
+    std::unique_ptr<ResourceController> controller) {
+  if (bytes_read)
+    result_.data.append(read_buffer_->data(), bytes_read);
+  controller->Resume();
+}
+
+void SyncResourceHandler::OnResponseCompleted(
+    const net::URLRequestStatus& status,
+    std::unique_ptr<ResourceController> controller) {
+  result_.error_code = status.error();
+
+  int total_transfer_size = request()->GetTotalReceivedBytes();
+  result_.encoded_data_length = total_transfer_size_ + total_transfer_size;
+  result_.encoded_body_length = request()->GetRawBodyBytes();
+
+  base::ResetAndReturn(&result_handler_).Run(&result_);
+
+  controller->Resume();
+}
+
+void SyncResourceHandler::OnDataDownloaded(int bytes_downloaded) {
+  // Sync requests don't involve ResourceMsg_DataDownloaded messages
+  // being sent back to renderers as progress is made.
+}
+
+}  // namespace content
diff --git a/content/browser/loader/sync_resource_handler.h b/content/browser/loader/sync_resource_handler.h
new file mode 100644
index 0000000..881be7f
--- /dev/null
+++ b/content/browser/loader/sync_resource_handler.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_LOADER_SYNC_RESOURCE_HANDLER_H_
+#define CONTENT_BROWSER_LOADER_SYNC_RESOURCE_HANDLER_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_handler.h"
+#include "content/public/common/resource_response.h"
+
+namespace net {
+class IOBuffer;
+class URLRequest;
+}
+
+namespace content {
+class ResourceController;
+
+// Used to complete a synchronous resource request in response to resource load
+// events from the resource dispatcher host.
+class SyncResourceHandler : public ResourceHandler {
+ public:
+  using SyncLoadResultCallback =
+      ResourceDispatcherHostImpl::SyncLoadResultCallback;
+
+  SyncResourceHandler(net::URLRequest* request,
+                      const SyncLoadResultCallback& sync_result_handler,
+                      ResourceDispatcherHostImpl* resource_dispatcher_host);
+  ~SyncResourceHandler() override;
+
+  void OnRequestRedirected(
+      const net::RedirectInfo& redirect_info,
+      ResourceResponse* response,
+      std::unique_ptr<ResourceController> controller) override;
+  void OnResponseStarted(
+      ResourceResponse* response,
+      std::unique_ptr<ResourceController> controller) override;
+  void OnWillStart(const GURL& url,
+                   std::unique_ptr<ResourceController> controller) override;
+  void OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+                  int* buf_size,
+                  std::unique_ptr<ResourceController> controller) override;
+  void OnReadCompleted(int bytes_read,
+                       std::unique_ptr<ResourceController> controller) override;
+  void OnResponseCompleted(
+      const net::URLRequestStatus& status,
+      std::unique_ptr<ResourceController> controller) override;
+  void OnDataDownloaded(int bytes_downloaded) override;
+
+ private:
+  enum { kReadBufSize = 3840 };
+
+  scoped_refptr<net::IOBuffer> read_buffer_;
+
+  SyncLoadResult result_;
+  SyncLoadResultCallback result_handler_;
+  ResourceDispatcherHostImpl* rdh_;
+  int64_t total_transfer_size_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_LOADER_SYNC_RESOURCE_HANDLER_H_
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index f4e8b4b..6a42a43 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -7,7 +7,6 @@
 
 // IPC messages for resource loading.
 //
-// WE ARE DEPRECATING THIS FILE. DO NOT ADD A NEW MESSAGE.
 // NOTE: All messages must send an |int request_id| as their first parameter.
 
 #include <stdint.h>
@@ -260,4 +259,109 @@
   IPC_STRUCT_TRAITS_MEMBER(ssl_info)
 IPC_STRUCT_TRAITS_END()
 
+// Resource messages sent from the browser to the renderer.
+
+// Sent when the headers are available for a resource request.
+IPC_MESSAGE_CONTROL2(ResourceMsg_ReceivedResponse,
+                     int /* request_id */,
+                     content::ResourceResponseHead)
+
+// Sent when cached metadata from a resource request is ready.
+IPC_MESSAGE_CONTROL2(ResourceMsg_ReceivedCachedMetadata,
+                     int /* request_id */,
+                     std::vector<uint8_t> /* data */)
+
+// Sent as upload progress is being made.
+IPC_MESSAGE_CONTROL3(ResourceMsg_UploadProgress,
+                     int /* request_id */,
+                     int64_t /* position */,
+                     int64_t /* size */)
+
+// Sent when the request has been redirected.  The receiver is expected to
+// respond with either a FollowRedirect message (if the redirect is to be
+// followed) or a CancelRequest message (if it should not be followed).
+IPC_MESSAGE_CONTROL3(ResourceMsg_ReceivedRedirect,
+                     int /* request_id */,
+                     net::RedirectInfo /* redirect_info */,
+                     content::ResourceResponseHead)
+
+// Sent to set the shared memory buffer to be used to transmit response data to
+// the renderer.  Subsequent DataReceived messages refer to byte ranges in the
+// shared memory buffer.  The shared memory buffer should be retained by the
+// renderer until the resource request completes.
+//
+// NOTE: The shared memory handle should already be mapped into the process
+// that receives this message.
+IPC_MESSAGE_CONTROL3(ResourceMsg_SetDataBuffer,
+                     int /* request_id */,
+                     base::SharedMemoryHandle /* shm_handle */,
+                     int /* shm_size */)
+
+// Sent when some data from a resource request is ready.  The data offset and
+// length specify a byte range into the shared memory buffer provided by the
+// SetDataBuffer message.
+IPC_MESSAGE_CONTROL4(ResourceMsg_DataReceived,
+                     int /* request_id */,
+                     int /* data_offset */,
+                     int /* data_length */,
+                     int /* encoded_data_length */)
+
+// Sent when some data from a resource request has been downloaded to
+// file. This is only called in the 'download_to_file' case and replaces
+// ResourceMsg_DataReceived in the call sequence in that case.
+IPC_MESSAGE_CONTROL3(ResourceMsg_DataDownloaded,
+                     int /* request_id */,
+                     int /* data_len */,
+                     int /* encoded_data_length */)
+
+// Sent when the request has been completed.
+IPC_MESSAGE_CONTROL2(ResourceMsg_RequestComplete,
+                     int /* request_id */,
+                     network::URLLoaderCompletionStatus)
+
+// Resource messages sent from the renderer to the browser.
+
+// Makes a resource request via the browser.
+IPC_MESSAGE_CONTROL4(
+    ResourceHostMsg_RequestResource,
+    int /* routing_id */,
+    int /* request_id */,
+    content::ResourceRequest,
+    net::MutableNetworkTrafficAnnotationTag /* network_traffic_annotation */)
+
+// Cancels a resource request with the ID given as the parameter.
+IPC_MESSAGE_CONTROL1(ResourceHostMsg_CancelRequest,
+                     int /* request_id */)
+
+// Follows a redirect that occured for the resource request with the ID given
+// as the parameter.
+IPC_MESSAGE_CONTROL1(ResourceHostMsg_FollowRedirect,
+                     int /* request_id */)
+
+// Makes a synchronous resource request via the browser.
+IPC_SYNC_MESSAGE_ROUTED2_1(ResourceHostMsg_SyncLoad,
+                           int /* request_id */,
+                           content::ResourceRequest,
+                           content::SyncLoadResult)
+
+// Sent when the renderer process is done processing a DataReceived
+// message.
+IPC_MESSAGE_CONTROL1(ResourceHostMsg_DataReceived_ACK,
+                     int /* request_id */)
+
+// Sent by the renderer process to acknowledge receipt of a
+// UploadProgress message.
+IPC_MESSAGE_CONTROL1(ResourceHostMsg_UploadProgress_ACK,
+                     int /* request_id */)
+
+// Sent when the renderer process deletes a resource loader.
+IPC_MESSAGE_CONTROL1(ResourceHostMsg_ReleaseDownloadedFile,
+                     int /* request_id */)
+
+// Sent by the renderer when a resource request changes priority.
+IPC_MESSAGE_CONTROL3(ResourceHostMsg_DidChangePriority,
+                     int /* request_id */,
+                     net::RequestPriority,
+                     int /* intra_priority_value */)
+
 #endif  // CONTENT_COMMON_RESOURCE_MESSAGES_H_
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index efafce70..09569f88 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -232,7 +232,11 @@
       presentation_receiver(false),
       media_controls_enabled(true),
       do_not_update_selection_on_mutating_selection_range(false),
-      autoplay_policy(AutoplayPolicy::kDocumentUserActivationRequired) {
+#if defined(OS_ANDROID)
+      autoplay_policy(AutoplayPolicy::kUserGestureRequired) {
+#else
+      autoplay_policy(AutoplayPolicy::kNoUserGestureRequired) {
+#endif  // defined(OS_ANDROID)
   standard_font_family_map[kCommonScript] =
       base::ASCIIToUTF16("Times New Roman");
   fixed_font_family_map[kCommonScript] = base::ASCIIToUTF16("Courier New");
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 13b627c0..40741ec3 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -236,6 +236,8 @@
     "java/gin_java_function_invocation_helper.h",
     "layout_test_dependencies.cc",
     "layout_test_dependencies.h",
+    "loader/child_resource_message_filter.cc",
+    "loader/child_resource_message_filter.h",
     "loader/child_url_loader_factory_getter_impl.cc",
     "loader/child_url_loader_factory_getter_impl.h",
     "loader/cors_url_loader.cc",
@@ -248,8 +250,12 @@
     "loader/request_extra_data.h",
     "loader/resource_dispatcher.cc",
     "loader/resource_dispatcher.h",
+    "loader/resource_scheduling_filter.cc",
+    "loader/resource_scheduling_filter.h",
     "loader/shared_memory_data_consumer_handle.cc",
     "loader/shared_memory_data_consumer_handle.h",
+    "loader/shared_memory_received_data_factory.cc",
+    "loader/shared_memory_received_data_factory.h",
     "loader/site_isolation_stats_gatherer.cc",
     "loader/site_isolation_stats_gatherer.h",
     "loader/sync_load_context.cc",
@@ -413,6 +419,8 @@
     "sad_plugin.h",
     "savable_resources.cc",
     "savable_resources.h",
+    "scheduler/resource_dispatch_throttler.cc",
+    "scheduler/resource_dispatch_throttler.h",
     "screen_orientation/screen_orientation_dispatcher.cc",
     "screen_orientation/screen_orientation_dispatcher.h",
     "seccomp_sandbox_status_android.cc",
diff --git a/content/renderer/loader/child_resource_message_filter.cc b/content/renderer/loader/child_resource_message_filter.cc
new file mode 100644
index 0000000..542dc86f
--- /dev/null
+++ b/content/renderer/loader/child_resource_message_filter.cc
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/loader/child_resource_message_filter.h"
+
+#include "base/bind.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "content/common/resource_messages.h"
+#include "content/renderer/loader/resource_dispatcher.h"
+
+namespace content {
+
+ChildResourceMessageFilter::ChildResourceMessageFilter(
+    ResourceDispatcher* resource_dispatcher)
+    : main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      resource_dispatcher_(resource_dispatcher) {}
+
+ChildResourceMessageFilter::~ChildResourceMessageFilter() {}
+
+bool ChildResourceMessageFilter::OnMessageReceived(
+    const IPC::Message& message) {
+  if (message.type() == ResourceMsg_RequestComplete::ID ||
+      message.type() == ResourceMsg_ReceivedResponse::ID ||
+      message.type() == ResourceMsg_ReceivedRedirect::ID) {
+    main_thread_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&ResourceDispatcher::set_io_timestamp,
+                                  base::Unretained(resource_dispatcher_),
+                                  base::TimeTicks::Now()));
+  }
+  return false;
+}
+
+}  // namespace content
diff --git a/content/renderer/loader/child_resource_message_filter.h b/content/renderer/loader/child_resource_message_filter.h
new file mode 100644
index 0000000..a8315fc
--- /dev/null
+++ b/content/renderer/loader/child_resource_message_filter.h
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_LOADER_CHILD_RESOURCE_MESSAGE_FILTER_H_
+#define CONTENT_RENDERER_LOADER_CHILD_RESOURCE_MESSAGE_FILTER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "ipc/message_filter.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace content {
+class ResourceDispatcher;
+
+// Supplies ResourceDispatcher with timestamps for some resource messages.
+//
+// Background: ResourceDispatcher converts browser process time to child
+// process time. This is done to achieve coherent timeline. Conversion is
+// a linear transformation such that given browser process time range is
+// mapped to corresponding child process time range. Timestamps for child
+// process time range should be taken by IO thread when resource messages
+// arrive. Otherwise, timestamps may be affected by long rendering / JS task.
+//
+// When specific message is processed by this filter, new task charged
+// with timestamp is posted to main thread. This task is processed just before
+// resource message and invokes ResourceDispatcher::set_io_timestamp.
+class ChildResourceMessageFilter : public IPC::MessageFilter {
+ public:
+  explicit ChildResourceMessageFilter(ResourceDispatcher* resource_dispatcher);
+
+  // IPC::MessageFilter implementation.
+  bool OnMessageReceived(const IPC::Message& message) override;
+
+  void SetMainThreadTaskRunner(
+      scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) {
+    main_thread_task_runner_ = main_thread_task_runner;
+  }
+
+ private:
+  ~ChildResourceMessageFilter() override;
+
+  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+  ResourceDispatcher* resource_dispatcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChildResourceMessageFilter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_LOADER_CHILD_RESOURCE_MESSAGE_FILTER_H_
diff --git a/content/renderer/loader/request_extra_data.cc b/content/renderer/loader/request_extra_data.cc
index a18495c..6d0bbf1 100644
--- a/content/renderer/loader/request_extra_data.cc
+++ b/content/renderer/loader/request_extra_data.cc
@@ -7,6 +7,7 @@
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/resource_request.h"
 #include "content/public/common/service_worker_modes.h"
+#include "ipc/ipc_message.h"
 #include "third_party/WebKit/common/page/page_visibility_state.mojom.h"
 
 using blink::WebString;
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index abdc1df..4ca7da2 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -15,6 +15,7 @@
 #include "base/debug/stack_trace.h"
 #include "base/files/file_path.h"
 #include "base/memory/ptr_util.h"
+#include "base/memory/shared_memory.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
@@ -23,6 +24,7 @@
 #include "build/build_config.h"
 #include "content/common/inter_process_time_ticks_converter.h"
 #include "content/common/navigation_params.h"
+#include "content/common/resource_messages.h"
 #include "content/common/throttling_url_loader.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/resource_request.h"
@@ -32,6 +34,8 @@
 #include "content/public/renderer/request_peer.h"
 #include "content/public/renderer/resource_dispatcher_delegate.h"
 #include "content/renderer/loader/request_extra_data.h"
+#include "content/renderer/loader/resource_scheduling_filter.h"
+#include "content/renderer/loader/shared_memory_received_data_factory.h"
 #include "content/renderer/loader/site_isolation_stats_gatherer.h"
 #include "content/renderer/loader/sync_load_context.h"
 #include "content/renderer/loader/sync_load_response.h"
@@ -55,6 +59,14 @@
   *time = converter.ToLocalTimeTicks(remote_time).ToTimeTicks();
 }
 
+void CrashOnMapFailure() {
+#if defined(OS_WIN)
+  DWORD last_err = GetLastError();
+  base::debug::Alias(&last_err);
+#endif
+  CHECK(false);
+}
+
 void CheckSchemeForReferrerPolicy(const ResourceRequest& request) {
   if ((request.referrer_policy == Referrer::GetDefaultReferrerPolicy() ||
        request.referrer_policy ==
@@ -110,14 +122,53 @@
 }
 
 ResourceDispatcher::ResourceDispatcher(
+    IPC::Sender* sender,
     scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner)
-    : delegate_(nullptr),
+    : message_sender_(sender),
+      delegate_(nullptr),
+      io_timestamp_(base::TimeTicks()),
       thread_task_runner_(thread_task_runner),
       weak_factory_(this) {}
 
 ResourceDispatcher::~ResourceDispatcher() {
 }
 
+bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
+  if (!IsResourceDispatcherMessage(message)) {
+    return false;
+  }
+
+  int request_id;
+
+  base::PickleIterator iter(message);
+  if (!iter.ReadInt(&request_id)) {
+    NOTREACHED() << "malformed resource message";
+    return true;
+  }
+
+  PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+  if (!request_info) {
+    // Release resources in the message if it is a data message.
+    ReleaseResourcesInDataMessage(message);
+    return true;
+  }
+
+  if (request_info->is_deferred) {
+    request_info->deferred_message_queue.push_back(new IPC::Message(message));
+    return true;
+  }
+
+  // Make sure any deferred messages are dispatched before we dispatch more.
+  if (!request_info->deferred_message_queue.empty()) {
+    request_info->deferred_message_queue.push_back(new IPC::Message(message));
+    FlushDeferredMessages(request_id);
+    return true;
+  }
+
+  DispatchMessage(message);
+  return true;
+}
+
 ResourceDispatcher::PendingRequestInfo*
 ResourceDispatcher::GetPendingRequestInfo(int request_id) {
   PendingRequestMap::iterator it = pending_requests_.find(request_id);
@@ -136,6 +187,13 @@
     return;
 
   request_info->peer->OnUploadProgress(position, size);
+
+  // URLLoaderClientImpl has its own acknowledgement, and doesn't need the IPC
+  // message here.
+  if (!request_info->url_loader) {
+    // Acknowledge receipt
+    message_sender_->Send(new ResourceHostMsg_UploadProgress_ACK(request_id));
+  }
 }
 
 void ResourceDispatcher::OnReceivedResponse(
@@ -144,7 +202,7 @@
   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
   if (!request_info)
     return;
-  request_info->response_start = base::TimeTicks::Now();
+  request_info->response_start = ConsumeIOTimestamp();
 
   if (delegate_) {
     std::unique_ptr<RequestPeer> new_peer = delegate_->OnReceivedResponse(
@@ -184,6 +242,80 @@
   }
 }
 
+void ResourceDispatcher::OnSetDataBuffer(int request_id,
+                                         base::SharedMemoryHandle shm_handle,
+                                         int shm_size) {
+  TRACE_EVENT0("loader", "ResourceDispatcher::OnSetDataBuffer");
+  PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+  if (!request_info)
+    return;
+
+  bool shm_valid = base::SharedMemory::IsHandleValid(shm_handle);
+  CHECK((shm_valid && shm_size > 0) || (!shm_valid && !shm_size));
+
+  request_info->buffer.reset(
+      new base::SharedMemory(shm_handle, true));  // read only
+  request_info->received_data_factory =
+      base::MakeRefCounted<SharedMemoryReceivedDataFactory>(
+          message_sender_, request_id, request_info->buffer);
+
+  bool ok = request_info->buffer->Map(shm_size);
+  if (!ok) {
+    base::SharedMemoryHandle shm_handle_copy = shm_handle;
+    base::debug::Alias(&shm_handle_copy);
+
+    CrashOnMapFailure();
+    return;
+  }
+
+  // TODO(erikchen): Temporary debugging. http://crbug.com/527588.
+  CHECK_GE(shm_size, 0);
+  CHECK_LE(shm_size, 512 * 1024);
+  request_info->buffer_size = shm_size;
+}
+
+void ResourceDispatcher::OnReceivedData(int request_id,
+                                        int data_offset,
+                                        int data_length,
+                                        int encoded_data_length) {
+  TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedData");
+  DCHECK_GT(data_length, 0);
+  PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+  bool send_ack = true;
+  if (request_info && data_length > 0) {
+    CHECK(base::SharedMemory::IsHandleValid(request_info->buffer->handle()));
+    CHECK_GE(request_info->buffer_size, data_offset + data_length);
+
+    const char* data_start = static_cast<char*>(request_info->buffer->memory());
+    CHECK(data_start);
+    CHECK(data_start + data_offset);
+    const char* data_ptr = data_start + data_offset;
+
+    // Check whether this response data is compliant with our cross-site
+    // document blocking policy. We only do this for the first chunk of data.
+    if (request_info->site_isolation_metadata.get()) {
+      SiteIsolationStatsGatherer::OnReceivedFirstChunk(
+          request_info->site_isolation_metadata, data_ptr, data_length);
+      request_info->site_isolation_metadata.reset();
+    }
+
+    std::unique_ptr<RequestPeer::ReceivedData> data =
+        request_info->received_data_factory->Create(data_offset, data_length);
+    // |data| takes care of ACKing.
+    send_ack = false;
+    request_info->peer->OnReceivedData(std::move(data));
+  }
+
+  // Get the request info again as the client callback may modify the info.
+  request_info = GetPendingRequestInfo(request_id);
+  if (request_info && encoded_data_length > 0)
+    request_info->peer->OnTransferSizeUpdated(encoded_data_length);
+
+  // Acknowledge the reception of this data.
+  if (send_ack)
+    message_sender_->Send(new ResourceHostMsg_DataReceived_ACK(request_id));
+}
+
 void ResourceDispatcher::OnDownloadedData(int request_id,
                                           int data_len,
                                           int encoded_data_length) {
@@ -202,7 +334,7 @@
   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
   if (!request_info)
     return;
-  request_info->response_start = base::TimeTicks::Now();
+  request_info->response_start = ConsumeIOTimestamp();
 
   ResourceResponseInfo renderer_response_info;
   ToResourceResponseInfo(*request_info, response_head, &renderer_response_info);
@@ -218,7 +350,8 @@
     request_info->response_url = redirect_info.new_url;
     request_info->response_method = redirect_info.new_method;
     request_info->response_referrer = GURL(redirect_info.new_referrer);
-    request_info->has_pending_redirect = true;
+    request_info->pending_redirect_message.reset(
+        new ResourceHostMsg_FollowRedirect(request_id));
     if (!request_info->is_deferred) {
       FollowPendingRedirect(request_info);
     }
@@ -229,9 +362,14 @@
 
 void ResourceDispatcher::FollowPendingRedirect(
     PendingRequestInfo* request_info) {
-  if (request_info->has_pending_redirect) {
-    request_info->has_pending_redirect = false;
-    request_info->url_loader->FollowRedirect();
+  IPC::Message* msg = request_info->pending_redirect_message.release();
+  if (msg) {
+    if (request_info->url_loader) {
+      request_info->url_loader->FollowRedirect();
+      delete msg;
+    } else {
+      message_sender_->Send(msg);
+    }
   }
 }
 
@@ -243,8 +381,11 @@
   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
   if (!request_info)
     return;
-  request_info->completion_time = base::TimeTicks::Now();
+  request_info->completion_time = ConsumeIOTimestamp();
   request_info->buffer.reset();
+  if (request_info->received_data_factory)
+    request_info->received_data_factory->Stop();
+  request_info->received_data_factory = nullptr;
   request_info->buffer_size = 0;
 
   RequestPeer* peer = request_info->peer.get();
@@ -285,6 +426,15 @@
   if (it == pending_requests_.end())
     return false;
 
+  PendingRequestInfo* request_info = it->second.get();
+
+  // |url_loader_client| releases the downloaded file. Otherwise (i.e., we
+  // are using Chrome IPC), we should release it here.
+  bool release_downloaded_file =
+      request_info->download_to_file && !it->second->url_loader_client;
+
+  ReleaseResourcesInMessageQueue(&request_info->deferred_message_queue);
+
   // Cancel loading.
   it->second->url_loader = nullptr;
   // Clear URLLoaderClient to stop receiving further Mojo IPC from the browser
@@ -297,6 +447,14 @@
   thread_task_runner_->DeleteSoon(FROM_HERE, it->second.release());
   pending_requests_.erase(it);
 
+  if (release_downloaded_file) {
+    message_sender_->Send(
+        new ResourceHostMsg_ReleaseDownloadedFile(request_id));
+  }
+
+  if (resource_scheduling_filter_.get())
+    resource_scheduling_filter_->ClearRequestIdTaskRunner(request_id);
+
   return true;
 }
 
@@ -309,6 +467,9 @@
 
   // Cancel the request if it didn't complete, and clean it up so the bridge
   // will receive no more messages.
+  const PendingRequestInfo& info = *it->second;
+  if (info.completion_time.is_null() && !info.url_loader)
+    message_sender_->Send(new ResourceHostMsg_CancelRequest(request_id));
   RemovePendingRequest(request_id);
 }
 
@@ -320,12 +481,19 @@
   }
   if (value) {
     request_info->is_deferred = value;
-    request_info->url_loader_client->SetDefersLoading();
+    if (request_info->url_loader_client)
+      request_info->url_loader_client->SetDefersLoading();
   } else if (request_info->is_deferred) {
     request_info->is_deferred = false;
-    request_info->url_loader_client->UnsetDefersLoading();
+
+    if (request_info->url_loader_client)
+      request_info->url_loader_client->UnsetDefersLoading();
 
     FollowPendingRedirect(request_info);
+
+    thread_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&ResourceDispatcher::FlushDeferredMessages,
+                                  weak_factory_.GetWeakPtr(), request_id));
   }
 }
 
@@ -334,7 +502,12 @@
                                            int intra_priority_value) {
   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
   DCHECK(request_info);
-  request_info->url_loader->SetPriority(new_priority, intra_priority_value);
+  if (request_info->url_loader) {
+    request_info->url_loader->SetPriority(new_priority, intra_priority_value);
+  } else {
+    message_sender_->Send(new ResourceHostMsg_DidChangePriority(
+        request_id, new_priority, intra_priority_value));
+  }
 }
 
 void ResourceDispatcher::OnTransferSizeUpdated(int request_id,
@@ -372,17 +545,72 @@
 ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() {
 }
 
+void ResourceDispatcher::DispatchMessage(const IPC::Message& message) {
+  IPC_BEGIN_MESSAGE_MAP(ResourceDispatcher, message)
+    IPC_MESSAGE_HANDLER(ResourceMsg_UploadProgress, OnUploadProgress)
+    IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedResponse, OnReceivedResponse)
+    IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedCachedMetadata,
+                        OnReceivedCachedMetadata)
+    IPC_MESSAGE_HANDLER(ResourceMsg_ReceivedRedirect, OnReceivedRedirect)
+    IPC_MESSAGE_HANDLER(ResourceMsg_SetDataBuffer, OnSetDataBuffer)
+    IPC_MESSAGE_HANDLER(ResourceMsg_DataReceived, OnReceivedData)
+    IPC_MESSAGE_HANDLER(ResourceMsg_DataDownloaded, OnDownloadedData)
+    IPC_MESSAGE_HANDLER(ResourceMsg_RequestComplete, OnRequestComplete)
+  IPC_END_MESSAGE_MAP()
+}
+
+void ResourceDispatcher::FlushDeferredMessages(int request_id) {
+  PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+  if (!request_info || request_info->is_deferred)
+    return;
+
+  if (request_info->url_loader) {
+    DCHECK(request_info->deferred_message_queue.empty());
+    request_info->url_loader_client->FlushDeferredMessages();
+    return;
+  }
+
+  // Because message handlers could result in request_info being destroyed,
+  // we need to work with a stack reference to the deferred queue.
+  MessageQueue q;
+  q.swap(request_info->deferred_message_queue);
+  while (!q.empty()) {
+    IPC::Message* m = q.front();
+    q.pop_front();
+    DispatchMessage(*m);
+    delete m;
+    // We need to find the request again in the list as it may have completed
+    // by now and the request_info instance above may be invalid.
+    request_info = GetPendingRequestInfo(request_id);
+    if (!request_info) {
+      // The recipient is gone, the messages won't be handled and
+      // resources they might hold won't be released. Explicitly release
+      // them from here so that they won't leak.
+      ReleaseResourcesInMessageQueue(&q);
+      return;
+    }
+    // If this request is deferred in the context of the above message, then
+    // we should honor the same and stop dispatching further messages.
+    if (request_info->is_deferred) {
+      request_info->deferred_message_queue.swap(q);
+      return;
+    }
+  }
+}
+
 void ResourceDispatcher::StartSync(
     std::unique_ptr<ResourceRequest> request,
     int routing_id,
     const url::Origin& frame_origin,
     const net::NetworkTrafficAnnotationTag& traffic_annotation,
     SyncLoadResponse* response,
+    blink::WebURLRequest::LoadingIPCType ipc_type,
     mojom::URLLoaderFactory* url_loader_factory,
     std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
     double timeout) {
   CheckSchemeForReferrerPolicy(*request);
 
+  if (ipc_type == blink::WebURLRequest::LoadingIPCType::kMojo) {
     mojom::URLLoaderFactoryPtrInfo url_loader_factory_copy;
     url_loader_factory->Clone(mojo::MakeRequest(&url_loader_factory_copy));
     base::WaitableEvent completed_event(
@@ -407,6 +635,32 @@
                        base::Unretained(terminate_sync_load_event_), timeout));
 
     completed_event.Wait();
+  } else {
+    SyncLoadResult result;
+    IPC::SyncMessage* msg = new ResourceHostMsg_SyncLoad(
+        routing_id, MakeRequestID(), *request, &result);
+
+    // NOTE: This may pump events (see RenderThread::Send).
+    if (!message_sender_->Send(msg)) {
+      response->error_code = net::ERR_FAILED;
+      return;
+    }
+
+    response->error_code = result.error_code;
+    response->url = result.final_url;
+    response->info.headers = result.headers;
+    response->info.mime_type = result.mime_type;
+    response->info.charset = result.charset;
+    response->info.request_time = result.request_time;
+    response->info.response_time = result.response_time;
+    response->info.load_timing = result.load_timing;
+    response->info.devtools_info = result.devtools_info;
+    response->data.swap(result.data);
+    response->info.download_file_path = result.download_file_path;
+    response->info.socket_address = result.socket_address;
+    response->info.encoded_data_length = result.encoded_data_length;
+    response->info.encoded_body_length = result.encoded_body_length;
+  }
 }
 
 int ResourceDispatcher::StartAsync(
@@ -417,6 +671,7 @@
     const net::NetworkTrafficAnnotationTag& traffic_annotation,
     bool is_sync,
     std::unique_ptr<RequestPeer> peer,
+    blink::WebURLRequest::LoadingIPCType ipc_type,
     mojom::URLLoaderFactory* url_loader_factory,
     std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
     mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints) {
@@ -429,6 +684,11 @@
       frame_origin, request->url, request->method, request->referrer,
       request->download_to_file);
 
+  if (resource_scheduling_filter_.get() && loading_task_runner) {
+    resource_scheduling_filter_->SetRequestIdTaskRunner(request_id,
+                                                        loading_task_runner);
+  }
+
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       loading_task_runner ? loading_task_runner : thread_task_runner_;
 
@@ -444,27 +704,35 @@
     return request_id;
   }
 
-  std::unique_ptr<URLLoaderClientImpl> client(
-      new URLLoaderClientImpl(request_id, this, task_runner));
+  if (ipc_type == blink::WebURLRequest::LoadingIPCType::kMojo) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+        loading_task_runner ? loading_task_runner : thread_task_runner_;
+    std::unique_ptr<URLLoaderClientImpl> client(
+        new URLLoaderClientImpl(request_id, this, task_runner));
 
-  uint32_t options = mojom::kURLLoadOptionNone;
-  // TODO(jam): use this flag for ResourceDispatcherHost code path once
-  // MojoLoading is the only IPC code path.
-  if (base::FeatureList::IsEnabled(features::kNetworkService) &&
-      request->fetch_request_context_type != REQUEST_CONTEXT_TYPE_FETCH) {
-    // MIME sniffing should be disabled for a request initiated by fetch().
-    options |= mojom::kURLLoadOptionSniffMimeType;
+    uint32_t options = mojom::kURLLoadOptionNone;
+    // TODO(jam): use this flag for ResourceDispatcherHost code path once
+    // MojoLoading is the only IPC code path.
+    if (base::FeatureList::IsEnabled(features::kNetworkService) &&
+        request->fetch_request_context_type != REQUEST_CONTEXT_TYPE_FETCH) {
+      // MIME sniffing should be disabled for a request initiated by fetch().
+      options |= mojom::kURLLoadOptionSniffMimeType;
+    }
+    if (is_sync)
+      options |= mojom::kURLLoadOptionSynchronous;
+
+    std::unique_ptr<ThrottlingURLLoader> url_loader =
+        ThrottlingURLLoader::CreateLoaderAndStart(
+            url_loader_factory, std::move(throttles), routing_id, request_id,
+            options, *request, client.get(), traffic_annotation,
+            std::move(task_runner));
+    pending_requests_[request_id]->url_loader = std::move(url_loader);
+    pending_requests_[request_id]->url_loader_client = std::move(client);
+  } else {
+    message_sender_->Send(new ResourceHostMsg_RequestResource(
+        routing_id, request_id, *request,
+        net::MutableNetworkTrafficAnnotationTag(traffic_annotation)));
   }
-  if (is_sync)
-    options |= mojom::kURLLoadOptionSynchronous;
-
-  std::unique_ptr<ThrottlingURLLoader> url_loader =
-      ThrottlingURLLoader::CreateLoaderAndStart(
-          url_loader_factory, std::move(throttles), routing_id, request_id,
-          options, *request, client.get(), traffic_annotation,
-          std::move(task_runner));
-  pending_requests_[request_id]->url_loader = std::move(url_loader);
-  pending_requests_[request_id]->url_loader_client = std::move(client);
 
   return request_id;
 }
@@ -524,6 +792,14 @@
   return base::TimeTicks::FromInternalValue(result);
 }
 
+base::TimeTicks ResourceDispatcher::ConsumeIOTimestamp() {
+  if (io_timestamp_ == base::TimeTicks())
+    return base::TimeTicks::Now();
+  base::TimeTicks result = io_timestamp_;
+  io_timestamp_ = base::TimeTicks();
+  return result;
+}
+
 void ResourceDispatcher::ContinueForNavigation(
     int request_id,
     mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints) {
@@ -549,4 +825,63 @@
   client_ptr->Bind(std::move(url_loader_client_endpoints));
 }
 
+// static
+bool ResourceDispatcher::IsResourceDispatcherMessage(
+    const IPC::Message& message) {
+  switch (message.type()) {
+    case ResourceMsg_UploadProgress::ID:
+    case ResourceMsg_ReceivedResponse::ID:
+    case ResourceMsg_ReceivedCachedMetadata::ID:
+    case ResourceMsg_ReceivedRedirect::ID:
+    case ResourceMsg_SetDataBuffer::ID:
+    case ResourceMsg_DataReceived::ID:
+    case ResourceMsg_DataDownloaded::ID:
+    case ResourceMsg_RequestComplete::ID:
+      return true;
+
+    default:
+      break;
+  }
+
+  return false;
+}
+
+// static
+void ResourceDispatcher::ReleaseResourcesInDataMessage(
+    const IPC::Message& message) {
+  base::PickleIterator iter(message);
+  int request_id;
+  if (!iter.ReadInt(&request_id)) {
+    NOTREACHED() << "malformed resource message";
+    return;
+  }
+
+  // If the message contains a shared memory handle, we should close the handle
+  // or there will be a memory leak.
+  if (message.type() == ResourceMsg_SetDataBuffer::ID) {
+    base::SharedMemoryHandle shm_handle;
+    if (IPC::ParamTraits<base::SharedMemoryHandle>::Read(&message,
+                                                         &iter,
+                                                         &shm_handle)) {
+      if (base::SharedMemory::IsHandleValid(shm_handle))
+        base::SharedMemory::CloseHandle(shm_handle);
+    }
+  }
+}
+
+// static
+void ResourceDispatcher::ReleaseResourcesInMessageQueue(MessageQueue* queue) {
+  while (!queue->empty()) {
+    IPC::Message* message = queue->front();
+    ReleaseResourcesInDataMessage(*message);
+    queue->pop_front();
+    delete message;
+  }
+}
+
+void ResourceDispatcher::SetResourceSchedulingFilter(
+    scoped_refptr<ResourceSchedulingFilter> resource_scheduling_filter) {
+  resource_scheduling_filter_ = resource_scheduling_filter;
+}
+
 }  // namespace content
diff --git a/content/renderer/loader/resource_dispatcher.h b/content/renderer/loader/resource_dispatcher.h
index d0f8329..ce4a7ccb 100644
--- a/content/renderer/loader/resource_dispatcher.h
+++ b/content/renderer/loader/resource_dispatcher.h
@@ -25,6 +25,8 @@
 #include "content/public/common/resource_type.h"
 #include "content/public/common/url_loader.mojom.h"
 #include "content/public/common/url_loader_throttle.h"
+#include "ipc/ipc_listener.h"
+#include "ipc/ipc_sender.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/base/request_priority.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -47,9 +49,11 @@
 namespace content {
 class RequestPeer;
 class ResourceDispatcherDelegate;
+class ResourceSchedulingFilter;
 struct ResourceResponseInfo;
 struct ResourceRequest;
 struct ResourceResponseHead;
+class SharedMemoryReceivedDataFactory;
 struct SiteIsolationResponseMetaData;
 struct SyncLoadResponse;
 class ThrottlingURLLoader;
@@ -62,7 +66,7 @@
 // This class serves as a communication interface to the ResourceDispatcherHost
 // in the browser process. It can be used from any child process.
 // Virtual methods are for tests.
-class CONTENT_EXPORT ResourceDispatcher {
+class CONTENT_EXPORT ResourceDispatcher : public IPC::Listener {
  public:
   // Generates ids for requests initiated by child processes unique to the
   // particular process, counted up from 0 (browser initiated requests count
@@ -73,9 +77,13 @@
   // CORS preflight requests.
   static int MakeRequestID();
 
-  explicit ResourceDispatcher(
+  ResourceDispatcher(
+      IPC::Sender* sender,
       scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner);
-  virtual ~ResourceDispatcher();
+  ~ResourceDispatcher() override;
+
+  // IPC::Listener implementation.
+  bool OnMessageReceived(const IPC::Message& message) override;
 
   // Call this method to load the resource synchronously (i.e., in one shot).
   // This is an alternative to the StartAsync method. Be warned that this method
@@ -94,13 +102,15 @@
       const url::Origin& frame_origin,
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
       SyncLoadResponse* response,
+      blink::WebURLRequest::LoadingIPCType ipc_type,
       mojom::URLLoaderFactory* url_loader_factory,
       std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
       double timeout);
 
   // Call this method to initiate the request. If this method succeeds, then
   // the peer's methods will be called asynchronously to report various events.
-  // Returns the request id. |url_loader_factory| must be non-null.
+  // Returns the request id. |url_loader_factory| must be non-null if and only
+  // if |ipc_type| is LoadingIPCType::Mojo.
   //
   // |routing_id| is used to associated the bridge with a frame's network
   // context.
@@ -115,6 +125,7 @@
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
       bool is_sync,
       std::unique_ptr<RequestPeer> peer,
+      blink::WebURLRequest::LoadingIPCType ipc_type,
       mojom::URLLoaderFactory* url_loader_factory,
       std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
       mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints);
@@ -137,17 +148,31 @@
                          net::RequestPriority new_priority,
                          int intra_priority_value);
 
+  void set_message_sender(IPC::Sender* sender) {
+    DCHECK(sender);
+    DCHECK(pending_requests_.empty());
+    message_sender_ = sender;
+  }
+
   // This does not take ownership of the delegate. It is expected that the
   // delegate have a longer lifetime than the ResourceDispatcher.
   void set_delegate(ResourceDispatcherDelegate* delegate) {
     delegate_ = delegate;
   }
 
+  // Remembers IO thread timestamp for next resource message.
+  void set_io_timestamp(base::TimeTicks io_timestamp) {
+    io_timestamp_ = io_timestamp;
+  }
+
   void SetThreadTaskRunner(
       scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner) {
     thread_task_runner_ = thread_task_runner;
   }
 
+  void SetResourceSchedulingFilter(
+      scoped_refptr<ResourceSchedulingFilter> resource_scheduling_filter);
+
   base::WeakPtr<ResourceDispatcher> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
   }
@@ -168,6 +193,7 @@
   friend class URLResponseBodyConsumer;
   friend class ResourceDispatcherTest;
 
+  using MessageQueue = base::circular_deque<IPC::Message*>;
   struct PendingRequestInfo {
     PendingRequestInfo(std::unique_ptr<RequestPeer> peer,
                        ResourceType resource_type,
@@ -183,6 +209,7 @@
     std::unique_ptr<RequestPeer> peer;
     ResourceType resource_type;
     int render_frame_id;
+    MessageQueue deferred_message_queue;
     bool is_deferred = false;
     // Original requested url.
     GURL url;
@@ -194,11 +221,12 @@
     std::string response_method;
     GURL response_referrer;
     bool download_to_file;
-    bool has_pending_redirect = false;
+    std::unique_ptr<IPC::Message> pending_redirect_message;
     base::TimeTicks request_start;
     base::TimeTicks response_start;
     base::TimeTicks completion_time;
     linked_ptr<base::SharedMemory> buffer;
+    scoped_refptr<SharedMemoryReceivedDataFactory> received_data_factory;
     std::unique_ptr<SiteIsolationResponseMetaData> site_isolation_metadata;
     int buffer_size;
 
@@ -223,10 +251,24 @@
   void OnReceivedRedirect(int request_id,
                           const net::RedirectInfo& redirect_info,
                           const ResourceResponseHead& response_head);
+  void OnSetDataBuffer(int request_id,
+                       base::SharedMemoryHandle shm_handle,
+                       int shm_size);
+  void OnReceivedData(int request_id,
+                      int data_offset,
+                      int data_length,
+                      int encoded_data_length);
   void OnDownloadedData(int request_id, int data_len, int encoded_data_length);
   void OnRequestComplete(int request_id,
                          const network::URLLoaderCompletionStatus& status);
 
+  // Dispatch the message to one of the message response handlers.
+  void DispatchMessage(const IPC::Message& message);
+
+  // Dispatch any deferred messages for the given request, provided it is not
+  // again in the deferred state. This method may mutate |pending_requests_|.
+  void FlushDeferredMessages(int request_id);
+
   void ToResourceResponseInfo(const PendingRequestInfo& request_info,
                               const ResourceResponseHead& browser_info,
                               ResourceResponseInfo* renderer_info) const;
@@ -235,16 +277,41 @@
       const PendingRequestInfo& request_info,
       const base::TimeTicks& browser_completion_time) const;
 
+  // Returns timestamp provided by IO thread. If no timestamp is supplied,
+  // then current time is returned. Saved timestamp is reset, so following
+  // invocations will return current time until set_io_timestamp is called.
+  base::TimeTicks ConsumeIOTimestamp();
+
   void ContinueForNavigation(
       int request_id,
       mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints);
 
+  // Returns true if the message passed in is a resource related message.
+  static bool IsResourceDispatcherMessage(const IPC::Message& message);
+
+  // ViewHostMsg_Resource_DataReceived is not POD, it has a shared memory
+  // handle in it that we should cleanup it up nicely. This method accepts any
+  // message and determine whether the message is
+  // ViewHostMsg_Resource_DataReceived and clean up the shared memory handle.
+  static void ReleaseResourcesInDataMessage(const IPC::Message& message);
+
+  // Iterate through a message queue and clean up the messages by calling
+  // ReleaseResourcesInDataMessage and removing them from the queue. Intended
+  // for use on deferred message queues that are no longer needed.
+  static void ReleaseResourcesInMessageQueue(MessageQueue* queue);
+
+  IPC::Sender* message_sender_;
+
   // All pending requests issued to the host
   PendingRequestMap pending_requests_;
 
   ResourceDispatcherDelegate* delegate_;
 
+  // IO thread timestamp for ongoing IPC message.
+  base::TimeTicks io_timestamp_;
+
   scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_;
+  scoped_refptr<ResourceSchedulingFilter> resource_scheduling_filter_;
 
   base::WaitableEvent* terminate_sync_load_event_ = nullptr;
 
diff --git a/content/renderer/loader/resource_dispatcher_unittest.cc b/content/renderer/loader/resource_dispatcher_unittest.cc
index 71890a9..1b107ce 100644
--- a/content/renderer/loader/resource_dispatcher_unittest.cc
+++ b/content/renderer/loader/resource_dispatcher_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "content/common/appcache_interfaces.h"
+#include "content/common/resource_messages.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/resource_request.h"
 #include "content/public/common/resource_request_body.h"
@@ -43,51 +44,169 @@
 
 namespace content {
 
-static constexpr char kTestPageUrl[] = "http://www.google.com/";
-static constexpr char kTestPageHeaders[] =
-    "HTTP/1.1 200 OK\nContent-Type:text/html\n\n";
-static constexpr char kTestPageMimeType[] = "text/html";
-static constexpr char kTestPageCharset[] = "";
-static constexpr char kTestPageContents[] =
-    "<html><head><title>Google</title></head><body><h1>Google</h1></body></"
-    "html>";
+static const char kTestPageUrl[] = "http://www.google.com/";
+static const char kTestPageHeaders[] =
+  "HTTP/1.1 200 OK\nContent-Type:text/html\n\n";
+static const char kTestPageMimeType[] = "text/html";
+static const char kTestPageCharset[] = "";
+static const char kTestPageContents[] =
+  "<html><head><title>Google</title></head><body><h1>Google</h1></body></html>";
+static const char kTestRedirectHeaders[] =
+  "HTTP/1.1 302 Found\nLocation:http://www.google.com/\n\n";
 
 // Sets up the message sender override for the unit test.
-class ResourceDispatcherTest : public testing::Test,
-                               public mojom::URLLoaderFactory {
+class ResourceDispatcherTest : public testing::Test, public IPC::Sender {
  public:
   ResourceDispatcherTest()
-      : dispatcher_(new ResourceDispatcher(message_loop_.task_runner())) {}
+      : dispatcher_(new ResourceDispatcher(this, message_loop_.task_runner())) {
+  }
 
   ~ResourceDispatcherTest() override {
+    shared_memory_map_.clear();
     dispatcher_.reset();
     base::RunLoop().RunUntilIdle();
   }
 
-  void CreateLoaderAndStart(
-      mojom::URLLoaderRequest request,
-      int32_t routing_id,
-      int32_t request_id,
-      uint32_t options,
-      const ResourceRequest& url_request,
-      mojom::URLLoaderClientPtr client,
-      const net::MutableNetworkTrafficAnnotationTag& annotation) override {
-    loader_and_clients_.emplace_back(std::move(request), std::move(client));
+  // Emulates IPC send operations (IPC::Sender) by adding
+  // pending messages to the queue.
+  bool Send(IPC::Message* msg) override {
+    message_queue_.push_back(IPC::Message(*msg));
+    delete msg;
+    return true;
   }
 
-  void Clone(mojom::URLLoaderFactoryRequest request) override { NOTREACHED(); }
+  size_t queued_messages() const { return message_queue_.size(); }
 
-  void CallOnReceiveResponse(mojom::URLLoaderClient* client) {
+  // Returns the ID of the consumed request.  Can't make assumptions about the
+  // ID, because numbering is based on a global.
+  int ConsumeRequestResource() {
+    if (message_queue_.empty()) {
+      ADD_FAILURE() << "Missing resource request message";
+      return -1;
+    }
+
+    ResourceHostMsg_RequestResource::Param params;
+    if (static_cast<uint32_t>(ResourceHostMsg_RequestResource::ID) !=
+            message_queue_[0].type() ||
+        !ResourceHostMsg_RequestResource::Read(&message_queue_[0], &params)) {
+      ADD_FAILURE() << "Expected ResourceHostMsg_RequestResource message";
+      return -1;
+    }
+    ResourceRequest request = std::get<2>(params);
+    EXPECT_EQ(kTestPageUrl, request.url.spec());
+    message_queue_.erase(message_queue_.begin());
+    return std::get<1>(params);
+  }
+
+  void ConsumeFollowRedirect(int expected_request_id) {
+    ASSERT_FALSE(message_queue_.empty());
+    std::tuple<int> args;
+    ASSERT_EQ(static_cast<uint32_t>(ResourceHostMsg_FollowRedirect::ID),
+              message_queue_[0].type());
+    ASSERT_TRUE(ResourceHostMsg_FollowRedirect::Read(
+        &message_queue_[0], &args));
+    EXPECT_EQ(expected_request_id, std::get<0>(args));
+    message_queue_.erase(message_queue_.begin());
+  }
+
+  void ConsumeDataReceived_ACK(int expected_request_id) {
+    ASSERT_FALSE(message_queue_.empty());
+    std::tuple<int> args;
+    ASSERT_EQ(static_cast<uint32_t>(ResourceHostMsg_DataReceived_ACK::ID),
+              message_queue_[0].type());
+    ASSERT_TRUE(ResourceHostMsg_DataReceived_ACK::Read(
+        &message_queue_[0], &args));
+    EXPECT_EQ(expected_request_id, std::get<0>(args));
+    message_queue_.erase(message_queue_.begin());
+  }
+
+  void ConsumeReleaseDownloadedFile(int expected_request_id) {
+    ASSERT_FALSE(message_queue_.empty());
+    std::tuple<int> args;
+    ASSERT_EQ(static_cast<uint32_t>(ResourceHostMsg_ReleaseDownloadedFile::ID),
+              message_queue_[0].type());
+    ASSERT_TRUE(ResourceHostMsg_ReleaseDownloadedFile::Read(
+        &message_queue_[0], &args));
+    EXPECT_EQ(expected_request_id, std::get<0>(args));
+    message_queue_.erase(message_queue_.begin());
+  }
+
+  void ConsumeCancelRequest(int expected_request_id) {
+    ASSERT_FALSE(message_queue_.empty());
+    std::tuple<int> args;
+    ASSERT_EQ(static_cast<uint32_t>(ResourceHostMsg_CancelRequest::ID),
+              message_queue_[0].type());
+    ASSERT_TRUE(ResourceHostMsg_CancelRequest::Read(
+        &message_queue_[0], &args));
+    EXPECT_EQ(expected_request_id, std::get<0>(args));
+    message_queue_.erase(message_queue_.begin());
+  }
+
+  void NotifyReceivedRedirect(int request_id) {
+    ResourceResponseHead head;
+    std::string raw_headers(kTestRedirectHeaders);
+    std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0');
+    head.headers = new net::HttpResponseHeaders(raw_headers);
+    net::RedirectInfo redirect_info;
+    redirect_info.status_code = 302;
+    redirect_info.new_method = "GET";
+    redirect_info.new_url = GURL(kTestPageUrl);
+    redirect_info.new_site_for_cookies = GURL(kTestPageUrl);
+    EXPECT_EQ(true, dispatcher_->OnMessageReceived(ResourceMsg_ReceivedRedirect(
+                        request_id, redirect_info, head)));
+  }
+
+  void NotifyReceivedResponse(int request_id) {
     ResourceResponseHead head;
     std::string raw_headers(kTestPageHeaders);
     std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0');
     head.headers = new net::HttpResponseHeaders(raw_headers);
     head.mime_type = kTestPageMimeType;
     head.charset = kTestPageCharset;
-    client->OnReceiveResponse(head, {}, {});
+    EXPECT_EQ(true, dispatcher_->OnMessageReceived(
+                        ResourceMsg_ReceivedResponse(request_id, head)));
   }
 
-  std::unique_ptr<ResourceRequest> CreateResourceRequest() {
+  void NotifySetDataBuffer(int request_id, size_t buffer_size) {
+    base::SharedMemory* shared_memory = new base::SharedMemory();
+    ASSERT_FALSE(shared_memory_map_[request_id]);
+    shared_memory_map_[request_id] = base::WrapUnique(shared_memory);
+    EXPECT_TRUE(shared_memory->CreateAndMapAnonymous(buffer_size));
+
+    base::SharedMemoryHandle duplicate_handle =
+        shared_memory->handle().Duplicate();
+    EXPECT_TRUE(duplicate_handle.IsValid());
+    EXPECT_TRUE(dispatcher_->OnMessageReceived(ResourceMsg_SetDataBuffer(
+        request_id, duplicate_handle, shared_memory->requested_size())));
+  }
+
+  void NotifyDataReceived(int request_id, const std::string& data) {
+    ASSERT_LE(data.length(), shared_memory_map_[request_id]->requested_size());
+    memcpy(shared_memory_map_[request_id]->memory(), data.c_str(),
+           data.length());
+
+    EXPECT_TRUE(dispatcher_->OnMessageReceived(ResourceMsg_DataReceived(
+        request_id, 0, data.length(), data.length())));
+  }
+
+  void NotifyDataDownloaded(int request_id,
+                            int decoded_length,
+                            int encoded_data_length) {
+    EXPECT_TRUE(dispatcher_->OnMessageReceived(ResourceMsg_DataDownloaded(
+        request_id, decoded_length, encoded_data_length)));
+  }
+
+  void NotifyRequestComplete(int request_id, size_t total_size) {
+    network::URLLoaderCompletionStatus status;
+    status.error_code = net::OK;
+    status.exists_in_cache = false;
+    status.encoded_data_length = total_size;
+    EXPECT_TRUE(dispatcher_->OnMessageReceived(
+        ResourceMsg_RequestComplete(request_id, status)));
+  }
+
+  std::unique_ptr<ResourceRequest> CreateResourceRequest(
+      bool download_to_file) {
     std::unique_ptr<ResourceRequest> request(new ResourceRequest());
 
     request->method = "GET";
@@ -98,6 +217,7 @@
     request->priority = net::LOW;
     request->fetch_request_mode = network::mojom::FetchRequestMode::kNoCORS;
     request->fetch_frame_type = network::mojom::RequestContextFrameType::kNone;
+    request->download_to_file = download_to_file;
 
     const RequestExtraData extra_data;
     extra_data.CopyToResourceRequest(request.get());
@@ -114,16 +234,19 @@
         new TestRequestPeer(dispatcher(), peer_context));
     int request_id = dispatcher()->StartAsync(
         std::move(request), 0, nullptr, url::Origin(),
-        TRAFFIC_ANNOTATION_FOR_TESTS, false, std::move(peer), this,
+        TRAFFIC_ANNOTATION_FOR_TESTS, false, std::move(peer),
+        blink::WebURLRequest::LoadingIPCType::kChromeIPC, nullptr,
         std::vector<std::unique_ptr<URLLoaderThrottle>>(),
         mojom::URLLoaderClientEndpointsPtr());
     peer_context->request_id = request_id;
     return request_id;
   }
 
- protected:
-  std::vector<std::pair<mojom::URLLoaderRequest, mojom::URLLoaderClientPtr>>
-      loader_and_clients_;
+ private:
+  // Map of request IDs to shared memory.
+  std::map<int, std::unique_ptr<base::SharedMemory>> shared_memory_map_;
+
+  std::vector<IPC::Message> message_queue_;
   base::MessageLoop message_loop_;
   std::unique_ptr<ResourceDispatcher> dispatcher_;
 };
@@ -138,6 +261,133 @@
   EXPECT_GE(first_id, 0);
 }
 
+// Does a simple request and tests that the correct data is received.  Simulates
+// two reads.
+TEST_F(ResourceDispatcherTest, RoundTrip) {
+  // Number of bytes received in the first read.
+  const size_t kFirstReceiveSize = 2;
+  ASSERT_LT(kFirstReceiveSize, strlen(kTestPageContents));
+
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context;
+  StartAsync(std::move(request), nullptr, &peer_context);
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  NotifyReceivedResponse(id);
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_TRUE(peer_context.received_response);
+
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, std::string(kTestPageContents, kFirstReceiveSize));
+  ConsumeDataReceived_ACK(id);
+  EXPECT_EQ(0u, queued_messages());
+
+  NotifyDataReceived(id, kTestPageContents + kFirstReceiveSize);
+  ConsumeDataReceived_ACK(id);
+  EXPECT_EQ(0u, queued_messages());
+
+  NotifyRequestComplete(id, strlen(kTestPageContents));
+  EXPECT_EQ(kTestPageContents, peer_context.data);
+  EXPECT_TRUE(peer_context.complete);
+  EXPECT_EQ(0u, queued_messages());
+}
+
+// Tests that the request IDs are straight when there are two interleaving
+// requests.
+TEST_F(ResourceDispatcherTest, MultipleRequests) {
+  const char kTestPageContents2[] = "Not kTestPageContents";
+
+  std::unique_ptr<ResourceRequest> request1(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context1;
+  StartAsync(std::move(request1), nullptr, &peer_context1);
+
+  std::unique_ptr<ResourceRequest> request2(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context2;
+  StartAsync(std::move(request2), nullptr, &peer_context2);
+
+  int id1 = ConsumeRequestResource();
+  int id2 = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  NotifyReceivedResponse(id1);
+  EXPECT_TRUE(peer_context1.received_response);
+  EXPECT_FALSE(peer_context2.received_response);
+  NotifyReceivedResponse(id2);
+  EXPECT_TRUE(peer_context2.received_response);
+  EXPECT_EQ(0u, queued_messages());
+
+  NotifySetDataBuffer(id2, strlen(kTestPageContents2));
+  NotifyDataReceived(id2, kTestPageContents2);
+  ConsumeDataReceived_ACK(id2);
+  NotifySetDataBuffer(id1, strlen(kTestPageContents));
+  NotifyDataReceived(id1, kTestPageContents);
+  ConsumeDataReceived_ACK(id1);
+  EXPECT_EQ(0u, queued_messages());
+
+  NotifyRequestComplete(id1, strlen(kTestPageContents));
+  EXPECT_EQ(kTestPageContents, peer_context1.data);
+  EXPECT_TRUE(peer_context1.complete);
+  EXPECT_FALSE(peer_context2.complete);
+
+  NotifyRequestComplete(id2, strlen(kTestPageContents2));
+  EXPECT_EQ(kTestPageContents2, peer_context2.data);
+  EXPECT_TRUE(peer_context2.complete);
+
+  EXPECT_EQ(0u, queued_messages());
+}
+
+// Tests that the cancel method prevents other messages from being received.
+TEST_F(ResourceDispatcherTest, Cancel) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context;
+  int request_id = StartAsync(std::move(request), nullptr, &peer_context);
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  // Cancel the request.
+  dispatcher()->Cancel(request_id);
+  ConsumeCancelRequest(id);
+
+  // Any future messages related to the request should be ignored.
+  NotifyReceivedResponse(id);
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, kTestPageContents);
+  NotifyRequestComplete(id, strlen(kTestPageContents));
+
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_EQ("", peer_context.data);
+  EXPECT_FALSE(peer_context.received_response);
+  EXPECT_FALSE(peer_context.complete);
+}
+
+// Tests that calling cancel during a callback works as expected.
+TEST_F(ResourceDispatcherTest, CancelDuringCallback) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context;
+  StartAsync(std::move(request), nullptr, &peer_context);
+  peer_context.cancel_on_receive_response = true;
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  NotifyReceivedResponse(id);
+  EXPECT_TRUE(peer_context.received_response);
+  // Request should have been cancelled.
+  ConsumeCancelRequest(id);
+
+  // Any future messages related to the request should be ignored.
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, kTestPageContents);
+  NotifyRequestComplete(id, strlen(kTestPageContents));
+
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_EQ("", peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+}
+
 class TestResourceDispatcherDelegate : public ResourceDispatcherDelegate {
  public:
   TestResourceDispatcherDelegate() {}
@@ -203,97 +453,409 @@
 };
 
 TEST_F(ResourceDispatcherTest, DelegateTest) {
-  std::unique_ptr<ResourceRequest> request(CreateResourceRequest());
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
   TestRequestPeer::Context peer_context;
   StartAsync(std::move(request), nullptr, &peer_context);
 
-  ASSERT_EQ(1u, loader_and_clients_.size());
-  mojom::URLLoaderClientPtr client = std::move(loader_and_clients_[0].second);
-  loader_and_clients_.clear();
-
   // Set the delegate that inserts a new peer in OnReceivedResponse.
   TestResourceDispatcherDelegate delegate;
   dispatcher()->set_delegate(&delegate);
 
+  // Run a simple round-trip.
+  const size_t kFirstReceiveSize = 2;
+  ASSERT_LT(kFirstReceiveSize, strlen(kTestPageContents));
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
   // The wrapper eats all messages until RequestComplete message is sent.
-  CallOnReceiveResponse(client.get());
-
-  mojo::DataPipe data_pipe;
-  client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
-
-  uint32_t size = strlen(kTestPageContents);
-  auto result = data_pipe.producer_handle->WriteData(kTestPageContents, &size,
-                                                     MOJO_WRITE_DATA_FLAG_NONE);
-  ASSERT_EQ(result, MOJO_RESULT_OK);
-  ASSERT_EQ(size, strlen(kTestPageContents));
-
-  data_pipe.producer_handle.reset();
-
-  base::RunLoop().RunUntilIdle();
+  NotifyReceivedResponse(id);
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, std::string(kTestPageContents, kFirstReceiveSize));
+  ConsumeDataReceived_ACK(id);
+  NotifyDataReceived(id, kTestPageContents + kFirstReceiveSize);
+  ConsumeDataReceived_ACK(id);
 
   EXPECT_FALSE(peer_context.received_response);
+  EXPECT_EQ(0u, queued_messages());
 
   // This lets the wrapper peer pass all the messages to the original
   // peer at once.
-  network::URLLoaderCompletionStatus status;
-  status.error_code = net::OK;
-  status.exists_in_cache = false;
-  status.encoded_data_length = strlen(kTestPageContents);
-  client->OnComplete(status);
-
-  base::RunLoop().RunUntilIdle();
+  NotifyRequestComplete(id, strlen(kTestPageContents));
 
   EXPECT_TRUE(peer_context.received_response);
   EXPECT_EQ(kTestPageContents, peer_context.data);
   EXPECT_TRUE(peer_context.complete);
+  EXPECT_EQ(0u, queued_messages());
 }
 
 TEST_F(ResourceDispatcherTest, CancelDuringCallbackWithWrapperPeer) {
-  std::unique_ptr<ResourceRequest> request(CreateResourceRequest());
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
   TestRequestPeer::Context peer_context;
   StartAsync(std::move(request), nullptr, &peer_context);
   peer_context.cancel_on_receive_response = true;
 
-  ASSERT_EQ(1u, loader_and_clients_.size());
-  mojom::URLLoaderClientPtr client = std::move(loader_and_clients_[0].second);
-  loader_and_clients_.clear();
-
   // Set the delegate that inserts a new peer in OnReceivedResponse.
   TestResourceDispatcherDelegate delegate;
   dispatcher()->set_delegate(&delegate);
 
-  CallOnReceiveResponse(client.get());
-  mojo::DataPipe data_pipe;
-  client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
-  uint32_t size = strlen(kTestPageContents);
-  auto result = data_pipe.producer_handle->WriteData(kTestPageContents, &size,
-                                                     MOJO_WRITE_DATA_FLAG_NONE);
-  ASSERT_EQ(result, MOJO_RESULT_OK);
-  ASSERT_EQ(size, strlen(kTestPageContents));
-  data_pipe.producer_handle.reset();
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
 
-  base::RunLoop().RunUntilIdle();
+  // The wrapper eats all messages until RequestComplete message is sent.
+  NotifyReceivedResponse(id);
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, kTestPageContents);
+  ConsumeDataReceived_ACK(id);
+
   EXPECT_FALSE(peer_context.received_response);
+  EXPECT_EQ(0u, queued_messages());
 
   // This lets the wrapper peer pass all the messages to the original
   // peer at once, but the original peer cancels right after it receives
   // the response. (This will remove pending request info from
   // ResourceDispatcher while the wrapper peer is still running
   // OnCompletedRequest, but it should not lead to crashes.)
-  network::URLLoaderCompletionStatus status;
-  status.error_code = net::OK;
-  status.exists_in_cache = false;
-  status.encoded_data_length = strlen(kTestPageContents);
-  client->OnComplete(status);
+  NotifyRequestComplete(id, strlen(kTestPageContents));
 
-  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(peer_context.received_response);
   // Request should have been cancelled with no additional messages.
+  EXPECT_EQ(0u, queued_messages());
   EXPECT_TRUE(peer_context.cancelled);
+
+  // Any future messages related to the request should be ignored.
+  NotifyDataReceived(id, kTestPageContents);
+  NotifyRequestComplete(id, strlen(kTestPageContents));
+
+  EXPECT_EQ(0u, queued_messages());
   EXPECT_EQ("", peer_context.data);
   EXPECT_FALSE(peer_context.complete);
 }
 
+// Checks that redirects work as expected.
+TEST_F(ResourceDispatcherTest, Redirect) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context;
+  StartAsync(std::move(request), nullptr, &peer_context);
+
+  int id = ConsumeRequestResource();
+
+  NotifyReceivedRedirect(id);
+  ConsumeFollowRedirect(id);
+  EXPECT_EQ(1, peer_context.seen_redirects);
+
+  NotifyReceivedRedirect(id);
+  ConsumeFollowRedirect(id);
+  EXPECT_EQ(2, peer_context.seen_redirects);
+
+  NotifyReceivedResponse(id);
+  EXPECT_TRUE(peer_context.received_response);
+
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, kTestPageContents);
+  ConsumeDataReceived_ACK(id);
+
+  NotifyRequestComplete(id, strlen(kTestPageContents));
+  EXPECT_EQ(kTestPageContents, peer_context.data);
+  EXPECT_TRUE(peer_context.complete);
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_EQ(2, peer_context.seen_redirects);
+}
+
+// Tests that that cancelling during a redirect method prevents other messages
+// from being received.
+TEST_F(ResourceDispatcherTest, CancelDuringRedirect) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context;
+  StartAsync(std::move(request), nullptr, &peer_context);
+  peer_context.follow_redirects = false;
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  // Redirect the request, which triggers a cancellation.
+  NotifyReceivedRedirect(id);
+  ConsumeCancelRequest(id);
+  EXPECT_EQ(1, peer_context.seen_redirects);
+  EXPECT_EQ(0u, queued_messages());
+
+  // Any future messages related to the request should be ignored.  In practice,
+  // only the NotifyRequestComplete should be received after this point.
+  NotifyReceivedRedirect(id);
+  NotifyReceivedResponse(id);
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, kTestPageContents);
+  NotifyRequestComplete(id, strlen(kTestPageContents));
+
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_EQ("", peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+  EXPECT_EQ(1, peer_context.seen_redirects);
+}
+
+// Checks that deferring a request delays messages until it's resumed.
+TEST_F(ResourceDispatcherTest, Defer) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context;
+  int request_id = StartAsync(std::move(request), nullptr, &peer_context);
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  dispatcher()->SetDefersLoading(request_id, true);
+  NotifyReceivedResponse(id);
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, kTestPageContents);
+  NotifyRequestComplete(id, strlen(kTestPageContents));
+
+  // None of the messages should have been processed yet, so no queued messages
+  // to the browser process, and no data received by the peer.
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_EQ("", peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+  EXPECT_EQ(0, peer_context.seen_redirects);
+
+  // Resuming the request should asynchronously unleash the deferred messages.
+  dispatcher()->SetDefersLoading(request_id, false);
+  base::RunLoop().RunUntilIdle();
+
+  ConsumeDataReceived_ACK(id);
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_TRUE(peer_context.received_response);
+  EXPECT_EQ(kTestPageContents, peer_context.data);
+  EXPECT_TRUE(peer_context.complete);
+}
+
+// Checks that deferring a request during a redirect delays messages until it's
+// resumed.
+TEST_F(ResourceDispatcherTest, DeferOnRedirect) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context;
+  int request_id = StartAsync(std::move(request), nullptr, &peer_context);
+  peer_context.defer_on_redirect = true;
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  // The request should be deferred during the redirect, including the message
+  // to follow the redirect.
+  NotifyReceivedRedirect(id);
+  NotifyReceivedResponse(id);
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, kTestPageContents);
+  NotifyRequestComplete(id, strlen(kTestPageContents));
+
+  // None of the messages should have been processed yet, so no queued messages
+  // to the browser process, and no data received by the peer.
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_EQ("", peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+  EXPECT_EQ(1, peer_context.seen_redirects);
+
+  // Resuming the request should asynchronously unleash the deferred messages.
+  dispatcher()->SetDefersLoading(request_id, false);
+  base::RunLoop().RunUntilIdle();
+
+  ConsumeFollowRedirect(id);
+  ConsumeDataReceived_ACK(id);
+
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_TRUE(peer_context.received_response);
+  EXPECT_EQ(kTestPageContents, peer_context.data);
+  EXPECT_TRUE(peer_context.complete);
+  EXPECT_EQ(1, peer_context.seen_redirects);
+}
+
+// Checks that a deferred request that's cancelled doesn't receive any messages.
+TEST_F(ResourceDispatcherTest, CancelDeferredRequest) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context;
+  int request_id = StartAsync(std::move(request), nullptr, &peer_context);
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  dispatcher()->SetDefersLoading(request_id, true);
+  NotifyReceivedRedirect(id);
+  dispatcher()->Cancel(request_id);
+  ConsumeCancelRequest(id);
+
+  NotifyRequestComplete(id, 0);
+  base::RunLoop().RunUntilIdle();
+
+  // None of the messages should have been processed.
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_EQ("", peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+  EXPECT_EQ(0, peer_context.seen_redirects);
+}
+
+// Checks cancelling a request while flushing deferred requests from
+// the FlushDeferredMessages() task.
+TEST_F(ResourceDispatcherTest, CancelWhileFlushingDeferredRequests) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context;
+  int request_id = StartAsync(std::move(request), nullptr, &peer_context);
+
+  // Cancel the request when the data message is handled.
+  peer_context.cancel_on_receive_data = true;
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  dispatcher()->SetDefersLoading(request_id, true);
+  NotifyReceivedResponse(id);
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, kTestPageContents);
+
+  // None of the messages should have been processed yet.
+  EXPECT_EQ("", peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+  EXPECT_EQ(0u, queued_messages());
+
+  dispatcher()->SetDefersLoading(request_id, false);
+
+  // Make sure that the FlushDeferredMessages() task posted from
+  // SetDefersLoading() is run. It should dispatch all the deferred
+  // messages.
+  base::RunLoop().RunUntilIdle();
+
+  // When the deferred DataReceived is dispatched, the handler will
+  // cancel the request, but the ACK is sent after the handler
+  // returns, so the cancel request ends up before the ACK in the
+  // message queue.
+  ConsumeCancelRequest(id);
+  ConsumeDataReceived_ACK(id);
+
+  // The data was consumed before the handler canceled
+  // the request, so the data should have been received.
+  EXPECT_EQ(kTestPageContents, peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+  EXPECT_EQ(0u, queued_messages());
+}
+
+// Checks cancelling a request while flushing deferred requests from
+// OnMessageReceived().
+TEST_F(ResourceDispatcherTest,
+       CancelWhileFlushingDeferredRequestsFromOnMessageReceived) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
+  TestRequestPeer::Context peer_context;
+  int request_id = StartAsync(std::move(request), nullptr, &peer_context);
+
+  // Cancel the request when the data message is handled.
+  peer_context.cancel_on_receive_data = true;
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  dispatcher()->SetDefersLoading(request_id, true);
+  NotifyReceivedResponse(id);
+  NotifySetDataBuffer(id, strlen(kTestPageContents));
+  NotifyDataReceived(id, kTestPageContents);
+
+  // None of the messages should have been processed yet.
+  EXPECT_EQ("", peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+  EXPECT_EQ(0u, queued_messages());
+
+  dispatcher()->SetDefersLoading(request_id, false);
+
+  // SetDefersLoading() posts a task to run FlushDeferredMessages() to dispatch
+  // the deferred messages. Since the message loop hasn't been run yet the
+  // task hasn't been run either and no IPC-messages should have been
+  // dispatched.
+  EXPECT_EQ("", peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+  EXPECT_EQ(0u, queued_messages());
+
+  // Calling NotifyRequestComplete() here, before the task from
+  // SetDefersLoading() has been run, triggers the flush in
+  // OnMessageReceived().
+  NotifyRequestComplete(id, strlen(kTestPageContents));
+
+  // When the deferred DataReceived is dispatched, the handler will
+  // cancel the request, but the ACK is sent after the handler
+  // returns, so the cancel request ends up before the ACK in the
+  // message queue.
+  ConsumeCancelRequest(id);
+  ConsumeDataReceived_ACK(id);
+
+  // The data was consumed before the handler canceled
+  // the request, so the data should have been received.
+  EXPECT_EQ(kTestPageContents, peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+  EXPECT_EQ(0u, queued_messages());
+
+  // Make sure that the FlushDeferredMessages() task posted from
+  // SetDefersLoading() is run. The messages should already have been
+  // flushed above, so it should be a NOOP.
+  base::RunLoop().RunUntilIdle();
+
+  // Check that the task didn't change anything.
+  EXPECT_EQ(kTestPageContents, peer_context.data);
+  EXPECT_FALSE(peer_context.complete);
+  EXPECT_EQ(0u, queued_messages());
+}
+
+TEST_F(ResourceDispatcherTest, DownloadToFile) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(true));
+  TestRequestPeer::Context peer_context;
+  int request_id = StartAsync(std::move(request), nullptr, &peer_context);
+  const int kDownloadedIncrement = 100;
+  const int kEncodedIncrement = 50;
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  NotifyReceivedResponse(id);
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_TRUE(peer_context.received_response);
+
+  int expected_total_downloaded_length = 0;
+  int expected_total_encoded_data_length = 0;
+  for (int i = 0; i < 10; ++i) {
+    NotifyDataDownloaded(id, kDownloadedIncrement, kEncodedIncrement);
+    expected_total_downloaded_length += kDownloadedIncrement;
+    expected_total_encoded_data_length += kEncodedIncrement;
+    EXPECT_EQ(expected_total_downloaded_length,
+              peer_context.total_downloaded_data_length);
+    EXPECT_EQ(expected_total_encoded_data_length,
+              peer_context.total_encoded_data_length);
+  }
+
+  NotifyRequestComplete(id, strlen(kTestPageContents));
+  EXPECT_EQ("", peer_context.data);
+  EXPECT_TRUE(peer_context.complete);
+  EXPECT_EQ(0u, queued_messages());
+
+  dispatcher()->RemovePendingRequest(request_id);
+  ConsumeReleaseDownloadedFile(id);
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_EQ(expected_total_downloaded_length,
+            peer_context.total_downloaded_data_length);
+  EXPECT_EQ(expected_total_encoded_data_length,
+            peer_context.total_encoded_data_length);
+}
+
+// Make sure that when a download to file is cancelled, the file is destroyed.
+TEST_F(ResourceDispatcherTest, CancelDownloadToFile) {
+  std::unique_ptr<ResourceRequest> request(CreateResourceRequest(true));
+  TestRequestPeer::Context peer_context;
+  int request_id = StartAsync(std::move(request), nullptr, &peer_context);
+
+  int id = ConsumeRequestResource();
+  EXPECT_EQ(0u, queued_messages());
+
+  NotifyReceivedResponse(id);
+  EXPECT_EQ(0u, queued_messages());
+  EXPECT_TRUE(peer_context.received_response);
+
+  // Cancelling the request deletes the file.
+  dispatcher()->Cancel(request_id);
+  ConsumeCancelRequest(id);
+  ConsumeReleaseDownloadedFile(id);
+}
+
 TEST_F(ResourceDispatcherTest, Cookies) {
   // FIXME
 }
@@ -304,15 +866,18 @@
 
 class TimeConversionTest : public ResourceDispatcherTest {
  public:
+  bool Send(IPC::Message* msg) override {
+    delete msg;
+    return true;
+  }
+
   void PerformTest(const ResourceResponseHead& response_head) {
-    std::unique_ptr<ResourceRequest> request(CreateResourceRequest());
+    std::unique_ptr<ResourceRequest> request(CreateResourceRequest(false));
     TestRequestPeer::Context peer_context;
     StartAsync(std::move(request), nullptr, &peer_context);
 
-    ASSERT_EQ(1u, loader_and_clients_.size());
-    auto client = std::move(loader_and_clients_[0].second);
-    loader_and_clients_.clear();
-    client->OnReceiveResponse(response_head, {}, {});
+    dispatcher()->OnMessageReceived(
+        ResourceMsg_ReceivedResponse(0, response_head));
   }
 
   const ResourceResponseInfo& response_info() const { return response_info_; }
diff --git a/content/renderer/loader/resource_scheduling_filter.cc b/content/renderer/loader/resource_scheduling_filter.cc
new file mode 100644
index 0000000..ca0cb037
--- /dev/null
+++ b/content/renderer/loader/resource_scheduling_filter.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/loader/resource_scheduling_filter.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "content/renderer/loader/resource_dispatcher.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_start.h"
+
+namespace content {
+
+ResourceSchedulingFilter::ResourceSchedulingFilter(
+    const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
+    ResourceDispatcher* resource_dispatcher)
+    : main_thread_task_runner_(main_thread_task_runner),
+      resource_dispatcher_(resource_dispatcher->GetWeakPtr()),
+      weak_ptr_factory_(this) {
+  DCHECK(main_thread_task_runner_.get());
+}
+
+ResourceSchedulingFilter::~ResourceSchedulingFilter() {
+}
+
+bool ResourceSchedulingFilter::OnMessageReceived(const IPC::Message& message) {
+  base::AutoLock lock(request_id_to_task_runner_map_lock_);
+  int request_id;
+
+  base::PickleIterator pickle_iterator(message);
+  if (!pickle_iterator.ReadInt(&request_id)) {
+    NOTREACHED() << "malformed resource message";
+    return true;
+  }
+  // Dispatch the message on the request id specific task runner, if there is
+  // one, or on the general main_thread_task_runner if there isn't.
+  RequestIdToTaskRunnerMap::const_iterator iter =
+      request_id_to_task_runner_map_.find(request_id);
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner;
+  if (iter != request_id_to_task_runner_map_.end()) {
+    task_runner = iter->second;
+  } else {
+    task_runner = main_thread_task_runner_;
+  }
+  task_runner->PostTask(
+      FROM_HERE, base::BindOnce(&ResourceSchedulingFilter::DispatchMessage,
+                                weak_ptr_factory_.GetWeakPtr(), message));
+  return true;
+}
+
+void ResourceSchedulingFilter::SetRequestIdTaskRunner(
+    int id,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+  base::AutoLock lock(request_id_to_task_runner_map_lock_);
+  request_id_to_task_runner_map_.insert(std::make_pair(id, task_runner));
+}
+
+void ResourceSchedulingFilter::ClearRequestIdTaskRunner(int id) {
+  base::AutoLock lock(request_id_to_task_runner_map_lock_);
+  request_id_to_task_runner_map_.erase(id);
+}
+
+bool ResourceSchedulingFilter::GetSupportedMessageClasses(
+    std::vector<uint32_t>* supported_message_classes) const {
+  supported_message_classes->push_back(ResourceMsgStart);
+  return true;
+}
+
+void ResourceSchedulingFilter::DispatchMessage(const IPC::Message& message) {
+  if (resource_dispatcher_)
+    resource_dispatcher_->OnMessageReceived(message);
+}
+
+}  // namespace content
diff --git a/content/renderer/loader/resource_scheduling_filter.h b/content/renderer/loader/resource_scheduling_filter.h
new file mode 100644
index 0000000..63233b10
--- /dev/null
+++ b/content/renderer/loader/resource_scheduling_filter.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_LOADER_RESOURCE_SCHEDULING_FILTER_H_
+#define CONTENT_RENDERER_LOADER_RESOURCE_SCHEDULING_FILTER_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "content/common/content_export.h"
+#include "ipc/message_filter.h"
+
+namespace content {
+class ResourceDispatcher;
+
+// This filter is used to dispatch resource messages on a specific
+// SingleThreadTaskRunner to facilitate task scheduling.
+class CONTENT_EXPORT ResourceSchedulingFilter : public IPC::MessageFilter {
+ public:
+  ResourceSchedulingFilter(const scoped_refptr<base::SingleThreadTaskRunner>&
+                               main_thread_task_runner,
+                           ResourceDispatcher* resource_dispatcher);
+
+  // IPC::MessageFilter overrides:
+  bool OnMessageReceived(const IPC::Message& message) override;
+
+  bool GetSupportedMessageClasses(
+      std::vector<uint32_t>* supported_message_classes) const override;
+
+  // Sets the task runner associated with request messages with |id|.
+  void SetRequestIdTaskRunner(
+      int id,
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+
+  // Removes the task runner associated with |id|.
+  void ClearRequestIdTaskRunner(int id);
+
+  void DispatchMessage(const IPC::Message& message);
+
+ private:
+  ~ResourceSchedulingFilter() override;
+
+  using RequestIdToTaskRunnerMap =
+      std::map<int, scoped_refptr<base::SingleThreadTaskRunner>>;
+
+  // This lock guards |request_id_to_task_runner_map_|
+  base::Lock request_id_to_task_runner_map_lock_;
+  RequestIdToTaskRunnerMap request_id_to_task_runner_map_;
+
+  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+  base::WeakPtr<ResourceDispatcher> resource_dispatcher_;
+  base::WeakPtrFactory<ResourceSchedulingFilter> weak_ptr_factory_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ResourceSchedulingFilter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_LOADER_RESOURCE_SCHEDULING_FILTER_H_
diff --git a/content/renderer/loader/shared_memory_received_data_factory.cc b/content/renderer/loader/shared_memory_received_data_factory.cc
new file mode 100644
index 0000000..b9530d50a
--- /dev/null
+++ b/content/renderer/loader/shared_memory_received_data_factory.cc
@@ -0,0 +1,126 @@
+// 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.
+
+#include "content/renderer/loader/shared_memory_received_data_factory.h"
+
+#include <algorithm>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "content/common/resource_messages.h"
+#include "ipc/ipc_sender.h"
+
+namespace content {
+
+class SharedMemoryReceivedDataFactory::SharedMemoryReceivedData final
+    : public RequestPeer::ReceivedData {
+ public:
+  SharedMemoryReceivedData(
+      const char* payload,
+      int length,
+      scoped_refptr<SharedMemoryReceivedDataFactory> factory,
+      SharedMemoryReceivedDataFactory::TicketId id)
+      : payload_(payload),
+        length_(length),
+        factory_(factory),
+        id_(id) {}
+
+  ~SharedMemoryReceivedData() override { factory_->Reclaim(id_); }
+
+  const char* payload() const override { return payload_; }
+  int length() const override { return length_; }
+
+ private:
+  const char* const payload_;
+  const int length_;
+
+  scoped_refptr<SharedMemoryReceivedDataFactory> factory_;
+  SharedMemoryReceivedDataFactory::TicketId id_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedMemoryReceivedData);
+};
+
+SharedMemoryReceivedDataFactory::SharedMemoryReceivedDataFactory(
+    IPC::Sender* message_sender,
+    int request_id,
+    linked_ptr<base::SharedMemory> memory)
+    : id_(0),
+      oldest_(0),
+      message_sender_(message_sender),
+      request_id_(request_id),
+      is_stopped_(false),
+      memory_(memory) {
+}
+
+SharedMemoryReceivedDataFactory::~SharedMemoryReceivedDataFactory() {
+  if (!is_stopped_)
+    SendAck(released_tickets_.size());
+}
+
+std::unique_ptr<RequestPeer::ReceivedData>
+SharedMemoryReceivedDataFactory::Create(int offset, int length) {
+  const char* start = static_cast<char*>(memory_->memory());
+  const char* payload = start + offset;
+  TicketId id = id_++;
+
+  return std::make_unique<SharedMemoryReceivedData>(payload, length, this, id);
+}
+
+void SharedMemoryReceivedDataFactory::Stop() {
+  is_stopped_ = true;
+  released_tickets_.clear();
+  message_sender_ = nullptr;
+}
+
+class SharedMemoryReceivedDataFactory::TicketComparator final {
+ public:
+  explicit TicketComparator(TicketId oldest) : oldest_(oldest) {}
+  bool operator()(TicketId x, TicketId y) const {
+    if ((oldest_ <= x) == (oldest_ <= y))
+      return x <= y;
+
+    return (oldest_ <= x);
+  }
+
+ private:
+  TicketId oldest_;
+};
+
+void SharedMemoryReceivedDataFactory::Reclaim(TicketId id) {
+  if (is_stopped_)
+    return;
+  if (oldest_ != id) {
+    released_tickets_.push_back(id);
+    return;
+  }
+
+  ++oldest_;
+  SendAck(1);
+  if (released_tickets_.empty()) {
+    // Fast path: (hopefully) the most typical case.
+    return;
+  }
+  std::sort(released_tickets_.begin(), released_tickets_.end(),
+            TicketComparator(oldest_));
+  size_t count = 0;
+  for (size_t i = 0;; ++i) {
+    if (i == released_tickets_.size() ||
+        released_tickets_[i] != static_cast<TicketId>(id + i + 1)) {
+      count = i;
+      break;
+    }
+  }
+  released_tickets_.erase(released_tickets_.begin(),
+                          released_tickets_.begin() + count);
+  oldest_ += count;
+  SendAck(count);
+}
+
+void SharedMemoryReceivedDataFactory::SendAck(size_t count) {
+  for (size_t i = 0; i < count; ++i) {
+    message_sender_->Send(new ResourceHostMsg_DataReceived_ACK(request_id_));
+  }
+}
+
+}  // namespace content
diff --git a/content/renderer/loader/shared_memory_received_data_factory.h b/content/renderer/loader/shared_memory_received_data_factory.h
new file mode 100644
index 0000000..72018cb7
--- /dev/null
+++ b/content/renderer/loader/shared_memory_received_data_factory.h
@@ -0,0 +1,69 @@
+// 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 CONTENT_RENDERER_LOADER_SHARED_MEMORY_RECEIVED_DATA_FACTORY_H_
+#define CONTENT_RENDERER_LOADER_SHARED_MEMORY_RECEIVED_DATA_FACTORY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "content/common/content_export.h"
+#include "content/public/renderer/request_peer.h"
+
+namespace IPC {
+class Sender;
+}  // namespace IPC
+
+namespace content {
+
+class CONTENT_EXPORT SharedMemoryReceivedDataFactory final
+    : public base::RefCounted<SharedMemoryReceivedDataFactory> {
+ public:
+  SharedMemoryReceivedDataFactory(IPC::Sender* message_sender,
+                                  int request_id,
+                                  linked_ptr<base::SharedMemory> memory);
+
+  std::unique_ptr<RequestPeer::ReceivedData> Create(int offset, int length);
+
+  // Stops this factory. After calling this function, releasing issued data
+  // won't send ack signal to the browser process.
+  void Stop();
+
+ private:
+  // Here TicketId is uint32_t, but a factory may issue more data by reusing id.
+  using TicketId = uint32_t;
+
+  class SharedMemoryReceivedData;
+  // Called by SharedMemoryReceivedData.
+  void Reclaim(TicketId id);
+
+  class TicketComparator;
+  friend class base::RefCounted<SharedMemoryReceivedDataFactory>;
+  ~SharedMemoryReceivedDataFactory();
+
+  void SendAck(size_t count);
+
+  TicketId id_;
+  TicketId oldest_;
+  std::vector<TicketId> released_tickets_;
+  // We assume that |message_sender_| is valid until |Stop| is called.
+  IPC::Sender* message_sender_;
+  int request_id_;
+  bool is_stopped_;
+  // Just to keep the payload alive while issued data is alive.
+  linked_ptr<base::SharedMemory> memory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedMemoryReceivedDataFactory);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_LOADER_SHARED_MEMORY_RECEIVED_DATA_FACTORY_H_
diff --git a/content/renderer/loader/shared_memory_received_data_factory_unittest.cc b/content/renderer/loader/shared_memory_received_data_factory_unittest.cc
new file mode 100644
index 0000000..8957d3ff
--- /dev/null
+++ b/content/renderer/loader/shared_memory_received_data_factory_unittest.cc
@@ -0,0 +1,225 @@
+// 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.
+
+#include "content/renderer/loader/shared_memory_received_data_factory.h"
+
+#include <stddef.h>
+#include <tuple>
+
+#include "content/common/resource_messages.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_sender.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::MockFunction;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+using Checkpoint = StrictMock<MockFunction<void(int)>>;
+using ReceivedData = RequestPeer::ReceivedData;
+
+class MockSender : public IPC::Sender {
+ public:
+  bool Send(IPC::Message* message) override {
+    bool result = false;
+    if (message->type() == ResourceHostMsg_DataReceived_ACK::ID) {
+      std::tuple<int> args;
+      ResourceHostMsg_DataReceived_ACK::Read(message, &args);
+      result = SendAck(std::get<0>(args));
+    } else {
+      result = SendOtherwise(message);
+    }
+    delete message;
+    return result;
+  }
+  MOCK_METHOD1(SendAck, bool(int));
+  MOCK_METHOD1(SendOtherwise, bool(IPC::Message*));
+};
+
+class SharedMemoryReceivedDataFactoryTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    sender_.reset(new StrictMock<MockSender>);
+    request_id_ = 0xdeadbeaf;
+    memory_.reset(new base::SharedMemory);
+    factory_ = base::MakeRefCounted<SharedMemoryReceivedDataFactory>(
+        sender_.get(), request_id_, memory_);
+    ASSERT_TRUE(memory_->CreateAndMapAnonymous(memory_size));
+
+    ON_CALL(*sender_, SendAck(_)).WillByDefault(Return(true));
+    ON_CALL(*sender_, SendOtherwise(_)).WillByDefault(Return(true));
+  }
+
+  static const size_t memory_size = 4 * 1024;
+  std::unique_ptr<MockSender> sender_;
+  int request_id_;
+  linked_ptr<base::SharedMemory> memory_;
+  scoped_refptr<SharedMemoryReceivedDataFactory> factory_;
+};
+
+TEST_F(SharedMemoryReceivedDataFactoryTest, Create) {
+  Checkpoint checkpoint;
+  InSequence s;
+  EXPECT_CALL(checkpoint, Call(0));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(checkpoint, Call(1));
+
+  std::unique_ptr<ReceivedData> data = factory_->Create(12, 34);
+  const char* memory_start = static_cast<const char*>(memory_->memory());
+
+  ASSERT_TRUE(data);
+  EXPECT_EQ(memory_start + 12, data->payload());
+  EXPECT_EQ(34, data->length());
+
+  checkpoint.Call(0);
+  data.reset();
+  checkpoint.Call(1);
+}
+
+TEST_F(SharedMemoryReceivedDataFactoryTest, CreateMultiple) {
+  Checkpoint checkpoint;
+  InSequence s;
+  EXPECT_CALL(checkpoint, Call(0));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(checkpoint, Call(1));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(checkpoint, Call(2));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(checkpoint, Call(3));
+
+  std::unique_ptr<ReceivedData> data1 = factory_->Create(0, 1);
+  std::unique_ptr<ReceivedData> data2 = factory_->Create(1, 1);
+  std::unique_ptr<ReceivedData> data3 = factory_->Create(2, 1);
+
+  EXPECT_TRUE(data1);
+  EXPECT_TRUE(data2);
+  EXPECT_TRUE(data3);
+
+  checkpoint.Call(0);
+  data1.reset();
+  checkpoint.Call(1);
+  data2.reset();
+  checkpoint.Call(2);
+  data3.reset();
+  checkpoint.Call(3);
+}
+
+TEST_F(SharedMemoryReceivedDataFactoryTest, ReclaimOutOfOrder) {
+  Checkpoint checkpoint;
+  InSequence s;
+  EXPECT_CALL(checkpoint, Call(0));
+  EXPECT_CALL(checkpoint, Call(1));
+  EXPECT_CALL(checkpoint, Call(2));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(checkpoint, Call(3));
+
+  std::unique_ptr<ReceivedData> data1 = factory_->Create(0, 1);
+  std::unique_ptr<ReceivedData> data2 = factory_->Create(1, 1);
+  std::unique_ptr<ReceivedData> data3 = factory_->Create(2, 1);
+
+  EXPECT_TRUE(data1);
+  EXPECT_TRUE(data2);
+  EXPECT_TRUE(data3);
+
+  checkpoint.Call(0);
+  data3.reset();
+  checkpoint.Call(1);
+  data2.reset();
+  checkpoint.Call(2);
+  data1.reset();
+  checkpoint.Call(3);
+}
+
+TEST_F(SharedMemoryReceivedDataFactoryTest, ReclaimOutOfOrderPartially) {
+  Checkpoint checkpoint;
+  InSequence s;
+  EXPECT_CALL(checkpoint, Call(0));
+  EXPECT_CALL(checkpoint, Call(1));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(checkpoint, Call(2));
+  EXPECT_CALL(checkpoint, Call(3));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(checkpoint, Call(4));
+
+  std::unique_ptr<ReceivedData> data1 = factory_->Create(0, 1);
+  std::unique_ptr<ReceivedData> data2 = factory_->Create(1, 1);
+  std::unique_ptr<ReceivedData> data3 = factory_->Create(2, 1);
+  std::unique_ptr<ReceivedData> data4 = factory_->Create(3, 1);
+  std::unique_ptr<ReceivedData> data5 = factory_->Create(4, 1);
+  std::unique_ptr<ReceivedData> data6 = factory_->Create(5, 1);
+
+  EXPECT_TRUE(data1);
+  EXPECT_TRUE(data2);
+  EXPECT_TRUE(data3);
+  EXPECT_TRUE(data4);
+  EXPECT_TRUE(data5);
+  EXPECT_TRUE(data6);
+
+  checkpoint.Call(0);
+  data3.reset();
+  data6.reset();
+  data2.reset();
+  checkpoint.Call(1);
+  data1.reset();
+  checkpoint.Call(2);
+  data5.reset();
+  checkpoint.Call(3);
+  data4.reset();
+  checkpoint.Call(4);
+}
+
+TEST_F(SharedMemoryReceivedDataFactoryTest, Stop) {
+  Checkpoint checkpoint;
+  InSequence s;
+  EXPECT_CALL(checkpoint, Call(0));
+  EXPECT_CALL(checkpoint, Call(1));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(*sender_, SendAck(request_id_));
+  EXPECT_CALL(checkpoint, Call(2));
+  EXPECT_CALL(checkpoint, Call(3));
+
+  std::unique_ptr<ReceivedData> data1 = factory_->Create(0, 1);
+  std::unique_ptr<ReceivedData> data2 = factory_->Create(1, 1);
+  std::unique_ptr<ReceivedData> data3 = factory_->Create(2, 1);
+  std::unique_ptr<ReceivedData> data4 = factory_->Create(3, 1);
+  std::unique_ptr<ReceivedData> data5 = factory_->Create(4, 1);
+  std::unique_ptr<ReceivedData> data6 = factory_->Create(5, 1);
+
+  EXPECT_TRUE(data1);
+  EXPECT_TRUE(data2);
+  EXPECT_TRUE(data3);
+  EXPECT_TRUE(data4);
+  EXPECT_TRUE(data5);
+  EXPECT_TRUE(data6);
+
+  checkpoint.Call(0);
+  data3.reset();
+  data6.reset();
+  data2.reset();
+  checkpoint.Call(1);
+  data1.reset();
+  checkpoint.Call(2);
+  factory_->Stop();
+  data5.reset();
+  data4.reset();
+  checkpoint.Call(3);
+}
+
+}  // namespace
+
+}  // namespace content
diff --git a/content/renderer/loader/sync_load_context.cc b/content/renderer/loader/sync_load_context.cc
index 2448196..d3711f7e 100644
--- a/content/renderer/loader/sync_load_context.cc
+++ b/content/renderer/loader/sync_load_context.cc
@@ -35,6 +35,7 @@
   context->request_id_ = context->resource_dispatcher_->StartAsync(
       std::move(request), routing_id, nullptr, frame_origin, traffic_annotation,
       true /* is_sync */, base::WrapUnique(context),
+      blink::WebURLRequest::LoadingIPCType::kMojo,
       context->url_loader_factory_.get(), std::move(throttles),
       mojom::URLLoaderClientEndpointsPtr());
 }
@@ -59,8 +60,8 @@
   url_loader_factory_.Bind(std::move(url_loader_factory));
 
   // Constructs a new ResourceDispatcher specifically for this request.
-  resource_dispatcher_ =
-      std::make_unique<ResourceDispatcher>(base::ThreadTaskRunnerHandle::Get());
+  resource_dispatcher_ = std::make_unique<ResourceDispatcher>(
+      nullptr, base::ThreadTaskRunnerHandle::Get());
 
   // Initialize the final URL with the original request URL. It will be
   // overwritten on redirects.
diff --git a/content/renderer/loader/url_loader_client_impl.cc b/content/renderer/loader/url_loader_client_impl.cc
index 16b5d8a..71f46ef 100644
--- a/content/renderer/loader/url_loader_client_impl.cc
+++ b/content/renderer/loader/url_loader_client_impl.cc
@@ -8,6 +8,7 @@
 
 #include "base/callback.h"
 #include "base/single_thread_task_runner.h"
+#include "content/common/resource_messages.h"
 #include "content/renderer/loader/resource_dispatcher.h"
 #include "content/renderer/loader/url_response_body_consumer.h"
 #include "net/url_request/redirect_info.h"
@@ -143,15 +144,10 @@
 
 void URLLoaderClientImpl::UnsetDefersLoading() {
   is_deferred_ = false;
-
-  task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&URLLoaderClientImpl::FlushDeferredMessages,
-                                weak_factory_.GetWeakPtr()));
 }
 
 void URLLoaderClientImpl::FlushDeferredMessages() {
-  if (is_deferred_)
-    return;
+  DCHECK(!is_deferred_);
   std::vector<std::unique_ptr<DeferredMessage>> messages;
   messages.swap(deferred_messages_);
   bool has_completion_message = false;
diff --git a/content/renderer/loader/url_loader_client_impl_unittest.cc b/content/renderer/loader/url_loader_client_impl_unittest.cc
index 4438d9c9..9bb5741f 100644
--- a/content/renderer/loader/url_loader_client_impl_unittest.cc
+++ b/content/renderer/loader/url_loader_client_impl_unittest.cc
@@ -11,6 +11,7 @@
 #include "content/public/common/url_loader_factory.mojom.h"
 #include "content/renderer/loader/resource_dispatcher.h"
 #include "content/renderer/loader/test_request_peer.h"
+#include "ipc/ipc_sender.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
@@ -20,10 +21,11 @@
 namespace content {
 
 class URLLoaderClientImplTest : public ::testing::Test,
+                                IPC::Sender,
                                 mojom::URLLoaderFactory {
  protected:
   URLLoaderClientImplTest()
-      : dispatcher_(new ResourceDispatcher(message_loop_.task_runner())),
+      : dispatcher_(new ResourceDispatcher(this, message_loop_.task_runner())),
         mojo_binding_(this) {
     mojo_binding_.Bind(mojo::MakeRequest(&url_loader_factory_proxy_));
 
@@ -32,6 +34,7 @@
         TRAFFIC_ANNOTATION_FOR_TESTS, false,
         std::make_unique<TestRequestPeer>(dispatcher_.get(),
                                           &request_peer_context_),
+        blink::WebURLRequest::LoadingIPCType::kMojo,
         url_loader_factory_proxy_.get(),
         std::vector<std::unique_ptr<URLLoaderThrottle>>(),
         mojom::URLLoaderClientEndpointsPtr());
@@ -46,6 +49,11 @@
     url_loader_factory_proxy_ = nullptr;
   }
 
+  bool Send(IPC::Message* message) override {
+    ADD_FAILURE() << "IPC::Sender::Send should not be called.";
+    return false;
+  }
+
   void CreateLoaderAndStart(mojom::URLLoaderRequest request,
                             int32_t routing_id,
                             int32_t request_id,
@@ -510,42 +518,4 @@
   EXPECT_FALSE(request_peer_context_.cancelled);
 }
 
-TEST_F(URLLoaderClientImplTest, CancelOnReceiveDataWhileFlushing) {
-  request_peer_context_.cancel_on_receive_data = true;
-  dispatcher_->SetDefersLoading(request_id_, true);
-
-  ResourceResponseHead response_head;
-  network::URLLoaderCompletionStatus status;
-
-  mojo::DataPipe data_pipe(DataPipeOptions());
-  uint32_t size = 5;
-  MojoResult result = data_pipe.producer_handle->WriteData(
-      "hello", &size, MOJO_WRITE_DATA_FLAG_NONE);
-  ASSERT_EQ(MOJO_RESULT_OK, result);
-  EXPECT_EQ(5u, size);
-
-  url_loader_client_->OnReceiveResponse(response_head, base::nullopt, nullptr);
-  url_loader_client_->OnStartLoadingResponseBody(
-      std::move(data_pipe.consumer_handle));
-  url_loader_client_->OnComplete(status);
-
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(request_peer_context_.received_response);
-  EXPECT_EQ("", request_peer_context_.data);
-  EXPECT_FALSE(request_peer_context_.complete);
-  EXPECT_FALSE(request_peer_context_.cancelled);
-
-  dispatcher_->SetDefersLoading(request_id_, false);
-  EXPECT_FALSE(request_peer_context_.received_response);
-  EXPECT_EQ("", request_peer_context_.data);
-  EXPECT_FALSE(request_peer_context_.complete);
-  EXPECT_FALSE(request_peer_context_.cancelled);
-
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(request_peer_context_.received_response);
-  EXPECT_EQ("hello", request_peer_context_.data);
-  EXPECT_FALSE(request_peer_context_.complete);
-  EXPECT_TRUE(request_peer_context_.cancelled);
-}
-
 }  // namespace content
diff --git a/content/renderer/loader/url_response_body_consumer.cc b/content/renderer/loader/url_response_body_consumer.cc
index 0379b99..0ffa014 100644
--- a/content/renderer/loader/url_response_body_consumer.cc
+++ b/content/renderer/loader/url_response_body_consumer.cc
@@ -8,6 +8,7 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "content/common/resource_messages.h"
 #include "content/public/renderer/request_peer.h"
 #include "content/renderer/loader/resource_dispatcher.h"
 #include "content/renderer/loader/site_isolation_stats_gatherer.h"
diff --git a/content/renderer/loader/url_response_body_consumer_unittest.cc b/content/renderer/loader/url_response_body_consumer_unittest.cc
index 6db7348..6d699d5 100644
--- a/content/renderer/loader/url_response_body_consumer_unittest.cc
+++ b/content/renderer/loader/url_response_body_consumer_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "content/common/resource_messages.h"
 #include "content/public/common/resource_request.h"
 #include "content/public/common/service_worker_modes.h"
 #include "content/public/renderer/request_peer.h"
@@ -87,38 +88,23 @@
   DISALLOW_COPY_AND_ASSIGN(TestRequestPeer);
 };
 
-class URLResponseBodyConsumerTest : public ::testing::Test {
+class URLResponseBodyConsumerTest : public ::testing::Test,
+                                    public ::IPC::Sender {
  protected:
-  // A URLResponseBodyConsumer needs an associated PendingRequestInfo, and
-  // we need a URLLoaderFactory to create a PendingRequestInfo. We don't need
-  // a true URLLoaderFactory, so here we define a no-op (other than keeping
-  // clients to avoid connection error notifications) factory.
-  class NoopURLLoaderFactory final : public mojom::URLLoaderFactory {
-   public:
-    void CreateLoaderAndStart(mojom::URLLoaderRequest request,
-                              int32_t routing_id,
-                              int32_t request_id,
-                              uint32_t options,
-                              const ResourceRequest& url_request,
-                              mojom::URLLoaderClientPtr client,
-                              const net::MutableNetworkTrafficAnnotationTag&
-                                  traffic_annotation) override {
-      clients_.push_back(std::move(client));
-    }
-
-    void Clone(mojom::URLLoaderFactoryRequest request) override {}
-
-    std::vector<mojom::URLLoaderClientPtr> clients_;
-  };
-
   URLResponseBodyConsumerTest()
-      : dispatcher_(new ResourceDispatcher(message_loop_.task_runner())) {}
+      : dispatcher_(new ResourceDispatcher(this, message_loop_.task_runner())) {
+  }
 
   ~URLResponseBodyConsumerTest() override {
     dispatcher_.reset();
     base::RunLoop().RunUntilIdle();
   }
 
+  bool Send(IPC::Message* message) override {
+    delete message;
+    return true;
+  }
+
   std::unique_ptr<ResourceRequest> CreateResourceRequest() {
     std::unique_ptr<ResourceRequest> request(new ResourceRequest);
 
@@ -151,7 +137,8 @@
         std::move(request), 0, nullptr, url::Origin(),
         TRAFFIC_ANNOTATION_FOR_TESTS, false,
         std::make_unique<TestRequestPeer>(context, message_loop_.task_runner()),
-        &factory_, std::vector<std::unique_ptr<URLLoaderThrottle>>(),
+        blink::WebURLRequest::LoadingIPCType::kChromeIPC, nullptr,
+        std::vector<std::unique_ptr<URLLoaderThrottle>>(),
         mojom::URLLoaderClientEndpointsPtr());
   }
 
@@ -162,7 +149,6 @@
   }
 
   base::MessageLoop message_loop_;
-  NoopURLLoaderFactory factory_;
   std::unique_ptr<ResourceDispatcher> dispatcher_;
   static const MojoWriteDataFlags kNone = MOJO_WRITE_DATA_FLAG_NONE;
 };
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index 209a43d..b93842b 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -26,6 +26,7 @@
 #include "build/build_config.h"
 #include "content/child/child_thread_impl.h"
 #include "content/child/scoped_child_process_reference.h"
+#include "content/common/resource_messages.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_features.h"
@@ -692,7 +693,7 @@
     resource_dispatcher_->StartSync(
         std::move(resource_request), request.RequestorID(),
         extra_data->frame_origin(), GetTrafficAnnotationTag(request),
-        sync_load_response, url_loader_factory_,
+        sync_load_response, request.GetLoadingIPCType(), url_loader_factory_,
         extra_data->TakeURLLoaderThrottles(), request.TimeoutInterval());
     return;
   }
@@ -704,7 +705,8 @@
       extra_data->frame_origin(), GetTrafficAnnotationTag(request),
       false /* is_sync */,
       std::make_unique<WebURLLoaderImpl::RequestPeerImpl>(this),
-      url_loader_factory_, extra_data->TakeURLLoaderThrottles(),
+      request.GetLoadingIPCType(), url_loader_factory_,
+      extra_data->TakeURLLoaderThrottles(),
       std::move(url_loader_client_endpoints));
 
   if (defers_loading_ != NOT_DEFERRING)
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc
index d58d48e..07c4c1e8 100644
--- a/content/renderer/loader/web_url_loader_impl_unittest.cc
+++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -63,8 +63,11 @@
 
 class TestResourceDispatcher : public ResourceDispatcher {
  public:
-  TestResourceDispatcher()
-      : ResourceDispatcher(nullptr), canceled_(false), defers_loading_(false) {}
+  TestResourceDispatcher() :
+      ResourceDispatcher(nullptr, nullptr),
+      canceled_(false),
+      defers_loading_(false) {
+  }
 
   ~TestResourceDispatcher() override {}
 
@@ -75,6 +78,7 @@
                  const url::Origin& frame_origin,
                  const net::NetworkTrafficAnnotationTag& traffic_annotation,
                  SyncLoadResponse* response,
+                 blink::WebURLRequest::LoadingIPCType ipc_type,
                  mojom::URLLoaderFactory* url_loader_factory,
                  std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
                  double timeout) override {
@@ -89,6 +93,7 @@
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
       bool is_sync,
       std::unique_ptr<RequestPeer> peer,
+      blink::WebURLRequest::LoadingIPCType ipc_type,
       mojom::URLLoaderFactory* url_loader_factory,
       std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
       mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints) override {
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 186a82a0..b0f96d14 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -68,6 +68,7 @@
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
 #include "content/common/gpu_stream_constants.h"
+#include "content/common/resource_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_features.h"
@@ -101,7 +102,9 @@
 #include "content/renderer/input/input_event_filter.h"
 #include "content/renderer/input/input_handler_manager.h"
 #include "content/renderer/input/main_thread_input_event_filter.h"
+#include "content/renderer/loader/child_resource_message_filter.h"
 #include "content/renderer/loader/resource_dispatcher.h"
+#include "content/renderer/loader/resource_scheduling_filter.h"
 #include "content/renderer/mash_util.h"
 #include "content/renderer/media/audio_input_message_filter.h"
 #include "content/renderer/media/audio_message_filter.h"
@@ -121,6 +124,7 @@
 #include "content/renderer/render_process_impl.h"
 #include "content/renderer/render_view_impl.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
+#include "content/renderer/scheduler/resource_dispatch_throttler.h"
 #include "content/renderer/service_worker/embedded_worker_instance_client_impl.h"
 #include "content/renderer/service_worker/service_worker_context_client.h"
 #include "content/renderer/service_worker/service_worker_context_message_filter.h"
@@ -240,6 +244,16 @@
 const int64_t kInitialIdleHandlerDelayMs = 1000;
 const int64_t kLongIdleHandlerDelayMs = 30 * 1000;
 
+#if defined(OS_ANDROID)
+// On Android, resource messages can each take ~1.5ms to dispatch on the browser
+// IO thread. Limiting the message rate to 3/frame at 60hz ensures that the
+// induced work takes but a fraction (~1/4) of the overall frame budget.
+const int kMaxResourceRequestsPerFlushWhenThrottled = 3;
+#else
+const int kMaxResourceRequestsPerFlushWhenThrottled = 8;
+#endif
+const double kThrottledResourceRequestFlushPeriodS = 1. / 60.;
+
 // Maximum allocation size allowed for image scaling filters that
 // require pre-scaling. Skia will fallback to a filter that doesn't
 // require pre-scaling if the default filter would require an
@@ -707,8 +721,11 @@
       new NotificationDispatcher(thread_safe_sender());
   AddFilter(notification_dispatcher_->GetFilter());
 
-  resource_dispatcher_.reset(
-      new ResourceDispatcher(message_loop()->task_runner()));
+  resource_dispatcher_.reset(new ResourceDispatcher(
+      this, message_loop()->task_runner()));
+  resource_message_filter_ =
+      new ChildResourceMessageFilter(resource_dispatcher_.get());
+  AddFilter(resource_message_filter_.get());
   quota_dispatcher_.reset(new QuotaDispatcher(message_loop()->task_runner()));
 
   auto registry = std::make_unique<service_manager::BinderRegistry>();
@@ -734,6 +751,14 @@
       new CacheStorageDispatcher(thread_safe_sender()));
   file_system_dispatcher_.reset(new FileSystemDispatcher());
 
+  // Note: This may reorder messages from the ResourceDispatcher with respect to
+  // other subsystems.
+  resource_dispatch_throttler_.reset(new ResourceDispatchThrottler(
+      static_cast<RenderThread*>(this), renderer_scheduler_.get(),
+      base::TimeDelta::FromSecondsD(kThrottledResourceRequestFlushPeriodS),
+      kMaxResourceRequestsPerFlushWhenThrottled));
+  resource_dispatcher_->set_message_sender(resource_dispatch_throttler_.get());
+
   blob_message_filter_ = new BlobMessageFilter(GetFileThreadTaskRunner());
   AddFilter(blob_message_filter_.get());
   vc_manager_.reset(new VideoCaptureImplManager());
@@ -1247,8 +1272,18 @@
   } else {
     resource_task_queue2 = renderer_scheduler_->LoadingTaskRunner();
   }
-  // The ResourceDispatcher needs to use the same queue to ensure tasks are
-  // executed in the expected order.
+  // Add a filter that forces resource messages to be dispatched via a
+  // particular task runner.
+  scoped_refptr<ResourceSchedulingFilter> filter(
+      new ResourceSchedulingFilter(
+          resource_task_queue2, resource_dispatcher_.get()));
+  channel()->AddFilter(filter.get());
+  resource_dispatcher_->SetResourceSchedulingFilter(filter);
+
+  // The ChildResourceMessageFilter and the ResourceDispatcher need to use the
+  // same queue to ensure tasks are executed in the expected order.
+  resource_message_filter_->SetMainThreadTaskRunner(
+      resource_task_queue2);
   resource_dispatcher_->SetThreadTaskRunner(resource_task_queue2);
 
   if (!command_line.HasSwitch(switches::kDisableThreadedCompositing))
@@ -1584,6 +1619,9 @@
 }
 
 bool RenderThreadImpl::OnMessageReceived(const IPC::Message& msg) {
+  // Resource responses are sent to the resource dispatcher.
+  if (resource_dispatcher_->OnMessageReceived(msg))
+    return true;
   if (file_system_dispatcher_->OnMessageReceived(msg))
     return true;
   return ChildThreadImpl::OnMessageReceived(msg);
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index fb53ccc..7ede741b 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -134,6 +134,7 @@
 class BrowserPluginManager;
 class CacheStorageDispatcher;
 class CategorizedWorkerPool;
+class ChildResourceMessageFilter;
 class CompositorForwardingMessageFilter;
 class DomStorageDispatcher;
 class FileSystemDispatcher;
@@ -150,6 +151,7 @@
 class RenderThreadObserver;
 class RendererBlinkPlatformImpl;
 class ResourceDispatcher;
+class ResourceDispatchThrottler;
 class ServiceWorkerMessageFilter;
 class VideoCaptureImplManager;
 
@@ -645,6 +647,7 @@
   std::unique_ptr<blink::scheduler::RendererScheduler> renderer_scheduler_;
   std::unique_ptr<RendererBlinkPlatformImpl> blink_platform_impl_;
   std::unique_ptr<ResourceDispatcher> resource_dispatcher_;
+  std::unique_ptr<ResourceDispatchThrottler> resource_dispatch_throttler_;
   std::unique_ptr<CacheStorageDispatcher> main_thread_cache_storage_dispatcher_;
   std::unique_ptr<FileSystemDispatcher> file_system_dispatcher_;
   std::unique_ptr<QuotaDispatcher> quota_dispatcher_;
@@ -654,6 +657,7 @@
   scoped_refptr<AudioInputMessageFilter> audio_input_message_filter_;
   scoped_refptr<MidiMessageFilter> midi_message_filter_;
   scoped_refptr<ServiceWorkerMessageFilter> service_worker_message_filter_;
+  scoped_refptr<ChildResourceMessageFilter> resource_message_filter_;
 
   std::unique_ptr<BrowserPluginManager> browser_plugin_manager_;
 
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc
index 1cb95d5..28957f2 100644
--- a/content/renderer/render_thread_impl_browsertest.cc
+++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -24,6 +24,7 @@
 #include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "content/app/mojo/mojo_init.h"
 #include "content/common/in_process_child_thread_params.h"
+#include "content/common/resource_messages.h"
 #include "content/common/service_manager/child_connection.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
@@ -306,6 +307,16 @@
 
 // Disabled under LeakSanitizer due to memory leaks.
 TEST_F(RenderThreadImplBrowserTest,
+       WILL_LEAK(ResourceDispatchIPCTasksGoThroughScheduler)) {
+  sender()->Send(new ResourceHostMsg_FollowRedirect(0));
+  sender()->Send(new TestMsg_QuitRunLoop());
+
+  run_loop_->Run();
+  EXPECT_EQ(1, test_task_counter_->NumTasksPosted());
+}
+
+// Disabled under LeakSanitizer due to memory leaks.
+TEST_F(RenderThreadImplBrowserTest,
        WILL_LEAK(NonResourceDispatchIPCTasksDontGoThroughScheduler)) {
   // NOTE other than not being a resource message, the actual message is
   // unimportant.
diff --git a/content/renderer/scheduler/resource_dispatch_throttler.cc b/content/renderer/scheduler/resource_dispatch_throttler.cc
new file mode 100644
index 0000000..6eae599
--- /dev/null
+++ b/content/renderer/scheduler/resource_dispatch_throttler.cc
@@ -0,0 +1,155 @@
+// 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.
+
+#include "content/renderer/scheduler/resource_dispatch_throttler.h"
+
+#include "base/auto_reset.h"
+#include "base/containers/circular_deque.h"
+#include "base/trace_event/trace_event.h"
+#include "content/common/resource_messages.h"
+#include "ipc/ipc_message_macros.h"
+#include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h"
+
+namespace content {
+namespace {
+
+bool IsResourceRequest(const IPC::Message& msg) {
+  return msg.type() == ResourceHostMsg_RequestResource::ID;
+}
+
+}  // namespace
+
+ResourceDispatchThrottler::ResourceDispatchThrottler(
+    IPC::Sender* proxied_sender,
+    blink::scheduler::RendererScheduler* scheduler,
+    base::TimeDelta flush_period,
+    uint32_t max_requests_per_flush)
+    : proxied_sender_(proxied_sender),
+      scheduler_(scheduler),
+      flush_period_(flush_period),
+      max_requests_per_flush_(max_requests_per_flush),
+      flush_timer_(
+          FROM_HERE,
+          flush_period_,
+          base::Bind(&ResourceDispatchThrottler::Flush, base::Unretained(this)),
+          false /* is_repeating */),
+      sent_requests_since_last_flush_(0) {
+  DCHECK(proxied_sender);
+  DCHECK(scheduler);
+  DCHECK_NE(flush_period_, base::TimeDelta());
+  DCHECK(max_requests_per_flush_);
+  flush_timer_.SetTaskRunner(scheduler->LoadingTaskRunner());
+}
+
+ResourceDispatchThrottler::~ResourceDispatchThrottler() {
+  FlushAll();
+}
+
+bool ResourceDispatchThrottler::Send(IPC::Message* msg) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (msg->is_sync()) {
+    // Flush any pending requests, preserving dispatch order between async and
+    // sync requests.
+    FlushAll();
+    return ForwardMessage(msg);
+  }
+
+  // Always defer message forwarding if there are pending messages, ensuring
+  // message dispatch ordering consistency.
+  if (!throttled_messages_.empty()) {
+    TRACE_EVENT_INSTANT0("loader", "ResourceDispatchThrottler::ThrottleMessage",
+                         TRACE_EVENT_SCOPE_THREAD);
+    throttled_messages_.push_back(msg);
+    return true;
+  }
+
+  if (!IsResourceRequest(*msg))
+    return ForwardMessage(msg);
+
+  if (!scheduler_->IsHighPriorityWorkAnticipated()) {
+    // Treat an unthrottled request as a flush.
+    LogFlush();
+    return ForwardMessage(msg);
+  }
+
+  if (Now() > (last_flush_time_ + flush_period_)) {
+    // If sufficient time has passed since the previous flush, we can
+    // effectively mark the pipeline as flushed.
+    LogFlush();
+    return ForwardMessage(msg);
+  }
+
+  if (sent_requests_since_last_flush_ < max_requests_per_flush_)
+    return ForwardMessage(msg);
+
+  TRACE_EVENT_INSTANT0("loader", "ResourceDispatchThrottler::ThrottleRequest",
+                       TRACE_EVENT_SCOPE_THREAD);
+  throttled_messages_.push_back(msg);
+  ScheduleFlush();
+  return true;
+}
+
+base::TimeTicks ResourceDispatchThrottler::Now() const {
+  return base::TimeTicks::Now();
+}
+
+void ResourceDispatchThrottler::ScheduleFlush() {
+  DCHECK(!flush_timer_.IsRunning());
+  flush_timer_.Reset();
+}
+
+void ResourceDispatchThrottler::Flush() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  TRACE_EVENT1("loader", "ResourceDispatchThrottler::Flush",
+               "total_throttled_messages", throttled_messages_.size());
+  LogFlush();
+
+  // If high-priority work is no longer anticipated, dispatch can be safely
+  // accelerated. Avoid completely flushing in such case in the event that
+  // a large number of requests have been throttled.
+  uint32_t max_requests = scheduler_->IsHighPriorityWorkAnticipated()
+                              ? max_requests_per_flush_
+                              : max_requests_per_flush_ * 2;
+
+  while (!throttled_messages_.empty() &&
+         (sent_requests_since_last_flush_ < max_requests ||
+          !IsResourceRequest(*throttled_messages_.front()))) {
+    IPC::Message* msg = throttled_messages_.front();
+    throttled_messages_.pop_front();
+    ForwardMessage(msg);
+  }
+
+  if (!throttled_messages_.empty())
+    ScheduleFlush();
+}
+
+void ResourceDispatchThrottler::FlushAll() {
+  LogFlush();
+  if (throttled_messages_.empty())
+    return;
+
+  TRACE_EVENT1("loader", "ResourceDispatchThrottler::FlushAll",
+               "total_throttled_messages", throttled_messages_.size());
+  base::circular_deque<IPC::Message*> throttled_messages;
+  throttled_messages.swap(throttled_messages_);
+  for (auto* message : throttled_messages)
+    ForwardMessage(message);
+  // There shouldn't be re-entrancy issues when forwarding an IPC, but validate
+  // as a safeguard.
+  DCHECK(throttled_messages_.empty());
+}
+
+void ResourceDispatchThrottler::LogFlush() {
+  sent_requests_since_last_flush_ = 0;
+  last_flush_time_ = Now();
+}
+
+bool ResourceDispatchThrottler::ForwardMessage(IPC::Message* msg) {
+  if (IsResourceRequest(*msg))
+    ++sent_requests_since_last_flush_;
+
+  return proxied_sender_->Send(msg);
+}
+
+}  // namespace content
diff --git a/content/renderer/scheduler/resource_dispatch_throttler.h b/content/renderer/scheduler/resource_dispatch_throttler.h
new file mode 100644
index 0000000..6c4c933
--- /dev/null
+++ b/content/renderer/scheduler/resource_dispatch_throttler.h
@@ -0,0 +1,77 @@
+// 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 CONTENT_RENDERER_SCHEDULER_RESOURCE_DISPATCH_THROTTLER_H_
+#define CONTENT_RENDERER_SCHEDULER_RESOURCE_DISPATCH_THROTTLER_H_
+
+#include <stdint.h>
+
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "content/common/content_export.h"
+#include "ipc/ipc_sender.h"
+
+namespace blink {
+namespace scheduler {
+class RendererScheduler;
+}
+}
+
+namespace content {
+
+// Utility class for throttling a stream of resource requests targetted to a
+// specific IPC sender. The throttling itself is very basic:
+//  * When there is no high-priority work imminent to the main thread, as
+//    indicated by the RendererScheduler, throttling is disabled.
+//  * When >= N requests have been sent in a given time window, requests are
+//    throttled. A timer periodically flushes a portion of the queued requests
+//    until all such requests have been flushed.
+// TODO(jdduke): Remove this class after resource requests become sufficiently
+// cheap on the IO thread, crbug.com/440037.
+class CONTENT_EXPORT ResourceDispatchThrottler : public IPC::Sender {
+ public:
+  // |flush_period| and |max_requests_per_flush| must be strictly positive
+  // in duration/value.
+  ResourceDispatchThrottler(IPC::Sender* proxied_sender,
+                            blink::scheduler::RendererScheduler* scheduler,
+                            base::TimeDelta flush_period,
+                            uint32_t max_requests_per_flush);
+  ~ResourceDispatchThrottler() override;
+
+  // IPC::Sender implementation:
+  bool Send(IPC::Message* msg) override;
+
+ private:
+  friend class ResourceDispatchThrottlerForTest;
+
+  // Virtual for testing.
+  virtual base::TimeTicks Now() const;
+  virtual void ScheduleFlush();
+
+  void Flush();
+  void FlushAll();
+  void LogFlush();
+  bool ForwardMessage(IPC::Message* msg);
+
+  base::ThreadChecker thread_checker_;
+
+  IPC::Sender* const proxied_sender_;
+  blink::scheduler::RendererScheduler* const scheduler_;
+  const base::TimeDelta flush_period_;
+  const uint32_t max_requests_per_flush_;
+
+  base::Timer flush_timer_;
+  base::TimeTicks last_flush_time_;
+  uint32_t sent_requests_since_last_flush_;
+  base::circular_deque<IPC::Message*> throttled_messages_;
+
+  DISALLOW_COPY_AND_ASSIGN(ResourceDispatchThrottler);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_SCHEDULER_RESOURCE_DISPATCH_THROTTLER_H_
diff --git a/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc b/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc
new file mode 100644
index 0000000..f18bfb1
--- /dev/null
+++ b/content/renderer/scheduler/resource_dispatch_throttler_unittest.cc
@@ -0,0 +1,424 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/scheduler/resource_dispatch_throttler.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "content/common/resource_messages.h"
+#include "content/public/common/resource_request.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h"
+
+namespace content {
+namespace {
+
+const uint32_t kRequestsPerFlush = 4;
+const double kFlushPeriodSeconds = 1.f / 60;
+const int kRoutingId = 1;
+
+typedef std::vector<std::unique_ptr<IPC::Message>> ScopedMessages;
+
+int GetRequestId(const IPC::Message& msg) {
+  int request_id = -1;
+  switch (msg.type()) {
+    case ResourceHostMsg_RequestResource::ID: {
+      base::PickleIterator iter(msg);
+      int routing_id = -1;
+      if (!iter.ReadInt(&routing_id) || !iter.ReadInt(&request_id))
+        NOTREACHED() << "Invalid id for resource request message.";
+    } break;
+
+    case ResourceHostMsg_DidChangePriority::ID:
+    case ResourceHostMsg_ReleaseDownloadedFile::ID:
+    case ResourceHostMsg_CancelRequest::ID:
+      if (!base::PickleIterator(msg).ReadInt(&request_id))
+        NOTREACHED() << "Invalid id for resource message.";
+      break;
+
+    default:
+      NOTREACHED() << "Invalid message for resource throttling.";
+      break;
+  }
+  return request_id;
+}
+
+class RendererSchedulerForTest
+    : public blink::scheduler::FakeRendererScheduler {
+ public:
+  RendererSchedulerForTest() : high_priority_work_anticipated_(false) {}
+  ~RendererSchedulerForTest() override {}
+
+  // RendererScheduler implementation:
+  bool IsHighPriorityWorkAnticipated() override {
+    return high_priority_work_anticipated_;
+  }
+
+  void set_high_priority_work_anticipated(bool anticipated) {
+    high_priority_work_anticipated_ = anticipated;
+  }
+
+ private:
+  bool high_priority_work_anticipated_;
+};
+
+}  // namespace
+
+class ResourceDispatchThrottlerForTest : public ResourceDispatchThrottler {
+ public:
+  ResourceDispatchThrottlerForTest(
+      IPC::Sender* sender,
+      blink::scheduler::RendererScheduler* scheduler)
+      : ResourceDispatchThrottler(
+            sender,
+            scheduler,
+            base::TimeDelta::FromSecondsD(kFlushPeriodSeconds),
+            kRequestsPerFlush),
+        now_(base::TimeTicks() + base::TimeDelta::FromDays(1)),
+        flush_scheduled_(false) {}
+  ~ResourceDispatchThrottlerForTest() override {}
+
+  void Advance(base::TimeDelta delta) { now_ += delta; }
+
+  bool RunScheduledFlush() {
+    if (!flush_scheduled_)
+      return false;
+
+    flush_scheduled_ = false;
+    Flush();
+    return true;
+  }
+
+  bool flush_scheduled() const { return flush_scheduled_; }
+
+ private:
+  // ResourceDispatchThrottler overrides:
+  base::TimeTicks Now() const override { return now_; }
+  void ScheduleFlush() override { flush_scheduled_ = true; }
+
+  base::TimeTicks now_;
+  bool flush_scheduled_;
+};
+
+class ResourceDispatchThrottlerTest : public testing::Test, public IPC::Sender {
+ public:
+  ResourceDispatchThrottlerTest() : last_request_id_(0) {
+    throttler_.reset(new ResourceDispatchThrottlerForTest(this, &scheduler_));
+  }
+  ~ResourceDispatchThrottlerTest() override {}
+
+  // IPC::Sender implementation:
+  bool Send(IPC::Message* msg) override {
+    sent_messages_.push_back(base::WrapUnique(msg));
+    return true;
+  }
+
+ protected:
+  void SetHighPriorityWorkAnticipated(bool anticipated) {
+    scheduler_.set_high_priority_work_anticipated(anticipated);
+  }
+
+  void Advance(base::TimeDelta delta) { throttler_->Advance(delta); }
+
+  bool RunScheduledFlush() { return throttler_->RunScheduledFlush(); }
+
+  bool FlushScheduled() { return throttler_->flush_scheduled(); }
+
+  bool RequestResource() {
+    ResourceRequest request;
+    request.download_to_file = true;
+    return throttler_->Send(new ResourceHostMsg_RequestResource(
+        kRoutingId, ++last_request_id_, request,
+        net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)));
+  }
+
+  bool RequestResourceSync() {
+    SyncLoadResult result;
+    return throttler_->Send(new ResourceHostMsg_SyncLoad(
+        kRoutingId, ++last_request_id_, ResourceRequest(), &result));
+  }
+
+  void RequestResourcesUntilThrottled() {
+    SetHighPriorityWorkAnticipated(true);
+    GetAndResetSentMessageCount();
+    RequestResource();
+    while (GetAndResetSentMessageCount())
+      RequestResource();
+  }
+
+  bool UpdateRequestPriority(int request_id, net::RequestPriority priority) {
+    return throttler_->Send(
+        new ResourceHostMsg_DidChangePriority(request_id, priority, 0));
+  }
+
+  bool ReleaseDownloadedFile(int request_id) {
+    return throttler_->Send(
+        new ResourceHostMsg_ReleaseDownloadedFile(request_id));
+  }
+
+  bool CancelRequest(int request_id) {
+    return throttler_->Send(new ResourceHostMsg_CancelRequest(request_id));
+  }
+
+  size_t GetAndResetSentMessageCount() {
+    size_t sent_message_count = sent_messages_.size();
+    sent_messages_.clear();
+    return sent_message_count;
+  }
+
+  const IPC::Message* LastSentMessage() const {
+    return sent_messages_.empty() ? nullptr : sent_messages_.back().get();
+  }
+
+  int LastSentRequestId() const {
+    const IPC::Message* msg = LastSentMessage();
+    if (!msg)
+      return -1;
+
+    int routing_id = -1;
+    int request_id = -1;
+    base::PickleIterator iter(*msg);
+    CHECK(IPC::ReadParam(msg, &iter, &routing_id));
+    CHECK(IPC::ReadParam(msg, &iter, &request_id));
+    return request_id;
+  }
+
+  int last_request_id() const { return last_request_id_; }
+
+  ScopedMessages sent_messages_;
+
+ private:
+  std::unique_ptr<ResourceDispatchThrottlerForTest> throttler_;
+  RendererSchedulerForTest scheduler_;
+  int last_request_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ResourceDispatchThrottlerTest);
+};
+
+TEST_F(ResourceDispatchThrottlerTest, NotThrottledByDefault) {
+  SetHighPriorityWorkAnticipated(false);
+  for (size_t i = 0; i < kRequestsPerFlush * 2; ++i) {
+    RequestResource();
+    EXPECT_EQ(i + 1, sent_messages_.size());
+  }
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NotThrottledIfSendLimitNotReached) {
+  SetHighPriorityWorkAnticipated(true);
+  for (size_t i = 0; i < kRequestsPerFlush; ++i) {
+    RequestResource();
+    EXPECT_EQ(i + 1, sent_messages_.size());
+  }
+}
+
+TEST_F(ResourceDispatchThrottlerTest, ThrottledWhenHighPriorityWork) {
+  SetHighPriorityWorkAnticipated(true);
+  for (size_t i = 0; i < kRequestsPerFlush; ++i)
+    RequestResource();
+  ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+  RequestResource();
+  EXPECT_EQ(0U, sent_messages_.size());
+
+  EXPECT_TRUE(RunScheduledFlush());
+  EXPECT_EQ(1U, sent_messages_.size());
+}
+
+TEST_F(ResourceDispatchThrottlerTest,
+       ThrottledWhenDeferredMessageQueueNonEmpty) {
+  SetHighPriorityWorkAnticipated(true);
+  for (size_t i = 0; i < kRequestsPerFlush; ++i)
+    RequestResource();
+  ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+  RequestResource();
+  EXPECT_EQ(0U, sent_messages_.size());
+  SetHighPriorityWorkAnticipated(false);
+  RequestResource();
+  EXPECT_EQ(0U, sent_messages_.size());
+
+  EXPECT_TRUE(RunScheduledFlush());
+  EXPECT_EQ(2U, sent_messages_.size());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NotThrottledIfSufficientTimePassed) {
+  SetHighPriorityWorkAnticipated(true);
+
+  for (size_t i = 0; i < kRequestsPerFlush * 2; ++i) {
+    Advance(base::TimeDelta::FromSecondsD(kFlushPeriodSeconds * 2));
+    RequestResource();
+    EXPECT_EQ(1U, GetAndResetSentMessageCount());
+    EXPECT_FALSE(FlushScheduled());
+  }
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NotThrottledIfSendRateSufficientlyLow) {
+  SetHighPriorityWorkAnticipated(true);
+
+  // Continuous dispatch of resource requests below the allowed send rate
+  // should never throttled.
+  const base::TimeDelta kAllowedContinuousSendInterval =
+      base::TimeDelta::FromSecondsD((kFlushPeriodSeconds / kRequestsPerFlush) +
+                                    .00001);
+  for (size_t i = 0; i < kRequestsPerFlush * 10; ++i) {
+    Advance(kAllowedContinuousSendInterval);
+    RequestResource();
+    EXPECT_EQ(1U, GetAndResetSentMessageCount());
+    EXPECT_FALSE(FlushScheduled());
+  }
+}
+
+TEST_F(ResourceDispatchThrottlerTest, ThrottledIfSendRateSufficientlyHigh) {
+  SetHighPriorityWorkAnticipated(true);
+
+  // Continuous dispatch of resource requests above the allowed send rate
+  // should be throttled.
+  const base::TimeDelta kThrottledContinuousSendInterval =
+      base::TimeDelta::FromSecondsD((kFlushPeriodSeconds / kRequestsPerFlush) -
+                                    .00001);
+
+  for (size_t i = 0; i < kRequestsPerFlush * 10; ++i) {
+    Advance(kThrottledContinuousSendInterval);
+    RequestResource();
+    // Only the first batch of requests under the limit should be unthrottled.
+    if (i < kRequestsPerFlush) {
+      EXPECT_EQ(1U, GetAndResetSentMessageCount());
+      EXPECT_FALSE(FlushScheduled());
+    } else {
+      EXPECT_EQ(0U, GetAndResetSentMessageCount());
+      EXPECT_TRUE(FlushScheduled());
+    }
+  }
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NotThrottledIfSyncMessage) {
+  SetHighPriorityWorkAnticipated(true);
+
+  RequestResourceSync();
+  EXPECT_EQ(1U, GetAndResetSentMessageCount());
+
+  // Saturate the queue.
+  for (size_t i = 0; i < kRequestsPerFlush * 2; ++i)
+    RequestResource();
+  ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+  // Synchronous messages should flush any previously throttled messages.
+  RequestResourceSync();
+  EXPECT_EQ(1U + kRequestsPerFlush, GetAndResetSentMessageCount());
+  RequestResourceSync();
+  EXPECT_EQ(1U, GetAndResetSentMessageCount());
+
+  // Previously throttled messages should already have been flushed.
+  RunScheduledFlush();
+  EXPECT_EQ(0U, GetAndResetSentMessageCount());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, MultipleFlushes) {
+  SetHighPriorityWorkAnticipated(true);
+  for (size_t i = 0; i < kRequestsPerFlush * 4; ++i)
+    RequestResource();
+  ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+  for (size_t i = 0; i < 3; ++i) {
+    SCOPED_TRACE(i);
+    EXPECT_TRUE(RunScheduledFlush());
+    EXPECT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+  }
+
+  EXPECT_FALSE(FlushScheduled());
+  EXPECT_EQ(0U, sent_messages_.size());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, MultipleFlushesWhileReceiving) {
+  SetHighPriorityWorkAnticipated(true);
+  for (size_t i = 0; i < kRequestsPerFlush * 4; ++i)
+    RequestResource();
+  ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+  for (size_t i = 0; i < 3; ++i) {
+    SCOPED_TRACE(i);
+    EXPECT_TRUE(RunScheduledFlush());
+    EXPECT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+    for (size_t j = 0; j < kRequestsPerFlush; ++j)
+      RequestResource();
+    EXPECT_EQ(0U, sent_messages_.size());
+  }
+
+  for (size_t i = 0; i < 3; ++i) {
+    EXPECT_TRUE(RunScheduledFlush());
+    EXPECT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+  }
+
+  EXPECT_FALSE(FlushScheduled());
+  EXPECT_EQ(0U, sent_messages_.size());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NonRequestsNeverTriggerThrottling) {
+  RequestResource();
+  ASSERT_EQ(1U, GetAndResetSentMessageCount());
+
+  for (size_t i = 0; i < kRequestsPerFlush * 3; ++i)
+    UpdateRequestPriority(last_request_id(), net::HIGHEST);
+  EXPECT_EQ(kRequestsPerFlush * 3, sent_messages_.size());
+
+  RequestResource();
+  EXPECT_EQ(1U + kRequestsPerFlush * 3, GetAndResetSentMessageCount());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, NonRequestsDeferredWhenThrottling) {
+  RequestResource();
+  ASSERT_EQ(1U, GetAndResetSentMessageCount());
+
+  RequestResourcesUntilThrottled();
+  UpdateRequestPriority(last_request_id(), net::HIGHEST);
+  ReleaseDownloadedFile(last_request_id());
+  CancelRequest(last_request_id());
+
+  EXPECT_TRUE(RunScheduledFlush());
+  EXPECT_EQ(4U, GetAndResetSentMessageCount());
+  EXPECT_FALSE(FlushScheduled());
+}
+
+TEST_F(ResourceDispatchThrottlerTest, MessageOrderingPreservedWhenThrottling) {
+  SetHighPriorityWorkAnticipated(true);
+  for (size_t i = 0; i < kRequestsPerFlush; ++i)
+    RequestResource();
+  ASSERT_EQ(kRequestsPerFlush, GetAndResetSentMessageCount());
+
+  for (size_t i = 0; i < kRequestsPerFlush; ++i) {
+    RequestResource();
+    UpdateRequestPriority(last_request_id(), net::HIGHEST);
+    CancelRequest(last_request_id() - 1);
+  }
+  ASSERT_EQ(0U, sent_messages_.size());
+
+  EXPECT_TRUE(RunScheduledFlush());
+  ASSERT_EQ(kRequestsPerFlush * 3, sent_messages_.size());
+  for (size_t i = 0; i < sent_messages_.size(); i += 3) {
+    SCOPED_TRACE(i);
+    const auto& request_msg = *sent_messages_[i];
+    const auto& priority_msg = *sent_messages_[i + 1];
+    const auto& cancel_msg = *sent_messages_[i + 2];
+
+    EXPECT_EQ(request_msg.type(),
+              static_cast<uint32_t>(ResourceHostMsg_RequestResource::ID));
+    EXPECT_EQ(priority_msg.type(),
+              static_cast<uint32_t>(ResourceHostMsg_DidChangePriority::ID));
+    EXPECT_EQ(cancel_msg.type(),
+              static_cast<uint32_t>(ResourceHostMsg_CancelRequest::ID));
+
+    EXPECT_EQ(GetRequestId(request_msg), GetRequestId(priority_msg));
+    EXPECT_EQ(GetRequestId(request_msg) - 1, GetRequestId(cancel_msg));
+  }
+  EXPECT_FALSE(FlushScheduled());
+}
+
+}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.cc b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
index f0fd7a02..f22b82e 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
@@ -33,8 +33,8 @@
 
 void ServiceWorkerFetchContextImpl::InitializeOnWorkerThread(
     scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner) {
-  resource_dispatcher_ =
-      std::make_unique<ResourceDispatcher>(std::move(loading_task_runner));
+  resource_dispatcher_ = std::make_unique<ResourceDispatcher>(
+      nullptr, std::move(loading_task_runner));
   resource_dispatcher_->set_terminate_sync_load_event(
       &terminate_sync_load_event_);
 
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.cc b/content/renderer/service_worker/worker_fetch_context_impl.cc
index 8132b9c..c42e3d1 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/worker_fetch_context_impl.cc
@@ -125,8 +125,8 @@
   DCHECK(loading_task_runner->RunsTasksInCurrentSequence());
   DCHECK(!resource_dispatcher_);
   DCHECK(!binding_.is_bound());
-  resource_dispatcher_ =
-      std::make_unique<ResourceDispatcher>(std::move(loading_task_runner));
+  resource_dispatcher_ = std::make_unique<ResourceDispatcher>(
+      nullptr, std::move(loading_task_runner));
   resource_dispatcher_->set_terminate_sync_load_event(
       &terminate_sync_load_event_);
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index cf355bd..b09cd0d5 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -733,6 +733,7 @@
     "../browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc",
     "../browser/indexed_db/mock_browsertest_indexed_db_class_factory.h",
     "../browser/isolated_origin_browsertest.cc",
+    "../browser/loader/async_resource_handler_browsertest.cc",
     "../browser/loader/cross_site_document_blocking_browsertest.cc",
     "../browser/loader/cross_site_resource_handler_browsertest.cc",
     "../browser/loader/reload_cache_control_browsertest.cc",
@@ -1294,6 +1295,7 @@
     "../browser/indexed_db/mock_mojo_indexed_db_database_callbacks.cc",
     "../browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h",
     "../browser/leveldb_wrapper_impl_unittest.cc",
+    "../browser/loader/async_resource_handler_unittest.cc",
     "../browser/loader/cross_site_document_resource_handler_unittest.cc",
     "../browser/loader/detachable_resource_handler_unittest.cc",
     "../browser/loader/intercepting_resource_handler_unittest.cc",
@@ -1561,6 +1563,7 @@
     "../renderer/loader/cors_url_loader_unittest.cc",
     "../renderer/loader/resource_dispatcher_unittest.cc",
     "../renderer/loader/shared_memory_data_consumer_handle_unittest.cc",
+    "../renderer/loader/shared_memory_received_data_factory_unittest.cc",
     "../renderer/loader/site_isolation_stats_gatherer_unittest.cc",
     "../renderer/loader/test_request_peer.cc",
     "../renderer/loader/test_request_peer.h",
@@ -1587,6 +1590,7 @@
     "../renderer/presentation/test_presentation_connection.h",
     "../renderer/render_thread_impl_unittest.cc",
     "../renderer/render_widget_unittest.cc",
+    "../renderer/scheduler/resource_dispatch_throttler_unittest.cc",
     "../renderer/service_worker/service_worker_context_client_unittest.cc",
     "../renderer/service_worker/service_worker_dispatcher_unittest.cc",
     "../renderer/service_worker/service_worker_provider_context_unittest.cc",
diff --git a/content/test/ppapi/ppapi_test.cc b/content/test/ppapi/ppapi_test.cc
index 31d0cdb9..c5fef56 100644
--- a/content/test/ppapi/ppapi_test.cc
+++ b/content/test/ppapi/ppapi_test.cc
@@ -16,7 +16,6 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/ppapi_test_utils.h"
 #include "content/shell/browser/shell.h"
-#include "media/base/media_switches.h"
 #include "net/base/filename_util.h"
 #include "ppapi/shared_impl/ppapi_switches.h"
 
@@ -58,10 +57,6 @@
   command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose_gc");
 
   command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
-
-  command_line->AppendSwitchASCII(
-      switches::kAutoplayPolicy,
-      switches::autoplay::kNoUserGestureRequiredPolicy);
 }
 
 GURL PPAPITestBase::GetTestFileUrl(const std::string& test_case) {
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
index 8e9a0b8..9811638e 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
@@ -52,6 +52,7 @@
       [[OmniboxPopupMediator alloc] initWithFetcher:std::move(imageFetcher)
                                            delegate:_popupView.get()];
   self.popupViewController = [[OmniboxPopupViewController alloc] init];
+  self.popupViewController.incognito = self.browserState->IsOffTheRecord();
 
   self.mediator.incognito = self.browserState->IsOffTheRecord();
   self.mediator.consumer = self.popupViewController;
@@ -61,7 +62,6 @@
 
   self.popupViewController.imageRetriever = self.mediator;
   self.popupViewController.delegate = self.mediator;
-  self.popupViewController.incognito = self.browserState->IsOffTheRecord();
 
   _popupView->SetMediator(self.mediator);
 }
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 3d3c6fa..f70ae43 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -266,7 +266,7 @@
 // Enables the Unified Autoplay policy by overriding the platform's default
 // autoplay policy.
 const base::Feature kUnifiedAutoplay{"UnifiedAutoplay",
-                                     base::FEATURE_ENABLED_BY_DEFAULT};
+                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Use SurfaceLayer instead of VideoLayer.
 const base::Feature kUseSurfaceLayerForVideo{"UseSurfaceLayerForVideo",
@@ -302,7 +302,7 @@
 // Enables the Media Engagement Index to override autoplay policies if an
 // origins engagement score is high enough.
 const base::Feature kMediaEngagementBypassAutoplayPolicies{
-    "MediaEngagementBypassAutoplayPolicies", base::FEATURE_ENABLED_BY_DEFAULT};
+    "MediaEngagementBypassAutoplayPolicies", base::FEATURE_DISABLED_BY_DEFAULT};
 
 #if defined(OS_ANDROID)
 // Lock the screen orientation when a video goes fullscreen.
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.gni b/media/cdm/ppapi/ppapi_cdm_adapter.gni
index 63e0ddec..002c9801 100644
--- a/media/cdm/ppapi/ppapi_cdm_adapter.gni
+++ b/media/cdm/ppapi/ppapi_cdm_adapter.gni
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/compiler/compiler.gni")
-
 # This template defines a CDM adapter target. Just use this as you would a
 # normal target and everything should work correctly.
 template("ppapi_cdm_adapter") {
@@ -63,11 +61,6 @@
     if (is_linux) {
       # CDM adapter depends on a CDM in component and non-component builds.
       configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
-
-      if (use_lld) {
-        # TODO(crbug.com/795158) LLD warns about libwidevinecdm.so
-        configs -= [ "//build/config/compiler:default_fatal_linker_warnings" ]
-      }
     }
 
     # TODO(jschuh) crbug.com/167187
diff --git a/media/filters/vpx_video_decoder_fuzzertest.cc b/media/filters/vpx_video_decoder_fuzzertest.cc
index c56df666a..0d086de 100644
--- a/media/filters/vpx_video_decoder_fuzzertest.cc
+++ b/media/filters/vpx_video_decoder_fuzzertest.cc
@@ -30,7 +30,6 @@
   base::AtExitManager at_exit_manager;
   base::MessageLoop message_loop;
 };
-Env* env = new Env();
 
 void OnDecodeComplete(const base::Closure& quit_closure, DecodeStatus status) {
   quit_closure.Run();
@@ -47,6 +46,11 @@
 
 // Entry point for LibFuzzer.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  // Create Env on the first run of LLVMFuzzerTestOneInput otherwise
+  // message_loop will be created before this process forks when used with AFL,
+  // causing hangs.
+  static Env* env = new Env();
+  ALLOW_UNUSED_LOCAL(env);
   std::mt19937_64 rng;
 
   {  // Seed rng from data.
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index d9be3639..f2dd3363 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -364,6 +364,7 @@
     { "name": "groups.google.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
     { "name": "gvt2.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
     { "name": "gvt3.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
+    { "name": "developer.android.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
     { "name": "market.android.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
     { "name": "translate.googleapis.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
     { "name": "withgoogle.com", "policy": "google", "mode": "force-https", "include_subdomains": true, "pins": "google" },
@@ -42179,6 +42180,7 @@
     { "name": "mitm-software.badssl.com", "policy": "custom", "mode": "force-https", "include_subdomains": true },
     { "name": "www.hyatt.com", "policy": "custom", "mode": "force-https", "include_subdomains": true },
     { "name": "connect.facebook.net", "policy": "custom", "mode": "force-https", "include_subdomains": true },
+    { "name": "bing.com", "policy": "custom", "mode": "force-https", "include_subdomains": true },
     // No subdomains
     { "name": "wordpress.com", "policy": "custom", "mode": "force-https", "include_subdomains": false },
     { "name": "www.wordpress.com", "policy": "custom", "mode": "force-https", "include_subdomains": false },
diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc
index 515d0ea..1b28aa2 100644
--- a/sandbox/linux/tests/unit_tests.cc
+++ b/sandbox/linux/tests/unit_tests.cc
@@ -135,7 +135,16 @@
   // We need to fork(), so we can't be multi-threaded, as threads could hold
   // locks.
   int num_threads = CountThreads();
+#if !defined(THREAD_SANITIZER)
   const int kNumExpectedThreads = 1;
+#else
+  // Under TSAN, there is a special helper thread. It should be completely
+  // invisible to our testing, so we ignore it. It should be ok to fork()
+  // with this thread. It's currently buggy, but it's the best we can do until
+  // there is a way to delay the start of the thread
+  // (https://code.google.com/p/thread-sanitizer/issues/detail?id=19).
+  const int kNumExpectedThreads = 2;
+#endif
 
   // The kernel is at liberty to wake a thread id futex before updating /proc.
   // If another test running in the same process has stopped a thread, it may
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 47426b4..93874c3 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -3683,6 +3683,7 @@
 
 # Sheriff failures 2017-12-15
 crbug.com/795250 [ Win7 ] virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-hover-state-iframe.html [ Pass Failure ]
+crbug.com/795250 [ Win7 ] virtual/mouseevent_fractional/fast/events/touch/gesture/gesture-tap-hover-state-iframe.html [ Pass Failure ]
 
 # Does not work on Mac
 crbug.com/793771 [ Mac ] virtual/modern-media-controls/media/controls/modern/scrubbing.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/fast/events/resize-display-none-iframe.html b/third_party/WebKit/LayoutTests/fast/events/resize-display-none-iframe.html
new file mode 100644
index 0000000..be3030d1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/resize-display-none-iframe.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<iframe id="ifr" width="50" height="40" style="display: none" srcdoc="x"></iframe>
+<script>
+
+var test = async_test("iframe fires resize event when displayed");
+var raf = requestAnimationFrame;
+var raf2 = (f) => { raf(() => { raf(f); })}
+var innerWindow = ifr.contentWindow;
+var width = 0;
+var height = 0;
+
+innerWindow.onresize = () => {
+  width = innerWindow.innerWidth;
+  height = innerWindow.innerHeight;
+};
+
+onload = () => {
+  raf2(() => {
+    assert_true(innerWindow.innerWidth == 0);
+    assert_true(innerWindow.innerHeight == 0);
+
+    // Displaying the iframe changes its viewport from 0x0 to 50x40.
+    // This should fire a resize event.
+    ifr.style.display = "block";
+
+    raf2(() => {
+      test.step(() => {
+        assert_true(width == 50);
+        assert_true(height == 40);
+      });
+      test.done();
+    });
+  });
+};
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/iframe-display-none-to-display-block-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/iframe-display-none-to-display-block-expected.txt
index f21af3f..b03ea5f7 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/iframe-display-none-to-display-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/iframe-display-none-to-display-block-expected.txt
@@ -20,10 +20,6 @@
       "reason": "appeared"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/mac/paint/invalidation/iframe-display-none-to-display-block-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/mac/paint/invalidation/iframe-display-none-to-display-block-expected.txt
index 84e79083..1b51e5d 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/mac/paint/invalidation/iframe-display-none-to-display-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/mac/paint/invalidation/iframe-display-none-to-display-block-expected.txt
@@ -45,10 +45,6 @@
       "reason": "appeared"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/mac/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/mac/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
index 3abb978..6f5e269 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/mac/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/mac/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -90,10 +90,6 @@
       "reason": "geometry"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/win/paint/invalidation/iframe-display-none-to-display-block-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/win/paint/invalidation/iframe-display-none-to-display-block-expected.txt
index c67a8085..e0de366d 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/win/paint/invalidation/iframe-display-none-to-display-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/win/paint/invalidation/iframe-display-none-to-display-block-expected.txt
@@ -45,10 +45,6 @@
       "reason": "appeared"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/win/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/win/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
index ca61c2fd..8492b2b 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/win/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/root-layer-scrolls/platform/win/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -90,10 +90,6 @@
       "reason": "geometry"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/network/network-choose-preview-view-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/network/network-choose-preview-view-expected.txt
index ec1be8c9..b47b78e9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/network/network-choose-preview-view-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/network/network-choose-preview-view-expected.txt
@@ -105,10 +105,10 @@
 Testing with MimeType: image/png, and StatusCode: 200
 Content: Bin**NULL**ary File**NULL****NULL**
 
-ResourceType(xhr): SearchableView > widget vbox
-ResourceType(fetch): SearchableView > widget vbox
-ResourceType(document): SearchableView > widget vbox
-ResourceType(other): SearchableView > widget vbox
+ResourceType(xhr): widget vbox image-view
+ResourceType(fetch): widget vbox image-view
+ResourceType(document): widget vbox image-view
+ResourceType(other): widget vbox image-view
 
 Binary Blank Image File
 Testing with MimeType: image/png, and StatusCode: 200
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/iframe-display-none-to-display-block-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/iframe-display-none-to-display-block-expected.txt
index dcb18836..2cf698774 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/iframe-display-none-to-display-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/iframe-display-none-to-display-block-expected.txt
@@ -35,10 +35,6 @@
       "reason": "appeared"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
index 9d4f505..15c168e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -80,10 +80,6 @@
       "reason": "geometry"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/iframe-display-none-to-display-block-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/iframe-display-none-to-display-block-expected.txt
index 510b8b6..c7f8f06d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/iframe-display-none-to-display-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/iframe-display-none-to-display-block-expected.txt
@@ -35,10 +35,6 @@
       "reason": "appeared"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
index e8c8cc0..9cfdd24c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -80,10 +80,6 @@
       "reason": "geometry"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/iframe-display-none-to-display-block-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/iframe-display-none-to-display-block-expected.txt
index b181cef..c879003 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/iframe-display-none-to-display-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/iframe-display-none-to-display-block-expected.txt
@@ -30,10 +30,6 @@
       "reason": "appeared"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
index dbc20805..a546ecc 100644
--- a/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spv175/paint/invalidation/position/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -69,10 +69,6 @@
       "reason": "geometry"
     },
     {
-      "object": "VerticalScrollbar",
-      "reason": "scroll control"
-    },
-    {
       "object": "LayoutView #document",
       "reason": "style change"
     },
diff --git a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
index edd9aada..d064a31 100644
--- a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
@@ -21,6 +21,8 @@
   "$bindings_core_v8_output_dir/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h",
   "$bindings_core_v8_output_dir/boolean_or_byte_string_byte_string_record.cc",
   "$bindings_core_v8_output_dir/boolean_or_byte_string_byte_string_record.h",
+  "$bindings_core_v8_output_dir/byte_string_sequence_sequence_or_byte_string_byte_string_record.cc",
+  "$bindings_core_v8_output_dir/byte_string_sequence_sequence_or_byte_string_byte_string_record.h",
   "$bindings_core_v8_output_dir/css_style_value_or_css_style_value_sequence.cc",
   "$bindings_core_v8_output_dir/css_style_value_or_css_style_value_sequence.h",
   "$bindings_core_v8_output_dir/css_style_value_or_string.cc",
diff --git a/third_party/WebKit/Source/bindings/modules/v8/generated.gni b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
index af45f24..1118887 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/generated.gni
+++ b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
@@ -28,8 +28,6 @@
   "$bindings_modules_v8_output_dir/boolean_or_constrain_boolean_parameters.h",
   "$bindings_modules_v8_output_dir/boolean_or_media_track_constraints.cc",
   "$bindings_modules_v8_output_dir/boolean_or_media_track_constraints.h",
-  "$bindings_modules_v8_output_dir/byte_string_sequence_sequence_or_byte_string_byte_string_record.cc",
-  "$bindings_modules_v8_output_dir/byte_string_sequence_sequence_or_byte_string_byte_string_record.h",
   "$bindings_modules_v8_output_dir/canvas_image_source.cc",
   "$bindings_modules_v8_output_dir/canvas_image_source.h",
   "$bindings_modules_v8_output_dir/client_or_service_worker_or_message_port.cc",
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 1070e36..b81457c 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1767,6 +1767,7 @@
     "fetch/DataConsumerHandleTestUtil.cpp",
     "fetch/DataConsumerHandleTestUtil.h",
     "fetch/FetchDataLoaderTest.cpp",
+    "fetch/FetchHeaderListTest.cpp",
     "fetch/FormDataBytesConsumerTest.cpp",
     "fetch/MultipartParserTest.cpp",
     "fetch/ReadableStreamBytesConsumerTest.cpp",
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni
index d07552ac..0b8b8b8 100644
--- a/third_party/WebKit/Source/core/core_idl_files.gni
+++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -166,6 +166,7 @@
                     "events/UIEvent.idl",
                     "events/WheelEvent.idl",
                     "fetch/Body.idl",
+                    "fetch/Headers.idl",
                     "fileapi/Blob.idl",
                     "fileapi/File.idl",
                     "fileapi/FileList.idl",
diff --git a/third_party/WebKit/Source/core/fetch/BUILD.gn b/third_party/WebKit/Source/core/fetch/BUILD.gn
index 130187af..b2bef16 100644
--- a/third_party/WebKit/Source/core/fetch/BUILD.gn
+++ b/third_party/WebKit/Source/core/fetch/BUILD.gn
@@ -18,11 +18,11 @@
     "BytesConsumerForDataConsumerHandle.h",
     "FetchDataLoader.cpp",
     "FetchDataLoader.h",
+    "FetchHeaderList.cpp",
+    "FetchHeaderList.h",
 
     # TODO(nhiroki): Move these files from modules/fetch to core/fetch.
     # (https://crbug.com/794837)
-    # "FetchHeaderList.cpp",
-    # "FetchHeaderList.h",
     # "FetchManager.cpp",
     # "FetchManager.h",
     # "FetchRequestData.cpp",
@@ -37,9 +37,9 @@
     # (https://crbug.com/794837)
     # "GlobalFetch.cpp",
     # "GlobalFetch.h",
-    # "Headers.cpp",
-    # "Headers.h",
 
+    "Headers.cpp",
+    "Headers.h",
     "MultipartParser.cpp",
     "MultipartParser.h",
     "ReadableStreamBytesConsumer.cpp",
diff --git a/third_party/WebKit/Source/modules/fetch/FetchHeaderList.cpp b/third_party/WebKit/Source/core/fetch/FetchHeaderList.cpp
similarity index 99%
rename from third_party/WebKit/Source/modules/fetch/FetchHeaderList.cpp
rename to third_party/WebKit/Source/core/fetch/FetchHeaderList.cpp
index dd8f20b..dcb898a7 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchHeaderList.cpp
+++ b/third_party/WebKit/Source/core/fetch/FetchHeaderList.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 "modules/fetch/FetchHeaderList.h"
+#include "core/fetch/FetchHeaderList.h"
 
 #include <algorithm>
 #include <utility>
diff --git a/third_party/WebKit/Source/modules/fetch/FetchHeaderList.h b/third_party/WebKit/Source/core/fetch/FetchHeaderList.h
similarity index 96%
rename from third_party/WebKit/Source/modules/fetch/FetchHeaderList.h
rename to third_party/WebKit/Source/core/fetch/FetchHeaderList.h
index 82aeb85..c3298a8 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchHeaderList.h
+++ b/third_party/WebKit/Source/core/fetch/FetchHeaderList.h
@@ -7,7 +7,7 @@
 
 #include <map>
 #include <utility>
-#include "modules/ModulesExport.h"
+#include "core/CoreExport.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/WTFString.h"
@@ -15,7 +15,7 @@
 namespace blink {
 
 // http://fetch.spec.whatwg.org/#terminology-headers
-class MODULES_EXPORT FetchHeaderList final
+class CORE_EXPORT FetchHeaderList final
     : public GarbageCollectedFinalized<FetchHeaderList> {
  public:
   struct ByteCaseInsensitiveCompare {
diff --git a/third_party/WebKit/Source/modules/fetch/FetchHeaderListTest.cpp b/third_party/WebKit/Source/core/fetch/FetchHeaderListTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/modules/fetch/FetchHeaderListTest.cpp
rename to third_party/WebKit/Source/core/fetch/FetchHeaderListTest.cpp
index cda35c12..9051179 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchHeaderListTest.cpp
+++ b/third_party/WebKit/Source/core/fetch/FetchHeaderListTest.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 "modules/fetch/FetchHeaderList.h"
+#include "core/fetch/FetchHeaderList.h"
 
 #include <utility>
 #include "platform/wtf/StdLibExtras.h"
diff --git a/third_party/WebKit/Source/modules/fetch/Headers.cpp b/third_party/WebKit/Source/core/fetch/Headers.cpp
similarity index 98%
rename from third_party/WebKit/Source/modules/fetch/Headers.cpp
rename to third_party/WebKit/Source/core/fetch/Headers.cpp
index a050a4d..eb756b2 100644
--- a/third_party/WebKit/Source/modules/fetch/Headers.cpp
+++ b/third_party/WebKit/Source/core/fetch/Headers.cpp
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "modules/fetch/Headers.h"
+#include "core/fetch/Headers.h"
 
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/V8IteratorResultValue.h"
-#include "bindings/modules/v8/byte_string_sequence_sequence_or_byte_string_byte_string_record.h"
+#include "bindings/core/v8/byte_string_sequence_sequence_or_byte_string_byte_string_record.h"
 #include "core/dom/Iterator.h"
 #include "platform/loader/fetch/FetchUtils.h"
 #include "platform/wtf/text/WTFString.h"
@@ -212,7 +212,7 @@
 // classes. For example, when initializing a Request object it is possible that
 // a Request's Headers must be filled with an existing Headers object.
 void Headers::FillWith(const Headers* object, ExceptionState& exception_state) {
-  DCHECK(header_list_->size() == 0);
+  DCHECK_EQ(header_list_->size(), 0U);
   for (const auto& header : object->header_list_->List()) {
     append(header.first, header.second, exception_state);
     if (exception_state.HadException())
diff --git a/third_party/WebKit/Source/modules/fetch/Headers.h b/third_party/WebKit/Source/core/fetch/Headers.h
similarity index 91%
rename from third_party/WebKit/Source/modules/fetch/Headers.h
rename to third_party/WebKit/Source/core/fetch/Headers.h
index 0a8e546..f20f94a 100644
--- a/third_party/WebKit/Source/modules/fetch/Headers.h
+++ b/third_party/WebKit/Source/core/fetch/Headers.h
@@ -6,8 +6,8 @@
 #define Headers_h
 
 #include "bindings/core/v8/Iterable.h"
-#include "modules/ModulesExport.h"
-#include "modules/fetch/FetchHeaderList.h"
+#include "core/CoreExport.h"
+#include "core/fetch/FetchHeaderList.h"
 #include "platform/bindings/ScriptState.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/wtf/Forward.h"
@@ -20,8 +20,8 @@
 using HeadersInit = ByteStringSequenceSequenceOrByteStringByteStringRecord;
 
 // http://fetch.spec.whatwg.org/#headers-class
-class MODULES_EXPORT Headers final : public ScriptWrappable,
-                                     public PairIterable<String, String> {
+class CORE_EXPORT Headers final : public ScriptWrappable,
+                                  public PairIterable<String, String> {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
diff --git a/third_party/WebKit/Source/modules/fetch/Headers.idl b/third_party/WebKit/Source/core/fetch/Headers.idl
similarity index 100%
rename from third_party/WebKit/Source/modules/fetch/Headers.idl
rename to third_party/WebKit/Source/core/fetch/Headers.idl
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 5167d58a..5a9900b4 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -5486,6 +5486,15 @@
   lifecycle_updates_throttled_ = false;
   if (auto owner = GetFrame().OwnerLayoutItem())
     owner.SetMayNeedPaintInvalidation();
+
+  LayoutView* layout_view = GetLayoutView();
+  bool layout_view_is_empty = layout_view && !layout_view->FirstChild();
+  if (layout_view_is_empty && !DidFirstLayout() && !NeedsLayout()) {
+    // Make sure a display:none iframe gets an initial layout pass.
+    layout_view->SetNeedsLayout(LayoutInvalidationReason::kAddedToLayout,
+                                kMarkOnlyThis);
+  }
+
   SetupRenderThrottling();
   UpdateRenderThrottlingStatus(hidden_for_throttling_, subtree_throttled_);
   // The compositor will "defer commits" for the main frame until we
diff --git a/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp b/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp
index ee4c802..e943087 100644
--- a/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/WorkerFetchContext.cpp
@@ -245,6 +245,7 @@
   DCHECK(!user_agent.IsNull());
   request.SetHTTPUserAgent(AtomicString(user_agent));
 
+  request.OverrideLoadingIPCType(WebURLRequest::LoadingIPCType::kMojo);
   WrappedResourceRequest webreq(request);
   web_context_->WillSendRequest(webreq);
 }
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp
index 58221ee..5142774 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -119,10 +119,8 @@
 }
 
 SVGElementRareData* SVGElement::EnsureSVGRareData() {
-  if (HasSVGRareData())
-    return SvgRareData();
-
-  svg_rare_data_ = new SVGElementRareData(this);
+  if (!svg_rare_data_)
+    svg_rare_data_ = new SVGElementRareData();
   return svg_rare_data_.Get();
 }
 
diff --git a/third_party/WebKit/Source/core/svg/SVGElementRareData.cpp b/third_party/WebKit/Source/core/svg/SVGElementRareData.cpp
index 096e689..730147f6 100644
--- a/third_party/WebKit/Source/core/svg/SVGElementRareData.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElementRareData.cpp
@@ -45,7 +45,6 @@
   visitor->Trace(animated_smil_style_properties_);
   visitor->Trace(element_instances_);
   visitor->Trace(corresponding_element_);
-  visitor->Trace(owner_);
 }
 
 AffineTransform* SVGElementRareData::AnimateMotionTransform() {
diff --git a/third_party/WebKit/Source/core/svg/SVGElementRareData.h b/third_party/WebKit/Source/core/svg/SVGElementRareData.h
index 65c066fb3..967308b 100644
--- a/third_party/WebKit/Source/core/svg/SVGElementRareData.h
+++ b/third_party/WebKit/Source/core/svg/SVGElementRareData.h
@@ -34,9 +34,8 @@
 class SVGElementRareData
     : public GarbageCollectedFinalized<SVGElementRareData> {
  public:
-  SVGElementRareData(SVGElement* owner)
-      : owner_(owner),
-        corresponding_element_(nullptr),
+  SVGElementRareData()
+      : corresponding_element_(nullptr),
         instances_updates_blocked_(false),
         use_override_computed_style_(false),
         needs_override_computed_style_update_(false),
@@ -103,7 +102,6 @@
   void Trace(blink::Visitor*);
 
  private:
-  Member<SVGElement> owner_;
   SVGElementSet outgoing_references_;
   SVGElementSet incoming_references_;
   HeapHashSet<WeakMember<SVGElement>> element_instances_;
diff --git a/third_party/WebKit/Source/devtools/front_end/network/RequestResponseView.js b/third_party/WebKit/Source/devtools/front_end/network/RequestResponseView.js
index eb9a2ff..db2e463 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/RequestResponseView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/RequestResponseView.js
@@ -47,11 +47,17 @@
    * @return {boolean}
    */
   static _hasTextContent(request, contentData) {
-    if (request.resourceType().isTextType())
+    var mimeType = request.mimeType;
+    var resourceType = Common.ResourceType.fromMimeType(mimeType);
+    if (resourceType === Common.resourceTypes.Other)
+      resourceType = request.contentType();
+    if (resourceType === Common.resourceTypes.Image)
+      return mimeType.startsWith('image/svg');
+    if (resourceType.isTextType())
       return true;
     if (contentData.error)
       return false;
-    if (request.resourceType() === Common.resourceTypes.Other)
+    if (resourceType === Common.resourceTypes.Other)
       return !!contentData.content && !contentData.encoded;
     return false;
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/PreviewFactory.js b/third_party/WebKit/Source/devtools/front_end/source_frame/PreviewFactory.js
index 73a6adb..bdf311ae 100644
--- a/third_party/WebKit/Source/devtools/front_end/source_frame/PreviewFactory.js
+++ b/third_party/WebKit/Source/devtools/front_end/source_frame/PreviewFactory.js
@@ -13,6 +13,17 @@
     if (!content)
       return new UI.EmptyWidget(Common.UIString('Nothing to preview'));
 
+    var resourceType = Common.ResourceType.fromMimeType(mimeType);
+    if (resourceType === Common.resourceTypes.Other)
+      resourceType = provider.contentType();
+
+    switch (resourceType) {
+      case Common.resourceTypes.Image:
+        return new SourceFrame.ImageView(mimeType, provider);
+      case Common.resourceTypes.Font:
+        return new SourceFrame.FontView(mimeType, provider);
+    }
+
     var parsedXML = SourceFrame.XMLView.parseXML(content, mimeType);
     if (parsedXML)
       return SourceFrame.XMLView.createSearchableView(parsedXML);
@@ -22,19 +33,11 @@
     if (parsedJSON && typeof parsedJSON.data === 'object')
       return SourceFrame.JSONView.createSearchableView(/** @type {!SourceFrame.ParsedJSON} */ (parsedJSON));
 
-    var resourceType = provider.contentType() || Common.resourceTypes.Other;
-
     if (resourceType.isTextType()) {
       var highlighterType = mimeType.replace(/;.*/, '');  // remove charset
       return SourceFrame.ResourceSourceFrame.createSearchableView(provider, highlighterType);
     }
 
-    switch (resourceType) {
-      case Common.resourceTypes.Image:
-        return new SourceFrame.ImageView(mimeType, provider);
-      case Common.resourceTypes.Font:
-        return new SourceFrame.FontView(mimeType, provider);
-    }
     return null;
   }
 };
diff --git a/third_party/WebKit/Source/modules/BUILD.gn b/third_party/WebKit/Source/modules/BUILD.gn
index 9cbd80e..4ef12f6 100644
--- a/third_party/WebKit/Source/modules/BUILD.gn
+++ b/third_party/WebKit/Source/modules/BUILD.gn
@@ -263,7 +263,6 @@
     "csspaint/PaintWorkletTest.cpp",
     "document_metadata/CopylessPasteExtractorTest.cpp",
     "eventsource/EventSourceParserTest.cpp",
-    "fetch/FetchHeaderListTest.cpp",
     "fetch/FetchResponseDataTest.cpp",
     "fetch/RequestTest.cpp",
     "fetch/ResponseTest.cpp",
diff --git a/third_party/WebKit/Source/modules/fetch/BUILD.gn b/third_party/WebKit/Source/modules/fetch/BUILD.gn
index c188a3d..ebf5680 100644
--- a/third_party/WebKit/Source/modules/fetch/BUILD.gn
+++ b/third_party/WebKit/Source/modules/fetch/BUILD.gn
@@ -6,8 +6,6 @@
 
 blink_modules_sources("fetch") {
   sources = [
-    "FetchHeaderList.cpp",
-    "FetchHeaderList.h",
     "FetchManager.cpp",
     "FetchManager.h",
     "FetchRequestData.cpp",
@@ -16,8 +14,6 @@
     "FetchResponseData.h",
     "GlobalFetch.cpp",
     "GlobalFetch.h",
-    "Headers.cpp",
-    "Headers.h",
     "Request.cpp",
     "Request.h",
     "RequestInit.cpp",
diff --git a/third_party/WebKit/Source/modules/fetch/FetchRequestData.cpp b/third_party/WebKit/Source/modules/fetch/FetchRequestData.cpp
index 7c3f1608..6138cd1 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchRequestData.cpp
+++ b/third_party/WebKit/Source/modules/fetch/FetchRequestData.cpp
@@ -8,9 +8,9 @@
 #include "core/fetch/BlobBytesConsumer.h"
 #include "core/fetch/BodyStreamBuffer.h"
 #include "core/fetch/BytesConsumer.h"
+#include "core/fetch/FetchHeaderList.h"
 #include "core/fetch/FormDataBytesConsumer.h"
 #include "core/loader/ThreadableLoader.h"
-#include "modules/fetch/FetchHeaderList.h"
 #include "platform/bindings/ScriptState.h"
 #include "platform/loader/fetch/ResourceLoaderOptions.h"
 #include "platform/loader/fetch/ResourceRequest.h"
diff --git a/third_party/WebKit/Source/modules/fetch/FetchResponseData.cpp b/third_party/WebKit/Source/modules/fetch/FetchResponseData.cpp
index cdf16fe..1a644a19 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchResponseData.cpp
+++ b/third_party/WebKit/Source/modules/fetch/FetchResponseData.cpp
@@ -5,8 +5,8 @@
 #include "modules/fetch/FetchResponseData.h"
 
 #include "core/fetch/BodyStreamBuffer.h"
+#include "core/fetch/FetchHeaderList.h"
 #include "core/typed_arrays/DOMArrayBuffer.h"
-#include "modules/fetch/FetchHeaderList.h"
 #include "platform/bindings/ScriptState.h"
 #include "platform/loader/fetch/FetchUtils.h"
 #include "platform/network/http_names.h"
diff --git a/third_party/WebKit/Source/modules/fetch/FetchResponseDataTest.cpp b/third_party/WebKit/Source/modules/fetch/FetchResponseDataTest.cpp
index 707cde2..e17c59f 100644
--- a/third_party/WebKit/Source/modules/fetch/FetchResponseDataTest.cpp
+++ b/third_party/WebKit/Source/modules/fetch/FetchResponseDataTest.cpp
@@ -4,8 +4,8 @@
 
 #include "modules/fetch/FetchResponseData.h"
 
+#include "core/fetch/FetchHeaderList.h"
 #include "core/typed_arrays/DOMArrayBuffer.h"
-#include "modules/fetch/FetchHeaderList.h"
 #include "platform/blob/BlobData.h"
 #include "platform/wtf/Vector.h"
 #include "public/platform/modules/serviceworker/WebServiceWorkerResponse.h"
diff --git a/third_party/WebKit/Source/modules/fetch/Request.h b/third_party/WebKit/Source/modules/fetch/Request.h
index 5436384..c03c5f3 100644
--- a/third_party/WebKit/Source/modules/fetch/Request.h
+++ b/third_party/WebKit/Source/modules/fetch/Request.h
@@ -8,9 +8,9 @@
 #include "bindings/core/v8/Dictionary.h"
 #include "bindings/modules/v8/request_or_usv_string.h"
 #include "core/fetch/Body.h"
+#include "core/fetch/Headers.h"
 #include "modules/ModulesExport.h"
 #include "modules/fetch/FetchRequestData.h"
-#include "modules/fetch/Headers.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
 #include "platform/weborigin/KURL.h"
diff --git a/third_party/WebKit/Source/modules/fetch/RequestInit.cpp b/third_party/WebKit/Source/modules/fetch/RequestInit.cpp
index c669361..5a80160 100644
--- a/third_party/WebKit/Source/modules/fetch/RequestInit.cpp
+++ b/third_party/WebKit/Source/modules/fetch/RequestInit.cpp
@@ -16,12 +16,12 @@
 #include "bindings/core/v8/V8URLSearchParams.h"
 #include "core/fetch/BlobBytesConsumer.h"
 #include "core/fetch/FormDataBytesConsumer.h"
+#include "core/fetch/Headers.h"
 #include "core/fileapi/Blob.h"
 #include "core/frame/Deprecation.h"
 #include "core/frame/UseCounter.h"
 #include "core/html/forms/FormData.h"
 #include "core/url/URLSearchParams.h"
-#include "modules/fetch/Headers.h"
 #include "platform/blob/BlobData.h"
 #include "platform/network/EncodedFormData.h"
 #include "platform/runtime_enabled_features.h"
diff --git a/third_party/WebKit/Source/modules/fetch/RequestInit.h b/third_party/WebKit/Source/modules/fetch/RequestInit.h
index 7ee36c8d..3950c50 100644
--- a/third_party/WebKit/Source/modules/fetch/RequestInit.h
+++ b/third_party/WebKit/Source/modules/fetch/RequestInit.h
@@ -7,8 +7,8 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "bindings/core/v8/NativeValueTraits.h"
-#include "bindings/modules/v8/byte_string_sequence_sequence_or_byte_string_byte_string_record.h"
-#include "modules/fetch/Headers.h"
+#include "bindings/core/v8/byte_string_sequence_sequence_or_byte_string_byte_string_record.h"
+#include "core/fetch/Headers.h"
 #include "platform/heap/Handle.h"
 #include "platform/weborigin/Referrer.h"
 #include "platform/wtf/Optional.h"
diff --git a/third_party/WebKit/Source/modules/fetch/Response.h b/third_party/WebKit/Source/modules/fetch/Response.h
index 8ba737d..56dc7096 100644
--- a/third_party/WebKit/Source/modules/fetch/Response.h
+++ b/third_party/WebKit/Source/modules/fetch/Response.h
@@ -9,9 +9,9 @@
 #include "bindings/core/v8/ScriptValue.h"
 #include "core/fetch/Body.h"
 #include "core/fetch/BodyStreamBuffer.h"
+#include "core/fetch/Headers.h"
 #include "modules/ModulesExport.h"
 #include "modules/fetch/FetchResponseData.h"
-#include "modules/fetch/Headers.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/blob/BlobData.h"
 #include "platform/heap/Handle.h"
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index 5351d9e..b21459e 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -116,7 +116,6 @@
           "encryptedmedia/MediaKeySystemAccess.idl",
           "encryptedmedia/MediaKeys.idl",
           "eventsource/EventSource.idl",
-          "fetch/Headers.idl",
           "fetch/Request.idl",
           "fetch/Response.idl",
           "filesystem/DOMFileSystem.idl",
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp
index d380a724..d55a62e 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScopeProxy.cpp
@@ -37,6 +37,7 @@
 #include "bindings/core/v8/SourceLocation.h"
 #include "bindings/core/v8/WorkerOrWorkletScriptController.h"
 #include "core/dom/ExecutionContext.h"
+#include "core/fetch/Headers.h"
 #include "core/frame/csp/ContentSecurityPolicy.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/messaging/MessagePort.h"
@@ -54,7 +55,6 @@
 #include "modules/background_fetch/BackgroundFetchedEventInit.h"
 #include "modules/background_sync/SyncEvent.h"
 #include "modules/exported/WebEmbeddedWorkerImpl.h"
-#include "modules/fetch/Headers.h"
 #include "modules/notifications/Notification.h"
 #include "modules/notifications/NotificationEvent.h"
 #include "modules/notifications/NotificationEventInit.h"
diff --git a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
index 9e8cf27..5861585f 100644
--- a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
@@ -412,6 +412,10 @@
   return resource_request_->CORSPreflightPolicy();
 }
 
+WebURLRequest::LoadingIPCType WebURLRequest::GetLoadingIPCType() const {
+  return resource_request_->GetLoadingIPCType();
+}
+
 void WebURLRequest::SetNavigationStartTime(double navigation_start_seconds) {
   resource_request_->SetNavigationStartTime(navigation_start_seconds);
 }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp
index d1ca12b..a6976e9 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.cpp
@@ -77,6 +77,7 @@
       is_external_request_(false),
       cors_preflight_policy_(
           network::mojom::CORSPreflightPolicy::kConsiderPreflight),
+      loading_ipc_type_(WebURLRequest::LoadingIPCType::kMojo),
       is_same_document_navigation_(false),
       input_perf_metric_report_policy_(
           InputToLoadPerfMetricReportPolicy::kNoReport),
@@ -118,6 +119,7 @@
   ui_start_time_ = data->ui_start_time_;
   is_external_request_ = data->is_external_request_;
   cors_preflight_policy_ = data->cors_preflight_policy_;
+  loading_ipc_type_ = data->loading_ipc_type_;
   input_perf_metric_report_policy_ = data->input_perf_metric_report_policy_;
   redirect_status_ = data->redirect_status_;
 }
@@ -204,6 +206,7 @@
   data->ui_start_time_ = ui_start_time_;
   data->is_external_request_ = is_external_request_;
   data->cors_preflight_policy_ = cors_preflight_policy_;
+  data->loading_ipc_type_ = loading_ipc_type_;
   data->input_perf_metric_report_policy_ = input_perf_metric_report_policy_;
   data->redirect_status_ = redirect_status_;
   return data;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h
index d63cab1..54c4bac7 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceRequest.h
@@ -334,6 +334,13 @@
     cors_preflight_policy_ = policy;
   }
 
+  void OverrideLoadingIPCType(WebURLRequest::LoadingIPCType loading_ipc_type) {
+    loading_ipc_type_ = loading_ipc_type;
+  }
+  WebURLRequest::LoadingIPCType GetLoadingIPCType() const {
+    return loading_ipc_type_;
+  }
+
   InputToLoadPerfMetricReportPolicy InputPerfMetricReportPolicy() const {
     return input_perf_metric_report_policy_;
   }
@@ -395,6 +402,7 @@
   double ui_start_time_;
   bool is_external_request_;
   network::mojom::CORSPreflightPolicy cors_preflight_policy_;
+  WebURLRequest::LoadingIPCType loading_ipc_type_;
   bool is_same_document_navigation_;
   InputToLoadPerfMetricReportPolicy input_perf_metric_report_policy_;
   RedirectStatus redirect_status_;
@@ -456,6 +464,7 @@
   double ui_start_time_;
   bool is_external_request_;
   network::mojom::CORSPreflightPolicy cors_preflight_policy_;
+  WebURLRequest::LoadingIPCType loading_ipc_type_;
   InputToLoadPerfMetricReportPolicy input_perf_metric_report_policy_;
   ResourceRequest::RedirectStatus redirect_status_;
 };
diff --git a/third_party/WebKit/public/platform/WebURLRequest.h b/third_party/WebKit/public/platform/WebURLRequest.h
index 9575dda..2b4515f 100644
--- a/third_party/WebKit/public/platform/WebURLRequest.h
+++ b/third_party/WebKit/public/platform/WebURLRequest.h
@@ -155,6 +155,11 @@
     kNone
   };
 
+  enum class LoadingIPCType : uint8_t {
+    kChromeIPC,
+    kMojo,
+  };
+
   class ExtraData {
    public:
     virtual ~ExtraData() = default;
@@ -338,6 +343,8 @@
   BLINK_PLATFORM_EXPORT network::mojom::CORSPreflightPolicy
   GetCORSPreflightPolicy() const;
 
+  BLINK_PLATFORM_EXPORT LoadingIPCType GetLoadingIPCType() const;
+
   BLINK_PLATFORM_EXPORT void SetNavigationStartTime(double);
 
   // PlzNavigate: specify that the request was intended to be loaded as a same
diff --git a/third_party/libaom/generate_gni.sh b/third_party/libaom/generate_gni.sh
index f5acabd..40d9be9e 100755
--- a/third_party/libaom/generate_gni.sh
+++ b/third_party/libaom/generate_gni.sh
@@ -312,6 +312,10 @@
 all_platforms="--enable-external-build --enable-postproc --disable-av1-encoder"
 all_platforms="${all_platforms} --size-limit=16384x16384"
 all_platforms="${all_platforms} --enable-realtime-only --disable-install-docs"
+# TODO(tomfinegan): This is a workaround for
+# https://bugs.chromium.org/p/aomedia/issues/detail?id=1173. It should be
+# removed once the quality issue is sorted out.
+all_platforms="${all_platforms} --disable-highbitdepth"
 x86_platforms="--enable-pic --as=yasm"
 gen_config_files linux/ia32 "--target=x86-linux-gcc ${all_platforms} ${x86_platforms}"
 gen_config_files linux/x64 "--target=x86_64-linux-gcc ${all_platforms} ${x86_platforms}"
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index c0db796..78542c9 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -27,7 +27,7 @@
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md
 # Reverting problematic clang rolls is safe, though.
-CLANG_REVISION = '321204'
+CLANG_REVISION = '318667'
 
 use_head_revision = bool(os.environ.get('LLVM_FORCE_HEAD_REVISION', '0')
                          in ('1', 'YES'))
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index f658725b..db372a4 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -1772,11 +1772,13 @@
 </action>
 
 <action name="AppList_AutoLaunchCanceled">
+  <obsolete>Voice search in Launcher is not supported anymore.</obsolete>
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
 </action>
 
 <action name="AppList_AutoLaunched">
+  <obsolete>Voice search in Launcher is not supported anymore.</obsolete>
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
 </action>
diff --git a/ui/app_list/app_list_view_delegate.h b/ui/app_list/app_list_view_delegate.h
index f72dd4855..944d707 100644
--- a/ui/app_list/app_list_view_delegate.h
+++ b/ui/app_list/app_list_view_delegate.h
@@ -50,7 +50,6 @@
 
   // Invoked to open the search result.
   virtual void OpenSearchResult(SearchResult* result,
-                                bool auto_launch,
                                 int event_flags) = 0;
 
   // Called to invoke a custom action on |result|.  |action_index| corresponds
@@ -59,13 +58,6 @@
                                         int action_index,
                                         int event_flags) = 0;
 
-  // Gets the timeout for auto-launching the first search result, or 0 if the
-  //  auto-launch should not happen for the current search session.
-  virtual base::TimeDelta GetAutoLaunchTimeout() = 0;
-
-  // Invoked when the auto-launch is canceled by the user action.
-  virtual void AutoLaunchCanceled() = 0;
-
   // Invoked when the app list UI is created.
   virtual void ViewInitialized() = 0;
 
diff --git a/ui/app_list/search/mixer.cc b/ui/app_list/search/mixer.cc
index 3fa7e30..7327053 100644
--- a/ui/app_list/search/mixer.cc
+++ b/ui/app_list/search/mixer.cc
@@ -61,7 +61,7 @@
     providers_.emplace_back(provider);
   }
 
-  void FetchResults(bool is_voice_query, const KnownResults& known_results) {
+  void FetchResults(const KnownResults& known_results) {
     results_.clear();
 
     for (const SearchProvider* provider : providers_) {
@@ -102,10 +102,6 @@
                   break;
               }
             }
-
-            // If this is a voice query, voice results receive a massive boost.
-            if (is_voice_query && result->voice_result())
-              boost += 4.0;
           }
         }
 
@@ -148,10 +144,9 @@
   groups_[group_id]->AddProvider(provider);
 }
 
-void Mixer::MixAndPublish(bool is_voice_query,
-                          const KnownResults& known_results,
+void Mixer::MixAndPublish(const KnownResults& known_results,
                           size_t num_max_results) {
-  FetchResults(is_voice_query, known_results);
+  FetchResults(known_results);
 
   SortedResults results;
   results.reserve(num_max_results);
@@ -251,10 +246,9 @@
   results->swap(final);
 }
 
-void Mixer::FetchResults(bool is_voice_query,
-                         const KnownResults& known_results) {
+void Mixer::FetchResults(const KnownResults& known_results) {
   for (const auto& group : groups_)
-    group->FetchResults(is_voice_query, known_results);
+    group->FetchResults(known_results);
 }
 
 }  // namespace app_list
diff --git a/ui/app_list/search/mixer.h b/ui/app_list/search/mixer.h
index 1f7adb5..ba26b28 100644
--- a/ui/app_list/search/mixer.h
+++ b/ui/app_list/search/mixer.h
@@ -47,9 +47,7 @@
   void AddProviderToGroup(size_t group_id, SearchProvider* provider);
 
   // Collects the results, sorts and publishes them.
-  void MixAndPublish(bool is_voice_query,
-                     const KnownResults& known_results,
-                     size_t num_max_results);
+  void MixAndPublish(const KnownResults& known_results, size_t num_max_results);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(test::MixerTest, Publish);
@@ -81,7 +79,7 @@
   // |results| may not have been sorted yet.
   static void RemoveDuplicates(SortedResults* results);
 
-  void FetchResults(bool is_voice_query, const KnownResults& known_results);
+  void FetchResults(const KnownResults& known_results);
 
   SearchModel::SearchResults* ui_results_;  // Not owned.
   Groups groups_;
diff --git a/ui/app_list/search/mixer_unittest.cc b/ui/app_list/search/mixer_unittest.cc
index fe3afdc3..ba0b0bb2 100644
--- a/ui/app_list/search/mixer_unittest.cc
+++ b/ui/app_list/search/mixer_unittest.cc
@@ -77,7 +77,7 @@
   ~TestSearchProvider() override {}
 
   // SearchProvider overrides:
-  void Start(bool is_voice_query, const base::string16& query) override {
+  void Start(const base::string16& query) override {
     ClearResults();
     for (size_t i = 0; i < count_; ++i) {
       const std::string id =
@@ -116,7 +116,7 @@
 
 class MixerTest : public testing::Test {
  public:
-  MixerTest() : is_voice_query_(false) {}
+  MixerTest() {}
   ~MixerTest() override {}
 
   // testing::Test overrides:
@@ -127,8 +127,6 @@
     providers_.push_back(std::make_unique<TestSearchProvider>("omnibox"));
     providers_.push_back(std::make_unique<TestSearchProvider>("webstore"));
 
-    is_voice_query_ = false;
-
     mixer_.reset(new Mixer(results_.get()));
 
     // TODO(warx): when fullscreen app list is default enabled, modify this test
@@ -147,9 +145,9 @@
     const base::string16 query;
 
     for (size_t i = 0; i < providers_.size(); ++i)
-      providers_[i]->Start(is_voice_query_, query);
+      providers_[i]->Start(query);
 
-    mixer_->MixAndPublish(is_voice_query_, known_results_, kMaxSearchResults);
+    mixer_->MixAndPublish(known_results_, kMaxSearchResults);
   }
 
   std::string GetResults() const {
@@ -169,11 +167,6 @@
   TestSearchProvider* omnibox_provider() { return providers_[1].get(); }
   TestSearchProvider* webstore_provider() { return providers_[2].get(); }
 
-  // Sets whether test runs should be treated as a voice query.
-  void set_is_voice_query(bool is_voice_query) {
-    is_voice_query_ = is_voice_query;
-  }
-
   void AddKnownResult(const std::string& id, KnownResultType type) {
     known_results_[id] = type;
   }
@@ -183,8 +176,6 @@
   std::unique_ptr<SearchModel::SearchResults> results_;
   KnownResults known_results_;
 
-  bool is_voice_query_;
-
   std::vector<std::unique_ptr<TestSearchProvider>> providers_;
 
   DISALLOW_COPY_AND_ASSIGN(MixerTest);
@@ -320,16 +311,6 @@
   omnibox_provider()->set_as_voice_result(1);
   RunQuery();
   EXPECT_EQ("omnibox0,omnibox1,omnibox2", GetResults());
-
-  // Perform a voice query. Expect voice result first.
-  set_is_voice_query(true);
-  RunQuery();
-  EXPECT_EQ("omnibox1,omnibox0,omnibox2", GetResults());
-
-  // All voice results should appear before non-voice results.
-  omnibox_provider()->set_as_voice_result(2);
-  RunQuery();
-  EXPECT_EQ("omnibox1,omnibox2,omnibox0", GetResults());
 }
 
 TEST_F(MixerTest, Publish) {
diff --git a/ui/app_list/search_controller.cc b/ui/app_list/search_controller.cc
index 705f2192..fd2f6c7 100644
--- a/ui/app_list/search_controller.cc
+++ b/ui/app_list/search_controller.cc
@@ -34,11 +34,9 @@
   base::string16 query;
   base::TrimWhitespace(search_box_->text(), base::TRIM_ALL, &query);
 
-  is_voice_query_ = search_box_->is_voice_query();
-
   dispatching_query_ = true;
   for (const auto& provider : providers_)
-    provider->Start(is_voice_query_, query);
+    provider->Start(query);
 
   dispatching_query_ = false;
   query_for_recommendation_ = query.empty();
@@ -110,7 +108,7 @@
 
   size_t num_max_results =
       query_for_recommendation_ ? kNumStartPageTiles : kMaxSearchResults;
-  mixer_->MixAndPublish(is_voice_query_, known_results, num_max_results);
+  mixer_->MixAndPublish(known_results, num_max_results);
 }
 
 }  // namespace app_list
diff --git a/ui/app_list/search_controller.h b/ui/app_list/search_controller.h
index 72073039..80242920 100644
--- a/ui/app_list/search_controller.h
+++ b/ui/app_list/search_controller.h
@@ -62,8 +62,6 @@
   std::unique_ptr<Mixer> mixer_;
   History* history_;  // KeyedService, not owned.
 
-  bool is_voice_query_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(SearchController);
 };
 
diff --git a/ui/app_list/search_provider.h b/ui/app_list/search_provider.h
index 7461e19..3da16b7 100644
--- a/ui/app_list/search_provider.h
+++ b/ui/app_list/search_provider.h
@@ -26,7 +26,7 @@
   virtual ~SearchProvider();
 
   // Invoked to start a query.
-  virtual void Start(bool is_voice_query, const base::string16& query) = 0;
+  virtual void Start(const base::string16& query) = 0;
 
   void set_result_changed_callback(const ResultChangedCallback& callback) {
     result_changed_callback_ = callback;
diff --git a/ui/app_list/test/app_list_test_view_delegate.cc b/ui/app_list/test/app_list_test_view_delegate.cc
index 59be767..94e46f0 100644
--- a/ui/app_list/test/app_list_test_view_delegate.cc
+++ b/ui/app_list/test/app_list_test_view_delegate.cc
@@ -42,7 +42,6 @@
 }
 
 void AppListTestViewDelegate::OpenSearchResult(SearchResult* result,
-                                               bool auto_launch,
                                                int event_flags) {
   const SearchModel::SearchResults* results = search_model_->results();
   for (size_t i = 0; i < results->item_count(); ++i) {
@@ -54,14 +53,6 @@
   ++open_search_result_count_;
 }
 
-base::TimeDelta AppListTestViewDelegate::GetAutoLaunchTimeout() {
-  return auto_launch_timeout_;
-}
-
-void AppListTestViewDelegate::AutoLaunchCanceled() {
-  auto_launch_timeout_ = base::TimeDelta();
-}
-
 void AppListTestViewDelegate::Dismiss() {
   ++dismiss_count_;
 }
diff --git a/ui/app_list/test/app_list_test_view_delegate.h b/ui/app_list/test/app_list_test_view_delegate.h
index 289cbef..28d2658 100644
--- a/ui/app_list/test/app_list_test_view_delegate.h
+++ b/ui/app_list/test/app_list_test_view_delegate.h
@@ -41,10 +41,6 @@
   // SetProfileByPath() is called.
   void set_next_profile_app_count(int apps) { next_profile_app_count_ = apps; }
 
-  void set_auto_launch_timeout(const base::TimeDelta& timeout) {
-    auto_launch_timeout_ = timeout;
-  }
-
   // Returns the value of |stop_speech_recognition_count_| and then resets this
   // value to 0.
   int GetStopSpeechRecognitionCountAndReset();
@@ -58,13 +54,10 @@
   SpeechUIModel* GetSpeechUI() override;
   void StartSearch() override {}
   void OpenSearchResult(SearchResult* result,
-                        bool auto_launch,
                         int event_flags) override;
   void InvokeSearchResultAction(SearchResult* result,
                                 int action_index,
                                 int event_flags) override {}
-  base::TimeDelta GetAutoLaunchTimeout() override;
-  void AutoLaunchCanceled() override;
   void ViewInitialized() override {}
   void Dismiss() override;
   void ViewClosing() override {}
@@ -93,7 +86,6 @@
   std::unique_ptr<SearchModel> search_model_;
   SpeechUIModel speech_ui_;
   std::vector<SkColor> wallpaper_prominent_colors_;
-  base::TimeDelta auto_launch_timeout_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListTestViewDelegate);
 };
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 6c4ce22..259297b 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -307,7 +307,6 @@
 void SearchBoxView::ClearSearch() {
   search_box_->SetText(base::string16());
   UpdateCloseButtonVisisbility();
-  view_delegate_->AutoLaunchCanceled();
   // Updates model and fires query changed manually because SetText() above
   // does not generate ContentsChanged() notification.
   UpdateModel(false);
@@ -699,8 +698,7 @@
 void SearchBoxView::UpdateModel(bool initiated_by_user) {
   // Temporarily remove from observer to ignore notifications caused by us.
   search_model_->search_box()->RemoveObserver(this);
-  search_model_->search_box()->Update(search_box_->text(), false,
-                                      initiated_by_user);
+  search_model_->search_box()->Update(search_box_->text(), initiated_by_user);
   search_model_->search_box()->SetSelectionModel(
       search_box_->GetSelectionModel());
   search_model_->search_box()->AddObserver(this);
@@ -716,7 +714,6 @@
   // Set search box focused when query changes.
   search_box_->RequestFocus();
   UpdateModel(true);
-  view_delegate_->AutoLaunchCanceled();
   NotifyQueryChanged();
   SetSearchBoxActive(true);
   UpdateCloseButtonVisisbility();
diff --git a/ui/app_list/views/search_box_view_unittest.cc b/ui/app_list/views/search_box_view_unittest.cc
index e2c4c23..0876433 100644
--- a/ui/app_list/views/search_box_view_unittest.cc
+++ b/ui/app_list/views/search_box_view_unittest.cc
@@ -92,19 +92,6 @@
 
   void SetSearchBoxActive(bool active) { view()->SetSearchBoxActive(active); }
 
-  void SetLongAutoLaunchTimeout() {
-    // Sets a long timeout that lasts longer than the test run.
-    view_delegate_.set_auto_launch_timeout(base::TimeDelta::FromDays(1));
-  }
-
-  base::TimeDelta GetAutoLaunchTimeout() {
-    return view_delegate_.GetAutoLaunchTimeout();
-  }
-
-  void ResetAutoLaunchTimeout() {
-    view_delegate_.set_auto_launch_timeout(base::TimeDelta());
-  }
-
   int GetContentsViewKeyPressCountAndReset() {
     return counter_view_->GetCountAndReset();
   }
@@ -151,29 +138,6 @@
   DISALLOW_COPY_AND_ASSIGN(SearchBoxViewTest);
 };
 
-// TODO(crbug.com/781407) Re-enable the test once voice search is back.
-TEST_F(SearchBoxViewTest, DISABLED_CancelAutoLaunch) {
-  SetLongAutoLaunchTimeout();
-  ASSERT_NE(base::TimeDelta(), GetAutoLaunchTimeout());
-
-  // Normal key event cancels the timeout.
-  KeyPress(ui::VKEY_A);
-  EXPECT_EQ(base::TimeDelta(), GetAutoLaunchTimeout());
-  ResetAutoLaunchTimeout();
-
-  // Unusual key event doesn't cancel -- it will be canceled in
-  // SearchResultListView.
-  SetLongAutoLaunchTimeout();
-  KeyPress(ui::VKEY_DOWN);
-  EXPECT_NE(base::TimeDelta(), GetAutoLaunchTimeout());
-  ResetAutoLaunchTimeout();
-
-  // Clearing search box also cancels.
-  SetLongAutoLaunchTimeout();
-  view()->ClearSearch();
-  EXPECT_EQ(base::TimeDelta(), GetAutoLaunchTimeout());
-}
-
 // Tests that the close button is invisible by default.
 TEST_F(SearchBoxViewTest, CloseButtonInvisibleByDefault) {
   EXPECT_FALSE(view()->close_button()->visible());
diff --git a/ui/app_list/views/search_result_answer_card_view.cc b/ui/app_list/views/search_result_answer_card_view.cc
index 9408c26..1d97f5b 100644
--- a/ui/app_list/views/search_result_answer_card_view.cc
+++ b/ui/app_list/views/search_result_answer_card_view.cc
@@ -122,7 +122,7 @@
   void ButtonPressed(views::Button* sender, const ui::Event& event) override {
     DCHECK(sender == this);
     if (search_result_)
-      view_delegate_->OpenSearchResult(search_result_, false, event.flags());
+      view_delegate_->OpenSearchResult(search_result_, event.flags());
   }
 
   // SearchResultObserver overrides:
diff --git a/ui/app_list/views/search_result_list_view.cc b/ui/app_list/views/search_result_list_view.cc
index f78ad7f..34294a5 100644
--- a/ui/app_list/views/search_result_list_view.cc
+++ b/ui/app_list/views/search_result_list_view.cc
@@ -11,7 +11,6 @@
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "base/time/time.h"
-#include "third_party/skia/include/core/SkColor.h"
 #include "ui/app_list/app_list_view_delegate.h"
 #include "ui/app_list/views/app_list_main_view.h"
 #include "ui/app_list/views/search_result_view.h"
@@ -24,10 +23,6 @@
 namespace {
 
 constexpr int kMaxResults = 5;
-constexpr int kTimeoutIndicatorHeight = 2;
-constexpr int kTimeoutFramerate = 60;
-constexpr SkColor kTimeoutIndicatorColor =
-    SkColorSetARGBMacro(255, 30, 144, 255);
 
 }  // namespace
 
@@ -37,20 +32,13 @@
                                            AppListViewDelegate* view_delegate)
     : main_view_(main_view),
       view_delegate_(view_delegate),
-      results_container_(new views::View),
-      auto_launch_indicator_(new views::View) {
+      results_container_(new views::View) {
   results_container_->SetLayoutManager(
       std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
 
   for (int i = 0; i < kMaxResults; ++i)
     results_container_->AddChildView(new SearchResultView(this));
   AddChildView(results_container_);
-
-  auto_launch_indicator_->SetBackground(
-      views::CreateSolidBackground(kTimeoutIndicatorColor));
-  auto_launch_indicator_->SetVisible(false);
-
-  AddChildView(auto_launch_indicator_);
 }
 
 SearchResultListView::~SearchResultListView() {}
@@ -64,29 +52,6 @@
              results_container_->child_at(selected_index())) == result_view;
 }
 
-void SearchResultListView::UpdateAutoLaunchState() {
-  SetAutoLaunchTimeout(view_delegate_->GetAutoLaunchTimeout());
-}
-
-void SearchResultListView::SetAutoLaunchTimeout(
-    const base::TimeDelta& timeout) {
-  if (timeout > base::TimeDelta()) {
-    auto_launch_indicator_->SetVisible(true);
-    auto_launch_indicator_->SetBounds(0, 0, 0, kTimeoutIndicatorHeight);
-    auto_launch_animation_.reset(
-        new gfx::LinearAnimation(timeout, kTimeoutFramerate, this));
-    auto_launch_animation_->Start();
-  } else {
-    auto_launch_indicator_->SetVisible(false);
-    auto_launch_animation_.reset();
-  }
-}
-
-void SearchResultListView::CancelAutoLaunchTimeout() {
-  SetAutoLaunchTimeout(base::TimeDelta());
-  view_delegate_->AutoLaunchCanceled();
-}
-
 SearchResultView* SearchResultListView::GetResultViewAt(int index) const {
   DCHECK(index >= 0 && index < results_container_->child_count());
   return static_cast<SearchResultView*>(results_container_->child_at(index));
@@ -156,7 +121,6 @@
       result_view->SetVisible(false);
     }
   }
-  UpdateAutoLaunchState();
 
   set_container_score(
       display_results.empty() ? 0 : display_results.front()->relevance());
@@ -181,11 +145,6 @@
   }
 }
 
-void SearchResultListView::ForceAutoLaunchForTest() {
-  if (auto_launch_animation_)
-    AnimationEnded(auto_launch_animation_.get());
-}
-
 void SearchResultListView::Layout() {
   results_container_->SetBoundsRect(GetLocalBounds());
 }
@@ -198,43 +157,10 @@
   return results_container_->GetHeightForWidth(w);
 }
 
-void SearchResultListView::VisibilityChanged(views::View* starting_from,
-                                             bool is_visible) {
-  if (is_visible)
-    UpdateAutoLaunchState();
-  else
-    CancelAutoLaunchTimeout();
-}
-
-void SearchResultListView::AnimationEnded(const gfx::Animation* animation) {
-  DCHECK_EQ(auto_launch_animation_.get(), animation);
-  if (results()->item_count() > 0) {
-    view_delegate_->OpenSearchResult(results()->GetItemAt(0), true,
-                                     ui::EF_NONE);
-  }
-
-  // The auto-launch has to be canceled explicitly. Think that one of searcher
-  // is extremely slow. Sometimes the events would happen in the following
-  // order:
-  //  1. The search results arrive, auto-launch is dispatched
-  //  2. Timed out and auto-launch the first search result
-  //  3. Then another searcher adds search results more
-  // At the step 3, we shouldn't dispatch the auto-launch again.
-  CancelAutoLaunchTimeout();
-}
-
-void SearchResultListView::AnimationProgressed(
-    const gfx::Animation* animation) {
-  DCHECK_EQ(auto_launch_animation_.get(), animation);
-  int indicator_width = auto_launch_animation_->CurrentValueBetween(0, width());
-  auto_launch_indicator_->SetBounds(0, 0, indicator_width,
-                                    kTimeoutIndicatorHeight);
-}
-
 void SearchResultListView::SearchResultActivated(SearchResultView* view,
                                                  int event_flags) {
   if (view_delegate_ && view->result())
-    view_delegate_->OpenSearchResult(view->result(), false, event_flags);
+    view_delegate_->OpenSearchResult(view->result(), event_flags);
 }
 
 void SearchResultListView::SearchResultActionActivated(SearchResultView* view,
diff --git a/ui/app_list/views/search_result_list_view.h b/ui/app_list/views/search_result_list_view.h
index e203dcc..08ae3450 100644
--- a/ui/app_list/views/search_result_list_view.h
+++ b/ui/app_list/views/search_result_list_view.h
@@ -10,13 +10,8 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/app_list/views/search_result_container_view.h"
-#include "ui/gfx/animation/animation_delegate.h"
 #include "ui/views/view.h"
 
-namespace gfx {
-class LinearAnimation;
-}
-
 namespace app_list {
 namespace test {
 class SearchResultListViewTest;
@@ -28,15 +23,12 @@
 
 // SearchResultListView displays SearchResultList with a list of
 // SearchResultView.
-class APP_LIST_EXPORT SearchResultListView : public gfx::AnimationDelegate,
-                                             public SearchResultContainerView {
+class APP_LIST_EXPORT SearchResultListView : public SearchResultContainerView {
  public:
   SearchResultListView(AppListMainView* main_view,
                        AppListViewDelegate* view_delegate);
   ~SearchResultListView() override;
 
-  void UpdateAutoLaunchState();
-
   bool IsResultViewSelected(const SearchResultView* result_view) const;
 
   void SearchResultActivated(SearchResultView* view, int event_flags);
@@ -71,31 +63,17 @@
   int DoUpdate() override;
   void UpdateSelectedIndex(int old_selected, int new_selected) override;
 
-  // Updates the auto launch states.
-  void SetAutoLaunchTimeout(const base::TimeDelta& timeout);
-  void CancelAutoLaunchTimeout();
-
   // Helper function to get SearchResultView at given |index|.
   SearchResultView* GetResultViewAt(int index) const;
 
-  // Forcibly auto-launch for test if it is in auto-launching state.
-  void ForceAutoLaunchForTest();
-
   // Overridden from views::View:
   void Layout() override;
   int GetHeightForWidth(int w) const override;
-  void VisibilityChanged(views::View* starting_from, bool is_visible) override;
-
-  // Overridden from gfx::AnimationDelegate:
-  void AnimationEnded(const gfx::Animation* animation) override;
-  void AnimationProgressed(const gfx::Animation* animation) override;
 
   AppListMainView* main_view_;          // Owned by views hierarchy.
   AppListViewDelegate* view_delegate_;  // Not owned.
 
   views::View* results_container_;
-  views::View* auto_launch_indicator_;
-  std::unique_ptr<gfx::LinearAnimation> auto_launch_animation_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchResultListView);
 };
diff --git a/ui/app_list/views/search_result_list_view_unittest.cc b/ui/app_list/views/search_result_list_view_unittest.cc
index ebcc1c4..ea1bd0cd 100644
--- a/ui/app_list/views/search_result_list_view_unittest.cc
+++ b/ui/app_list/views/search_result_list_view_unittest.cc
@@ -52,15 +52,6 @@
     return view_delegate_.GetSearchModel()->results();
   }
 
-  void SetLongAutoLaunchTimeout() {
-    // Sets a long timeout that lasts longer than the test run.
-    view_delegate_.set_auto_launch_timeout(base::TimeDelta::FromDays(1));
-  }
-
-  base::TimeDelta GetAutoLaunchTimeout() {
-    return view_delegate_.GetAutoLaunchTimeout();
-  }
-
   void SetUpSearchResults() {
     SearchModel::SearchResults* results = GetResults();
     for (int i = 0; i < kDefaultSearchItems; ++i) {
@@ -102,10 +93,6 @@
     return view_->OnKeyPressed(event);
   }
 
-  bool IsAutoLaunching() const { return !!view_->auto_launch_animation_; }
-
-  void ForceAutoLaunch() { view_->ForceAutoLaunchForTest(); }
-
   void ExpectConsistent() {
     // Adding results will schedule Update().
     RunPendingMessages();
@@ -127,83 +114,6 @@
   DISALLOW_COPY_AND_ASSIGN(SearchResultListViewTest);
 };
 
-// TODO(crbug.com/766807): Remove the test once the new focus model is stable.
-TEST_F(SearchResultListViewTest, DISABLED_Basic) {
-  SetUpSearchResults();
-
-  const int results = GetResultCount();
-  EXPECT_EQ(kDefaultSearchItems, results);
-  EXPECT_EQ(0, GetSelectedIndex());
-  EXPECT_FALSE(IsAutoLaunching());
-
-  EXPECT_TRUE(KeyPress(ui::VKEY_RETURN));
-  EXPECT_EQ(1, GetOpenResultCountAndReset(0));
-
-  for (int i = 1; i < results; ++i) {
-    EXPECT_TRUE(KeyPress(ui::VKEY_DOWN));
-    EXPECT_EQ(i, GetSelectedIndex());
-  }
-  // When navigating off the end of the list, pass the event to the parent to
-  // handle.
-  EXPECT_FALSE(KeyPress(ui::VKEY_DOWN));
-  EXPECT_EQ(results - 1, GetSelectedIndex());
-
-  for (int i = 1; i < results; ++i) {
-    EXPECT_TRUE(KeyPress(ui::VKEY_UP));
-    EXPECT_EQ(results - i - 1, GetSelectedIndex());
-  }
-  // Navigate off top of list.
-  EXPECT_FALSE(KeyPress(ui::VKEY_UP));
-  EXPECT_EQ(0, GetSelectedIndex());
-  ResetSelectedIndex();
-
-  for (int i = 1; i < results; ++i) {
-    EXPECT_TRUE(KeyPress(ui::VKEY_TAB));
-    EXPECT_EQ(i, GetSelectedIndex());
-  }
-  // Navigate off bottom of list.
-  EXPECT_FALSE(KeyPress(ui::VKEY_TAB));
-  EXPECT_EQ(results - 1, GetSelectedIndex());
-}
-
-// TODO(crbug.com/781407) Re-enable the test once voice search is back.
-TEST_F(SearchResultListViewTest, DISABLED_AutoLaunch) {
-  SetLongAutoLaunchTimeout();
-  SetUpSearchResults();
-
-  EXPECT_TRUE(IsAutoLaunching());
-  ForceAutoLaunch();
-
-  EXPECT_FALSE(IsAutoLaunching());
-  EXPECT_EQ(1, GetOpenResultCountAndReset(0));
-
-  // The timeout has to be cleared after the auto-launch, to prevent opening
-  // the search result twice. See the comment in AnimationEnded().
-  EXPECT_EQ(base::TimeDelta(), GetAutoLaunchTimeout());
-}
-
-// TODO(crbug.com/781407) Re-enable the test once voice search is back.
-TEST_F(SearchResultListViewTest, DISABLED_CancelAutoLaunch) {
-  SetLongAutoLaunchTimeout();
-  SetUpSearchResults();
-
-  EXPECT_TRUE(IsAutoLaunching());
-
-  EXPECT_TRUE(KeyPress(ui::VKEY_DOWN));
-  EXPECT_FALSE(IsAutoLaunching());
-
-  SetLongAutoLaunchTimeout();
-  view()->UpdateAutoLaunchState();
-  EXPECT_TRUE(IsAutoLaunching());
-
-  view()->SetVisible(false);
-  EXPECT_FALSE(IsAutoLaunching());
-
-  SetLongAutoLaunchTimeout();
-  view()->SetVisible(true);
-  EXPECT_TRUE(IsAutoLaunching());
-}
-
 TEST_F(SearchResultListViewTest, SpokenFeedback) {
   SetUpSearchResults();
 
diff --git a/ui/app_list/views/search_result_tile_item_view.cc b/ui/app_list/views/search_result_tile_item_view.cc
index 2c0cb56..b181e30 100644
--- a/ui/app_list/views/search_result_tile_item_view.cc
+++ b/ui/app_list/views/search_result_tile_item_view.cc
@@ -237,7 +237,7 @@
   if (IsSuggestedAppTile())
     LogAppLaunch();
 
-  view_delegate_->OpenSearchResult(item_, false, event.flags());
+  view_delegate_->OpenSearchResult(item_, event.flags());
 }
 
 void SearchResultTileItemView::GetAccessibleNodeData(
@@ -263,7 +263,7 @@
     if (IsSuggestedAppTile())
       LogAppLaunch();
 
-    view_delegate_->OpenSearchResult(item_, false, event.flags());
+    view_delegate_->OpenSearchResult(item_, event.flags());
     return true;
   }
 
diff --git a/ui/events/platform/x11/x11_event_source.cc b/ui/events/platform/x11/x11_event_source.cc
index ed3581a9..a3f614d 100644
--- a/ui/events/platform/x11/x11_event_source.cc
+++ b/ui/events/platform/x11/x11_event_source.cc
@@ -143,6 +143,10 @@
   ExtractCookieDataDispatchEvent(event);
 }
 
+void X11EventSource::BlockUntilWindowMapped(XID window) {
+  BlockOnWindowStructureEvent(window, MapNotify);
+}
+
 Time X11EventSource::GetCurrentServerTime() {
   DCHECK(display_);
 
@@ -272,6 +276,16 @@
   }
 }
 
+void X11EventSource::BlockOnWindowStructureEvent(XID window, int type) {
+  XEvent event;
+  do {
+    // Block until there's a StructureNotify event of |type| on |window|. Then
+    // remove it from the queue and stuff it in |event|.
+    XWindowEvent(display_, window, StructureNotifyMask, &event);
+    ExtractCookieDataDispatchEvent(&event);
+  } while (event.type != type);
+}
+
 void X11EventSource::StopCurrentEventStream() {
   continue_stream_ = false;
 }
diff --git a/ui/events/platform/x11/x11_event_source.h b/ui/events/platform/x11/x11_event_source.h
index a0cd370..c274490 100644
--- a/ui/events/platform/x11/x11_event_source.h
+++ b/ui/events/platform/x11/x11_event_source.h
@@ -62,6 +62,17 @@
   // main X11 event loop.
   void DispatchXEventNow(XEvent* event);
 
+  // Blocks on the X11 event queue until we receive notification from the
+  // xserver that |w| has been mapped; StructureNotifyMask events on |w| are
+  // pulled out from the queue and dispatched out of order.
+  //
+  // For those that know X11, this is really a wrapper around XWindowEvent
+  // which still makes sure the preempted event is dispatched instead of
+  // dropped on the floor. This method exists because mapping a window is
+  // asynchronous (and we receive an XEvent when mapped), while there are also
+  // functions which require a mapped window.
+  void BlockUntilWindowMapped(XID window);
+
   XDisplay* display() { return display_; }
 
   // Returns the timestamp of the event currently being dispatched.  Falls back
@@ -85,6 +96,10 @@
   // Handles updates after event has been dispatched.
   void PostDispatchEvent(XEvent* xevent);
 
+  // Block until receiving a structure notify event of |type| on |window|.
+  // Dispatch all encountered events prior to the one we're blocking on.
+  void BlockOnWindowStructureEvent(XID window, int type);
+
   // Explicitly asks the X11 server for the current timestamp, and updates
   // |last_seen_server_time_| with this value.
   Time GetCurrentServerTime();
diff --git a/ui/platform_window/x11/x11_window_base.cc b/ui/platform_window/x11/x11_window_base.cc
index d069fb0..d309fc8 100644
--- a/ui/platform_window/x11/x11_window_base.cc
+++ b/ui/platform_window/x11/x11_window_base.cc
@@ -144,13 +144,18 @@
     return;
 
   XMapWindow(xdisplay_, xwindow_);
+
+  // We now block until our window is mapped. Some X11 APIs will crash and
+  // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
+  // asynchronous.
+  if (X11EventSource::GetInstance())
+    X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
   window_mapped_ = true;
 }
 
 void X11WindowBase::Hide() {
   if (!window_mapped_)
     return;
-
   XWithdrawWindow(xdisplay_, xwindow_, 0);
   window_mapped_ = false;
 }
diff --git a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
index d6b086c1..cb78410 100644
--- a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
+++ b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
@@ -275,6 +275,7 @@
       new ui::XScopedEventSelector(grab_input_window_, event_mask));
 
   XMapRaised(display, grab_input_window_);
+  ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(grab_input_window_);
 }
 
 }  // namespace views