diff --git a/DEPS b/DEPS
index a82af38..4e7d417 100644
--- a/DEPS
+++ b/DEPS
@@ -78,7 +78,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'ba9cf60e14c870dae107dc4c071847f6ea800e23',
+  'v8_revision': 'ad1474a10f76712669b926fb1e53313c9921b487',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
index 03bb959..31c2626 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java
@@ -424,8 +424,6 @@
             String url = TemplateUrlService.getInstance().getSearchEngineUrlFromTemplateUrl(
                     toKeyword(mSelectedSearchEnginePosition));
             Bundle fragmentArgs = SingleWebsitePreferences.createFragmentArgsForSite(url);
-            fragmentArgs.putBoolean(SingleWebsitePreferences.EXTRA_LOCATION,
-                    locationEnabled((TemplateUrl) getItem(mSelectedSearchEnginePosition)));
             settingsIntent.putExtra(Preferences.EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs);
             mContext.startActivity(settingsIntent);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
index fb99774d..a01eab7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
@@ -48,12 +48,9 @@
     // EXTRA_ORIGIN (a WebsiteAddress) to be present (but not both). If
     // EXTRA_SITE is present, the fragment will display the permissions in that
     // Website object. If EXTRA_ORIGIN is present, the fragment will find all
-    // permissions for that website address and display those. If EXTRA_LOCATION
-    // is present, the fragment will add a Location toggle, even if the site
-    // specifies no Location permission.
+    // permissions for that website address and display those.
     public static final String EXTRA_SITE = "org.chromium.chrome.preferences.site";
     public static final String EXTRA_ORIGIN = "org.chromium.chrome.preferences.origin";
-    public static final String EXTRA_LOCATION = "org.chromium.chrome.preferences.location";
 
     public static final String EXTRA_WEB_CONTENTS = "org.chromium.chrome.preferences.web_contents";
     public static final String EXTRA_USB_INFO = "org.chromium.chrome.preferences.usb_info";
@@ -620,17 +617,11 @@
 
     private void setUpLocationPreference(Preference preference) {
         ContentSetting permission = mSite.getGeolocationPermission();
-        Object locationAllowed = getArguments().getSerializable(EXTRA_LOCATION);
         if (shouldUseDSEGeolocationSetting()) {
             String origin = mSite.getAddress().getOrigin();
             mSite.setGeolocationInfo(new GeolocationInfo(origin, origin, false));
             setUpListPreference(preference, ContentSetting.ALLOW);
             updateLocationPreferenceForDSESetting(preference);
-        } else if (permission == null && locationAllowed != null) {
-            String origin = mSite.getAddress().getOrigin();
-            mSite.setGeolocationInfo(new GeolocationInfo(origin, origin, false));
-            setUpListPreference(preference, (boolean) locationAllowed
-                    ? ContentSetting.ALLOW : ContentSetting.BLOCK);
         } else {
             setUpListPreference(preference, permission);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index ccacf483..080164c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -332,6 +332,12 @@
             }
 
             @Override
+            public void onShown(Tab tab) {
+                if (TextUtils.isEmpty(tab.getUrl())) return;
+                mControlContainer.setReadyForBitmapCapture(true);
+            }
+
+            @Override
             public void onCrash(Tab tab, boolean sadTabShown) {
                 updateTabLoadingState(false);
                 updateButtonStatus();
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js
index 4d1bc38..a5e1d1a 100644
--- a/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -91,6 +91,7 @@
     'menuGuestMode',             // Enables "Guest mode" menu item
     'menuKeyboardOptions',       // Enables "Keyboard options" menu item
     'menuEnterpriseEnrollment',  // Enables "Enterprise enrollment" menu item.
+    'lsbReleaseBoard',           // Chrome OS Release board name
 
     // The email fields allow for the following possibilities:
     //
@@ -328,6 +329,9 @@
           mi += 'ee,';
         if (mi.length)
           url = appendParam(url, 'mi', mi);
+
+        if (data.lsbReleaseBoard)
+          url = appendParam(url, 'chromeos_board', data.lsbReleaseBoard);
       }
     } else {
       url = appendParam(url, 'continue', this.continueUrl_);
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 740480a..f3eba34 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
@@ -370,6 +371,7 @@
     // (see https://crbug.com/709244 ).
     params.SetString("chromeOSApiVersion", "2");
   }
+  params.SetString("lsbReleaseBoard", base::SysInfo::GetLsbReleaseBoard());
 
   frame_state_ = FRAME_STATE_LOADING;
   CallJS("loadAuthExtension", params);
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index 9c5fac9..ce0b826d 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -22,7 +22,6 @@
     "color_scheme.h",
     "content_input_delegate.cc",
     "content_input_delegate.h",
-    "controller_mesh.cc",
     "controller_mesh.h",
     "databinding/binding.h",
     "databinding/binding_base.cc",
@@ -156,9 +155,13 @@
     "web_contents_event_forwarder.h",
   ]
 
-  public_deps = [
-    "//chrome/browser/resources:vr_shell_resources",
-  ]
+  if (enable_gvr_services) {
+    sources += [ "controller_mesh.cc" ]
+
+    public_deps = [
+      "//chrome/browser/resources:vr_shell_resources",
+    ]
+  }
 
   deps = [
     "//base",
@@ -286,6 +289,12 @@
     "test/vr_common_test_suite.h",
   ]
 
+  if (!enable_gvr_services) {
+    # For testing, we add back controller_mesh.cc on platforms where it isn't
+    # included by vr_common.
+    sources += [ "controller_mesh.cc" ]
+  }
+
   public_deps = [
     ":vr_common",
     ":vr_test_pak",
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 4ff9231..10ab601 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -172,7 +172,7 @@
       sources += [ "$root_gen_dir/chrome/print_preview_resources.pak" ]
       deps += [ "//chrome/browser/resources:print_preview_resources" ]
     }
-    if (enable_vr) {
+    if (enable_gvr_services) {
       sources += [ "$root_gen_dir/chrome/vr_shell_resources.pak" ]
       deps += [ "//chrome/browser/resources:vr_shell_resources" ]
     }
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc
index 698d76c9..a4ad6c5 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -17,6 +17,7 @@
 #include "components/offline_pages/core/model/add_page_task.h"
 #include "components/offline_pages/core/model/create_archive_task.h"
 #include "components/offline_pages/core/model/delete_page_task.h"
+#include "components/offline_pages/core/model/get_pages_task.h"
 #include "components/offline_pages/core/model/mark_page_accessed_task.h"
 #include "components/offline_pages/core/offline_page_metadata_store.h"
 #include "components/offline_pages/core/offline_page_metadata_store_sql.h"
@@ -36,6 +37,14 @@
 // one.
 const base::TimeDelta kClearStorageInterval = base::TimeDelta::FromMinutes(30);
 
+void WrapInMultipleItemsCallback(const MultipleOfflineIdCallback& callback,
+                                 const MultipleOfflinePageItemResult& pages) {
+  std::vector<int64_t> results;
+  for (const auto& page : pages)
+    results.push_back(page.offline_id);
+  callback.Run(results);
+}
+
 SavePageResult ArchiverResultToSavePageResult(ArchiverResult archiver_result) {
   switch (archiver_result) {
     case ArchiverResult::SUCCESSFULLY_CREATED:
@@ -146,38 +155,76 @@
     const DeletePageCallback& callback) {}
 
 void OfflinePageModelTaskified::GetAllPages(
-    const MultipleOfflinePageItemCallback& callback) {}
+    const MultipleOfflinePageItemCallback& callback) {
+  auto task = GetPagesTask::CreateTaskMatchingAllPages(store_.get(), callback);
+  task_queue_.AddTask(std::move(task));
+}
 
 void OfflinePageModelTaskified::GetPageByOfflineId(
     int64_t offline_id,
-    const SingleOfflinePageItemCallback& callback) {}
+    const SingleOfflinePageItemCallback& callback) {
+  auto task = GetPagesTask::CreateTaskMatchingOfflineId(store_.get(), callback,
+                                                        offline_id);
+  task_queue_.AddTask(std::move(task));
+}
 
 void OfflinePageModelTaskified::GetPagesByClientIds(
     const std::vector<ClientId>& client_ids,
-    const MultipleOfflinePageItemCallback& callback) {}
+    const MultipleOfflinePageItemCallback& callback) {
+  auto task = GetPagesTask::CreateTaskMatchingClientIds(store_.get(), callback,
+                                                        client_ids);
+  task_queue_.AddTask(std::move(task));
+}
 
 void OfflinePageModelTaskified::GetPagesByURL(
     const GURL& url,
     URLSearchMode url_search_mode,
-    const MultipleOfflinePageItemCallback& callback) {}
+    const MultipleOfflinePageItemCallback& callback) {
+  auto task = GetPagesTask::CreateTaskMatchingUrl(store_.get(), callback, url);
+  task_queue_.AddTask(std::move(task));
+}
 
 void OfflinePageModelTaskified::GetPagesByNamespace(
     const std::string& name_space,
-    const MultipleOfflinePageItemCallback& callback) {}
+    const MultipleOfflinePageItemCallback& callback) {
+  auto task = GetPagesTask::CreateTaskMatchingNamespace(store_.get(), callback,
+                                                        name_space);
+  task_queue_.AddTask(std::move(task));
+}
 
 void OfflinePageModelTaskified::GetPagesRemovedOnCacheReset(
-    const MultipleOfflinePageItemCallback& callback) {}
+    const MultipleOfflinePageItemCallback& callback) {
+  auto task = GetPagesTask::CreateTaskMatchingPagesRemovedOnCacheReset(
+      store_.get(), callback, policy_controller_.get());
+  task_queue_.AddTask(std::move(task));
+}
 
 void OfflinePageModelTaskified::GetPagesSupportedByDownloads(
-    const MultipleOfflinePageItemCallback& callback) {}
+    const MultipleOfflinePageItemCallback& callback) {
+  auto task = GetPagesTask::CreateTaskMatchingPagesSupportedByDownloads(
+      store_.get(), callback, policy_controller_.get());
+  task_queue_.AddTask(std::move(task));
+}
 
 void OfflinePageModelTaskified::GetPagesByRequestOrigin(
     const std::string& request_origin,
-    const MultipleOfflinePageItemCallback& callback) {}
+    const MultipleOfflinePageItemCallback& callback) {
+  auto task = GetPagesTask::CreateTaskMatchingRequestOrigin(
+      store_.get(), callback, request_origin);
+  task_queue_.AddTask(std::move(task));
+}
 
 void OfflinePageModelTaskified::GetOfflineIdsForClientId(
     const ClientId& client_id,
-    const MultipleOfflineIdCallback& callback) {}
+    const MultipleOfflineIdCallback& callback) {
+  // We're currently getting offline IDs by querying offline items based on
+  // client ids, and then extract the offline IDs from the items. This is fine
+  // since we're not expecting many pages with the same client ID.
+  auto task = GetPagesTask::CreateTaskMatchingClientIds(
+      store_.get(), base::Bind(&WrapInMultipleItemsCallback, callback),
+      {client_id});
+  task_queue_.AddTask(std::move(task));
+}
 
 const base::FilePath& OfflinePageModelTaskified::GetArchiveDirectory(
     const std::string& name_space) const {
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.h b/components/offline_pages/core/model/offline_page_model_taskified.h
index 42cb3f4..747070b4 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.h
+++ b/components/offline_pages/core/model/offline_page_model_taskified.h
@@ -90,8 +90,10 @@
   void GetPagesByNamespace(
       const std::string& name_space,
       const MultipleOfflinePageItemCallback& callback) override;
+  // Get all pages in the namespaces that will be removed on cache reset.
   void GetPagesRemovedOnCacheReset(
       const MultipleOfflinePageItemCallback& callback) override;
+  // Get all pages in the namespaces that are shown in download ui.
   void GetPagesSupportedByDownloads(
       const MultipleOfflinePageItemCallback& callback) override;
   void GetPagesByRequestOrigin(
diff --git a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
index 5d4cd4ec..9cc90c8 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -31,8 +31,12 @@
 using testing::_;
 using testing::A;
 using testing::An;
+using testing::ElementsAre;
 using testing::Eq;
+using testing::IsEmpty;
+using testing::Pointee;
 using testing::SaveArg;
+using testing::UnorderedElementsAre;
 
 namespace offline_pages {
 
@@ -41,6 +45,9 @@
 namespace {
 const GURL kTestUrl("http://example.com");
 const GURL kTestUrl2("http://other.page.com");
+const GURL kTestUrlWithFragment("http://example.com#frag");
+const GURL kTestUrl2WithFragment("http://other.page.com#frag");
+const GURL kRandomUrl("http://foo");
 const GURL kFileUrl("file:///foo");
 const ClientId kTestClientId1(kDefaultNamespace, "1234");
 const ClientId kTestClientId2(kDefaultNamespace, "5678");
@@ -118,8 +125,8 @@
   OfflinePageMetadataStoreTestUtil* store_test_util() {
     return &store_test_util_;
   }
-  OfflinePageItemGenerator* generator() { return &generator_; }
-  TaskQueue* model_task_queue() { return &model_->task_queue_; }
+  OfflinePageItemGenerator* page_generator() { return &generator_; }
+  TaskQueue* task_queue() { return &model_->task_queue_; }
   const base::FilePath& temporary_dir_path() {
     return temporary_dir_.GetPath();
   }
@@ -127,7 +134,9 @@
     return persistent_dir_.GetPath();
   }
 
-  const base::FilePath& last_archiver_path() { return last_archiver_path_; }
+  const base::FilePath& last_path_created_by_archiver() {
+    return last_path_created_by_archiver_;
+  }
   bool observer_add_page_called() { return observer_add_page_called_; }
   const OfflinePageItem& last_added_page() { return last_added_page_; }
   bool observer_delete_page_called() { return observer_delete_page_called_; }
@@ -141,7 +150,7 @@
   base::ScopedTempDir temporary_dir_;
   base::ScopedTempDir persistent_dir_;
 
-  base::FilePath last_archiver_path_;
+  base::FilePath last_path_created_by_archiver_;
   bool observer_add_page_called_;
   OfflinePageItem last_added_page_;
   bool observer_delete_page_called_;
@@ -190,7 +199,7 @@
 }
 
 void OfflinePageModelTaskifiedTest::ResetResults() {
-  last_archiver_path_.clear();
+  last_path_created_by_archiver_.clear();
   observer_add_page_called_ = false;
   observer_delete_page_called_ = false;
 }
@@ -213,7 +222,7 @@
 
 void OfflinePageModelTaskifiedTest::SetLastPathCreatedByArchiver(
     const base::FilePath& file_path) {
-  last_archiver_path_ = file_path;
+  last_path_created_by_archiver_ = file_path;
 }
 
 void OfflinePageModelTaskifiedTest::SavePageWithCallback(
@@ -266,8 +275,8 @@
 }
 
 void OfflinePageModelTaskifiedTest::CheckTaskQueueIdle() {
-  EXPECT_FALSE(model_task_queue()->HasPendingTasks());
-  EXPECT_FALSE(model_task_queue()->HasRunningTask());
+  EXPECT_FALSE(task_queue()->HasPendingTasks());
+  EXPECT_FALSE(task_queue()->HasRunningTask());
 }
 
 TEST_F(OfflinePageModelTaskifiedTest, SavePageSuccessful) {
@@ -284,7 +293,7 @@
   EXPECT_EQ(kTestUrl, saved_page_ptr->url);
   EXPECT_EQ(kTestClientId1.id, saved_page_ptr->client_id.id);
   EXPECT_EQ(kTestClientId1.name_space, saved_page_ptr->client_id.name_space);
-  EXPECT_EQ(last_archiver_path(), saved_page_ptr->file_path);
+  EXPECT_EQ(last_path_created_by_archiver(), saved_page_ptr->file_path);
   EXPECT_EQ(kTestFileSize, saved_page_ptr->file_size);
   EXPECT_EQ(0, saved_page_ptr->access_count);
   EXPECT_EQ(0, saved_page_ptr->flags);
@@ -325,7 +334,7 @@
   EXPECT_EQ(kTestUrl, saved_page_ptr->url);
   EXPECT_EQ(kTestClientId1.id, saved_page_ptr->client_id.id);
   EXPECT_EQ(kTestClientId1.name_space, saved_page_ptr->client_id.name_space);
-  EXPECT_EQ(last_archiver_path(), saved_page_ptr->file_path);
+  EXPECT_EQ(last_path_created_by_archiver(), saved_page_ptr->file_path);
   EXPECT_EQ(kTestFileSize, saved_page_ptr->file_size);
   EXPECT_EQ(0, saved_page_ptr->access_count);
   EXPECT_EQ(0, saved_page_ptr->flags);
@@ -416,7 +425,7 @@
 
   EXPECT_EQ(1LL, GetFileCountInDir(temporary_dir_path()));
   EXPECT_EQ(1LL, store_test_util()->GetPageCount());
-  base::FilePath saved_file_path1 = last_archiver_path();
+  base::FilePath saved_file_path1 = last_path_created_by_archiver();
 
   ResetResults();
 
@@ -427,7 +436,7 @@
   // Check that offline_id1 refers to the second save page request.
   EXPECT_EQ(2LL, GetFileCountInDir(temporary_dir_path()));
   EXPECT_EQ(2LL, store_test_util()->GetPageCount());
-  base::FilePath saved_file_path2 = last_archiver_path();
+  base::FilePath saved_file_path2 = last_path_created_by_archiver();
 
   auto saved_page_ptr1 = store_test_util()->GetPageByOfflineId(offline_id1);
   auto saved_page_ptr2 = store_test_util()->GetPageByOfflineId(offline_id2);
@@ -448,14 +457,14 @@
 
 TEST_F(OfflinePageModelTaskifiedTest, AddPage) {
   // Creates a fresh page.
-  generator()->SetArchiveDirectory(temporary_dir_path());
-  OfflinePageItem page = generator()->CreateItemWithTempFile();
+  page_generator()->SetArchiveDirectory(temporary_dir_path());
+  OfflinePageItem page = page_generator()->CreateItemWithTempFile();
 
   base::MockCallback<AddPageCallback> callback;
   EXPECT_CALL(callback, Run(An<AddPageResult>(), Eq(page.offline_id)));
 
   model()->AddPage(page, callback.Get());
-  EXPECT_TRUE(model_task_queue()->HasRunningTask());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
 
   PumpLoop();
   EXPECT_TRUE(observer_add_page_called());
@@ -463,11 +472,11 @@
 }
 
 TEST_F(OfflinePageModelTaskifiedTest, MarkPageAccessed) {
-  OfflinePageItem page = generator()->CreateItem();
+  OfflinePageItem page = page_generator()->CreateItem();
   InsertPageIntoStore(page);
 
   model()->MarkPageAccessed(page.offline_id);
-  EXPECT_TRUE(model_task_queue()->HasRunningTask());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
 
   PumpLoop();
 
@@ -477,6 +486,224 @@
   EXPECT_EQ(1LL, accessed_page_ptr->access_count);
 }
 
+TEST_F(OfflinePageModelTaskifiedTest, GetAllPagesWhenStoreEmpty) {
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(IsEmpty()));
+
+  model()->GetAllPages(callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+
+  PumpLoop();
+}
+
+TEST_F(OfflinePageModelTaskifiedTest, GetPageByOfflineId) {
+  page_generator()->SetNamespace(kDefaultNamespace);
+  page_generator()->SetUrl(kTestUrl);
+  OfflinePageItem page = page_generator()->CreateItem();
+  InsertPageIntoStore(page);
+
+  base::MockCallback<SingleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(Pointee(Eq(page))));
+
+  model()->GetPageByOfflineId(page.offline_id, callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+
+  PumpLoop();
+}
+
+TEST_F(OfflinePageModelTaskifiedTest, GetPagesByUrl_FinalUrl) {
+  page_generator()->SetUrl(kTestUrl);
+  OfflinePageItem page1 = page_generator()->CreateItem();
+  InsertPageIntoStore(page1);
+  page_generator()->SetUrl(kTestUrl2);
+  OfflinePageItem page2 = page_generator()->CreateItem();
+  InsertPageIntoStore(page2);
+
+  // Search by kTestUrl.
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(ElementsAre(page1)));
+  model()->GetPagesByURL(kTestUrl, URLSearchMode::SEARCH_BY_FINAL_URL_ONLY,
+                         callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+  PumpLoop();
+
+  // Search by kTestUrl2.
+  EXPECT_CALL(callback, Run(ElementsAre(page2)));
+  model()->GetPagesByURL(kTestUrl2, URLSearchMode::SEARCH_BY_FINAL_URL_ONLY,
+                         callback.Get());
+  PumpLoop();
+
+  // Search by random url, which should return no pages.
+  EXPECT_CALL(callback, Run(IsEmpty()));
+  model()->GetPagesByURL(kRandomUrl, URLSearchMode::SEARCH_BY_FINAL_URL_ONLY,
+                         callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+  PumpLoop();
+}
+
+TEST_F(OfflinePageModelTaskifiedTest,
+       GetPagesByUrl_FinalUrlWithFragmentStripped) {
+  page_generator()->SetUrl(kTestUrl);
+  OfflinePageItem page1 = page_generator()->CreateItem();
+  InsertPageIntoStore(page1);
+  page_generator()->SetUrl(kTestUrl2WithFragment);
+  OfflinePageItem page2 = page_generator()->CreateItem();
+  InsertPageIntoStore(page2);
+
+  // Search by kTestUrlWithFragment.
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(ElementsAre(page1)));
+  model()->GetPagesByURL(kTestUrlWithFragment,
+                         URLSearchMode::SEARCH_BY_FINAL_URL_ONLY,
+                         callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+  PumpLoop();
+
+  // Search by kTestUrl2.
+  EXPECT_CALL(callback, Run(ElementsAre(page2)));
+  model()->GetPagesByURL(kTestUrl2, URLSearchMode::SEARCH_BY_FINAL_URL_ONLY,
+                         callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+  PumpLoop();
+
+  // Search by kTestUrl2WithFragment.
+  EXPECT_CALL(callback, Run(ElementsAre(page2)));
+  model()->GetPagesByURL(kTestUrl2WithFragment,
+                         URLSearchMode::SEARCH_BY_FINAL_URL_ONLY,
+                         callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+  PumpLoop();
+}
+
+TEST_F(OfflinePageModelTaskifiedTest, GetPagesByUrl_AllUrls) {
+  page_generator()->SetUrl(kTestUrl);
+  page_generator()->SetOriginalUrl(kTestUrl2);
+  OfflinePageItem page1 = page_generator()->CreateItem();
+  InsertPageIntoStore(page1);
+  page_generator()->SetUrl(kTestUrl2);
+  page_generator()->SetOriginalUrl(GURL());
+  OfflinePageItem page2 = page_generator()->CreateItem();
+  InsertPageIntoStore(page2);
+
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(UnorderedElementsAre(page1, page2)));
+  model()->GetPagesByURL(kTestUrl2, URLSearchMode::SEARCH_BY_ALL_URLS,
+                         callback.Get());
+  PumpLoop();
+}
+
+TEST_F(OfflinePageModelTaskifiedTest, GetOfflineIdsForClientId) {
+  page_generator()->SetNamespace(kTestClientId1.name_space);
+  page_generator()->SetId(kTestClientId1.id);
+  OfflinePageItem page1 = page_generator()->CreateItem();
+  OfflinePageItem page2 = page_generator()->CreateItem();
+  InsertPageIntoStore(page1);
+  InsertPageIntoStore(page2);
+
+  base::MockCallback<MultipleOfflineIdCallback> callback;
+  EXPECT_CALL(callback,
+              Run(UnorderedElementsAre(page1.offline_id, page2.offline_id)));
+
+  model()->GetOfflineIdsForClientId(kTestClientId1, callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+
+  PumpLoop();
+}
+
+TEST_F(OfflinePageModelTaskifiedTest, GetPagesByClientIds) {
+  page_generator()->SetNamespace(kTestClientId1.name_space);
+  page_generator()->SetId(kTestClientId1.id);
+  OfflinePageItem page1 = page_generator()->CreateItem();
+  OfflinePageItem page2 = page_generator()->CreateItem();
+  page_generator()->SetNamespace(kTestUserRequestedClientId.name_space);
+  OfflinePageItem page3 = page_generator()->CreateItem();
+  InsertPageIntoStore(page1);
+  InsertPageIntoStore(page2);
+  InsertPageIntoStore(page3);
+
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(UnorderedElementsAre(page1, page2)));
+
+  model()->GetPagesByClientIds({kTestClientId1}, callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+
+  PumpLoop();
+}
+
+TEST_F(OfflinePageModelTaskifiedTest, GetPagesByRequestOrigin) {
+  page_generator()->SetRequestOrigin(kTestRequestOrigin);
+  OfflinePageItem page1 = page_generator()->CreateItem();
+  page_generator()->SetRequestOrigin(kEmptyRequestOrigin);
+  OfflinePageItem page2 = page_generator()->CreateItem();
+  InsertPageIntoStore(page1);
+  InsertPageIntoStore(page2);
+
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(ElementsAre(page1)));
+
+  model()->GetPagesByRequestOrigin(kTestRequestOrigin, callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+
+  PumpLoop();
+}
+
+TEST_F(OfflinePageModelTaskifiedTest, GetPagesByNamespace) {
+  page_generator()->SetNamespace(kDefaultNamespace);
+  OfflinePageItem page1 = page_generator()->CreateItem();
+  OfflinePageItem page2 = page_generator()->CreateItem();
+  page_generator()->SetNamespace(kDownloadNamespace);
+  OfflinePageItem page3 = page_generator()->CreateItem();
+  InsertPageIntoStore(page1);
+  InsertPageIntoStore(page2);
+  InsertPageIntoStore(page3);
+
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(UnorderedElementsAre(page1, page2)));
+
+  model()->GetPagesByNamespace(kDefaultNamespace, callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+
+  PumpLoop();
+}
+
+TEST_F(OfflinePageModelTaskifiedTest, GetPagesRemovedOnCacheReset) {
+  page_generator()->SetNamespace(kDefaultNamespace);
+  OfflinePageItem page1 = page_generator()->CreateItem();
+  OfflinePageItem page2 = page_generator()->CreateItem();
+  InsertPageIntoStore(page1);
+  InsertPageIntoStore(page2);
+  page_generator()->SetNamespace(kDownloadNamespace);
+  OfflinePageItem page3 = page_generator()->CreateItem();
+  InsertPageIntoStore(page3);
+
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(UnorderedElementsAre(page1, page2)));
+
+  model()->GetPagesRemovedOnCacheReset(callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+
+  PumpLoop();
+}
+
+TEST_F(OfflinePageModelTaskifiedTest, GetPagesSupportedByDownloads) {
+  page_generator()->SetNamespace(kDownloadNamespace);
+  OfflinePageItem page1 = page_generator()->CreateItem();
+  OfflinePageItem page2 = page_generator()->CreateItem();
+  InsertPageIntoStore(page1);
+  InsertPageIntoStore(page2);
+  page_generator()->SetNamespace(kDefaultNamespace);
+  OfflinePageItem page3 = page_generator()->CreateItem();
+  InsertPageIntoStore(page3);
+
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(UnorderedElementsAre(page1, page2)));
+
+  model()->GetPagesSupportedByDownloads(callback.Get());
+  EXPECT_TRUE(task_queue()->HasRunningTask());
+
+  PumpLoop();
+}
+
 // This test is affected by https://crbug.com/725685, which only affects windows
 // platform.
 #if defined(OS_WIN)
@@ -486,25 +713,17 @@
 #define MAYBE_CheckPagesSavedInSeparateDirs CheckPagesSavedInSeparateDirs
 #endif
 TEST_F(OfflinePageModelTaskifiedTest, MAYBE_CheckPagesSavedInSeparateDirs) {
-  auto archiver = BuildArchiver(kTestUrl, ArchiverResult::SUCCESSFULLY_CREATED);
-  int64_t temporary_id;
-  int64_t persistent_id;
-
-  base::MockCallback<SavePageCallback> callback;
-  EXPECT_CALL(callback, Run(Eq(SavePageResult::SUCCESS), A<int64_t>()))
-      .Times(2)
-      .WillOnce(SaveArg<1>(&temporary_id))
-      .WillOnce(SaveArg<1>(&persistent_id));
-
   // Save a temporary page.
-  SavePageWithCallback(kTestUrl, kTestClientId1, GURL(), kEmptyRequestOrigin,
-                       std::move(archiver), callback.Get());
+  auto archiver = BuildArchiver(kTestUrl, ArchiverResult::SUCCESSFULLY_CREATED);
+  int64_t temporary_id = SavePageWithExpectedResult(
+      kTestUrl, kTestClientId1, GURL(), kEmptyRequestOrigin,
+      std::move(archiver), SavePageResult::SUCCESS);
 
   // Save a persistent page.
   archiver = BuildArchiver(kTestUrl2, ArchiverResult::SUCCESSFULLY_CREATED);
-  SavePageWithCallback(kTestUrl2, kTestUserRequestedClientId, GURL(),
-                       kEmptyRequestOrigin, std::move(archiver),
-                       callback.Get());
+  int64_t persistent_id = SavePageWithExpectedResult(
+      kTestUrl2, kTestUserRequestedClientId, GURL(), kEmptyRequestOrigin,
+      std::move(archiver), SavePageResult::SUCCESS);
 
   std::unique_ptr<OfflinePageItem> temporary_page =
       store_test_util()->GetPageByOfflineId(temporary_id);
@@ -528,11 +747,11 @@
 TEST_F(OfflinePageModelTaskifiedTest,
        DISABLED_ClearCachedPagesTriggeredWhenSaveFailed) {
   // After a save failed, only PostClearCachedPagesTask will be triggered.
-  generator()->SetArchiveDirectory(temporary_dir_path());
-  generator()->SetNamespace(kDefaultNamespace);
-  generator()->SetUrl(kTestUrl);
-  OfflinePageItem page1 = generator()->CreateItemWithTempFile();
-  OfflinePageItem page2 = generator()->CreateItemWithTempFile();
+  page_generator()->SetArchiveDirectory(temporary_dir_path());
+  page_generator()->SetNamespace(kDefaultNamespace);
+  page_generator()->SetUrl(kTestUrl);
+  OfflinePageItem page1 = page_generator()->CreateItemWithTempFile();
+  OfflinePageItem page2 = page_generator()->CreateItemWithTempFile();
   InsertPageIntoStore(page1);
   InsertPageIntoStore(page2);
 
@@ -562,11 +781,11 @@
   // Add pages that have the same namespace and url directly into store, in
   // order to avoid triggering the removal.
   // The 'default' namespace has a limit of 1 per url.
-  generator()->SetArchiveDirectory(temporary_dir_path());
-  generator()->SetNamespace(kDefaultNamespace);
-  generator()->SetUrl(kTestUrl);
-  OfflinePageItem page1 = generator()->CreateItemWithTempFile();
-  OfflinePageItem page2 = generator()->CreateItemWithTempFile();
+  page_generator()->SetArchiveDirectory(temporary_dir_path());
+  page_generator()->SetNamespace(kDefaultNamespace);
+  page_generator()->SetUrl(kTestUrl);
+  OfflinePageItem page1 = page_generator()->CreateItemWithTempFile();
+  OfflinePageItem page2 = page_generator()->CreateItemWithTempFile();
   InsertPageIntoStore(page1);
   InsertPageIntoStore(page2);
 
@@ -591,4 +810,16 @@
   EXPECT_EQ(persistent_dir_path(), persistent_dir);
 }
 
+TEST_F(OfflinePageModelTaskifiedTest, GetAllPages) {
+  OfflinePageItem page1 = page_generator()->CreateItem();
+  OfflinePageItem page2 = page_generator()->CreateItem();
+  InsertPageIntoStore(page1);
+  InsertPageIntoStore(page2);
+
+  base::MockCallback<MultipleOfflinePageItemCallback> callback;
+  EXPECT_CALL(callback, Run(UnorderedElementsAre(page1, page2)));
+  model()->GetAllPages(callback.Get());
+  PumpLoop();
+}
+
 }  // namespace offline_pages
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index c5a0216..7a4cc4c 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -227,15 +227,8 @@
 
   for (auto& pass : render_passes_in_draw_order) {
     auto& resource = render_pass_textures_[pass->id];
-    if (!resource) {
+    if (!resource)
       resource = std::make_unique<cc::ScopedResource>(resource_provider_);
-
-      // |has_damage_from_contributing_content| is used to determine if previous
-      // contents can be reused when caching render pass and as a result needs
-      // to be true when a new resource is created to ensure that it is updated
-      // and not assumed to already contain correct contents.
-      pass->has_damage_from_contributing_content = true;
-    }
   }
 }
 
@@ -377,22 +370,6 @@
   current_frame_valid_ = false;
 }
 
-gfx::Rect DirectRenderer::DrawingFrame::ComputeScissorRectForRenderPass()
-    const {
-  if (current_render_pass == root_render_pass)
-    return root_damage_rect;
-
-  // If the root damage rect has been expanded due to overlays, all the other
-  // damage rect calculations are incorrect.
-  if (!root_render_pass->damage_rect.Contains(root_damage_rect))
-    return current_render_pass->output_rect;
-
-  DCHECK(
-      current_render_pass->copy_requests.empty() ||
-      (current_render_pass->damage_rect == current_render_pass->output_rect));
-  return current_render_pass->damage_rect;
-}
-
 gfx::Rect DirectRenderer::DeviceViewportRectInDrawSpace() const {
   gfx::Rect device_viewport_rect(current_frame()->device_viewport_size);
   device_viewport_rect -= current_viewport_rect_.OffsetFromOrigin();
@@ -524,8 +501,9 @@
 
 void DirectRenderer::DrawRenderPass(const RenderPass* render_pass) {
   TRACE_EVENT0("cc", "DirectRenderer::DrawRenderPass");
-  if (!UseRenderPass(render_pass))
+  if (CanSkipRenderPass(render_pass))
     return;
+  UseRenderPass(render_pass);
 
   const gfx::Rect surface_rect_in_draw_space = OutputSurfaceRectInDrawSpace();
   gfx::Rect render_pass_scissor_in_draw_space = surface_rect_in_draw_space;
@@ -538,7 +516,7 @@
 
   if (use_partial_swap_) {
     render_pass_scissor_in_draw_space.Intersect(
-        current_frame()->ComputeScissorRectForRenderPass());
+        ComputeScissorRectForRenderPass(current_frame()->current_render_pass));
   }
 
   bool is_root_render_pass =
@@ -624,9 +602,32 @@
     GenerateMipmap();
 }
 
-bool DirectRenderer::UseRenderPass(const RenderPass* render_pass) {
+bool DirectRenderer::CanSkipRenderPass(const RenderPass* render_pass) const {
+  if (render_pass == current_frame()->root_render_pass)
+    return false;
+
+  if (ComputeScissorRectForRenderPass(render_pass).IsEmpty())
+    return true;
+
+  // If the RenderPass wants to be cached, then we only draw it if we need to.
+  // When damage is present, then we can't skip the RenderPass. Or if the
+  // texture does not exist (first frame, or was deleted) then we can't skip
+  // the RenderPass.
+  if (render_pass->cache_render_pass) {
+    if (render_pass->has_damage_from_contributing_content)
+      return false;
+    auto it = render_pass_textures_.find(render_pass->id);
+    DCHECK(it != render_pass_textures_.end());
+    cc::ScopedResource* texture = it->second.get();
+    DCHECK(texture);
+    return texture->id() != 0;
+  }
+
+  return false;
+}
+
+void DirectRenderer::UseRenderPass(const RenderPass* render_pass) {
   current_frame()->current_render_pass = render_pass;
-  current_frame()->current_texture = nullptr;
   if (render_pass == current_frame()->root_render_pass) {
     BindFramebufferToOutputSurface();
 
@@ -637,7 +638,7 @@
     InitializeViewport(current_frame(), render_pass->output_rect,
                        gfx::Rect(current_frame()->device_viewport_size),
                        current_frame()->device_viewport_size);
-    return true;
+    return;
   }
 
   cc::ScopedResource* texture = render_pass_textures_[render_pass->id].get();
@@ -646,26 +647,36 @@
   gfx::Size size = RenderPassTextureSize(render_pass);
   size.Enlarge(enlarge_pass_texture_amount_.width(),
                enlarge_pass_texture_amount_.height());
+
   if (!texture->id()) {
     texture->Allocate(size, RenderPassTextureHint(render_pass),
                       BackbufferFormat(),
                       current_frame()->current_render_pass->color_space);
-  } else if (render_pass->cache_render_pass &&
-             !render_pass->has_damage_from_contributing_content) {
-    return false;
-  } else if (current_frame()->ComputeScissorRectForRenderPass().IsEmpty()) {
-    return false;
   }
   DCHECK(texture->id());
 
-  if (BindFramebufferToTexture(texture)) {
-    InitializeViewport(current_frame(), render_pass->output_rect,
-                       gfx::Rect(render_pass->output_rect.size()),
-                       texture->size());
-    return true;
-  }
+  BindFramebufferToTexture(texture);
+  InitializeViewport(current_frame(), render_pass->output_rect,
+                     gfx::Rect(render_pass->output_rect.size()),
+                     texture->size());
+}
 
-  return false;
+gfx::Rect DirectRenderer::ComputeScissorRectForRenderPass(
+    const RenderPass* render_pass) const {
+  const RenderPass* root_render_pass = current_frame()->root_render_pass;
+  const gfx::Rect root_damage_rect = current_frame()->root_damage_rect;
+
+  if (render_pass == root_render_pass)
+    return root_damage_rect;
+
+  // If the root damage rect has been expanded due to overlays, all the other
+  // damage rect calculations are incorrect.
+  if (!root_render_pass->damage_rect.Contains(root_damage_rect))
+    return render_pass->output_rect;
+
+  DCHECK(render_pass->copy_requests.empty() ||
+         (render_pass->damage_rect == render_pass->output_rect));
+  return render_pass->damage_rect;
 }
 
 bool DirectRenderer::HasAllocatedResourcesForTesting(
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h
index df4954fb..b4ae8d3 100644
--- a/components/viz/service/display/direct_renderer.h
+++ b/components/viz/service/display/direct_renderer.h
@@ -78,12 +78,10 @@
   struct VIZ_SERVICE_EXPORT DrawingFrame {
     DrawingFrame();
     ~DrawingFrame();
-    gfx::Rect ComputeScissorRectForRenderPass() const;
 
     const RenderPassList* render_passes_in_draw_order = nullptr;
     const RenderPass* root_render_pass = nullptr;
     const RenderPass* current_render_pass = nullptr;
-    const cc::ScopedResource* current_texture = nullptr;
 
     gfx::Rect root_damage_rect;
     std::vector<gfx::Rect> root_content_bounds;
@@ -141,7 +139,13 @@
       bool use_render_pass_scissor);
   void DrawRenderPassAndExecuteCopyRequests(RenderPass* render_pass);
   void DrawRenderPass(const RenderPass* render_pass);
-  bool UseRenderPass(const RenderPass* render_pass);
+  // Returns true if it detects that we do not need to draw the render pass.
+  // This may be because the RenderPass is already cached, or because it is
+  // entirely clipped out, for instance.
+  bool CanSkipRenderPass(const RenderPass* render_pass) const;
+  void UseRenderPass(const RenderPass* render_pass);
+  gfx::Rect ComputeScissorRectForRenderPass(
+      const RenderPass* render_pass) const;
 
   void DoDrawPolygon(const DrawPolygon& poly,
                      const gfx::Rect& render_pass_scissor,
@@ -155,7 +159,7 @@
   virtual bool CanPartialSwap() = 0;
   virtual ResourceFormat BackbufferFormat() const = 0;
   virtual void BindFramebufferToOutputSurface() = 0;
-  virtual bool BindFramebufferToTexture(const cc::ScopedResource* resource) = 0;
+  virtual void BindFramebufferToTexture(const cc::ScopedResource* resource) = 0;
   virtual void SetScissorTestRect(const gfx::Rect& scissor_rect) = 0;
   virtual void PrepareSurfaceForPass(
       SurfaceInitializationMode initialization_mode,
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 78800a75..e0a8985 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -1125,11 +1125,20 @@
       params->quad->shared_quad_state->quad_to_target_transform;
   if (!InitializeRPDQParameters(params))
     return;
+
   UpdateRPDQShadersForBlending(params);
-  if (!UpdateRPDQWithSkiaFilters(params))
-    return;
+  bool can_draw = UpdateRPDQWithSkiaFilters(params);
+  // The above calls use ScopedUseGrContext which can change the bound
+  // framebuffer, so we need to restore it for the current RenderPass.
   UseRenderPass(current_frame()->current_render_pass);
+  // As part of restoring the framebuffer, we call SetViewport directly, rather
+  // than through PrepareSurfaceForPass. PrepareSurfaceForPass also clears the
+  // surface, which is not desired when restoring.
   SetViewport();
+
+  if (!can_draw)
+    return;
+
   UpdateRPDQTexturesForSampling(params);
   UpdateRPDQBlendMode(params);
   ChooseRPDQProgram(params);
@@ -2862,7 +2871,7 @@
   }
 }
 
-bool GLRenderer::BindFramebufferToTexture(const cc::ScopedResource* texture) {
+void GLRenderer::BindFramebufferToTexture(const cc::ScopedResource* texture) {
   DCHECK(texture->id());
 
   // Explicitly release lock, otherwise we can crash when try to lock
@@ -2904,7 +2913,6 @@
   } else {
     SetStencilEnabled(false);
   }
-  return true;
 }
 
 void GLRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h
index 6fb1b1a3..2926f3a4 100644
--- a/components/viz/service/display/gl_renderer.h
+++ b/components/viz/service/display/gl_renderer.h
@@ -94,7 +94,7 @@
   bool CanPartialSwap() override;
   ResourceFormat BackbufferFormat() const override;
   void BindFramebufferToOutputSurface() override;
-  bool BindFramebufferToTexture(const cc::ScopedResource* resource) override;
+  void BindFramebufferToTexture(const cc::ScopedResource* resource) override;
   void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
   void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
                              const gfx::Rect& render_pass_scissor) override;
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 14b50b7f..409c288 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -215,7 +215,7 @@
   }
 }
 
-bool SkiaRenderer::BindFramebufferToTexture(const cc::ScopedResource* texture) {
+void SkiaRenderer::BindFramebufferToTexture(const cc::ScopedResource* texture) {
   DCHECK(texture->id());
 
   // Explicitly release lock, otherwise we can crash when try to lock
@@ -235,7 +235,6 @@
           current_framebuffer_lock_->format(), false, true, 0));
 
   current_canvas_ = current_framebuffer_surface_lock_->surface()->getCanvas();
-  return true;
 }
 
 void SkiaRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index a198a76..1844751 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -44,7 +44,7 @@
   bool CanPartialSwap() override;
   ResourceFormat BackbufferFormat() const override;
   void BindFramebufferToOutputSurface() override;
-  bool BindFramebufferToTexture(const cc::ScopedResource* texture) override;
+  void BindFramebufferToTexture(const cc::ScopedResource* texture) override;
   void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
   void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
                              const gfx::Rect& render_pass_scissor) override;
diff --git a/components/viz/service/display/software_renderer.cc b/components/viz/service/display/software_renderer.cc
index cdf5baf..0731801 100644
--- a/components/viz/service/display/software_renderer.cc
+++ b/components/viz/service/display/software_renderer.cc
@@ -115,7 +115,7 @@
   current_canvas_ = root_canvas_;
 }
 
-bool SoftwareRenderer::BindFramebufferToTexture(
+void SoftwareRenderer::BindFramebufferToTexture(
     const cc::ScopedResource* texture) {
   DCHECK(texture->id());
 
@@ -128,7 +128,6 @@
   current_framebuffer_canvas_ =
       std::make_unique<SkCanvas>(current_framebuffer_lock_->sk_bitmap());
   current_canvas_ = current_framebuffer_canvas_.get();
-  return true;
 }
 
 void SoftwareRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
diff --git a/components/viz/service/display/software_renderer.h b/components/viz/service/display/software_renderer.h
index 08b0258..a8784c5 100644
--- a/components/viz/service/display/software_renderer.h
+++ b/components/viz/service/display/software_renderer.h
@@ -42,7 +42,7 @@
   bool CanPartialSwap() override;
   ResourceFormat BackbufferFormat() const override;
   void BindFramebufferToOutputSurface() override;
-  bool BindFramebufferToTexture(const cc::ScopedResource* texture) override;
+  void BindFramebufferToTexture(const cc::ScopedResource* texture) override;
   void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
   void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
                              const gfx::Rect& render_pass_scissor) override;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index cc0e307..9d6e2b4 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -688,8 +688,6 @@
     "download/download_job_impl.h",
     "download/download_manager_impl.cc",
     "download/download_manager_impl.h",
-    "download/download_net_log_parameters.cc",
-    "download/download_net_log_parameters.h",
     "download/download_request_core.cc",
     "download/download_request_core.h",
     "download/download_request_handle.cc",
@@ -1452,6 +1450,8 @@
     "service_worker/service_worker_cache_writer.h",
     "service_worker/service_worker_client_utils.cc",
     "service_worker/service_worker_client_utils.h",
+    "service_worker/service_worker_consts.cc",
+    "service_worker/service_worker_consts.h",
     "service_worker/service_worker_content_settings_proxy_impl.cc",
     "service_worker/service_worker_content_settings_proxy_impl.h",
     "service_worker/service_worker_context_core.cc",
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 1de0430..f3cffff 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -1493,7 +1493,8 @@
   BrowserGpuChannelHostFactory::Initialize(established_gpu_channel);
 #elif defined(USE_AURA) || defined(OS_MACOSX)
   established_gpu_channel = true;
-  if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor() ||
+  if (parsed_command_line_.HasSwitch(switches::kDisableGpu) ||
+      parsed_command_line_.HasSwitch(switches::kDisableGpuCompositing) ||
       parsed_command_line_.HasSwitch(switches::kDisableGpuEarlyInit) ||
       is_mus) {
     established_gpu_channel = always_uses_gpu = false;
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index b4c871b..5146fdac 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -127,56 +127,6 @@
 #endif  // defined(OS_WIN)
 }
 
-scoped_refptr<ui::ContextProviderCommandBuffer> CreateContextCommon(
-    scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
-    gpu::SurfaceHandle surface_handle,
-    bool need_alpha_channel,
-    bool need_stencil_bits,
-    bool support_locking,
-    ui::ContextProviderCommandBuffer* shared_context_provider,
-    ui::command_buffer_metrics::ContextType type) {
-  DCHECK(
-      content::GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor());
-  DCHECK(gpu_channel_host);
-
-  // All browser contexts get the same stream id because we don't use sync
-  // tokens for browser surfaces.
-  int32_t stream_id = content::kGpuStreamIdDefault;
-  gpu::SchedulingPriority stream_priority = content::kGpuStreamPriorityUI;
-
-  // This is called from a few places to create different contexts:
-  // - The shared main thread context (offscreen).
-  // - The compositor context, which is used by the browser compositor
-  //   (offscreen) for synchronization mostly, and by the display compositor
-  //   (onscreen, except for with mus) for actual GL drawing.
-  // - The compositor worker context (offscreen) used for GPU raster.
-  // So ask for capabilities needed by any of these cases (we can optimize by
-  // branching on |surface_handle| being null if these needs diverge).
-  //
-  // The default framebuffer for an offscreen context is not used, so it does
-  // not need alpha, stencil, depth, antialiasing. The display compositor does
-  // not use these things either (except for alpha when using mus for
-  // non-opaque ui that overlaps the system's window borders or stencil bits
-  // for overdraw feedback), so we can request only that when needed.
-  gpu::gles2::ContextCreationAttribHelper attributes;
-  attributes.alpha_size = need_alpha_channel ? 8 : -1;
-  attributes.depth_size = 0;
-  attributes.stencil_size = need_stencil_bits ? 8 : 0;
-  attributes.samples = 0;
-  attributes.sample_buffers = 0;
-  attributes.bind_generates_resource = false;
-  attributes.lose_context_when_out_of_memory = true;
-  attributes.buffer_preserved = false;
-
-  constexpr bool automatic_flushes = false;
-
-  GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
-  return base::MakeRefCounted<ui::ContextProviderCommandBuffer>(
-      std::move(gpu_channel_host), stream_id, stream_priority, surface_handle,
-      url, automatic_flushes, support_locking, gpu::SharedMemoryLimits(),
-      attributes, shared_context_provider, type);
-}
-
 #if defined(OS_MACOSX)
 bool IsCALayersDisabledFromCommandLine() {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -267,8 +217,10 @@
   software_backing_ = std::make_unique<viz::OutputDeviceBacking>();
 #endif
 
-  if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
+  if (command_line->HasSwitch(switches::kDisableGpu) ||
+      command_line->HasSwitch(switches::kDisableGpuCompositing)) {
     DisableGpuCompositing(nullptr);
+  }
 }
 
 GpuProcessTransportFactory::~GpuProcessTransportFactory() {
@@ -373,9 +325,7 @@
 
   const bool use_vulkan = static_cast<bool>(SharedVulkanContextProvider());
   const bool use_gpu_compositing =
-      !compositor->force_software_compositor() &&
-      !is_gpu_compositing_disabled_ &&
-      GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor();
+      !compositor->force_software_compositor() && !is_gpu_compositing_disabled_;
   if (use_gpu_compositing && !use_vulkan) {
     gpu_channel_factory_->EstablishGpuChannel(base::Bind(
         &GpuProcessTransportFactory::EstablishedGpuChannel,
@@ -392,9 +342,12 @@
   if (!compositor)
     return;
 
-  // CanUseGpuBrowserCompositor can change as a result of EstablishGpuChannel().
-  if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
+  if (gpu_channel_host &&
+      gpu_channel_host->gpu_feature_info()
+              .status_values[gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING] !=
+          gpu::kGpuFeatureStatusEnabled) {
     use_gpu_compositing = false;
+  }
   // Gpu compositing may have been disabled in the meantime.
   if (is_gpu_compositing_disabled_)
     use_gpu_compositing = false;
@@ -1003,8 +956,15 @@
 
   scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
       gpu_channel_factory_->EstablishGpuChannelSync(nullptr);
-  if (!gpu_channel_host)
+  if (!gpu_channel_host ||
+      gpu_channel_host->gpu_feature_info()
+              .status_values[gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING] !=
+          gpu::kGpuFeatureStatusEnabled) {
+    DisableGpuCompositing(nullptr);
+    if (gpu_channel_host)
+      gpu_channel_host->DestroyChannel();
     return nullptr;
+  }
 
   // We need a separate context from the compositor's so that skia and gl_helper
   // don't step on each other.
@@ -1092,4 +1052,54 @@
                      callback_factory_.GetWeakPtr()));
 }
 
+scoped_refptr<ui::ContextProviderCommandBuffer>
+GpuProcessTransportFactory::CreateContextCommon(
+    scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
+    gpu::SurfaceHandle surface_handle,
+    bool need_alpha_channel,
+    bool need_stencil_bits,
+    bool support_locking,
+    ui::ContextProviderCommandBuffer* shared_context_provider,
+    ui::command_buffer_metrics::ContextType type) {
+  DCHECK(gpu_channel_host);
+  DCHECK(!is_gpu_compositing_disabled_);
+
+  // All browser contexts get the same stream id because we don't use sync
+  // tokens for browser surfaces.
+  int32_t stream_id = content::kGpuStreamIdDefault;
+  gpu::SchedulingPriority stream_priority = content::kGpuStreamPriorityUI;
+
+  // This is called from a few places to create different contexts:
+  // - The shared main thread context (offscreen).
+  // - The compositor context, which is used by the browser compositor
+  //   (offscreen) for synchronization mostly, and by the display compositor
+  //   (onscreen, except for with mus) for actual GL drawing.
+  // - The compositor worker context (offscreen) used for GPU raster.
+  // So ask for capabilities needed by any of these cases (we can optimize by
+  // branching on |surface_handle| being null if these needs diverge).
+  //
+  // The default framebuffer for an offscreen context is not used, so it does
+  // not need alpha, stencil, depth, antialiasing. The display compositor does
+  // not use these things either (except for alpha when using mus for
+  // non-opaque ui that overlaps the system's window borders or stencil bits
+  // for overdraw feedback), so we can request only that when needed.
+  gpu::gles2::ContextCreationAttribHelper attributes;
+  attributes.alpha_size = need_alpha_channel ? 8 : -1;
+  attributes.depth_size = 0;
+  attributes.stencil_size = need_stencil_bits ? 8 : 0;
+  attributes.samples = 0;
+  attributes.sample_buffers = 0;
+  attributes.bind_generates_resource = false;
+  attributes.lose_context_when_out_of_memory = true;
+  attributes.buffer_preserved = false;
+
+  constexpr bool automatic_flushes = false;
+
+  GURL url("chrome://gpu/GpuProcessTransportFactory::CreateContextCommon");
+  return base::MakeRefCounted<ui::ContextProviderCommandBuffer>(
+      std::move(gpu_channel_host), stream_id, stream_priority, surface_handle,
+      url, automatic_flushes, support_locking, gpu::SharedMemoryLimits(),
+      attributes, shared_context_provider, type);
+}
+
 }  // namespace content
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h
index d454929..a2c6a967 100644
--- a/content/browser/compositor/gpu_process_transport_factory.h
+++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -22,6 +22,7 @@
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "content/browser/compositor/image_transport_factory.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
+#include "services/ui/public/cpp/gpu/command_buffer_metrics.h"
 #include "ui/compositor/compositor.h"
 
 namespace base {
@@ -129,6 +130,15 @@
   // viz::ContextLostObserver implementation.
   void OnContextLost() override;
 
+  scoped_refptr<ui::ContextProviderCommandBuffer> CreateContextCommon(
+      scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
+      gpu::SurfaceHandle surface_handle,
+      bool need_alpha_channel,
+      bool need_stencil_bits,
+      bool support_locking,
+      ui::ContextProviderCommandBuffer* shared_context_provider,
+      ui::command_buffer_metrics::ContextType type);
+
   viz::FrameSinkIdAllocator frame_sink_id_allocator_;
 
 #if defined(OS_WIN)
diff --git a/content/browser/compositor/image_transport_factory_browsertest.cc b/content/browser/compositor/image_transport_factory_browsertest.cc
index 768d897..8a918a7 100644
--- a/content/browser/compositor/image_transport_factory_browsertest.cc
+++ b/content/browser/compositor/image_transport_factory_browsertest.cc
@@ -8,10 +8,10 @@
 #include "build/build_config.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "content/browser/compositor/owned_mailbox.h"
-#include "content/public/browser/gpu_data_manager.h"
 #include "content/public/test/content_browser_test.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/config/gpu_feature_info.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/compositor/compositor.h"
 
@@ -36,12 +36,17 @@
 // resources are reset.
 IN_PROC_BROWSER_TEST_F(ImageTransportFactoryBrowserTest,
                        MAYBE_TestLostContext) {
-  // This test doesn't make sense in software compositing mode.
-  if (!GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor())
-    return;
-
   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
 
+  // This test doesn't make sense in software compositing mode.
+  scoped_refptr<viz::ContextProvider> context_provider =
+      factory->GetContextFactory()->SharedMainThreadContextProvider();
+  if (context_provider->GetGpuFeatureInfo()
+          .status_values[gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING] !=
+      gpu::kGpuFeatureStatusEnabled) {
+    return;
+  }
+
   scoped_refptr<OwnedMailbox> mailbox =
       new OwnedMailbox(factory->GetGLHelper());
   EXPECT_FALSE(mailbox->mailbox().IsZero());
@@ -53,9 +58,7 @@
   EXPECT_CALL(observer, OnLostResources())
       .WillOnce(testing::InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
 
-  ui::ContextFactory* context_factory = factory->GetContextFactory();
-  gpu::gles2::GLES2Interface* gl =
-      context_factory->SharedMainThreadContextProvider()->ContextGL();
+  gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
   gl->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
                           GL_INNOCENT_CONTEXT_RESET_ARB);
 
@@ -97,10 +100,16 @@
 // called and the created resources are reset.
 IN_PROC_BROWSER_TEST_F(ImageTransportFactoryTearDownBrowserTest,
                        MAYBE_LoseOnTearDown) {
-  // This test doesn't make sense in software compositing mode.
-  if (!GpuDataManager::GetInstance()->CanUseGpuBrowserCompositor())
-    return;
   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+  // This test doesn't make sense in software compositing mode.
+  scoped_refptr<viz::ContextProvider> context_provider =
+      factory->GetContextFactory()->SharedMainThreadContextProvider();
+  if (context_provider->GetGpuFeatureInfo()
+          .status_values[gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING] !=
+      gpu::kGpuFeatureStatusEnabled) {
+    return;
+  }
+
   viz::GLHelper* helper = factory->GetGLHelper();
   ASSERT_TRUE(helper);
   mailbox_ = new OwnedMailbox(helper);
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 91b3a0b..6564be3 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -2217,12 +2217,12 @@
   CountingDownloadFile(std::unique_ptr<DownloadSaveInfo> save_info,
                        const base::FilePath& default_downloads_directory,
                        std::unique_ptr<DownloadManager::InputStream> stream,
-                       const net::NetLogWithSource& net_log,
+                       uint32_t download_id,
                        base::WeakPtr<DownloadDestinationObserver> observer)
       : DownloadFileImpl(std::move(save_info),
                          default_downloads_directory,
                          std::move(stream),
-                         net_log,
+                         download_id,
                          observer) {}
 
   ~CountingDownloadFile() override {
@@ -2274,11 +2274,11 @@
       std::unique_ptr<DownloadSaveInfo> save_info,
       const base::FilePath& default_downloads_directory,
       std::unique_ptr<DownloadManager::InputStream> stream,
-      const net::NetLogWithSource& net_log,
+      uint32_t download_id,
       base::WeakPtr<DownloadDestinationObserver> observer) override {
     return new CountingDownloadFile(std::move(save_info),
                                     default_downloads_directory,
-                                    std::move(stream), net_log, observer);
+                                    std::move(stream), download_id, observer);
   }
 };
 
diff --git a/content/browser/download/base_file.cc b/content/browser/download/base_file.cc
index 0da99a1..230234db 100644
--- a/content/browser/download/base_file.cc
+++ b/content/browser/download/base_file.cc
@@ -11,23 +11,60 @@
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "base/pickle.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "content/browser/download/download_interrupt_reasons_impl.h"
-#include "content/browser/download/download_net_log_parameters.h"
 #include "content/browser/download/download_stats.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/download_item.h"
 #include "content/public/common/quarantine.h"
 #include "crypto/secure_hash.h"
 #include "net/base/net_errors.h"
-#include "net/log/net_log.h"
-#include "net/log/net_log_event_type.h"
+
+#define CONDITIONAL_TRACE(trace)                  \
+  do {                                            \
+    if (download_id_ != DownloadItem::kInvalidId) \
+      TRACE_EVENT_##trace;                        \
+  } while (0)
 
 namespace content {
 
-BaseFile::BaseFile(const net::NetLogWithSource& net_log) : net_log_(net_log) {
+namespace {
+class FileErrorData : public base::trace_event::ConvertableToTraceFormat {
+ public:
+  FileErrorData(const char* operation,
+                int os_error,
+                DownloadInterruptReason interrupt_reason)
+      : operation_(operation),
+        os_error_(os_error),
+        interrupt_reason_(interrupt_reason) {}
+
+  ~FileErrorData() override = default;
+
+  void AppendAsTraceFormat(std::string* out) const override {
+    out->append("{");
+    out->append(
+        base::StringPrintf("\"operation\":\"%s\",", operation_.c_str()));
+    out->append(base::StringPrintf("\"os_error\":\"%d\",", os_error_));
+    out->append(base::StringPrintf(
+        "\"interrupt_reason\":\"%s\",",
+        DownloadInterruptReasonToString(interrupt_reason_).c_str()));
+    out->append("}");
+  }
+
+ private:
+  std::string operation_;
+  int os_error_;
+  DownloadInterruptReason interrupt_reason_;
+  DISALLOW_COPY_AND_ASSIGN(FileErrorData);
+};
+}  // namespace
+
+BaseFile::BaseFile(uint32_t download_id) : download_id_(download_id) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
@@ -103,7 +140,10 @@
   if (data_len == 0)
     return DOWNLOAD_INTERRUPT_REASON_NONE;
 
-  net_log_.BeginEvent(net::NetLogEventType::DOWNLOAD_FILE_WRITTEN);
+  // Use nestable async event instead of sync event so that all the writes
+  // belong to the same download will be grouped together.
+  CONDITIONAL_TRACE(
+      NESTABLE_ASYNC_BEGIN0("download", "DownloadFileWrite", download_id_));
   int write_result = file_.Write(offset, data, data_len);
   DCHECK_NE(0, write_result);
 
@@ -120,8 +160,8 @@
   }
 
   bytes_so_far_ += data_len;
-  net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_WRITTEN,
-                    net::NetLog::Int64Callback("bytes", data_len));
+  CONDITIONAL_TRACE(NESTABLE_ASYNC_END1("download", "DownloadFileWrite",
+                                        download_id_, "bytes", data_len));
 
   if (secure_hash_)
     secure_hash_->Update(data, data_len);
@@ -144,9 +184,9 @@
 
   Close();
 
-  net_log_.BeginEvent(
-      net::NetLogEventType::DOWNLOAD_FILE_RENAMED,
-      base::Bind(&FileRenamedNetLogCallback, &full_path_, &new_path));
+  CONDITIONAL_TRACE(BEGIN2("download", "DownloadFileRename", "old_filename",
+                           full_path_.AsUTF8Unsafe(), "new_filename",
+                           new_path.AsUTF8Unsafe()));
 
   base::CreateDirectory(new_path.DirName());
 
@@ -154,7 +194,7 @@
   // permissions / security descriptors that makes sense in the new directory.
   rename_result = MoveFileAndAdjustPermissions(new_path);
 
-  net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_RENAMED);
+  CONDITIONAL_TRACE(END0("download", "DownloadFileRename"));
 
   if (rename_result == DOWNLOAD_INTERRUPT_REASON_NONE)
     full_path_ = new_path;
@@ -171,19 +211,22 @@
 
 void BaseFile::Detach() {
   detached_ = true;
-  net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_FILE_DETACHED);
+  CONDITIONAL_TRACE(
+      INSTANT0("download", "DownloadFileDetached", TRACE_EVENT_SCOPE_THREAD));
 }
 
 void BaseFile::Cancel() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!detached_);
 
-  net_log_.AddEvent(net::NetLogEventType::CANCELLED);
+  CONDITIONAL_TRACE(
+      INSTANT0("download", "DownloadCancelled", TRACE_EVENT_SCOPE_THREAD));
 
   Close();
 
   if (!full_path_.empty()) {
-    net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_FILE_DELETED);
+    CONDITIONAL_TRACE(
+        INSTANT0("download", "DownloadFileDeleted", TRACE_EVENT_SCOPE_THREAD));
     base::DeleteFile(full_path_, false);
   }
 
@@ -294,9 +337,9 @@
     }
   }
 
-  net_log_.BeginEvent(
-      net::NetLogEventType::DOWNLOAD_FILE_OPENED,
-      base::Bind(&FileOpenedNetLogCallback, &full_path_, bytes_so_far_));
+  CONDITIONAL_TRACE(NESTABLE_ASYNC_BEGIN2(
+      "download", "DownloadFileOpen", download_id_, "file_name",
+      full_path_.AsUTF8Unsafe(), "bytes_so_far", bytes_so_far_));
 
   // For sparse file, skip hash validation.
   if (is_sparse_file_) {
@@ -356,14 +399,16 @@
   // This should only be called when we have a stream.
   DCHECK(file_.IsValid());
   file_.Close();
-  net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_OPENED);
+  CONDITIONAL_TRACE(
+      NESTABLE_ASYNC_END0("download", "DownloadFileOpen", download_id_));
 }
 
 DownloadInterruptReason BaseFile::LogNetError(
     const char* operation,
     net::Error error) {
-  net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_FILE_ERROR,
-                    base::Bind(&FileErrorNetLogCallback, operation, error));
+  CONDITIONAL_TRACE(INSTANT2("download", "DownloadFileError",
+                             TRACE_EVENT_SCOPE_THREAD, "operation", operation,
+                             "net_error", error));
   return ConvertNetErrorToInterruptReason(error, DOWNLOAD_INTERRUPT_FROM_DISK);
 }
 
@@ -384,9 +429,11 @@
   DVLOG(1) << __func__ << "() operation:" << operation
            << " os_error:" << os_error
            << " reason:" << DownloadInterruptReasonToString(reason);
-  net_log_.AddEvent(
-      net::NetLogEventType::DOWNLOAD_FILE_ERROR,
-      base::Bind(&FileInterruptedNetLogCallback, operation, os_error, reason));
+  auto error_data =
+      base::MakeUnique<FileErrorData>(operation, os_error, reason);
+  CONDITIONAL_TRACE(INSTANT1("download", "DownloadFileError",
+                             TRACE_EVENT_SCOPE_THREAD, "file_error",
+                             std::move(error_data)));
   return reason;
 }
 
@@ -433,11 +480,12 @@
   DCHECK(!detached_);
   DCHECK(!full_path_.empty());
 
-  net_log_.BeginEvent(net::NetLogEventType::DOWNLOAD_FILE_ANNOTATED);
+  CONDITIONAL_TRACE(BEGIN0("download", "DownloadFileAnnotate"));
   QuarantineFileResult result = QuarantineFile(
       full_path_, GetEffectiveAuthorityURL(source_url, referrer_url),
       referrer_url, client_guid);
-  net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_ANNOTATED);
+  CONDITIONAL_TRACE(END0("download", "DownloadFileAnnotate"));
+
   switch (result) {
     case QuarantineFileResult::OK:
       return DOWNLOAD_INTERRUPT_REASON_NONE;
diff --git a/content/browser/download/base_file.h b/content/browser/download/base_file.h
index 8b54877..f7775678 100644
--- a/content/browser/download/base_file.h
+++ b/content/browser/download/base_file.h
@@ -22,7 +22,6 @@
 #include "content/public/browser/download_interrupt_reasons.h"
 #include "crypto/secure_hash.h"
 #include "net/base/net_errors.h"
-#include "net/log/net_log_with_source.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -36,7 +35,7 @@
  public:
   // May be constructed on any thread.  All other routines (including
   // destruction) must occur on the same sequence.
-  BaseFile(const net::NetLogWithSource& net_log);
+  BaseFile(uint32_t download_id);
   ~BaseFile();
 
   // Returns DOWNLOAD_INTERRUPT_REASON_NONE on success, or a
@@ -252,7 +251,8 @@
   // verify that writes are not overlapping.
   bool is_sparse_file_ = false;
 
-  net::NetLogWithSource net_log_;
+  // ID of the download, used for trace events.
+  uint32_t download_id_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/content/browser/download/base_file_unittest.cc b/content/browser/download/base_file_unittest.cc
index 3dad668..dd03ecad 100644
--- a/content/browser/download/base_file_unittest.cc
+++ b/content/browser/download/base_file_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/test/test_file_util.h"
 #include "build/build_config.h"
 #include "content/public/browser/download_interrupt_reasons.h"
+#include "content/public/browser/download_item.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "crypto/secure_hash.h"
 #include "crypto/sha2.h"
@@ -60,7 +61,7 @@
 
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    base_file_.reset(new BaseFile(net::NetLogWithSource()));
+    base_file_.reset(new BaseFile(DownloadItem::kInvalidId));
   }
 
   void TearDown() override {
@@ -118,7 +119,7 @@
   // Create a file.  Returns the complete file path.
   base::FilePath CreateTestFile() {
     base::FilePath file_name;
-    BaseFile file((net::NetLogWithSource()));
+    BaseFile file(DownloadItem::kInvalidId);
 
     EXPECT_EQ(
         DOWNLOAD_INTERRUPT_REASON_NONE,
@@ -140,7 +141,7 @@
   // Create a file with the specified file name.
   void CreateFileWithName(const base::FilePath& file_name) {
     EXPECT_NE(base::FilePath::StringType(), file_name.value());
-    BaseFile duplicate_file((net::NetLogWithSource()));
+    BaseFile duplicate_file(DownloadItem::kInvalidId);
     EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
               duplicate_file.Initialize(file_name, temp_dir_.GetPath(),
                                         base::File(), 0, std::string(),
@@ -292,7 +293,7 @@
   ASSERT_TRUE(base::CopyFile(base_file_->full_path(), new_file_path));
 
   // Create another file
-  BaseFile second_file((net::NetLogWithSource()));
+  BaseFile second_file(DownloadItem::kInvalidId);
   ASSERT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
             second_file.Initialize(new_file_path,
                                    base::FilePath(),
@@ -418,7 +419,7 @@
   // Pass a file handle which was opened without the WRITE flag.
   // This should result in an error when writing.
   base::File file(path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ);
-  base_file_.reset(new BaseFile(net::NetLogWithSource()));
+  base_file_.reset(new BaseFile(DownloadItem::kInvalidId));
   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
             base_file_->Initialize(path, base::FilePath(), std::move(file), 0,
                                    std::string(),
@@ -460,7 +461,7 @@
   set_expected_data(kTestData4);
 
   // Use the file we've just created.
-  base_file_.reset(new BaseFile(net::NetLogWithSource()));
+  base_file_.reset(new BaseFile(DownloadItem::kInvalidId));
   ASSERT_EQ(
       DOWNLOAD_INTERRUPT_REASON_NONE,
       base_file_->Initialize(existing_file_name, base::FilePath(), base::File(),
@@ -491,7 +492,7 @@
   EXPECT_TRUE(base::MakeFileUnwritable(readonly_file_name));
 
   // Try to overwrite it.
-  base_file_.reset(new BaseFile(net::NetLogWithSource()));
+  base_file_.reset(new BaseFile(DownloadItem::kInvalidId));
   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
             base_file_->Initialize(readonly_file_name, base::FilePath(),
                                    base::File(), 0, std::string(),
diff --git a/content/browser/download/base_file_win_unittest.cc b/content/browser/download/base_file_win_unittest.cc
index f29f79e..1b1c929 100644
--- a/content/browser/download/base_file_win_unittest.cc
+++ b/content/browser/download/base_file_win_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "content/public/browser/download_interrupt_reasons.h"
+#include "content/public/browser/download_item.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/filename_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -68,7 +69,7 @@
     SCOPED_TRACE(::testing::Message() << "Source URL: " << url.spec()
                                       << " Referrer: " << test_case.referrer);
 
-    BaseFile base_file((net::NetLogWithSource()));
+    BaseFile base_file(DownloadItem::kInvalidId);
     ASSERT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
               base_file.Initialize(base::FilePath(), target_directory.GetPath(),
                                    base::File(), 0, std::string(),
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 8fd1ebf..c8bbf9e 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -172,7 +172,7 @@
   DownloadFileWithDelay(std::unique_ptr<DownloadSaveInfo> save_info,
                         const base::FilePath& default_download_directory,
                         std::unique_ptr<DownloadManager::InputStream> stream,
-                        const net::NetLogWithSource& net_log,
+                        uint32_t download_id,
                         base::WeakPtr<DownloadDestinationObserver> observer,
                         base::WeakPtr<DownloadFileWithDelayFactory> owner);
 
@@ -217,7 +217,7 @@
       std::unique_ptr<DownloadSaveInfo> save_info,
       const base::FilePath& default_download_directory,
       std::unique_ptr<DownloadManager::InputStream> stream,
-      const net::NetLogWithSource& net_log,
+      uint32_t download_id,
       base::WeakPtr<DownloadDestinationObserver> observer) override;
 
   void AddRenameCallback(base::Closure callback);
@@ -238,13 +238,13 @@
     std::unique_ptr<DownloadSaveInfo> save_info,
     const base::FilePath& default_download_directory,
     std::unique_ptr<DownloadManager::InputStream> stream,
-    const net::NetLogWithSource& net_log,
+    uint32_t download_id,
     base::WeakPtr<DownloadDestinationObserver> observer,
     base::WeakPtr<DownloadFileWithDelayFactory> owner)
     : DownloadFileImpl(std::move(save_info),
                        default_download_directory,
                        std::move(stream),
-                       net_log,
+                       download_id,
                        observer),
       owner_(owner) {}
 
@@ -297,14 +297,11 @@
     std::unique_ptr<DownloadSaveInfo> save_info,
     const base::FilePath& default_download_directory,
     std::unique_ptr<DownloadManager::InputStream> stream,
-    const net::NetLogWithSource& net_log,
+    uint32_t download_id,
     base::WeakPtr<DownloadDestinationObserver> observer) {
-  return new DownloadFileWithDelay(std::move(save_info),
-                                   default_download_directory,
-                                   std::move(stream),
-                                   net_log,
-                                   observer,
-                                   weak_ptr_factory_.GetWeakPtr());
+  return new DownloadFileWithDelay(
+      std::move(save_info), default_download_directory, std::move(stream),
+      download_id, observer, weak_ptr_factory_.GetWeakPtr());
 }
 
 void DownloadFileWithDelayFactory::AddRenameCallback(base::Closure callback) {
@@ -335,12 +332,12 @@
   CountingDownloadFile(std::unique_ptr<DownloadSaveInfo> save_info,
                        const base::FilePath& default_downloads_directory,
                        std::unique_ptr<DownloadManager::InputStream> stream,
-                       const net::NetLogWithSource& net_log,
+                       uint32_t download_id,
                        base::WeakPtr<DownloadDestinationObserver> observer)
       : DownloadFileImpl(std::move(save_info),
                          default_downloads_directory,
                          std::move(stream),
-                         net_log,
+                         download_id,
                          observer) {}
 
   ~CountingDownloadFile() override {
@@ -393,13 +390,11 @@
       std::unique_ptr<DownloadSaveInfo> save_info,
       const base::FilePath& default_downloads_directory,
       std::unique_ptr<DownloadManager::InputStream> stream,
-      const net::NetLogWithSource& net_log,
+      uint32_t download_id,
       base::WeakPtr<DownloadDestinationObserver> observer) override {
     return new CountingDownloadFile(std::move(save_info),
                                     default_downloads_directory,
-                                    std::move(stream),
-                                    net_log,
-                                    observer);
+                                    std::move(stream), download_id, observer);
   }
 };
 
@@ -409,14 +404,14 @@
       std::unique_ptr<DownloadSaveInfo> save_info,
       const base::FilePath& default_downloads_directory,
       std::unique_ptr<DownloadManager::InputStream> stream,
-      const net::NetLogWithSource& net_log,
+      uint32_t download_id,
       base::WeakPtr<DownloadDestinationObserver> observer,
       int64_t error_stream_offset,
       int64_t error_stream_length)
       : DownloadFileImpl(std::move(save_info),
                          default_downloads_directory,
                          std::move(stream),
-                         net_log,
+                         download_id,
                          observer),
         error_stream_offset_(error_stream_offset),
         error_stream_length_(error_stream_length) {}
@@ -456,11 +451,11 @@
       std::unique_ptr<DownloadSaveInfo> save_info,
       const base::FilePath& default_download_directory,
       std::unique_ptr<DownloadManager::InputStream> stream,
-      const net::NetLogWithSource& net_log,
+      uint32_t download_id,
       base::WeakPtr<DownloadDestinationObserver> observer) override {
     ErrorInjectionDownloadFile* download_file = new ErrorInjectionDownloadFile(
         std::move(save_info), default_download_directory, std::move(stream),
-        net_log, observer, injected_error_offset_, injected_error_length_);
+        download_id, observer, injected_error_offset_, injected_error_length_);
     // If the InjectError() is not called yet, memorize |download_file| and wait
     // for error to be injected.
     if (injected_error_offset_ < 0)
diff --git a/content/browser/download/download_create_info.cc b/content/browser/download/download_create_info.cc
index 4f795e10..e7741fb 100644
--- a/content/browser/download/download_create_info.cc
+++ b/content/browser/download/download_create_info.cc
@@ -15,7 +15,6 @@
 
 DownloadCreateInfo::DownloadCreateInfo(
     const base::Time& start_time,
-    const net::NetLogWithSource& net_log,
     std::unique_ptr<DownloadSaveInfo> save_info)
     : download_id(DownloadItem::kInvalidId),
       start_time(start_time),
@@ -25,14 +24,12 @@
       transient(false),
       result(DOWNLOAD_INTERRUPT_REASON_NONE),
       save_info(std::move(save_info)),
-      request_net_log(net_log),
       accept_range(false),
       connection_info(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN),
       method("GET") {}
 
 DownloadCreateInfo::DownloadCreateInfo()
     : DownloadCreateInfo(base::Time(),
-                         net::NetLogWithSource(),
                          base::WrapUnique(new DownloadSaveInfo)) {}
 
 DownloadCreateInfo::~DownloadCreateInfo() {}
diff --git a/content/browser/download/download_create_info.h b/content/browser/download/download_create_info.h
index af6eac17..acc0da42 100644
--- a/content/browser/download/download_create_info.h
+++ b/content/browser/download/download_create_info.h
@@ -21,7 +21,6 @@
 #include "content/public/browser/download_interrupt_reasons.h"
 #include "content/public/browser/download_save_info.h"
 #include "net/http/http_response_info.h"
-#include "net/log/net_log_with_source.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
@@ -35,7 +34,6 @@
 // want to pass |DownloadItem|s between threads.
 struct CONTENT_EXPORT DownloadCreateInfo {
   DownloadCreateInfo(const base::Time& start_time,
-                     const net::NetLogWithSource& net_log,
                      std::unique_ptr<DownloadSaveInfo> save_info);
   DownloadCreateInfo();
   ~DownloadCreateInfo();
@@ -105,10 +103,6 @@
   // The handle to the URLRequest sourcing this download.
   std::unique_ptr<DownloadRequestHandleInterface> request_handle;
 
-  // The request's |NetLogWithSource|, for "source_dependency" linking with the
-  // download item's.
-  const net::NetLogWithSource request_net_log;
-
   // ---------------------------------------------------------------------------
   // The remaining fields are Entity-body properties. These are only set if
   // |result| is DOWNLOAD_INTERRUPT_REASON_NONE.
diff --git a/content/browser/download/download_file_factory.cc b/content/browser/download/download_file_factory.cc
index db80e1f..9030353 100644
--- a/content/browser/download/download_file_factory.cc
+++ b/content/browser/download/download_file_factory.cc
@@ -16,10 +16,10 @@
     std::unique_ptr<DownloadSaveInfo> save_info,
     const base::FilePath& default_downloads_directory,
     std::unique_ptr<DownloadManager::InputStream> stream,
-    const net::NetLogWithSource& net_log,
+    uint32_t download_id,
     base::WeakPtr<DownloadDestinationObserver> observer) {
   return new DownloadFileImpl(std::move(save_info), default_downloads_directory,
-                              std::move(stream), net_log, observer);
+                              std::move(stream), download_id, observer);
 }
 
 }  // namespace content
diff --git a/content/browser/download/download_file_factory.h b/content/browser/download/download_file_factory.h
index 832c707..bad3ad2 100644
--- a/content/browser/download/download_file_factory.h
+++ b/content/browser/download/download_file_factory.h
@@ -16,10 +16,6 @@
 #include "content/common/content_export.h"
 #include "url/gurl.h"
 
-namespace net {
-class NetLogWithSource;
-}
-
 namespace content {
 
 class DownloadDestinationObserver;
@@ -34,7 +30,7 @@
       std::unique_ptr<DownloadSaveInfo> save_info,
       const base::FilePath& default_downloads_directory,
       std::unique_ptr<DownloadManager::InputStream> stream,
-      const net::NetLogWithSource& net_log,
+      uint32_t download_id,
       base::WeakPtr<DownloadDestinationObserver> observer);
 };
 
diff --git a/content/browser/download/download_file_impl.cc b/content/browser/download/download_file_impl.cc
index ea230c3..278594a 100644
--- a/content/browser/download/download_file_impl.cc
+++ b/content/browser/download/download_file_impl.cc
@@ -18,7 +18,6 @@
 #include "content/browser/download/download_create_info.h"
 #include "content/browser/download/download_destination_observer.h"
 #include "content/browser/download/download_interrupt_reasons_impl.h"
-#include "content/browser/download/download_net_log_parameters.h"
 #include "content/browser/download/download_stats.h"
 #include "content/browser/download/download_utils.h"
 #include "content/browser/download/parallel_download_utils.h"
@@ -28,10 +27,6 @@
 #include "crypto/sha2.h"
 #include "mojo/public/c/system/types.h"
 #include "net/base/io_buffer.h"
-#include "net/log/net_log.h"
-#include "net/log/net_log_event_type.h"
-#include "net/log/net_log_source.h"
-#include "net/log/net_log_source_type.h"
 
 namespace content {
 
@@ -201,11 +196,11 @@
     std::unique_ptr<DownloadSaveInfo> save_info,
     const base::FilePath& default_download_directory,
     std::unique_ptr<DownloadManager::InputStream> stream,
-    const net::NetLogWithSource& download_item_net_log,
+    uint32_t download_id,
     base::WeakPtr<DownloadDestinationObserver> observer)
     : DownloadFileImpl(std::move(save_info),
                        default_download_directory,
-                       download_item_net_log,
+                       download_id,
                        observer) {
   source_streams_[save_info_->offset] = std::make_unique<SourceStream>(
       save_info_->offset, save_info_->length, std::move(stream));
@@ -214,12 +209,9 @@
 DownloadFileImpl::DownloadFileImpl(
     std::unique_ptr<DownloadSaveInfo> save_info,
     const base::FilePath& default_download_directory,
-    const net::NetLogWithSource& download_item_net_log,
+    uint32_t download_id,
     base::WeakPtr<DownloadDestinationObserver> observer)
-    : net_log_(
-          net::NetLogWithSource::Make(download_item_net_log.net_log(),
-                                      net::NetLogSourceType::DOWNLOAD_FILE)),
-      file_(net_log_),
+    : file_(download_id),
       save_info_(std::move(save_info)),
       default_download_directory_(default_download_directory),
       potential_file_length_(kUnknownContentLength),
@@ -229,14 +221,13 @@
       bytes_seen_with_parallel_streams_(0),
       bytes_seen_without_parallel_streams_(0),
       is_paused_(false),
+      download_id_(download_id),
       observer_(observer),
       weak_factory_(this) {
-  download_item_net_log.AddEvent(
-      net::NetLogEventType::DOWNLOAD_FILE_CREATED,
-      net_log_.source().ToEventParametersCallback());
-  net_log_.BeginEvent(
-      net::NetLogEventType::DOWNLOAD_FILE_ACTIVE,
-      download_item_net_log.source().ToEventParametersCallback());
+  TRACE_EVENT_INSTANT0("download", "DownloadFileCreated",
+                       TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("download", "DownloadFileActive",
+                                    download_id);
 
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
@@ -244,7 +235,8 @@
 DownloadFileImpl::~DownloadFileImpl() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_FILE_ACTIVE);
+  TRACE_EVENT_NESTABLE_ASYNC_END0("download", "DownloadFileActive",
+                                  download_id_);
 }
 
 void DownloadFileImpl::Initialize(
@@ -632,11 +624,9 @@
   else
     NotifyObserver(source_stream, reason, state, should_terminate);
 
-  if (net_log_.IsCapturing()) {
-    net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_STREAM_DRAINED,
-                      base::Bind(&FileStreamDrainedNetLogCallback,
-                                 total_incoming_data_size, num_buffers));
-  }
+  TRACE_EVENT_INSTANT2("download", "DownloadStreamDrained",
+                       TRACE_EVENT_SCOPE_THREAD, "stream_size",
+                       total_incoming_data_size, "num_buffers", num_buffers);
 }
 
 void DownloadFileImpl::OnStreamCompleted(SourceStream* source_stream) {
diff --git a/content/browser/download/download_file_impl.h b/content/browser/download/download_file_impl.h
index e197ee5..3285a64 100644
--- a/content/browser/download/download_file_impl.h
+++ b/content/browser/download/download_file_impl.h
@@ -30,7 +30,6 @@
 #include "content/public/common/download_stream.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/system/simple_watcher.h"
-#include "net/log/net_log_with_source.h"
 
 namespace content {
 class ByteStreamReader;
@@ -49,7 +48,7 @@
   DownloadFileImpl(std::unique_ptr<DownloadSaveInfo> save_info,
                    const base::FilePath& default_downloads_directory,
                    std::unique_ptr<DownloadManager::InputStream> stream,
-                   const net::NetLogWithSource& net_log,
+                   uint32_t download_id,
                    base::WeakPtr<DownloadDestinationObserver> observer);
 
   ~DownloadFileImpl() override;
@@ -206,7 +205,7 @@
 
   DownloadFileImpl(std::unique_ptr<DownloadSaveInfo> save_info,
                    const base::FilePath& default_downloads_directory,
-                   const net::NetLogWithSource& net_log,
+                   uint32_t download_id,
                    base::WeakPtr<DownloadDestinationObserver> observer);
 
   // Options for RenameWithRetryInternal.
@@ -306,8 +305,6 @@
   // Print the internal states for debugging.
   void DebugStates() const;
 
-  net::NetLogWithSource net_log_;
-
   // The base file instance.
   BaseFile file_;
 
@@ -356,6 +353,8 @@
   // by DownloadRequestCore in that case.
   bool is_paused_;
 
+  uint32_t download_id_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtr<DownloadDestinationObserver> observer_;
diff --git a/content/browser/download/download_file_unittest.cc b/content/browser/download/download_file_unittest.cc
index 583e1638..9b7b0d0 100644
--- a/content/browser/download/download_file_unittest.cc
+++ b/content/browser/download/download_file_unittest.cc
@@ -30,7 +30,6 @@
 #include "net/base/file_stream.h"
 #include "net/base/mock_file_stream.h"
 #include "net/base/net_errors.h"
-#include "net/log/net_log_with_source.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -121,12 +120,12 @@
   TestDownloadFileImpl(std::unique_ptr<DownloadSaveInfo> save_info,
                        const base::FilePath& default_downloads_directory,
                        std::unique_ptr<DownloadManager::InputStream> stream,
-                       const net::NetLogWithSource& net_log,
+                       uint32_t download_id,
                        base::WeakPtr<DownloadDestinationObserver> observer)
       : DownloadFileImpl(std::move(save_info),
                          default_downloads_directory,
                          std::move(stream),
-                         net_log,
+                         download_id,
                          observer) {}
 
  protected:
@@ -230,7 +229,7 @@
         std::move(save_info), base::FilePath(),
         std::make_unique<DownloadManager::InputStream>(
             std::unique_ptr<ByteStreamReader>(input_stream_)),
-        net::NetLogWithSource(), observer_factory_.GetWeakPtr()));
+        DownloadItem::kInvalidId, observer_factory_.GetWeakPtr()));
 
     EXPECT_CALL(*input_stream_, Read(_, _))
         .WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
diff --git a/content/browser/download/download_item_factory.h b/content/browser/download/download_item_factory.h
index c9a083b..a1f64a8 100644
--- a/content/browser/download/download_item_factory.h
+++ b/content/browser/download/download_item_factory.h
@@ -23,10 +23,6 @@
 class FilePath;
 }
 
-namespace net {
-class NetLogWithSource;
-}
-
 namespace content {
 
 class DownloadItem;
@@ -65,14 +61,12 @@
       bool opened,
       base::Time last_access_time,
       bool transient,
-      const std::vector<DownloadItem::ReceivedSlice>& received_slices,
-      const net::NetLogWithSource& net_log) = 0;
+      const std::vector<DownloadItem::ReceivedSlice>& received_slices) = 0;
 
   virtual DownloadItemImpl* CreateActiveItem(
       DownloadItemImplDelegate* delegate,
       uint32_t download_id,
-      const DownloadCreateInfo& info,
-      const net::NetLogWithSource& net_log) = 0;
+      const DownloadCreateInfo& info) = 0;
 
   virtual DownloadItemImpl* CreateSavePageItem(
       DownloadItemImplDelegate* delegate,
@@ -80,8 +74,7 @@
       const base::FilePath& path,
       const GURL& url,
       const std::string& mime_type,
-      std::unique_ptr<DownloadRequestHandleInterface> request_handle,
-      const net::NetLogWithSource& net_log) = 0;
+      std::unique_ptr<DownloadRequestHandleInterface> request_handle) = 0;
 };
 
 }  // namespace content
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index e5a0ca5ad..ae2922c8 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -43,7 +43,6 @@
 #include "content/browser/download/download_item_impl_delegate.h"
 #include "content/browser/download/download_job_factory.h"
 #include "content/browser/download/download_job_impl.h"
-#include "content/browser/download/download_net_log_parameters.h"
 #include "content/browser/download/download_request_handle.h"
 #include "content/browser/download/download_stats.h"
 #include "content/browser/download/download_task_runner.h"
@@ -61,10 +60,6 @@
 #include "content/public/common/referrer.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
-#include "net/log/net_log.h"
-#include "net/log/net_log_event_type.h"
-#include "net/log/net_log_parameters_callback.h"
-#include "net/log/net_log_source.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace content {
@@ -127,6 +122,101 @@
          reason == DOWNLOAD_INTERRUPT_REASON_USER_CANCELED;
 }
 
+std::string GetDownloadTypeNames(DownloadItem::DownloadType type) {
+  switch (type) {
+    case DownloadItem::TYPE_ACTIVE_DOWNLOAD:
+      return "NEW_DOWNLOAD";
+    case DownloadItem::TYPE_HISTORY_IMPORT:
+      return "HISTORY_IMPORT";
+    case DownloadItem::TYPE_SAVE_PAGE_AS:
+      return "SAVE_PAGE_AS";
+    default:
+      NOTREACHED();
+      return "INVALID_TYPE";
+  }
+}
+
+std::string GetDownloadDangerNames(DownloadDangerType type) {
+  switch (type) {
+    case DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
+      return "NOT_DANGEROUS";
+    case DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
+      return "DANGEROUS_FILE";
+    case DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
+      return "DANGEROUS_URL";
+    case DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
+      return "DANGEROUS_CONTENT";
+    case DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
+      return "MAYBE_DANGEROUS_CONTENT";
+    case DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
+      return "UNCOMMON_CONTENT";
+    case DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
+      return "USER_VALIDATED";
+    case DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
+      return "DANGEROUS_HOST";
+    case DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
+      return "POTENTIALLY_UNWANTED";
+    default:
+      NOTREACHED();
+      return "UNKNOWN_DANGER_TYPE";
+  }
+}
+
+class DownloadItemActivatedData
+    : public base::trace_event::ConvertableToTraceFormat {
+ public:
+  DownloadItemActivatedData(DownloadItem::DownloadType download_type,
+                            uint32_t download_id,
+                            std::string original_url,
+                            std::string final_url,
+                            std::string file_name,
+                            DownloadDangerType danger_type,
+                            int64_t start_offset,
+                            bool has_user_gesture)
+      : download_type_(download_type),
+        download_id_(download_id),
+        original_url_(original_url),
+        final_url_(final_url),
+        file_name_(file_name),
+        danger_type_(danger_type),
+        start_offset_(start_offset),
+        has_user_gesture_(has_user_gesture) {}
+
+  ~DownloadItemActivatedData() override = default;
+
+  void AppendAsTraceFormat(std::string* out) const override {
+    out->append("{");
+    out->append(base::StringPrintf(
+        "\"type\":\"%s\",", GetDownloadTypeNames(download_type_).c_str()));
+    out->append(base::StringPrintf("\"id\":\"%d\",", download_id_));
+    out->append(
+        base::StringPrintf("\"original_url\":\"%s\",", original_url_.c_str()));
+    out->append(
+        base::StringPrintf("\"final_url\":\"%s\",", final_url_.c_str()));
+    out->append(
+        base::StringPrintf("\"file_name\":\"%s\",", file_name_.c_str()));
+    out->append(
+        base::StringPrintf("\"danger_type\":\"%s\",",
+                           GetDownloadDangerNames(danger_type_).c_str()));
+    out->append(
+        base::StringPrintf("\"start_offset\":\"%" PRId64 "\",", start_offset_));
+    out->append(base::StringPrintf("\"has_user_gesture\":\"%s\"",
+                                   has_user_gesture_ ? "true" : "false"));
+    out->append("}");
+  }
+
+ private:
+  DownloadItem::DownloadType download_type_;
+  uint32_t download_id_;
+  std::string original_url_;
+  std::string final_url_;
+  std::string file_name_;
+  DownloadDangerType danger_type_;
+  int64_t start_offset_;
+  bool has_user_gesture_;
+  DISALLOW_COPY_AND_ASSIGN(DownloadItemActivatedData);
+};
+
 }  // namespace
 
 const uint32_t DownloadItem::kInvalidId = 0;
@@ -220,8 +310,7 @@
     bool opened,
     base::Time last_access_time,
     bool transient,
-    const std::vector<DownloadItem::ReceivedSlice>& received_slices,
-    const net::NetLogWithSource& net_log)
+    const std::vector<DownloadItem::ReceivedSlice>& received_slices)
     : request_info_(url_chain,
                     referrer_url,
                     site_url,
@@ -255,21 +344,19 @@
       last_modified_time_(last_modified),
       etag_(etag),
       received_slices_(received_slices),
-      net_log_(net_log),
       is_updating_observers_(false),
       weak_ptr_factory_(this) {
   delegate_->Attach();
   DCHECK(state_ == COMPLETE_INTERNAL || state_ == INTERRUPTED_INTERNAL ||
          state_ == CANCELLED_INTERNAL);
   DCHECK(base::IsValidGUID(guid_));
-  Init(false /* not actively downloading */, SRC_HISTORY_IMPORT);
+  Init(false /* not actively downloading */, TYPE_HISTORY_IMPORT);
 }
 
 // Constructing for a regular download:
 DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
                                    uint32_t download_id,
-                                   const DownloadCreateInfo& info,
-                                   const net::NetLogWithSource& net_log)
+                                   const DownloadCreateInfo& info)
     : request_info_(info.url_chain,
                     info.referrer_url,
                     info.site_url,
@@ -300,21 +387,13 @@
                             : TARGET_DISPOSITION_OVERWRITE),
       last_modified_time_(info.last_modified),
       etag_(info.etag),
-      net_log_(net_log),
       is_updating_observers_(false),
       fetch_error_body_(info.fetch_error_body),
       weak_ptr_factory_(this) {
   delegate_->Attach();
-  Init(true /* actively downloading */, SRC_ACTIVE_DOWNLOAD);
+  Init(true /* actively downloading */, TYPE_ACTIVE_DOWNLOAD);
 
-  // Link the event sources.
-  net_log_.AddEvent(
-      net::NetLogEventType::DOWNLOAD_URL_REQUEST,
-      info.request_net_log.source().ToEventParametersCallback());
-
-  info.request_net_log.AddEvent(
-      net::NetLogEventType::DOWNLOAD_STARTED,
-      net_log_.source().ToEventParametersCallback());
+  TRACE_EVENT_INSTANT0("download", "DownloadStarted", TRACE_EVENT_SCOPE_THREAD);
 }
 
 // Constructing for the "Save Page As..." feature:
@@ -324,8 +403,7 @@
     const base::FilePath& path,
     const GURL& url,
     const std::string& mime_type,
-    std::unique_ptr<DownloadRequestHandleInterface> request_handle,
-    const net::NetLogWithSource& net_log)
+    std::unique_ptr<DownloadRequestHandleInterface> request_handle)
     : request_info_(url),
       guid_(base::GenerateGUID()),
       download_id_(download_id),
@@ -335,13 +413,12 @@
       state_(IN_PROGRESS_INTERNAL),
       delegate_(delegate),
       destination_info_(path, path, 0, false, std::string(), base::Time()),
-      net_log_(net_log),
       is_updating_observers_(false),
       weak_ptr_factory_(this) {
   job_ = DownloadJobFactory::CreateJob(this, std::move(request_handle),
                                        DownloadCreateInfo(), true);
   delegate_->Attach();
-  Init(true /* actively downloading */, SRC_SAVE_PAGE_AS);
+  Init(true /* actively downloading */, TYPE_SAVE_PAGE_AS);
 }
 
 DownloadItemImpl::~DownloadItemImpl() {
@@ -398,9 +475,9 @@
 
   danger_type_ = DOWNLOAD_DANGER_TYPE_USER_VALIDATED;
 
-  net_log_.AddEvent(
-      net::NetLogEventType::DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
-      base::Bind(&ItemCheckedNetLogCallback, GetDangerType()));
+  TRACE_EVENT_INSTANT1("download", "DownloadItemSaftyStateUpdated",
+                       TRACE_EVENT_SCOPE_THREAD, "danger_type",
+                       GetDownloadDangerNames(danger_type_).c_str());
 
   UpdateObservers();  // TODO(asanka): This is potentially unsafe. The download
                       // may not be in a consistent state or around at all after
@@ -1153,10 +1230,6 @@
   return weak_ptr_factory_.GetWeakPtr();
 }
 
-const net::NetLogWithSource& DownloadItemImpl::GetNetLogWithSource() const {
-  return net_log_;
-}
-
 void DownloadItemImpl::SetTotalBytes(int64_t total_bytes) {
   total_bytes_ = total_bytes;
 }
@@ -1220,11 +1293,9 @@
 
   UpdateProgress(bytes_so_far, bytes_per_sec);
   received_slices_ = received_slices;
-  if (net_log_.IsCapturing()) {
-    net_log_.AddEvent(
-        net::NetLogEventType::DOWNLOAD_ITEM_UPDATED,
-        net::NetLog::Int64Callback("bytes_so_far", GetReceivedBytes()));
-  }
+  TRACE_EVENT_INSTANT1("download", "DownloadItemUpdated",
+                       TRACE_EVENT_SCOPE_THREAD, "bytes_so_far",
+                       GetReceivedBytes());
 
   UpdateObservers();
 }
@@ -1267,11 +1338,11 @@
 // **** Download progression cascade
 
 void DownloadItemImpl::Init(bool active,
-                            DownloadType download_type) {
+                            DownloadItem::DownloadType download_type) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   std::string file_name;
-  if (download_type == SRC_HISTORY_IMPORT) {
+  if (download_type == TYPE_HISTORY_IMPORT) {
     // target_path_ works for History and Save As versions.
     file_name = GetTargetFilePath().AsUTF8Unsafe();
   } else {
@@ -1285,14 +1356,17 @@
       file_name = GetURL().ExtractFileName();
   }
 
-  net::NetLogParametersCallback active_data =
-      base::Bind(&ItemActivatedNetLogCallback, this, download_type, &file_name);
+  auto active_data = base::MakeUnique<DownloadItemActivatedData>(
+      download_type, GetId(), GetOriginalUrl().spec(), GetURL().spec(),
+      file_name, GetDangerType(), GetReceivedBytes(), HasUserGesture());
+
   if (active) {
-    net_log_.BeginEvent(net::NetLogEventType::DOWNLOAD_ITEM_ACTIVE,
-                              active_data);
+    TRACE_EVENT_ASYNC_BEGIN1("download", "DownloadItemActive", download_id_,
+                             "download_item", std::move(active_data));
   } else {
-    net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_ITEM_ACTIVE,
-                            active_data);
+    TRACE_EVENT_INSTANT1("download", "DownloadItemActive",
+                         TRACE_EVENT_SCOPE_THREAD, "download_item",
+                         std::move(active_data));
   }
 
   DVLOG(20) << __func__ << "() " << DebugString(true);
@@ -2015,37 +2089,39 @@
       DCHECK(GetFullPath() == GetTargetFilePath())
           << "Current output path must match target path.";
 
-      net_log_.AddEvent(
-          net::NetLogEventType::DOWNLOAD_ITEM_COMPLETING,
-          base::Bind(&ItemCompletingNetLogCallback, GetReceivedBytes(),
-                     &destination_info_.hash));
+      TRACE_EVENT_INSTANT2("download", "DownloadItemCompleting",
+                           TRACE_EVENT_SCOPE_THREAD, "bytes_so_far",
+                           GetReceivedBytes(), "final_hash",
+                           destination_info_.hash);
       break;
 
     case COMPLETE_INTERNAL:
-      net_log_.AddEvent(
-          net::NetLogEventType::DOWNLOAD_ITEM_FINISHED,
-          base::Bind(&ItemFinishedNetLogCallback, auto_opened_));
+      TRACE_EVENT_INSTANT1("download", "DownloadItemFinished",
+                           TRACE_EVENT_SCOPE_THREAD, "auto_opened",
+                           auto_opened_ ? "yes" : "no");
       break;
 
     case INTERRUPTED_INTERNAL:
       DCHECK(!download_file_)
           << "Download file must be released prior to interruption.";
       DCHECK_NE(last_reason_, DOWNLOAD_INTERRUPT_REASON_NONE);
-      net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_ITEM_INTERRUPTED,
-                        base::Bind(&ItemInterruptedNetLogCallback, last_reason_,
-                                   GetReceivedBytes()));
+      TRACE_EVENT_INSTANT2("download", "DownloadItemInterrupted",
+                           TRACE_EVENT_SCOPE_THREAD, "interrupt_reason",
+                           DownloadInterruptReasonToString(last_reason_),
+                           "bytes_so_far", GetReceivedBytes());
       break;
 
     case RESUMING_INTERNAL:
-      net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_ITEM_RESUMED,
-                        base::Bind(&ItemResumingNetLogCallback, false,
-                                   last_reason_, GetReceivedBytes()));
+      TRACE_EVENT_INSTANT2("download", "DownloadItemResumed",
+                           TRACE_EVENT_SCOPE_THREAD, "interrupt_reason",
+                           DownloadInterruptReasonToString(last_reason_),
+                           "bytes_so_far", GetReceivedBytes());
       break;
 
     case CANCELLED_INTERNAL:
-      net_log_.AddEvent(
-          net::NetLogEventType::DOWNLOAD_ITEM_CANCELED,
-          base::Bind(&ItemCanceledNetLogCallback, GetReceivedBytes()));
+      TRACE_EVENT_INSTANT1("download", "DownloadItemCancelled",
+                           TRACE_EVENT_SCOPE_THREAD, "bytes_so_far",
+                           GetReceivedBytes());
       break;
 
     case MAX_DOWNLOAD_INTERNAL_STATE:
@@ -2065,22 +2141,25 @@
 
   // Termination
   if (is_done && !was_done)
-    net_log_.EndEvent(net::NetLogEventType::DOWNLOAD_ITEM_ACTIVE);
+    TRACE_EVENT_ASYNC_END0("download", "DownloadItemActive", download_id_);
 
   // Resumption
   if (was_done && !is_done) {
     std::string file_name(GetTargetFilePath().BaseName().AsUTF8Unsafe());
-    net_log_.BeginEvent(net::NetLogEventType::DOWNLOAD_ITEM_ACTIVE,
-                              base::Bind(&ItemActivatedNetLogCallback, this,
-                                         SRC_ACTIVE_DOWNLOAD, &file_name));
+    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
+        "download", "DownloadItemActive", download_id_, "download_item",
+        base::MakeUnique<DownloadItemActivatedData>(
+            TYPE_ACTIVE_DOWNLOAD, GetId(), GetOriginalUrl().spec(),
+            GetURL().spec(), file_name, GetDangerType(), GetReceivedBytes(),
+            HasUserGesture()));
   }
 }
 
 void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
   if (danger_type != danger_type_) {
-    net_log_.AddEvent(
-        net::NetLogEventType::DOWNLOAD_ITEM_SAFETY_STATE_UPDATED,
-        base::Bind(&ItemCheckedNetLogCallback, danger_type));
+    TRACE_EVENT_INSTANT1("download", "DownloadItemSaftyStateUpdated",
+                         TRACE_EVENT_SCOPE_THREAD, "danger_type",
+                         GetDownloadDangerNames(danger_type).c_str());
   }
   // Only record the Malicious UMA stat if it's going from {not malicious} ->
   // {malicious}.
@@ -2103,9 +2182,10 @@
             << DebugString(true);
   DCHECK(!new_path.empty());
 
-  net_log_.AddEvent(net::NetLogEventType::DOWNLOAD_ITEM_RENAMED,
-                    base::Bind(&ItemRenamedNetLogCallback,
-                               &destination_info_.current_path, &new_path));
+  TRACE_EVENT_INSTANT2("download", "DownloadItemRenamed",
+                       TRACE_EVENT_SCOPE_THREAD, "old_filename",
+                       destination_info_.current_path.AsUTF8Unsafe(),
+                       "new_filename", new_path.AsUTF8Unsafe());
 
   destination_info_.current_path = new_path;
 }
diff --git a/content/browser/download/download_item_impl.h b/content/browser/download/download_item_impl.h
index 6a7fc588..ed6795d 100644
--- a/content/browser/download/download_item_impl.h
+++ b/content/browser/download/download_item_impl.h
@@ -18,12 +18,10 @@
 #include "base/observer_list.h"
 #include "base/time/time.h"
 #include "content/browser/download/download_destination_observer.h"
-#include "content/browser/download/download_net_log_parameters.h"
 #include "content/browser/download/download_request_handle.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/download_interrupt_reasons.h"
 #include "content/public/browser/download_item.h"
-#include "net/log/net_log_with_source.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -178,15 +176,13 @@
       bool opened,
       base::Time last_access_time,
       bool transient,
-      const std::vector<DownloadItem::ReceivedSlice>& received_slices,
-      const net::NetLogWithSource& net_log);
+      const std::vector<DownloadItem::ReceivedSlice>& received_slices);
 
   // Constructing for a regular download.
   // |net_log| is constructed externally for our use.
   DownloadItemImpl(DownloadItemImplDelegate* delegate,
                    uint32_t id,
-                   const DownloadCreateInfo& info,
-                   const net::NetLogWithSource& net_log);
+                   const DownloadCreateInfo& info);
 
   // Constructing for the "Save Page As..." feature:
   // |net_log| is constructed externally for our use.
@@ -196,8 +192,7 @@
       const base::FilePath& path,
       const GURL& url,
       const std::string& mime_type,
-      std::unique_ptr<DownloadRequestHandleInterface> request_handle,
-      const net::NetLogWithSource& net_log);
+      std::unique_ptr<DownloadRequestHandleInterface> request_handle);
 
   ~DownloadItemImpl() override;
 
@@ -307,9 +302,6 @@
   virtual base::WeakPtr<DownloadDestinationObserver>
       DestinationObserverAsWeakPtr();
 
-  // Get the download's NetLogWithSource.
-  virtual const net::NetLogWithSource& GetNetLogWithSource() const;
-
   // DownloadItemImpl routines only needed by SavePackage ----------------------
 
   // Called by SavePackage to set the total number of bytes on the item.
@@ -497,9 +489,8 @@
 
   // Construction common to all constructors. |active| should be true for new
   // downloads and false for downloads from the history.
-  // |download_type| indicates to the net log system what kind of download
-  // this is.
-  void Init(bool active, DownloadType download_type);
+  // |download_type| indicates to the trace event what kind of download this is.
+  void Init(bool active, DownloadItem::DownloadType download_type);
 
   // Callback from file thread when we initialize the DownloadFile.
   void OnDownloadFileInitialized(DownloadInterruptReason result);
@@ -747,9 +738,6 @@
   // The data slices that have been received so far.
   std::vector<DownloadItem::ReceivedSlice> received_slices_;
 
-  // Net log to use for this download.
-  const net::NetLogWithSource net_log_;
-
   std::unique_ptr<DownloadJob> job_;
 
   // Value of |received_bytes_| at the time the download was interrupted with
diff --git a/content/browser/download/download_item_impl_unittest.cc b/content/browser/download/download_item_impl_unittest.cc
index 0797c3c1..6b0e71b 100644
--- a/content/browser/download/download_item_impl_unittest.cc
+++ b/content/browser/download/download_item_impl_unittest.cc
@@ -277,9 +277,8 @@
 
   DownloadItemImpl* CreateDownloadItemWithCreateInfo(
       std::unique_ptr<DownloadCreateInfo> info) {
-    DownloadItemImpl* download =
-        new DownloadItemImpl(mock_delegate(), next_download_id_++,
-                             *(info.get()), net::NetLogWithSource());
+    DownloadItemImpl* download = new DownloadItemImpl(
+        mock_delegate(), next_download_id_++, *(info.get()));
     allocated_downloads_[download] = base::WrapUnique(download);
     return download;
   }
@@ -296,9 +295,8 @@
   // called.
   DownloadItemImpl* CreateDownloadItem() {
     create_info_->download_id = ++next_download_id_;
-    DownloadItemImpl* download =
-        new DownloadItemImpl(mock_delegate(), create_info_->download_id,
-                             *create_info_, net::NetLogWithSource());
+    DownloadItemImpl* download = new DownloadItemImpl(
+        mock_delegate(), create_info_->download_id, *create_info_);
     allocated_downloads_[download] = base::WrapUnique(download);
     return download;
   }
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 474e2b2..675b085 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -56,8 +56,6 @@
 #include "net/base/load_flags.h"
 #include "net/base/request_priority.h"
 #include "net/base/upload_bytes_element_reader.h"
-#include "net/log/net_log_source_type.h"
-#include "net/log/net_log_with_source.h"
 #include "net/url_request/url_request_context.h"
 #include "storage/browser/blob/blob_url_request_job_factory.h"
 #include "url/origin.h"
@@ -103,7 +101,7 @@
     base::WeakPtr<DownloadManagerImpl> download_manager) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   std::unique_ptr<DownloadCreateInfo> failed_created_info(
-      new DownloadCreateInfo(base::Time::Now(), net::NetLogWithSource(),
+      new DownloadCreateInfo(base::Time::Now(),
                              base::WrapUnique(new DownloadSaveInfo)));
   failed_created_info->url_chain.push_back(params->url());
   failed_created_info->result = reason;
@@ -244,22 +242,20 @@
       bool opened,
       base::Time last_access_time,
       bool transient,
-      const std::vector<DownloadItem::ReceivedSlice>& received_slices,
-      const net::NetLogWithSource& net_log) override {
+      const std::vector<DownloadItem::ReceivedSlice>& received_slices)
+      override {
     return new DownloadItemImpl(
         delegate, guid, download_id, current_path, target_path, url_chain,
         referrer_url, site_url, tab_url, tab_refererr_url, mime_type,
         original_mime_type, start_time, end_time, etag, last_modified,
         received_bytes, total_bytes, hash, state, danger_type, interrupt_reason,
-        opened, last_access_time, transient, received_slices, net_log);
+        opened, last_access_time, transient, received_slices);
   }
 
-  DownloadItemImpl* CreateActiveItem(
-      DownloadItemImplDelegate* delegate,
-      uint32_t download_id,
-      const DownloadCreateInfo& info,
-      const net::NetLogWithSource& net_log) override {
-    return new DownloadItemImpl(delegate, download_id, info, net_log);
+  DownloadItemImpl* CreateActiveItem(DownloadItemImplDelegate* delegate,
+                                     uint32_t download_id,
+                                     const DownloadCreateInfo& info) override {
+    return new DownloadItemImpl(delegate, download_id, info);
   }
 
   DownloadItemImpl* CreateSavePageItem(
@@ -268,10 +264,9 @@
       const base::FilePath& path,
       const GURL& url,
       const std::string& mime_type,
-      std::unique_ptr<DownloadRequestHandleInterface> request_handle,
-      const net::NetLogWithSource& net_log) override {
+      std::unique_ptr<DownloadRequestHandleInterface> request_handle) override {
     return new DownloadItemImpl(delegate, download_id, path, url, mime_type,
-                                std::move(request_handle), net_log);
+                                std::move(request_handle));
   }
 };
 
@@ -291,7 +286,6 @@
       initialized_(false),
       browser_context_(browser_context),
       delegate_(nullptr),
-      net_log_(nullptr),
       weak_factory_(this) {
   DCHECK(browser_context);
 }
@@ -305,10 +299,7 @@
     const DownloadCreateInfo& info) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!base::ContainsKey(downloads_, id));
-  net::NetLogWithSource net_log =
-      net::NetLogWithSource::Make(net_log_, net::NetLogSourceType::DOWNLOAD);
-  DownloadItemImpl* download =
-      item_factory_->CreateActiveItem(this, id, info, net_log);
+  DownloadItemImpl* download = item_factory_->CreateActiveItem(this, id, info);
   downloads_[id] = base::WrapUnique(download);
   downloads_by_guid_[download->GetGuid()] = download;
   return download;
@@ -488,8 +479,7 @@
     DCHECK(stream.get());
     download_file.reset(file_factory_->CreateFile(
         std::move(info->save_info), default_download_directory,
-        std::move(stream), download->GetNetLogWithSource(),
-        download->DestinationObserverAsWeakPtr()));
+        std::move(stream), id, download->DestinationObserverAsWeakPtr()));
   }
   // It is important to leave info->save_info intact in the case of an interrupt
   // so that the DownloadItem can salvage what it can out of a failed resumption
@@ -574,11 +564,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_NE(content::DownloadItem::kInvalidId, id);
   DCHECK(!base::ContainsKey(downloads_, id));
-  net::NetLogWithSource net_log =
-      net::NetLogWithSource::Make(net_log_, net::NetLogSourceType::DOWNLOAD);
   DownloadItemImpl* download_item = item_factory_->CreateSavePageItem(
-      this, id, main_file_path, page_url, mime_type, std::move(request_handle),
-      net_log);
+      this, id, main_file_path, page_url, mime_type, std::move(request_handle));
   downloads_[download_item->GetId()] = base::WrapUnique(download_item);
   DCHECK(!base::ContainsKey(downloads_by_guid_, download_item->GetGuid()));
   downloads_by_guid_[download_item->GetGuid()] = download_item;
@@ -773,8 +760,7 @@
       site_url, tab_url, tab_refererr_url, mime_type, original_mime_type,
       start_time, end_time, etag, last_modified, received_bytes, total_bytes,
       hash, state, danger_type, interrupt_reason, opened, last_access_time,
-      transient, received_slices,
-      net::NetLogWithSource::Make(net_log_, net::NetLogSourceType::DOWNLOAD));
+      transient, received_slices);
   downloads_[id] = base::WrapUnique(item);
   downloads_by_guid_[guid] = item;
   for (auto& observer : observers_)
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index ead13aa..368a104 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -30,10 +30,6 @@
 #include "content/public/browser/download_url_parameters.h"
 #include "content/public/browser/ssl_status.h"
 
-namespace net {
-class NetLog;
-}
-
 namespace content {
 class DownloadFileFactory;
 class DownloadItemFactory;
@@ -251,8 +247,6 @@
   // Allows an embedder to control behavior. Guaranteed to outlive this object.
   DownloadManagerDelegate* delegate_;
 
-  net::NetLog* net_log_;
-
   std::vector<UniqueUrlDownloadHandlerPtr> url_download_handlers_;
 
   base::WeakPtrFactory<DownloadManagerImpl> weak_factory_;
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index 01b76bd..c59f97f 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -40,7 +40,6 @@
 #include "content/public/test/mock_download_item.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "net/log/net_log_with_source.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gmock_mutant.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -154,21 +153,17 @@
       bool opened,
       base::Time last_access_time,
       bool transient,
-      const std::vector<DownloadItem::ReceivedSlice>& received_slices,
-      const net::NetLogWithSource& net_log) override;
-  DownloadItemImpl* CreateActiveItem(
-      DownloadItemImplDelegate* delegate,
-      uint32_t download_id,
-      const DownloadCreateInfo& info,
-      const net::NetLogWithSource& net_log) override;
+      const std::vector<DownloadItem::ReceivedSlice>& received_slices) override;
+  DownloadItemImpl* CreateActiveItem(DownloadItemImplDelegate* delegate,
+                                     uint32_t download_id,
+                                     const DownloadCreateInfo& info) override;
   DownloadItemImpl* CreateSavePageItem(
       DownloadItemImplDelegate* delegate,
       uint32_t download_id,
       const base::FilePath& path,
       const GURL& url,
       const std::string& mime_type,
-      std::unique_ptr<DownloadRequestHandleInterface> request_handle,
-      const net::NetLogWithSource& net_log) override;
+      std::unique_ptr<DownloadRequestHandleInterface> request_handle) override;
 
  private:
   std::map<uint32_t, MockDownloadItemImpl*> items_;
@@ -229,8 +224,7 @@
     bool opened,
     base::Time last_access_time,
     bool transient,
-    const std::vector<DownloadItem::ReceivedSlice>& received_slices,
-    const net::NetLogWithSource& net_log) {
+    const std::vector<DownloadItem::ReceivedSlice>& received_slices) {
   DCHECK(items_.find(download_id) == items_.end());
   MockDownloadItemImpl* result =
       new StrictMock<MockDownloadItemImpl>(&item_delegate_);
@@ -244,8 +238,7 @@
 DownloadItemImpl* MockDownloadItemFactory::CreateActiveItem(
     DownloadItemImplDelegate* delegate,
     uint32_t download_id,
-    const DownloadCreateInfo& info,
-    const net::NetLogWithSource& net_log) {
+    const DownloadCreateInfo& info) {
   DCHECK(items_.find(download_id) == items_.end());
 
   MockDownloadItemImpl* result =
@@ -269,8 +262,7 @@
     const base::FilePath& path,
     const GURL& url,
     const std::string& mime_type,
-    std::unique_ptr<DownloadRequestHandleInterface> request_handle,
-    const net::NetLogWithSource& net_log) {
+    std::unique_ptr<DownloadRequestHandleInterface> request_handle) {
   DCHECK(items_.find(download_id) == items_.end());
 
   MockDownloadItemImpl* result =
@@ -298,7 +290,7 @@
       std::unique_ptr<DownloadSaveInfo> save_info,
       const base::FilePath& default_download_directory,
       std::unique_ptr<DownloadManager::InputStream> stream,
-      const net::NetLogWithSource& net_log,
+      uint32_t download_id,
       base::WeakPtr<DownloadDestinationObserver> observer) override {
     return MockCreateFile(*save_info, stream.get());
   }
diff --git a/content/browser/download/download_net_log_parameters.cc b/content/browser/download/download_net_log_parameters.cc
deleted file mode 100644
index d74de475..0000000
--- a/content/browser/download/download_net_log_parameters.cc
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/download/download_net_log_parameters.h"
-
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/values.h"
-#include "content/public/browser/download_interrupt_reasons.h"
-#include "net/base/net_errors.h"
-#include "net/log/net_log_capture_mode.h"
-#include "url/gurl.h"
-
-namespace content {
-
-namespace {
-
-static const char* const download_type_names[] = {
-  "NEW_DOWNLOAD",
-  "HISTORY_IMPORT",
-  "SAVE_PAGE_AS"
-};
-static const char* const download_danger_names[] = {
-  "NOT_DANGEROUS",
-  "DANGEROUS_FILE",
-  "DANGEROUS_URL",
-  "DANGEROUS_CONTENT",
-  "MAYBE_DANGEROUS_CONTENT",
-  "UNCOMMON_CONTENT",
-  "USER_VALIDATED",
-  "DANGEROUS_HOST",
-  "POTENTIALLY_UNWANTED"
-};
-
-static_assert(arraysize(download_type_names) == SRC_SAVE_PAGE_AS + 1,
-              "download type enum has changed");
-static_assert(arraysize(download_danger_names) == DOWNLOAD_DANGER_TYPE_MAX,
-              "download danger enum has changed");
-
-}  // namespace
-
-std::unique_ptr<base::Value> ItemActivatedNetLogCallback(
-    const DownloadItem* download_item,
-    DownloadType download_type,
-    const std::string* file_name,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("type", download_type_names[download_type]);
-  dict->SetString("id", base::UintToString(download_item->GetId()));
-  dict->SetString("original_url", download_item->GetOriginalUrl().spec());
-  dict->SetString("final_url", download_item->GetURL().spec());
-  dict->SetString("file_name", *file_name);
-  dict->SetString("danger_type",
-                  download_danger_names[download_item->GetDangerType()]);
-  dict->SetString("start_offset",
-                  base::Int64ToString(download_item->GetReceivedBytes()));
-  dict->SetBoolean("has_user_gesture", download_item->HasUserGesture());
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> ItemCheckedNetLogCallback(
-    DownloadDangerType danger_type,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("danger_type", download_danger_names[danger_type]);
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> ItemRenamedNetLogCallback(
-    const base::FilePath* old_filename,
-    const base::FilePath* new_filename,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("old_filename", old_filename->AsUTF8Unsafe());
-  dict->SetString("new_filename", new_filename->AsUTF8Unsafe());
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> ItemInterruptedNetLogCallback(
-    DownloadInterruptReason reason,
-    int64_t bytes_so_far,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("interrupt_reason", DownloadInterruptReasonToString(reason));
-  dict->SetString("bytes_so_far", base::Int64ToString(bytes_so_far));
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> ItemResumingNetLogCallback(
-    bool user_initiated,
-    DownloadInterruptReason reason,
-    int64_t bytes_so_far,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("user_initiated", user_initiated ? "true" : "false");
-  dict->SetString("interrupt_reason", DownloadInterruptReasonToString(reason));
-  dict->SetString("bytes_so_far", base::Int64ToString(bytes_so_far));
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> ItemCompletingNetLogCallback(
-    int64_t bytes_so_far,
-    const std::string* final_hash,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("bytes_so_far", base::Int64ToString(bytes_so_far));
-  dict->SetString("final_hash",
-                  base::HexEncode(final_hash->data(), final_hash->size()));
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> ItemFinishedNetLogCallback(
-    bool auto_opened,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("auto_opened", auto_opened ? "yes" : "no");
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> ItemCanceledNetLogCallback(
-    int64_t bytes_so_far,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("bytes_so_far", base::Int64ToString(bytes_so_far));
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> FileOpenedNetLogCallback(
-    const base::FilePath* file_name,
-    int64_t start_offset,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("file_name", file_name->AsUTF8Unsafe());
-  dict->SetString("start_offset", base::Int64ToString(start_offset));
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> FileStreamDrainedNetLogCallback(
-    size_t stream_size,
-    size_t num_buffers,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetInteger("stream_size", static_cast<int>(stream_size));
-  dict->SetInteger("num_buffers", static_cast<int>(num_buffers));
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> FileRenamedNetLogCallback(
-    const base::FilePath* old_filename,
-    const base::FilePath* new_filename,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("old_filename", old_filename->AsUTF8Unsafe());
-  dict->SetString("new_filename", new_filename->AsUTF8Unsafe());
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> FileErrorNetLogCallback(
-    const char* operation,
-    net::Error net_error,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("operation", operation);
-  dict->SetInteger("net_error", net_error);
-
-  return std::move(dict);
-}
-
-std::unique_ptr<base::Value> FileInterruptedNetLogCallback(
-    const char* operation,
-    int os_error,
-    DownloadInterruptReason reason,
-    net::NetLogCaptureMode capture_mode) {
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-  dict->SetString("operation", operation);
-  if (os_error != 0)
-    dict->SetInteger("os_error", os_error);
-  dict->SetString("interrupt_reason", DownloadInterruptReasonToString(reason));
-
-  return std::move(dict);
-}
-
-}  // namespace content
diff --git a/content/browser/download/download_net_log_parameters.h b/content/browser/download/download_net_log_parameters.h
deleted file mode 100644
index 0e816b3..0000000
--- a/content/browser/download/download_net_log_parameters.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_NET_LOG_PARAMETERS_H_
-#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_NET_LOG_PARAMETERS_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "content/public/browser/download_item.h"
-#include "net/base/net_errors.h"
-
-namespace base {
-class FilePath;
-class Value;
-}
-
-namespace net {
-class NetLogCaptureMode;
-}
-
-namespace content {
-
-enum DownloadType {
-  SRC_ACTIVE_DOWNLOAD,
-  SRC_HISTORY_IMPORT,
-  SRC_SAVE_PAGE_AS
-};
-
-// Returns NetLog parameters when a DownloadItem is activated.
-std::unique_ptr<base::Value> ItemActivatedNetLogCallback(
-    const DownloadItem* download_item,
-    DownloadType download_type,
-    const std::string* file_name,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a DownloadItem is checked for danger.
-std::unique_ptr<base::Value> ItemCheckedNetLogCallback(
-    DownloadDangerType danger_type,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a DownloadItem is renamed.
-std::unique_ptr<base::Value> ItemRenamedNetLogCallback(
-    const base::FilePath* old_filename,
-    const base::FilePath* new_filename,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a DownloadItem is interrupted.
-std::unique_ptr<base::Value> ItemInterruptedNetLogCallback(
-    DownloadInterruptReason reason,
-    int64_t bytes_so_far,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a DownloadItem is resumed.
-std::unique_ptr<base::Value> ItemResumingNetLogCallback(
-    bool user_initiated,
-    DownloadInterruptReason reason,
-    int64_t bytes_so_far,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a DownloadItem is completing.
-std::unique_ptr<base::Value> ItemCompletingNetLogCallback(
-    int64_t bytes_so_far,
-    const std::string* final_hash,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a DownloadItem is finished.
-std::unique_ptr<base::Value> ItemFinishedNetLogCallback(
-    bool auto_opened,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a DownloadItem is canceled.
-std::unique_ptr<base::Value> ItemCanceledNetLogCallback(
-    int64_t bytes_so_far,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a DownloadFile is opened.
-std::unique_ptr<base::Value> FileOpenedNetLogCallback(
-    const base::FilePath* file_name,
-    int64_t start_offset,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a DownloadFile is opened.
-std::unique_ptr<base::Value> FileStreamDrainedNetLogCallback(
-    size_t stream_size,
-    size_t num_buffers,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a DownloadFile is renamed.
-std::unique_ptr<base::Value> FileRenamedNetLogCallback(
-    const base::FilePath* old_filename,
-    const base::FilePath* new_filename,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters when a File has an error.
-std::unique_ptr<base::Value> FileErrorNetLogCallback(
-    const char* operation,
-    net::Error net_error,
-    net::NetLogCaptureMode capture_mode);
-
-// Returns NetLog parameters for a download interruption.
-std::unique_ptr<base::Value> FileInterruptedNetLogCallback(
-    const char* operation,
-    int os_error,
-    DownloadInterruptReason reason,
-    net::NetLogCaptureMode capture_mode);
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_NET_LOG_PARAMETERS_H_
diff --git a/content/browser/download/download_request_core.cc b/content/browser/download/download_request_core.cc
index f11f2e1d..1f4ff5b0 100644
--- a/content/browser/download/download_request_core.cc
+++ b/content/browser/download/download_request_core.cc
@@ -190,8 +190,8 @@
 DownloadRequestCore::CreateDownloadCreateInfo(DownloadInterruptReason result) {
   DCHECK(!started_);
   started_ = true;
-  std::unique_ptr<DownloadCreateInfo> create_info(new DownloadCreateInfo(
-      base::Time::Now(), request()->net_log(), std::move(save_info_)));
+  std::unique_ptr<DownloadCreateInfo> create_info(
+      new DownloadCreateInfo(base::Time::Now(), std::move(save_info_)));
 
   if (result == DOWNLOAD_INTERRUPT_REASON_NONE)
     create_info->remote_address = request()->GetSocketAddress().host();
diff --git a/content/browser/download/download_response_handler.cc b/content/browser/download/download_response_handler.cc
index 2d982c9..7879b771 100644
--- a/content/browser/download/download_response_handler.cc
+++ b/content/browser/download/download_response_handler.cc
@@ -107,8 +107,8 @@
     const ResourceResponseHead& head) {
   // TODO(qinmin): instead of using NetLogWithSource, introduce new logging
   // class for download.
-  auto create_info = std::make_unique<DownloadCreateInfo>(
-      base::Time::Now(), net::NetLogWithSource(), std::move(save_info_));
+  auto create_info = base::MakeUnique<DownloadCreateInfo>(
+      base::Time::Now(), std::move(save_info_));
 
   DownloadInterruptReason result =
       head.headers
diff --git a/content/browser/download/mock_download_item_impl.cc b/content/browser/download/mock_download_item_impl.cc
index 37a92c9..ab1eb1f 100644
--- a/content/browser/download/mock_download_item_impl.cc
+++ b/content/browser/download/mock_download_item_impl.cc
@@ -32,8 +32,7 @@
                        false,
                        base::Time(),
                        true,
-                       DownloadItem::ReceivedSlices(),
-                       net::NetLogWithSource()) {}
+                       DownloadItem::ReceivedSlices()) {}
 
 MockDownloadItemImpl::~MockDownloadItemImpl() = default;
 
diff --git a/content/browser/download/parallel_download_job_unittest.cc b/content/browser/download/parallel_download_job_unittest.cc
index 3c5a172..1ce7294b 100644
--- a/content/browser/download/parallel_download_job_unittest.cc
+++ b/content/browser/download/parallel_download_job_unittest.cc
@@ -452,7 +452,7 @@
       std::move(save_info), base::FilePath(),
       std::make_unique<DownloadManager::InputStream>(
           std::unique_ptr<ByteStreamReader>(input_stream)),
-      net::NetLogWithSource(), observer_factory.GetWeakPtr());
+      DownloadItem::kInvalidId, observer_factory.GetWeakPtr());
   CreateParallelJob(0, 100, DownloadItem::ReceivedSlices(), 2, 0, 0);
   job_->Start(download_file.get(),
               base::Bind(&ParallelDownloadJobTest::OnFileInitialized,
diff --git a/content/browser/download/save_file.cc b/content/browser/download/save_file.cc
index a9b0aae..ac029b17 100644
--- a/content/browser/download/save_file.cc
+++ b/content/browser/download/save_file.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "content/browser/download/download_task_runner.h"
-#include "net/log/net_log_with_source.h"
+#include "content/public/browser/download_item.h"
 
 namespace content {
 
@@ -15,7 +15,7 @@
 //               Unfortunately, as it is, constructors of SaveFile don't always
 //               have access to the SavePackage at this point.
 SaveFile::SaveFile(const SaveFileCreateInfo* info, bool calculate_hash)
-    : file_(net::NetLogWithSource()), info_(info) {
+    : file_(DownloadItem::kInvalidId), info_(info) {
   DCHECK(GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
 
   DCHECK(info);
diff --git a/content/browser/gpu/gpu_data_manager_impl.cc b/content/browser/gpu/gpu_data_manager_impl.cc
index 5a3d62c..fc442119 100644
--- a/content/browser/gpu/gpu_data_manager_impl.cc
+++ b/content/browser/gpu/gpu_data_manager_impl.cc
@@ -165,11 +165,6 @@
          private_->GpuAccessAllowed(nullptr);
 }
 
-bool GpuDataManagerImpl::CanUseGpuBrowserCompositor() const {
-  base::AutoLock auto_lock(lock_);
-  return private_->CanUseGpuBrowserCompositor();
-}
-
 void GpuDataManagerImpl::GetDisabledExtensions(
     std::string* disabled_extensions) const {
   base::AutoLock auto_lock(lock_);
diff --git a/content/browser/gpu/gpu_data_manager_impl.h b/content/browser/gpu/gpu_data_manager_impl.h
index ebaf2b9..6f81e672 100644
--- a/content/browser/gpu/gpu_data_manager_impl.h
+++ b/content/browser/gpu/gpu_data_manager_impl.h
@@ -95,7 +95,6 @@
                     std::string* gl_version) override;
   void DisableHardwareAcceleration() override;
   bool HardwareAccelerationEnabled() const override;
-  bool CanUseGpuBrowserCompositor() const override;
   void GetDisabledExtensions(std::string* disabled_extensions) const override;
   void SetGpuInfo(const gpu::GPUInfo& gpu_info) override;
 
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index 571ff80..47d2eeb 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -803,16 +803,12 @@
 void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
     WebPreferences* prefs) const {
   DCHECK(prefs);
-
-#if defined(USE_AURA)
-  if (!CanUseGpuBrowserCompositor()) {
-    prefs->accelerated_2d_canvas_enabled = false;
-    prefs->pepper_3d_enabled = false;
-  }
-#endif
-
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
+  // TODO(zmo): Remove this when we check on the renderer side for 2d canvas.
+  if (command_line->HasSwitch(switches::kDisableGpuCompositing)) {
+    prefs->accelerated_2d_canvas_enabled = false;
+  }
   if (!ShouldDisableAcceleratedVideoDecode(command_line) &&
       !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
     prefs->pepper_accelerated_video_decode_enabled = true;
@@ -961,17 +957,6 @@
   return true;
 }
 
-bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableGpuCompositing))
-    return false;
-  if (ShouldUseSwiftShader())
-    return false;
-  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING))
-    return false;
-  return true;
-}
-
 bool GpuDataManagerImplPrivate::ShouldDisableAcceleratedVideoDecode(
     const base::CommandLine* command_line) const {
   if (command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.h b/content/browser/gpu/gpu_data_manager_impl_private.h
index 8862506d..369d07b0 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.h
+++ b/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -95,7 +95,6 @@
 
   void HandleGpuSwitch();
 
-  bool CanUseGpuBrowserCompositor() const;
   bool ShouldDisableAcceleratedVideoDecode(
       const base::CommandLine* command_line) const;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
index a74b7bc2..62e8d99a 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -17,7 +17,6 @@
 #include "build/build_config.h"
 #include "cc/paint/skia_paint_canvas.h"
 #include "content/browser/gpu/compositor_util.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/renderer_host/dip_util.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
@@ -677,14 +676,11 @@
                        run_loop.QuitClosure());
         rwhv->CopyFromSurfaceToVideoFrame(copy_rect, video_frame, callback);
       } else {
-        if (!content::GpuDataManager::GetInstance()
-                 ->CanUseGpuBrowserCompositor()) {
-          // Skia rendering can cause color differences, particularly in the
-          // middle two columns.
-          SetAllowableError(2);
-          SetExcludeRect(gfx::Rect(output_size.width() / 2 - 1, 0, 2,
-                                   output_size.height()));
-        }
+        // Skia rendering can cause color differences, particularly in the
+        // middle two columns.
+        SetAllowableError(2);
+        SetExcludeRect(
+            gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height()));
 
         const ReadbackRequestCallback callback =
             base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
diff --git a/content/browser/service_worker/service_worker_consts.cc b/content/browser/service_worker/service_worker_consts.cc
new file mode 100644
index 0000000..0a6663f
--- /dev/null
+++ b/content/browser/service_worker/service_worker_consts.cc
@@ -0,0 +1,52 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/service_worker/service_worker_consts.h"
+
+namespace content {
+
+const char ServiceWorkerConsts::kBadMessageFromNonWindow[] =
+    "The request message should not come from a non-window client.";
+
+const char ServiceWorkerConsts::kBadMessageGetRegistrationForReadyDuplicated[] =
+    "There's already a completed or ongoing request to get the ready "
+    "registration.";
+
+const char ServiceWorkerConsts::kBadMessageImproperOrigins[] =
+    "Origins are not matching, or some cannot access service worker.";
+
+const char ServiceWorkerConsts::kBadMessageInvalidURL[] =
+    "Some URLs are invalid.";
+
+const char ServiceWorkerConsts::kBadNavigationPreloadHeaderValue[] =
+    "The navigation preload header value is invalid.";
+
+const char ServiceWorkerConsts::kDatabaseErrorMessage[] =
+    "Failed to access storage.";
+
+const char ServiceWorkerConsts::kEnableNavigationPreloadErrorPrefix[] =
+    "Failed to enable or disable navigation preload: ";
+
+const char ServiceWorkerConsts::kGetNavigationPreloadStateErrorPrefix[] =
+    "Failed to get navigation preload state: ";
+
+const char ServiceWorkerConsts::kInvalidStateErrorMessage[] =
+    "The object is in an invalid state.";
+
+const char ServiceWorkerConsts::kNoActiveWorkerErrorMessage[] =
+    "The registration does not have an active worker.";
+
+const char ServiceWorkerConsts::kNoDocumentURLErrorMessage[] =
+    "No URL is associated with the caller's document.";
+
+const char ServiceWorkerConsts::kSetNavigationPreloadHeaderErrorPrefix[] =
+    "Failed to set navigation preload header: ";
+
+const char ServiceWorkerConsts::kShutdownErrorMessage[] =
+    "The Service Worker system has shutdown.";
+
+const char ServiceWorkerConsts::kUserDeniedPermissionMessage[] =
+    "The user denied permission to use Service Worker.";
+
+}  // namespace content
diff --git a/content/browser/service_worker/service_worker_consts.h b/content/browser/service_worker/service_worker_consts.h
new file mode 100644
index 0000000..d119a47
--- /dev/null
+++ b/content/browser/service_worker/service_worker_consts.h
@@ -0,0 +1,29 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONSTS_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONSTS_H_
+
+namespace content {
+
+struct ServiceWorkerConsts {
+  static const char kBadMessageFromNonWindow[];
+  static const char kBadMessageGetRegistrationForReadyDuplicated[];
+  static const char kBadMessageImproperOrigins[];
+  static const char kBadMessageInvalidURL[];
+  static const char kBadNavigationPreloadHeaderValue[];
+  static const char kDatabaseErrorMessage[];
+  static const char kEnableNavigationPreloadErrorPrefix[];
+  static const char kGetNavigationPreloadStateErrorPrefix[];
+  static const char kInvalidStateErrorMessage[];
+  static const char kNoActiveWorkerErrorMessage[];
+  static const char kNoDocumentURLErrorMessage[];
+  static const char kSetNavigationPreloadHeaderErrorPrefix[];
+  static const char kShutdownErrorMessage[];
+  static const char kUserDeniedPermissionMessage[];
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONSTS_H_
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index c3f8407..ba845718 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -15,6 +15,7 @@
 #include "content/browser/bad_message.h"
 #include "content/browser/interface_provider_filtering.h"
 #include "content/browser/service_worker/embedded_worker_status.h"
+#include "content/browser/service_worker/service_worker_consts.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_context_request_handler.h"
 #include "content/browser/service_worker/service_worker_controllee_request_handler.h"
@@ -48,21 +49,6 @@
 
 namespace {
 
-const char kNoDocumentURLErrorMessage[] =
-    "No URL is associated with the caller's document.";
-const char kShutdownErrorMessage[] = "The Service Worker system has shutdown.";
-const char kUserDeniedPermissionMessage[] =
-    "The user denied permission to use Service Worker.";
-
-const char kBadMessageInvalidURL[] = "Some URLs are invalid.";
-const char kBadMessageInproperOrigins[] =
-    "Origins are not matching, or some cannot access service worker.";
-const char kBadMessageFromNonWindow[] =
-    "The request message should not come from a non-window client.";
-const char kBadMessageGetRegistrationForReadyDuplicated[] =
-    "There's already a completed or ongoing request to get the ready "
-    "registration.";
-
 // Provider host for navigation with PlzNavigate or when service worker's
 // context is created on the browser side. This function provides the next
 // ServiceWorkerProviderHost ID for them, starts at -2 and keeps going down.
@@ -928,10 +914,11 @@
                          trace_id, "Status", status, "Registration ID",
                          registration_id);
   if (!dispatcher_host_ || !IsContextAlive()) {
-    std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kAbort,
-                            std::string(kServiceWorkerRegisterErrorPrefix) +
-                                std::string(kShutdownErrorMessage),
-                            nullptr);
+    std::move(callback).Run(
+        blink::mojom::ServiceWorkerErrorType::kAbort,
+        std::string(kServiceWorkerRegisterErrorPrefix) +
+            std::string(ServiceWorkerConsts::kShutdownErrorMessage),
+        nullptr);
     return;
   }
 
@@ -1027,7 +1014,7 @@
     std::move(callback).Run(
         blink::mojom::ServiceWorkerErrorType::kAbort,
         std::string(kServiceWorkerGetRegistrationErrorPrefix) +
-            std::string(kShutdownErrorMessage),
+            std::string(ServiceWorkerConsts::kShutdownErrorMessage),
         nullptr);
     return;
   }
@@ -1065,7 +1052,7 @@
     std::move(callback).Run(
         blink::mojom::ServiceWorkerErrorType::kAbort,
         std::string(kServiceWorkerGetRegistrationsErrorPrefix) +
-            std::string(kShutdownErrorMessage),
+            std::string(ServiceWorkerConsts::kShutdownErrorMessage),
         base::nullopt);
     return;
   }
@@ -1142,11 +1129,11 @@
     const blink::mojom::ServiceWorkerRegistrationOptions& options,
     std::string* out_error) const {
   if (client_type() != blink::kWebServiceWorkerClientTypeWindow) {
-    *out_error = kBadMessageFromNonWindow;
+    *out_error = ServiceWorkerConsts::kBadMessageFromNonWindow;
     return false;
   }
   if (!options.scope.is_valid() || !script_url.is_valid()) {
-    *out_error = kBadMessageInvalidURL;
+    *out_error = ServiceWorkerConsts::kBadMessageInvalidURL;
     return false;
   }
   if (ServiceWorkerUtils::ContainsDisallowedCharacter(options.scope, script_url,
@@ -1155,7 +1142,7 @@
   }
   std::vector<GURL> urls = {document_url(), options.scope, script_url};
   if (!ServiceWorkerUtils::AllOriginsMatchAndCanAccessServiceWorkers(urls)) {
-    *out_error = kBadMessageInproperOrigins;
+    *out_error = ServiceWorkerConsts::kBadMessageImproperOrigins;
     return false;
   }
 
@@ -1166,16 +1153,16 @@
     const GURL& client_url,
     std::string* out_error) const {
   if (client_type() != blink::kWebServiceWorkerClientTypeWindow) {
-    *out_error = kBadMessageFromNonWindow;
+    *out_error = ServiceWorkerConsts::kBadMessageFromNonWindow;
     return false;
   }
   if (!client_url.is_valid()) {
-    *out_error = kBadMessageInvalidURL;
+    *out_error = ServiceWorkerConsts::kBadMessageInvalidURL;
     return false;
   }
   std::vector<GURL> urls = {document_url(), client_url};
   if (!ServiceWorkerUtils::AllOriginsMatchAndCanAccessServiceWorkers(urls)) {
-    *out_error = kBadMessageInproperOrigins;
+    *out_error = ServiceWorkerConsts::kBadMessageImproperOrigins;
     return false;
   }
 
@@ -1185,11 +1172,11 @@
 bool ServiceWorkerProviderHost::IsValidGetRegistrationsMessage(
     std::string* out_error) const {
   if (client_type() != blink::kWebServiceWorkerClientTypeWindow) {
-    *out_error = kBadMessageFromNonWindow;
+    *out_error = ServiceWorkerConsts::kBadMessageFromNonWindow;
     return false;
   }
   if (!OriginCanAccessServiceWorkers(document_url())) {
-    *out_error = kBadMessageInproperOrigins;
+    *out_error = ServiceWorkerConsts::kBadMessageImproperOrigins;
     return false;
   }
 
@@ -1199,12 +1186,13 @@
 bool ServiceWorkerProviderHost::IsValidGetRegistrationForReadyMessage(
     std::string* out_error) const {
   if (client_type() != blink::kWebServiceWorkerClientTypeWindow) {
-    *out_error = kBadMessageFromNonWindow;
+    *out_error = ServiceWorkerConsts::kBadMessageFromNonWindow;
     return false;
   }
 
   if (get_ready_callback_) {
-    *out_error = kBadMessageGetRegistrationForReadyDuplicated;
+    *out_error =
+        ServiceWorkerConsts::kBadMessageGetRegistrationForReadyDuplicated;
     return false;
   }
 
@@ -1233,7 +1221,8 @@
   if (!dispatcher_host_ || !IsContextAlive()) {
     std::move(*callback).Run(
         blink::mojom::ServiceWorkerErrorType::kAbort,
-        std::string(error_prefix) + std::string(kShutdownErrorMessage),
+        std::string(error_prefix) +
+            std::string(ServiceWorkerConsts::kShutdownErrorMessage),
         args...);
     return false;
   }
@@ -1243,7 +1232,8 @@
   if (document_url().is_empty()) {
     std::move(*callback).Run(
         blink::mojom::ServiceWorkerErrorType::kSecurity,
-        std::string(error_prefix) + std::string(kNoDocumentURLErrorMessage),
+        std::string(error_prefix) +
+            std::string(ServiceWorkerConsts::kNoDocumentURLErrorMessage),
         args...);
     return false;
   }
@@ -1253,7 +1243,8 @@
           base::Bind(&GetWebContents, render_process_id_, frame_id()))) {
     std::move(*callback).Run(
         blink::mojom::ServiceWorkerErrorType::kDisabled,
-        std::string(error_prefix) + std::string(kUserDeniedPermissionMessage),
+        std::string(error_prefix) +
+            std::string(ServiceWorkerConsts::kUserDeniedPermissionMessage),
         args...);
     return false;
   }
diff --git a/content/browser/service_worker/service_worker_registration_handle.cc b/content/browser/service_worker/service_worker_registration_handle.cc
index 0e5abd8c..5da1553 100644
--- a/content/browser/service_worker/service_worker_registration_handle.cc
+++ b/content/browser/service_worker/service_worker_registration_handle.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/service_worker/service_worker_registration_handle.h"
 
+#include "content/browser/service_worker/service_worker_consts.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_dispatcher_host.h"
 #include "content/browser/service_worker/service_worker_handle.h"
@@ -23,26 +24,6 @@
 
 namespace {
 
-const char kNoDocumentURLErrorMessage[] =
-    "No URL is associated with the caller's document.";
-const char kShutdownErrorMessage[] = "The Service Worker system has shutdown.";
-const char kUserDeniedPermissionMessage[] =
-    "The user denied permission to use Service Worker.";
-const char kEnableNavigationPreloadErrorPrefix[] =
-    "Failed to enable or disable navigation preload: ";
-const char kGetNavigationPreloadStateErrorPrefix[] =
-    "Failed to get navigation preload state: ";
-const char kSetNavigationPreloadHeaderErrorPrefix[] =
-    "Failed to set navigation preload header: ";
-const char kInvalidStateErrorMessage[] = "The object is in an invalid state.";
-const char kBadMessageImproperOrigins[] =
-    "Origins are not matching, or some cannot access service worker.";
-const char kBadNavigationPreloadHeaderValue[] =
-    "The navigation preload header value is invalid.";
-const char kNoActiveWorkerErrorMessage[] =
-    "The registration does not have an active worker.";
-const char kDatabaseErrorMessage[] = "Failed to access storage.";
-
 WebContents* GetWebContents(int render_process_id, int render_frame_id) {
   RenderFrameHost* rfh =
       RenderFrameHost::FromID(render_process_id, render_frame_id);
@@ -137,9 +118,10 @@
   if (!registration_->GetNewestVersion()) {
     // This can happen if update() is called during initial script evaluation.
     // Abort the following steps according to the spec.
-    std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kState,
-                            std::string(kServiceWorkerUpdateErrorPrefix) +
-                                std::string(kInvalidStateErrorMessage));
+    std::move(callback).Run(
+        blink::mojom::ServiceWorkerErrorType::kState,
+        std::string(kServiceWorkerUpdateErrorPrefix) +
+            std::string(ServiceWorkerConsts::kInvalidStateErrorMessage));
     return;
   }
 
@@ -168,14 +150,16 @@
     bool enable,
     EnableNavigationPreloadCallback callback) {
   if (!CanServeRegistrationObjectHostMethods(
-          &callback, kEnableNavigationPreloadErrorPrefix)) {
+          &callback,
+          ServiceWorkerConsts::kEnableNavigationPreloadErrorPrefix)) {
     return;
   }
 
   if (!registration_->active_version()) {
-    std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kState,
-                            std::string(kEnableNavigationPreloadErrorPrefix) +
-                                std::string(kNoActiveWorkerErrorMessage));
+    std::move(callback).Run(
+        blink::mojom::ServiceWorkerErrorType::kState,
+        std::string(ServiceWorkerConsts::kEnableNavigationPreloadErrorPrefix) +
+            std::string(ServiceWorkerConsts::kNoActiveWorkerErrorMessage));
     return;
   }
 
@@ -189,7 +173,8 @@
 void ServiceWorkerRegistrationHandle::GetNavigationPreloadState(
     GetNavigationPreloadStateCallback callback) {
   if (!CanServeRegistrationObjectHostMethods(
-          &callback, kGetNavigationPreloadStateErrorPrefix, nullptr)) {
+          &callback, ServiceWorkerConsts::kGetNavigationPreloadStateErrorPrefix,
+          nullptr)) {
     return;
   }
 
@@ -202,22 +187,25 @@
     const std::string& value,
     SetNavigationPreloadHeaderCallback callback) {
   if (!CanServeRegistrationObjectHostMethods(
-          &callback, kSetNavigationPreloadHeaderErrorPrefix)) {
+          &callback,
+          ServiceWorkerConsts::kSetNavigationPreloadHeaderErrorPrefix)) {
     return;
   }
 
   if (!registration_->active_version()) {
     std::move(callback).Run(
         blink::mojom::ServiceWorkerErrorType::kState,
-        std::string(kSetNavigationPreloadHeaderErrorPrefix) +
-            std::string(kNoActiveWorkerErrorMessage));
+        std::string(
+            ServiceWorkerConsts::kSetNavigationPreloadHeaderErrorPrefix) +
+            std::string(ServiceWorkerConsts::kNoActiveWorkerErrorMessage));
     return;
   }
 
   // TODO(falken): Ideally this would match Blink's isValidHTTPHeaderValue.
   // Chrome's check is less restrictive: it allows non-latin1 characters.
   if (!net::HttpUtil::IsValidHeaderValue(value)) {
-    bindings_.ReportBadMessage(kBadNavigationPreloadHeaderValue);
+    bindings_.ReportBadMessage(
+        ServiceWorkerConsts::kBadNavigationPreloadHeaderValue);
     return;
   }
 
@@ -269,9 +257,10 @@
     EnableNavigationPreloadCallback callback,
     ServiceWorkerStatusCode status) {
   if (status != SERVICE_WORKER_OK) {
-    std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kUnknown,
-                            std::string(kEnableNavigationPreloadErrorPrefix) +
-                                std::string(kDatabaseErrorMessage));
+    std::move(callback).Run(
+        blink::mojom::ServiceWorkerErrorType::kUnknown,
+        std::string(ServiceWorkerConsts::kEnableNavigationPreloadErrorPrefix) +
+            std::string(ServiceWorkerConsts::kDatabaseErrorMessage));
     return;
   }
 
@@ -288,8 +277,9 @@
   if (status != SERVICE_WORKER_OK) {
     std::move(callback).Run(
         blink::mojom::ServiceWorkerErrorType::kUnknown,
-        std::string(kSetNavigationPreloadHeaderErrorPrefix) +
-            std::string(kDatabaseErrorMessage));
+        std::string(
+            ServiceWorkerConsts::kSetNavigationPreloadHeaderErrorPrefix) +
+            std::string(ServiceWorkerConsts::kDatabaseErrorMessage));
     return;
   }
 
@@ -342,7 +332,8 @@
   if (!provider_host_ || !context_) {
     std::move(*callback).Run(
         blink::mojom::ServiceWorkerErrorType::kAbort,
-        std::string(error_prefix) + std::string(kShutdownErrorMessage),
+        std::string(error_prefix) +
+            std::string(ServiceWorkerConsts::kShutdownErrorMessage),
         args...);
     return false;
   }
@@ -352,7 +343,8 @@
   if (provider_host_->document_url().is_empty()) {
     std::move(*callback).Run(
         blink::mojom::ServiceWorkerErrorType::kSecurity,
-        std::string(error_prefix) + std::string(kNoDocumentURLErrorMessage),
+        std::string(error_prefix) +
+            std::string(ServiceWorkerConsts::kNoDocumentURLErrorMessage),
         args...);
     return false;
   }
@@ -360,7 +352,7 @@
   std::vector<GURL> urls = {provider_host_->document_url(),
                             registration_->pattern()};
   if (!ServiceWorkerUtils::AllOriginsMatchAndCanAccessServiceWorkers(urls)) {
-    bindings_.ReportBadMessage(kBadMessageImproperOrigins);
+    bindings_.ReportBadMessage(ServiceWorkerConsts::kBadMessageImproperOrigins);
     return false;
   }
 
@@ -371,7 +363,8 @@
                      provider_host_->frame_id()))) {
     std::move(*callback).Run(
         blink::mojom::ServiceWorkerErrorType::kDisabled,
-        std::string(error_prefix) + std::string(kUserDeniedPermissionMessage),
+        std::string(error_prefix) +
+            std::string(ServiceWorkerConsts::kUserDeniedPermissionMessage),
         args...);
     return false;
   }
diff --git a/content/common/page_state.mojom b/content/common/page_state.mojom
index e6afdb43..f30a38c 100644
--- a/content/common/page_state.mojom
+++ b/content/common/page_state.mojom
@@ -29,7 +29,7 @@
 // compatibility. If re-ordering fields, make sure to retain the original
 // ordinal value.
 // Update the below value if your change introduces fields using it.
-// Next MinVersion: 1
+// Next MinVersion: 2
 
 // Next Ordinal: 4
 struct FileSystemFile {
@@ -77,14 +77,17 @@
   kManual = 1
 };
 
-// Next Ordinal: 3
+// Next Ordinal: 6
 struct ViewState {
   gfx.mojom.PointF visual_viewport_scroll_offset@0;
   gfx.mojom.Point scroll_offset@1;
   double page_scale_factor@2;
+  // Serialized scroll anchor fields
+  [MinVersion=1] mojo.common.mojom.String16? scroll_anchor_selector@3;
+  [MinVersion=1] gfx.mojom.PointF? scroll_anchor_offset@4;
+  [MinVersion=1] uint64 scroll_anchor_simhash@5 = 0;
 };
 
-// Next Ordinal: 12
 struct FrameState {
   mojo.common.mojom.String16? url_string@0;
   mojo.common.mojom.String16? referrer@1;
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc
index a2ec09f..0e04469 100644
--- a/content/common/page_state_serialization.cc
+++ b/content/common/page_state_serialization.cc
@@ -4,8 +4,6 @@
 
 #include "content/common/page_state_serialization.h"
 
-#include <stddef.h>
-
 #include <algorithm>
 #include <limits>
 
@@ -220,7 +218,7 @@
 // 24: Add did save scroll or scale state.
 // 25: Limit the length of unique names: https://crbug.com/626202
 // 26: Switch to mojo-based serialization.
-//
+// 27: Add serialized scroll anchor to FrameState.
 // NOTE: If the version is -1, then the pickle contains only a URL string.
 // See ReadPageState.
 //
@@ -228,7 +226,7 @@
 // NOTE: When changing the version, please add a backwards compatibility test.
 // See PageStateSerializationTest.DumpExpectedPageStateForBackwardsCompat for
 // instructions on how to generate the new test case.
-const int kCurrentVersion = 26;
+const int kCurrentVersion = 27;
 
 // A bunch of convenience functions to write to/read from SerializeObjects.  The
 // de-serializers assume the input data will be in the correct format and fall
@@ -833,6 +831,15 @@
     frame->view_state->visual_viewport_scroll_offset =
         state.visual_viewport_scroll_offset;
     frame->view_state->page_scale_factor = state.page_scale_factor;
+    // We discard all scroll anchor data if the selector is over the length
+    // limit. We don't want to bloat the size of FrameState, and the other
+    // fields are useless without the selector.
+    if (state.scroll_anchor_selector && state.scroll_anchor_selector->length() <
+                                            kMaxScrollAnchorSelectorLength) {
+      frame->view_state->scroll_anchor_selector = state.scroll_anchor_selector;
+      frame->view_state->scroll_anchor_offset = state.scroll_anchor_offset;
+      frame->view_state->scroll_anchor_simhash = state.scroll_anchor_simhash;
+    }
   }
 
   frame->item_sequence_number = state.item_sequence_number;
@@ -874,6 +881,13 @@
     state->page_scale_factor = frame->view_state->page_scale_factor;
   }
 
+  if (frame->view_state) {
+    state->scroll_anchor_selector = frame->view_state->scroll_anchor_selector;
+    state->scroll_anchor_offset =
+        frame->view_state->scroll_anchor_offset.value_or(gfx::PointF());
+    state->scroll_anchor_simhash = frame->view_state->scroll_anchor_simhash;
+  }
+
   state->item_sequence_number = frame->item_sequence_number;
   state->document_sequence_number = frame->document_sequence_number;
 
@@ -979,7 +993,8 @@
       item_sequence_number(0),
       document_sequence_number(0),
       page_scale_factor(0.0),
-      referrer_policy(blink::kWebReferrerPolicyDefault) {}
+      referrer_policy(blink::kWebReferrerPolicyDefault),
+      scroll_anchor_simhash(0) {}
 
 ExplodedFrameState::ExplodedFrameState(const ExplodedFrameState& other) {
   assign(other);
@@ -1008,6 +1023,9 @@
   page_scale_factor = other.page_scale_factor;
   referrer_policy = other.referrer_policy;
   http_body = other.http_body;
+  scroll_anchor_selector = other.scroll_anchor_selector;
+  scroll_anchor_offset = other.scroll_anchor_offset;
+  scroll_anchor_simhash = other.scroll_anchor_simhash;
   children = other.children;
 }
 
diff --git a/content/common/page_state_serialization.h b/content/common/page_state_serialization.h
index 8f68584..943cc26e 100644
--- a/content/common/page_state_serialization.h
+++ b/content/common/page_state_serialization.h
@@ -24,6 +24,8 @@
 
 namespace content {
 
+constexpr int kMaxScrollAnchorSelectorLength = 500;
+
 struct CONTENT_EXPORT ExplodedHttpBody {
   base::Optional<base::string16> http_content_type;
   scoped_refptr<ResourceRequestBody> request_body;
@@ -48,6 +50,9 @@
   double page_scale_factor;
   blink::WebReferrerPolicy referrer_policy;
   ExplodedHttpBody http_body;
+  base::Optional<base::string16> scroll_anchor_selector;
+  gfx::PointF scroll_anchor_offset;
+  uint64_t scroll_anchor_simhash;
   std::vector<ExplodedFrameState> children;
 
   ExplodedFrameState();
diff --git a/content/common/page_state_serialization_unittest.cc b/content/common/page_state_serialization_unittest.cc
index 2ec8199..ab3dd50 100644
--- a/content/common/page_state_serialization_unittest.cc
+++ b/content/common/page_state_serialization_unittest.cc
@@ -86,6 +86,9 @@
   EXPECT_EQ(expected.item_sequence_number, actual.item_sequence_number);
   EXPECT_EQ(expected.document_sequence_number, actual.document_sequence_number);
   EXPECT_EQ(expected.page_scale_factor, actual.page_scale_factor);
+  EXPECT_EQ(expected.scroll_anchor_selector, actual.scroll_anchor_selector);
+  EXPECT_EQ(expected.scroll_anchor_offset, actual.scroll_anchor_offset);
+  EXPECT_EQ(expected.scroll_anchor_simhash, actual.scroll_anchor_simhash);
   ExpectEquality(expected.http_body, actual.http_body);
   ExpectEquality(expected.children, actual.children);
 }
@@ -120,6 +123,9 @@
     frame_state->item_sequence_number = 1;
     frame_state->document_sequence_number = 2;
     frame_state->page_scale_factor = 2.0;
+    frame_state->scroll_anchor_selector = base::UTF8ToUTF16("#selector");
+    frame_state->scroll_anchor_offset = gfx::PointF(2.5, 3.5);
+    frame_state->scroll_anchor_simhash = 12345;
   }
 
   void PopulateHttpBody(
@@ -408,6 +414,26 @@
   ExpectEquality(actual_encoded_state, expected_encoded_state);
 }
 
+TEST_F(PageStateSerializationTest, ScrollAnchorSelectorLengthLimited) {
+  ExplodedPageState input;
+  PopulateFrameState(&input.top);
+
+  std::string excessive_length_string(kMaxScrollAnchorSelectorLength + 1, 'a');
+
+  input.top.scroll_anchor_selector = base::UTF8ToUTF16(excessive_length_string);
+
+  std::string encoded;
+  EncodePageState(input, &encoded);
+
+  ExplodedPageState output;
+  DecodePageState(encoded, &output);
+
+  // We should drop all the scroll anchor data if the length is over the limit.
+  EXPECT_FALSE(output.top.scroll_anchor_selector);
+  EXPECT_EQ(output.top.scroll_anchor_offset, gfx::PointF());
+  EXPECT_EQ(output.top.scroll_anchor_simhash, 0ul);
+}
+
 // Change to #if 1 to enable this code. Run this test to generate data, based on
 // the current serialization format, for the BackwardsCompat_vXX tests. This
 // will generate an expected.dat in the temp directory, which should be moved
@@ -512,10 +538,20 @@
   TestBackwardsCompat(26);
 }
 
+TEST_F(PageStateSerializationTest, BackwardsCompat_v27) {
+  TestBackwardsCompat(27);
+}
+
+// Add your new backwards compat test for future versions *above* this
+// comment block; field-specific tests go *below* this comment block.
+// Any field additions require a new version and backcompat test; only fields
+// with external type definitions require their own dedicated test.
+// See DumpExpectedPageStateForBackwardsCompat for more details.
 // If any of the below tests fail, you likely made a backwards incompatible
 // change to a definition that page_state.mojom relies on. Ideally you should
 // find a way to avoid making this change; if that's not possible, contact the
 // page state serialization owners to figure out a resolution.
+
 TEST_F(PageStateSerializationTest, BackwardsCompat_ReferencedFiles) {
   ExplodedPageState state;
   state.referenced_files.push_back(base::UTF8ToUTF16("file.txt"));
@@ -634,10 +670,8 @@
   ExpectEquality(state, saved_state);
 }
 
-// Add your new backwards compat test for future versions/fields here.
-// Any field additions require a new version and backcompat test; only fields
-// with external type definitions require their own dedicated test.
-// See DumpExpectedPageStateForBackwardsCompat for more details.
+// Add new backwards compat field-specific tests here.  See comment above for
+// where to put backwards compat version tests.
 
 }  // namespace
 }  // namespace content
diff --git a/content/public/browser/download_item.h b/content/public/browser/download_item.h
index 15540f4..fd833f0d 100644
--- a/content/public/browser/download_item.h
+++ b/content/public/browser/download_item.h
@@ -84,6 +84,13 @@
                                    // TARGET_DISPOSITION_OVERWRITE.
   };
 
+  // How download item is created. Used for trace event.
+  enum DownloadType {
+    TYPE_ACTIVE_DOWNLOAD,
+    TYPE_HISTORY_IMPORT,
+    TYPE_SAVE_PAGE_AS
+  };
+
   // Callback used with AcquireFileAndDeleteDownload().
   typedef base::Callback<void(const base::FilePath&)> AcquireFileCallback;
 
diff --git a/content/public/browser/gpu_data_manager.h b/content/public/browser/gpu_data_manager.h
index 06758fb..d6db972a 100644
--- a/content/public/browser/gpu_data_manager.h
+++ b/content/public/browser/gpu_data_manager.h
@@ -93,9 +93,6 @@
   // Whether a GPU is in use (as opposed to a software renderer).
   virtual bool HardwareAccelerationEnabled() const = 0;
 
-  // Whether the browser compositor can be used.
-  virtual bool CanUseGpuBrowserCompositor() const = 0;
-
   // Extensions that are currently disabled.
   virtual void GetDisabledExtensions(
       std::string* disabled_extensions) const = 0;
diff --git a/content/public/test/test_file_error_injector.cc b/content/public/test/test_file_error_injector.cc
index f4f3176..ce195bf 100644
--- a/content/public/test/test_file_error_injector.cc
+++ b/content/public/test/test_file_error_injector.cc
@@ -34,7 +34,7 @@
   DownloadFileWithError(std::unique_ptr<DownloadSaveInfo> save_info,
                         const base::FilePath& default_download_directory,
                         std::unique_ptr<DownloadManager::InputStream> stream,
-                        const net::NetLogWithSource& net_log,
+                        uint32_t download_id,
                         base::WeakPtr<DownloadDestinationObserver> observer,
                         const TestFileErrorInjector::FileErrorInfo& error_info,
                         const base::Closure& ctor_callback,
@@ -111,7 +111,7 @@
     std::unique_ptr<DownloadSaveInfo> save_info,
     const base::FilePath& default_download_directory,
     std::unique_ptr<DownloadManager::InputStream> stream,
-    const net::NetLogWithSource& net_log,
+    uint32_t download_id,
     base::WeakPtr<DownloadDestinationObserver> observer,
     const TestFileErrorInjector::FileErrorInfo& error_info,
     const base::Closure& ctor_callback,
@@ -119,7 +119,7 @@
     : DownloadFileImpl(std::move(save_info),
                        default_download_directory,
                        std::move(stream),
-                       net_log,
+                       download_id,
                        observer),
       error_info_(error_info),
       destruction_callback_(dtor_callback) {
@@ -286,7 +286,7 @@
       std::unique_ptr<DownloadSaveInfo> save_info,
       const base::FilePath& default_download_directory,
       std::unique_ptr<DownloadManager::InputStream> stream,
-      const net::NetLogWithSource& net_log,
+      uint32_t download_id,
       base::WeakPtr<DownloadDestinationObserver> observer) override;
 
   bool SetError(TestFileErrorInjector::FileErrorInfo error);
@@ -312,11 +312,11 @@
     std::unique_ptr<DownloadSaveInfo> save_info,
     const base::FilePath& default_download_directory,
     std::unique_ptr<DownloadManager::InputStream> stream,
-    const net::NetLogWithSource& net_log,
+    uint32_t download_id,
     base::WeakPtr<DownloadDestinationObserver> observer) {
   return new DownloadFileWithError(
       std::move(save_info), default_download_directory, std::move(stream),
-      net_log, observer, injected_error_, construction_callback_,
+      download_id, observer, injected_error_, construction_callback_,
       destruction_callback_);
 }
 
diff --git a/content/renderer/history_serialization.cc b/content/renderer/history_serialization.cc
index 7f56afd7..0c29a57 100644
--- a/content/renderer/history_serialization.cc
+++ b/content/renderer/history_serialization.cc
@@ -65,6 +65,12 @@
     state->http_body.request_body = GetRequestBodyForWebHTTPBody(http_body);
     state->http_body.contains_passwords = http_body.ContainsPasswordData();
   }
+
+  blink::ScrollAnchorData anchor = item.GetScrollAnchorData();
+  state->scroll_anchor_selector =
+      WebString::ToOptionalString16(anchor.selector_);
+  state->scroll_anchor_offset = anchor.offset_;
+  state->scroll_anchor_simhash = anchor.simhash_;
 }
 
 void RecursivelyGenerateHistoryItem(const ExplodedFrameState& state,
@@ -107,6 +113,10 @@
     item.SetHTTPBody(
         GetWebHTTPBodyForRequestBody(state.http_body.request_body));
   }
+
+  item.SetScrollAnchorData({WebString::FromUTF16(state.scroll_anchor_selector),
+                            state.scroll_anchor_offset,
+                            state.scroll_anchor_simhash});
   node->set_item(item);
 
   for (size_t i = 0; i < state.children.size(); ++i)
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc
index eb41e82c..2f52cd26 100644
--- a/content/renderer/pepper/ppb_graphics_3d_impl.cc
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc
@@ -240,6 +240,8 @@
   RenderThreadImpl* render_thread = RenderThreadImpl::current();
   if (!render_thread)
     return false;
+  if (render_thread->IsGpuCompositingDisabled())
+    return false;
 
   scoped_refptr<gpu::GpuChannelHost> channel =
       render_thread->EstablishGpuChannelSync();
diff --git a/content/test/data/page_state/serialized_v27.dat b/content/test/data/page_state/serialized_v27.dat
new file mode 100644
index 0000000..f9dd8fc
--- /dev/null
+++ b/content/test/data/page_state/serialized_v27.dat
@@ -0,0 +1,36 @@
++AcAABsAAADwBwAAGAAAAAAAAAAQAAAAAAAAAEAAAAAAAAAAEAAAAAEAAAAIAAAAAAAAABAAAAAA
+AAAACAAAAAAAAAAYAAAACAAAAGYAaQBsAGUALgB0AHgAdABgAAAAAAAAAFgAAAAAAAAAkAAAAAAA
+AADIAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAQAAAJACAAAAAAAAewAAAAAAAADIAQAAAAAA
+AOACAAAAAAAACAQAAAAAAAAQAAAAAAAAAAgAAAAAAAAAMAAAABQAAABoAHQAdABwADoALwAvAGMA
+aAByAG8AbQBpAHUAbQAuAG8AcgBnAC8AEAAAAAAAAAAIAAAAAAAAACwAAAASAAAAaAB0AHQAcAA6
+AC8ALwBnAG8AbwBnAGwAZQAuAGMAbwBtAC8AAAAAABAAAAAAAAAACAAAAAAAAAAUAAAABgAAAHQA
+YQByAGcAZQB0AAAAAABIAAAACAAAAEAAAAAAAAAAsAAAAAAAAADQAAAAAAAAAOgAAAAAAAAAAAEA
+AAAAAAAYAQAAAAAAADABAAAAAAAAUAEAAAAAAAAQAAAAAAAAAAgAAAAAAAAAaAAAADAAAAAKAA0A
+PwAlACAAVwBlAGIASwBpAHQAIABzAGUAcgBpAGEAbABpAHoAZQBkACAAZgBvAHIAbQAgAHMAdABh
+AHQAZQAgAHYAZQByAHMAaQBvAG4AIAA4ACAACgANAD0AJgAQAAAAAAAAAAgAAAAAAAAAGAAAAAgA
+AABmAG8AcgBtACAAawBlAHkAEAAAAAAAAAAIAAAAAAAAAAoAAAABAAAAMQAAAAAAAAAQAAAAAAAA
+AAgAAAAAAAAADgAAAAMAAABmAG8AbwAAABAAAAAAAAAACAAAAAAAAAAQAAAABAAAAGYAaQBsAGUA
+EAAAAAAAAAAIAAAAAAAAAAoAAAABAAAAMgAAAAAAAAAQAAAAAAAAAAgAAAAAAAAAGAAAAAgAAABm
+AGkAbABlAC4AdAB4AHQAEAAAAAAAAAAIAAAAAAAAAB4AAAALAAAAZABpAHMAcABsAGEAeQBOAGEA
+bQBlAAAAOAAAAAEAAAAwAAAAAAAAADgAAAAAAAAAAAAAAAAAAEAAAAAAAAAAADAAAAAAAAAAAAAA
+AAAAAAAQAAAAAAAAAAAAgL8AAIC/EAAAAAAAAAAqAAAA1v///xAAAAAAAAAAAAAAAAAAAAAgAAAA
+AAAAABgAAAAAAAAAOAAAAAAAAAAAAAAAAAAAABAAAAAAAAAACAAAAAAAAAAWAAAABwAAAGYAbwBv
+AC8AYgBhAHIAAAAgAAAAAAAAABgAAAAAAAAAFQMAAAAAAAAAAAAAAAAAADgAAAADAAAAEAAAAAEA
+AAAoAAAAAAAAABAAAAACAAAAMAAAAAAAAAAQAAAAAQAAAIAAAAAAAAAAGAAAABAAAABmaXJzdCBk
+YXRhIGJsb2NrKAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAA//////////8wAAAAAAAAABAAAAAAAAAA
+CAAAAAAAAAAYAAAACAAAAGYAaQBsAGUALgB0AHgAdAAQAAAAAAAAAAAAAAAAAAAAFwAAAA8AAABk
+YXRhIHRoZSBzZWNvbmQAEAAAAAEAAAAIAAAAAAAAAGAAAAAAAAAAWAAAAAAAAACQAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAC4AAAAAAAAAAAAAAABAAAAaAIAAAAAAAB7AAAAAAAAAMgBAAAAAAAAuAIA
+AAAAAADQAgAAAAAAABAAAAAAAAAACAAAAAAAAAAwAAAAFAAAAGgAdAB0AHAAOgAvAC8AYwBoAHIA
+bwBtAGkAdQBtAC4AbwByAGcALwAQAAAAAAAAAAgAAAAAAAAALAAAABIAAABoAHQAdABwADoALwAv
+AGcAbwBvAGcAbABlAC4AYwBvAG0ALwAAAAAASAAAAAgAAABAAAAAAAAAALAAAAAAAAAA0AAAAAAA
+AADoAAAAAAAAAAABAAAAAAAAGAEAAAAAAAAwAQAAAAAAAFABAAAAAAAAEAAAAAAAAAAIAAAAAAAA
+AGgAAAAwAAAACgANAD8AJQAgAFcAZQBiAEsAaQB0ACAAcwBlAHIAaQBhAGwAaQB6AGUAZAAgAGYA
+bwByAG0AIABzAHQAYQB0AGUAIAB2AGUAcgBzAGkAbwBuACAAOAAgAAoADQA9ACYAEAAAAAAAAAAI
+AAAAAAAAABgAAAAIAAAAZgBvAHIAbQAgAGsAZQB5ABAAAAAAAAAACAAAAAAAAAAKAAAAAQAAADEA
+AAAAAAAAEAAAAAAAAAAIAAAAAAAAAA4AAAADAAAAZgBvAG8AAAAQAAAAAAAAAAgAAAAAAAAAEAAA
+AAQAAABmAGkAbABlABAAAAAAAAAACAAAAAAAAAAKAAAAAQAAADIAAAAAAAAAEAAAAAAAAAAIAAAA
+AAAAABgAAAAIAAAAZgBpAGwAZQAuAHQAeAB0ABAAAAAAAAAACAAAAAAAAAAeAAAACwAAAGQAaQBz
+AHAAbABhAHkATgBhAG0AZQAAADgAAAABAAAAMAAAAAAAAAA4AAAAAAAAAAAAAAAAAABAAAAAAAAA
+AAAwAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAIC/AACAvxAAAAAAAAAAKgAAANb///8QAAAAAAAA
+AAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAA==
diff --git a/content/test/gpu/gpu_tests/gpu_process_expectations.py b/content/test/gpu/gpu_tests/gpu_process_expectations.py
index fa3778e..16b5bac7 100644
--- a/content/test/gpu/gpu_tests/gpu_process_expectations.py
+++ b/content/test/gpu/gpu_tests/gpu_process_expectations.py
@@ -17,6 +17,9 @@
     self.Skip('GpuProcess_no_gpu_process', ['android'], bug=643282)
     self.Skip('GpuProcess_skip_gpu_process', ['android'], bug=(610951, 610023))
 
+    # TODO(zmo): Consider deleting this test on Linux/Win due to SwiftShader?
+    self.Fail('GpuProcess_no_gpu_process', ['win', 'linux'])
+
     # Chrome on Windows and Linux create a GPU process that uses SwiftShader
     # when using either --disable-gpu or a blacklisted GPU.
     self.Skip('GpuProcess_skip_gpu_process', ['win', 'linux'], bug=630728)
diff --git a/device/u2f/u2f_apdu_command.cc b/device/u2f/u2f_apdu_command.cc
index 7336b116..527c211 100644
--- a/device/u2f/u2f_apdu_command.cc
+++ b/device/u2f/u2f_apdu_command.cc
@@ -168,7 +168,8 @@
 std::unique_ptr<U2fApduCommand> U2fApduCommand::CreateSign(
     const std::vector<uint8_t>& appid_digest,
     const std::vector<uint8_t>& challenge_digest,
-    const std::vector<uint8_t>& key_handle) {
+    const std::vector<uint8_t>& key_handle,
+    bool check_only) {
   if (appid_digest.size() != kAppIdDigestLen ||
       challenge_digest.size() != kChallengeDigestLen ||
       key_handle.size() > kMaxKeyHandleLength) {
@@ -181,7 +182,7 @@
   data.push_back(static_cast<uint8_t>(key_handle.size()));
   data.insert(data.end(), key_handle.begin(), key_handle.end());
   command->set_ins(kInsU2fSign);
-  command->set_p1(kP1TupRequiredConsumed);
+  command->set_p1(check_only ? kP1CheckOnly : kP1TupRequiredConsumed);
   command->set_data(data);
   return command;
 }
diff --git a/device/u2f/u2f_apdu_command.h b/device/u2f/u2f_apdu_command.h
index c44ba564d..cee66e246 100644
--- a/device/u2f/u2f_apdu_command.h
+++ b/device/u2f/u2f_apdu_command.h
@@ -53,10 +53,14 @@
   static std::unique_ptr<U2fApduCommand> CreateVersion();
   // Early U2F drafts defined a non-ISO 7816-4 conforming layout.
   static std::unique_ptr<U2fApduCommand> CreateLegacyVersion();
+
+  // Returns an APDU command for sign(). If optional parameter |check_only| is
+  // set to true, then control byte is set to 0X07.
   static std::unique_ptr<U2fApduCommand> CreateSign(
       const std::vector<uint8_t>& appid_digest,
       const std::vector<uint8_t>& challenge_digest,
-      const std::vector<uint8_t>& key_handle);
+      const std::vector<uint8_t>& key_handle,
+      bool check_only = false);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(U2fApduTest, TestDeserializeBasic);
@@ -88,7 +92,10 @@
   static constexpr uint8_t kP1TupConsumed = 0x02;
   static constexpr uint8_t kP1TupRequiredConsumed =
       kP1TupRequired | kP1TupConsumed;
-
+  // Control byte used for check-only setting. The check-only command is used to
+  // determine if the provided key handle was originally created by this token
+  // and whether it was created for the provided application parameter.
+  static constexpr uint8_t kP1CheckOnly = 0x07;
   static constexpr size_t kMaxKeyHandleLength = 255;
   static constexpr size_t kChallengeDigestLen = 32;
   static constexpr size_t kAppIdDigestLen = 32;
diff --git a/device/u2f/u2f_device.cc b/device/u2f/u2f_device.cc
index 2545cc1..f1efa9e 100644
--- a/device/u2f/u2f_device.cc
+++ b/device/u2f/u2f_device.cc
@@ -31,9 +31,10 @@
 void U2fDevice::Sign(const std::vector<uint8_t>& app_param,
                      const std::vector<uint8_t>& challenge_param,
                      const std::vector<uint8_t>& key_handle,
-                     const MessageCallback& callback) {
-  std::unique_ptr<U2fApduCommand> sign_cmd =
-      U2fApduCommand::CreateSign(app_param, challenge_param, key_handle);
+                     const MessageCallback& callback,
+                     bool check_only) {
+  std::unique_ptr<U2fApduCommand> sign_cmd = U2fApduCommand::CreateSign(
+      app_param, challenge_param, key_handle, check_only);
   if (!sign_cmd) {
     callback.Run(U2fReturnCode::INVALID_PARAMS, std::vector<uint8_t>());
     return;
diff --git a/device/u2f/u2f_device.h b/device/u2f/u2f_device.h
index 71150c4..ece2b556 100644
--- a/device/u2f/u2f_device.h
+++ b/device/u2f/u2f_device.h
@@ -47,7 +47,9 @@
   void Sign(const std::vector<uint8_t>& appid_digest,
             const std::vector<uint8_t>& challenge_digest,
             const std::vector<uint8_t>& key_handle,
-            const MessageCallback& callback);
+            const MessageCallback& callback,
+            bool check_only = false);
+
   virtual void TryWink(const WinkCallback& callback) = 0;
   virtual std::string GetId() const = 0;
 
diff --git a/device/u2f/u2f_register.cc b/device/u2f/u2f_register.cc
index 059432d..3c33432 100644
--- a/device/u2f/u2f_register.cc
+++ b/device/u2f/u2f_register.cc
@@ -3,60 +3,130 @@
 // found in the LICENSE file.
 
 #include "device/u2f/u2f_register.h"
-
 #include <utility>
-
+#include "base/stl_util.h"
 #include "device/u2f/u2f_discovery.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace device {
 
-U2fRegister::U2fRegister(const std::vector<uint8_t>& challenge_hash,
-                         const std::vector<uint8_t>& app_param,
-                         std::vector<std::unique_ptr<U2fDiscovery>> discoveries,
-                         const ResponseCallback& cb)
+U2fRegister::U2fRegister(
+    const std::vector<std::vector<uint8_t>>& registered_keys,
+    const std::vector<uint8_t>& challenge_hash,
+    const std::vector<uint8_t>& app_param,
+    std::vector<std::unique_ptr<U2fDiscovery>> discoveries,
+    const ResponseCallback& cb)
     : U2fRequest(std::move(discoveries), cb),
       challenge_hash_(challenge_hash),
       app_param_(app_param),
+      registered_keys_(registered_keys),
       weak_factory_(this) {}
 
 U2fRegister::~U2fRegister() {}
 
 // static
 std::unique_ptr<U2fRequest> U2fRegister::TryRegistration(
+    const std::vector<std::vector<uint8_t>>& registered_keys,
     const std::vector<uint8_t>& challenge_hash,
     const std::vector<uint8_t>& app_param,
     std::vector<std::unique_ptr<U2fDiscovery>> discoveries,
     const ResponseCallback& cb) {
   std::unique_ptr<U2fRequest> request = std::make_unique<U2fRegister>(
-      challenge_hash, app_param, std::move(discoveries), cb);
+      registered_keys, challenge_hash, app_param, std::move(discoveries), cb);
   request->Start();
   return request;
 }
 
 void U2fRegister::TryDevice() {
   DCHECK(current_device_);
-
-  current_device_->Register(
-      app_param_, challenge_hash_,
-      base::Bind(&U2fRegister::OnTryDevice, weak_factory_.GetWeakPtr()));
+  if (registered_keys_.size() > 0 && !CheckedForDuplicateRegistration()) {
+    auto it = registered_keys_.cbegin();
+    current_device_->Sign(app_param_, challenge_hash_, *it,
+                          base::Bind(&U2fRegister::OnTryCheckRegistration,
+                                     weak_factory_.GetWeakPtr(), it),
+                          true);
+  } else {
+    current_device_->Register(app_param_, challenge_hash_,
+                              base::Bind(&U2fRegister::OnTryDevice,
+                                         weak_factory_.GetWeakPtr(), false));
+  }
 }
 
-void U2fRegister::OnTryDevice(U2fReturnCode return_code,
+void U2fRegister::OnTryCheckRegistration(
+    std::vector<std::vector<uint8_t>>::const_iterator it,
+    U2fReturnCode return_code,
+    const std::vector<uint8_t>& response_data) {
+  switch (return_code) {
+    case U2fReturnCode::SUCCESS:
+    case U2fReturnCode::CONDITIONS_NOT_SATISFIED:
+      // Duplicate registration found. Call bogus registration to check for
+      // user presence (touch) and terminate the registration process.
+      current_device_->Register(U2fRequest::GetBogusAppParam(),
+                                U2fRequest::GetBogusChallenge(),
+                                base::Bind(&U2fRegister::OnTryDevice,
+                                           weak_factory_.GetWeakPtr(), true));
+      break;
+
+    case U2fReturnCode::INVALID_PARAMS:
+      // Continue to iterate through the provided key handles in the exclude
+      // list and check for already registered keys.
+      if (++it != registered_keys_.end()) {
+        current_device_->Sign(app_param_, challenge_hash_, *it,
+                              base::Bind(&U2fRegister::OnTryCheckRegistration,
+                                         weak_factory_.GetWeakPtr(), it),
+                              true);
+      } else {
+        checked_device_id_list_.insert(current_device_->GetId());
+        if (devices_.empty()) {
+          // When all devices have been checked, proceed to registration.
+          CompleteNewDeviceRegistration();
+        } else {
+          state_ = State::IDLE;
+          Transition();
+        }
+      }
+      break;
+    default:
+      // Some sort of failure occurred. Abandon this device and move on.
+      state_ = State::IDLE;
+      current_device_ = nullptr;
+      Transition();
+      break;
+  }
+}
+
+void U2fRegister::CompleteNewDeviceRegistration() {
+  if (current_device_)
+    attempted_devices_.push_back(std::move(current_device_));
+
+  devices_.splice(devices_.end(), std::move(attempted_devices_));
+  state_ = State::IDLE;
+  Transition();
+  return;
+}
+
+bool U2fRegister::CheckedForDuplicateRegistration() {
+  return base::ContainsKey(checked_device_id_list_, current_device_->GetId());
+}
+
+void U2fRegister::OnTryDevice(bool is_duplicate_registration,
+                              U2fReturnCode return_code,
                               const std::vector<uint8_t>& response_data) {
   switch (return_code) {
     case U2fReturnCode::SUCCESS:
       state_ = State::COMPLETE;
+      if (is_duplicate_registration)
+        return_code = U2fReturnCode::CONDITIONS_NOT_SATISFIED;
       cb_.Run(return_code, response_data);
       break;
     case U2fReturnCode::CONDITIONS_NOT_SATISFIED:
-      // Waiting for user touch, move on and try this device later
+      // Waiting for user touch, move on and try this device later.
       state_ = State::IDLE;
       Transition();
       break;
     default:
       state_ = State::IDLE;
-      // An error has occured, quit trying this device
+      // An error has occurred, quit trying this device.
       current_device_ = nullptr;
       Transition();
       break;
diff --git a/device/u2f/u2f_register.h b/device/u2f/u2f_register.h
index 9260594..0b11e68 100644
--- a/device/u2f/u2f_register.h
+++ b/device/u2f/u2f_register.h
@@ -6,8 +6,8 @@
 #define DEVICE_U2F_U2F_REGISTER_H_
 
 #include <memory>
+#include <set>
 #include <vector>
-
 #include "device/u2f/u2f_request.h"
 
 namespace device {
@@ -16,13 +16,15 @@
 
 class U2fRegister : public U2fRequest {
  public:
-  U2fRegister(const std::vector<uint8_t>& challenge_hash,
+  U2fRegister(const std::vector<std::vector<uint8_t>>& registered_keys,
+              const std::vector<uint8_t>& challenge_hash,
               const std::vector<uint8_t>& app_param,
               std::vector<std::unique_ptr<U2fDiscovery>> discoveries,
               const ResponseCallback& cb);
   ~U2fRegister() override;
 
   static std::unique_ptr<U2fRequest> TryRegistration(
+      const std::vector<std::vector<uint8_t>>& registered_keys,
       const std::vector<uint8_t>& challenge_hash,
       const std::vector<uint8_t>& app_param,
       std::vector<std::unique_ptr<U2fDiscovery>> discoveries,
@@ -30,11 +32,30 @@
 
  private:
   void TryDevice() override;
-  void OnTryDevice(U2fReturnCode return_code,
+  void OnTryDevice(bool is_duplicate_registration,
+                   U2fReturnCode return_code,
                    const std::vector<uint8_t>& response_data);
 
+  // Callback function called when non-empty exclude list was provided. This
+  // function iterates through all key handles in |registered_keys_| for all
+  // devices and checks for already registered keys.
+  void OnTryCheckRegistration(
+      std::vector<std::vector<uint8_t>>::const_iterator it,
+      U2fReturnCode return_code,
+      const std::vector<uint8_t>& response_data);
+  // Function handling registration flow after all devices were checked for
+  // already registered keys.
+  void CompleteNewDeviceRegistration();
+  // Returns whether |current_device_| has been checked for duplicate
+  // registration for all key handles provided in |registered_keys_|.
+  bool CheckedForDuplicateRegistration();
+
   std::vector<uint8_t> challenge_hash_;
   std::vector<uint8_t> app_param_;
+  const std::vector<std::vector<uint8_t>> registered_keys_;
+  // List of authenticators that did not create any of the key handles in the
+  // exclude list.
+  std::set<std::string> checked_device_id_list_;
   base::WeakPtrFactory<U2fRegister> weak_factory_;
 };
 
diff --git a/device/u2f/u2f_register_unittest.cc b/device/u2f/u2f_register_unittest.cc
index 917f7df4..4e0ca38 100644
--- a/device/u2f/u2f_register_unittest.cc
+++ b/device/u2f/u2f_register_unittest.cc
@@ -14,6 +14,8 @@
 
 namespace device {
 
+using ::testing::_;
+
 class U2fRegisterTest : public testing::Test {
  public:
   U2fRegisterTest()
@@ -55,9 +57,12 @@
 TEST_F(U2fRegisterTest, TestRegisterSuccess) {
   std::unique_ptr<MockU2fDevice> device(new MockU2fDevice());
   auto discovery = std::make_unique<MockU2fDiscovery>();
-  EXPECT_CALL(*device.get(), DeviceTransactPtr(testing::_, testing::_))
+
+  EXPECT_CALL(*device.get(), GetId())
+      .WillRepeatedly(testing::Return("device0"));
+  EXPECT_CALL(*device.get(), DeviceTransactPtr(_, _))
       .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister));
-  EXPECT_CALL(*device.get(), TryWink(testing::_))
+  EXPECT_CALL(*device.get(), TryWink(_))
       .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
   EXPECT_CALL(*discovery, Start())
       .WillOnce(testing::Invoke(discovery.get(),
@@ -67,8 +72,9 @@
   std::vector<std::unique_ptr<U2fDiscovery>> discoveries;
   MockU2fDiscovery* discovery_weak = discovery.get();
   discoveries.push_back(std::move(discovery));
+  std::vector<std::vector<uint8_t>> registration_keys;
   std::unique_ptr<U2fRequest> request = U2fRegister::TryRegistration(
-      std::vector<uint8_t>(32), std::vector<uint8_t>(32),
+      registration_keys, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
       std::move(discoveries), cb.callback());
   request->Start();
   discovery_weak->AddDevice(std::move(device));
@@ -83,11 +89,13 @@
   std::unique_ptr<MockU2fDevice> device(new MockU2fDevice());
   auto discovery = std::make_unique<MockU2fDiscovery>();
 
+  EXPECT_CALL(*device.get(), GetId())
+      .WillRepeatedly(testing::Return("device0"));
   // Go through the state machine twice before success
-  EXPECT_CALL(*device.get(), DeviceTransactPtr(testing::_, testing::_))
+  EXPECT_CALL(*device.get(), DeviceTransactPtr(_, _))
       .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied))
       .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister));
-  EXPECT_CALL(*device.get(), TryWink(testing::_))
+  EXPECT_CALL(*device.get(), TryWink(_))
       .Times(2)
       .WillRepeatedly(testing::Invoke(MockU2fDevice::WinkDoNothing));
   EXPECT_CALL(*discovery, Start())
@@ -97,9 +105,10 @@
 
   std::vector<std::unique_ptr<U2fDiscovery>> discoveries;
   MockU2fDiscovery* discovery_weak = discovery.get();
+  std::vector<std::vector<uint8_t>> registration_keys;
   discoveries.push_back(std::move(discovery));
   std::unique_ptr<U2fRequest> request = U2fRegister::TryRegistration(
-      std::vector<uint8_t>(32), std::vector<uint8_t>(32),
+      registration_keys, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
       std::move(discoveries), cb.callback());
   request->Start();
   discovery_weak->AddDevice(std::move(device));
@@ -116,14 +125,71 @@
   std::unique_ptr<MockU2fDevice> device1(new MockU2fDevice());
   auto discovery = std::make_unique<MockU2fDiscovery>();
 
-  EXPECT_CALL(*device0.get(), DeviceTransactPtr(testing::_, testing::_))
+  EXPECT_CALL(*device0.get(), GetId())
+      .WillRepeatedly(testing::Return("device0"));
+  EXPECT_CALL(*device1.get(), GetId())
+      .WillRepeatedly(testing::Return("device1"));
+  EXPECT_CALL(*device0.get(), DeviceTransactPtr(_, _))
       .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied));
   // One wink per device
-  EXPECT_CALL(*device0.get(), TryWink(testing::_))
+  EXPECT_CALL(*device0.get(), TryWink(_))
       .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
-  EXPECT_CALL(*device1.get(), DeviceTransactPtr(testing::_, testing::_))
+  EXPECT_CALL(*device1.get(), DeviceTransactPtr(_, _))
       .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister));
-  EXPECT_CALL(*device1.get(), TryWink(testing::_))
+  EXPECT_CALL(*device1.get(), TryWink(_))
+      .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
+  EXPECT_CALL(*discovery, Start())
+      .WillOnce(testing::Invoke(discovery.get(),
+                                &MockU2fDiscovery::StartSuccessAsync));
+
+  TestRegisterCallback cb;
+  std::vector<std::unique_ptr<U2fDiscovery>> discoveries;
+  MockU2fDiscovery* discovery_weak = discovery.get();
+  discoveries.push_back(std::move(discovery));
+  std::vector<std::vector<uint8_t>> registration_keys;
+  std::unique_ptr<U2fRequest> request = U2fRegister::TryRegistration(
+      registration_keys, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
+      std::move(discoveries), cb.callback());
+  request->Start();
+  discovery_weak->AddDevice(std::move(device0));
+  discovery_weak->AddDevice(std::move(device1));
+  std::pair<U2fReturnCode, std::vector<uint8_t>>& response =
+      cb.WaitForCallback();
+  EXPECT_EQ(U2fReturnCode::SUCCESS, response.first);
+  ASSERT_LT(0u, response.second.size());
+  EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kRegister), response.second[0]);
+}
+
+// Tests a scenario where a single device is connected and registration call
+// is received with three unknown key handles. We expect that three check only
+// sign-in calls be processed before registration.
+TEST_F(U2fRegisterTest, TestSingleDeviceRegistrationWithExclusionList) {
+  std::vector<uint8_t> unknown_key0(32, 0xB);
+  std::vector<uint8_t> unknown_key1(32, 0xC);
+  std::vector<uint8_t> unknown_key2(32, 0xD);
+  std::vector<std::vector<uint8_t>> handles = {unknown_key0, unknown_key1,
+                                               unknown_key2};
+  std::unique_ptr<MockU2fDevice> device(new MockU2fDevice());
+  auto discovery = std::make_unique<MockU2fDiscovery>();
+
+  EXPECT_CALL(*device.get(), GetId())
+      .WillRepeatedly(testing::Return("device0"));
+  // DeviceTransact() will be called four times including three check
+  // only sign-in calls and one registration call. For the first three calls,
+  // device will invoke MockU2fDevice::WrongData as the authenticator did not
+  // create the three key handles provided in the exclude list. At the fourth
+  // call, MockU2fDevice::NoErrorRegister will be invoked after registration.
+  EXPECT_CALL(*device.get(), DeviceTransactPtr(_, _))
+      .Times(4)
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister));
+  // TryWink() will be called twice. First during the check only sign-in. After
+  // check only sign operation is complete, request state is changed to IDLE,
+  // and TryWink() is called again before Register() is called.
+  EXPECT_CALL(*device.get(), TryWink(_))
+      .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing))
       .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
   EXPECT_CALL(*discovery, Start())
       .WillOnce(testing::Invoke(discovery.get(),
@@ -134,11 +200,9 @@
   MockU2fDiscovery* discovery_weak = discovery.get();
   discoveries.push_back(std::move(discovery));
   std::unique_ptr<U2fRequest> request = U2fRegister::TryRegistration(
-      std::vector<uint8_t>(32), std::vector<uint8_t>(32),
+      handles, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
       std::move(discoveries), cb.callback());
-  request->Start();
-  discovery_weak->AddDevice(std::move(device0));
-  discovery_weak->AddDevice(std::move(device1));
+  discovery_weak->AddDevice(std::move(device));
   std::pair<U2fReturnCode, std::vector<uint8_t>>& response =
       cb.WaitForCallback();
   EXPECT_EQ(U2fReturnCode::SUCCESS, response.first);
@@ -146,4 +210,193 @@
   EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kRegister), response.second[0]);
 }
 
+// Tests a scenario where two devices are connected and registration call is
+// received with three unknown key handles. We assume that user will proceed the
+// registration with second device, "device1".
+TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithExclusionList) {
+  std::vector<uint8_t> unknown_key0(32, 0xB);
+  std::vector<uint8_t> unknown_key1(32, 0xC);
+  std::vector<uint8_t> unknown_key2(32, 0xD);
+  std::vector<std::vector<uint8_t>> handles = {unknown_key0, unknown_key1,
+                                               unknown_key2};
+  std::unique_ptr<MockU2fDevice> device0(new MockU2fDevice());
+  std::unique_ptr<MockU2fDevice> device1(new MockU2fDevice());
+  auto discovery = std::make_unique<MockU2fDiscovery>();
+
+  EXPECT_CALL(*device0.get(), GetId())
+      .WillRepeatedly(testing::Return("device0"));
+  EXPECT_CALL(*device1.get(), GetId())
+      .WillRepeatedly(testing::Return("device1"));
+
+  // DeviceTransact() will be called four times: three times to check for
+  // duplicate key handles and once for registration. Since user
+  // will register using "device1", the fourth call will invoke
+  // MockU2fDevice::NotSatisfied.
+  EXPECT_CALL(*device0.get(), DeviceTransactPtr(_, _))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied));
+  // We assume that user registers with second device. Therefore, the fourth
+  // DeviceTransact() will invoke MockU2fDevice::NoErrorRegister after
+  // successful registration.
+  EXPECT_CALL(*device1.get(), DeviceTransactPtr(_, _))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister));
+
+  // TryWink() will be called twice on both devices -- during check only
+  // sign-in operation and during registration attempt.
+  EXPECT_CALL(*device0.get(), TryWink(_))
+      .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing))
+      .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
+  EXPECT_CALL(*device1.get(), TryWink(_))
+      .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing))
+      .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
+
+  EXPECT_CALL(*discovery, Start())
+      .WillOnce(testing::Invoke(discovery.get(),
+                                &MockU2fDiscovery::StartSuccessAsync));
+
+  TestRegisterCallback cb;
+  std::vector<std::unique_ptr<U2fDiscovery>> discoveries;
+  MockU2fDiscovery* discovery_weak = discovery.get();
+  discoveries.push_back(std::move(discovery));
+  std::unique_ptr<U2fRequest> request = U2fRegister::TryRegistration(
+      handles, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
+      std::move(discoveries), cb.callback());
+
+  discovery_weak->AddDevice(std::move(device0));
+  discovery_weak->AddDevice(std::move(device1));
+  std::pair<U2fReturnCode, std::vector<uint8_t>>& response =
+      cb.WaitForCallback();
+
+  EXPECT_EQ(U2fReturnCode::SUCCESS, response.first);
+  ASSERT_LT(static_cast<size_t>(0), response.second.size());
+  EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kRegister), response.second[0]);
+}
+
+// Tests a scenario where single device is connected and registration is called
+// with a key in the exclude list that was created by this device. We assume
+// that the duplicate key is the last key handle in the exclude list. Therefore,
+// after duplicate key handle is found, the process is expected to terminate
+// after calling bogus registration which checks for user presence.
+TEST_F(U2fRegisterTest, TestSingleDeviceRegistrationWithDuplicateHandle) {
+  std::vector<uint8_t> unknown_key0(32, 0xB);
+  std::vector<uint8_t> unknown_key1(32, 0xC);
+  std::vector<uint8_t> unknown_key2(32, 0xD);
+  std::vector<uint8_t> duplicate_key(32, 0xA);
+
+  std::vector<std::vector<uint8_t>> handles = {unknown_key0, unknown_key1,
+                                               unknown_key2, duplicate_key};
+  std::unique_ptr<MockU2fDevice> device(new MockU2fDevice());
+  auto discovery = std::make_unique<MockU2fDiscovery>();
+
+  EXPECT_CALL(*device.get(), GetId())
+      .WillRepeatedly(testing::Return("device0"));
+
+  // For four keys in exclude list, the first three keys will invoke
+  // MockU2fDevice::WrongData and the final duplicate key handle will invoke
+  // MockU2fDevice::NoErrorSign. Once duplicate key handle is found, bogus
+  // registration is called to confirm user presence. This invokes
+  // MockU2fDevice::NoErrorRegister.
+  EXPECT_CALL(*device.get(), DeviceTransactPtr(_, _))
+      .Times(5)
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::NoErrorSign))
+      .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister));
+
+  // Since duplicate key handle is found, registration process is terminated
+  // before actual Register() is called on the device. Therefore, TryWink() is
+  // invoked once.
+  EXPECT_CALL(*device.get(), TryWink(_))
+      .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
+
+  EXPECT_CALL(*discovery, Start())
+      .WillOnce(testing::Invoke(discovery.get(),
+                                &MockU2fDiscovery::StartSuccessAsync));
+  TestRegisterCallback cb;
+  std::vector<std::unique_ptr<U2fDiscovery>> discoveries;
+  MockU2fDiscovery* discovery_weak = discovery.get();
+  discoveries.push_back(std::move(discovery));
+  std::unique_ptr<U2fRequest> request = U2fRegister::TryRegistration(
+      handles, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
+      std::move(discoveries), cb.callback());
+  discovery_weak->AddDevice(std::move(device));
+  std::pair<U2fReturnCode, std::vector<uint8_t>>& response =
+      cb.WaitForCallback();
+  EXPECT_EQ(U2fReturnCode::CONDITIONS_NOT_SATISFIED, response.first);
+}
+
+// Tests a scenario where one(device1) of the two devices connected has created
+// a key handle provided in exclude list. We assume that duplicate key is the
+// fourth key handle provided in the exclude list.
+TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithDuplicateHandle) {
+  std::vector<uint8_t> unknown_key0(32, 0xB);
+  std::vector<uint8_t> unknown_key1(32, 0xC);
+  std::vector<uint8_t> unknown_key2(32, 0xD);
+  std::vector<uint8_t> duplicate_key(32, 0xA);
+  std::vector<std::vector<uint8_t>> handles = {unknown_key0, unknown_key1,
+                                               unknown_key2, duplicate_key};
+  std::unique_ptr<MockU2fDevice> device0(new MockU2fDevice());
+  std::unique_ptr<MockU2fDevice> device1(new MockU2fDevice());
+  auto discovery = std::make_unique<MockU2fDiscovery>();
+
+  EXPECT_CALL(*device0.get(), GetId())
+      .WillRepeatedly(testing::Return("device0"));
+
+  EXPECT_CALL(*device1.get(), GetId())
+      .WillRepeatedly(testing::Return("device1"));
+
+  // Since the first device did not create any of the key handles provided in
+  // exclude list, we expect that check only sign() should be called
+  // four times, and all the calls to DeviceTransact() invoke
+  // MockU2fDevice::WrongData.
+  EXPECT_CALL(*device0.get(), DeviceTransactPtr(_, _))
+      .Times(4)
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData));
+  // Since the last key handle in exclude list is a duplicate key, we expect
+  // that the first three calls to check only sign() invoke
+  // MockU2fDevice::WrongData and that fourth sign() call invoke
+  // MockU2fDevice::NoErrorSign. After duplicate key is found, process is
+  // terminated after user presence is verified using bogus registration, which
+  // invokes MockU2fDevice::NoErrorRegister.
+  EXPECT_CALL(*device1.get(), DeviceTransactPtr(_, _))
+      .Times(5)
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
+      .WillOnce(testing::Invoke(MockU2fDevice::NoErrorSign))
+      .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister));
+
+  EXPECT_CALL(*device0.get(), TryWink(_))
+      .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
+
+  EXPECT_CALL(*device1.get(), TryWink(_))
+      .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
+
+  EXPECT_CALL(*discovery, Start())
+      .WillOnce(testing::Invoke(discovery.get(),
+                                &MockU2fDiscovery::StartSuccessAsync));
+  TestRegisterCallback cb;
+  std::vector<std::unique_ptr<U2fDiscovery>> discoveries;
+  MockU2fDiscovery* discovery_weak = discovery.get();
+  discoveries.push_back(std::move(discovery));
+  std::unique_ptr<U2fRequest> request = U2fRegister::TryRegistration(
+      handles, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
+      std::move(discoveries), cb.callback());
+  discovery_weak->AddDevice(std::move(device0));
+  discovery_weak->AddDevice(std::move(device1));
+
+  std::pair<U2fReturnCode, std::vector<uint8_t>>& response =
+      cb.WaitForCallback();
+  EXPECT_EQ(U2fReturnCode::CONDITIONS_NOT_SATISFIED, response.first);
+}
+
 }  // namespace device
diff --git a/device/u2f/u2f_request.cc b/device/u2f/u2f_request.cc
index 3bb86c4..37a8658 100644
--- a/device/u2f/u2f_request.cc
+++ b/device/u2f/u2f_request.cc
@@ -121,4 +121,16 @@
   Transition();
 }
 
+// static
+const std::vector<uint8_t>& U2fRequest::GetBogusAppParam() {
+  static const std::vector<uint8_t> kBogusAppParam(32, 0x41);
+  return kBogusAppParam;
+}
+
+// static
+const std::vector<uint8_t>& U2fRequest::GetBogusChallenge() {
+  static const std::vector<uint8_t> kBogusChallenge(32, 0x42);
+  return kBogusChallenge;
+}
+
 }  // namespace device
diff --git a/device/u2f/u2f_request.h b/device/u2f/u2f_request.h
index 81e31e8..33e1170 100644
--- a/device/u2f/u2f_request.h
+++ b/device/u2f/u2f_request.h
@@ -45,10 +45,18 @@
     COMPLETE,
   };
 
+  // Returns bogus application parameter and challenge to be used to verify user
+  // presence.
+  static const std::vector<uint8_t>& GetBogusAppParam();
+  static const std::vector<uint8_t>& GetBogusChallenge();
+
   void Transition();
   virtual void TryDevice() = 0;
 
   std::unique_ptr<U2fDevice> current_device_;
+  std::list<std::unique_ptr<U2fDevice>> devices_;
+  std::list<std::unique_ptr<U2fDevice>> attempted_devices_;
+
   State state_;
   std::vector<std::unique_ptr<U2fDiscovery>> discoveries_;
   ResponseCallback cb_;
@@ -66,8 +74,6 @@
   void IterateDevice();
   void OnWaitComplete();
 
-  std::list<std::unique_ptr<U2fDevice>> devices_;
-  std::list<std::unique_ptr<U2fDevice>> attempted_devices_;
   base::CancelableClosure delay_callback_;
   size_t started_count_ = 0;
 
diff --git a/device/u2f/u2f_sign.cc b/device/u2f/u2f_sign.cc
index 80071eb..d3c6aad 100644
--- a/device/u2f/u2f_sign.cc
+++ b/device/u2f/u2f_sign.cc
@@ -44,7 +44,7 @@
   if (registered_keys_.size() == 0) {
     // Send registration (Fake enroll) if no keys were provided
     current_device_->Register(
-        kBogusAppParam, kBogusChallenge,
+        U2fRequest::GetBogusAppParam(), U2fRequest::GetBogusChallenge(),
         base::Bind(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(),
                    registered_keys_.cbegin()));
     return;
@@ -81,7 +81,7 @@
         // No provided key was accepted by this device. Send registration
         // (Fake enroll) request to device.
         current_device_->Register(
-            kBogusAppParam, kBogusChallenge,
+            U2fRequest::GetBogusAppParam(), U2fRequest::GetBogusChallenge(),
             base::Bind(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(),
                        registered_keys_.cbegin()));
       }
diff --git a/device/u2f/u2f_sign.h b/device/u2f/u2f_sign.h
index 5b3f9bfb..0941ddc 100644
--- a/device/u2f/u2f_sign.h
+++ b/device/u2f/u2f_sign.h
@@ -39,14 +39,6 @@
   const std::vector<std::vector<uint8_t>> registered_keys_;
   std::vector<uint8_t> challenge_hash_;
   std::vector<uint8_t> app_param_;
-  const std::vector<uint8_t> kBogusAppParam = {
-      0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
-      0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
-      0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41};
-  const std::vector<uint8_t> kBogusChallenge = {
-      0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
-      0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
-      0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42};
 
   base::WeakPtrFactory<U2fSign> weak_factory_;
 };
diff --git a/gpu/config/gpu_util.cc b/gpu/config/gpu_util.cc
index 5b0c25a..b1301534 100644
--- a/gpu/config/gpu_util.cc
+++ b/gpu/config/gpu_util.cc
@@ -166,6 +166,22 @@
   return kGpuFeatureStatusEnabled;
 }
 
+GpuFeatureStatus GetGpuCompositingFeatureStatus(
+    const std::set<int>& blacklisted_features,
+    bool use_swift_shader,
+    bool use_swift_shader_for_webgl) {
+  if (use_swift_shader) {
+    // This is for testing only. Chrome should exercise the GPU accelerated
+    // path on top of SwiftShader driver.
+    return kGpuFeatureStatusEnabled;
+  }
+  if (use_swift_shader_for_webgl)
+    return kGpuFeatureStatusDisabled;
+  if (blacklisted_features.count(GPU_FEATURE_TYPE_GPU_COMPOSITING))
+    return kGpuFeatureStatusBlacklisted;
+  return kGpuFeatureStatusEnabled;
+}
+
 void AppendWorkaroundsToCommandLine(const GpuFeatureInfo& gpu_feature_info,
                                     base::CommandLine* command_line) {
   if (gpu_feature_info.IsWorkaroundEnabled(DISABLE_D3D11)) {
@@ -327,6 +343,15 @@
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE] =
       GetAcceleratedVideoDecodeFeatureStatus(
           blacklisted_features, use_swift_shader, use_swift_shader_for_webgl);
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_GPU_COMPOSITING] =
+      GetGpuCompositingFeatureStatus(blacklisted_features, use_swift_shader,
+                                     use_swift_shader_for_webgl);
+
+  if (gpu_feature_info.status_values[GPU_FEATURE_TYPE_GPU_COMPOSITING] !=
+      kGpuFeatureStatusEnabled) {
+    gpu_feature_info.status_values[GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS] =
+        kGpuFeatureStatusSoftware;
+  }
 
   gl::ExtensionSet all_disabled_extensions;
   std::string disabled_gl_extensions_value =
diff --git a/mojo/public/cpp/bindings/tests/connector_unittest.cc b/mojo/public/cpp/bindings/tests/connector_unittest.cc
index 8266b910..68f51fc 100644
--- a/mojo/public/cpp/bindings/tests/connector_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/connector_unittest.cc
@@ -497,9 +497,7 @@
 
 void AccumulateWithNestedLoop(MessageAccumulator* accumulator,
                               const base::Closure& closure) {
-  base::RunLoop nested_run_loop;
-  base::MessageLoop::ScopedNestableTaskAllower allow(
-      base::MessageLoop::current());
+  base::RunLoop nested_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
   accumulator->set_closure(nested_run_loop.QuitClosure());
   nested_run_loop.Run();
   closure.Run();
diff --git a/ppapi/proxy/ppb_testing_proxy.cc b/ppapi/proxy/ppb_testing_proxy.cc
index 8e85ba2e..44bbd40 100644
--- a/ppapi/proxy/ppb_testing_proxy.cc
+++ b/ppapi/proxy/ppb_testing_proxy.cc
@@ -54,11 +54,9 @@
 }
 
 void RunMessageLoop(PP_Instance instance) {
-  base::MessageLoop::ScopedNestableTaskAllower allow(
-      base::MessageLoop::current());
   CHECK(PpapiGlobals::Get()->GetMainThreadMessageLoop()->
       BelongsToCurrentThread());
-  base::RunLoop().Run();
+  base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).Run();
 }
 
 void QuitMessageLoop(PP_Instance instance) {
@@ -261,3 +259,4 @@
 
 }  // namespace proxy
 }  // namespace ppapi
+
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index a1ff8df7..b9125429 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2387,6 +2387,9 @@
 crbug.com/678481 http/tests/devtools/appcache/appcache-iframe-manifests.html [ Timeout Failure Pass ]
 crbug.com/678481 virtual/mojo-loading/http/tests/devtools/appcache/appcache-iframe-manifests.html [ Timeout Failure Pass ]
 
+crbug.com/782858 virtual/display_list_2d_canvas/fast/canvas/canvas-filter-units-off-screen.html [ Skip ]
+crbug.com/782858 virtual/display_list_2d_canvas/fast/canvas/canvas-filter-units.html [ Skip ]
+
 crbug.com/701047 [ Mac10.12 ] editing/caret/caret-color.html [ Failure ]
 crbug.com/701047 [ Mac10.12 ] editing/deleting/delete-at-paragraph-boundaries-011.html [ Failure ]
 crbug.com/701047 [ Mac10.12 ] editing/deleting/delete-line-001.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/processing-model/preventScroll-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/processing-model/preventScroll-expected.txt
deleted file mode 100644
index 3e0d12a..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/processing-model/preventScroll-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-This is a testharness.js-based test.
-PASS Sanity test
-PASS elm.focus() without arguments
-PASS elm.focus(undefined)
-PASS elm.focus(null)
-PASS elm.focus({})
-PASS elm.focus({preventScroll: false})
-FAIL elm.focus({preventScroll: true}) assert_false: expected false got true
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/processing-model/preventScroll.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/processing-model/preventScroll.html
index fda9480..97d341b3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/processing-model/preventScroll.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/focus/processing-model/preventScroll.html
@@ -67,7 +67,8 @@
   test(() => {
     resetState(win);
     elm.focus({preventScroll: true});
-    assert_false(isEntirelyInView(elm, win));
+    assert_equals(win.scrollX, 0);
+    assert_equals(win.scrollY, 0);
   }, 'elm.focus({preventScroll: true})');
 
   done();
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png
index b0427cd..cf3e85646 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
index d2e9d70bb..fc457708 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png
index b7dbc78..e27dc16 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png
index 369581c..0d10a60 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
index 396bbdb..fe14df1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
index 8a308f1..d1a5b0f1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png
index 46b4f87..d4b107d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png
index 605d21f..ce3c6420c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
index ae68e7d6..836814b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
index 6b357e5..aa94bdad 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-incremental-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png
index 6c923768..5505ce312 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/fillrect_gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-arc-circumference-expected.png b/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-arc-circumference-expected.png
deleted file mode 100644
index 7ecb23a..0000000
--- a/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-arc-circumference-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-arc-circumference-fill-expected.png b/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-arc-circumference-fill-expected.png
deleted file mode 100644
index f44424a..0000000
--- a/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-arc-circumference-fill-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-transformclip-expected.png b/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-transformclip-expected.png
deleted file mode 100644
index 6ff69f8..0000000
--- a/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-composite-transformclip-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-ellipse-circumference-expected.png b/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-ellipse-circumference-expected.png
deleted file mode 100644
index 079d827..0000000
--- a/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-ellipse-circumference-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-ellipse-circumference-fill-expected.png b/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-ellipse-circumference-fill-expected.png
deleted file mode 100644
index 9679b87..0000000
--- a/third_party/WebKit/LayoutTests/virtual/display_list_2d_canvas/fast/canvas/canvas-ellipse-circumference-fill-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni
index 30ca70e..3c151af 100644
--- a/third_party/WebKit/Source/core/core_idl_files.gni
+++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -593,6 +593,7 @@
                     "geometry/DOMPointInit.idl",
                     "geometry/DOMQuadInit.idl",
                     "geometry/DOMRectInit.idl",
+                    "html/FocusOptions.idl",
                     "html/AssignedNodesOptions.idl",
                     "html/ImageDataColorSettings.idl",
                     "html/canvas/CanvasContextCreationAttributes.idl",
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 6a8aad2..a0c751a 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -4538,7 +4538,8 @@
       goto SetFocusedElementDone;
     }
     CancelFocusAppearanceUpdate();
-    focused_element_->UpdateFocusAppearance(params.selection_behavior);
+    focused_element_->UpdateFocusAppearanceWithOptions(
+        params.selection_behavior, params.options);
 
     // Dispatch the focus event and let the node do any other focus related
     // activities (important for text fields)
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index e32df9e..4f149e6 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2837,6 +2837,11 @@
   return GetElementData()->Attributes().Find(q_name);
 }
 
+void Element::focus(FocusOptions options) {
+  focus(FocusParams(SelectionBehaviorOnFocus::kRestore, kWebFocusTypeNone,
+                    nullptr, options));
+}
+
 void Element::focus(const FocusParams& params) {
   if (!isConnected())
     return;
@@ -2867,7 +2872,7 @@
                          .FindFocusableElementInShadowHost(*this);
     if (found && IsShadowIncludingInclusiveAncestorOf(found)) {
       found->focus(FocusParams(SelectionBehaviorOnFocus::kReset,
-                               kWebFocusTypeForward, nullptr));
+                               kWebFocusTypeForward, nullptr, params.options));
       return;
     }
   }
@@ -2891,6 +2896,12 @@
 
 void Element::UpdateFocusAppearance(
     SelectionBehaviorOnFocus selection_behavior) {
+  UpdateFocusAppearanceWithOptions(selection_behavior, FocusOptions());
+}
+
+void Element::UpdateFocusAppearanceWithOptions(
+    SelectionBehaviorOnFocus selection_behavior,
+    const FocusOptions& options) {
   if (selection_behavior == SelectionBehaviorOnFocus::kNone)
     return;
   if (IsRootEditableElement(*this)) {
@@ -2918,10 +2929,13 @@
             .SetShouldClearTypingStyle(true)
             .SetDoNotSetFocus(true)
             .Build());
-    frame->Selection().RevealSelection();
+    if (!options.preventScroll())
+      frame->Selection().RevealSelection();
   } else if (GetLayoutObject() &&
              !GetLayoutObject()->IsLayoutEmbeddedContent()) {
-    GetLayoutObject()->ScrollRectToVisible(BoundingBox());
+    if (!options.preventScroll()) {
+      GetLayoutObject()->ScrollRectToVisible(BoundingBox());
+    }
   }
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index 61dd005..c30c31c 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -31,6 +31,7 @@
 #include "core/dom/ContainerNode.h"
 #include "core/dom/ElementData.h"
 #include "core/dom/WhitespaceAttacher.h"
+#include "core/html/FocusOptions.h"
 #include "core/html_names.h"
 #include "core/resize_observer/ResizeObserver.h"
 #include "platform/bindings/TraceWrapperMember.h"
@@ -55,6 +56,7 @@
 class ElementShadow;
 class ExceptionState;
 class FloatQuad;
+class FocusOptions;
 class Image;
 class InputDeviceCapabilities;
 class Locale;
@@ -118,15 +120,18 @@
   FocusParams() {}
   FocusParams(SelectionBehaviorOnFocus selection,
               WebFocusType focus_type,
-              InputDeviceCapabilities* capabilities)
+              InputDeviceCapabilities* capabilities,
+              FocusOptions focus_options = FocusOptions())
       : selection_behavior(selection),
         type(focus_type),
-        source_capabilities(capabilities) {}
+        source_capabilities(capabilities),
+        options(focus_options) {}
 
   SelectionBehaviorOnFocus selection_behavior =
       SelectionBehaviorOnFocus::kRestore;
   WebFocusType type = kWebFocusTypeNone;
   Member<InputDeviceCapabilities> source_capabilities = nullptr;
+  FocusOptions options = FocusOptions();
 };
 
 typedef HeapVector<TraceWrapperMember<Attr>> AttrNodeList;
@@ -567,7 +572,11 @@
   virtual Image* ImageContents() { return nullptr; }
 
   virtual void focus(const FocusParams& = FocusParams());
-  virtual void UpdateFocusAppearance(SelectionBehaviorOnFocus);
+  void focus(FocusOptions);
+
+  void UpdateFocusAppearance(SelectionBehaviorOnFocus);
+  virtual void UpdateFocusAppearanceWithOptions(SelectionBehaviorOnFocus,
+                                                const FocusOptions&);
   virtual void blur();
 
   void setDistributeScroll(ScrollStateCallback*, String native_scroll_behavior);
diff --git a/third_party/WebKit/Source/core/exported/WebHistoryItem.cpp b/third_party/WebKit/Source/core/exported/WebHistoryItem.cpp
index 5b41e0f..dfbaaaa 100644
--- a/third_party/WebKit/Source/core/exported/WebHistoryItem.cpp
+++ b/third_party/WebKit/Source/core/exported/WebHistoryItem.cpp
@@ -213,6 +213,20 @@
   return private_->GetViewState();
 }
 
+ScrollAnchorData WebHistoryItem::GetScrollAnchorData() const {
+  if (HistoryItem::ViewState* scroll_and_view_state =
+          private_->GetViewState()) {
+    return scroll_and_view_state->scroll_anchor_data_;
+  }
+
+  return ScrollAnchorData();
+}
+
+void WebHistoryItem::SetScrollAnchorData(
+    const struct ScrollAnchorData& scroll_anchor_data) {
+  private_->SetScrollAnchorData(scroll_anchor_data);
+}
+
 WebHistoryItem::WebHistoryItem(HistoryItem* item) : private_(item) {}
 
 WebHistoryItem& WebHistoryItem::operator=(HistoryItem* item) {
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index c87ddb5..581f431 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -1890,6 +1890,13 @@
   SetScrollbarsSuppressed(false);
 }
 
+bool LocalFrameView::RestoreScrollAnchor(
+    const ScrollAnchor::SerializedAnchor& serialized_anchor) {
+  if (!RuntimeEnabledFeatures::ScrollAnchorSerializationEnabled())
+    return false;
+  return scroll_anchor_.RestoreAnchor(frame_->GetDocument(), serialized_anchor);
+}
+
 void LocalFrameView::ProcessUrlFragment(const KURL& url,
                                         UrlFragmentBehavior behavior) {
   // If our URL has no ref, then we have no place we need to jump to.
@@ -2048,6 +2055,8 @@
   if (frame_->GetDocument() &&
       !frame_->GetDocument()->GetLayoutViewItem().IsNull())
     frame_->GetDocument()->Fetcher()->UpdateAllImageResourcePriorities();
+
+  GetFrame().Loader().SaveScrollAnchor();
 }
 
 void LocalFrameView::UpdateLayersAndCompositingAfterScrollIfNeeded() {
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.h b/third_party/WebKit/Source/core/frame/LocalFrameView.h
index fd326870..3a290fe 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.h
@@ -283,6 +283,7 @@
   void DidAttachDocument();
 
   void RestoreScrollbar();
+  bool RestoreScrollAnchor(const ScrollAnchor::SerializedAnchor&);
 
   void PostLayoutTimerFired(TimerBase*);
 
diff --git a/third_party/WebKit/Source/core/html/FocusOptions.idl b/third_party/WebKit/Source/core/html/FocusOptions.idl
new file mode 100644
index 0000000..8a9ef0fc
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/FocusOptions.idl
@@ -0,0 +1,3 @@
+dictionary FocusOptions {
+    [RuntimeEnabled=FocusOptions]boolean preventScroll = false;
+};
diff --git a/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp b/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp
index 7b3d10b..e8aadd3a 100644
--- a/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp
@@ -221,14 +221,17 @@
   ToLayoutImage(layout_object)->AreaElementFocusChanged(this);
 }
 
-void HTMLAreaElement::UpdateFocusAppearance(
-    SelectionBehaviorOnFocus selection_behavior) {
+void HTMLAreaElement::UpdateFocusAppearanceWithOptions(
+    SelectionBehaviorOnFocus selection_behavior,
+    const FocusOptions& options) {
   GetDocument().UpdateStyleAndLayoutTreeForNode(this);
   if (!IsFocusable())
     return;
 
-  if (HTMLImageElement* image_element = this->ImageElement())
-    image_element->UpdateFocusAppearance(selection_behavior);
+  if (HTMLImageElement* image_element = this->ImageElement()) {
+    image_element->UpdateFocusAppearanceWithOptions(selection_behavior,
+                                                    options);
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLAreaElement.h b/third_party/WebKit/Source/core/html/HTMLAreaElement.h
index 18de31b93..9057bb5 100644
--- a/third_party/WebKit/Source/core/html/HTMLAreaElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLAreaElement.h
@@ -65,7 +65,8 @@
   bool IsKeyboardFocusable() const override;
   bool IsMouseFocusable() const override;
   bool LayoutObjectIsFocusable() const override;
-  void UpdateFocusAppearance(SelectionBehaviorOnFocus) override;
+  void UpdateFocusAppearanceWithOptions(SelectionBehaviorOnFocus,
+                                        const FocusOptions&) override;
   void SetFocused(bool, WebFocusType) override;
 
   enum Shape { kDefault, kPoly, kRect, kCircle };
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.idl b/third_party/WebKit/Source/core/html/HTMLElement.idl
index de97f7e..3e2e9989 100644
--- a/third_party/WebKit/Source/core/html/HTMLElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLElement.idl
@@ -33,7 +33,7 @@
     [RuntimeCallStatsCounter=HTMLElementClick] void click();
     [CEReactions, CustomElementCallbacks] attribute long tabIndex;
     [CEReactions, RuntimeEnabled=InertAttribute, Reflect] attribute boolean inert;
-    void focus();
+    void focus(optional FocusOptions options);
     void blur();
     [CEReactions, Reflect] attribute DOMString accessKey;
     [CEReactions, CustomElementCallbacks] attribute boolean draggable;
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
index 07692e7a..cf57b07 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.cpp
@@ -295,8 +295,9 @@
   return input_type_->ShouldShowFocusRingOnMouseFocus();
 }
 
-void HTMLInputElement::UpdateFocusAppearance(
-    SelectionBehaviorOnFocus selection_behavior) {
+void HTMLInputElement::UpdateFocusAppearanceWithOptions(
+    SelectionBehaviorOnFocus selection_behavior,
+    const FocusOptions& options) {
   if (IsTextField()) {
     switch (selection_behavior) {
       case SelectionBehaviorOnFocus::kReset:
@@ -312,13 +313,15 @@
     // FrameSelection::revealSelection().  It doesn't scroll correctly in a
     // case of RangeSelection. crbug.com/443061.
     GetDocument().EnsurePaintLocationDataValidForNode(this);
-    if (GetLayoutObject()) {
-      GetLayoutObject()->ScrollRectToVisible(BoundingBox());
+    if (!options.preventScroll()) {
+      if (GetLayoutObject())
+        GetLayoutObject()->ScrollRectToVisible(BoundingBox());
+      if (GetDocument().GetFrame())
+        GetDocument().GetFrame()->Selection().RevealSelection();
     }
-    if (GetDocument().GetFrame())
-      GetDocument().GetFrame()->Selection().RevealSelection();
   } else {
-    TextControlElement::UpdateFocusAppearance(selection_behavior);
+    TextControlElement::UpdateFocusAppearanceWithOptions(selection_behavior,
+                                                         options);
   }
 }
 
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h
index 87fc485..fe8a8e9 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h
+++ b/third_party/WebKit/Source/core/html/forms/HTMLInputElement.h
@@ -180,7 +180,8 @@
   bool LayoutObjectIsNeeded(const ComputedStyle&) final;
   LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
   void DetachLayoutTree(const AttachContext& = AttachContext()) final;
-  void UpdateFocusAppearance(SelectionBehaviorOnFocus) final;
+  void UpdateFocusAppearanceWithOptions(SelectionBehaviorOnFocus,
+                                        const FocusOptions&) final;
 
   // FIXME: For isActivatedSubmit and setActivatedSubmit, we should use the
   // NVI-idiom here by making it private virtual in all classes and expose a
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLLabelElement.cpp b/third_party/WebKit/Source/core/html/forms/HTMLLabelElement.cpp
index 0d5e0c9..4e5e247 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLLabelElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/HTMLLabelElement.cpp
@@ -236,7 +236,7 @@
   // To match other browsers, always restore previous selection.
   if (HTMLElement* element = control()) {
     element->focus(FocusParams(SelectionBehaviorOnFocus::kRestore, params.type,
-                               params.source_capabilities));
+                               params.source_capabilities, params.options));
   }
 }
 
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLLegendElement.cpp b/third_party/WebKit/Source/core/html/forms/HTMLLegendElement.cpp
index 0becaca..25da8a2 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLLegendElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/HTMLLegendElement.cpp
@@ -61,7 +61,7 @@
   // To match other browsers' behavior, never restore previous selection.
   if (HTMLFormControlElement* control = AssociatedControl()) {
     control->focus(FocusParams(SelectionBehaviorOnFocus::kReset, params.type,
-                               params.source_capabilities));
+                               params.source_capabilities, params.options));
   }
 }
 
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLTextAreaElement.cpp b/third_party/WebKit/Source/core/html/forms/HTMLTextAreaElement.cpp
index 5d660e9..aedb7f0 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLTextAreaElement.cpp
+++ b/third_party/WebKit/Source/core/html/forms/HTMLTextAreaElement.cpp
@@ -246,8 +246,9 @@
   return true;
 }
 
-void HTMLTextAreaElement::UpdateFocusAppearance(
-    SelectionBehaviorOnFocus selection_behavior) {
+void HTMLTextAreaElement::UpdateFocusAppearanceWithOptions(
+    SelectionBehaviorOnFocus selection_behavior,
+    const FocusOptions& options) {
   switch (selection_behavior) {
     case SelectionBehaviorOnFocus::kReset:  // Fallthrough.
     case SelectionBehaviorOnFocus::kRestore:
@@ -256,8 +257,10 @@
     case SelectionBehaviorOnFocus::kNone:
       return;
   }
-  if (GetDocument().GetFrame())
-    GetDocument().GetFrame()->Selection().RevealSelection();
+  if (!options.preventScroll()) {
+    if (GetDocument().GetFrame())
+      GetDocument().GetFrame()->Selection().RevealSelection();
+  }
 }
 
 void HTMLTextAreaElement::DefaultEventHandler(Event* event) {
diff --git a/third_party/WebKit/Source/core/html/forms/HTMLTextAreaElement.h b/third_party/WebKit/Source/core/html/forms/HTMLTextAreaElement.h
index b23eeda0..03637f4 100644
--- a/third_party/WebKit/Source/core/html/forms/HTMLTextAreaElement.h
+++ b/third_party/WebKit/Source/core/html/forms/HTMLTextAreaElement.h
@@ -125,7 +125,8 @@
   bool HasCustomFocusLogic() const override;
   bool ShouldShowFocusRingOnMouseFocus() const override;
   bool IsKeyboardFocusable() const override;
-  void UpdateFocusAppearance(SelectionBehaviorOnFocus) override;
+  void UpdateFocusAppearanceWithOptions(SelectionBehaviorOnFocus,
+                                        const FocusOptions&) override;
 
   void AccessKeyAction(bool send_mouse_events) override;
 
diff --git a/third_party/WebKit/Source/core/layout/ScrollAnchor.cpp b/third_party/WebKit/Source/core/layout/ScrollAnchor.cpp
index a671d844..7f0abba 100644
--- a/third_party/WebKit/Source/core/layout/ScrollAnchor.cpp
+++ b/third_party/WebKit/Source/core/layout/ScrollAnchor.cpp
@@ -17,6 +17,7 @@
 namespace blink {
 
 using Corner = ScrollAnchor::Corner;
+using SerializedAnchor = ScrollAnchor::SerializedAnchor;
 
 ScrollAnchor::ScrollAnchor()
     : anchor_object_(nullptr),
@@ -327,6 +328,19 @@
                     WebFeature::kScrollAnchored);
 }
 
+bool ScrollAnchor::RestoreAnchor(Document* document,
+                                 const SerializedAnchor& serialized_anchor) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+const SerializedAnchor ScrollAnchor::SerializeAnchor() {
+  // TODO(pnoland): When implementing, limit the length of the serialized
+  // anchor's selector to some constant.
+  NOTIMPLEMENTED();
+  return SerializedAnchor("", LayoutPoint());
+}
+
 void ScrollAnchor::ClearSelf() {
   LayoutObject* anchor_object = anchor_object_;
   anchor_object_ = nullptr;
diff --git a/third_party/WebKit/Source/core/layout/ScrollAnchor.h b/third_party/WebKit/Source/core/layout/ScrollAnchor.h
index b78bb672..9a5a8aa4 100644
--- a/third_party/WebKit/Source/core/layout/ScrollAnchor.h
+++ b/third_party/WebKit/Source/core/layout/ScrollAnchor.h
@@ -8,9 +8,11 @@
 #include "core/CoreExport.h"
 #include "platform/geometry/LayoutPoint.h"
 #include "platform/heap/Handle.h"
+#include "platform/wtf/text/WTFString.h"
 
 namespace blink {
 
+class Document;
 class LayoutObject;
 class ScrollableArea;
 
@@ -58,6 +60,31 @@
   // Only meaningful if anchorObject() is non-null.
   Corner GetCorner() const { return corner_; }
 
+  struct SerializedAnchor {
+    SerializedAnchor() : simhash(0) {}
+    SerializedAnchor(const String& s, const LayoutPoint& p)
+        : selector(s), relative_offset(p), simhash(0) {}
+    SerializedAnchor(const String& s, const LayoutPoint& p, uint64_t hash)
+        : selector(s), relative_offset(p), simhash(hash) {}
+
+    bool IsValid() { return !selector.IsEmpty(); }
+
+    // Used to locate an element previously used as a scroll anchor.
+    const String selector;
+    // Used to restore the previous offset of the element within its scroller.
+    const LayoutPoint relative_offset;
+    // Used to compare the similarity of a prospective anchor's contents to the
+    // contents at the time the previous anchor was saved.
+    const uint64_t simhash;
+  };
+
+  // Attempt to restore |serialized_anchor| by scrolling to the element
+  // identified by its selector, adjusting by its relative_offset.
+  bool RestoreAnchor(Document*, const SerializedAnchor&);
+
+  // Create a serialized representation of the current anchor_object_.
+  const SerializedAnchor SerializeAnchor();
+
   // Checks if we hold any references to the specified object.
   bool RefersTo(const LayoutObject*) const;
 
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 8d51c8cf..aa75f34 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -316,6 +316,41 @@
     frame_->GetNavigationScheduler().StartTimer();
 }
 
+bool FrameLoader::ShouldSerializeScrollAnchor() {
+  return RuntimeEnabledFeatures::ScrollAnchorSerializationEnabled();
+}
+
+void FrameLoader::SaveScrollAnchor() {
+  if (!ShouldSerializeScrollAnchor())
+    return;
+
+  if (!document_loader_ || !document_loader_->GetHistoryItem() ||
+      !frame_->View())
+    return;
+
+  // Shouldn't clobber anything if we might still restore later.
+  if (NeedsHistoryItemRestore(document_loader_->LoadType()) &&
+      !document_loader_->GetInitialScrollState().was_scrolled_by_user)
+    return;
+
+  HistoryItem* history_item = document_loader_->GetHistoryItem();
+  if (ScrollableArea* layout_scrollable_area =
+          frame_->View()->LayoutViewportScrollableArea()) {
+    ScrollAnchor* scroll_anchor = layout_scrollable_area->GetScrollAnchor();
+    DCHECK(scroll_anchor);
+
+    ScrollAnchor::SerializedAnchor serialized_anchor =
+        scroll_anchor->SerializeAnchor();
+    if (serialized_anchor.IsValid()) {
+      history_item->SetScrollAnchorData(
+          {serialized_anchor.selector,
+           WebFloatPoint(serialized_anchor.relative_offset.X(),
+                         serialized_anchor.relative_offset.Y()),
+           serialized_anchor.simhash});
+    }
+  }
+}
+
 void FrameLoader::SaveScrollState() {
   if (!document_loader_ || !document_loader_->GetHistoryItem() ||
       !frame_->View())
@@ -346,6 +381,9 @@
   // protected. It will be detached soon.
   protect_provisional_loader_ = false;
   SaveScrollState();
+  // TODO(pnoland): move this SaveScrollAnchorCall to where we fire the
+  // visibilitychange event with value 'hidden.'
+  SaveScrollAnchor();
 
   if (frame_->GetDocument() && !SVGImage::IsInSVGImage(frame_->GetDocument()))
     frame_->GetDocument()->DispatchUnloadEvents();
@@ -1141,8 +1179,19 @@
     return;
 
   if (should_restore_scroll) {
-    view->LayoutViewportScrollableArea()->SetScrollOffset(
-        view_state->scroll_offset_, kProgrammaticScroll);
+    // TODO(pnoland): attempt to restore the anchor in more places than this.
+    // Anchor-based restore should allow for earlier restoration.
+    bool did_restore =
+        ShouldSerializeScrollAnchor() &&
+        view->RestoreScrollAnchor(
+            {view_state->scroll_anchor_data_.selector_,
+             LayoutPoint(view_state->scroll_anchor_data_.offset_.x,
+                         view_state->scroll_anchor_data_.offset_.y),
+             view_state->scroll_anchor_data_.simhash_});
+    if (!did_restore) {
+      view->LayoutViewportScrollableArea()->SetScrollOffset(
+          view_state->scroll_offset_, kProgrammaticScroll);
+    }
   }
 
   // For main frame restore scale and visual viewport position
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.h b/third_party/WebKit/Source/core/loader/FrameLoader.h
index 6ddc391a..9ee291c9 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.h
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.h
@@ -176,6 +176,8 @@
                                        FrameLoadType,
                                        Document*);
 
+  bool ShouldSerializeScrollAnchor();
+  void SaveScrollAnchor();
   void SaveScrollState();
   void RestoreScrollPositionAndViewState();
 
diff --git a/third_party/WebKit/Source/core/loader/HistoryItem.cpp b/third_party/WebKit/Source/core/loader/HistoryItem.cpp
index a20a7fe..90ab5c2c 100644
--- a/third_party/WebKit/Source/core/loader/HistoryItem.cpp
+++ b/third_party/WebKit/Source/core/loader/HistoryItem.cpp
@@ -93,6 +93,13 @@
   view_state_->page_scale_factor_ = scale_factor;
 }
 
+void HistoryItem::SetScrollAnchorData(
+    const ScrollAnchorData& scroll_anchor_data) {
+  if (!view_state_)
+    view_state_ = WTF::MakeUnique<ViewState>();
+  view_state_->scroll_anchor_data_ = scroll_anchor_data;
+}
+
 void HistoryItem::SetDocumentState(const Vector<String>& state) {
   DCHECK(!document_state_);
   document_state_vector_ = state;
diff --git a/third_party/WebKit/Source/core/loader/HistoryItem.h b/third_party/WebKit/Source/core/loader/HistoryItem.h
index b90548a..83da5ed 100644
--- a/third_party/WebKit/Source/core/loader/HistoryItem.h
+++ b/third_party/WebKit/Source/core/loader/HistoryItem.h
@@ -32,10 +32,12 @@
 #include "core/loader/FrameLoaderTypes.h"
 #include "platform/geometry/FloatPoint.h"
 #include "platform/geometry/IntPoint.h"
+#include "platform/geometry/LayoutPoint.h"
 #include "platform/heap/Handle.h"
 #include "platform/scroll/ScrollTypes.h"
 #include "platform/weborigin/Referrer.h"
 #include "platform/wtf/text/WTFString.h"
+#include "public/platform/WebScrollAnchorData.h"
 #include "public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
 
 namespace blink {
@@ -67,6 +69,7 @@
     ScrollOffset visual_viewport_scroll_offset_;
     ScrollOffset scroll_offset_;
     float page_scale_factor_;
+    ScrollAnchorData scroll_anchor_data_;
   };
 
   ViewState* GetViewState() const { return view_state_.get(); }
@@ -112,6 +115,8 @@
     return scroll_restoration_type_;
   }
 
+  void SetScrollAnchorData(const ScrollAnchorData&);
+
   void SetFormInfoFromRequest(const ResourceRequest&);
   void SetFormData(scoped_refptr<EncodedFormData>);
   void SetFormContentType(const AtomicString&);
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
index f86fc83..c1748b9 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -1458,7 +1458,8 @@
     if (this._prettyPrintInfobar)
       return;
 
-    if (!TextUtils.isMinified(/** @type {string} */ (this.uiSourceCode().content())))
+    var content = this.uiSourceCode().content();
+    if (!content || !TextUtils.isMinified(content))
       return;
 
     this._prettyPrintInfobar = UI.Infobar.create(
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
index 3c960e5..4c05e091 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
@@ -51,7 +51,6 @@
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/effects/SkHighContrastFilter.h"
 #include "third_party/skia/include/effects/SkLumaColorFilter.h"
-#include "third_party/skia/include/effects/SkPictureImageFilter.h"
 #include "third_party/skia/include/effects/SkTableColorFilter.h"
 #include "third_party/skia/include/pathops/SkPathOps.h"
 #include "third_party/skia/include/utils/SkNullCanvas.h"
@@ -351,17 +350,17 @@
 
   PaintFlags flags;
   flags.setBlendMode(op);
+  flags.setFilterQuality(
+      static_cast<SkFilterQuality>(ImageInterpolationQuality()));
   canvas_->save();
-  SkRect source_bounds = src;
-  SkRect sk_bounds = dest;
-  SkMatrix transform;
-  transform.setRectToRect(source_bounds, sk_bounds, SkMatrix::kFill_ScaleToFit);
-  canvas_->concat(transform);
-  flags.setImageFilter(SkPictureImageFilter::MakeForLocalSpace(
-      ToSkPicture(record, source_bounds), source_bounds,
-      static_cast<SkFilterQuality>(ImageInterpolationQuality())));
-  canvas_->saveLayer(&source_bounds, &flags);
-  canvas_->restore();
+  canvas_->concat(
+      SkMatrix::MakeRectToRect(src, dest, SkMatrix::kFill_ScaleToFit));
+  canvas_->drawImage(PaintImageBuilder::WithDefault()
+                         .set_paint_record(record, RoundedIntRect(src),
+                                           PaintImage::GetNextContentId())
+                         .set_id(PaintImage::GetNextId())
+                         .TakePaintImage(),
+                     0, 0, &flags);
   canvas_->restore();
 }
 
diff --git a/third_party/WebKit/Source/platform/runtime_enabled_features.json5 b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
index 28861401..f83c41e2 100644
--- a/third_party/WebKit/Source/platform/runtime_enabled_features.json5
+++ b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
@@ -413,6 +413,10 @@
       status: "stable",
     },
     {
+      name: "FocusOptions",
+      status: "stable",
+    },
+    {
       name: "FontCacheScaling",
       status: "test",
     },
@@ -893,6 +897,10 @@
       settable_from_internals: true,
       status: "experimental",
     },
+    // Serialize and restore scroll anchors.
+    {
+      name: "ScrollAnchorSerialization",
+    },
     {
       name: "ScrollCustomization",
     },
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 8f8808b..205fffcb 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -316,6 +316,7 @@
     "platform/WebRenderingStats.h",
     "platform/WebRuntimeFeatures.h",
     "platform/WebScreenInfo.h",
+    "platform/WebScrollAnchorData.h",
     "platform/WebScrollBoundaryBehavior.h",
     "platform/WebScrollbar.h",
     "platform/WebScrollbarBehavior.h",
diff --git a/third_party/WebKit/public/platform/WebScrollAnchorData.h b/third_party/WebKit/public/platform/WebScrollAnchorData.h
new file mode 100644
index 0000000..feda183f
--- /dev/null
+++ b/third_party/WebKit/public/platform/WebScrollAnchorData.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebScrollAnchorData_h
+#define WebScrollAnchorData_h
+
+#include "public/platform/WebFloatPoint.h"
+#include "public/platform/WebString.h"
+
+namespace blink {
+
+struct ScrollAnchorData {
+  WebString selector_;
+  WebFloatPoint offset_;
+  uint64_t simhash_;
+
+  ScrollAnchorData(const WebString& selector,
+                   const WebFloatPoint& offset,
+                   uint64_t simhash)
+      : selector_(selector), offset_(offset), simhash_(simhash) {}
+
+  ScrollAnchorData() { ScrollAnchorData(WebString(), WebFloatPoint(0, 0), 0); }
+};
+
+}  // namespace blink
+
+#endif  // WebScrollAnchorData_h
diff --git a/third_party/WebKit/public/web/WebHistoryItem.h b/third_party/WebKit/public/web/WebHistoryItem.h
index b4e0ade..547e0582 100644
--- a/third_party/WebKit/public/web/WebHistoryItem.h
+++ b/third_party/WebKit/public/web/WebHistoryItem.h
@@ -35,6 +35,7 @@
 #include "public/platform/WebHistoryScrollRestorationType.h"
 #include "public/platform/WebPrivatePtr.h"
 #include "public/platform/WebReferrerPolicy.h"
+#include "public/platform/WebScrollAnchorData.h"
 #include "public/platform/WebString.h"
 
 namespace blink {
@@ -119,6 +120,9 @@
 
   BLINK_EXPORT bool DidSaveScrollOrScaleState() const;
 
+  BLINK_EXPORT ScrollAnchorData GetScrollAnchorData() const;
+  BLINK_EXPORT void SetScrollAnchorData(const ScrollAnchorData&);
+
 #if INSIDE_BLINK
   BLINK_EXPORT WebHistoryItem(HistoryItem*);
   BLINK_EXPORT WebHistoryItem& operator=(HistoryItem*);
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index b7b1c69..68fe2ad 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -544,9 +544,10 @@
 
 void Compositor::RequestNewLayerTreeFrameSink() {
   DCHECK(!layer_tree_frame_sink_requested_);
-  layer_tree_frame_sink_requested_ = true;
   if (widget_valid_)
     context_factory_->CreateLayerTreeFrameSink(weak_ptr_factory_.GetWeakPtr());
+  else
+    layer_tree_frame_sink_requested_ = true;
 }
 
 void Compositor::DidFailToInitializeLayerTreeFrameSink() {
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 9c9ddf5..078b9dd0 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -2,7 +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/linux/pangocairo/pangocairo.gni")
 import("//build/config/ui.gni")
 import("//device/vr/features/features.gni")
 import("//testing/test.gni")
@@ -219,7 +218,6 @@
       "skia_paint_util.cc",
       "skia_paint_util.h",
     ]
-    deps += [ "//build/config/linux/pangocairo:features" ]
   }
 
   configs += [
@@ -387,10 +385,6 @@
     sources -= [ "path_x11.cc" ]
   }
 
-  if (use_pangocairo) {
-    configs += [ "//build/config/linux/pangocairo" ]
-  }
-
   if (is_fuchsia) {
     sources += [
       "font_fallback_fuchsia.cc",
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc
index c2b610ec..7855804 100644
--- a/ui/gfx/canvas.cc
+++ b/ui/gfx/canvas.cc
@@ -9,7 +9,6 @@
 
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
-#include "build/config/linux/pangocairo/features.h"
 #include "cc/paint/paint_flags.h"
 #include "cc/paint/paint_shader.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -36,13 +35,6 @@
   Size pixel_size = ScaleToCeiledSize(size, image_scale);
   canvas_ = CreateOwnedCanvas(pixel_size, is_opaque);
 
-#if !BUILDFLAG(USE_PANGOCAIRO)
-  // skia::PlatformCanvas instances are initialized to 0 by Cairo, but
-  // uninitialized on other platforms.
-  if (!is_opaque)
-    canvas_->clear(SkColorSetARGB(0, 0, 0, 0));
-#endif
-
   SkScalar scale_scalar = SkFloatToScalar(image_scale);
   canvas_->scale(scale_scalar, scale_scalar);
 }
diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h
index 17f9be2..58c5e60 100644
--- a/ui/gfx/native_widget_types.h
+++ b/ui/gfx/native_widget_types.h
@@ -91,8 +91,6 @@
 class NSWindow;
 class NSTextField;
 #endif  // __OBJC__
-#elif defined(OS_POSIX)
-typedef struct _cairo cairo_t;
 #endif
 
 #if defined(OS_ANDROID)