diff --git a/DEPS b/DEPS
index 93a093a..7773e974 100644
--- a/DEPS
+++ b/DEPS
@@ -56,7 +56,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
-  'buildtools_revision': '38477c2e103caf651d113dad07cd3e4efb992209',
+  'buildtools_revision': '7f2cacbbe274ef9df2c94452e05e8702c3ae65a9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSites.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSites.java
index 1597af0..cac588939 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSites.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSites.java
@@ -90,15 +90,21 @@
     void removeBlacklistedUrl(String url);
 
     /**
-     * Records metrics about an impression, including the sources (local, server, ...) and visual
-     * types of the tiles that are shown.
-     * @param tileTypes An array of values from {@link TileVisualType} indicating the type of each
-     *                  tile that's currently showing.
-     * @param sources An array of values from {@link TileSource} indicating the source of each tile
-     *                that's currently showing.
-     * @param tileUrls An array of strings indicating the URL of each tile.
+     * Records metrics about an impression of the surface with tiles.
+     * @param tilesCount Count of tiles available on the surface at the moment.
      */
-    void recordPageImpression(int[] tileTypes, int[] sources, String[] tileUrls);
+    void recordPageImpression(int tilesCount);
+
+    /**
+     * Records metrics about an impression of a tile including its source (local, server, ...) and
+     * its visual type.
+     * @param index The index of the tile that was impressed (0-based).
+     * @param type The visual type of the item as defined in {@link TileVisualType}.
+     * @param source The {@link TileSource} that generated this item.
+     * @param url The URL of the tile.
+     */
+    void recordTileImpression(
+            int index, @TileVisualType int type, @TileSource int source, String url);
 
     /**
      * Records the opening of a Most Visited Item.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java
index d59c78349..ad5ff12 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/MostVisitedSitesBridge.java
@@ -94,8 +94,13 @@
     }
 
     @Override
-    public void recordPageImpression(int[] tileTypes, int[] sources, String[] tileUrls) {
-        nativeRecordPageImpression(mNativeMostVisitedSitesBridge, tileTypes, sources, tileUrls);
+    public void recordPageImpression(int tilesCount) {
+        nativeRecordPageImpression(mNativeMostVisitedSitesBridge, tilesCount);
+    }
+
+    @Override
+    public void recordTileImpression(int index, int type, int source, String url) {
+        nativeRecordTileImpression(mNativeMostVisitedSitesBridge, index, type, source, url);
     }
 
     @Override
@@ -123,7 +128,9 @@
     private native void nativeAddOrRemoveBlacklistedUrl(
             long nativeMostVisitedSitesBridge, String url, boolean addUrl);
     private native void nativeRecordPageImpression(
-            long nativeMostVisitedSitesBridge, int[] tileTypes, int[] sources, String[] tileUrls);
+            long nativeMostVisitedSitesBridge, int tilesCount);
+    private native void nativeRecordTileImpression(
+            long nativeMostVisitedSitesBridge, int index, int type, int source, String url);
     private native void nativeRecordOpenedMostVisitedItem(
             long nativeMostVisitedSitesBridge, int index, int tileType, int source);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
index cd3903aa..568dc875 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
@@ -92,17 +92,12 @@
     public void onLoadingComplete(Tile[] tiles) {
         assert !mIsDestroyed;
 
-        int types[] = new int[tiles.length];
-        int sources[] = new int[tiles.length];
-        String urls[] = new String[tiles.length];
-
         for (int i = 0; i < tiles.length; i++) {
-            types[i] = tiles[i].getType();
-            sources[i] = tiles[i].getSource();
-            urls[i] = tiles[i].getUrl();
+            mMostVisitedSites.recordTileImpression(
+                    i, tiles[i].getType(), tiles[i].getSource(), tiles[i].getUrl());
         }
 
-        mMostVisitedSites.recordPageImpression(types, sources, urls);
+        mMostVisitedSites.recordPageImpression(tiles.length);
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/FakeMostVisitedSites.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/FakeMostVisitedSites.java
index 19061a35..a0fc588 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/FakeMostVisitedSites.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/FakeMostVisitedSites.java
@@ -49,7 +49,12 @@
     }
 
     @Override
-    public void recordPageImpression(int[] sources, int[] tileTypes, String[] tileUrls) {
+    public void recordPageImpression(int tilesCount) {
+        // Metrics are stubbed out.
+    }
+
+    @Override
+    public void recordTileImpression(int index, int source, int type, String url) {
         // Metrics are stubbed out.
     }
 
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index a45f527..94c51dcf 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1346,10 +1346,6 @@
     "task_profiler/task_profiler_data_serializer.h",
     "themes/theme_service_win.cc",
     "themes/theme_service_win.h",
-    "thumbnails/content_analysis.cc",
-    "thumbnails/content_analysis.h",
-    "thumbnails/content_based_thumbnailing_algorithm.cc",
-    "thumbnails/content_based_thumbnailing_algorithm.h",
     "thumbnails/simple_thumbnail_crop.cc",
     "thumbnails/simple_thumbnail_crop.h",
     "thumbnails/thumbnail_list_source.cc",
diff --git a/chrome/browser/android/ntp/most_visited_sites_bridge.cc b/chrome/browser/android/ntp/most_visited_sites_bridge.cc
index f43a562..4bc86d1 100644
--- a/chrome/browser/android/ntp/most_visited_sites_bridge.cc
+++ b/chrome/browser/android/ntp/most_visited_sites_bridge.cc
@@ -34,7 +34,6 @@
 using ntp_tiles::TileSource;
 using ntp_tiles::NTPTilesVector;
 using ntp_tiles::TileVisualType;
-using ntp_tiles::metrics::TileImpression;
 
 namespace {
 
@@ -171,28 +170,22 @@
 void MostVisitedSitesBridge::RecordPageImpression(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jintArray>& jtile_types,
-    const JavaParamRef<jintArray>& jsources,
-    const JavaParamRef<jobjectArray>& jtile_urls) {
-  std::vector<int> int_sources;
-  base::android::JavaIntArrayToIntVector(env, jsources, &int_sources);
-  std::vector<int> int_tile_types;
-  base::android::JavaIntArrayToIntVector(env, jtile_types, &int_tile_types);
-  std::vector<std::string> string_tile_urls;
-  base::android::AppendJavaStringArrayToStringVector(env, jtile_urls,
-                                                     &string_tile_urls);
+    jint jtiles_count) {
+  ntp_tiles::metrics::RecordPageImpression(jtiles_count);
+}
 
-  DCHECK_EQ(int_sources.size(), int_tile_types.size());
-  DCHECK_EQ(int_sources.size(), string_tile_urls.size());
+void MostVisitedSitesBridge::RecordTileImpression(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    jint jindex,
+    jint jtype,
+    jint jsource,
+    const JavaParamRef<jstring>& jurl) {
+  GURL url(ConvertJavaStringToUTF8(env, jurl));
+  TileSource source = static_cast<TileSource>(jsource);
+  TileVisualType type = static_cast<TileVisualType>(jtype);
 
-  std::vector<TileImpression> tiles;
-  for (size_t i = 0; i < int_sources.size(); i++) {
-    TileSource source = static_cast<TileSource>(int_sources[i]);
-    TileVisualType tile_type = static_cast<TileVisualType>(int_tile_types[i]);
-
-    tiles.emplace_back(source, tile_type, GURL(string_tile_urls[i]));
-  }
-  ntp_tiles::metrics::RecordPageImpression(tiles,
+  ntp_tiles::metrics::RecordTileImpression(jindex, source, type, url,
                                            g_browser_process->rappor_service());
 }
 
diff --git a/chrome/browser/android/ntp/most_visited_sites_bridge.h b/chrome/browser/android/ntp/most_visited_sites_bridge.h
index 3335f5d..bda4050c 100644
--- a/chrome/browser/android/ntp/most_visited_sites_bridge.h
+++ b/chrome/browser/android/ntp/most_visited_sites_bridge.h
@@ -39,12 +39,15 @@
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jstring>& j_url,
       jboolean add_url);
-  void RecordPageImpression(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jintArray>& jtile_types,
-      const base::android::JavaParamRef<jintArray>& jsources,
-      const base::android::JavaParamRef<jobjectArray>& jtile_urls);
+  void RecordPageImpression(JNIEnv* env,
+                            const base::android::JavaParamRef<jobject>& obj,
+                            jint jtiles_count);
+  void RecordTileImpression(JNIEnv* env,
+                            const base::android::JavaParamRef<jobject>& obj,
+                            jint jindex,
+                            jint jtype,
+                            jint jsource,
+                            const base::android::JavaParamRef<jstring>& jurl);
   void RecordOpenedMostVisitedItem(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc
index 94702527..9307f9f9 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.cc
+++ b/chrome/browser/chromeos/login/app_launch_controller.cc
@@ -111,8 +111,8 @@
         weak_factory_(this) {
     if (!window_registry_->GetAppWindowsForApp(app_id).empty()) {
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(&AppWindowWatcher::NotifyAppWindowCreated,
-                                weak_factory_.GetWeakPtr()));
+          FROM_HERE, base::BindOnce(&AppWindowWatcher::NotifyAppWindowCreated,
+                                    weak_factory_.GetWeakPtr()));
       return;
     } else {
       window_registry_->AddObserver(this);
diff --git a/chrome/browser/chromeos/login/app_launch_signin_screen.cc b/chrome/browser/chromeos/login/app_launch_signin_screen.cc
index 62e11a9..c94fdb8 100644
--- a/chrome/browser/chromeos/login/app_launch_signin_screen.cc
+++ b/chrome/browser/chromeos/login/app_launch_signin_screen.cc
@@ -90,9 +90,8 @@
   authenticator_ = UserSessionManager::GetInstance()->CreateAuthenticator(this);
   content::BrowserThread::PostTask(
       content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&Authenticator::AuthenticateToUnlock,
-                 authenticator_.get(),
-                 user_context));
+      base::BindOnce(&Authenticator::AuthenticateToUnlock, authenticator_.get(),
+                     user_context));
 }
 
 void AppLaunchSigninScreen::MigrateUserData(const std::string& old_password) {
diff --git a/chrome/browser/chromeos/login/auth/auth_prewarmer.cc b/chrome/browser/chromeos/login/auth/auth_prewarmer.cc
index 17ce83bf..3b811a9 100644
--- a/chrome/browser/chromeos/login/auth/auth_prewarmer.cc
+++ b/chrome/browser/chromeos/login/auth/auth_prewarmer.cc
@@ -91,10 +91,10 @@
   const GURL& url = GaiaUrls::GetInstance()->service_login_url();
   content::BrowserThread::PostTask(
       content::BrowserThread::IO, FROM_HERE,
-      base::Bind(&content::PreconnectUrl,
-                 ProfileHelper::GetSigninProfile()->GetResourceContext(), url,
-                 url, kConnectionsNeeded, true,
-                 net::HttpRequestInfo::EARLY_LOAD_MOTIVATED));
+      base::BindOnce(&content::PreconnectUrl,
+                     ProfileHelper::GetSigninProfile()->GetResourceContext(),
+                     url, url, kConnectionsNeeded, true,
+                     net::HttpRequestInfo::EARLY_LOAD_MOTIVATED));
   if (!completion_callback_.is_null()) {
     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
                                      completion_callback_);
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 6877c0f9..efbda30b 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -308,9 +308,8 @@
           base::FilePath(chrome::kLocalStorePoolName),
           BrowserThread::GetBlockingPool());
   local_state_task_runner->PostTaskAndReply(
-      FROM_HERE,
-      base::Bind(&EnsureLocalStateIsWritten),
-      base::Bind(&ChromeRestartRequest::RestartJob, AsWeakPtr()));
+      FROM_HERE, base::BindOnce(&EnsureLocalStateIsWritten),
+      base::BindOnce(&ChromeRestartRequest::RestartJob, AsWeakPtr()));
 }
 
 void ChromeRestartRequest::RestartJob() {
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc
index 0de29c0..5d266ab7 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc
@@ -100,7 +100,7 @@
     callback_.Run(user_context);
     // Schedule deletion.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&EndReauthAttempt));
+        FROM_HERE, base::BindOnce(&EndReauthAttempt));
   }
 
   void OnAuthFailure(const chromeos::AuthFailure& error) override {}
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc
index 6376a3c..21a9117 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.cc
@@ -40,7 +40,7 @@
     const base::Callback<void(crypto::ScopedPK11Slot)>& callback,
     crypto::ScopedPK11Slot slot) {
   response_task_runner->PostTask(FROM_HERE,
-                                 base::Bind(callback, base::Passed(&slot)));
+                                 base::BindOnce(callback, base::Passed(&slot)));
 }
 
 // Gets TPM system slot. Must be called on IO thread.
@@ -114,7 +114,7 @@
   if (!private_key) {
     LOG(ERROR) << "Private key for signing data not found";
     response_task_runner->PostTask(FROM_HERE,
-                                   base::Bind(callback, std::string()));
+                                   base::BindOnce(callback, std::string()));
     return;
   }
 
@@ -125,13 +125,14 @@
                    SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION) != SECSuccess) {
     LOG(ERROR) << "Failed to sign data";
     response_task_runner->PostTask(FROM_HERE,
-                                   base::Bind(callback, std::string()));
+                                   base::BindOnce(callback, std::string()));
     return;
   }
 
   std::string signature(reinterpret_cast<const char*>(sign_result->data),
                         sign_result->len);
-  response_task_runner->PostTask(FROM_HERE, base::Bind(callback, signature));
+  response_task_runner->PostTask(FROM_HERE,
+                                 base::BindOnce(callback, signature));
 }
 
 // Creates a RSA key pair in |slot|. When done, it runs |callback| with the
@@ -146,7 +147,8 @@
     const base::Callback<void(const std::string&)>& callback) {
   if (!public_key.empty() &&
       GetPrivateKeyOnWorkerThread(slot.get(), public_key)) {
-    response_task_runner->PostTask(FROM_HERE, base::Bind(callback, public_key));
+    response_task_runner->PostTask(FROM_HERE,
+                                   base::BindOnce(callback, public_key));
     return;
   }
 
@@ -157,7 +159,7 @@
                                      &private_key_obj)) {
     LOG(ERROR) << "Failed to create an RSA key.";
     response_task_runner->PostTask(FROM_HERE,
-                                   base::Bind(callback, std::string()));
+                                   base::BindOnce(callback, std::string()));
     return;
   }
 
@@ -166,14 +168,15 @@
   if (!public_key_der) {
     LOG(ERROR) << "Failed to export public key.";
     response_task_runner->PostTask(FROM_HERE,
-                                   base::Bind(callback, std::string()));
+                                   base::BindOnce(callback, std::string()));
     return;
   }
 
   response_task_runner->PostTask(
-      FROM_HERE, base::Bind(callback, std::string(reinterpret_cast<const char*>(
-                                                      public_key_der->data),
-                                                  public_key_der->len)));
+      FROM_HERE,
+      base::BindOnce(callback, std::string(reinterpret_cast<const char*>(
+                                               public_key_der->data),
+                                           public_key_der->len)));
 }
 
 }  // namespace
@@ -237,8 +240,8 @@
 
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&EnsureUserTPMInitializedOnIOThread, username_hash_,
-                   base::ThreadTaskRunnerHandle::Get(), on_user_tpm_ready));
+        base::BindOnce(&EnsureUserTPMInitializedOnIOThread, username_hash_,
+                       base::ThreadTaskRunnerHandle::Get(), on_user_tpm_ready));
   }
 
   return false;
@@ -250,9 +253,9 @@
 
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&EasyUnlockTpmKeyManager::OnTpmKeyCreated,
-                 get_tpm_slot_weak_ptr_factory_.GetWeakPtr(),
-                 std::string()),
+      base::BindOnce(&EasyUnlockTpmKeyManager::OnTpmKeyCreated,
+                     get_tpm_slot_weak_ptr_factory_.GetWeakPtr(),
+                     std::string()),
       base::TimeDelta::FromMilliseconds(timeout_ms));
   return true;
 }
@@ -287,11 +290,10 @@
                  key, data, callback);
 
   content::BrowserThread::PostTask(
-      content::BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&GetSystemSlotOnIOThread,
-                 base::ThreadTaskRunnerHandle::Get(),
-                 sign_with_system_slot));
+      content::BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&GetSystemSlotOnIOThread,
+                     base::ThreadTaskRunnerHandle::Get(),
+                     sign_with_system_slot));
 }
 
 bool EasyUnlockTpmKeyManager::StartedCreatingTpmKeys() const {
@@ -321,8 +323,9 @@
 
   content::BrowserThread::PostTask(
       content::BrowserThread::IO, FROM_HERE,
-      base::Bind(&GetSystemSlotOnIOThread, base::ThreadTaskRunnerHandle::Get(),
-                 create_key_with_system_slot));
+      base::BindOnce(&GetSystemSlotOnIOThread,
+                     base::ThreadTaskRunnerHandle::Get(),
+                     create_key_with_system_slot));
 }
 
 void EasyUnlockTpmKeyManager::CreateKeyInSystemSlot(
@@ -341,10 +344,11 @@
   base::PostTaskWithTraits(
       FROM_HERE,
       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::Bind(&CreateTpmKeyPairOnWorkerThread, base::Passed(&system_slot),
-                 public_key, base::ThreadTaskRunnerHandle::Get(),
-                 base::Bind(&EasyUnlockTpmKeyManager::OnTpmKeyCreated,
-                            weak_ptr_factory_.GetWeakPtr())));
+      base::BindOnce(&CreateTpmKeyPairOnWorkerThread,
+                     base::Passed(&system_slot), public_key,
+                     base::ThreadTaskRunnerHandle::Get(),
+                     base::Bind(&EasyUnlockTpmKeyManager::OnTpmKeyCreated,
+                                weak_ptr_factory_.GetWeakPtr())));
 }
 
 void EasyUnlockTpmKeyManager::SignDataWithSystemSlot(
@@ -358,10 +362,10 @@
   base::PostTaskWithTraits(
       FROM_HERE,
       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::Bind(&SignDataOnWorkerThread, base::Passed(&system_slot),
-                 public_key, data, base::ThreadTaskRunnerHandle::Get(),
-                 base::Bind(&EasyUnlockTpmKeyManager::OnDataSigned,
-                            weak_ptr_factory_.GetWeakPtr(), callback)));
+      base::BindOnce(&SignDataOnWorkerThread, base::Passed(&system_slot),
+                     public_key, data, base::ThreadTaskRunnerHandle::Get(),
+                     base::Bind(&EasyUnlockTpmKeyManager::OnDataSigned,
+                                weak_ptr_factory_.GetWeakPtr(), callback)));
 }
 
 void EasyUnlockTpmKeyManager::OnTpmKeyCreated(const std::string& public_key) {
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
index 76aae0c..6e6d93a 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
@@ -233,8 +233,8 @@
     // Has to be done on IO thread due to thread assertions in nss code.
     content::BrowserThread::PostTaskAndReply(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&EasyUnlockTpmKeyManagerTest::InitTestNssUserOnIOThread,
-                   base::Unretained(this), base::Unretained(&success)),
+        base::BindOnce(&EasyUnlockTpmKeyManagerTest::InitTestNssUserOnIOThread,
+                       base::Unretained(this), base::Unretained(&success)),
         run_loop.QuitClosure());
     run_loop.Run();
     return success;
@@ -257,8 +257,9 @@
     // Has to be done on IO thread due to thread assertions in nss code.
     content::BrowserThread::PostTaskAndReply(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&EasyUnlockTpmKeyManagerTest::FinalizeTestNssUserOnIOThread,
-                   base::Unretained(this)),
+        base::BindOnce(
+            &EasyUnlockTpmKeyManagerTest::FinalizeTestNssUserOnIOThread,
+            base::Unretained(this)),
         run_loop.QuitClosure());
     run_loop.Run();
   }
@@ -270,8 +271,8 @@
     // Has to be done on IO thread due to thread assertions in nss code.
     content::BrowserThread::PostTaskAndReply(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&EasyUnlockTpmKeyManagerTest::ResetTestNssUserOnIOThread,
-                   base::Unretained(this)),
+        base::BindOnce(&EasyUnlockTpmKeyManagerTest::ResetTestNssUserOnIOThread,
+                       base::Unretained(this)),
         run_loop.QuitClosure());
     run_loop.Run();
   }
diff --git a/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.cc b/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.cc
index 270742f3..10b3dfb6 100644
--- a/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.cc
@@ -32,7 +32,8 @@
 
   task_runner->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&ShortLivedUserContext::Reset, weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&ShortLivedUserContext::Reset,
+                     weak_ptr_factory_.GetWeakPtr()),
       base::TimeDelta::FromMinutes(kUserContextTimeToLiveMinutes));
 }
 
diff --git a/chrome/browser/chromeos/login/enable_debugging_browsertest.cc b/chrome/browser/chromeos/login/enable_debugging_browsertest.cc
index 5a562e2..2874502 100644
--- a/chrome/browser/chromeos/login/enable_debugging_browsertest.cc
+++ b/chrome/browser/chromeos/login/enable_debugging_browsertest.cc
@@ -84,7 +84,7 @@
       bool succeeded) {
     LOG(WARNING) << "OnRemoveRootfsVerification: succeeded = " << succeeded;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(original_callback, succeeded));
+        FROM_HERE, base::BindOnce(original_callback, succeeded));
     if (runner_.get())
       runner_->Quit();
     else
@@ -100,7 +100,7 @@
     LOG(WARNING) << "OnQueryDebuggingFeatures: succeeded = " << succeeded
                  << ", feature_mask = " << feature_mask;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(original_callback, succeeded, feature_mask));
+        FROM_HERE, base::BindOnce(original_callback, succeeded, feature_mask));
     if (runner_.get())
       runner_->Quit();
     else
@@ -115,7 +115,7 @@
     LOG(WARNING) << "OnEnableDebuggingFeatures: succeeded = " << succeeded
                  << ", feature_mask = ";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(original_callback, succeeded));
+        FROM_HERE, base::BindOnce(original_callback, succeeded));
     if (runner_.get())
       runner_->Quit();
     else
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
index a2d3773..9d494764 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
@@ -245,9 +245,9 @@
   // their work before.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(&AutoEnrollmentCheckScreen::Finish,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 ScreenExitCode::ENTERPRISE_AUTO_ENROLLMENT_CHECK_COMPLETED));
+      base::BindOnce(
+          &AutoEnrollmentCheckScreen::Finish, weak_ptr_factory_.GetWeakPtr(),
+          ScreenExitCode::ENTERPRISE_AUTO_ENROLLMENT_CHECK_COMPLETED));
 }
 
 bool AutoEnrollmentCheckScreen::IsCompleted() const {
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen_unittest.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen_unittest.cc
index 8a380cf..e8c8daa 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen_unittest.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen_unittest.cc
@@ -158,8 +158,9 @@
 
   // Schedule user retry button click after 30 sec.
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(&EnrollmentScreen::OnRetry,
-                            enrollment_screen_->weak_ptr_factory_.GetWeakPtr()),
+      FROM_HERE,
+      base::BindOnce(&EnrollmentScreen::OnRetry,
+                     enrollment_screen_->weak_ptr_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(30));
 
   // Fast forward time by 1 minute.
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 66bb6fa..7b3da7a 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -152,7 +152,7 @@
   // Last but not least tell the policy subsystem to refresh now as it might
   // have been stuck until now too.
   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
-                                   base::Bind(&RefreshPoliciesOnUIThread));
+                                   base::BindOnce(&RefreshPoliciesOnUIThread));
 }
 
 // Record UMA for password login of regular user when Easy sign-in is enabled.
@@ -372,10 +372,10 @@
 
     content::BrowserThread::PostDelayedTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&TransferContextAuthenticationsOnIOThread,
-                   base::RetainedRef(signin_profile_context_getter),
-                   base::RetainedRef(webview_context_getter),
-                   base::RetainedRef(browser_process_context_getter)),
+        base::BindOnce(&TransferContextAuthenticationsOnIOThread,
+                       base::RetainedRef(signin_profile_context_getter),
+                       base::RetainedRef(webview_context_getter),
+                       base::RetainedRef(browser_process_context_getter)),
         base::TimeDelta::FromMilliseconds(kAuthCacheTransferDelayMs));
   }
 }
@@ -727,9 +727,10 @@
     ShowError(IDS_LOGIN_ERROR_OWNER_REQUIRED, error);
     content::BrowserThread::PostDelayedTask(
         content::BrowserThread::UI, FROM_HERE,
-        base::Bind(&SessionManagerClient::StopSession,
-                   base::Unretained(DBusThreadManager::Get()->
-                                    GetSessionManagerClient())),
+        base::BindOnce(
+            &SessionManagerClient::StopSession,
+            base::Unretained(
+                DBusThreadManager::Get()->GetSessionManagerClient())),
         base::TimeDelta::FromMilliseconds(kSafeModeRestartUiDelayMs));
   } else if (failure.reason() == AuthFailure::TPM_ERROR) {
     ShowTPMError();
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index 7fc7149..3932372 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -266,7 +266,7 @@
   profile_prepared_observer.Wait();
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&ClearNotifications));
+      FROM_HERE, base::BindOnce(&ClearNotifications));
   content::RunAllPendingInMessageLoop();
 }
 
@@ -820,7 +820,7 @@
 
   profile_prepared_observer.Wait();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&ClearNotifications));
+      FROM_HERE, base::BindOnce(&ClearNotifications));
   content::RunAllPendingInMessageLoop();
 }
 
@@ -840,7 +840,7 @@
 
   profile_prepared_observer.Wait();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&ClearNotifications));
+      FROM_HERE, base::BindOnce(&ClearNotifications));
   content::RunAllPendingInMessageLoop();
 }
 
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index 1a0599f7..fd78daa 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -320,8 +320,9 @@
   // Add guard for case when something get broken in call chain to unlock
   // for sure.
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(&ScreenLocker::UnlockOnLoginSuccess,
-                            weak_factory_.GetWeakPtr()),
+      FROM_HERE,
+      base::BindOnce(&ScreenLocker::UnlockOnLoginSuccess,
+                     weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromMilliseconds(kUnlockGuardTimeoutMs));
   delegate_->AnimateAuthenticationSuccess();
 
@@ -397,20 +398,21 @@
                                         ->TransformKey(user_context);
       BrowserThread::PostTask(
           BrowserThread::UI, FROM_HERE,
-          base::Bind(&ExtendedAuthenticator::AuthenticateToCheck,
-                     extended_authenticator_.get(), updated_context,
-                     base::Bind(&ScreenLocker::OnPasswordAuthSuccess,
-                                weak_factory_.GetWeakPtr(), updated_context)));
+          base::BindOnce(
+              &ExtendedAuthenticator::AuthenticateToCheck,
+              extended_authenticator_.get(), updated_context,
+              base::Bind(&ScreenLocker::OnPasswordAuthSuccess,
+                         weak_factory_.GetWeakPtr(), updated_context)));
       return;
     }
   }
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&ExtendedAuthenticator::AuthenticateToCheck,
-                 extended_authenticator_.get(), user_context,
-                 base::Bind(&ScreenLocker::OnPasswordAuthSuccess,
-                            weak_factory_.GetWeakPtr(), user_context)));
+      base::BindOnce(&ExtendedAuthenticator::AuthenticateToCheck,
+                     extended_authenticator_.get(), user_context,
+                     base::Bind(&ScreenLocker::OnPasswordAuthSuccess,
+                                weak_factory_.GetWeakPtr(), user_context)));
 }
 
 const user_manager::User* ScreenLocker::FindUnlockUser(
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
index b48de8e4..aa4fd53 100644
--- a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
@@ -393,23 +393,23 @@
   if (state == PowerManagerClient::LidState::OPEN) {
     content::BrowserThread::PostTask(
         content::BrowserThread::UI, FROM_HERE,
-        base::Bind(&WebUIScreenLocker::FocusUserPod,
-                   weak_factory_.GetWeakPtr()));
+        base::BindOnce(&WebUIScreenLocker::FocusUserPod,
+                       weak_factory_.GetWeakPtr()));
   }
 }
 
 void WebUIScreenLocker::SuspendImminent() {
   content::BrowserThread::PostTask(
       content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&WebUIScreenLocker::ResetAndFocusUserPod,
-                 weak_factory_.GetWeakPtr()));
+      base::BindOnce(&WebUIScreenLocker::ResetAndFocusUserPod,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void WebUIScreenLocker::SuspendDone(const base::TimeDelta& sleep_duration) {
   content::BrowserThread::PostTask(
-      content::BrowserThread::UI,
-      FROM_HERE,
-      base::Bind(&WebUIScreenLocker::FocusUserPod, weak_factory_.GetWeakPtr()));
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&WebUIScreenLocker::FocusUserPod,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void WebUIScreenLocker::RenderProcessGone(base::TerminationStatus status) {
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc
index a1fd32e..44929f5 100644
--- a/chrome/browser/chromeos/login/login_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -221,8 +221,8 @@
     StartupUtils::MarkOobeCompleted();
     base::RunLoop loop;
     fake_auth_policy_client()->RefreshDevicePolicy(
-        base::Bind(&ActiveDirectoryLoginTest::OnRefreshedPolicy,
-                   base::Unretained(this), loop.QuitClosure()));
+        base::BindOnce(&ActiveDirectoryLoginTest::OnRefreshedPolicy,
+                       base::Unretained(this), loop.QuitClosure()));
     loop.Run();
   }
 
diff --git a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
index 5da1aaf..48824f9 100644
--- a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
@@ -48,7 +48,7 @@
   void TearDownOnMainThread() override {
     // This shuts down the login UI.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&chrome::AttemptExit));
+        FROM_HERE, base::BindOnce(&chrome::AttemptExit));
     base::RunLoop().RunUntilIdle();
   }
 };
diff --git a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
index 2fc7f66..a9fe71d 100644
--- a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
@@ -56,8 +56,8 @@
     focused_ = true;
     if (runner_.get()) {
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::Bind(&FocusPODWaiter::ExitMessageLoop, base::Unretained(this)));
+          FROM_HERE, base::BindOnce(&FocusPODWaiter::ExitMessageLoop,
+                                    base::Unretained(this)));
     }
   }
 
diff --git a/chrome/browser/chromeos/login/oobe_browsertest.cc b/chrome/browser/chromeos/login/oobe_browsertest.cc
index fd2fb54..4cdcfd4 100644
--- a/chrome/browser/chromeos/login/oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_browsertest.cc
@@ -47,7 +47,7 @@
     // If the login display is still showing, exit gracefully.
     if (LoginDisplayHost::default_host()) {
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(&chrome::AttemptExit));
+          FROM_HERE, base::BindOnce(&chrome::AttemptExit));
       content::RunMessageLoop();
     }
 
diff --git a/chrome/browser/chromeos/login/profile_auth_data.cc b/chrome/browser/chromeos/login/profile_auth_data.cc
index 08968f5..9fef4cb3 100644
--- a/chrome/browser/chromeos/login/profile_auth_data.cc
+++ b/chrome/browser/chromeos/login/profile_auth_data.cc
@@ -179,8 +179,8 @@
   }
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
-      base::Bind(&ProfileAuthDataTransferer::BeginTransferOnIOThread,
-                 base::Unretained(this)));
+      base::BindOnce(&ProfileAuthDataTransferer::BeginTransferOnIOThread,
+                     base::Unretained(this)));
 }
 
 void ProfileAuthDataTransferer::BeginTransferOnIOThread() {
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index dda3f1f..428d8599 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -1217,13 +1217,12 @@
   ASSERT_TRUE(profile);
   base::RunLoop run_loop;
   content::BrowserThread::PostTask(
-      content::BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&SAMLPolicyTest::GetCookiesOnIOThread,
-                 base::Unretained(this),
-                 scoped_refptr<net::URLRequestContextGetter>(
-                     profile->GetRequestContext()),
-                 run_loop.QuitClosure()));
+      content::BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&SAMLPolicyTest::GetCookiesOnIOThread,
+                     base::Unretained(this),
+                     scoped_refptr<net::URLRequestContextGetter>(
+                         profile->GetRequestContext()),
+                     run_loop.QuitClosure()));
   run_loop.Run();
 }
 
diff --git a/chrome/browser/chromeos/login/screens/chrome_user_selection_screen.cc b/chrome/browser/chromeos/login/screens/chrome_user_selection_screen.cc
index 0f2b0461..19ae27f0 100644
--- a/chrome/browser/chromeos/login/screens/chrome_user_selection_screen.cc
+++ b/chrome/browser/chromeos/login/screens/chrome_user_selection_screen.cc
@@ -109,8 +109,8 @@
   // been informed of the change.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(&ChromeUserSelectionScreen::SetPublicSessionDisplayName,
-                 weak_factory_.GetWeakPtr(), account_id));
+      base::BindOnce(&ChromeUserSelectionScreen::SetPublicSessionDisplayName,
+                     weak_factory_.GetWeakPtr(), account_id));
 }
 
 void ChromeUserSelectionScreen::CheckForPublicSessionLocalePolicyChange(
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc
index d26f50f7..c80d5ec 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -361,7 +361,7 @@
     is_first_detection_notification_ = false;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(
+        base::BindOnce(
             base::IgnoreResult(&NetworkPortalDetector::StartDetectionIfIdle),
             base::Unretained(network_portal_detector::GetInstance())));
     return;
@@ -536,8 +536,8 @@
     // Send UPDATE_STATUS_UPDATING message every |kHostStatusReportDelay|ms.
     base::SequencedTaskRunnerHandle::Get()->PostNonNestableDelayedTask(
         FROM_HERE,
-        base::Bind(&UpdateScreen::SetHostPairingControllerStatus,
-                   weak_factory_.GetWeakPtr(), update_status),
+        base::BindOnce(&UpdateScreen::SetHostPairingControllerStatus,
+                       weak_factory_.GetWeakPtr(), update_status),
         base::TimeDelta::FromMilliseconds(kHostStatusReportDelay));
   }
 }
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 478276e..a2ce9eb 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -1178,7 +1178,7 @@
       // NOTIFICATION_PROFILE_CREATED which marks user profile as initialized.
       base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
-          base::Bind(
+          base::BindOnce(
               &UserSessionManager::CompleteProfileCreateAfterAuthTransfer,
               AsWeakPtr(), profile));
     }
@@ -1189,8 +1189,8 @@
     // Call FinalizePrepareProfile directly and skip RestoreAuthSessionImpl
     // because there is no need to merge session for Active Directory users.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&UserSessionManager::FinalizePrepareProfile,
-                              AsWeakPtr(), profile));
+        FROM_HERE, base::BindOnce(&UserSessionManager::FinalizePrepareProfile,
+                                  AsWeakPtr(), profile));
     return;
   }
 
@@ -1340,8 +1340,9 @@
       base::Bind(&UserSessionManager::ChildAccountStatusReceivedCallback,
                  weak_factory_.GetWeakPtr(), profile));
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(&UserSessionManager::StopChildStatusObserving,
-                            weak_factory_.GetWeakPtr(), profile),
+      FROM_HERE,
+      base::BindOnce(&UserSessionManager::StopChildStatusObserving,
+                     weak_factory_.GetWeakPtr(), profile),
       base::TimeDelta::FromMilliseconds(kFlagsFetchingLoginTimeoutMs));
 
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
@@ -1660,7 +1661,7 @@
   // Restart unconditionally in case if we are stuck somewhere in a session
   // restore process. http://crbug.com/520346.
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(RestartOnTimeout),
+      FROM_HERE, base::BindOnce(RestartOnTimeout),
       base::TimeDelta::FromSeconds(kMaxRestartDelaySeconds));
 
   if (CheckEasyUnlockKeyOps(base::Bind(&UserSessionManager::AttemptRestart,
diff --git a/chrome/browser/chromeos/login/signin/merge_session_resource_throttle.cc b/chrome/browser/chromeos/login/signin/merge_session_resource_throttle.cc
index 5483789..b64316e 100644
--- a/chrome/browser/chromeos/login/signin/merge_session_resource_throttle.cc
+++ b/chrome/browser/chromeos/login/signin/merge_session_resource_throttle.cc
@@ -62,7 +62,7 @@
       content::ResourceRequestInfo::ForRequest(request_);
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(
+      base::BindOnce(
           &DelayXHRLoadOnUIThread, info->GetWebContentsGetterForRequest(),
           request_->url(),
           base::Bind(&MergeSessionResourceThrottle::OnBlockingPageComplete,
diff --git a/chrome/browser/chromeos/login/signin/merge_session_xhr_request_waiter.cc b/chrome/browser/chromeos/login/signin/merge_session_xhr_request_waiter.cc
index 487c3e9b..11a57e1 100644
--- a/chrome/browser/chromeos/login/signin/merge_session_xhr_request_waiter.cc
+++ b/chrome/browser/chromeos/login/signin/merge_session_xhr_request_waiter.cc
@@ -47,8 +47,8 @@
     manager->AddObserver(this);
     BrowserThread::PostDelayedTask(
         BrowserThread::UI, FROM_HERE,
-        base::Bind(&MergeSessionXHRRequestWaiter::OnTimeout,
-                   weak_ptr_factory_.GetWeakPtr()),
+        base::BindOnce(&MergeSessionXHRRequestWaiter::OnTimeout,
+                       weak_ptr_factory_.GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(kMaxRequestWaitTimeMS));
   } else {
     NotifyBlockingDone();
diff --git a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
index 0364a12c..01aeea74 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
@@ -151,7 +151,7 @@
             base::WaitableEvent::InitialState::NOT_SIGNALED)) {
     content::BrowserThread::PostTask(
         identifier, FROM_HERE,
-        base::Bind(&BlockThreadOnThread, base::Owned(unblock_event_)));
+        base::BindOnce(&BlockThreadOnThread, base::Owned(unblock_event_)));
   }
   ~BrowserThreadBlocker() { unblock_event_->Signal(); }
 
@@ -408,8 +408,7 @@
     context_ = profile->GetRequestContext();
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&CookieReader::ReadCookiesOnIOThread,
-                   this));
+        base::BindOnce(&CookieReader::ReadCookiesOnIOThread, this));
     runner_ = new content::MessageLoopRunner;
     runner_->Run();
   }
@@ -441,8 +440,7 @@
     cookie_list_ = cookies;
     content::BrowserThread::PostTask(
         content::BrowserThread::UI, FROM_HERE,
-        base::Bind(&CookieReader::OnCookiesReadyOnUIThread,
-                   this));
+        base::BindOnce(&CookieReader::OnCookiesReadyOnUIThread, this));
   }
 
   void OnCookiesReadyOnUIThread() {
@@ -647,8 +645,8 @@
       start_event_.Signal();
       content::BrowserThread::PostTask(
           content::BrowserThread::UI, FROM_HERE,
-          base::Bind(&FakeGoogle::QuitRunnerOnUIThread,
-                     base::Unretained(this)));
+          base::BindOnce(&FakeGoogle::QuitRunnerOnUIThread,
+                         base::Unretained(this)));
 
       http_response->set_code(net::HTTP_OK);
       http_response->set_content_type("text/html");
@@ -721,8 +719,8 @@
     start_event_.Signal();
     content::BrowserThread::PostTask(
         content::BrowserThread::UI, FROM_HERE,
-        base::Bind(&DelayedFakeGaia::QuitRunnerOnUIThread,
-                   base::Unretained(this)));
+        base::BindOnce(&DelayedFakeGaia::QuitRunnerOnUIThread,
+                       base::Unretained(this)));
     blocking_event_.Wait();
     FakeGaia::HandleMergeSession(request, http_response);
   }
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc
index c2ff8b39..7b9e179 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc
@@ -53,12 +53,9 @@
     // If network is offline, defer the token fetching until online.
     VLOG(1) << "Network is offline.  Deferring OAuth2 token fetch.";
     BrowserThread::PostDelayedTask(
-        BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies,
-                   AsWeakPtr(),
-                   session_index,
-                   signin_scoped_device_id),
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(&OAuth2TokenFetcher::StartExchangeFromCookies,
+                       AsWeakPtr(), session_index, signin_scoped_device_id),
         base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
     return;
   }
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_authenticator.cc b/chrome/browser/chromeos/login/supervised/supervised_user_authenticator.cc
index bca16cf0..94ca08b 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_authenticator.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_authenticator.cc
@@ -190,43 +190,35 @@
       // the user in because their data is horked.  So, override with
       // the appropriate failure.
       BrowserThread::PostTask(
-          BrowserThread::UI,
-          FROM_HERE,
-          base::Bind(&SupervisedUserAuthenticator::OnAuthenticationFailure,
-                     this,
-                     state));
+          BrowserThread::UI, FROM_HERE,
+          base::BindOnce(&SupervisedUserAuthenticator::OnAuthenticationFailure,
+                         this, state));
       break;
     case NO_MOUNT:
       // In this case, whether login succeeded or not, we can't log
       // the user in because no data exist. So, override with
       // the appropriate failure.
       BrowserThread::PostTask(
-          BrowserThread::UI,
-          FROM_HERE,
-          base::Bind(&SupervisedUserAuthenticator::OnAuthenticationFailure,
-                     this,
-                     state));
+          BrowserThread::UI, FROM_HERE,
+          base::BindOnce(&SupervisedUserAuthenticator::OnAuthenticationFailure,
+                         this, state));
       break;
     case FAILED_TPM:
       // In this case, we tried to create/mount cryptohome and failed
       // because of the critical TPM error.
       // Chrome will notify user and request reboot.
       BrowserThread::PostTask(
-          BrowserThread::UI,
-          FROM_HERE,
-          base::Bind(&SupervisedUserAuthenticator::OnAuthenticationFailure,
-                     this,
-                     state));
+          BrowserThread::UI, FROM_HERE,
+          base::BindOnce(&SupervisedUserAuthenticator::OnAuthenticationFailure,
+                         this, state));
       break;
     case SUCCESS:
       VLOG(2) << "Supervised user login";
       BrowserThread::PostTask(
-          BrowserThread::UI,
-          FROM_HERE,
-          base::Bind(&SupervisedUserAuthenticator::OnAuthenticationSuccess,
-                     this,
-                     current_state_->hash(),
-                     current_state_->add_key));
+          BrowserThread::UI, FROM_HERE,
+          base::BindOnce(&SupervisedUserAuthenticator::OnAuthenticationSuccess,
+                         this, current_state_->hash(),
+                         current_state_->add_key));
       break;
     default:
       NOTREACHED();
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc
index b3bffd4..b2b0dc7 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.cc
@@ -410,9 +410,9 @@
     case SupervisedUserCreationController::CRYPTOHOME_NO_MOUNT:
     case SupervisedUserCreationController::CRYPTOHOME_FAILED_MOUNT:
     case SupervisedUserCreationController::CRYPTOHOME_FAILED_TPM:
-      ::login::GetSecureModuleUsed(
-          base::Bind(&SupervisedUserCreationScreen::UpdateSecureModuleMessages,
-                     weak_factory_.GetWeakPtr()));
+      ::login::GetSecureModuleUsed(base::BindOnce(
+          &SupervisedUserCreationScreen::UpdateSecureModuleMessages,
+          weak_factory_.GetWeakPtr()));
       return;
     case SupervisedUserCreationController::CLOUD_SERVER_ERROR:
     case SupervisedUserCreationController::TOKEN_WRITE_FAILED:
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.cc b/chrome/browser/chromeos/login/test/oobe_base_test.cc
index c7eed6d5..8139b03 100644
--- a/chrome/browser/chromeos/login/test/oobe_base_test.cc
+++ b/chrome/browser/chromeos/login/test/oobe_base_test.cc
@@ -128,7 +128,7 @@
   // If the login display is still showing, exit gracefully.
   if (LoginDisplayHost::default_host()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&chrome::AttemptExit));
+        FROM_HERE, base::BindOnce(&chrome::AttemptExit));
     content::RunMessageLoop();
   }
   EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
index bd4afc4a..97eb2c7c 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -1248,7 +1248,7 @@
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(&EnableSystemSoundsForAccessibility),
+      FROM_HERE, base::BindOnce(&EnableSystemSoundsForAccessibility),
       media::SoundsManager::Get()->GetDuration(SOUND_STARTUP));
 }
 
diff --git a/chrome/browser/chromeos/login/ui/login_feedback.cc b/chrome/browser/chromeos/login/ui/login_feedback.cc
index 3906002..5b5174f 100644
--- a/chrome/browser/chromeos/login/ui/login_feedback.cc
+++ b/chrome/browser/chromeos/login/ui/login_feedback.cc
@@ -259,7 +259,8 @@
   // Make sure there is a feedback app window opened.
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&LoginFeedback::EnsureFeedbackUI, weak_factory_.GetWeakPtr()),
+      base::BindOnce(&LoginFeedback::EnsureFeedbackUI,
+                     weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(1));
 }
 
diff --git a/chrome/browser/chromeos/login/ui/user_adding_screen.cc b/chrome/browser/chromeos/login/ui/user_adding_screen.cc
index d70983e..0e07736f 100644
--- a/chrome/browser/chromeos/login/ui/user_adding_screen.cc
+++ b/chrome/browser/chromeos/login/ui/user_adding_screen.cc
@@ -50,9 +50,8 @@
   CHECK(!IsRunning());
   gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size()));
   display_host_ = new chromeos::LoginDisplayHostImpl(screen_bounds);
-  display_host_->StartUserAdding(
-      base::Bind(&UserAddingScreenImpl::OnDisplayHostCompletion,
-                 base::Unretained(this)));
+  display_host_->StartUserAdding(base::BindOnce(
+      &UserAddingScreenImpl::OnDisplayHostCompletion, base::Unretained(this)));
 
   session_manager::SessionManager::Get()->SetSessionState(
       session_manager::SessionState::LOGIN_SECONDARY);
diff --git a/chrome/browser/chromeos/login/user_flow.cc b/chrome/browser/chromeos/login/user_flow.cc
index 7507a6b..2c3325a2 100644
--- a/chrome/browser/chromeos/login/user_flow.cc
+++ b/chrome/browser/chromeos/login/user_flow.cc
@@ -103,8 +103,8 @@
 void ExtendedUserFlow::UnregisterFlowSoon() {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(&ChromeUserManager::ResetUserFlow,
-                 base::Unretained(ChromeUserManager::Get()), account_id()));
+      base::BindOnce(&ChromeUserManager::ResetUserFlow,
+                     base::Unretained(ChromeUserManager::Get()), account_id()));
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_loader.cc b/chrome/browser/chromeos/login/users/avatar/user_image_loader.cc
index 6d2890b..e4516a9 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_loader.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_loader.cc
@@ -220,8 +220,9 @@
   if (!data_is_ready) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(image_info.loaded_cb, base::Passed(base::WrapUnique(
-                                             new user_manager::UserImage))));
+        base::BindOnce(
+            image_info.loaded_cb,
+            base::Passed(base::WrapUnique(new user_manager::UserImage))));
     return;
   }
 
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
index 069bb110..394ef9e 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
@@ -976,10 +976,8 @@
   image_properties->GetString(kImagePathNodeName, &image_path);
   if (!image_path.empty()) {
     background_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(base::IgnoreResult(&base::DeleteFile),
-                   base::FilePath(image_path),
-                   false));
+        FROM_HERE, base::BindOnce(base::IgnoreResult(&base::DeleteFile),
+                                  base::FilePath(image_path), false));
   }
   update->RemoveWithoutPathExpansion(user_id(), nullptr);
 }
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index b3fdb4a..3a02872 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -221,8 +221,8 @@
   if (base::ThreadTaskRunnerHandle::IsSet()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(&ChromeUserManagerImpl::RetrieveTrustedDevicePolicies,
-                   weak_factory_.GetWeakPtr()));
+        base::BindOnce(&ChromeUserManagerImpl::RetrieveTrustedDevicePolicies,
+                       weak_factory_.GetWeakPtr()));
   }
 
   local_accounts_subscription_ = cros_settings_->AddSettingsObserver(
@@ -519,9 +519,9 @@
         // in ProfileManager. It happens in case of sync profile load when
         // NOTIFICATION_PROFILE_CREATED is called synchronously.
         base::ThreadTaskRunnerHandle::Get()->PostTask(
-            FROM_HERE,
-            base::Bind(&ChromeUserManagerImpl::SwitchActiveUser,
-                       weak_factory_.GetWeakPtr(), GetPendingUserSwitchID()));
+            FROM_HERE, base::BindOnce(&ChromeUserManagerImpl::SwitchActiveUser,
+                                      weak_factory_.GetWeakPtr(),
+                                      GetPendingUserSwitchID()));
         SetPendingUserSwitchId(EmptyAccountId());
       }
       break;
@@ -1361,7 +1361,8 @@
     std::string* out_resolved_locale) const {
   base::PostTaskWithTraitsAndReply(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
-      base::Bind(ResolveLocale, locale, base::Unretained(out_resolved_locale)),
+      base::BindOnce(ResolveLocale, locale,
+                     base::Unretained(out_resolved_locale)),
       on_resolved_callback);
 }
 
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
index 7b01d15..59f012b 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -332,11 +332,12 @@
     } else if (!wallpaper_path_.empty()) {
       manager->task_runner_->PostTask(
           FROM_HERE,
-          base::Bind(&WallpaperManager::GetCustomWallpaperInternal, account_id_,
-                     info_, wallpaper_path_, true /* update wallpaper */,
-                     base::ThreadTaskRunnerHandle::Get(),
-                     base::Passed(std::move(on_finish_)),
-                     manager->weak_factory_.GetWeakPtr()));
+          base::BindOnce(&WallpaperManager::GetCustomWallpaperInternal,
+                         account_id_, info_, wallpaper_path_,
+                         true /* update wallpaper */,
+                         base::ThreadTaskRunnerHandle::Get(),
+                         base::Passed(std::move(on_finish_)),
+                         manager->weak_factory_.GetWeakPtr()));
     } else if (!info_.location.empty()) {
       manager->LoadWallpaper(account_id_, info_, true, std::move(on_finish_));
     } else {
@@ -562,10 +563,9 @@
     case chrome::NOTIFICATION_LOGIN_USER_CHANGED: {
       ClearDisposableWallpaperCache();
       BrowserThread::PostDelayedTask(
-          BrowserThread::UI,
-          FROM_HERE,
-          base::Bind(&WallpaperManager::MoveLoggedInUserCustomWallpaper,
-                     weak_factory_.GetWeakPtr()),
+          BrowserThread::UI, FROM_HERE,
+          base::BindOnce(&WallpaperManager::MoveLoggedInUserCustomWallpaper,
+                         weak_factory_.GetWeakPtr()),
           base::TimeDelta::FromSeconds(kMoveCustomWallpaperDelaySeconds));
       break;
     }
@@ -573,8 +573,8 @@
       if (!GetCommandLine()->HasSwitch(switches::kDisableBootAnimation)) {
         BrowserThread::PostDelayedTask(
             BrowserThread::UI, FROM_HERE,
-            base::Bind(&WallpaperManager::CacheUsersWallpapers,
-                       weak_factory_.GetWeakPtr()),
+            base::BindOnce(&WallpaperManager::CacheUsersWallpapers,
+                           weak_factory_.GetWeakPtr()),
             base::TimeDelta::FromMilliseconds(kCacheWallpaperDelayMs));
       } else {
         should_cache_wallpaper_ = true;
@@ -586,8 +586,8 @@
       if (should_cache_wallpaper_) {
         BrowserThread::PostDelayedTask(
             BrowserThread::UI, FROM_HERE,
-            base::Bind(&WallpaperManager::CacheUsersWallpapers,
-                       weak_factory_.GetWeakPtr()),
+            base::BindOnce(&WallpaperManager::CacheUsersWallpapers,
+                           weak_factory_.GetWeakPtr()),
             base::TimeDelta::FromMilliseconds(kCacheWallpaperDelayMs));
         should_cache_wallpaper_ = false;
       }
@@ -683,10 +683,11 @@
                 sequence_token_, base::SequencedWorkerPool::BLOCK_SHUTDOWN);
     // TODO(bshe): This may break if RawImage becomes RefCountedMemory.
     blocking_task_runner->PostTask(
-        FROM_HERE,
-        base::Bind(&WallpaperManager::SaveCustomWallpaper, wallpaper_files_id,
-                   base::FilePath(wallpaper_info.location),
-                   wallpaper_info.layout, base::Passed(std::move(deep_copy))));
+        FROM_HERE, base::BindOnce(&WallpaperManager::SaveCustomWallpaper,
+                                  wallpaper_files_id,
+                                  base::FilePath(wallpaper_info.location),
+                                  wallpaper_info.layout,
+                                  base::Passed(std::move(deep_copy))));
   }
 
   std::string relative_path =
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
index 9e20e63c..fdeab49 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -426,7 +426,6 @@
   auto provider = base::MakeUnique<BreakingNewsSuggestionsProvider>(
       service, std::move(handler), base::MakeUnique<base::DefaultClock>(),
       base::MakeUnique<RemoteSuggestionsDatabase>(database_dir, task_runner));
-  provider->Start();
   service->RegisterProvider(std::move(provider));
 }
 
@@ -535,8 +534,7 @@
   RegisterPrefetchingObserver(service, profile);
 #endif
 
-  if (base::FeatureList::IsEnabled(
-          ntp_snippets::kContentSuggestionsPushFeature)) {
+  if (base::FeatureList::IsEnabled(ntp_snippets::kBreakingNewsPushFeature)) {
     SubscribeForGCMPushUpdates(pref_service, service, profile);
   }
   return service;
diff --git a/chrome/browser/thumbnails/content_analysis.cc b/chrome/browser/thumbnails/content_analysis.cc
deleted file mode 100644
index 70743e6..0000000
--- a/chrome/browser/thumbnails/content_analysis.cc
+++ /dev/null
@@ -1,770 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/thumbnails/content_analysis.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <cmath>
-#include <deque>
-#include <functional>
-#include <limits>
-#include <numeric>
-#include <vector>
-
-#include "base/logging.h"
-#include "skia/ext/convolver.h"
-#include "skia/ext/recursive_gaussian_convolution.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkSize.h"
-#include "ui/gfx/color_analysis.h"
-
-namespace {
-
-const float kSigmaThresholdForRecursive = 1.5f;
-const float kAspectRatioToleranceFactor = 1.02f;
-
-template<class InputIterator, class OutputIterator, class Compare>
-void SlidingWindowMinMax(InputIterator first,
-                         InputIterator last,
-                         OutputIterator output,
-                         int window_size,
-                         Compare cmp) {
-  typedef std::deque<
-      std::pair<typename std::iterator_traits<InputIterator>::value_type, int> >
-          deque_type;
-  deque_type slider;
-  int front_tail_length = window_size / 2;
-  int i = 0;
-  DCHECK_LT(front_tail_length, last - first);
-  // This min-max filter functions the way image filters do. The min/max we
-  // compute is placed in the center of the window. Thus, first we need to
-  // 'pre-load' the window with the slider with right-tail of the filter.
-  for (; first < last && i < front_tail_length; ++i, ++first)
-    slider.push_back(std::make_pair(*first, i));
-
-  for (; first < last; ++i, ++first, ++output) {
-    while (!slider.empty() && !cmp(slider.back().first, *first))
-      slider.pop_back();
-    slider.push_back(std::make_pair(*first, i));
-
-    while (slider.front().second <= i - window_size)
-      slider.pop_front();
-    *output = slider.front().first;
-  }
-
-  // Now at the tail-end we will simply need to use whatever value is left of
-  // the filter to compute the remaining front_tail_length taps in the output.
-
-  // If input shorter than window, remainder length needs to be adjusted.
-  front_tail_length = std::min(front_tail_length, i);
-  for (; front_tail_length >= 0; --front_tail_length, ++i) {
-    while (slider.front().second <= i - window_size)
-      slider.pop_front();
-    *output = slider.front().first;
-  }
-}
-
-size_t FindOtsuThresholdingIndex(const std::vector<int>& histogram) {
-  // Otsu's method seeks to maximize variance between two classes of pixels
-  // correspondng to valleys and peaks of the profile.
-  double w1 = histogram[0];  // Total weight of the first class.
-  double t1 = 0.5 * w1;
-  double w2 = 0.0;
-  double t2 = 0.0;
-  for (size_t i = 1; i < histogram.size(); ++i) {
-    w2 += histogram[i];
-    t2 += (0.5 + i) * histogram[i];
-  }
-
-  size_t max_index = 0;
-  double m1 = t1 / w1;
-  double m2 = t2 / w2;
-  double max_variance_score = w1 * w2 * (m1 - m2) * (m1 - m2);
-  // Iterate through all possible ways of splitting the histogram.
-  for (size_t i = 1; i < histogram.size() - 1; i++) {
-    double bin_volume = (0.5 + i) * histogram[i];
-    w1 += histogram[i];
-    w2 -= histogram[i];
-    t2 -= bin_volume;
-    t1 += bin_volume;
-    m1 = t1 / w1;
-    m2 = t2 / w2;
-    double variance_score = w1 * w2 * (m1 - m2) * (m1 - m2);
-    if (variance_score >= max_variance_score) {
-      max_variance_score = variance_score;
-      max_index = i;
-    }
-  }
-
-  return max_index;
-}
-
-bool ComputeScaledHistogram(const std::vector<float>& source,
-                            std::vector<int>* histogram,
-                            std::pair<float, float>* minmax) {
-  DCHECK(histogram);
-  DCHECK(minmax);
-  histogram->clear();
-  histogram->resize(256);
-  float value_min = std::numeric_limits<float>::max();
-  float value_max = 0.0f;
-
-  std::vector<float>::const_iterator it;
-  for (it = source.begin(); it < source.end(); ++it) {
-    value_min = std::min(value_min, *it);
-    value_max = std::max(value_max, *it);
-  }
-
-  *minmax = std::make_pair(value_min, value_max);
-
-  if (value_max - value_min <= std::numeric_limits<float>::epsilon() * 100.0f) {
-    // Scaling won't work and there is nothing really to segment anyway.
-    return false;
-  }
-
-  float value_span = value_max - value_min;
-  float scale = 255.0f / value_span;
-  for (it = source.begin(); it < source.end(); ++it) {
-    float scaled_value = (*it - value_min) * scale;
-    (*histogram)[static_cast<int>(scaled_value)] += 1;
-  }
-  return true;
-}
-
-void ConstrainedProfileThresholding(const std::vector<float>& profile,
-                                    const std::vector<int>& histogram,
-                                    int current_clip_index,
-                                    float current_threshold,
-                                    const std::pair<float, float>& range,
-                                    int size_for_threshold,
-                                    int target_size,
-                                    std::vector<bool>* result) {
-  DCHECK(!profile.empty());
-  DCHECK_EQ(histogram.size(), 256U);
-  DCHECK(result);
-
-  // A subroutine performing thresholding on the |profile|.
-  if (size_for_threshold != target_size) {
-    // Find a cut-off point (on the histogram) closest to the desired size.
-    int candidate_size = profile.size();
-    int candidate_clip_index = 0;
-    for (std::vector<int>::const_iterator it = histogram.begin();
-         it != histogram.end(); ++it, ++candidate_clip_index) {
-      if (std::abs(candidate_size - target_size) <
-          std::abs(candidate_size - *it - target_size)) {
-        break;
-      }
-      candidate_size -= *it;
-    }
-
-    if (std::abs(candidate_size - target_size) <
-        std::abs(candidate_size -size_for_threshold)) {
-      current_clip_index = candidate_clip_index;
-      current_threshold =  (range.second - range.first) *
-          current_clip_index / 255.0f + range.first;
-      // Recount, rather than assume. One-offs due to rounding can be very
-      // harmful when eroding / dilating the result.
-      size_for_threshold = std::count_if(profile.begin(), profile.end(),
-                                         [current_threshold](float value) {
-                                           return value > current_threshold;
-                                         });
-    }
-  }
-
-  result->resize(profile.size());
-  for (size_t i = 0; i < profile.size(); ++i)
-    (*result)[i] = profile[i] > current_threshold;
-
-  while (size_for_threshold > target_size) {
-    // If the current size is larger than target size, erode exactly as needed.
-    std::vector<bool>::iterator mod_it = result->begin();
-    std::vector<bool>::const_iterator lead_it = result->begin();
-    bool prev_value = true;
-    for (++lead_it;
-         lead_it < result->end() && size_for_threshold > target_size;
-         ++lead_it, ++mod_it) {
-      bool value = *mod_it;
-      // If any neighbour is false, switch the element off.
-      if (!prev_value || !*lead_it) {
-        *mod_it = false;
-        --size_for_threshold;
-      }
-      prev_value = value;
-    }
-
-    if (lead_it == result->end() && !prev_value) {
-      *mod_it = false;
-      --size_for_threshold;
-    }
-  }
-
-  while (size_for_threshold < target_size) {
-    std::vector<bool>::iterator mod_it = result->begin();
-    std::vector<bool>::const_iterator lead_it = result->begin();
-    bool prev_value = false;
-    for (++lead_it;
-         lead_it < result->end() && size_for_threshold < target_size;
-         ++lead_it, ++mod_it) {
-      bool value = *mod_it;
-      // If any neighbour is false, switch the element off.
-      if (!prev_value || !*lead_it) {
-        *mod_it = true;
-        ++size_for_threshold;
-      }
-      prev_value = value;
-    }
-
-    if (lead_it == result->end() && !prev_value) {
-      *mod_it = true;
-      ++size_for_threshold;
-    }
-  }
-}
-
-}  // namespace
-
-namespace thumbnailing_utils {
-
-void ApplyGaussianGradientMagnitudeFilter(SkBitmap* input_bitmap,
-                                          float kernel_sigma) {
-  // The purpose of this function is to highlight salient
-  // (attention-attracting?) features of the image for use in image
-  // retargeting.
-  DCHECK(input_bitmap);
-  DCHECK(input_bitmap->getPixels());
-  DCHECK_EQ(kAlpha_8_SkColorType, input_bitmap->colorType());
-
-  // To perform computations we will need one intermediate buffer. It can
-  // very well be just another bitmap.
-  const SkISize image_size = SkISize::Make(input_bitmap->width(),
-                                           input_bitmap->height());
-  SkBitmap intermediate;
-  intermediate.allocPixels(input_bitmap->info().makeWH(image_size.width(),
-                                                       image_size.height()));
-
-  SkBitmap intermediate2;
-  intermediate2.allocPixels(input_bitmap->info().makeWH(image_size.width(),
-                                                        image_size.height()));
-
-  if (kernel_sigma <= kSigmaThresholdForRecursive) {
-    // For small kernels classic implementation is faster.
-    skia::ConvolutionFilter1D smoothing_filter;
-    skia::SetUpGaussianConvolutionKernel(
-        &smoothing_filter, kernel_sigma, false);
-    skia::SingleChannelConvolveX1D(
-        input_bitmap->getAddr8(0, 0),
-        static_cast<int>(input_bitmap->rowBytes()),
-        0, input_bitmap->bytesPerPixel(),
-        smoothing_filter,
-        image_size,
-        intermediate.getAddr8(0, 0),
-        static_cast<int>(intermediate.rowBytes()),
-        0, intermediate.bytesPerPixel(), false);
-    skia::SingleChannelConvolveY1D(
-        intermediate.getAddr8(0, 0),
-        static_cast<int>(intermediate.rowBytes()),
-        0, intermediate.bytesPerPixel(),
-        smoothing_filter,
-        image_size,
-        input_bitmap->getAddr8(0, 0),
-        static_cast<int>(input_bitmap->rowBytes()),
-        0, input_bitmap->bytesPerPixel(), false);
-
-    skia::ConvolutionFilter1D gradient_filter;
-    skia::SetUpGaussianConvolutionKernel(&gradient_filter, kernel_sigma, true);
-    skia::SingleChannelConvolveX1D(
-        input_bitmap->getAddr8(0, 0),
-        static_cast<int>(input_bitmap->rowBytes()),
-        0, input_bitmap->bytesPerPixel(),
-        gradient_filter,
-        image_size,
-        intermediate.getAddr8(0, 0),
-        static_cast<int>(intermediate.rowBytes()),
-        0, intermediate.bytesPerPixel(), true);
-    skia::SingleChannelConvolveY1D(
-        input_bitmap->getAddr8(0, 0),
-        static_cast<int>(input_bitmap->rowBytes()),
-        0, input_bitmap->bytesPerPixel(),
-        gradient_filter,
-        image_size,
-        intermediate2.getAddr8(0, 0),
-        static_cast<int>(intermediate2.rowBytes()),
-        0, intermediate2.bytesPerPixel(), true);
-  } else {
-    // For larger sigma values use the recursive filter.
-    skia::RecursiveFilter smoothing_filter(kernel_sigma,
-                                           skia::RecursiveFilter::FUNCTION);
-    skia::SingleChannelRecursiveGaussianX(
-        input_bitmap->getAddr8(0, 0),
-        static_cast<int>(input_bitmap->rowBytes()),
-        0, input_bitmap->bytesPerPixel(),
-        smoothing_filter,
-        image_size,
-        intermediate.getAddr8(0, 0),
-        static_cast<int>(intermediate.rowBytes()),
-        0, intermediate.bytesPerPixel(), false);
-    unsigned char smoothed_max = skia::SingleChannelRecursiveGaussianY(
-        intermediate.getAddr8(0, 0),
-        static_cast<int>(intermediate.rowBytes()),
-        0, intermediate.bytesPerPixel(),
-        smoothing_filter,
-        image_size,
-        input_bitmap->getAddr8(0, 0),
-        static_cast<int>(input_bitmap->rowBytes()),
-        0, input_bitmap->bytesPerPixel(), false);
-    if (smoothed_max < 127) {
-      int bit_shift = 8 - static_cast<int>(
-          std::log10(static_cast<float>(smoothed_max)) / std::log10(2.0f));
-      for (int r = 0; r < image_size.height(); ++r) {
-        uint8_t* row = input_bitmap->getAddr8(0, r);
-        for (int c = 0; c < image_size.width(); ++c, ++row) {
-          *row <<= bit_shift;
-        }
-      }
-    }
-
-    skia::RecursiveFilter gradient_filter(
-        kernel_sigma, skia::RecursiveFilter::FIRST_DERIVATIVE);
-    skia::SingleChannelRecursiveGaussianX(
-        input_bitmap->getAddr8(0, 0),
-        static_cast<int>(input_bitmap->rowBytes()),
-        0, input_bitmap->bytesPerPixel(),
-        gradient_filter,
-        image_size,
-        intermediate.getAddr8(0, 0),
-        static_cast<int>(intermediate.rowBytes()),
-        0, intermediate.bytesPerPixel(), true);
-    skia::SingleChannelRecursiveGaussianY(
-        input_bitmap->getAddr8(0, 0),
-        static_cast<int>(input_bitmap->rowBytes()),
-        0, input_bitmap->bytesPerPixel(),
-        gradient_filter,
-        image_size,
-        intermediate2.getAddr8(0, 0),
-        static_cast<int>(intermediate2.rowBytes()),
-        0, intermediate2.bytesPerPixel(), true);
-  }
-
-  unsigned grad_max = 0;
-  for (int r = 0; r < image_size.height(); ++r) {
-    const uint8_t* grad_x_row = intermediate.getAddr8(0, r);
-    const uint8_t* grad_y_row = intermediate2.getAddr8(0, r);
-    for (int c = 0; c < image_size.width(); ++c) {
-      unsigned grad_x = grad_x_row[c];
-      unsigned grad_y = grad_y_row[c];
-      grad_max = std::max(grad_max, grad_x * grad_x + grad_y * grad_y);
-    }
-  }
-
-  int bit_shift = 0;
-  if (grad_max > 255)
-    bit_shift = static_cast<int>(
-        std::log10(static_cast<float>(grad_max)) / std::log10(2.0f)) - 7;
-  for (int r = 0; r < image_size.height(); ++r) {
-    const uint8_t* grad_x_row = intermediate.getAddr8(0, r);
-    const uint8_t* grad_y_row = intermediate2.getAddr8(0, r);
-    uint8_t* target_row = input_bitmap->getAddr8(0, r);
-    for (int c = 0; c < image_size.width(); ++c) {
-      unsigned grad_x = grad_x_row[c];
-      unsigned grad_y = grad_y_row[c];
-      target_row[c] = (grad_x * grad_x + grad_y * grad_y) >> bit_shift;
-    }
-  }
-}
-
-void ExtractImageProfileInformation(const SkBitmap& input_bitmap,
-                                    const gfx::Rect& area,
-                                    const gfx::Size& target_size,
-                                    bool apply_log,
-                                    std::vector<float>* rows,
-                                    std::vector<float>* columns) {
-  DCHECK(rows);
-  DCHECK(columns);
-  DCHECK(input_bitmap.getPixels());
-  DCHECK_EQ(kAlpha_8_SkColorType, input_bitmap.colorType());
-  DCHECK_GE(area.x(), 0);
-  DCHECK_GE(area.y(), 0);
-  DCHECK_LE(area.right(), input_bitmap.width());
-  DCHECK_LE(area.bottom(), input_bitmap.height());
-
-  // Make sure rows and columns are allocated and initialized to 0.
-  rows->clear();
-  columns->clear();
-  rows->resize(area.height(), 0);
-  columns->resize(area.width(), 0);
-
-  for (int r = 0; r < area.height(); ++r) {
-    // Points to the first byte of the row in the rectangle.
-    const uint8_t* image_row = input_bitmap.getAddr8(area.x(), r + area.y());
-    unsigned row_sum = 0;
-    for (int c = 0; c < area.width(); ++c, ++image_row) {
-      row_sum += *image_row;
-      (*columns)[c] += *image_row;
-    }
-    (*rows)[r] = row_sum;
-  }
-
-  if (apply_log) {
-    // Generally for processing we will need to take logarithm of this data.
-    // The option not to apply it is left principally as a test seam.
-    std::vector<float>::iterator it;
-    for (it = columns->begin(); it < columns->end(); ++it)
-      *it = std::log(1.0f + *it);
-
-    for (it = rows->begin(); it < rows->end(); ++it)
-      *it = std::log(1.0f + *it);
-  }
-
-  if (!target_size.IsEmpty()) {
-    // If the target size is given, profiles should be further processed through
-    // morphological closing. The idea is to close valleys smaller than what
-    // can be seen after scaling down to avoid deforming noticable features
-    // when profiles are used.
-    // Morphological closing is defined as dilation followed by errosion. In
-    // normal-speak: sliding-window maximum followed by minimum.
-    int column_window_size = 1 + 2 *
-        static_cast<int>(0.5f * area.width() / target_size.width() + 0.5f);
-    int row_window_size = 1 + 2 *
-        static_cast<int>(0.5f * area.height() / target_size.height() + 0.5f);
-
-    // Dilate and erode each profile with the given window size.
-    if (column_window_size >= 3) {
-      SlidingWindowMinMax(columns->begin(),
-                          columns->end(),
-                          columns->begin(),
-                          column_window_size,
-                          std::greater<float>());
-      SlidingWindowMinMax(columns->begin(),
-                          columns->end(),
-                          columns->begin(),
-                          column_window_size,
-                          std::less<float>());
-    }
-
-    if (row_window_size >= 3) {
-      SlidingWindowMinMax(rows->begin(),
-                          rows->end(),
-                          rows->begin(),
-                          row_window_size,
-                          std::greater<float>());
-      SlidingWindowMinMax(rows->begin(),
-                          rows->end(),
-                          rows->begin(),
-                          row_window_size,
-                          std::less<float>());
-    }
-  }
-}
-
-float AutoSegmentPeaks(const std::vector<float>& input) {
-  // This is a thresholding operation based on Otsu's method.
-  std::vector<int> histogram;
-  std::pair<float, float> minmax;
-  if (!ComputeScaledHistogram(input, &histogram, &minmax))
-    return minmax.first;
-
-  // max_index refers to the bin *after* which we need to split. The sought
-  // threshold is the centre of this bin, scaled back to the original range.
-  size_t max_index = FindOtsuThresholdingIndex(histogram);
-  return (minmax.second - minmax.first) * (max_index + 0.5f) / 255.0f +
-      minmax.first;
-}
-
-gfx::Size AdjustClippingSizeToAspectRatio(const gfx::Size& target_size,
-                                          const gfx::Size& image_size,
-                                          const gfx::Size& computed_size) {
-  DCHECK_GT(target_size.width(), 0);
-  DCHECK_GT(target_size.height(), 0);
-  // If the computed thumbnail would be too wide or to tall, we shall attempt
-  // to fix it. Generally the idea is to re-add content to the part which has
-  // been more aggressively shrunk unless there is nothing to add there or if
-  // adding there won't fix anything. Should that be the case,  we will
-  // (reluctantly) take away more from the other dimension.
-  float desired_aspect =
-      static_cast<float>(target_size.width()) / target_size.height();
-  int computed_width = std::max(computed_size.width(), target_size.width());
-  int computed_height = std::max(computed_size.height(), target_size.height());
-  float computed_aspect = static_cast<float>(computed_width) / computed_height;
-  float aspect_change_delta = std::abs(computed_aspect - desired_aspect);
-  float prev_aspect_change_delta = 1000.0f;
-  const float kAspectChangeEps = 0.01f;
-  const float kLargeEffect = 2.0f;
-
-  while ((prev_aspect_change_delta - aspect_change_delta > kAspectChangeEps) &&
-         (computed_aspect / desired_aspect > kAspectRatioToleranceFactor ||
-          desired_aspect / computed_aspect > kAspectRatioToleranceFactor)) {
-    int new_computed_width = computed_width;
-    int new_computed_height = computed_height;
-    float row_dimension_shrink =
-        static_cast<float>(image_size.height()) / computed_height;
-    float column_dimension_shrink =
-        static_cast<float>(image_size.width()) / computed_width;
-
-    if (computed_aspect / desired_aspect > kAspectRatioToleranceFactor) {
-      // Too wide.
-      if (row_dimension_shrink > column_dimension_shrink) {
-        // Bring the computed_height to the least of:
-        // (1) image height (2) the number of lines that would
-        // make up the desired aspect or (3) number of lines we would get
-        // at the same 'aggressivity' level as width or.
-        new_computed_height = std::min(
-            static_cast<int>(image_size.height()),
-            static_cast<int>(computed_width / desired_aspect + 0.5f));
-        new_computed_height = std::min(
-            new_computed_height,
-            static_cast<int>(
-                image_size.height() / column_dimension_shrink + 0.5f));
-      } else if (row_dimension_shrink >= kLargeEffect ||
-                 new_computed_width <= target_size.width()) {
-        // Even though rows were resized less, we will generally rather add than
-        // remove (or there is nothing to remove in x already).
-        new_computed_height = std::min(
-            static_cast<int>(image_size.height()),
-            static_cast<int>(computed_width / desired_aspect + 0.5f));
-      } else {
-        // Rows were already shrunk less aggressively. This means there is
-        // simply no room left too expand. Cut columns to get the desired
-        // aspect ratio.
-        new_computed_width = desired_aspect * computed_height + 0.5f;
-      }
-    } else {
-      // Too tall.
-      if (column_dimension_shrink > row_dimension_shrink) {
-        // Columns were shrunk more aggressively. Try to relax the same way as
-        // above.
-        new_computed_width = std::min(
-            static_cast<int>(image_size.width()),
-            static_cast<int>(desired_aspect * computed_height + 0.5f));
-        new_computed_width = std::min(
-            new_computed_width,
-            static_cast<int>(
-                image_size.width() / row_dimension_shrink  + 0.5f));
-      } else if (column_dimension_shrink  >= kLargeEffect ||
-                 new_computed_height <= target_size.height()) {
-        new_computed_width = std::min(
-            static_cast<int>(image_size.width()),
-            static_cast<int>(desired_aspect * computed_height + 0.5f));
-      } else {
-        new_computed_height = computed_width / desired_aspect + 0.5f;
-      }
-    }
-
-    new_computed_width = std::max(new_computed_width, target_size.width());
-    new_computed_height = std::max(new_computed_height, target_size.height());
-
-    // Update loop control variables.
-    float new_computed_aspect =
-        static_cast<float>(new_computed_width) / new_computed_height;
-
-    if (std::abs(new_computed_aspect - desired_aspect) >
-        std::abs(computed_aspect - desired_aspect)) {
-      // Do not take inferior results.
-      break;
-    }
-
-    computed_width = new_computed_width;
-    computed_height = new_computed_height;
-    computed_aspect = new_computed_aspect;
-    prev_aspect_change_delta = aspect_change_delta;
-    aspect_change_delta = std::abs(new_computed_aspect - desired_aspect);
-  }
-
-  return gfx::Size(computed_width, computed_height);
-}
-
-void ConstrainedProfileSegmentation(const std::vector<float>& row_profile,
-                                    const std::vector<float>& column_profile,
-                                    const gfx::Size& target_size,
-                                    std::vector<bool>* included_rows,
-                                    std::vector<bool>* included_columns) {
-  DCHECK(included_rows);
-  DCHECK(included_columns);
-
-  std::vector<int> histogram_rows;
-  std::pair<float, float> minmax_rows;
-  bool rows_well_behaved = ComputeScaledHistogram(
-      row_profile, &histogram_rows, &minmax_rows);
-
-  float row_threshold = minmax_rows.first;
-  size_t clip_index_rows = 0;
-
-  if (rows_well_behaved) {
-    clip_index_rows = FindOtsuThresholdingIndex(histogram_rows);
-    row_threshold = (minmax_rows.second - minmax_rows.first) *
-        (clip_index_rows + 0.5f) / 255.0f + minmax_rows.first;
-  }
-
-  std::vector<int> histogram_columns;
-  std::pair<float, float> minmax_columns;
-  bool columns_well_behaved = ComputeScaledHistogram(column_profile,
-                                                     &histogram_columns,
-                                                     &minmax_columns);
-  float column_threshold = minmax_columns.first;
-  size_t clip_index_columns = 0;
-
-  if (columns_well_behaved) {
-    clip_index_columns = FindOtsuThresholdingIndex(histogram_columns);
-    column_threshold = (minmax_columns.second - minmax_columns.first) *
-        (clip_index_columns + 0.5f) / 255.0f + minmax_columns.first;
-  }
-
-  int auto_segmented_width = count_if(
-      column_profile.begin(), column_profile.end(),
-      [column_threshold](float value) { return value > column_threshold; });
-  int auto_segmented_height =
-      count_if(row_profile.begin(), row_profile.end(),
-               [row_threshold](float value) { return value > row_threshold; });
-
-  gfx::Size computed_size = AdjustClippingSizeToAspectRatio(
-      target_size,
-      gfx::Size(column_profile.size(), row_profile.size()),
-      gfx::Size(auto_segmented_width, auto_segmented_height));
-
-  // Apply thresholding.
-  if (rows_well_behaved) {
-    ConstrainedProfileThresholding(row_profile,
-                                   histogram_rows,
-                                   clip_index_rows,
-                                   row_threshold,
-                                   minmax_rows,
-                                   auto_segmented_height,
-                                   computed_size.height(),
-                                   included_rows);
-  } else {
-    // This is essentially an error condition, invoked when no segmentation was
-    // possible. This will result in applying a very low threshold and likely
-    // in producing a thumbnail which should get rejected.
-    included_rows->resize(row_profile.size());
-    for (size_t i = 0; i < row_profile.size(); ++i)
-      (*included_rows)[i] = row_profile[i] > row_threshold;
-  }
-
-  if (columns_well_behaved) {
-    ConstrainedProfileThresholding(column_profile,
-                                   histogram_columns,
-                                   clip_index_columns,
-                                   column_threshold,
-                                   minmax_columns,
-                                   auto_segmented_width,
-                                   computed_size.width(),
-                                   included_columns);
-  } else {
-    included_columns->resize(column_profile.size());
-    for (size_t i = 0; i < column_profile.size(); ++i)
-      (*included_columns)[i] = column_profile[i] > column_threshold;
-  }
-}
-
-SkBitmap ComputeDecimatedImage(const SkBitmap& bitmap,
-                               const std::vector<bool>& rows,
-                               const std::vector<bool>& columns) {
-  DCHECK(bitmap.getPixels());
-  DCHECK_GT(bitmap.bytesPerPixel(), 0);
-  DCHECK_EQ(bitmap.width(), static_cast<int>(columns.size()));
-  DCHECK_EQ(bitmap.height(), static_cast<int>(rows.size()));
-
-  unsigned target_row_count = std::count(rows.begin(), rows.end(), true);
-  unsigned target_column_count = std::count(
-      columns.begin(), columns.end(), true);
-
-  if (target_row_count == 0 || target_column_count == 0)
-    return SkBitmap();  // Not quite an error, so no DCHECK. Just return empty.
-
-  if (target_row_count == rows.size() && target_column_count == columns.size())
-    return SkBitmap();  // Equivalent of the situation above (empty target).
-
-  // Allocate the target image.
-  SkBitmap target;
-  target.allocPixels(bitmap.info().makeWH(target_column_count,
-                                          target_row_count));
-
-  int target_row = 0;
-  for (int r = 0; r < bitmap.height(); ++r) {
-    if (!rows[r])
-      continue;  // We can just skip this one.
-    uint8_t* src_row =
-        static_cast<uint8_t*>(bitmap.getPixels()) + r * bitmap.rowBytes();
-    uint8_t* insertion_target = static_cast<uint8_t*>(target.getPixels()) +
-                                target_row * target.rowBytes();
-    int left_copy_pixel = -1;
-    for (int c = 0; c < bitmap.width(); ++c) {
-      if (left_copy_pixel < 0 && columns[c]) {
-        left_copy_pixel = c;  // Next time we will start copying from here.
-      } else if (left_copy_pixel >= 0 && !columns[c]) {
-        // This closes a fragment we want to copy. We do it now.
-        size_t bytes_to_copy = (c - left_copy_pixel) * bitmap.bytesPerPixel();
-        memcpy(insertion_target,
-               src_row + left_copy_pixel * bitmap.bytesPerPixel(),
-               bytes_to_copy);
-        left_copy_pixel = -1;
-        insertion_target += bytes_to_copy;
-      }
-    }
-    // We can still have the tail end to process here.
-    if (left_copy_pixel >= 0) {
-      size_t bytes_to_copy =
-          (bitmap.width() - left_copy_pixel) * bitmap.bytesPerPixel();
-      memcpy(insertion_target,
-             src_row + left_copy_pixel * bitmap.bytesPerPixel(),
-             bytes_to_copy);
-    }
-    target_row++;
-  }
-
-  return target;
-}
-
-SkBitmap CreateRetargetedThumbnailImage(
-    const SkBitmap& source_bitmap,
-    const gfx::Size& target_size,
-    float kernel_sigma) {
-  // First thing we need for this method is to color-reduce the source_bitmap.
-  SkBitmap reduced_color;
-  reduced_color.allocPixels(SkImageInfo::MakeA8(source_bitmap.width(),
-                                                source_bitmap.height()));
-
-  if (!color_utils::ComputePrincipalComponentImage(source_bitmap,
-                                                   &reduced_color)) {
-    // CCIR601 luminance conversion vector.
-    gfx::Vector3dF transform(0.299f, 0.587f, 0.114f);
-    if (!color_utils::ApplyColorReduction(
-            source_bitmap, transform, true, &reduced_color)) {
-      DLOG(WARNING) << "Failed to compute luminance image from a screenshot. "
-                    << "Cannot compute retargeted thumbnail.";
-      return SkBitmap();
-    }
-    DLOG(WARNING) << "Could not compute principal color image for a thumbnail. "
-                  << "Using luminance instead.";
-  }
-
-  // Turn 'color-reduced' image into the 'energy' image.
-  ApplyGaussianGradientMagnitudeFilter(&reduced_color, kernel_sigma);
-
-  // Extract vertical and horizontal projection of image features.
-  std::vector<float> row_profile;
-  std::vector<float> column_profile;
-  ExtractImageProfileInformation(reduced_color,
-                                 gfx::Rect(reduced_color.width(),
-                                           reduced_color.height()),
-                                 target_size,
-                                 true,
-                                 &row_profile,
-                                 &column_profile);
-
-  std::vector<bool> included_rows, included_columns;
-  ConstrainedProfileSegmentation(row_profile,
-                                 column_profile,
-                                 target_size,
-                                 &included_rows,
-                                 &included_columns);
-
-  // Use the original image and computed inclusion vectors to create a resized
-  // image.
-  return ComputeDecimatedImage(source_bitmap, included_rows, included_columns);
-}
-
-}  // namespace thumbnailing_utils
diff --git a/chrome/browser/thumbnails/content_analysis.h b/chrome/browser/thumbnails/content_analysis.h
deleted file mode 100644
index f9d0029..0000000
--- a/chrome/browser/thumbnails/content_analysis.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_THUMBNAILS_CONTENT_ANALYSIS_H_
-#define CHROME_BROWSER_THUMBNAILS_CONTENT_ANALYSIS_H_
-
-#include <vector>
-
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-
-class SkBitmap;
-
-namespace thumbnailing_utils {
-
-// Compute in-place gaussian gradient magnitude of |input_bitmap| with sigma
-// |kernel_sigma|. |input_bitmap| is requried to be of SkBitmap::kA8_Config
-// type. The routine computes first-order gaussian derivative on a
-// gaussian-smoothed image. Beware, this is fairly slow since kernel size is
-// 4 * kernel_sigma + 1.
-void ApplyGaussianGradientMagnitudeFilter(SkBitmap* input_bitmap,
-                                          float kernel_sigma);
-
-// Accumulates vertical and horizontal sum of pixel values from a subsection of
-// |input_bitmap| defined by |image_area|. The image is required to be of
-// SkBitmap::kA8_Config type.
-// If non-empty |target_size| is given, the routine will use it to process the
-// profiles with closing operator sized to eliminate gaps which would be smaller
-// than 1 pixel after rescaling to |target_size|.
-// If |apply_log| is true, logarithm of counts are used for morhology (and
-// returned).
-void ExtractImageProfileInformation(const SkBitmap& input_bitmap,
-                                    const gfx::Rect& image_area,
-                                    const gfx::Size& target_size,
-                                    bool apply_log,
-                                    std::vector<float>* rows,
-                                    std::vector<float>* columns);
-
-// Compute a threshold value separating background (low) from signal (high)
-// areas in the |input| profile.
-float AutoSegmentPeaks(const std::vector<float>& input);
-
-// Compute and return a workable (not too distorted, not bigger than the image)
-// target size for retargeting in ConstrainedProfileSegmentation. |target_size|
-// is the desired image size (defines aspect ratio and minimal image size) while
-// |computed_size| is the size of a result of unconstrained segmentation.
-// This routine makes very little sense outside ConstrainedProfileSegmentation
-// and is exposed only for unit tests (it is somehow complicated).
-gfx::Size AdjustClippingSizeToAspectRatio(const gfx::Size& target_size,
-                                          const gfx::Size& image_size,
-                                          const gfx::Size& computed_size);
-
-// Compute thresholding guides |included_rows| and |included_columns| by
-// segmenting 1-d profiles |row_profile| and |column_profile|. The routine will
-// attempt to keep the image which would result from using these guides as close
-// to the desired aspect ratio (given by |target_size|) as reasonable.
-void ConstrainedProfileSegmentation(const std::vector<float>& row_profile,
-                                    const std::vector<float>& column_profile,
-                                    const gfx::Size& target_size,
-                                    std::vector<bool>* included_rows,
-                                    std::vector<bool>* included_columns);
-
-// Shrinks the source |bitmap| by removing rows and columns where |rows| and
-// |columns| are false, respectively. The function returns a new bitmap if the
-// shrinking can be performed and an empty instance otherwise.
-SkBitmap ComputeDecimatedImage(const SkBitmap& bitmap,
-                               const std::vector<bool>& rows,
-                               const std::vector<bool>& columns);
-
-// Creates a new bitmap which contains only 'interesting' areas of
-// |source_bitmap|. The |target_size| is used to estimate some computation
-// parameters, but the resulting bitmap will not necessarily be of that size.
-// |kernel_sigma| defines the degree of image smoothing in gradient computation.
-// For a natural-sized (not shrunk) screenshot at 96 DPI and regular font size
-// 5.0 was determined to be a good value.
-SkBitmap CreateRetargetedThumbnailImage(const SkBitmap& source_bitmap,
-                                        const gfx::Size& target_size,
-                                        float kernel_sigma);
-
-}  // namespace thumbnailing_utils
-
-#endif  // CHROME_BROWSER_THUMBNAILS_CONTENT_ANALYSIS_H_
diff --git a/chrome/browser/thumbnails/content_analysis_unittest.cc b/chrome/browser/thumbnails/content_analysis_unittest.cc
deleted file mode 100644
index 387da01e..0000000
--- a/chrome/browser/thumbnails/content_analysis_unittest.cc
+++ /dev/null
@@ -1,687 +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 "chrome/browser/thumbnails/content_analysis.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <cmath>
-#include <cstdlib>
-#include <functional>
-#include <limits>
-#include <memory>
-#include <numeric>
-#include <vector>
-
-#include "skia/ext/platform_canvas.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/color_analysis.h"
-#include "ui/gfx/color_utils.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/image/image.h"
-
-namespace {
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-unsigned long ImagePixelSum(const SkBitmap& bitmap, const gfx::Rect& rect) {
-  // Get the sum of pixel values in the rectangle. Applicable only to
-  // monochrome bitmaps.
-  DCHECK_EQ(kAlpha_8_SkColorType, bitmap.colorType());
-  unsigned long total = 0;
-  for (int r = rect.y(); r < rect.bottom(); ++r) {
-    const uint8_t* row_data =
-        static_cast<const uint8_t*>(bitmap.getPixels()) + r * bitmap.rowBytes();
-    for (int c = rect.x(); c < rect.right(); ++c)
-      total += row_data[c];
-  }
-
-  return total;
-}
-
-bool CompareImageFragments(const SkBitmap& bitmap_left,
-                           const SkBitmap& bitmap_right,
-                           const gfx::Size& comparison_area,
-                           const gfx::Point& origin_left,
-                           const gfx::Point& origin_right) {
-  for (int r = 0; r < comparison_area.height(); ++r) {
-    for (int c = 0; c < comparison_area.width(); ++c) {
-      SkColor color_left = bitmap_left.getColor(origin_left.x() + c,
-                                                origin_left.y() + r);
-      SkColor color_right = bitmap_right.getColor(origin_right.x() + c,
-                                                  origin_right.y() + r);
-      if (color_left != color_right)
-        return false;
-    }
-  }
-
-  return true;
-}
-
-float AspectDifference(const gfx::Size& reference, const gfx::Size& candidate) {
-  return std::abs(static_cast<float>(candidate.width()) / candidate.height() -
-                  static_cast<float>(reference.width()) / reference.height());
-}
-
-}  // namespace
-
-namespace thumbnailing_utils {
-
-class ThumbnailContentAnalysisTest : public testing::Test {
-};
-
-TEST_F(ThumbnailContentAnalysisTest, ApplyGradientMagnitudeOnImpulse) {
-  gfx::Canvas canvas(gfx::Size(800, 600), 1.0f, true);
-
-  // The image consists of a point spike on uniform (non-zero) background.
-  canvas.FillRect(gfx::Rect(0, 0, 800, 600), SkColorSetRGB(10, 10, 10));
-  canvas.FillRect(gfx::Rect(400, 300, 1, 1), SkColorSetRGB(255, 255, 255));
-
-  SkBitmap source = canvas.GetBitmap();
-
-  SkBitmap reduced_color;
-  reduced_color.allocPixels(SkImageInfo::MakeA8(source.width(),
-                                                source.height()));
-
-  gfx::Vector3dF transform(0.299f, 0.587f, 0.114f);
-  EXPECT_TRUE(color_utils::ApplyColorReduction(
-      source, transform, true, &reduced_color));
-
-  float sigma = 2.5f;
-  ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma);
-
-  // Expect everything to be within 8 * sigma.
-  int tail_length = static_cast<int>(8.0f * sigma + 0.5f);
-  gfx::Rect echo_rect(399 - tail_length, 299 - tail_length,
-                      2 * tail_length + 1, 2 * tail_length + 1);
-  unsigned long data_sum = ImagePixelSum(reduced_color, echo_rect);
-  unsigned long all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600));
-  EXPECT_GT(data_sum, 0U);
-  EXPECT_EQ(data_sum, all_sum);
-
-  sigma = 5.0f;
-  ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma);
-
-  // Expect everything to be within 8 * sigma.
-  tail_length = static_cast<int>(8.0f * sigma + 0.5f);
-  echo_rect = gfx::Rect(399 - tail_length, 299 - tail_length,
-                        2 * tail_length + 1, 2 * tail_length + 1);
-  data_sum = ImagePixelSum(reduced_color, echo_rect);
-  all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600));
-  EXPECT_GT(data_sum, 0U);
-  EXPECT_EQ(data_sum, all_sum);
-}
-
-TEST_F(ThumbnailContentAnalysisTest, ApplyGradientMagnitudeOnFrame) {
-  gfx::Canvas canvas(gfx::Size(800, 600), 1.0f, true);
-
-  // The image consists of a single white block in the centre.
-  gfx::RectF draw_rect(300, 200, 200, 200);
-  canvas.FillRect(gfx::Rect(0, 0, 800, 600), SkColorSetRGB(0, 0, 0));
-  canvas.DrawRect(draw_rect, SkColorSetRGB(255, 255, 255));
-
-  SkBitmap source = canvas.GetBitmap();
-
-  SkBitmap reduced_color;
-  reduced_color.allocPixels(SkImageInfo::MakeA8(source.width(),
-                                                source.height()));
-
-  gfx::Vector3dF transform(0.299f, 0.587f, 0.114f);
-  EXPECT_TRUE(color_utils::ApplyColorReduction(
-      source, transform, true, &reduced_color));
-
-  float sigma = 2.5f;
-  ApplyGaussianGradientMagnitudeFilter(&reduced_color, sigma);
-
-  int tail_length = static_cast<int>(8.0f * sigma + 0.5f);
-  gfx::Rect outer_rect(draw_rect.x() - tail_length,
-                       draw_rect.y() - tail_length,
-                       draw_rect.width() + 2 * tail_length,
-                       draw_rect.height() + 2 * tail_length);
-  gfx::Rect inner_rect(draw_rect.x() + tail_length,
-                       draw_rect.y() + tail_length,
-                       draw_rect.width() - 2 * tail_length,
-                       draw_rect.height() - 2 * tail_length);
-  unsigned long data_sum = ImagePixelSum(reduced_color, outer_rect);
-  unsigned long all_sum = ImagePixelSum(reduced_color, gfx::Rect(800, 600));
-  EXPECT_GT(data_sum, 0U);
-  EXPECT_EQ(data_sum, all_sum);
-  EXPECT_EQ(ImagePixelSum(reduced_color, inner_rect), 0U);
-}
-
-TEST_F(ThumbnailContentAnalysisTest, ExtractImageProfileInformation) {
-  gfx::Canvas canvas(gfx::Size(800, 600), 1.0f, true);
-
-  // The image consists of a white frame drawn in the centre.
-  gfx::RectF draw_rect(100, 100, 200, 100);
-  gfx::Rect image_rect(0, 0, 800, 600);
-  canvas.FillRect(image_rect, SkColorSetRGB(0, 0, 0));
-  canvas.DrawRect(draw_rect, SkColorSetRGB(255, 255, 255));
-
-  SkBitmap source = canvas.GetBitmap();
-  SkBitmap reduced_color;
-  reduced_color.allocPixels(SkImageInfo::MakeA8(source.width(),
-                                                source.height()));
-
-  gfx::Vector3dF transform(1, 0, 0);
-  EXPECT_TRUE(color_utils::ApplyColorReduction(
-      source, transform, true, &reduced_color));
-  std::vector<float> column_profile;
-  std::vector<float> row_profile;
-  ExtractImageProfileInformation(reduced_color,
-                                 image_rect,
-                                 gfx::Size(),
-                                 false,
-                                 &row_profile,
-                                 &column_profile);
-  EXPECT_EQ(0, std::accumulate(column_profile.begin(),
-                               column_profile.begin() + draw_rect.x() - 1,
-                               0));
-  EXPECT_EQ(column_profile[draw_rect.x()], 255U * (draw_rect.height() + 1));
-  EXPECT_EQ(2 * 255 * (draw_rect.width() - 2),
-            std::accumulate(column_profile.begin() + draw_rect.x() + 1,
-                            column_profile.begin() + draw_rect.right() - 1,
-                            0));
-
-  EXPECT_EQ(0, std::accumulate(row_profile.begin(),
-                               row_profile.begin() + draw_rect.y() - 1,
-                               0));
-  EXPECT_EQ(row_profile[draw_rect.y()], 255U * (draw_rect.width() + 1));
-  EXPECT_EQ(2 * 255 * (draw_rect.height() - 2),
-            std::accumulate(row_profile.begin() + draw_rect.y() + 1,
-                            row_profile.begin() + draw_rect.bottom() - 1,
-                            0));
-
-  gfx::Rect test_rect(150, 80, 400, 100);
-  ExtractImageProfileInformation(reduced_color,
-                                 test_rect,
-                                 gfx::Size(),
-                                 false,
-                                 &row_profile,
-                                 &column_profile);
-
-  // Some overlap with the drawn rectagle. If you work it out on a piece of
-  // paper, sums should be as follows.
-  EXPECT_EQ(255 * (test_rect.bottom() - draw_rect.y()) +
-            255 * (draw_rect.right() - test_rect.x()),
-            std::accumulate(row_profile.begin(), row_profile.end(), 0));
-  EXPECT_EQ(255 * (test_rect.bottom() - draw_rect.y()) +
-            255 * (draw_rect.right() - test_rect.x()),
-            std::accumulate(column_profile.begin(), column_profile.end(), 0));
-}
-
-TEST_F(ThumbnailContentAnalysisTest,
-       ExtractImageProfileInformationWithClosing) {
-  gfx::Canvas canvas(gfx::Size(800, 600), 1.0f, true);
-
-  // The image consists of a two white frames drawn side by side, with a
-  // single-pixel vertical gap in between.
-  gfx::Rect image_rect(0, 0, 800, 600);
-  canvas.FillRect(image_rect, SkColorSetRGB(0, 0, 0));
-  canvas.DrawRect(gfx::RectF(300, 250, 99, 100), SkColorSetRGB(255, 255, 255));
-  canvas.DrawRect(gfx::RectF(401, 250, 99, 100), SkColorSetRGB(255, 255, 255));
-
-  SkBitmap source = canvas.GetBitmap();
-  SkBitmap reduced_color;
-  reduced_color.allocPixels(SkImageInfo::MakeA8(source.width(),
-                                                source.height()));
-
-  gfx::Vector3dF transform(1, 0, 0);
-  EXPECT_TRUE(color_utils::ApplyColorReduction(
-      source, transform, true, &reduced_color));
-  std::vector<float> column_profile;
-  std::vector<float> row_profile;
-
-  ExtractImageProfileInformation(reduced_color,
-                                 image_rect,
-                                 gfx::Size(),
-                                 true,
-                                 &row_profile,
-                                 &column_profile);
-  // Column profiles should have two spikes in the middle, with a single
-  // 0-valued value between them.
-  EXPECT_GT(column_profile[398], 0.0f);
-  EXPECT_GT(column_profile[399], column_profile[398]);
-  EXPECT_GT(column_profile[402], 0.0f);
-  EXPECT_GT(column_profile[401], column_profile[402]);
-  EXPECT_EQ(column_profile[401], column_profile[399]);
-  EXPECT_EQ(column_profile[402], column_profile[398]);
-  EXPECT_EQ(column_profile[400], 0.0f);
-  EXPECT_EQ(column_profile[299], 0.0f);
-  EXPECT_EQ(column_profile[502], 0.0f);
-
-  // Now the same with closing applied. The space in the middle will be closed.
-  ExtractImageProfileInformation(reduced_color,
-                                 image_rect,
-                                 gfx::Size(200, 100),
-                                 true,
-                                 &row_profile,
-                                 &column_profile);
-  EXPECT_GT(column_profile[398], 0);
-  EXPECT_GT(column_profile[400], 0);
-  EXPECT_GT(column_profile[402], 0);
-  EXPECT_EQ(column_profile[299], 0);
-  EXPECT_EQ(column_profile[502], 0);
-  EXPECT_EQ(column_profile[399], column_profile[401]);
-  EXPECT_EQ(column_profile[398], column_profile[402]);
-}
-
-TEST_F(ThumbnailContentAnalysisTest, AdjustClippingSizeToAspectRatio) {
-  // The test will exercise several relations of sizes. Basic invariants
-  // checked in each case: each dimension in adjusted_size ougth not be greater
-  // than the source image and not lesser than requested target. Aspect ratio
-  // of adjusted_size should never be worse than that of computed_size.
-  gfx::Size target_size(212, 100);
-  gfx::Size image_size(1000, 2000);
-  gfx::Size computed_size(420, 200);
-
-  gfx::Size adjusted_size = AdjustClippingSizeToAspectRatio(
-      target_size, image_size, computed_size);
-
-  EXPECT_LE(adjusted_size.width(), image_size.width());
-  EXPECT_LE(adjusted_size.height(), image_size.height());
-  EXPECT_GE(adjusted_size.width(), target_size.width());
-  EXPECT_GE(adjusted_size.height(), target_size.height());
-  EXPECT_LE(AspectDifference(target_size, adjusted_size),
-            AspectDifference(target_size, computed_size));
-  // This case is special (and trivial): no change expected.
-  EXPECT_EQ(computed_size, adjusted_size);
-
-  // Computed size is too tall. Adjusted size has to add rows.
-  computed_size.SetSize(600, 150);
-  adjusted_size = AdjustClippingSizeToAspectRatio(
-      target_size, image_size, computed_size);
-  // Invariant check.
-  EXPECT_LE(adjusted_size.width(), image_size.width());
-  EXPECT_LE(adjusted_size.height(), image_size.height());
-  EXPECT_GE(adjusted_size.width(), target_size.width());
-  EXPECT_GE(adjusted_size.height(), target_size.height());
-  EXPECT_LE(AspectDifference(target_size, adjusted_size),
-            AspectDifference(target_size, computed_size));
-  // Specific to this case.
-  EXPECT_EQ(computed_size.width(), adjusted_size.width());
-  EXPECT_LE(computed_size.height(), adjusted_size.height());
-  EXPECT_NEAR(
-      static_cast<float>(target_size.width()) / target_size.height(),
-      static_cast<float>(adjusted_size.width()) / adjusted_size.height(),
-      0.02f);
-
-  // Computed size is too wide. Adjusted size has to add columns.
-  computed_size.SetSize(200, 400);
-  adjusted_size = AdjustClippingSizeToAspectRatio(
-      target_size, image_size, computed_size);
-  // Invariant check.
-  EXPECT_LE(adjusted_size.width(), image_size.width());
-  EXPECT_LE(adjusted_size.height(), image_size.height());
-  EXPECT_GE(adjusted_size.width(), target_size.width());
-  EXPECT_GE(adjusted_size.height(), target_size.height());
-  EXPECT_LE(AspectDifference(target_size, adjusted_size),
-            AspectDifference(target_size, computed_size));
-  EXPECT_NEAR(
-      static_cast<float>(target_size.width()) / target_size.height(),
-      static_cast<float>(adjusted_size.width()) / adjusted_size.height(),
-      0.02f);
-
-  target_size.SetSize(416, 205);
-  image_size.SetSize(1200, 1200);
-  computed_size.SetSize(900, 300);
-  adjusted_size = AdjustClippingSizeToAspectRatio(
-      target_size, image_size, computed_size);
-  // Invariant check.
-  EXPECT_LE(adjusted_size.width(), image_size.width());
-  EXPECT_LE(adjusted_size.height(), image_size.height());
-  EXPECT_GE(adjusted_size.width(), target_size.width());
-  EXPECT_GE(adjusted_size.height(), target_size.height());
-  EXPECT_LE(AspectDifference(target_size, adjusted_size),
-            AspectDifference(target_size, computed_size));
-  // Specific to this case.
-  EXPECT_EQ(computed_size.width(), adjusted_size.width());
-  EXPECT_LE(computed_size.height(), adjusted_size.height());
-  EXPECT_NEAR(
-      static_cast<float>(target_size.width()) / target_size.height(),
-      static_cast<float>(adjusted_size.width()) / adjusted_size.height(),
-      0.02f);
-
-  target_size.SetSize(416, 205);
-  image_size.SetSize(1200, 1200);
-  computed_size.SetSize(300, 300);
-  adjusted_size = AdjustClippingSizeToAspectRatio(
-      target_size, image_size, computed_size);
-  // Invariant check.
-  EXPECT_LE(adjusted_size.width(), image_size.width());
-  EXPECT_LE(adjusted_size.height(), image_size.height());
-  EXPECT_GE(adjusted_size.width(), target_size.width());
-  EXPECT_GE(adjusted_size.height(), target_size.height());
-  EXPECT_LE(AspectDifference(target_size, adjusted_size),
-            AspectDifference(target_size, computed_size));
-  // Specific to this case.
-  EXPECT_EQ(computed_size.height(), adjusted_size.height());
-  EXPECT_LE(computed_size.width(), adjusted_size.width());
-  EXPECT_NEAR(
-      static_cast<float>(target_size.width()) / target_size.height(),
-      static_cast<float>(adjusted_size.width()) / adjusted_size.height(),
-      0.02f);
-
-  computed_size.SetSize(200, 300);
-  adjusted_size = AdjustClippingSizeToAspectRatio(
-      target_size, image_size, computed_size);
-  // Invariant check.
-  EXPECT_LE(adjusted_size.width(), image_size.width());
-  EXPECT_LE(adjusted_size.height(), image_size.height());
-  EXPECT_GE(adjusted_size.width(), target_size.width());
-  EXPECT_GE(adjusted_size.height(), target_size.height());
-  EXPECT_LE(AspectDifference(target_size, adjusted_size),
-            AspectDifference(target_size, computed_size));
-  // Specific to this case.
-  EXPECT_EQ(computed_size.height(), adjusted_size.height());
-  EXPECT_LE(computed_size.width(), adjusted_size.width());
-  EXPECT_NEAR(
-      static_cast<float>(target_size.width()) / target_size.height(),
-      static_cast<float>(adjusted_size.width()) / adjusted_size.height(),
-      0.02f);
-
-  target_size.SetSize(416, 205);
-  image_size.SetSize(1400, 600);
-  computed_size.SetSize(300, 300);
-  adjusted_size = AdjustClippingSizeToAspectRatio(
-      target_size, image_size, computed_size);
-  // Invariant check.
-  EXPECT_LE(adjusted_size.width(), image_size.width());
-  EXPECT_LE(adjusted_size.height(), image_size.height());
-  EXPECT_GE(adjusted_size.width(), target_size.width());
-  EXPECT_GE(adjusted_size.height(), target_size.height());
-  EXPECT_LE(AspectDifference(target_size, adjusted_size),
-            AspectDifference(target_size, computed_size));
-  // Specific to this case.
-  EXPECT_EQ(computed_size.height(), adjusted_size.height());
-  EXPECT_LE(computed_size.width(), adjusted_size.width());
-  EXPECT_NEAR(
-      static_cast<float>(target_size.width()) / target_size.height(),
-      static_cast<float>(adjusted_size.width()) / adjusted_size.height(),
-      0.02f);
-
-  computed_size.SetSize(900, 300);
-  adjusted_size = AdjustClippingSizeToAspectRatio(
-      target_size, image_size, computed_size);
-  // Invariant check.
-  EXPECT_LE(adjusted_size.width(), image_size.width());
-  EXPECT_LE(adjusted_size.height(), image_size.height());
-  EXPECT_GE(adjusted_size.width(), target_size.width());
-  EXPECT_GE(adjusted_size.height(), target_size.height());
-  EXPECT_LE(AspectDifference(target_size, adjusted_size),
-            AspectDifference(target_size, computed_size));
-  // Specific to this case.
-  EXPECT_LE(computed_size.height(), adjusted_size.height());
-  EXPECT_NEAR(
-      static_cast<float>(target_size.width()) / target_size.height(),
-      static_cast<float>(adjusted_size.width()) / adjusted_size.height(),
-      0.02f);
-}
-
-TEST_F(ThumbnailContentAnalysisTest, AutoSegmentPeaks) {
-  std::vector<float> profile_info;
-
-  EXPECT_EQ(AutoSegmentPeaks(profile_info), std::numeric_limits<float>::max());
-  profile_info.resize(1000, 1.0f);
-  EXPECT_EQ(AutoSegmentPeaks(profile_info), 1.0f);
-  std::srand(42);
-  std::generate(profile_info.begin(), profile_info.end(), std::rand);
-  float threshold = AutoSegmentPeaks(profile_info);
-  EXPECT_GT(threshold, 0);  // Not much to expect.
-
-  // There should be roughly 50% above and below the threshold.
-  // Random is not really random thanks to srand, so we can sort-of compare.
-  int above_count =
-      std::count_if(profile_info.begin(), profile_info.end(),
-                    [threshold](float value) { return value > threshold; });
-  EXPECT_GT(above_count, 450);  // Not much to expect.
-  EXPECT_LT(above_count, 550);
-
-  for (unsigned i = 0; i < profile_info.size(); ++i) {
-    float y = std::sin(M_PI * i / 250.0f);
-    profile_info[i] = y > 0 ? y : 0;
-  }
-  threshold = AutoSegmentPeaks(profile_info);
-
-  above_count =
-      std::count_if(profile_info.begin(), profile_info.end(),
-                    [threshold](float value) { return value > threshold; });
-  EXPECT_LT(above_count, 500);  // Negative y expected to fall below threshold.
-
-  // Expect two peaks around between 0 and 250 and 500 and 750.
-  std::vector<bool> thresholded_values(profile_info.size(), false);
-  std::transform(profile_info.begin(), profile_info.end(),
-                 thresholded_values.begin(),
-                 [threshold](float value) { return value > threshold; });
-  EXPECT_TRUE(thresholded_values[125]);
-  EXPECT_TRUE(thresholded_values[625]);
-  int transitions = 0;
-  for (unsigned i = 1; i < thresholded_values.size(); ++i) {
-    if (thresholded_values[i] != thresholded_values[i-1])
-      transitions++;
-  }
-  EXPECT_EQ(transitions, 4);  // We have two contiguous peaks. Good going!
-}
-
-TEST_F(ThumbnailContentAnalysisTest, ConstrainedProfileSegmentation) {
-  const size_t kRowCount = 800;
-  const size_t kColumnCount = 1400;
-  const gfx::Size target_size(300, 150);
-  std::vector<float> rows_profile(kRowCount);
-  std::vector<float> columns_profile(kColumnCount);
-
-  std::srand(42);
-  std::generate(rows_profile.begin(), rows_profile.end(), []() {
-    return std::rand() / static_cast<float>(RAND_MAX) + 1.f;
-  });
-  std::generate(columns_profile.begin(), columns_profile.end(), []() {
-    return std::rand() / static_cast<float>(RAND_MAX) + 1.f;
-  });
-
-  std::transform(rows_profile.begin() + 300,
-                 rows_profile.begin() + 450,
-                 rows_profile.begin() + 300,
-                 [](float value) { return value + 8.f; });
-  std::transform(columns_profile.begin() + 400,
-                 columns_profile.begin() + 1000,
-                 columns_profile.begin() + 400,
-                 [](float value) { return value + 10.f; });
-
-  // Make sure that threshold falls somewhere reasonable.
-  float row_threshold = AutoSegmentPeaks(rows_profile);
-  EXPECT_GT(row_threshold, 1.0f);
-  EXPECT_LT(row_threshold, 9.0f);
-
-  int row_above_count = std::count_if(
-      rows_profile.begin(),
-      rows_profile.end(),
-      [row_threshold](float value) { return value > row_threshold; });
-  EXPECT_EQ(row_above_count, 150);
-
-  float column_threshold = AutoSegmentPeaks(columns_profile);
-  EXPECT_GT(column_threshold, 1.0f);
-  EXPECT_LT(column_threshold, 11.0f);
-
-  int column_above_count = std::count_if(
-      columns_profile.begin(),
-      columns_profile.end(),
-      [column_threshold](float value) { return value > column_threshold; });
-  EXPECT_EQ(column_above_count, 600);
-
-
-  std::vector<bool> rows_guide;
-  std::vector<bool> columns_guide;
-  ConstrainedProfileSegmentation(
-      rows_profile, columns_profile, target_size, &rows_guide, &columns_guide);
-
-  int row_count = std::count(rows_guide.begin(), rows_guide.end(), true);
-  int column_count = std::count(
-      columns_guide.begin(), columns_guide.end(), true);
-  float expected_aspect =
-      static_cast<float>(target_size.width()) / target_size.height();
-  float actual_aspect = static_cast<float>(column_count) / row_count;
-  EXPECT_GE(1.05f, expected_aspect / actual_aspect);
-  EXPECT_GE(1.05f, actual_aspect / expected_aspect);
-}
-
-TEST_F(ThumbnailContentAnalysisTest, ComputeDecimatedImage) {
-  gfx::Size image_size(1600, 1200);
-  gfx::Canvas canvas(image_size, 1.0f, true);
-
-  // Make some content we will later want to keep.
-  canvas.FillRect(gfx::Rect(100, 200, 100, 100), SkColorSetRGB(125, 0, 0));
-  canvas.FillRect(gfx::Rect(300, 200, 100, 100), SkColorSetRGB(0, 200, 0));
-  canvas.FillRect(gfx::Rect(500, 200, 100, 100), SkColorSetRGB(0, 0, 225));
-  canvas.FillRect(gfx::Rect(100, 400, 600, 100), SkColorSetRGB(125, 200, 225));
-
-  std::vector<bool> rows(image_size.height(), false);
-  std::fill_n(rows.begin() + 200, 100, true);
-  std::fill_n(rows.begin() + 400, 100, true);
-
-  std::vector<bool> columns(image_size.width(), false);
-  std::fill_n(columns.begin() + 100, 100, true);
-  std::fill_n(columns.begin() + 300, 100, true);
-  std::fill_n(columns.begin() + 500, 100, true);
-
-  SkBitmap source = canvas.GetBitmap();
-  SkBitmap result = ComputeDecimatedImage(source, rows, columns);
-  EXPECT_FALSE(result.empty());
-  EXPECT_EQ(300, result.width());
-  EXPECT_EQ(200, result.height());
-
-  // The call should have removed all empty spaces.
-  ASSERT_TRUE(CompareImageFragments(source,
-                                    result,
-                                    gfx::Size(100, 100),
-                                    gfx::Point(100, 200),
-                                    gfx::Point(0, 0)));
-  ASSERT_TRUE(CompareImageFragments(source,
-                                    result,
-                                    gfx::Size(100, 100),
-                                    gfx::Point(300, 200),
-                                    gfx::Point(100, 0)));
-  ASSERT_TRUE(CompareImageFragments(source,
-                                    result,
-                                    gfx::Size(100, 100),
-                                    gfx::Point(500, 200),
-                                    gfx::Point(200, 0)));
-  ASSERT_TRUE(CompareImageFragments(source,
-                                    result,
-                                    gfx::Size(100, 100),
-                                    gfx::Point(100, 400),
-                                    gfx::Point(0, 100)));
-}
-
-TEST_F(ThumbnailContentAnalysisTest, CreateRetargetedThumbnailImage) {
-  gfx::Size image_size(1200, 1300);
-  gfx::Canvas canvas(image_size, 1.0f, true);
-
-  // The following will create a 'fake image' consisting of color blocks placed
-  // on a neutral background. The entire layout is supposed to mimic a
-  // screenshot of a web page.
-  // The tested function is supposed to locate the interesing areas in the
-  // middle.
-  const int margin_horizontal = 60;
-  const int margin_vertical = 20;
-  canvas.FillRect(gfx::Rect(image_size), SkColorSetRGB(200, 210, 210));
-  const gfx::Rect header_rect(margin_horizontal,
-                              margin_vertical,
-                              image_size.width() - 2 * margin_horizontal,
-                              100);
-  const gfx::Rect footer_rect(margin_horizontal,
-                              image_size.height() - margin_vertical - 100,
-                              image_size.width() - 2 * margin_horizontal,
-                              100);
-  const gfx::Rect body_rect(margin_horizontal,
-                            header_rect.bottom() + margin_vertical,
-                            image_size.width() - 2 * margin_horizontal,
-                            footer_rect.y() - header_rect.bottom() -
-                            2 * margin_vertical);
-  canvas.FillRect(header_rect, SkColorSetRGB(200, 40, 10));
-  canvas.FillRect(footer_rect, SkColorSetRGB(10, 40, 180));
-  canvas.FillRect(body_rect, SkColorSetRGB(150, 180, 40));
-
-  // 'Fine print' at the bottom.
-  const int fine_print = 8;
-  const SkColor print_color = SkColorSetRGB(45, 30, 30);
-  for (int y = footer_rect.y() + fine_print;
-       y < footer_rect.bottom() - fine_print;
-       y += 2 * fine_print) {
-    for (int x = footer_rect.x() + fine_print;
-         x < footer_rect.right() - fine_print;
-         x += 2 * fine_print) {
-      canvas.DrawRect(gfx::RectF(x, y, fine_print, fine_print), print_color);
-    }
-  }
-
-  // Blocky content at the top.
-  const int block_size = header_rect.height() - margin_vertical;
-  for (int x = header_rect.x() + margin_horizontal;
-       x < header_rect.right() - block_size;
-       x += block_size + margin_horizontal) {
-    const int half_block = block_size / 2 - 5;
-    const SkColor block_color = SkColorSetRGB(255, 255, 255);
-    const int y = header_rect.y() + margin_vertical / 2;
-    int second_col = x + half_block + 10;
-    int second_row = y + half_block + 10;
-    canvas.FillRect(gfx::Rect(x, y, half_block, block_size), block_color);
-    canvas.FillRect(gfx::Rect(second_col,  y, half_block, half_block),
-                    block_color);
-    canvas.FillRect(gfx::Rect(second_col, second_row, half_block, half_block),
-                    block_color);
-  }
-
-  // Now the main body. Mostly text with some 'pictures'.
-  for (int y = body_rect.y() + fine_print;
-       y < body_rect.bottom() - fine_print;
-       y += 2 * fine_print) {
-    for (int x = body_rect.x() + fine_print;
-         x < body_rect.right() - fine_print;
-         x += 2 * fine_print) {
-      canvas.DrawRect(gfx::RectF(x, y, fine_print, fine_print), print_color);
-    }
-  }
-
-  for (int line = 0; line < 3; ++line) {
-    int alignment = line % 2;
-    const int y = body_rect.y() +
-        body_rect.height() / 3 * line + margin_vertical;
-    const int x = body_rect.x() +
-        alignment * body_rect.width() / 2 + margin_vertical;
-    gfx::Rect pict_rect(x, y, body_rect.width() / 2 - 2 * margin_vertical,
-                        body_rect.height() / 3 - 2 * margin_vertical);
-    canvas.FillRect(pict_rect, SkColorSetRGB(255, 255, 255));
-    canvas.DrawRect(gfx::RectF(pict_rect), SkColorSetRGB(0, 0, 0));
-  }
-
-  SkBitmap source = canvas.GetBitmap();
-
-  SkBitmap result = CreateRetargetedThumbnailImage(
-      source, gfx::Size(424, 264), 2.5);
-  EXPECT_FALSE(result.empty());
-
-  // Given the nature of computation We can't really assert much here about the
-  // image itself. We know it should have been computed, should be smaller than
-  // the original and it must not be zero.
-  EXPECT_LT(result.width(), image_size.width());
-  EXPECT_LT(result.height(), image_size.height());
-
-  int histogram[256] = {};
-  color_utils::BuildLumaHistogram(result, histogram);
-  int non_zero_color_count = std::count_if(
-      histogram, histogram + 256, [](int value) { return value > 0; });
-  EXPECT_GT(non_zero_color_count, 4);
-
-}
-
-}  // namespace thumbnailing_utils
diff --git a/chrome/browser/thumbnails/content_based_thumbnailing_algorithm.cc b/chrome/browser/thumbnails/content_based_thumbnailing_algorithm.cc
deleted file mode 100644
index 65591785..0000000
--- a/chrome/browser/thumbnails/content_based_thumbnailing_algorithm.cc
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/thumbnails/content_based_thumbnailing_algorithm.h"
-
-#include <stddef.h>
-
-#include "base/metrics/histogram_macros.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "chrome/browser/thumbnails/content_analysis.h"
-#include "chrome/browser/thumbnails/simple_thumbnail_crop.h"
-#include "content/public/browser/browser_thread.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/color_utils.h"
-#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/scrollbar_size.h"
-#include "ui/gfx/skbitmap_operations.h"
-#include "ui/gfx/skia_util.h"
-
-namespace {
-
-const char kThumbnailHistogramName[] = "Thumbnail.RetargetMS";
-const char kFailureHistogramName[] = "Thumbnail.FailedRetargetMS";
-const float kScoreBoostFromSuccessfulRetargeting = 1.1f;
-
-void CallbackInvocationAdapter(
-    const thumbnails::ThumbnailingAlgorithm::ConsumerCallback& callback,
-    scoped_refptr<thumbnails::ThumbnailingContext> context,
-    const SkBitmap& source_bitmap) {
-  callback.Run(*context.get(), source_bitmap);
-}
-
-}  // namespace
-
-namespace thumbnails {
-
-using content::BrowserThread;
-
-ContentBasedThumbnailingAlgorithm::ContentBasedThumbnailingAlgorithm(
-    const gfx::Size& target_size)
-    : target_size_(target_size) {
-  DCHECK(!target_size.IsEmpty());
-}
-
-ClipResult ContentBasedThumbnailingAlgorithm::GetCanvasCopyInfo(
-    const gfx::Size& source_size,
-    ui::ScaleFactor scale_factor,
-    gfx::Rect* clipping_rect,
-    gfx::Size* copy_size) const {
-  DCHECK(!source_size.IsEmpty());
-  gfx::Size copy_thumbnail_size =
-      SimpleThumbnailCrop::GetCopySizeForThumbnail(scale_factor, target_size_);
-
-  ClipResult clipping_method = thumbnails::CLIP_RESULT_NOT_CLIPPED;
-  *clipping_rect = GetClippingRect(source_size, copy_thumbnail_size, copy_size,
-                                   &clipping_method);
-  return clipping_method;
-}
-
-void ContentBasedThumbnailingAlgorithm::ProcessBitmap(
-    scoped_refptr<ThumbnailingContext> context,
-    const ConsumerCallback& callback,
-    const SkBitmap& bitmap) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(context.get());
-  if (bitmap.isNull() || bitmap.empty())
-    return;
-
-  gfx::Size target_thumbnail_size =
-      SimpleThumbnailCrop::ComputeTargetSizeAtMaximumScale(target_size_);
-
-  SkBitmap source_bitmap =
-      PrepareSourceBitmap(bitmap, target_thumbnail_size, context.get());
-
-  // If the source is same (or smaller) than the target, just return it as
-  // the final result. Otherwise, send the shrinking task to the blocking
-  // thread pool.
-  if (source_bitmap.width() <= target_thumbnail_size.width() ||
-      source_bitmap.height() <= target_thumbnail_size.height()) {
-    context->score.boring_score =
-        color_utils::CalculateBoringScore(source_bitmap);
-    context->score.good_clipping =
-        (context->clip_result == CLIP_RESULT_WIDER_THAN_TALL ||
-         context->clip_result == CLIP_RESULT_TALLER_THAN_WIDE ||
-         context->clip_result == CLIP_RESULT_NOT_CLIPPED ||
-         context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET);
-
-    callback.Run(*context.get(), source_bitmap);
-    return;
-  }
-
-  base::PostTaskWithTraits(
-      FROM_HERE,
-      {base::TaskPriority::BACKGROUND,
-       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
-      base::Bind(&CreateRetargetedThumbnail, source_bitmap,
-                 target_thumbnail_size, context, callback));
-}
-
-// static
-SkBitmap ContentBasedThumbnailingAlgorithm::PrepareSourceBitmap(
-    const SkBitmap& received_bitmap,
-    const gfx::Size& thumbnail_size,
-    ThumbnailingContext* context) {
-  gfx::Size resize_target;
-  SkBitmap clipped_bitmap;
-  if (context->clip_result == CLIP_RESULT_UNPROCESSED) {
-    // This case will require extracting a fragment from the retrieved bitmap.
-    int scrollbar_size = gfx::scrollbar_size();
-    gfx::Size scrollbarless(
-        std::max(1, received_bitmap.width() - scrollbar_size),
-        std::max(1, received_bitmap.height() - scrollbar_size));
-
-    gfx::Rect clipping_rect = GetClippingRect(
-        scrollbarless,
-        thumbnail_size,
-        &resize_target,
-        &context->clip_result);
-
-    received_bitmap.extractSubset(&clipped_bitmap,
-                                  gfx::RectToSkIRect(clipping_rect));
-  } else {
-    // This means that the source bitmap has been requested and at least
-    // clipped. Upstream code in same cases seems opportunistic and it may
-    // not perform actual resizing if copying with resize is not supported.
-    // In this case we will resize to the orignally requested copy size.
-    resize_target = context->requested_copy_size;
-    clipped_bitmap = received_bitmap;
-  }
-
-  SkBitmap result_bitmap = SkBitmapOperations::DownsampleByTwoUntilSize(
-      clipped_bitmap, resize_target.width(), resize_target.height());
-
-  return result_bitmap;
-}
-
-// static
-void ContentBasedThumbnailingAlgorithm::CreateRetargetedThumbnail(
-    const SkBitmap& source_bitmap,
-    const gfx::Size& thumbnail_size,
-    scoped_refptr<ThumbnailingContext> context,
-    const ConsumerCallback& callback) {
-  base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
-  float kernel_sigma =
-      context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET ? 5.0f : 2.5f;
-  SkBitmap thumbnail = thumbnailing_utils::CreateRetargetedThumbnailImage(
-      source_bitmap, thumbnail_size, kernel_sigma);
-  bool processing_failed = thumbnail.empty();
-  if (processing_failed) {
-    // Log and apply the method very much like in SimpleThumbnailCrop (except
-    // that some clipping and copying is not required).
-    LOG(WARNING) << "CreateRetargetedThumbnailImage failed. "
-                 << "The thumbnail for " << context->url
-                 << " will be created the old-fashioned way.";
-
-    ClipResult clip_result;
-    gfx::Rect clipping_rect = SimpleThumbnailCrop::GetClippingRect(
-        gfx::Size(source_bitmap.width(), source_bitmap.height()),
-        thumbnail_size,
-        &clip_result);
-    source_bitmap.extractSubset(&thumbnail, gfx::RectToSkIRect(clipping_rect));
-    thumbnail = SkBitmapOperations::DownsampleByTwoUntilSize(
-        thumbnail, thumbnail_size.width(), thumbnail_size.height());
-  }
-
-  if (processing_failed) {
-    LOCAL_HISTOGRAM_TIMES(kFailureHistogramName,
-                          base::TimeTicks::Now() - begin_compute_thumbnail);
-  } else {
-    LOCAL_HISTOGRAM_TIMES(kThumbnailHistogramName,
-                          base::TimeTicks::Now() - begin_compute_thumbnail);
-  }
-  context->score.boring_score =
-      color_utils::CalculateBoringScore(source_bitmap);
-  if (!processing_failed)
-    context->score.boring_score *= kScoreBoostFromSuccessfulRetargeting;
-  context->score.good_clipping =
-      (context->clip_result == CLIP_RESULT_WIDER_THAN_TALL ||
-       context->clip_result == CLIP_RESULT_TALLER_THAN_WIDE ||
-       context->clip_result == CLIP_RESULT_NOT_CLIPPED ||
-       context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET);
-  // Post the result (the bitmap) back to the callback.
-  BrowserThread::PostTask(
-      BrowserThread::UI,
-      FROM_HERE,
-      base::Bind(&CallbackInvocationAdapter, callback, context, thumbnail));
-}
-
-ContentBasedThumbnailingAlgorithm::~ContentBasedThumbnailingAlgorithm() {
-}
-
-//  static
-gfx::Rect ContentBasedThumbnailingAlgorithm::GetClippingRect(
-    const gfx::Size& source_size,
-    const gfx::Size& thumbnail_size,
-    gfx::Size* target_size,
-    ClipResult* clip_result) {
-  // Compute and return the clipping rectagle of the source image and the
-  // size of the target bitmap which will be used for the further processing.
-  // This function in 'general case' is trivial (don't clip, halve the source)
-  // but it is needed for handling edge cases (source smaller than the target
-  // thumbnail size).
-  DCHECK(target_size);
-  DCHECK(clip_result);
-  gfx::Rect clipping_rect;
-  if (source_size.width() < thumbnail_size.width() ||
-      source_size.height() < thumbnail_size.height()) {
-    clipping_rect = gfx::Rect(thumbnail_size);
-    *target_size = thumbnail_size;
-    *clip_result = CLIP_RESULT_SOURCE_IS_SMALLER;
-  } else if (source_size.width() < thumbnail_size.width() * 4 ||
-             source_size.height() < thumbnail_size.height() * 4) {
-    clipping_rect = gfx::Rect(source_size);
-    *target_size = source_size;
-    *clip_result = CLIP_RESULT_SOURCE_SAME_AS_TARGET;
-  } else {
-    clipping_rect = gfx::Rect(source_size);
-    target_size->SetSize(source_size.width() / 2, source_size.height() / 2);
-    *clip_result = CLIP_RESULT_NOT_CLIPPED;
-  }
-
-  return clipping_rect;
-}
-
-}  // namespace thumbnails
diff --git a/chrome/browser/thumbnails/content_based_thumbnailing_algorithm.h b/chrome/browser/thumbnails/content_based_thumbnailing_algorithm.h
deleted file mode 100644
index ede432c..0000000
--- a/chrome/browser/thumbnails/content_based_thumbnailing_algorithm.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_THUMBNAILS_CONTENT_BASED_THUMBNAILING_ALGORITHM_H_
-#define CHROME_BROWSER_THUMBNAILS_CONTENT_BASED_THUMBNAILING_ALGORITHM_H_
-
-#include "base/macros.h"
-#include "chrome/browser/thumbnails/thumbnailing_algorithm.h"
-
-namespace thumbnails {
-
-// Encapsulates a method of creating a thumbnail from a captured tab shot which
-// attempts to preserve only relevant fragments of the original image.
-// The algorithm detects areas of high activity at low resolution and discards
-// rows and columns which do not intersect with these areas.
-class ContentBasedThumbnailingAlgorithm : public ThumbnailingAlgorithm {
- public:
-  explicit ContentBasedThumbnailingAlgorithm(const gfx::Size& target_size);
-
-  ClipResult GetCanvasCopyInfo(const gfx::Size& source_size,
-                               ui::ScaleFactor scale_factor,
-                               gfx::Rect* clipping_rect,
-                               gfx::Size* copy_size) const override;
-
-  void ProcessBitmap(scoped_refptr<ThumbnailingContext> context,
-                     const ConsumerCallback& callback,
-                     const SkBitmap& bitmap) override;
-
-  // Prepares (clips to size, copies etc.) the bitmap passed to ProcessBitmap.
-  // Always returns a bitmap that can be properly refcounted.
-  // Extracted and exposed as a test seam.
-  static SkBitmap PrepareSourceBitmap(const SkBitmap& received_bitmap,
-                                      const gfx::Size& thumbnail_size,
-                                      ThumbnailingContext* context);
-
-  // The function processes |source_bitmap| into a thumbnail of |thumbnail_size|
-  // and passes the result into |callback| (on UI thread). |context| describes
-  // how the thumbnail is being created.
-  static void CreateRetargetedThumbnail(
-      const SkBitmap& source_bitmap,
-      const gfx::Size& thumbnail_size,
-      scoped_refptr<ThumbnailingContext> context,
-      const ConsumerCallback& callback);
-
- protected:
-  ~ContentBasedThumbnailingAlgorithm() override;
-
- private:
-  static gfx::Rect GetClippingRect(const gfx::Size& source_size,
-                                   const gfx::Size& thumbnail_size,
-                                   gfx::Size* target_size,
-                                   ClipResult* clip_result);
-
-  const gfx::Size target_size_;
-
-  DISALLOW_COPY_AND_ASSIGN(ContentBasedThumbnailingAlgorithm);
-};
-
-}  // namespace thumbnails
-
-#endif  // CHROME_BROWSER_THUMBNAILS_CONTENT_BASED_THUMBNAILING_ALGORITHM_H_
diff --git a/chrome/browser/thumbnails/content_based_thumbnailing_algorithm_unittest.cc b/chrome/browser/thumbnails/content_based_thumbnailing_algorithm_unittest.cc
deleted file mode 100644
index cf6de0e..0000000
--- a/chrome/browser/thumbnails/content_based_thumbnailing_algorithm_unittest.cc
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/thumbnails/content_based_thumbnailing_algorithm.h"
-
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "chrome/browser/thumbnails/simple_thumbnail_crop.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "skia/ext/platform_canvas.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/scrollbar_size.h"
-
-namespace thumbnails {
-
-typedef testing::Test ContentBasedThumbnailingAlgorithmTest;
-
-class ConsumerCallbackCatcher {
- public:
-  ConsumerCallbackCatcher()
-      : called_back_(false), clip_result_(CLIP_RESULT_UNPROCESSED) {
-  }
-
-  void UiThreadCallback(const ThumbnailingContext& context,
-                        const SkBitmap& bitmap) {
-    called_back_ = true;
-    captured_bitmap_ = bitmap;
-    clip_result_ = context.clip_result;
-    score_ = context.score;
-  }
-
-  bool called_back() const {
-    return called_back_;
-  }
-
-  const SkBitmap& captured_bitmap() const {
-    return captured_bitmap_;
-  }
-
-  ClipResult clip_result() const {
-    return clip_result_;
-  }
-
-  const ThumbnailScore& score() const {
-    return score_;
-  }
-
- private:
-  SkBitmap captured_bitmap_;
-  bool called_back_;
-  ClipResult clip_result_;
-  ThumbnailScore score_;
-
-  DISALLOW_COPY_AND_ASSIGN(ConsumerCallbackCatcher);
-};
-
-TEST_F(ContentBasedThumbnailingAlgorithmTest, GetCanvasCopyInfo) {
-  // We will want to use the entirety of the image as the source. Usually,
-  // an image in its original size should be requested, except for reakky large
-  // canvas. In that case, image will be shrunk but wit aspect ratio preserved.
-  const gfx::Size thumbnail_size(312, 165);
-  scoped_refptr<ThumbnailingAlgorithm> algorithm(
-      new ContentBasedThumbnailingAlgorithm(thumbnail_size));
-
-  gfx::Rect clipping_rect;
-  gfx::Size target_size;
-  gfx::Size source_size(1000, 600);
-
-  ClipResult clip_result = algorithm->GetCanvasCopyInfo(
-      source_size, ui::SCALE_FACTOR_100P, &clipping_rect, &target_size);
-  EXPECT_EQ(CLIP_RESULT_SOURCE_SAME_AS_TARGET, clip_result);
-  EXPECT_EQ(source_size.ToString(), clipping_rect.size().ToString());
-  EXPECT_EQ(gfx::Point(0, 0).ToString(), clipping_rect.origin().ToString());
-  EXPECT_EQ(source_size, target_size);
-
-  source_size.SetSize(6000, 3000);
-  clip_result = algorithm->GetCanvasCopyInfo(
-      source_size, ui::SCALE_FACTOR_100P, &clipping_rect, &target_size);
-  EXPECT_EQ(CLIP_RESULT_NOT_CLIPPED, clip_result);
-  EXPECT_EQ(source_size.ToString(), clipping_rect.size().ToString());
-  EXPECT_EQ(gfx::Point(0, 0).ToString(), clipping_rect.origin().ToString());
-  EXPECT_LT(target_size.width(), source_size.width());
-  EXPECT_LT(target_size.height(), source_size.height());
-  EXPECT_NEAR(static_cast<float>(target_size.width()) / target_size.height(),
-              static_cast<float>(source_size.width()) / source_size.height(),
-              0.1f);
-  source_size.SetSize(300, 200);
-  clip_result = algorithm->GetCanvasCopyInfo(
-      source_size, ui::SCALE_FACTOR_100P, &clipping_rect, &target_size);
-  EXPECT_EQ(CLIP_RESULT_SOURCE_IS_SMALLER, clip_result);
-  EXPECT_EQ(clipping_rect.size().ToString(),
-            SimpleThumbnailCrop::GetCopySizeForThumbnail(
-                ui::SCALE_FACTOR_100P, thumbnail_size).ToString());
-  EXPECT_EQ(gfx::Point(0, 0).ToString(), clipping_rect.origin().ToString());
-}
-
-TEST_F(ContentBasedThumbnailingAlgorithmTest, PrepareSourceBitmap) {
-  const gfx::Size thumbnail_size(312, 165);
-  const gfx::Size copy_size(400, 200);
-  scoped_refptr<ThumbnailingContext> context(
-      ThumbnailingContext::CreateThumbnailingContextForTest());
-  context->requested_copy_size = copy_size;
-
-  // This calls for exercising two distinct paths: with prior clipping and
-  // without.
-  SkBitmap source;
-  source.allocN32Pixels(800, 600);
-  source.eraseARGB(255, 50, 150, 200);
-  SkBitmap result = ContentBasedThumbnailingAlgorithm::PrepareSourceBitmap(
-      source, thumbnail_size, context.get());
-  EXPECT_EQ(CLIP_RESULT_SOURCE_SAME_AS_TARGET, context->clip_result);
-  EXPECT_GE(result.width(), copy_size.width());
-  EXPECT_GE(result.height(), copy_size.height());
-  EXPECT_LT(result.width(), source.width());
-  EXPECT_LT(result.height(), source.height());
-  // The check below is a bit of a side effect: since the image was clipped
-  // by scrollbar_size, it cannot be shrunk and thus what we get below is
-  // true.
-  EXPECT_NEAR(result.width(), source.width(), gfx::scrollbar_size());
-  EXPECT_NEAR(result.height(), source.height(), gfx::scrollbar_size());
-
-  result = ContentBasedThumbnailingAlgorithm::PrepareSourceBitmap(
-      source, thumbnail_size, context.get());
-  EXPECT_EQ(CLIP_RESULT_SOURCE_SAME_AS_TARGET, context->clip_result);
-  EXPECT_GE(result.width(), copy_size.width());
-  EXPECT_GE(result.height(), copy_size.height());
-  EXPECT_LT(result.width(), source.width());
-  EXPECT_LT(result.height(), source.height());
-}
-
-TEST_F(ContentBasedThumbnailingAlgorithmTest, CreateRetargetedThumbnail) {
-  // This tests the invocation of the main thumbnail-making apparatus.
-  // The actual content is not really of concern here, just check the plumbing.
-  const gfx::Size image_size(1200, 800);
-  gfx::Canvas canvas(image_size, 1.0f, true);
-
-  // The image consists of vertical non-overlapping stripes 150 pixels wide.
-  canvas.FillRect(gfx::Rect(200, 200, 800, 400), SkColorSetRGB(255, 255, 255));
-  SkBitmap source = canvas.GetBitmap();
-
-  ConsumerCallbackCatcher catcher;
-  const gfx::Size thumbnail_size(432, 284);
-  scoped_refptr<ThumbnailingContext> context(
-      ThumbnailingContext::CreateThumbnailingContextForTest());
-  context->requested_copy_size = image_size;
-  context->clip_result = CLIP_RESULT_SOURCE_SAME_AS_TARGET;
-
-  content::TestBrowserThreadBundle test_browser_thread_bundle;
-  ContentBasedThumbnailingAlgorithm::CreateRetargetedThumbnail(
-      source,
-      thumbnail_size,
-      context,
-      base::Bind(&ConsumerCallbackCatcher::UiThreadCallback,
-                 base::Unretained(&catcher)));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(catcher.called_back());
-  EXPECT_TRUE(catcher.score().good_clipping);
-  EXPECT_FALSE(catcher.captured_bitmap().empty());
-  EXPECT_LT(catcher.captured_bitmap().width(), source.width());
-  EXPECT_LT(catcher.captured_bitmap().height(), source.height());
-}
-
-}  // namespace thumbnails
diff --git a/chrome/browser/thumbnails/thumbnail_service.h b/chrome/browser/thumbnails/thumbnail_service.h
index 97000d2e..cf8290f 100644
--- a/chrome/browser/thumbnails/thumbnail_service.h
+++ b/chrome/browser/thumbnails/thumbnail_service.h
@@ -36,6 +36,7 @@
   // process of creating a thumbnail from tab contents. The lifetime of these
   // instances is limited to the act of processing a single tab image. They
   // are permitted to hold the state of such process.
+  // TODO(treib): Return a scoped_refptr rather than raw pointer.
   virtual ThumbnailingAlgorithm* GetThumbnailingAlgorithm() const = 0;
 
   // Gets a thumbnail for a given page. Returns true iff we have the thumbnail.
diff --git a/chrome/browser/thumbnails/thumbnail_service_impl.cc b/chrome/browser/thumbnails/thumbnail_service_impl.cc
index 8c2d1a9..603c1a21 100644
--- a/chrome/browser/thumbnails/thumbnail_service_impl.cc
+++ b/chrome/browser/thumbnails/thumbnail_service_impl.cc
@@ -4,16 +4,12 @@
 
 #include "chrome/browser/thumbnails/thumbnail_service_impl.h"
 
-#include "base/command_line.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/time/time.h"
 #include "chrome/browser/history/history_utils.h"
 #include "chrome/browser/history/top_sites_factory.h"
-#include "chrome/browser/thumbnails/content_based_thumbnailing_algorithm.h"
 #include "chrome/browser/thumbnails/simple_thumbnail_crop.h"
 #include "chrome/browser/thumbnails/thumbnailing_context.h"
-#include "chrome/common/chrome_switches.h"
-#include "components/search/search.h"
 #include "content/public/browser/browser_thread.h"
 #include "url/gurl.h"
 
@@ -28,15 +24,6 @@
 const int kThumbnailWidth = 154;
 const int kThumbnailHeight = 96;
 
-// True if thumbnail retargeting feature is enabled (Finch/flags).
-bool IsThumbnailRetargetingEnabled() {
-  if (!search::IsInstantExtendedAPIEnabled())
-    return false;
-
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kEnableThumbnailRetargeting);
-}
-
 void AddForcedURLOnUIThread(scoped_refptr<history::TopSites> top_sites,
                             const GURL& url) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -50,9 +37,7 @@
 namespace thumbnails {
 
 ThumbnailServiceImpl::ThumbnailServiceImpl(Profile* profile)
-    : top_sites_(TopSitesFactory::GetForProfile(profile)),
-      use_thumbnail_retargeting_(IsThumbnailRetargetingEnabled()) {
-}
+    : top_sites_(TopSitesFactory::GetForProfile(profile)) {}
 
 ThumbnailServiceImpl::~ThumbnailServiceImpl() {
 }
@@ -89,10 +74,7 @@
 
 ThumbnailingAlgorithm* ThumbnailServiceImpl::GetThumbnailingAlgorithm()
     const {
-  const gfx::Size thumbnail_size(kThumbnailWidth, kThumbnailHeight);
-  if (use_thumbnail_retargeting_)
-    return new ContentBasedThumbnailingAlgorithm(thumbnail_size);
-  return new SimpleThumbnailCrop(thumbnail_size);
+  return new SimpleThumbnailCrop(gfx::Size(kThumbnailWidth, kThumbnailHeight));
 }
 
 bool ThumbnailServiceImpl::ShouldAcquirePageThumbnail(const GURL& url) {
diff --git a/chrome/browser/thumbnails/thumbnail_service_impl.h b/chrome/browser/thumbnails/thumbnail_service_impl.h
index 537bf0e..19b29727 100644
--- a/chrome/browser/thumbnails/thumbnail_service_impl.h
+++ b/chrome/browser/thumbnails/thumbnail_service_impl.h
@@ -40,7 +40,6 @@
   ~ThumbnailServiceImpl() override;
 
   scoped_refptr<history::TopSites> top_sites_;
-  bool use_thumbnail_retargeting_;
 
   DISALLOW_COPY_AND_ASSIGN(ThumbnailServiceImpl);
 };
diff --git a/chrome/browser/ui/search/ntp_user_data_logger.cc b/chrome/browser/ui/search/ntp_user_data_logger.cc
index 370ff05..91253f7 100644
--- a/chrome/browser/ui/search/ntp_user_data_logger.cc
+++ b/chrome/browser/ui/search/ntp_user_data_logger.cc
@@ -165,8 +165,8 @@
   DVLOG(1) << "Emitting NTP load time: " << load_time << ", "
            << "number of tiles: " << impression_was_logged_.count();
 
-  std::vector<ntp_tiles::metrics::TileImpression> tiles;
   bool has_server_side_suggestions = false;
+  int tiles_count = 0;
   for (int i = 0; i < kNumMostVisited; i++) {
     if (!impression_was_logged_[i]) {
       break;
@@ -175,14 +175,14 @@
         ntp_tiles::TileSource::SUGGESTIONS_SERVICE) {
       has_server_side_suggestions = true;
     }
-    // No URL passed since we're not interested in favicon-related Rappor
-    // metrics.
-    tiles.emplace_back(impression_tile_source_[i], impression_tile_type_[i],
-                       GURL());
+    // No URL and rappor service passed - not interested in favicon-related
+    // Rappor metrics.
+    ntp_tiles::metrics::RecordTileImpression(i, impression_tile_source_[i],
+                                             impression_tile_type_[i], GURL(),
+                                             /*rappor_service=*/nullptr);
+    ++tiles_count;
   }
-
-  // Not interested in Rappor metrics.
-  ntp_tiles::metrics::RecordPageImpression(tiles, /*rappor_service=*/nullptr);
+  ntp_tiles::metrics::RecordPageImpression(tiles_count);
 
   UMA_HISTOGRAM_LOAD_TIME("NewTabPage.TilesReceivedTime", tiles_received_time_);
   UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime", load_time);
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 53cdd61..c042489 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -424,10 +424,6 @@
 // Enables user control over muting tab audio from the tab strip.
 const char kEnableTabAudioMuting[]  = "enable-tab-audio-muting";
 
-// Enables fanciful thumbnail processing. Used with NTP for
-// instant-extended-api, where thumbnails are generally smaller.
-const char kEnableThumbnailRetargeting[]   = "enable-thumbnail-retargeting";
-
 // Enables Web Notification custom layouts.
 const char kEnableWebNotificationCustomLayouts[] =
     "enable-web-notification-custom-layouts";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 597aee9b..7a74fa7 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -132,7 +132,6 @@
 extern const char kEnableSiteSettings[];
 extern const char kEnableSupervisedUserManagedBookmarksFolder[];
 extern const char kEnableTabAudioMuting[];
-extern const char kEnableThumbnailRetargeting[];
 extern const char kEnableWebNotificationCustomLayouts[];
 extern const char kEnableWebRtcEventLoggingFromExtension[];
 extern const char kExtensionContentVerification[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 3ebf6d1..9070ab1 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3283,8 +3283,6 @@
     "../browser/sync/sessions/sync_sessions_web_contents_router_unittest.cc",
     "../browser/sync/sync_startup_tracker_unittest.cc",
     "../browser/task_profiler/task_profiler_data_serializer_unittest.cc",
-    "../browser/thumbnails/content_analysis_unittest.cc",
-    "../browser/thumbnails/content_based_thumbnailing_algorithm_unittest.cc",
     "../browser/thumbnails/simple_thumbnail_crop_unittest.cc",
     "../browser/thumbnails/thumbnail_service_unittest.cc",
     "../browser/translate/chrome_translate_client_unittest.cc",
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn
index a719f54f..651fe36e 100644
--- a/components/ntp_snippets/BUILD.gn
+++ b/components/ntp_snippets/BUILD.gn
@@ -17,6 +17,7 @@
     "bookmarks/bookmark_suggestions_provider.h",
     "breaking_news/breaking_news_gcm_app_handler.cc",
     "breaking_news/breaking_news_gcm_app_handler.h",
+    "breaking_news/breaking_news_listener.h",
     "breaking_news/breaking_news_suggestions_provider.cc",
     "breaking_news/breaking_news_suggestions_provider.h",
     "breaking_news/subscription_json_request.cc",
diff --git a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc
index d25f967..31c4e1c2 100644
--- a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc
+++ b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc
@@ -15,19 +15,19 @@
 
 namespace ntp_snippets {
 
-const char kContentSuggestionsGCMAppID[] = "com.google.contentsuggestions.gcm";
+const char kBreakingNewsGCMAppID[] = "com.google.breakingnews.gcm";
 
 // The sender ID is used in the registration process.
 // See: https://developers.google.com/cloud-messaging/gcm#senderid
 // TODO(mamir): use proper sender Id.
-const char kContentSuggestionsGCMSenderId[] = "128223710667";
+const char kBreakingNewsGCMSenderId[] = "128223710667";
 
 // OAuth2 Scope passed to getToken to obtain GCM registration tokens.
 // Must match Java GoogleCloudMessaging.INSTANCE_ID_SCOPE.
 const char kGCMScope[] = "GCM";
 
-// Key of the suggestion json in the data in the pushed content suggestion.
-const char kPushedSuggestionKey[] = "payload";
+// Key of the news json in the data in the pushed breaking news.
+const char kPushedNewsKey[] = "payload";
 
 BreakingNewsGCMAppHandler::BreakingNewsGCMAppHandler(
     gcm::GCMDriver* gcm_driver,
@@ -40,7 +40,7 @@
       pref_service_(pref_service),
       subscription_manager_(std::move(subscription_manager)),
       parse_json_callback_(parse_json_callback),
-      weak_factory_(this) {}
+      weak_ptr_factory_(this) {}
 
 BreakingNewsGCMAppHandler::~BreakingNewsGCMAppHandler() {
   StopListening();
@@ -54,23 +54,23 @@
 #endif
   Subscribe();
   on_new_content_callback_ = std::move(on_new_content_callback);
-  gcm_driver_->AddAppHandler(kContentSuggestionsGCMAppID, this);
+  gcm_driver_->AddAppHandler(kBreakingNewsGCMAppID, this);
 }
 
 void BreakingNewsGCMAppHandler::StopListening() {
-  DCHECK_EQ(gcm_driver_->GetAppHandler(kContentSuggestionsGCMAppID), this);
-  gcm_driver_->RemoveAppHandler(kContentSuggestionsGCMAppID);
+  DCHECK_EQ(gcm_driver_->GetAppHandler(kBreakingNewsGCMAppID), this);
+  gcm_driver_->RemoveAppHandler(kBreakingNewsGCMAppID);
   on_new_content_callback_ = OnNewContentCallback();
   // TODO(mamir): Check which token should be used for unsubscription when
   // handling change in the token.
   std::string token = pref_service_->GetString(
-      ntp_snippets::prefs::kContentSuggestionsGCMSubscriptionTokenCache);
+      ntp_snippets::prefs::kBreakingNewsGCMSubscriptionTokenCache);
   subscription_manager_->Unsubscribe(token);
 }
 
 void BreakingNewsGCMAppHandler::Subscribe() {
   std::string token = pref_service_->GetString(
-      ntp_snippets::prefs::kContentSuggestionsGCMSubscriptionTokenCache);
+      ntp_snippets::prefs::kBreakingNewsGCMSubscriptionTokenCache);
   // If a token has been already obtained, subscribe directly at the content
   // suggestions server.
   if (!token.empty()) {
@@ -80,11 +80,11 @@
     return;
   }
 
-  instance_id_driver_->GetInstanceID(kContentSuggestionsGCMAppID)
-      ->GetToken(kContentSuggestionsGCMSenderId, kGCMScope,
+  instance_id_driver_->GetInstanceID(kBreakingNewsGCMAppID)
+      ->GetToken(kBreakingNewsGCMSenderId, kGCMScope,
                  std::map<std::string, std::string>() /* options */,
                  base::Bind(&BreakingNewsGCMAppHandler::DidSubscribe,
-                            weak_factory_.GetWeakPtr()));
+                            weak_ptr_factory_.GetWeakPtr()));
 }
 
 void BreakingNewsGCMAppHandler::DidSubscribe(const std::string& subscription_id,
@@ -92,7 +92,7 @@
   switch (result) {
     case InstanceID::SUCCESS:
       pref_service_->SetString(
-          ntp_snippets::prefs::kContentSuggestionsGCMSubscriptionTokenCache,
+          ntp_snippets::prefs::kBreakingNewsGCMSubscriptionTokenCache,
           subscription_id);
       subscription_manager_->Subscribe(subscription_id);
       return;
@@ -114,27 +114,27 @@
 
 void BreakingNewsGCMAppHandler::OnStoreReset() {
   pref_service_->ClearPref(
-      ntp_snippets::prefs::kContentSuggestionsGCMSubscriptionTokenCache);
+      ntp_snippets::prefs::kBreakingNewsGCMSubscriptionTokenCache);
 }
 
 void BreakingNewsGCMAppHandler::OnMessage(const std::string& app_id,
                                           const gcm::IncomingMessage& message) {
-  DCHECK_EQ(app_id, kContentSuggestionsGCMAppID);
+  DCHECK_EQ(app_id, kBreakingNewsGCMAppID);
 
-  gcm::MessageData::const_iterator it = message.data.find(kPushedSuggestionKey);
+  gcm::MessageData::const_iterator it = message.data.find(kPushedNewsKey);
   if (it == message.data.end()) {
     LOG(WARNING)
-        << "Receiving pushed content failure: Content suggestion ID missing.";
+        << "Receiving pushed content failure: Breaking News ID missing.";
     return;
   }
 
-  std::string suggestions = it->second;
+  std::string news = it->second;
 
-  parse_json_callback_.Run(suggestions,
+  parse_json_callback_.Run(news,
                            base::Bind(&BreakingNewsGCMAppHandler::OnJsonSuccess,
-                                      weak_factory_.GetWeakPtr()),
+                                      weak_ptr_factory_.GetWeakPtr()),
                            base::Bind(&BreakingNewsGCMAppHandler::OnJsonError,
-                                      weak_factory_.GetWeakPtr(), suggestions));
+                                      weak_ptr_factory_.GetWeakPtr(), news));
 }
 
 void BreakingNewsGCMAppHandler::OnMessagesDeleted(const std::string& app_id) {
@@ -160,8 +160,8 @@
 
 void BreakingNewsGCMAppHandler::RegisterProfilePrefs(
     PrefRegistrySimple* registry) {
-  registry->RegisterStringPref(
-      prefs::kContentSuggestionsGCMSubscriptionTokenCache, std::string());
+  registry->RegisterStringPref(prefs::kBreakingNewsGCMSubscriptionTokenCache,
+                               std::string());
 }
 
 void BreakingNewsGCMAppHandler::OnJsonSuccess(
diff --git a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h
index c21a05b..4dcfe34 100644
--- a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h
+++ b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h
@@ -8,6 +8,7 @@
 #include "base/memory/weak_ptr.h"
 #include "components/gcm_driver/gcm_app_handler.h"
 #include "components/gcm_driver/instance_id/instance_id.h"
+#include "components/ntp_snippets/breaking_news/breaking_news_listener.h"
 #include "components/ntp_snippets/breaking_news/subscription_manager.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -27,7 +28,8 @@
 // Handler for pushed GCM breaking news. It retrieves a subscription token
 // from the GCM server and registers/unregisters itself with the GCM service to
 // be called upon received push breaking news.
-class BreakingNewsGCMAppHandler : public gcm::GCMAppHandler {
+class BreakingNewsGCMAppHandler : public BreakingNewsListener,
+                                  public gcm::GCMAppHandler {
  public:
   // Callbacks for JSON parsing to allow injecting platform-dependent code.
   using SuccessCallback =
@@ -51,14 +53,9 @@
   // If still listening, calls StopListening()
   ~BreakingNewsGCMAppHandler() override;
 
-  // Subscribe to the GCM service if necessary and start listening for pushed
-  // content suggestions. Must not be called if already listening.
-  void StartListening(OnNewContentCallback on_new_content_callback);
-
-  // Remove the handler, and stop listening for incoming GCM messages. Any
-  // further pushed content suggestions will be ignored. Must be called while
-  // listening.
-  void StopListening();
+  // BreakingNewsListener overrides.
+  void StartListening(OnNewContentCallback on_new_content_callback) override;
+  void StopListening() override;
 
   // GCMAppHandler overrides.
   void ShutdownHandler() override;
@@ -100,7 +97,7 @@
   // the content provider.
   OnNewContentCallback on_new_content_callback_;
 
-  base::WeakPtrFactory<BreakingNewsGCMAppHandler> weak_factory_;
+  base::WeakPtrFactory<BreakingNewsGCMAppHandler> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(BreakingNewsGCMAppHandler);
 };
diff --git a/components/ntp_snippets/breaking_news/breaking_news_listener.h b/components/ntp_snippets/breaking_news/breaking_news_listener.h
new file mode 100644
index 0000000..41c1909
--- /dev/null
+++ b/components/ntp_snippets/breaking_news/breaking_news_listener.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_LISTENER_H_
+#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_LISTENER_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/values.h"
+
+namespace ntp_snippets {
+
+class BreakingNewsListener {
+ public:
+  using OnNewContentCallback =
+      base::Callback<void(std::unique_ptr<base::Value> content)>;
+
+  // Subscribe to the breaking news service and start listening for pushed
+  // breaking news. Must not be called if already listening.
+  virtual void StartListening(OnNewContentCallback on_new_content_callback) = 0;
+
+  // Stop listening for incoming breaking news. Any further pushed breaking news
+  // will be ignored. Must be called while listening.
+  virtual void StopListening() = 0;
+};
+}  // namespace ntp_snippets
+
+#endif  // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_LISTENER_H_
diff --git a/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.cc b/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.cc
index 0d57a2d..bfa8cd3 100644
--- a/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.cc
+++ b/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/json/json_writer.h"
 #include "base/time/clock.h"
-#include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h"
+#include "components/ntp_snippets/breaking_news/breaking_news_listener.h"
 #include "components/ntp_snippets/category.h"
 #include "components/ntp_snippets/pref_names.h"
 #include "components/ntp_snippets/remote/json_to_categories.h"
@@ -17,11 +17,11 @@
 
 BreakingNewsSuggestionsProvider::BreakingNewsSuggestionsProvider(
     ContentSuggestionsProvider::Observer* observer,
-    std::unique_ptr<BreakingNewsGCMAppHandler> gcm_app_handler,
+    std::unique_ptr<BreakingNewsListener> breaking_news_listener,
     std::unique_ptr<base::Clock> clock,
     std::unique_ptr<RemoteSuggestionsDatabase> database)
     : ContentSuggestionsProvider(observer),
-      gcm_app_handler_(std::move(gcm_app_handler)),
+      breaking_news_listener_(std::move(breaking_news_listener)),
       clock_(std::move(clock)),
       database_(std::move(database)),
       provided_category_(
@@ -33,17 +33,14 @@
   database_->LoadSnippets(
       base::Bind(&BreakingNewsSuggestionsProvider::OnDatabaseLoaded,
                  base::Unretained(this)));
+  // Unretained because |this| owns |breaking_news_listener_|.
+  breaking_news_listener_->StartListening(
+      base::Bind(&BreakingNewsSuggestionsProvider::OnNewContentSuggestion,
+                 base::Unretained(this)));
 }
 
 BreakingNewsSuggestionsProvider::~BreakingNewsSuggestionsProvider() {
-  gcm_app_handler_->StopListening();
-}
-
-void BreakingNewsSuggestionsProvider::Start() {
-  // Unretained because |this| owns |gcm_app_handler_|.
-  gcm_app_handler_->StartListening(
-      base::Bind(&BreakingNewsSuggestionsProvider::OnNewContentSuggestion,
-                 base::Unretained(this)));
+  breaking_news_listener_->StopListening();
 }
 
 void BreakingNewsSuggestionsProvider::OnNewContentSuggestion(
diff --git a/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h b/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h
index df316a9..23b40ab 100644
--- a/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h
+++ b/components/ntp_snippets/breaking_news/breaking_news_suggestions_provider.h
@@ -11,7 +11,7 @@
 #include "components/prefs/pref_registry_simple.h"
 
 namespace ntp_snippets {
-class BreakingNewsGCMAppHandler;
+class BreakingNewsListener;
 }
 
 namespace base {
@@ -20,21 +20,20 @@
 
 namespace ntp_snippets {
 
-// Receives breaking news suggestions via GCM push messages, stores them and
-// provides them as content suggestions.
-class BreakingNewsSuggestionsProvider : public ContentSuggestionsProvider {
+// Receives breaking news suggestions asynchronously via BreakingNewsListener,
+// stores them and provides them as content suggestions.
+// This class is final because it does things in its constructor which make it
+// unsafe to derive from it.
+class BreakingNewsSuggestionsProvider final
+    : public ContentSuggestionsProvider {
  public:
   BreakingNewsSuggestionsProvider(
       ContentSuggestionsProvider::Observer* observer,
-      std::unique_ptr<BreakingNewsGCMAppHandler> gcm_app_handler,
+      std::unique_ptr<BreakingNewsListener> breaking_news_listener_,
       std::unique_ptr<base::Clock> clock,
       std::unique_ptr<RemoteSuggestionsDatabase> database);
   ~BreakingNewsSuggestionsProvider() override;
 
-  // Starts the underlying GCM handler and registers the callback when GCM
-  // receives a message.
-  void Start();
-
  private:
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
@@ -55,8 +54,8 @@
       const DismissedSuggestionsCallback& callback) override;
   void ClearDismissedSuggestionsForDebugging(Category category) override;
 
-  // Callback called from the GCM handler when new content has been pushed from
-  // the server.
+  // Callback called from the breaking news listener when new content has been
+  // pushed from the server.
   void OnNewContentSuggestion(std::unique_ptr<base::Value> content);
 
   // Callbacks for the RemoteSuggestionsDatabase.
@@ -67,7 +66,7 @@
   void NotifyNewSuggestions(
       std::vector<std::unique_ptr<RemoteSuggestion>> suggestions);
 
-  std::unique_ptr<BreakingNewsGCMAppHandler> gcm_app_handler_;
+  std::unique_ptr<BreakingNewsListener> breaking_news_listener_;
   std::unique_ptr<base::Clock> clock_;
 
   // The database for persisting suggestions.
diff --git a/components/ntp_snippets/breaking_news/subscription_manager.cc b/components/ntp_snippets/breaking_news/subscription_manager.cc
index 5588bf9..aba15d2 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager.cc
+++ b/components/ntp_snippets/breaking_news/subscription_manager.cc
@@ -66,7 +66,7 @@
       // change.
       // TODO(mamir): store region and language.
       pref_service_->SetString(
-          ntp_snippets::prefs::kContentSuggestionsSubscriptionDataToken,
+          ntp_snippets::prefs::kBreakingNewsSubscriptionDataToken,
           subscription_token_);
       break;
     default:
@@ -97,7 +97,7 @@
 
 bool SubscriptionManager::IsSubscribed() {
   std::string subscription_token_ = pref_service_->GetString(
-      ntp_snippets::prefs::kContentSuggestionsSubscriptionDataToken);
+      ntp_snippets::prefs::kBreakingNewsSubscriptionDataToken);
   return !subscription_token_.empty();
 }
 
@@ -109,7 +109,7 @@
       // In case of successful unsubscription, clear the previously stored data.
       // TODO(mamir): clear stored region and language.
       pref_service_->ClearPref(
-          ntp_snippets::prefs::kContentSuggestionsSubscriptionDataToken);
+          ntp_snippets::prefs::kBreakingNewsSubscriptionDataToken);
       break;
     default:
       // TODO(mamir): handle failure.
@@ -118,14 +118,13 @@
 }
 
 void SubscriptionManager::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterStringPref(prefs::kContentSuggestionsSubscriptionDataToken,
+  registry->RegisterStringPref(prefs::kBreakingNewsSubscriptionDataToken,
                                std::string());
 }
 
 GURL GetPushUpdatesSubscriptionEndpoint(version_info::Channel channel) {
   std::string endpoint = base::GetFieldTrialParamValueByFeature(
-      ntp_snippets::kContentSuggestionsPushFeature,
-      kPushSubscriptionBackendParam);
+      ntp_snippets::kBreakingNewsPushFeature, kPushSubscriptionBackendParam);
   if (!endpoint.empty()) {
     return GURL{endpoint};
   }
@@ -146,8 +145,7 @@
 
 GURL GetPushUpdatesUnsubscriptionEndpoint(version_info::Channel channel) {
   std::string endpoint = base::GetFieldTrialParamValueByFeature(
-      ntp_snippets::kContentSuggestionsPushFeature,
-      kPushUnsubscriptionBackendParam);
+      ntp_snippets::kBreakingNewsPushFeature, kPushUnsubscriptionBackendParam);
   if (!endpoint.empty()) {
     return GURL{endpoint};
   }
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_unittest.cc b/components/ntp_snippets/breaking_news/subscription_manager_unittest.cc
index 1cf4f41..b90d1e5 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager_unittest.cc
+++ b/components/ntp_snippets/breaking_news/subscription_manager_unittest.cc
@@ -71,7 +71,7 @@
   RespondWithData("");
   EXPECT_TRUE(manager.IsSubscribed());
   EXPECT_EQ(GetPrefService()->GetString(
-                ntp_snippets::prefs::kContentSuggestionsSubscriptionDataToken),
+                ntp_snippets::prefs::kBreakingNewsSubscriptionDataToken),
             token);
 }
 
@@ -83,33 +83,33 @@
   RespondWithError(net::ERR_TIMED_OUT);
   EXPECT_FALSE(manager.IsSubscribed());
   EXPECT_FALSE(GetPrefService()->HasPrefPath(
-      ntp_snippets::prefs::kContentSuggestionsSubscriptionDataToken));
+      ntp_snippets::prefs::kBreakingNewsSubscriptionDataToken));
 }
 
 TEST_F(SubscriptionManagerTest, UnsubscribeSuccessfully) {
   std::string token = "1234567890";
   GetPrefService()->SetString(
-      ntp_snippets::prefs::kContentSuggestionsSubscriptionDataToken, token);
+      ntp_snippets::prefs::kBreakingNewsSubscriptionDataToken, token);
   SubscriptionManager manager(GetRequestContext(), GetPrefService(), GURL(url),
                               GURL(url));
   manager.Unsubscribe(token);
   RespondWithData("");
   EXPECT_FALSE(manager.IsSubscribed());
   EXPECT_FALSE(GetPrefService()->HasPrefPath(
-      ntp_snippets::prefs::kContentSuggestionsSubscriptionDataToken));
+      ntp_snippets::prefs::kBreakingNewsSubscriptionDataToken));
 }
 
 TEST_F(SubscriptionManagerTest, UnsubscribeWithErrors) {
   std::string token = "1234567890";
   GetPrefService()->SetString(
-      ntp_snippets::prefs::kContentSuggestionsSubscriptionDataToken, token);
+      ntp_snippets::prefs::kBreakingNewsSubscriptionDataToken, token);
   SubscriptionManager manager(GetRequestContext(), GetPrefService(), GURL(url),
                               GURL(url));
   manager.Unsubscribe(token);
   RespondWithError(net::ERR_TIMED_OUT);
   EXPECT_TRUE(manager.IsSubscribed());
   EXPECT_EQ(GetPrefService()->GetString(
-                ntp_snippets::prefs::kContentSuggestionsSubscriptionDataToken),
+                ntp_snippets::prefs::kBreakingNewsSubscriptionDataToken),
             token);
 }
 
diff --git a/components/ntp_snippets/features.cc b/components/ntp_snippets/features.cc
index d080397..f32adff 100644
--- a/components/ntp_snippets/features.cc
+++ b/components/ntp_snippets/features.cc
@@ -18,7 +18,7 @@
                                         &kBookmarkSuggestionsFeature,
                                         &kCategoryOrder,
                                         &kCategoryRanker,
-                                        &kContentSuggestionsPushFeature,
+                                        &kBreakingNewsPushFeature,
                                         &kForeignSessionsSuggestionsFeature,
                                         &kIncreasedVisibility,
                                         &kKeepPrefetchedContentSuggestions,
@@ -46,8 +46,8 @@
 const base::Feature kForeignSessionsSuggestionsFeature{
     "NTPForeignSessionsSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kContentSuggestionsPushFeature{
-    "ContentSuggestionsPush", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kBreakingNewsPushFeature{"BreakingNewsPush",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kCategoryRanker{"ContentSuggestionsCategoryRanker",
                                     base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/ntp_snippets/features.h b/components/ntp_snippets/features.h
index be450632..83800fa15 100644
--- a/components/ntp_snippets/features.h
+++ b/components/ntp_snippets/features.h
@@ -38,7 +38,7 @@
 extern const base::Feature kIncreasedVisibility;
 
 // Feature to listen for GCM push updates from the server.
-extern const base::Feature kContentSuggestionsPushFeature;
+extern const base::Feature kBreakingNewsPushFeature;
 
 // Feature to choose a category ranker.
 extern const base::Feature kCategoryRanker;
diff --git a/components/ntp_snippets/pref_names.cc b/components/ntp_snippets/pref_names.cc
index 13a2b615..1583914 100644
--- a/components/ntp_snippets/pref_names.cc
+++ b/components/ntp_snippets/pref_names.cc
@@ -81,11 +81,11 @@
 const char kClickBasedCategoryRankerLastDecayTime[] =
     "ntp_suggestions.click_based_category_ranker.last_decay_time";
 
-const char kContentSuggestionsSubscriptionDataToken[] =
-    "ntp_suggestions.content_suggestions_subscription_data.token";
+const char kBreakingNewsSubscriptionDataToken[] =
+    "ntp_suggestions.breaking_news_subscription_data.token";
 
-const char kContentSuggestionsGCMSubscriptionTokenCache[] =
-    "ntp_suggestions.content_suggestions_gcm_subscription_token_cache";
+const char kBreakingNewsGCMSubscriptionTokenCache[] =
+    "ntp_suggestions.breaking_news_gcm_subscription_token_cache";
 
 }  // namespace prefs
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/pref_names.h b/components/ntp_snippets/pref_names.h
index 8dac4cd..75090cc 100644
--- a/components/ntp_snippets/pref_names.h
+++ b/components/ntp_snippets/pref_names.h
@@ -90,23 +90,22 @@
 // The pref name for the time when last click decay has happened.
 extern const char kClickBasedCategoryRankerLastDecayTime[];
 
-// kContentSuggestionsSubscriptionData* hold the data used when subscribing for
-// content suggestions via GCM push updates. They are stored in pref such that
-// in case of change (e.g. the token renders invalid), re-subscription is
-// required.
+// The folllowing prefs hold the data used when subscribing for content
+// suggestions via GCM push updates. They are stored in pref such that in case
+// of change (e.g. the token renders invalid), re-subscription is required.
 ///////////////////////////////////////////////////////////////////////////////
 // The pref name for the subscription token used when subscription for
 // breaking news push updates.
-extern const char kContentSuggestionsSubscriptionDataToken[];
-//////////////////////// End of kContentSuggestionsSubscriptionData *
+extern const char kBreakingNewsSubscriptionDataToken[];
+//////////////////////// End of breaking news subscription-related prefs.
 
 // The pref name for the subscription token received from the gcm server. As
 // recommended by the GCM team, it is cached in pref for faster bookkeeping to
 // see if subscription exists. This is pref holds the valid token even if
 // different from the one used for subscription. When they are different, Chrome
 // unsubscribes the old token from the content suggestions server, subscribe
-// with the new one and update kContentSuggestionsSubscriptionDataToken.
-extern const char kContentSuggestionsGCMSubscriptionTokenCache[];
+// with the new one and update kBreakingNewsSubscriptionDataToken.
+extern const char kBreakingNewsGCMSubscriptionTokenCache[];
 
 }  // namespace prefs
 }  // namespace ntp_snippets
diff --git a/components/ntp_tiles/metrics.cc b/components/ntp_tiles/metrics.cc
index f657ced1..4064c15 100644
--- a/components/ntp_tiles/metrics.cc
+++ b/components/ntp_tiles/metrics.cc
@@ -85,46 +85,45 @@
 
 }  // namespace
 
-void RecordPageImpression(const std::vector<TileImpression>& tiles,
+void RecordPageImpression(int number_of_tiles) {
+  UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfTiles", number_of_tiles);
+}
+
+void RecordTileImpression(int index,
+                          TileSource source,
+                          TileVisualType type,
+                          const GURL& url,
                           rappor::RapporService* rappor_service) {
-  UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.NumberOfTiles", tiles.size());
+  UMA_HISTOGRAM_ENUMERATION("NewTabPage.SuggestionsImpression", index,
+                            kMaxNumTiles);
 
-  for (int index = 0; index < static_cast<int>(tiles.size()); index++) {
-    TileSource source = tiles[index].source;
-    TileVisualType tile_type = tiles[index].type;
+  std::string source_name = GetSourceHistogramName(source);
+  std::string impression_histogram = base::StringPrintf(
+      "NewTabPage.SuggestionsImpression.%s", source_name.c_str());
+  LogHistogramEvent(impression_histogram, index, kMaxNumTiles);
 
-    UMA_HISTOGRAM_ENUMERATION("NewTabPage.SuggestionsImpression", index,
-                              kMaxNumTiles);
+  if (type > LAST_RECORDED_TILE_TYPE) {
+    return;
+  }
 
-    std::string source_name = GetSourceHistogramName(source);
-    std::string impression_histogram = base::StringPrintf(
-        "NewTabPage.SuggestionsImpression.%s", source_name.c_str());
-    LogHistogramEvent(impression_histogram, index, kMaxNumTiles);
+  UMA_HISTOGRAM_ENUMERATION("NewTabPage.TileType", type,
+                            LAST_RECORDED_TILE_TYPE + 1);
 
-    if (tile_type > LAST_RECORDED_TILE_TYPE) {
-      continue;
-    }
+  std::string tile_type_histogram =
+      base::StringPrintf("NewTabPage.TileType.%s", source_name.c_str());
+  LogHistogramEvent(tile_type_histogram, type, LAST_RECORDED_TILE_TYPE + 1);
 
-    UMA_HISTOGRAM_ENUMERATION("NewTabPage.TileType", tile_type,
-                              LAST_RECORDED_TILE_TYPE + 1);
+  const char* tile_type_suffix = GetTileTypeSuffix(type);
+  if (tile_type_suffix) {
+    // Note: This handles a null |rappor_service|.
+    rappor::SampleDomainAndRegistryFromGURL(
+        rappor_service,
+        base::StringPrintf("NTP.SuggestionsImpressions.%s", tile_type_suffix),
+        url);
 
-    std::string tile_type_histogram =
-        base::StringPrintf("NewTabPage.TileType.%s", source_name.c_str());
-    LogHistogramEvent(tile_type_histogram, tile_type,
-                      LAST_RECORDED_TILE_TYPE + 1);
-
-    const char* tile_type_suffix = GetTileTypeSuffix(tile_type);
-    if (tile_type_suffix) {
-      // Note: This handles a null |rappor_service|.
-      rappor::SampleDomainAndRegistryFromGURL(
-          rappor_service,
-          base::StringPrintf("NTP.SuggestionsImpressions.%s", tile_type_suffix),
-          tiles[index].url);
-
-      std::string icon_impression_histogram = base::StringPrintf(
-          "NewTabPage.SuggestionsImpression.%s", tile_type_suffix);
-      LogHistogramEvent(icon_impression_histogram, index, kMaxNumTiles);
-    }
+    std::string icon_impression_histogram = base::StringPrintf(
+        "NewTabPage.SuggestionsImpression.%s", tile_type_suffix);
+    LogHistogramEvent(icon_impression_histogram, index, kMaxNumTiles);
   }
 }
 
diff --git a/components/ntp_tiles/metrics.h b/components/ntp_tiles/metrics.h
index 187d719..eb0bf2d2 100644
--- a/components/ntp_tiles/metrics.h
+++ b/components/ntp_tiles/metrics.h
@@ -19,19 +19,16 @@
 namespace ntp_tiles {
 namespace metrics {
 
-struct TileImpression {
-  TileImpression(TileSource source, TileVisualType type, const GURL& url)
-      : source(source), type(type), url(url) {}
-
-  TileSource source;
-  TileVisualType type;
-  GURL url;
-};
-
 // Records an NTP impression, after all tiles have loaded.
-// Includes the visual types (see above) of all visible tiles. If
-// |rappor_service| is null, no rappor metrics will be reported.
-void RecordPageImpression(const std::vector<TileImpression>& tiles,
+void RecordPageImpression(int number_of_tiles);
+
+// Records a tile impression at |index| (zero based) created by |source|. This
+// should be called only after the visual |type| of the tile has been
+// determined. If |rappor_service| is null, no rappor metrics will be reported.
+void RecordTileImpression(int index,
+                          TileSource source,
+                          TileVisualType type,
+                          const GURL& url,
                           rappor::RapporService* rappor_service);
 
 // Records a click on a tile.
diff --git a/components/ntp_tiles/metrics_unittest.cc b/components/ntp_tiles/metrics_unittest.cc
index 4b5eac9a..dbbe4c1 100644
--- a/components/ntp_tiles/metrics_unittest.cc
+++ b/components/ntp_tiles/metrics_unittest.cc
@@ -22,19 +22,33 @@
 using testing::ElementsAre;
 using testing::IsEmpty;
 
-TEST(RecordPageImpressionTest, ShouldRecordUmaForIcons) {
+TEST(RecordPageImpressionTest, ShouldRecordNumberOfTiles) {
   base::HistogramTester histogram_tester;
-  RecordPageImpression({{TileSource::TOP_SITES, ICON_REAL, GURL()},
-                        {TileSource::TOP_SITES, ICON_REAL, GURL()},
-                        {TileSource::TOP_SITES, ICON_REAL, GURL()},
-                        {TileSource::TOP_SITES, ICON_COLOR, GURL()},
-                        {TileSource::TOP_SITES, ICON_COLOR, GURL()},
-                        {TileSource::SUGGESTIONS_SERVICE, ICON_REAL, GURL()},
-                        {TileSource::SUGGESTIONS_SERVICE, ICON_DEFAULT, GURL()},
-                        {TileSource::POPULAR, ICON_COLOR, GURL()}},
-                       /*rappor_service=*/nullptr);
+  RecordPageImpression(5);
   EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.NumberOfTiles"),
-              ElementsAre(base::Bucket(/*min=*/8, /*count=*/1)));
+              ElementsAre(base::Bucket(/*min=*/5, /*count=*/1)));
+}
+
+TEST(RecordTileImpressionTest, ShouldRecordUmaForIcons) {
+  base::HistogramTester histogram_tester;
+
+  RecordTileImpression(0, TileSource::TOP_SITES, ICON_REAL, GURL(),
+                       /*rappor_service=*/nullptr);
+  RecordTileImpression(1, TileSource::TOP_SITES, ICON_REAL, GURL(),
+                       /*rappor_service=*/nullptr);
+  RecordTileImpression(2, TileSource::TOP_SITES, ICON_REAL, GURL(),
+                       /*rappor_service=*/nullptr);
+  RecordTileImpression(3, TileSource::TOP_SITES, ICON_COLOR, GURL(),
+                       /*rappor_service=*/nullptr);
+  RecordTileImpression(4, TileSource::TOP_SITES, ICON_COLOR, GURL(),
+                       /*rappor_service=*/nullptr);
+  RecordTileImpression(5, TileSource::SUGGESTIONS_SERVICE, ICON_REAL, GURL(),
+                       /*rappor_service=*/nullptr);
+  RecordTileImpression(6, TileSource::SUGGESTIONS_SERVICE, ICON_DEFAULT, GURL(),
+                       /*rappor_service=*/nullptr);
+  RecordTileImpression(7, TileSource::POPULAR, ICON_COLOR, GURL(),
+                       /*rappor_service=*/nullptr);
+
   EXPECT_THAT(
       histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression"),
       ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
@@ -88,14 +102,16 @@
               ElementsAre(base::Bucket(/*min=*/6, /*count=*/1)));
 }
 
-TEST(RecordPageImpressionTest, ShouldRecordUmaForThumbnails) {
+TEST(RecordTileImpressionTest, ShouldRecordUmaForThumbnails) {
   base::HistogramTester histogram_tester;
-  RecordPageImpression({{TileSource::TOP_SITES, THUMBNAIL_FAILED, GURL()},
-                        {TileSource::SUGGESTIONS_SERVICE, THUMBNAIL, GURL()},
-                        {TileSource::POPULAR, THUMBNAIL, GURL()}},
+
+  RecordTileImpression(0, TileSource::TOP_SITES, THUMBNAIL_FAILED, GURL(),
                        /*rappor_service=*/nullptr);
-  EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.NumberOfTiles"),
-              ElementsAre(base::Bucket(/*min=*/3, /*count=*/1)));
+  RecordTileImpression(1, TileSource::SUGGESTIONS_SERVICE, THUMBNAIL, GURL(),
+                       /*rappor_service=*/nullptr);
+  RecordTileImpression(2, TileSource::POPULAR, THUMBNAIL, GURL(),
+                       /*rappor_service=*/nullptr);
+
   EXPECT_THAT(
       histogram_tester.GetAllSamples("NewTabPage.SuggestionsImpression"),
       ElementsAre(base::Bucket(/*min=*/0, /*count=*/1),
@@ -216,14 +232,15 @@
       IsEmpty());
 }
 
-TEST(RecordPageImpressionTest, ShouldRecordRappor) {
+TEST(RecordTileImpressionTest, ShouldRecordRappor) {
   rappor::TestRapporServiceImpl rappor_service;
 
-  RecordPageImpression(
-      {{TileSource::TOP_SITES, ICON_REAL, GURL("http://www.site1.com/")},
-       {TileSource::TOP_SITES, ICON_COLOR, GURL("http://www.site2.com/")},
-       {TileSource::TOP_SITES, ICON_DEFAULT, GURL("http://www.site3.com/")}},
-      &rappor_service);
+  RecordTileImpression(0, TileSource::TOP_SITES, ICON_REAL,
+                       GURL("http://www.site1.com/"), &rappor_service);
+  RecordTileImpression(1, TileSource::TOP_SITES, ICON_COLOR,
+                       GURL("http://www.site2.com/"), &rappor_service);
+  RecordTileImpression(2, TileSource::TOP_SITES, ICON_DEFAULT,
+                       GURL("http://www.site3.com/"), &rappor_service);
 
   EXPECT_EQ(3, rappor_service.GetReportsCount());
 
@@ -255,13 +272,13 @@
   }
 }
 
-TEST(RecordPageImpressionTest, ShouldNotRecordRapporForUnknownTileType) {
+TEST(RecordTileImpressionTest, ShouldNotRecordRapporForUnknownTileType) {
   rappor::TestRapporServiceImpl rappor_service;
 
-  RecordPageImpression(
-      {{TileSource::TOP_SITES, ICON_REAL, GURL("http://www.s1.com/")},
-       {TileSource::TOP_SITES, UNKNOWN_TILE_TYPE, GURL("http://www.s2.com/")}},
-      &rappor_service);
+  RecordTileImpression(0, TileSource::TOP_SITES, ICON_REAL,
+                       GURL("http://www.s1.com/"), &rappor_service);
+  RecordTileImpression(1, TileSource::TOP_SITES, UNKNOWN_TILE_TYPE,
+                       GURL("http://www.s2.com/"), &rappor_service);
 
   // Unknown tile type shouldn't get reported.
   EXPECT_EQ(1, rappor_service.GetReportsCount());
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc
index 21814d2..b740f5b 100644
--- a/components/printing/renderer/print_web_view_helper.cc
+++ b/components/printing/renderer/print_web_view_helper.cc
@@ -581,7 +581,15 @@
       blink::WebView::Create(nullptr, blink::kWebPageVisibilityStateVisible);
   web_view->GetSettings()->SetJavaScriptEnabled(true);
 
-  blink::WebFrameClient frame_client;
+  class HeaderAndFooterClient final : public blink::WebFrameClient {
+   public:
+    void FrameDetached(blink::WebLocalFrame* frame,
+                       DetachType detach_type) override {
+      frame->FrameWidget()->Close();
+      frame->Close();
+    }
+  };
+  HeaderAndFooterClient frame_client;
   blink::WebLocalFrame* frame = blink::WebLocalFrame::Create(
       blink::WebTreeScopeType::kDocument, &frame_client, nullptr, nullptr);
   web_view->SetMainFrame(frame);
@@ -680,6 +688,8 @@
       blink::WebSandboxFlags sandbox_flags,
       const blink::WebParsedFeaturePolicy& container_policy,
       const blink::WebFrameOwnerProperties& frame_owner_properties) override;
+  void FrameDetached(blink::WebLocalFrame* frame,
+                     DetachType detach_type) override;
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader() override;
 
   void CallOnReady();
@@ -848,6 +858,12 @@
   return nullptr;
 }
 
+void PrepareFrameAndViewForPrint::FrameDetached(blink::WebLocalFrame* frame,
+                                                DetachType detach_type) {
+  frame->FrameWidget()->Close();
+  frame->Close();
+}
+
 std::unique_ptr<blink::WebURLLoader>
 PrepareFrameAndViewForPrint::CreateURLLoader() {
   // TODO(yhirano): Stop using Platform::CreateURLLoader() here.
@@ -887,7 +903,6 @@
     if (owns_web_view_) {
       DCHECK(!frame->IsLoading());
       owns_web_view_ = false;
-      frame->FrameWidget()->Close();
       web_view->Close();
     }
   }
diff --git a/content/browser/loader/DEPS b/content/browser/loader/DEPS
index 51d8fdb..c6e43ce 100644
--- a/content/browser/loader/DEPS
+++ b/content/browser/loader/DEPS
@@ -165,6 +165,7 @@
     "+content/browser/streams/stream_registry.h",
     "+content/common/content_export.h",
     "+content/common/net/url_request_service_worker_data.h",
+    "+content/common/site_isolation_policy.h",
     "+content/public/browser/browser_thread.h",
     "+content/public/browser/navigation_ui_data.h",
     "+content/public/browser/plugin_service.h",
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 548a9af..05d2f2cd 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -78,6 +78,7 @@
 #include "content/common/resource_request.h"
 #include "content/common/resource_request_body_impl.h"
 #include "content/common/resource_request_completion_status.h"
+#include "content/common/site_isolation_policy.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/global_request_id.h"
@@ -168,6 +169,9 @@
 // The interval for calls to ResourceDispatcherHostImpl::UpdateLoadStates
 const int kUpdateLoadStatesIntervalMsec = 250;
 
+// The interval for calls to RecordOutstandingRequestsStats.
+const int kRecordOutstandingRequestsStatsIntervalSec = 60;
+
 // Maximum byte "cost" of all the outstanding requests for a renderer.
 // See declaration of |max_outstanding_requests_cost_per_process_| for details.
 // This bound is 25MB, which allows for around 6000 outstanding requests.
@@ -360,7 +364,16 @@
       FROM_HERE,
       base::Bind(&ResourceDispatcherHostImpl::OnInit, base::Unretained(this)));
 
-  update_load_states_timer_.reset(new base::RepeatingTimer());
+  update_load_states_timer_ = base::MakeUnique<base::RepeatingTimer>();
+
+  // Monitor per-tab outstanding requests only if OOPIF is not enabled, because
+  // the routing id doesn't represent tabs in OOPIF modes.
+  if (!SiteIsolationPolicy::UseDedicatedProcessesForAllSites() &&
+      !SiteIsolationPolicy::IsTopDocumentIsolationEnabled() &&
+      !SiteIsolationPolicy::AreIsolatedOriginsEnabled()) {
+    record_outstanding_requests_stats_timer_ =
+        base::MakeUnique<base::RepeatingTimer>();
+  }
 }
 
 // The default ctor is only used by unittests. It is reasonable to assume that
@@ -371,6 +384,7 @@
 
 ResourceDispatcherHostImpl::~ResourceDispatcherHostImpl() {
   DCHECK(outstanding_requests_stats_map_.empty());
+  DCHECK(outstanding_requests_per_tab_map_.empty());
   DCHECK(g_resource_dispatcher_host);
   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
   g_resource_dispatcher_host = NULL;
@@ -589,13 +603,20 @@
 }
 
 void ResourceDispatcherHostImpl::DidStartRequest(ResourceLoader* loader) {
-  // Make sure we have the load state monitor running.
+  // Make sure we have the load state monitors running.
   if (!update_load_states_timer_->IsRunning() &&
       scheduler_->HasLoadingClients()) {
     update_load_states_timer_->Start(
         FROM_HERE, TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec),
         this, &ResourceDispatcherHostImpl::UpdateLoadInfo);
   }
+  if (record_outstanding_requests_stats_timer_ &&
+      !record_outstanding_requests_stats_timer_->IsRunning()) {
+    record_outstanding_requests_stats_timer_->Start(
+        FROM_HERE,
+        TimeDelta::FromSeconds(kRecordOutstandingRequestsStatsIntervalSec),
+        this, &ResourceDispatcherHostImpl::RecordOutstandingRequestsStats);
+  }
 }
 
 void ResourceDispatcherHostImpl::DidReceiveRedirect(
@@ -784,10 +805,11 @@
   is_shutdown_ = true;
   pending_loaders_.clear();
 
-  // Make sure we shutdown the timer now, otherwise by the time our destructor
+  // Make sure we shutdown the timers now, otherwise by the time our destructor
   // runs if the timer is still running the Task is deleted twice (once by
   // the MessageLoop and the second time by RepeatingTimer).
   update_load_states_timer_.reset();
+  record_outstanding_requests_stats_timer_.reset();
 
   // Clear blocked requests if any left.
   // Note that we have to do this in 2 passes as we cannot call
@@ -1919,6 +1941,18 @@
     outstanding_requests_stats_map_[info.GetChildID()] = stats;
 }
 
+void ResourceDispatcherHostImpl::IncrementOutstandingRequestsPerTab(
+    int count,
+    const ResourceRequestInfoImpl& info) {
+  auto key = std::make_pair(info.GetChildID(), info.GetRouteID());
+  OutstandingRequestsPerTabMap::iterator entry =
+      outstanding_requests_per_tab_map_.insert(std::make_pair(key, 0)).first;
+  entry->second += count;
+  DCHECK_GE(entry->second, 0);
+  if (entry->second == 0)
+    outstanding_requests_per_tab_map_.erase(entry);
+}
+
 ResourceDispatcherHostImpl::OustandingRequestsStats
 ResourceDispatcherHostImpl::IncrementOutstandingRequestsMemory(
     int count,
@@ -1954,6 +1988,8 @@
   DCHECK_GE(stats.num_requests, 0);
   UpdateOutstandingRequestsStats(*info, stats);
 
+  IncrementOutstandingRequestsPerTab(count, *info);
+
   if (num_in_flight_requests_ > largest_outstanding_request_count_seen_) {
     largest_outstanding_request_count_seen_ = num_in_flight_requests_;
     UMA_HISTOGRAM_COUNTS_1M(
@@ -1969,6 +2005,14 @@
         largest_outstanding_request_per_process_count_seen_);
   }
 
+  if (num_in_flight_requests_ > peak_outstanding_request_count_)
+    peak_outstanding_request_count_ = num_in_flight_requests_;
+
+  if (HasRequestsFromMultipleActiveTabs() &&
+      num_in_flight_requests_ > peak_outstanding_request_count_multitab_) {
+    peak_outstanding_request_count_multitab_ = num_in_flight_requests_;
+  }
+
   return stats;
 }
 
@@ -2498,6 +2542,23 @@
       base::Bind(UpdateLoadStateOnUI, loader_delegate_, base::Passed(&infos)));
 }
 
+void ResourceDispatcherHostImpl::RecordOutstandingRequestsStats() {
+  if (peak_outstanding_request_count_ != 0) {
+    UMA_HISTOGRAM_COUNTS_1M(
+        "Net.ResourceDispatcherHost.PeakOutstandingRequests",
+        peak_outstanding_request_count_);
+    peak_outstanding_request_count_ = num_in_flight_requests_;
+  }
+
+  if (peak_outstanding_request_count_multitab_ != 0) {
+    UMA_HISTOGRAM_COUNTS_1M(
+        "Net.ResourceDispatcherHost.PeakOutstandingRequests.MultiTabLoading",
+        peak_outstanding_request_count_multitab_);
+    peak_outstanding_request_count_multitab_ =
+        HasRequestsFromMultipleActiveTabs() ? num_in_flight_requests_ : 0;
+  }
+}
+
 void ResourceDispatcherHostImpl::BlockRequestsForRoute(
     const GlobalFrameRoutingId& global_routing_id) {
   DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
@@ -2707,4 +2768,20 @@
   return handler;
 }
 
+bool ResourceDispatcherHostImpl::HasRequestsFromMultipleActiveTabs() {
+  if (outstanding_requests_per_tab_map_.size() < 2)
+    return false;
+
+  int active_tabs = 0;
+  for (auto iter = outstanding_requests_per_tab_map_.begin();
+       iter != outstanding_requests_per_tab_map_.end(); ++iter) {
+    if (iter->second > 2) {
+      active_tabs++;
+      if (active_tabs >= 2)
+        return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace content
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index 3f5aa95..70f377e 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -457,6 +457,13 @@
       int count,
       ResourceRequestInfoImpl* info);
 
+  // Called from IncrementOutstandingRequestsCount to update the per-tab
+  // request stats in |outstanding_requests_per_tab_map_|.
+  // TODO(ksakamoto): This is just for temporary metrics collection for the
+  // Loading Dispatcher v0 (crbug.com/723233), and will be removed soon.
+  void IncrementOutstandingRequestsPerTab(int count,
+                                          const ResourceRequestInfoImpl& info);
+
   // Estimate how much heap space |request| will consume to run.
   static int CalculateApproximateMemoryCost(net::URLRequest* request);
 
@@ -513,6 +520,10 @@
   // Checks all pending requests and updates the load info if necessary.
   void UpdateLoadInfo();
 
+  // Records statistics about outstanding requests since the last call, and
+  // reset the stats.
+  void RecordOutstandingRequestsStats();
+
   // Resumes or cancels (if |cancel_requests| is true) any blocked requests.
   void ProcessBlockedRequestsForRoute(
       const GlobalFrameRoutingId& global_routing_id,
@@ -695,6 +706,10 @@
       bool must_download,
       bool is_new_request);
 
+  // Returns true if there are two or more tabs that are not network 2-quiet
+  // (i.e. have at least three outstanding requests).
+  bool HasRequestsFromMultipleActiveTabs();
+
   LoaderMap pending_loaders_;
 
   // Collection of temp files downloaded for child processes via
@@ -710,6 +725,10 @@
   // not empty and at least one RenderViewHost is loading.
   std::unique_ptr<base::RepeatingTimer> update_load_states_timer_;
 
+  // A timer that periodically calls RecordOutstandingRequestsStats.
+  std::unique_ptr<base::RepeatingTimer>
+      record_outstanding_requests_stats_timer_;
+
   // Request ID for browser initiated requests. request_ids generated by
   // child processes are counted up from 0, while browser created requests
   // start at -2 and go down from there. (We need to start at -2 because -1 is
@@ -732,6 +751,14 @@
   typedef std::map<int, OustandingRequestsStats> OutstandingRequestsStatsMap;
   OutstandingRequestsStatsMap outstanding_requests_stats_map_;
 
+  // Maps (child_id, route_id) to the number of outstanding requests.
+  // Used only when OOPIF is not enabled, since in OOPIF modes routing_id
+  // doesn't represent tabs.
+  // TODO(ksakamoto): This is just for temporary metrics collection for the
+  // Loading Dispatcher v0 (crbug.com/723233), and will be removed soon.
+  typedef std::map<std::pair<int, int>, int> OutstandingRequestsPerTabMap;
+  OutstandingRequestsPerTabMap outstanding_requests_per_tab_map_;
+
   // |num_in_flight_requests_| is the total number of requests currently issued
   // summed across all renderers.
   int num_in_flight_requests_;
@@ -763,6 +790,15 @@
   // Largest number of outstanding requests seen so far in any single process.
   int largest_outstanding_request_per_process_count_seen_;
 
+  // Largest number of outstanding requests seen since the last call to
+  // RecordOutstandingRequestsStats.
+  int peak_outstanding_request_count_ = 0;
+
+  // Largest number of outstanding requests seen while there are outstanding
+  // requests from two or more tabs, since the last call to
+  // RecordOutstandingRequestsStats.
+  int peak_outstanding_request_count_multitab_ = 0;
+
   // Time of the last user gesture. Stored so that we can add a load
   // flag to requests occurring soon after a gesture to indicate they
   // may be because of explicit user action.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 52ddbab..617f484 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -988,8 +988,6 @@
   }
   if (browser_plugin_embedder_)
     browser_plugin_embedder_->CancelGuestDialogs();
-  if (delegate_)
-    delegate_->HideValidationMessage(this);
 }
 
 void WebContentsImpl::ClosePage() {
@@ -4696,6 +4694,9 @@
   // Cancel any visible dialogs so they are not left dangling over the sad tab.
   CancelActiveAndPendingDialogs();
 
+  if (delegate_)
+    delegate_->HideValidationMessage(this);
+
   audio_stream_monitor_.RenderProcessGone(rvh->GetProcess()->GetID());
 
   // Reset the loading progress. TODO(avi): What does it mean to have a
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index fea1eb6..2f161b01 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -1467,78 +1467,4 @@
   wc->SetJavaScriptDialogManagerForTesting(nullptr);
 }
 
-class FormBubbleDelegate : public WebContentsDelegate {
- public:
-  FormBubbleDelegate() = default;
-
-  void WaitUntilShown() {
-    while (!is_visible_) {
-      message_loop_runner_ = new MessageLoopRunner;
-      message_loop_runner_->Run();
-    }
-  }
-
-  void WaitUntilHidden() {
-    while (is_visible_) {
-      message_loop_runner_ = new MessageLoopRunner;
-      message_loop_runner_->Run();
-    }
-  }
-
- private:
-  void ShowValidationMessage(WebContents* web_contents,
-                             const gfx::Rect& anchor_in_root_view,
-                             const base::string16& main_text,
-                             const base::string16& sub_text) override {
-    is_visible_ = true;
-    if (message_loop_runner_)
-      message_loop_runner_->Quit();
-  }
-
-  void HideValidationMessage(WebContents* web_contents) override {
-    is_visible_ = false;
-    if (message_loop_runner_)
-      message_loop_runner_->Quit();
-  }
-
-  bool is_visible_ = false;
-  scoped_refptr<MessageLoopRunner> message_loop_runner_;
-};
-
-IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
-                       NavigationHidesFormValidationBubble) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  EXPECT_TRUE(NavigateToURL(
-      shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
-
-  // Start listening for requests to show or hide the form validation bubble.
-  WebContentsImpl* web_contents =
-      static_cast<WebContentsImpl*>(shell()->web_contents());
-  FormBubbleDelegate bubble_delegate;
-  web_contents->SetDelegate(&bubble_delegate);
-
-  // Trigger a form validation bubble and verify that the bubble is shown.
-  std::string script = R"(
-      var input_field = document.createElement('input');
-      input_field.required = true;
-      var form = document.createElement('form');
-      form.appendChild(input_field);
-      document.body.appendChild(form);
-
-      setTimeout(function() {
-              input_field.setCustomValidity('Custom validity message');
-              input_field.reportValidity();
-          },
-          0);
-      )";
-  ASSERT_TRUE(ExecuteScript(web_contents, script));
-  bubble_delegate.WaitUntilShown();
-
-  // Navigate to another page and verify that the form validation bubble is
-  // hidden.
-  EXPECT_TRUE(NavigateToURL(
-      shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
-  bubble_delegate.WaitUntilHidden();
-}
-
 }  // namespace content
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 4d9cae32..0fc9075 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -382,8 +382,6 @@
     (ProceduralBlock)callback;
 // Shows the Sync encryption passphrase (part of Settings).
 - (void)showSyncEncryptionPassphrase;
-// Shows the Native Apps Settings UI (part of Settings).
-- (void)showNativeAppsSettings;
 // Shows the Clear Browsing Data Settings UI (part of Settings).
 - (void)showClearBrowsingDataSettingsController;
 // Shows the Contextual search UI (part of Settings).
@@ -1471,9 +1469,6 @@
     case IDC_RESET_ALL_WEBVIEWS:
       [self.currentBVC resetAllWebViews];
       break;
-    case IDC_SHOW_GOOGLE_APPS_SETTINGS:
-      [self showNativeAppsSettings];
-      break;
     case IDC_SHOW_CLEAR_BROWSING_DATA_SETTINGS:
       [self showClearBrowsingDataSettingsController];
       break;
@@ -2143,18 +2138,6 @@
   } copy];
 }
 
-- (void)showNativeAppsSettings {
-  if (_settingsNavigationController)
-    return;
-  _settingsNavigationController =
-      [SettingsNavigationController newNativeAppsController:_mainBrowserState
-                                                   delegate:self];
-  [[self topPresentedViewController]
-      presentViewController:_settingsNavigationController
-                   animated:YES
-                 completion:nil];
-}
-
 - (void)closeSettingsAnimated:(BOOL)animated
                    completion:(ProceduralBlock)completion {
   DCHECK(_settingsNavigationController);
diff --git a/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm
index ccc45c18..e0dc77209 100644
--- a/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm
+++ b/ios/chrome/browser/content_suggestions/content_suggestions_mediator.mm
@@ -431,7 +431,7 @@
 
   if (mostVisited.size() && !self.recordedPageImpression) {
     self.recordedPageImpression = YES;
-    RecordPageImpression(mostVisited);
+    RecordImpression(mostVisited);
   }
 }
 
diff --git a/ios/chrome/browser/content_suggestions/mediator_util.h b/ios/chrome/browser/content_suggestions/mediator_util.h
index 74cc22e2..f75d042 100644
--- a/ios/chrome/browser/content_suggestions/mediator_util.h
+++ b/ios/chrome/browser/content_suggestions/mediator_util.h
@@ -61,8 +61,8 @@
 // Creates and returns a SectionInfo for the Most Visited section.
 ContentSuggestionsSectionInformation* MostVisitedSectionInformation();
 
-// Records the page impression of the ntp tiles.
-void RecordPageImpression(const std::vector<ntp_tiles::NTPTile>& mostVisited);
+// Records the impression of the NTP and of all |mostVisited| tiles.
+void RecordImpression(const std::vector<ntp_tiles::NTPTile>& mostVisited);
 
 // Converts a ntp_tiles::NTPTile |tile| to a ContentSuggestionsMostVisitedItem
 // with a |sectionInfo|.
diff --git a/ios/chrome/browser/content_suggestions/mediator_util.mm b/ios/chrome/browser/content_suggestions/mediator_util.mm
index 3e02880e..53638396 100644
--- a/ios/chrome/browser/content_suggestions/mediator_util.mm
+++ b/ios/chrome/browser/content_suggestions/mediator_util.mm
@@ -124,14 +124,14 @@
   return sectionInfo;
 }
 
-void RecordPageImpression(const ntp_tiles::NTPTilesVector& mostVisited) {
-  std::vector<ntp_tiles::metrics::TileImpression> tiles;
+void RecordImpression(const ntp_tiles::NTPTilesVector& mostVisited) {
+  int index = 0;
   for (const ntp_tiles::NTPTile& ntpTile : mostVisited) {
-    tiles.emplace_back(ntpTile.source, ntp_tiles::UNKNOWN_TILE_TYPE,
-                       ntpTile.url);
+    ntp_tiles::metrics::RecordTileImpression(
+        index++, ntpTile.source, ntp_tiles::UNKNOWN_TILE_TYPE, ntpTile.url,
+        GetApplicationContext()->GetRapporServiceImpl());
   }
-  ntp_tiles::metrics::RecordPageImpression(
-      tiles, GetApplicationContext()->GetRapporServiceImpl());
+  ntp_tiles::metrics::RecordPageImpression(mostVisited.size());
 }
 
 ContentSuggestionsMostVisitedItem* ConvertNTPTile(
diff --git a/ios/chrome/browser/ui/commands/ios_command_ids.h b/ios/chrome/browser/ui/commands/ios_command_ids.h
index 4c3115d..751932e6 100644
--- a/ios/chrome/browser/ui/commands/ios_command_ids.h
+++ b/ios/chrome/browser/ui/commands/ios_command_ids.h
@@ -58,7 +58,6 @@
 #define IDC_RESET_ALL_WEBVIEWS                         40928
 #define IDC_SHARE_PAGE                                 40929
 #define IDC_BACK_FORWARD_IN_TAB_HISTORY                40930
-#define IDC_SHOW_GOOGLE_APPS_SETTINGS                  40931
 #define IDC_SHOW_PRIVACY_SETTINGS                      40934
 #define IDC_HIDE_SETTINGS_AND_SHOW_PRIVACY_SETTINGS    40935
 #define IDC_REPORT_AN_ISSUE                            40936
diff --git a/ios/chrome/browser/ui/ntp/google_landing_mediator.mm b/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
index 72227e7..0cebfb3 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
+++ b/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
@@ -259,13 +259,13 @@
 
   if (data.size() && !_recordedPageImpression) {
     _recordedPageImpression = YES;
-    std::vector<ntp_tiles::metrics::TileImpression> tiles;
+    int index = 0;
     for (const ntp_tiles::NTPTile& ntpTile : data) {
-      tiles.emplace_back(ntpTile.source, ntp_tiles::UNKNOWN_TILE_TYPE,
-                         ntpTile.url);
+      ntp_tiles::metrics::RecordTileImpression(
+          index++, ntpTile.source, ntp_tiles::UNKNOWN_TILE_TYPE, ntpTile.url,
+          GetApplicationContext()->GetRapporServiceImpl());
     }
-    ntp_tiles::metrics::RecordPageImpression(
-        tiles, GetApplicationContext()->GetRapporServiceImpl());
+    ntp_tiles::metrics::RecordPageImpression(data.size());
   }
 }
 
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index 6ae3b8d..8638120 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -65,9 +65,6 @@
     "import_data_collection_view_controller.mm",
     "material_cell_catalog_view_controller.h",
     "material_cell_catalog_view_controller.mm",
-    "native_apps_collection_view_controller.h",
-    "native_apps_collection_view_controller.mm",
-    "native_apps_collection_view_controller_private.h",
     "password_details_collection_view_controller.h",
     "password_details_collection_view_controller.mm",
     "physical_web_collection_view_controller.h",
@@ -151,7 +148,6 @@
     "//ios/chrome/browser/prefs",
     "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/signin",
-    "//ios/chrome/browser/store_kit",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/translate",
     "//ios/chrome/browser/ui",
@@ -198,7 +194,6 @@
   libs = [
     "CoreLocation.framework",
     "LocalAuthentication.framework",
-    "StoreKit.framework",
     "UIKit.framework",
   ]
 }
@@ -256,7 +251,6 @@
     "dataplan_usage_collection_view_controller_unittest.mm",
     "do_not_track_collection_view_controller_unittest.mm",
     "import_data_collection_view_controller_unittest.mm",
-    "native_apps_collection_view_controller_unittest.mm",
     "password_details_collection_view_controller_unittest.mm",
     "physical_web_collection_view_controller_unittest.mm",
     "privacy_collection_view_controller_unittest.mm",
diff --git a/ios/chrome/browser/ui/settings/cells/BUILD.gn b/ios/chrome/browser/ui/settings/cells/BUILD.gn
index de546429..37b2570 100644
--- a/ios/chrome/browser/ui/settings/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/cells/BUILD.gn
@@ -18,8 +18,6 @@
     "encryption_item.mm",
     "import_data_multiline_detail_cell.h",
     "import_data_multiline_detail_cell.mm",
-    "native_app_item.h",
-    "native_app_item.mm",
     "passphrase_error_item.h",
     "passphrase_error_item.mm",
     "password_details_item.h",
@@ -56,7 +54,6 @@
     "copied_to_chrome_item_unittest.mm",
     "encryption_item_unittest.mm",
     "import_data_multiline_detail_cell_unittest.mm",
-    "native_app_item_unittest.mm",
     "passphrase_error_item_unittest.mm",
     "password_details_item_unittest.mm",
     "sync_switch_item_unittest.mm",
diff --git a/ios/chrome/browser/ui/settings/cells/native_app_item.h b/ios/chrome/browser/ui/settings/cells/native_app_item.h
deleted file mode 100644
index b03afcf..0000000
--- a/ios/chrome/browser/ui/settings/cells/native_app_item.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_NATIVE_APP_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_NATIVE_APP_ITEM_H_
-
-#import <UIKit/UIKit.h>
-
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
-
-@class MDCButton;
-
-typedef NS_ENUM(NSInteger, NativeAppItemState) {
-  NativeAppItemSwitchOff,
-  NativeAppItemSwitchOn,
-  NativeAppItemInstall,
-};
-
-// Item to display and interact with a Native App.
-@interface NativeAppItem : CollectionViewItem
-
-// The display name of the app.
-@property(nonatomic, copy) NSString* name;
-
-// The icon of the app.
-@property(nonatomic, strong) UIImage* icon;
-
-// The state of the item:
-// - NativeAppItemSwitchOff: displays a switch set to OFF;
-// - NativeAppItemSwitchOn: displays a switch set to ON;
-// - NativeAppItemInstall: displays an INSTALL button;
-@property(nonatomic, assign) NativeAppItemState state;
-
-@end
-
-// Cell class associated to NativeAppItem.
-@interface NativeAppCell : MDCCollectionViewCell
-
-// Label for the app name.
-@property(nonatomic, strong, readonly) UILabel* nameLabel;
-
-// Image view for the app icon.
-@property(nonatomic, strong, readonly) UIImageView* iconImageView;
-
-// Accessory controls. switchControl is available after calling
-// -updateWithState: with NativeAppItemSwitch{On|Off}, while installButton is
-// available after calling -updateWithState: with NativeAppItemInstall.
-@property(nonatomic, strong, readonly) UISwitch* switchControl;
-@property(nonatomic, strong, readonly) MDCButton* installButton;
-
-// Updates the accessory view according to the given |state|.
-- (void)updateWithState:(NativeAppItemState)state;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_NATIVE_APP_ITEM_H_
diff --git a/ios/chrome/browser/ui/settings/cells/native_app_item.mm b/ios/chrome/browser/ui/settings/cells/native_app_item.mm
deleted file mode 100644
index c0c0d3f..0000000
--- a/ios/chrome/browser/ui/settings/cells/native_app_item.mm
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/settings/cells/native_app_item.h"
-
-#import <QuartzCore/QuartzCore.h>
-
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-// Padding used on the leading and trailing edges of the cell.
-const CGFloat kHorizontalPadding = 16;
-
-// Icon rounded corner radius.
-const CGFloat kIconCornerRadius = 5.088;
-
-// Icon size.
-const CGFloat kIconSize = 29;
-
-// Placeholder icon for native app cells.
-UIImage* PlaceholderIcon() {
-  return [UIImage imageNamed:@"app_icon_placeholder"];
-}
-
-}  // namespace
-
-@implementation NativeAppItem
-
-@synthesize name = _name;
-@synthesize icon = _icon;
-@synthesize state = _state;
-
-- (instancetype)initWithType:(NSInteger)type {
-  self = [super initWithType:type];
-  if (self) {
-    self.cellClass = [NativeAppCell class];
-  }
-  return self;
-}
-
-#pragma mark CollectionViewItem
-
-- (void)configureCell:(NativeAppCell*)cell {
-  [super configureCell:cell];
-  cell.nameLabel.text = self.name;
-  if (self.icon) {
-    cell.iconImageView.image = self.icon;
-  }
-  [cell updateWithState:self.state];
-}
-
-@end
-
-@implementation NativeAppCell
-
-@synthesize nameLabel = _nameLabel;
-@synthesize iconImageView = _iconImageView;
-@synthesize switchControl = _switchControl;
-@synthesize installButton = _installButton;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    UIView* contentView = self.contentView;
-    self.isAccessibilityElement = YES;
-
-    _iconImageView = [[UIImageView alloc] init];
-    _iconImageView.translatesAutoresizingMaskIntoConstraints = NO;
-    _iconImageView.image = PlaceholderIcon();
-    _iconImageView.layer.cornerRadius = kIconCornerRadius;
-    _iconImageView.layer.masksToBounds = YES;
-    self.layer.shouldRasterize = YES;
-    self.layer.rasterizationScale = [[UIScreen mainScreen] scale];
-    [contentView addSubview:_iconImageView];
-
-    _nameLabel = [[UILabel alloc] init];
-    _nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    [contentView addSubview:_nameLabel];
-
-    _nameLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
-    _nameLabel.textColor = [[MDCPalette greyPalette] tint900];
-
-    _switchControl = [[UISwitch alloc] init];
-    _switchControl.onTintColor = [[MDCPalette cr_bluePalette] tint500];
-
-    _installButton = [[MDCFlatButton alloc] init];
-    _installButton.translatesAutoresizingMaskIntoConstraints = NO;
-    _installButton.customTitleColor = [[MDCPalette cr_bluePalette] tint500];
-    [_installButton
-        setTitle:l10n_util::GetNSString(IDS_IOS_GOOGLE_APPS_INSTALL_BUTTON)
-        forState:UIControlStateNormal];
-    [_installButton setTitle:@"" forState:UIControlStateDisabled];
-    _installButton.accessibilityHint = l10n_util::GetNSString(
-        IDS_IOS_GOOGLE_APPS_INSTALL_BUTTON_ACCESSIBILITY_HINT);
-
-    // Set up the constraints.
-    [NSLayoutConstraint activateConstraints:@[
-      [_iconImageView.leadingAnchor
-          constraintEqualToAnchor:contentView.leadingAnchor
-                         constant:kHorizontalPadding],
-      [_iconImageView.trailingAnchor
-          constraintEqualToAnchor:_nameLabel.leadingAnchor
-                         constant:-kHorizontalPadding],
-      [_iconImageView.widthAnchor constraintEqualToConstant:kIconSize],
-      [_iconImageView.heightAnchor constraintEqualToConstant:kIconSize],
-      [_nameLabel.trailingAnchor
-          constraintEqualToAnchor:contentView.trailingAnchor
-                         constant:-kHorizontalPadding],
-      [_iconImageView.centerYAnchor
-          constraintEqualToAnchor:contentView.centerYAnchor],
-      [_nameLabel.centerYAnchor
-          constraintEqualToAnchor:contentView.centerYAnchor],
-      [_installButton.widthAnchor constraintGreaterThanOrEqualToConstant:79],
-      [_installButton.widthAnchor constraintLessThanOrEqualToConstant:127],
-    ]];
-  }
-  return self;
-}
-
-- (void)updateWithState:(NativeAppItemState)state {
-  switch (state) {
-    case NativeAppItemSwitchOn:
-      self.switchControl.on = YES;
-      self.accessoryView = self.switchControl;
-      break;
-    case NativeAppItemSwitchOff:
-      self.switchControl.on = NO;
-      self.accessoryView = self.switchControl;
-      break;
-    case NativeAppItemInstall:
-      self.accessoryView = self.installButton;
-      break;
-  }
-}
-
-- (void)prepareForReuse {
-  [super prepareForReuse];
-  [self.switchControl removeTarget:nil
-                            action:nil
-                  forControlEvents:[self.switchControl allControlEvents]];
-  self.switchControl.tag = 0;
-  [self.installButton removeTarget:nil
-                            action:nil
-                  forControlEvents:[self.installButton allControlEvents]];
-  self.iconImageView.image = PlaceholderIcon();
-  self.iconImageView.tag = 0;
-}
-
-#pragma mark - UIAccessibility
-
-- (CGPoint)accessibilityActivationPoint {
-  // Activate over the accessory view.
-  CGRect accessoryViewFrame = UIAccessibilityConvertFrameToScreenCoordinates(
-      [self.accessoryView frame], self);
-  return CGPointMake(CGRectGetMidX(accessoryViewFrame),
-                     CGRectGetMidY(accessoryViewFrame));
-}
-
-- (NSString*)accessibilityHint {
-  return [self.accessoryView accessibilityHint];
-}
-
-- (NSString*)accessibilityValue {
-  if (self.accessoryView == self.switchControl) {
-    if (self.switchControl.on) {
-      return [NSString
-          stringWithFormat:@"%@, %@", self.nameLabel.text,
-                           l10n_util::GetNSString(IDS_IOS_SETTING_ON)];
-    } else {
-      return [NSString
-          stringWithFormat:@"%@, %@", self.nameLabel.text,
-                           l10n_util::GetNSString(IDS_IOS_SETTING_OFF)];
-    }
-  }
-
-  return [NSString stringWithFormat:@"%@, %@", self.nameLabel.text,
-                                    l10n_util::GetNSString(
-                                        IDS_IOS_GOOGLE_APPS_INSTALL_BUTTON)];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/settings/cells/native_app_item_unittest.mm b/ios/chrome/browser/ui/settings/cells/native_app_item_unittest.mm
deleted file mode 100644
index d83e1cb7..0000000
--- a/ios/chrome/browser/ui/settings/cells/native_app_item_unittest.mm
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/settings/cells/native_app_item.h"
-
-#import "ios/chrome/browser/ui/collection_view/cells/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-// Tests that the name, icon and state are honoured after a call to
-// |configureCell:|.
-TEST(NativeAppItemTest, ConfigureCell) {
-  NativeAppItem* item = [[NativeAppItem alloc] initWithType:0];
-  NSString* text = @"Test Switch";
-  UIImage* image = ios_internal::CollectionViewTestImage();
-
-  item.name = text;
-  item.icon = image;
-
-  id cell = [[[item cellClass] alloc] init];
-  ASSERT_TRUE([cell isMemberOfClass:[NativeAppCell class]]);
-
-  NativeAppCell* appCell = static_cast<NativeAppCell*>(cell);
-  EXPECT_FALSE(appCell.nameLabel.text);
-  EXPECT_TRUE(appCell.iconImageView.image);
-  EXPECT_NE(image, appCell.iconImageView.image);
-  EXPECT_FALSE(appCell.accessoryView);
-
-  [item configureCell:cell];
-  EXPECT_NSEQ(text, appCell.nameLabel.text);
-  EXPECT_NSEQ(image, appCell.iconImageView.image);
-  EXPECT_EQ((UIView*)appCell.switchControl, appCell.accessoryView);
-  EXPECT_FALSE(appCell.switchControl.on);
-}
-
-// Tests that the NativeAppItemSwitchOff configures the cell with a switch,
-// turned off.
-TEST(NativeAppItemTest, State_SwitchOff) {
-  NativeAppItem* item = [[NativeAppItem alloc] initWithType:0];
-  item.state = NativeAppItemSwitchOff;
-  NativeAppCell* appCell = [[[item cellClass] alloc] init];
-  [item configureCell:appCell];
-
-  EXPECT_EQ((UIView*)appCell.switchControl, appCell.accessoryView);
-  EXPECT_FALSE(appCell.switchControl.on);
-}
-
-// Tests that the NativeAppItemSwitchOn configures the cell with a switch,
-// turned on.
-TEST(NativeAppItemTest, State_SwitchOn) {
-  NativeAppItem* item = [[NativeAppItem alloc] initWithType:0];
-  item.state = NativeAppItemSwitchOn;
-  NativeAppCell* appCell = [[[item cellClass] alloc] init];
-  [item configureCell:appCell];
-
-  EXPECT_EQ((UIView*)appCell.switchControl, appCell.accessoryView);
-  EXPECT_TRUE(appCell.switchControl.on);
-}
-
-// Tests that the NativeAppItemInstall configures the cell with a button.
-TEST(NativeAppItemTest, State_Install) {
-  NativeAppItem* item = [[NativeAppItem alloc] initWithType:0];
-  item.state = NativeAppItemInstall;
-  NativeAppCell* appCell = [[[item cellClass] alloc] init];
-  [item configureCell:appCell];
-
-  EXPECT_EQ((UIView*)appCell.installButton, appCell.accessoryView);
-}
-
-}  // namespace
diff --git a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
index 608b04b..9afd756 100644
--- a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
@@ -35,7 +35,6 @@
 #import "ios/chrome/browser/ui/payments/cells/price_item.h"
 #import "ios/chrome/browser/ui/settings/cells/account_signin_item.h"
 #import "ios/chrome/browser/ui/settings/cells/autofill_data_item.h"
-#import "ios/chrome/browser/ui/settings/cells/native_app_item.h"
 #import "ios/chrome/browser/ui/settings/cells/sync_switch_item.h"
 #import "ios/chrome/browser/ui/settings/cells/text_and_error_item.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
@@ -218,21 +217,6 @@
   [model addItem:[self syncSwitchItem]
       toSectionWithIdentifier:SectionIdentifierSwitchCell];
 
-  // Native app cells.
-  [model addSectionWithIdentifier:SectionIdentifierNativeAppCell];
-  NativeAppItem* fooApp = [[NativeAppItem alloc] initWithType:ItemTypeApp];
-  fooApp.name = @"App Foo";
-  fooApp.state = NativeAppItemSwitchOff;
-  [model addItem:fooApp toSectionWithIdentifier:SectionIdentifierNativeAppCell];
-  NativeAppItem* barApp = [[NativeAppItem alloc] initWithType:ItemTypeApp];
-  barApp.name = @"App Bar";
-  barApp.state = NativeAppItemSwitchOn;
-  [model addItem:barApp toSectionWithIdentifier:SectionIdentifierNativeAppCell];
-  NativeAppItem* bazApp = [[NativeAppItem alloc] initWithType:ItemTypeApp];
-  bazApp.name = @"App Baz Qux Bla Bug Lorem ipsum dolor sit amet";
-  bazApp.state = NativeAppItemInstall;
-  [model addItem:bazApp toSectionWithIdentifier:SectionIdentifierNativeAppCell];
-
   // Autofill cells.
   [model addSectionWithIdentifier:SectionIdentifierAutofill];
   [model addItem:[self autofillItemWithMainAndTrailingText]
diff --git a/ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h b/ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h
deleted file mode 100644
index 9e8db3e..0000000
--- a/ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_NATIVE_APPS_COLLECTION_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_NATIVE_APPS_COLLECTION_VIEW_CONTROLLER_H_
-
-#import "ios/chrome/browser/store_kit/store_kit_launcher.h"
-#import "ios/chrome/browser/ui/settings/settings_root_collection_view_controller.h"
-
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
-
-// Settings view controller that displays the list of native apps that Chrome
-// can launch given a specific URL. From this view controller, native apps can
-// be installed if they are not present on the device. If they are present, a
-// switch lets the user opt-in to open automatically related links.
-// Icons for apps are static resources on a server and are therefore retrieved
-// and displayed asynchronously.
-@interface NativeAppsCollectionViewController
-    : SettingsRootCollectionViewController<StoreKitLauncher>
-
-// Designated initializer. |requestContextGetter| is kept as a weak reference,
-// therefore must outlive the initialized instance.
-- (id)initWithURLRequestContextGetter:
-    (net::URLRequestContextGetter*)requestContextGetter;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_NATIVE_APPS_COLLECTION_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/settings/native_apps_collection_view_controller.mm b/ios/chrome/browser/ui/settings/native_apps_collection_view_controller.mm
deleted file mode 100644
index 68602f5..0000000
--- a/ios/chrome/browser/ui/settings/native_apps_collection_view_controller.mm
+++ /dev/null
@@ -1,405 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h"
-#import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller_private.h"
-
-#import <StoreKit/StoreKit.h>
-
-#include "base/logging.h"
-#import "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "base/metrics/user_metrics_action.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h"
-#import "ios/chrome/browser/installation_notifier.h"
-#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
-#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#import "ios/chrome/browser/ui/settings/cells/native_app_item.h"
-#import "ios/chrome/browser/ui/settings/settings_utils.h"
-#import "ios/chrome/common/string_util.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
-#import "ios/public/provider/chrome/browser/native_app_launcher/native_app_metadata.h"
-#import "ios/public/provider/chrome/browser/native_app_launcher/native_app_whitelist_manager.h"
-#import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
-#include "ios/web/public/web_thread.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-const NSInteger kTagShift = 1000;
-
-namespace {
-
-typedef NS_ENUM(NSInteger, SectionIdentifier) {
-  SectionIdentifierLearnMore = kSectionIdentifierEnumZero,
-  SectionIdentifierApps,
-};
-
-typedef NS_ENUM(NSInteger, ItemType) {
-  ItemTypeApp = kItemTypeEnumZero,
-  ItemTypeLearnMore,
-};
-
-}  // namespace
-
-@interface NativeAppsCollectionViewController ()<
-    SKStoreProductViewControllerDelegate> {
-  std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper> _imageFetcher;
-  NSArray* _nativeAppsInSettings;
-  BOOL _userDidSomething;
-}
-
-// List of the native apps visible in Settings.
-@property(nonatomic, copy) NSArray* appsInSettings;
-
-// Delegate for App-Store-related operations.
-@property(nonatomic, weak) id<StoreKitLauncher> storeKitLauncher;
-
-// Sets up the list of visible apps based on |nativeAppWhitelistManager|, which
-// serves as datasource for this controller. Apps from
-// |nativeAppWhitelistManager| are stored in |_nativeAppsInSettings| and
-// |-reloadData| is sent to the receiver.
-- (void)configureWithNativeAppWhiteListManager:
-    (id<NativeAppWhitelistManager>)nativeAppWhitelistManager;
-
-// Returns a new Native App collection view item for the metadata at |index| in
-// |_nativeAppsInSettings|.
-- (CollectionViewItem*)nativeAppItemAtIndex:(NSUInteger)index;
-
-// Target method for the auto open in app switch.
-// Called when an auto-open-in-app switch is toggled.
-- (void)autoOpenInAppChanged:(UISwitch*)switchControl;
-
-// Called when an Install button is being tapped.
-- (void)installApp:(UIButton*)button;
-
-// Called when an app with the registered scheme is opened.
-- (void)appDidInstall:(NSNotification*)notification;
-
-// Returns the app at |index| in the list of visible apps.
-- (id<NativeAppMetadata>)nativeAppAtIndex:(NSUInteger)index;
-
-// Records a user action in UMA under NativeAppLauncher.Settings.
-// If this method is not called during the lifetime of the view,
-// |settings::kNativeAppsActionDidNothing| is recorded in UMA.
-- (void)recordUserAction:(settings::NativeAppsAction)action;
-
-@end
-
-@implementation NativeAppsCollectionViewController
-
-@synthesize storeKitLauncher = _storeKitLauncher;
-
-- (id)initWithURLRequestContextGetter:
-    (net::URLRequestContextGetter*)requestContextGetter {
-  self = [super initWithStyle:CollectionViewControllerStyleAppBar];
-  if (self) {
-    _imageFetcher = base::MakeUnique<image_fetcher::IOSImageDataFetcherWrapper>(
-        requestContextGetter, web::WebThread::GetBlockingPool());
-    base::RecordAction(base::UserMetricsAction("MobileGALOpenSettings"));
-    _storeKitLauncher = self;
-
-    [self loadModel];
-  }
-  return self;
-}
-
-- (void)dealloc {
-  [[InstallationNotifier sharedInstance] unregisterForNotifications:self];
-  if (!_userDidSomething)
-    [self recordUserAction:settings::kNativeAppsActionDidNothing];
-}
-
-#pragma mark - View lifecycle
-
-- (void)viewDidLoad {
-  self.title = l10n_util::GetNSString(IDS_IOS_GOOGLE_APPS_SM_SETTINGS);
-  [self configureWithNativeAppWhiteListManager:
-            ios::GetChromeBrowserProvider()->GetNativeAppWhitelistManager()];
-
-  [super viewDidLoad];
-}
-
-- (void)viewWillAppear:(BOOL)animated {
-  [super viewWillAppear:animated];
-  [[InstallationNotifier sharedInstance] checkNow];
-  [[NSNotificationCenter defaultCenter]
-      addObserver:self
-         selector:@selector(reloadData)
-             name:UIApplicationDidBecomeActiveNotification
-           object:nil];
-}
-
-- (void)viewDidDisappear:(BOOL)animated {
-  [super viewDidDisappear:animated];
-  [[NSNotificationCenter defaultCenter]
-      removeObserver:self
-                name:UIApplicationDidBecomeActiveNotification
-              object:nil];
-}
-
-#pragma mark - CollectionViewController
-
-- (void)loadModel {
-  [super loadModel];
-  CollectionViewModel* model = self.collectionViewModel;
-  NSUInteger appsCount = [_nativeAppsInSettings count];
-
-  [model addSectionWithIdentifier:SectionIdentifierLearnMore];
-  [model addItem:[self learnMoreItem]
-      toSectionWithIdentifier:SectionIdentifierLearnMore];
-
-  [model addSectionWithIdentifier:SectionIdentifierApps];
-
-  for (NSUInteger i = 0; i < appsCount; i++) {
-    [model addItem:[self nativeAppItemAtIndex:i]
-        toSectionWithIdentifier:SectionIdentifierApps];
-  }
-}
-
-- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
-                 cellForItemAtIndexPath:(NSIndexPath*)indexPath {
-  UICollectionViewCell* cell =
-      [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
-  if ([self.collectionViewModel
-          sectionIdentifierForSection:indexPath.section] ==
-      SectionIdentifierApps) {
-    NativeAppCell* appCell = base::mac::ObjCCastStrict<NativeAppCell>(cell);
-    [self configureNativeAppCell:appCell atIndexPath:indexPath];
-  }
-  return cell;
-}
-
-#pragma mark - MDCCollectionViewStylingDelegate
-
-- (CGFloat)collectionView:(nonnull UICollectionView*)collectionView
-    cellHeightAtIndexPath:(nonnull NSIndexPath*)indexPath {
-  CollectionViewItem* item =
-      [self.collectionViewModel itemAtIndexPath:indexPath];
-  switch (item.type) {
-    case ItemTypeLearnMore:
-      return [MDCCollectionViewCell
-          cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
-                             forItem:item];
-    case ItemTypeApp:
-      return MDCCellDefaultOneLineWithAvatarHeight;
-    default:
-      return MDCCellDefaultOneLineHeight;
-  }
-}
-
-- (void)configureNativeAppCell:(NativeAppCell*)appCell
-                   atIndexPath:(NSIndexPath*)indexPath {
-  appCell.switchControl.tag = [self tagForIndexPath:indexPath];
-  [appCell.switchControl addTarget:self
-                            action:@selector(autoOpenInAppChanged:)
-                  forControlEvents:UIControlEventValueChanged];
-  appCell.installButton.tag = [self tagForIndexPath:indexPath];
-  [appCell.installButton addTarget:self
-                            action:@selector(installApp:)
-                  forControlEvents:UIControlEventTouchUpInside];
-  CollectionViewItem* item =
-      [self.collectionViewModel itemAtIndexPath:indexPath];
-  NativeAppItem* appItem = base::mac::ObjCCastStrict<NativeAppItem>(item);
-  if (!appItem.icon) {
-    // Fetch the real icon.
-    __weak NativeAppsCollectionViewController* weakSelf = self;
-    id<NativeAppMetadata> metadata = [self nativeAppAtIndex:indexPath.item];
-    [metadata fetchSmallIconWithImageFetcher:_imageFetcher.get()
-                             completionBlock:^(UIImage* image) {
-
-                               NativeAppsCollectionViewController* strongSelf =
-                                   weakSelf;
-                               if (!image || !strongSelf)
-                                 return;
-                               appItem.icon = image;
-                               [strongSelf.collectionView
-                                   reloadItemsAtIndexPaths:@[ indexPath ]];
-                             }];
-  }
-}
-
-- (CollectionViewItem*)learnMoreItem {
-  NSString* learnMoreText =
-      l10n_util::GetNSString(IDS_IOS_GOOGLE_APPS_SM_SECTION_HEADER);
-  CollectionViewFooterItem* learnMoreItem =
-      [[CollectionViewFooterItem alloc] initWithType:ItemTypeLearnMore];
-  learnMoreItem.text = learnMoreText;
-  return learnMoreItem;
-}
-
-#pragma mark - SKStoreProductViewControllerDelegate methods
-
-- (void)productViewControllerDidFinish:
-    (SKStoreProductViewController*)viewController {
-  [self dismissViewControllerAnimated:YES completion:nil];
-}
-
-#pragma mark - StoreKitLauncher methods
-
-- (void)openAppStore:(NSString*)appId {
-  // Reported crashes show that -openAppStore: had been called with
-  // a nil |appId|, but opening AppStore is meaningful only if the |appId| is
-  // not nil, so be defensive and early return if |appId| is nil.
-  if (![appId length])
-    return;
-  NSDictionary* product =
-      @{SKStoreProductParameterITunesItemIdentifier : appId};
-  SKStoreProductViewController* storeViewController =
-      [[SKStoreProductViewController alloc] init];
-  [storeViewController setDelegate:self];
-  [storeViewController loadProductWithParameters:product completionBlock:nil];
-  [self presentViewController:storeViewController animated:YES completion:nil];
-}
-
-#pragma mark - MDCCollectionViewStylingDelegate
-
-// MDCCollectionViewStylingDelegate protocol is implemented so that cells don't
-// display ink on touch.
-- (BOOL)collectionView:(nonnull UICollectionView*)collectionView
-    hidesInkViewAtIndexPath:(nonnull NSIndexPath*)indexPath {
-  return YES;
-}
-
-- (MDCCollectionViewCellStyle)collectionView:(UICollectionView*)collectionView
-                         cellStyleForSection:(NSInteger)section {
-  NSInteger sectionIdentifier =
-      [self.collectionViewModel sectionIdentifierForSection:section];
-  switch (sectionIdentifier) {
-    case SectionIdentifierLearnMore:
-      // Display the Learn More footer in the default style with no "card" UI
-      // and no section padding.
-      return MDCCollectionViewCellStyleDefault;
-    default:
-      return self.styler.cellStyle;
-  }
-}
-
-- (BOOL)collectionView:(UICollectionView*)collectionView
-    shouldHideItemBackgroundAtIndexPath:(NSIndexPath*)indexPath {
-  NSInteger sectionIdentifier =
-      [self.collectionViewModel sectionIdentifierForSection:indexPath.section];
-  switch (sectionIdentifier) {
-    case SectionIdentifierLearnMore:
-      // Display the Learn More footer without any background image or
-      // shadowing.
-      return YES;
-    default:
-      return NO;
-  }
-}
-#pragma mark - Private methods
-
-- (void)autoOpenInAppChanged:(UISwitch*)switchControl {
-  NSInteger index = [self indexPathForTag:switchControl.tag].item;
-  id<NativeAppMetadata> metadata = [self nativeAppAtIndex:index];
-  DCHECK([metadata isInstalled]);
-  BOOL autoOpenOn = switchControl.on;
-  metadata.shouldAutoOpenLinks = autoOpenOn;
-  [self recordUserAction:(autoOpenOn
-                              ? settings::kNativeAppsActionTurnedAutoOpenOn
-                              : settings::kNativeAppsActionTurnedAutoOpenOff)];
-}
-
-- (void)installApp:(UIButton*)button {
-  [self recordUserAction:settings::kNativeAppsActionClickedInstall];
-  NSInteger index = [self indexPathForTag:button.tag].item;
-  id<NativeAppMetadata> metadata = [self nativeAppAtIndex:index];
-  DCHECK(![metadata isInstalled]);
-  [metadata updateCounterWithAppInstallation];
-
-  // Register to get a notification when the app is installed.
-  [[InstallationNotifier sharedInstance]
-      registerForInstallationNotifications:self
-                              withSelector:@selector(appDidInstall:)
-                                 forScheme:[metadata anyScheme]];
-  [self.storeKitLauncher openAppStore:[metadata appId]];
-}
-
-- (void)appDidInstall:(NSNotification*)notification {
-  // The name of the notification is the scheme of the new app installed.
-  GURL url(base::SysNSStringToUTF8([notification name]) + ":");
-  DCHECK(url.is_valid());
-  NSUInteger matchingAppIndex = [_nativeAppsInSettings
-      indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL* stop) {
-        id<NativeAppMetadata> metadata =
-            static_cast<id<NativeAppMetadata>>(obj);
-        return [metadata canOpenURL:url];
-      }];
-  [[self nativeAppAtIndex:matchingAppIndex] setShouldAutoOpenLinks:YES];
-  [self reloadData];
-}
-
-- (void)configureWithNativeAppWhiteListManager:
-    (id<NativeAppWhitelistManager>)nativeAppWhitelistManager {
-  NSArray* allApps = [nativeAppWhitelistManager
-      filteredAppsUsingBlock:^(const id<NativeAppMetadata> app, BOOL* stop) {
-        return [app isGoogleOwnedApp];
-      }];
-  [self setAppsInSettings:allApps];
-  [self reloadData];
-}
-
-- (id<NativeAppMetadata>)nativeAppAtIndex:(NSUInteger)index {
-  id<NativeAppMetadata> metadata = [_nativeAppsInSettings objectAtIndex:index];
-  DCHECK([metadata conformsToProtocol:@protocol(NativeAppMetadata)]);
-  return metadata;
-}
-
-- (void)recordUserAction:(settings::NativeAppsAction)action {
-  _userDidSomething = YES;
-  UMA_HISTOGRAM_ENUMERATION("NativeAppLauncher.Settings", action,
-                            settings::kNativeAppsActionCount);
-}
-
-- (CollectionViewItem*)nativeAppItemAtIndex:(NSUInteger)index {
-  id<NativeAppMetadata> metadata = [self nativeAppAtIndex:index];
-  // Determine the state of the cell.
-  NativeAppItemState state;
-  if ([metadata isInstalled]) {
-    state = [metadata shouldAutoOpenLinks] ? NativeAppItemSwitchOn
-                                           : NativeAppItemSwitchOff;
-  } else {
-    state = NativeAppItemInstall;
-  }
-  NativeAppItem* appItem = [[NativeAppItem alloc] initWithType:ItemTypeApp];
-  appItem.name = [metadata appName];
-  appItem.state = state;
-  return appItem;
-}
-
-- (NSArray*)appsInSettings {
-  return _nativeAppsInSettings;
-}
-
-- (void)setAppsInSettings:(NSArray*)apps {
-  _nativeAppsInSettings = [apps copy];
-}
-
-- (NSInteger)tagForIndexPath:(NSIndexPath*)indexPath {
-  DCHECK(indexPath.section ==
-         [self.collectionViewModel
-             sectionForSectionIdentifier:SectionIdentifierApps]);
-  return indexPath.item + kTagShift;
-}
-
-- (NSIndexPath*)indexPathForTag:(NSInteger)shiftedTag {
-  NSInteger unshiftedTag = shiftedTag - kTagShift;
-  return [NSIndexPath
-      indexPathForItem:unshiftedTag
-             inSection:[self.collectionViewModel
-                           sectionForSectionIdentifier:SectionIdentifierApps]];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/settings/native_apps_collection_view_controller_private.h b/ios/chrome/browser/ui/settings/native_apps_collection_view_controller_private.h
deleted file mode 100644
index 1e098aee..0000000
--- a/ios/chrome/browser/ui/settings/native_apps_collection_view_controller_private.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_NATIVE_APPS_COLLECTION_VIEW_CONTROLLER_PRIVATE_H_
-#define IOS_CHROME_BROWSER_UI_SETTINGS_NATIVE_APPS_COLLECTION_VIEW_CONTROLLER_PRIVATE_H_
-
-#import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h"
-
-// This file is a private header for NativeAppsCollectionViewController.
-// It exposes private details for testing purposes.
-
-namespace settings {
-
-// User actions.
-typedef enum {
-  kNativeAppsActionDidNothing,
-  kNativeAppsActionClickedInstall,
-  kNativeAppsActionTurnedDefaultBrowserOn,
-  kNativeAppsActionTurnedDefaultBrowserOff,
-  kNativeAppsActionTurnedAutoOpenOn,
-  kNativeAppsActionTurnedAutoOpenOff,
-  kNativeAppsActionCount,
-} NativeAppsAction;
-
-}  // namespace settings
-
-// Arbitrary value to shift indices (from 0 to N), to a range that doesn't
-// include 0, in order to not mistake the default value (0) with the first
-// index. That way, an invalid (or default) tag value can be detected.
-// That means that all app cells have a tag computed by adding their index and
-// this shift.
-extern const NSInteger kTagShift;
-
-#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_NATIVE_APPS_COLLECTION_VIEW_CONTROLLER_PRIVATE_H_
diff --git a/ios/chrome/browser/ui/settings/native_apps_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/native_apps_collection_view_controller_unittest.mm
deleted file mode 100644
index 25a75dc..0000000
--- a/ios/chrome/browser/ui/settings/native_apps_collection_view_controller_unittest.mm
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h"
-#import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller_private.h"
-
-#include <memory>
-
-#include "base/compiler_specific.h"
-#import "base/ios/block_types.h"
-#include "base/test/histogram_tester.h"
-#include "base/threading/thread_task_runner_handle.h"
-#import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h"
-#import "ios/chrome/browser/ui/settings/cells/native_app_item.h"
-#import "ios/public/provider/chrome/browser/native_app_launcher/fake_native_app_metadata.h"
-#import "ios/public/provider/chrome/browser/native_app_launcher/fake_native_app_whitelist_manager.h"
-#include "ios/web/public/test/test_web_thread_bundle.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-#include "ui/base/l10n/l10n_util.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface NativeAppsCollectionViewController (Testing)
-@property(nonatomic, retain) NSArray* appsInSettings;
-@property(nonatomic, assign) id<StoreKitLauncher> storeKitLauncher;
-- (void)configureWithNativeAppWhiteListManager:
-    (id<NativeAppWhitelistManager>)nativeAppWhitelistManager;
-- (void)autoOpenInAppChanged:(UISwitch*)switchControl;
-- (void)installApp:(UIButton*)button;
-- (void)recordUserAction:(settings::NativeAppsAction)action;
-- (void)appDidInstall:(NSNotification*)note;
-- (id<NativeAppMetadata>)nativeAppAtIndex:(NSUInteger)index;
-@end
-
-@interface MockNativeAppWhitelistManager : FakeNativeAppWhitelistManager
-@end
-
-@implementation MockNativeAppWhitelistManager
-
-- (id)init {
-  self = [super init];
-  if (self) {
-    FakeNativeAppMetadata* app1 = [[FakeNativeAppMetadata alloc] init];
-    [app1 setAppName:@"App1"];
-    [app1 setAppId:@"1"];
-    [app1 setGoogleOwnedApp:YES];
-
-    FakeNativeAppMetadata* app2 = [[FakeNativeAppMetadata alloc] init];
-    [app2 setAppName:@"App2"];
-    [app2 setAppId:@"2"];
-    [app2 setGoogleOwnedApp:YES];
-
-    FakeNativeAppMetadata* app3 = [[FakeNativeAppMetadata alloc] init];
-    [app3 setAppName:@"App3"];
-    [app3 setAppId:@"3"];
-    [app3 setGoogleOwnedApp:YES];
-
-    FakeNativeAppMetadata* notOwnedApp = [[FakeNativeAppMetadata alloc] init];
-    [notOwnedApp setAppName:@"NotOwnedApp"];
-    [notOwnedApp setAppId:@"999"];
-    [notOwnedApp setGoogleOwnedApp:NO];
-
-    [self setAppList:@[ app1, app2, notOwnedApp, app3 ]
-               tldList:nil
-        acceptStoreIDs:nil];
-  }
-  return self;
-}
-
-@end
-
-@interface MockStoreKitLauncher : NSObject<StoreKitLauncher>
-@end
-
-@implementation MockStoreKitLauncher
-- (void)openAppStore:(id<NativeAppMetadata>)metadata {
-}
-@end
-
-namespace {
-
-class NativeAppsCollectionViewControllerTest
-    : public CollectionViewControllerTest {
- protected:
-  void SetUp() override {
-    CollectionViewControllerTest::SetUp();
-    request_context_getter_ = new net::TestURLRequestContextGetter(
-        base::ThreadTaskRunnerHandle::Get());
-    NativeAppsCollectionViewController* native_apps_controller =
-        static_cast<NativeAppsCollectionViewController*>(controller());
-
-    mock_whitelist_manager_ = [[MockNativeAppWhitelistManager alloc] init];
-    [native_apps_controller
-        configureWithNativeAppWhiteListManager:mock_whitelist_manager_];
-  }
-
-  CollectionViewController* InstantiateController() override {
-    DCHECK(request_context_getter_.get());
-    return [[NativeAppsCollectionViewController alloc]
-        initWithURLRequestContextGetter:request_context_getter_.get()];
-  }
-
-  // Runs the block and checks that the |action| (and only the action) has been
-  // recorded.
-  void ExpectUserActionAfterBlock(settings::NativeAppsAction action,
-                                  ProceduralBlock block) {
-    std::unique_ptr<base::HistogramTester> histogram_tester(
-        new base::HistogramTester());
-    block();
-    histogram_tester->ExpectUniqueSample("NativeAppLauncher.Settings", action,
-                                         1);
-  }
-
-  // Adds a mocked app of class MockNativeAppMetadata at the end of the apps'
-  // list.
-  void AddMockedApp() {
-    NativeAppsCollectionViewController* native_apps_controller =
-        static_cast<NativeAppsCollectionViewController*>(controller());
-    // Add a mock app at the end of the app list.
-    NSMutableArray* apps =
-        [NSMutableArray arrayWithArray:[native_apps_controller appsInSettings]];
-    ASSERT_GT([apps count], 0U);
-    FakeNativeAppMetadata* installed_app = [[FakeNativeAppMetadata alloc] init];
-    [installed_app setAppName:@"App4"];
-    [installed_app setAppId:@"4"];
-    [installed_app setGoogleOwnedApp:YES];
-    [installed_app resetInfobarHistory];
-    [installed_app unsetShouldAutoOpenLinks];
-    [installed_app setInstalled:YES];
-    [apps addObject:installed_app];
-    [native_apps_controller setAppsInSettings:apps];
-  }
-
-  // Checks that the object's state is consistent with the represented app
-  // metadata at |index| in |section|.
-  void CheckNativeAppItem(NSUInteger section, NSUInteger index) {
-    NativeAppsCollectionViewController* native_apps_controller =
-        static_cast<NativeAppsCollectionViewController*>(controller());
-    id<NativeAppMetadata> metadata =
-        [native_apps_controller nativeAppAtIndex:index];
-    NativeAppItem* item = GetCollectionViewItem(section, index);
-    EXPECT_TRUE(item);
-    EXPECT_NSEQ([metadata appName], item.name);
-    if ([metadata isInstalled]) {
-      if ([metadata shouldAutoOpenLinks])
-        EXPECT_EQ(NativeAppItemSwitchOn, item.state);
-      else
-        EXPECT_EQ(NativeAppItemSwitchOff, item.state);
-    } else {
-      EXPECT_EQ(NativeAppItemInstall, item.state);
-    }
-  }
-
-  web::TestWebThreadBundle thread_bundle_;
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-  MockNativeAppWhitelistManager* mock_whitelist_manager_;
-};
-
-// Tests the integrity of the loaded model: section titles, sections and rows,
-// along with checking that objects are correctly set up and appear in the
-// correct order.
-TEST_F(NativeAppsCollectionViewControllerTest, TestModel) {
-  NativeAppsCollectionViewController* native_apps_controller =
-      static_cast<NativeAppsCollectionViewController*>(controller());
-  CheckController();
-  EXPECT_EQ(2, NumberOfSections());
-
-  // As many rows as there are apps.
-  NSInteger apps_count = [[native_apps_controller appsInSettings] count];
-  EXPECT_EQ(apps_count, NumberOfItemsInSection(1));
-  for (NSInteger i = 0; i < apps_count; i++) {
-    CheckNativeAppItem(1, i);
-  }
-}
-
-// Tests that native app metadata are correctly updated when the user toggles
-// switches. It checks that the appropriate UMA is sent for this user action.
-TEST_F(NativeAppsCollectionViewControllerTest, AutoOpenInAppChanged) {
-  NativeAppsCollectionViewController* native_apps_controller =
-      static_cast<NativeAppsCollectionViewController*>(controller());
-  AddMockedApp();
-  // Make sure the last app is installed.
-  NSInteger last_index = [[native_apps_controller appsInSettings] count] - 1;
-  id<NativeAppMetadata> last_app =
-      [native_apps_controller nativeAppAtIndex:last_index];
-  ASSERT_TRUE([last_app isInstalled]);
-
-  EXPECT_FALSE([last_app shouldAutoOpenLinks]);
-  UISwitch* switch_from_cell = [[UISwitch alloc] init];
-  switch_from_cell.on = YES;
-  switch_from_cell.tag = kTagShift + last_index;
-
-  ExpectUserActionAfterBlock(settings::kNativeAppsActionTurnedAutoOpenOn, ^{
-    [native_apps_controller autoOpenInAppChanged:switch_from_cell];
-    EXPECT_TRUE([last_app shouldAutoOpenLinks]);
-  });
-
-  switch_from_cell.on = NO;
-
-  ExpectUserActionAfterBlock(settings::kNativeAppsActionTurnedAutoOpenOff, ^{
-    [native_apps_controller autoOpenInAppChanged:switch_from_cell];
-    EXPECT_FALSE([last_app shouldAutoOpenLinks]);
-  });
-}
-
-// Tests that the App Store is launched when the user clicks on an Install
-// button. It checks that the appropriate UMA is sent for this user action.
-TEST_F(NativeAppsCollectionViewControllerTest, InstallApp) {
-  NativeAppsCollectionViewController* native_apps_controller =
-      static_cast<NativeAppsCollectionViewController*>(controller());
-  id<StoreKitLauncher> real_opener = [native_apps_controller storeKitLauncher];
-  id<StoreKitLauncher> mockLauncher = [[MockStoreKitLauncher alloc] init];
-  [native_apps_controller setStoreKitLauncher:mockLauncher];
-  UIButton* button_from_cell = [UIButton buttonWithType:UIButtonTypeCustom];
-  button_from_cell.tag = kTagShift;
-  id mock_button = [OCMockObject partialMockForObject:button_from_cell];
-  ExpectUserActionAfterBlock(settings::kNativeAppsActionClickedInstall, ^{
-    [native_apps_controller installApp:mock_button];
-  });
-
-  [mock_button verify];
-
-  [native_apps_controller setStoreKitLauncher:real_opener];
-}
-
-// Tests that native app metadata are correctly updated when the related app has
-// been installed.
-TEST_F(NativeAppsCollectionViewControllerTest, AppDidInstall) {
-  NativeAppsCollectionViewController* native_apps_controller =
-      static_cast<NativeAppsCollectionViewController*>(controller());
-  AddMockedApp();
-  // Make sure the last app can open any URL.
-  id<NativeAppMetadata> last_app =
-      [[native_apps_controller appsInSettings] lastObject];
-  ASSERT_TRUE([last_app canOpenURL:GURL()]);
-
-  EXPECT_FALSE([last_app shouldAutoOpenLinks]);
-  [native_apps_controller
-      appDidInstall:[NSNotification notificationWithName:@"App4" object:nil]];
-  EXPECT_TRUE([last_app shouldAutoOpenLinks]);
-
-  [last_app unsetShouldAutoOpenLinks];
-}
-
-}  // namespace
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.h b/ios/chrome/browser/ui/settings/settings_navigation_controller.h
index 3f917fe..2afb19a 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.h
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.h
@@ -79,13 +79,6 @@
                              delegate:(id<SettingsNavigationControllerDelegate>)
                                           delegate;
 
-// Creates a new NativeAppsCollectionViewController and the chrome around it.
-// |browserState| is used to personalize some settings aspects and should not be
-// nil. |delegate| may be nil.
-+ (SettingsNavigationController*)
-newNativeAppsController:(ios::ChromeBrowserState*)browserState
-               delegate:(id<SettingsNavigationControllerDelegate>)delegate;
-
 // Creates a new ClearBrowsingDataCollectionViewController and the chrome around
 // it.
 // |browserState| is used to personalize some settings aspects and should not be
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
index d3c885f..56309540 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -23,7 +23,6 @@
 #import "ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/contextual_search_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/import_data_collection_view_controller.h"
-#import "ios/chrome/browser/ui/settings/native_apps_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_utils.h"
@@ -223,18 +222,6 @@
 }
 
 + (SettingsNavigationController*)
-newNativeAppsController:(ios::ChromeBrowserState*)browserState
-               delegate:(id<SettingsNavigationControllerDelegate>)delegate {
-  UIViewController* controller = [[NativeAppsCollectionViewController alloc]
-      initWithURLRequestContextGetter:browserState->GetRequestContext()];
-  SettingsNavigationController* nc = [[SettingsNavigationController alloc]
-      initWithRootViewController:controller
-                    browserState:browserState
-                        delegate:delegate];
-  return nc;
-}
-
-+ (SettingsNavigationController*)
 newSavePasswordsController:(ios::ChromeBrowserState*)browserState
                   delegate:(id<SettingsNavigationControllerDelegate>)delegate {
   UIViewController* controller = [[SavePasswordsCollectionViewController alloc]
diff --git a/ios/shared/chrome/browser/ui/browser_list/BUILD.gn b/ios/shared/chrome/browser/ui/browser_list/BUILD.gn
index 489be46..692a147a 100644
--- a/ios/shared/chrome/browser/ui/browser_list/BUILD.gn
+++ b/ios/shared/chrome/browser/ui/browser_list/BUILD.gn
@@ -15,6 +15,7 @@
     "browser_list_session_service_factory.mm",
     "browser_list_session_service_impl.h",
     "browser_list_session_service_impl.mm",
+    "browser_user_data.h",
     "browser_web_state_list_delegate.h",
     "browser_web_state_list_delegate.mm",
   ]
diff --git a/ios/shared/chrome/browser/ui/browser_list/browser.h b/ios/shared/chrome/browser/ui/browser_list/browser.h
index ef6cbb00..213f8d1 100644
--- a/ios/shared/chrome/browser/ui/browser_list/browser.h
+++ b/ios/shared/chrome/browser/ui/browser_list/browser.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/supports_user_data.h"
 
 class WebStateList;
 class WebStateListDelegate;
@@ -21,10 +22,10 @@
 
 // Browser holds the state backing a collection of Tabs and the attached
 // UI elements (Tab strip, ...).
-class Browser {
+class Browser : public base::SupportsUserData {
  public:
   explicit Browser(ios::ChromeBrowserState* browser_state);
-  ~Browser();
+  ~Browser() override;
 
   WebStateList& web_state_list() { return *web_state_list_.get(); }
   const WebStateList& web_state_list() const { return *web_state_list_.get(); }
diff --git a/ios/shared/chrome/browser/ui/browser_list/browser_user_data.h b/ios/shared/chrome/browser/ui/browser_list/browser_user_data.h
new file mode 100644
index 0000000..15562a3
--- /dev/null
+++ b/ios/shared/chrome/browser/ui/browser_list/browser_user_data.h
@@ -0,0 +1,74 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_USER_DATA_H_
+#define IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_USER_DATA_H_
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/supports_user_data.h"
+#import "ios/shared/chrome/browser/ui/browser_list/browser.h"
+
+// A base class for classes attached to, and scoped to, the lifetime of a
+// Browser. For example:
+//
+// --- in foo.h ---
+// class Foo : public BrowserUserData<Foo> {
+//  public:
+//   ~Foo() override;
+//   // ... more public stuff here ...
+//  private:
+//   explicit Foo(Browser* browser);
+//   friend class BrowserUserData<Foo>;
+//   // ... more private stuff here ...
+// }
+// --- in foo.mm ---
+// DEFINE_BROWSER_USER_DATA_KEY(Foo);
+//
+template <typename T>
+class BrowserUserData : public base::SupportsUserData::Data {
+ public:
+  // Creates an object of type T, and attaches it to the specified Browser.
+  // If an instance is already attached, does nothing.
+  static void CreateForBrowser(Browser* browser) {
+    DCHECK(browser);
+    if (!FromBrowser(browser)) {
+      browser->SetUserData(UserDataKey(), base::WrapUnique(new T(browser)));
+    }
+  }
+
+  // Retrieves the instance of type T that was attached to the specified
+  // Browser (via CreateForBrowser above) and returns it. If no
+  // instance of the type was attached, returns nullptr.
+  static T* FromBrowser(Browser* browser) {
+    return static_cast<T*>(browser->GetUserData(UserDataKey()));
+  }
+  static const T* FromBrowser(const Browser* browser) {
+    return static_cast<const T*>(browser->GetUserData(UserDataKey()));
+  }
+  // Removes the instance attached to the specified WebState.
+  static void RemoveFromBrowser(Browser* browser) {
+    browser->RemoveUserData(UserDataKey());
+  }
+
+ protected:
+  static inline void* UserDataKey() { return &kLocatorKey; }
+
+ private:
+  // The user data key.
+  static int kLocatorKey;
+};
+
+// The macro to define the locator key. This key should be defined in the
+// implementation file of the derived class.
+//
+// The "= 0" is surprising, but is required to effect a definition rather than
+// a declaration. Without it, this would be merely a declaration of a template
+// specialization. (C++98: 14.7.3.15; C++11: 14.7.3.13)
+//
+#define DEFINE_BROWSER_USER_DATA_KEY(TYPE) \
+  template <>                              \
+  int BrowserUserData<TYPE>::kLocatorKey = 0
+
+#endif  // IOS_SHARED_CHROME_BROWSER_UI_BROWSER_LIST_BROWSER_USER_DATA_H_
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 4e30c10..42dea08 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -938,7 +938,7 @@
 
 # Ref tests that needs investigation.
 crbug.com/404597 [ Mac ] fast/css3-text/css3-text-justify/text-justify-crash.html [ Failure ]
-crbug.com/404597 fast/forms/long-text-in-input.html [ Failure ]
+crbug.com/404597 fast/forms/long-text-in-input.html [ Skip ]
 
 # Web Components related tests (Shadow DOM, Custom Elements) failures.
 crbug.com/505364 external/wpt/shadow-dom/untriaged/styles/test-003.html [ Failure ]
@@ -2665,10 +2665,10 @@
 crbug.com/703533 [ Mac ] shapedetection/detection-security-test.html  [ Crash Pass Timeout ]
 
 # Sheriff failures 2017-05-11
-crbug.com/724027 [ Linux ] http/tests/security/contentSecurityPolicy/directive-parsing-03.html [ Failure Pass Timeout ]
-crbug.com/724027 [ Linux ] http/tests/security/contentSecurityPolicy/source-list-parsing-04.html [ Failure Pass Timeout ]
-crbug.com/724027 [ Linux ] virtual/mojo-loading/http/tests/security/contentSecurityPolicy/directive-parsing-03.html [ Failure Pass Timeout ]
-crbug.com/724027 [ Linux ] virtual/mojo-loading/http/tests/security/contentSecurityPolicy/source-list-parsing-04.html [ Failure Pass Timeout ]
+crbug.com/724027 http/tests/security/contentSecurityPolicy/directive-parsing-03.html [ Skip ]
+crbug.com/724027 http/tests/security/contentSecurityPolicy/source-list-parsing-04.html [ Skip ]
+crbug.com/724027 virtual/mojo-loading/http/tests/security/contentSecurityPolicy/directive-parsing-03.html [ Skip ]
+crbug.com/724027 virtual/mojo-loading/http/tests/security/contentSecurityPolicy/source-list-parsing-04.html [ Skip ]
 
 # Sheriff failures 2017-05-16
 crbug.com/722212 fast/events/pointerevents/mouse-pointer-event-properties.html [ Failure Timeout Pass ]
@@ -2831,3 +2831,66 @@
 crbug.com/736177 [ Mac ] virtual/off-main-thread-fetch/http/tests/misc/acid2-pixel.html [ Failure Pass ]
 crbug.com/736177 [ Mac ] virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-with-incomplete-style.html [ Failure Pass ]
 crbug.com/736177 [ Mac ] virtual/rootlayerscrolls/scrollbars/custom-scrollbar-with-incomplete-style.html [ Failure Pass ]
+
+crbug.com/734762 [ Mac Debug ] inspector-protocol/timeline/page-frames.js [ Failure ]
+
+crbug.com/736255 [ Mac ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-001.html [ Skip ]
+
+# These tests crash, fail or are flaky on Mac 10.9
+crbug.com/736257 [ Mac10.9 ] editing/selection/modify_move/move_left_right_character_in_mixed_bidi.html [ Skip ]
+crbug.com/736257 [ Mac10.9 ] external/wpt/css/css-writing-modes-3/bidi-isolate-override-007.html [ Skip ]
+crbug.com/736257 [ Mac10.9 ] fast/text-autosizing/tables/css-table-single-cell-lots-of-text.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text-autosizing/tables/nested-table-wrapping.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text-autosizing/tables/nested-tables.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text-autosizing/tables/table-for-layout.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text-autosizing/tables/wide-specified-width.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/atsui-pointtooffset-calls-cg.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/atsui-rtl-override-selection.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/basic/011.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/basic/013.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/ellipsis-at-edge-of-rtl-text-in-ltr-flow.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/ellipsis-ltr-text-in-ltr-flow-underline-composition.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/ellipsis-rtl-text-in-ltr-flow.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/emphasis-complex.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/fallback-for-custom-font.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/font-fallback.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/font-features/caps-native-synthesis.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/font-initial.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/font-weight.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/bidi-AN-after-L.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/bidi-CS-after-AN.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/bidi-L2-run-reordering.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/bidi-LDB-2-CSS.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/bidi-LDB-2-formatting-characters.html [ Skip ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/bidi-ignored-for-first-child-inline.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/bidi-layout-across-linebreak.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/bidi-neutral-directionality-paragraph-start.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/bidi-neutral-run.html [ Skip ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/hebrew-vowels.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/hindi-spacing.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/mixed-directionality-selection.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/rtl-white-space-pre-wrap.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/international/unicode-bidi-plaintext.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/justified-selection-at-edge.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/justified-selection.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/justify-ideograph-complex.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/justify-ideograph-simple.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/midword-break-after-breakable-char.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/place-ellipsis-in-inline-blocks-align-center.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/place-mixed-ellipsis-in-inline-blocks-align-left-2.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/place-rtl-ellipsis-in-inline-blocks-align-left.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/reset-emptyRun.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/should-use-atsui.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/wbr-styled.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/whitespace/001.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/whitespace/005.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/whitespace/006.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/whitespace/011.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/whitespace/016.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/whitespace/021.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/whitespace/027.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/whitespace/028.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/whitespace/030.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/whitespace/span-in-word-space-causes-overflow.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] fast/text/word-break.html [ Failure Pass ]
+crbug.com/736257 [ Mac10.9 ] inspector/elements/bidi-dom-tree.html [ Skip ]
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index eefc614..a98fa7a 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1227,6 +1227,7 @@
     "dom/ElementTest.cpp",
     "dom/ElementVisibilityObserverTest.cpp",
     "dom/IdleDeadlineTest.cpp",
+    "dom/IntersectionObserverTest.cpp",
     "dom/LayoutTreeBuilderTraversalTest.cpp",
     "dom/MockScriptElementBase.h",
     "dom/ModulatorTest.cpp",
@@ -1235,6 +1236,7 @@
     "dom/NodeTest.cpp",
     "dom/NthIndexCacheTest.cpp",
     "dom/RangeTest.cpp",
+    "dom/ResizeObserverTest.cpp",
     "dom/ScriptModuleResolverImplTest.cpp",
     "dom/ScriptRunnerTest.cpp",
     "dom/ScriptedAnimationControllerTest.cpp",
@@ -1260,19 +1262,32 @@
     "dom/custom/CustomElementTestHelpers.h",
     "dom/custom/CustomElementUpgradeSorterTest.cpp",
     "dom/shadow/FlatTreeTraversalTest.cpp",
+    "dom/shadow/ShadowDOMV0Test.cpp",
     "dom/shadow/SlotScopedTraversalTest.cpp",
     "editing/CaretDisplayItemClientTest.cpp",
+    "editing/TextFinderTest.cpp",
     "events/EventPathTest.cpp",
     "events/EventTargetTest.cpp",
     "events/PointerEventFactoryTest.cpp",
     "events/TouchEventTest.cpp",
+    "events/WebInputEventConversionTest.cpp",
     "exported/WebAssociatedURLLoaderImplTest.cpp",
+    "exported/WebDocumentTest.cpp",
     "exported/WebDragDataTest.cpp",
     "exported/WebElementTest.cpp",
+    "exported/WebFrameSerializerTest.cpp",
     "exported/WebNodeTest.cpp",
+    "exported/WebRangeTest.cpp",
+    "exported/WebScopedWindowFocusAllowedIndicatorTest.cpp",
+    "exported/WebSearchableFormDataTest.cpp",
+    "exported/WebSelectorTest.cpp",
+    "exported/WebUserGestureTokenTest.cpp",
+    "exported/WebViewTest.cpp",
     "fileapi/FileListTest.cpp",
     "fileapi/FileTest.cpp",
+    "frame/BrowserControlsTest.cpp",
     "frame/DOMTimerTest.cpp",
+    "frame/FrameSerializerTest.cpp",
     "frame/FrameTest.cpp",
     "frame/FrameTestHelpers.cpp",
     "frame/FrameTestHelpers.h",
@@ -1283,6 +1298,7 @@
     "frame/RootFrameViewportTest.cpp",
     "frame/SubresourceIntegrityTest.cpp",
     "frame/UseCounterTest.cpp",
+    "frame/VisualViewportTest.cpp",
     "frame/csp/CSPDirectiveListTest.cpp",
     "frame/csp/CSPSourceTest.cpp",
     "frame/csp/ContentSecurityPolicyTest.cpp",
@@ -1326,6 +1342,7 @@
     "html/parser/AtomicHTMLTokenTest.cpp",
     "html/parser/CSSPreloadScannerTest.cpp",
     "html/parser/CompactHTMLTokenTest.cpp",
+    "html/parser/HTMLDocumentParserLoadingTest.cpp",
     "html/parser/HTMLDocumentParserTest.cpp",
     "html/parser/HTMLEntityParserTest.cpp",
     "html/parser/HTMLParserIdiomsTest.cpp",
@@ -1400,6 +1417,7 @@
     "layout/svg/LayoutSVGRootTest.cpp",
     "loader/BaseFetchContextTest.cpp",
     "loader/DocumentLoadTimingTest.cpp",
+    "loader/DocumentLoaderTest.cpp",
     "loader/FrameFetchContextTest.cpp",
     "loader/LinkLoaderTest.cpp",
     "loader/MixedContentCheckerTest.cpp",
@@ -1428,6 +1446,7 @@
     "page/PrintContextTest.cpp",
     "page/WindowFeaturesTest.cpp",
     "page/scrolling/ScrollStateTest.cpp",
+    "page/scrolling/ScrollingCoordinatorTest.cpp",
     "page/scrolling/SnapCoordinatorTest.cpp",
     "paint/BoxPaintInvalidatorTest.cpp",
     "paint/FirstMeaningfulPaintDetectorTest.cpp",
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 8b987e68..96f33e2 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -3250,6 +3250,8 @@
     return;
 
   if (load_event_progress_ <= kUnloadEventInProgress) {
+    if (GetPage())
+      GetPage()->WillUnloadDocument(*this);
     Element* current_focused_element = FocusedElement();
     if (isHTMLInputElement(current_focused_element))
       toHTMLInputElement(*current_focused_element).EndEditing();
diff --git a/third_party/WebKit/Source/core/dom/DocumentTest.cpp b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
index 582986e..6ebc468 100644
--- a/third_party/WebKit/Source/core/dom/DocumentTest.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
@@ -294,8 +294,12 @@
   MockValidationMessageClient() { Reset(); }
   void Reset() {
     show_validation_message_was_called = false;
+    will_unload_document_was_called = false;
+    document_detached_was_called = false;
   }
   bool show_validation_message_was_called;
+  bool will_unload_document_was_called;
+  bool document_detached_was_called;
 
   // ValidationMessageClient functions.
   void ShowValidationMessage(const Element& anchor,
@@ -309,6 +313,12 @@
   bool IsValidationMessageVisible(const Element& anchor) override {
     return true;
   }
+  void WillUnloadDocument(const Document&) override {
+    will_unload_document_was_called = true;
+  }
+  void DocumentDetached(const Document&) override {
+    document_detached_was_called = true;
+  }
   void WillBeDestroyed() override {}
 
   // DEFINE_INLINE_VIRTUAL_TRACE() { ValidationMessageClient::trace(visitor); }
@@ -816,6 +826,8 @@
 
   // prepareForCommit() unloads the document, and shutdown.
   GetDocument().GetFrame()->PrepareForCommit();
+  EXPECT_TRUE(mock_client->will_unload_document_was_called);
+  EXPECT_TRUE(mock_client->document_detached_was_called);
   // Unload handler tried to show a validation message, but it should fail.
   EXPECT_FALSE(mock_client->show_validation_message_was_called);
 
diff --git a/third_party/WebKit/Source/web/tests/IntersectionObserverTest.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserverTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/IntersectionObserverTest.cpp
rename to third_party/WebKit/Source/core/dom/IntersectionObserverTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/ResizeObserverTest.cpp b/third_party/WebKit/Source/core/dom/ResizeObserverTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/ResizeObserverTest.cpp
rename to third_party/WebKit/Source/core/dom/ResizeObserverTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/ShadowDOMV0Test.cpp b/third_party/WebKit/Source/core/dom/shadow/ShadowDOMV0Test.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/ShadowDOMV0Test.cpp
rename to third_party/WebKit/Source/core/dom/shadow/ShadowDOMV0Test.cpp
diff --git a/third_party/WebKit/Source/web/tests/TextFinderTest.cpp b/third_party/WebKit/Source/core/editing/TextFinderTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/TextFinderTest.cpp
rename to third_party/WebKit/Source/core/editing/TextFinderTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp b/third_party/WebKit/Source/core/events/WebInputEventConversionTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/WebInputEventConversionTest.cpp
rename to third_party/WebKit/Source/core/events/WebInputEventConversionTest.cpp
diff --git a/third_party/WebKit/Source/core/exported/DEPS b/third_party/WebKit/Source/core/exported/DEPS
index 09e1f4ec..7925eccdb 100644
--- a/third_party/WebKit/Source/core/exported/DEPS
+++ b/third_party/WebKit/Source/core/exported/DEPS
@@ -3,4 +3,8 @@
   # exported.
   "+core/exported",
   "+public/web",
+  # We do not want any new dependencies on Web(Local|Remote)FrameBase.h until
+  # we resolve the control layer.
+  "+core/frame/WebLocalFrameBase.h",
+  "+core/frame/WebRemoteFrameBase.h"
 ]
diff --git a/third_party/WebKit/Source/web/tests/WebDocumentTest.cpp b/third_party/WebKit/Source/core/exported/WebDocumentTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/WebDocumentTest.cpp
rename to third_party/WebKit/Source/core/exported/WebDocumentTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameSerializerTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp
rename to third_party/WebKit/Source/core/exported/WebFrameSerializerTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/WebRangeTest.cpp b/third_party/WebKit/Source/core/exported/WebRangeTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/WebRangeTest.cpp
rename to third_party/WebKit/Source/core/exported/WebRangeTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/WebScopedWindowFocusAllowedIndicatorTest.cpp b/third_party/WebKit/Source/core/exported/WebScopedWindowFocusAllowedIndicatorTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/WebScopedWindowFocusAllowedIndicatorTest.cpp
rename to third_party/WebKit/Source/core/exported/WebScopedWindowFocusAllowedIndicatorTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/WebSearchableFormDataTest.cpp b/third_party/WebKit/Source/core/exported/WebSearchableFormDataTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/WebSearchableFormDataTest.cpp
rename to third_party/WebKit/Source/core/exported/WebSearchableFormDataTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/WebSelectorTest.cpp b/third_party/WebKit/Source/core/exported/WebSelectorTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/WebSelectorTest.cpp
rename to third_party/WebKit/Source/core/exported/WebSelectorTest.cpp
diff --git a/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.cpp b/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.cpp
index fdc6f8b..bcd9557 100644
--- a/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebSharedWorkerImpl.cpp
@@ -188,8 +188,6 @@
   main_frame_->DataSource()->SetServiceWorkerNetworkProvider(
       client_->CreateServiceWorkerNetworkProvider());
   main_script_loader_ = WorkerScriptLoader::Create();
-  main_script_loader_->SetRequestContext(
-      WebURLRequest::kRequestContextSharedWorker);
   loading_document_ = main_frame_->GetFrame()->GetDocument();
 
   WebURLRequest::FetchRequestMode fetch_request_mode =
@@ -202,7 +200,8 @@
   }
 
   main_script_loader_->LoadAsynchronously(
-      *loading_document_.Get(), url_, fetch_request_mode,
+      *loading_document_.Get(), url_,
+      WebURLRequest::kRequestContextSharedWorker, fetch_request_mode,
       fetch_credentials_mode, creation_address_space_,
       Bind(&WebSharedWorkerImpl::DidReceiveScriptLoaderResponse,
            WTF::Unretained(this)),
diff --git a/third_party/WebKit/Source/web/tests/WebUserGestureTokenTest.cpp b/third_party/WebKit/Source/core/exported/WebUserGestureTokenTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/WebUserGestureTokenTest.cpp
rename to third_party/WebKit/Source/core/exported/WebUserGestureTokenTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/core/exported/WebViewTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/WebViewTest.cpp
rename to third_party/WebKit/Source/core/exported/WebViewTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/BrowserControlsTest.cpp b/third_party/WebKit/Source/core/frame/BrowserControlsTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/BrowserControlsTest.cpp
rename to third_party/WebKit/Source/core/frame/BrowserControlsTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/FrameSerializerTest.cpp b/third_party/WebKit/Source/core/frame/FrameSerializerTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/FrameSerializerTest.cpp
rename to third_party/WebKit/Source/core/frame/FrameSerializerTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp b/third_party/WebKit/Source/core/frame/VisualViewportTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
rename to third_party/WebKit/Source/core/frame/VisualViewportTest.cpp
index 606ec76..edcb604ce 100644
--- a/third_party/WebKit/Source/web/tests/VisualViewportTest.cpp
+++ b/third_party/WebKit/Source/core/frame/VisualViewportTest.cpp
@@ -1114,10 +1114,7 @@
            x,
            y,
            std::string(negation ? "is" : "isn't") + " at expected location [" +
-               PrintToString(x) +
-               ", " +
-               PrintToString(y) +
-               "]") {
+               PrintToString(x) + ", " + PrintToString(y) + "]") {
   return arg.mouse_position.x == x && arg.mouse_position.y == y;
 }
 
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp
index 4bf34611..add9daf 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.cpp
@@ -257,6 +257,10 @@
   View()->RequestDecode(image, std::move(callback));
 }
 
+DEFINE_TRACE(WebFrameWidgetBase) {
+  visitor->Trace(current_drag_data_);
+}
+
 // TODO(665924): Remove direct dispatches of mouse events from
 // PointerLockController, instead passing them through EventHandler.
 void WebFrameWidgetBase::PointerLockMouseEvent(
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
index ddbc9c6..dd5494c 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
@@ -9,6 +9,7 @@
 #include "core/clipboard/DataObject.h"
 #include "core/dom/UserGestureIndicator.h"
 #include "platform/graphics/paint/PaintImage.h"
+#include "platform/heap/Handle.h"
 #include "platform/wtf/Assertions.h"
 #include "public/platform/WebCoalescedInputEvent.h"
 #include "public/platform/WebDragData.h"
@@ -28,8 +29,11 @@
 struct WebPoint;
 
 class CORE_EXPORT WebFrameWidgetBase
-    : public NON_EXPORTED_BASE(WebFrameWidget) {
+    : public GarbageCollectedFinalized<WebFrameWidgetBase>,
+      public NON_EXPORTED_BASE(WebFrameWidget) {
  public:
+  virtual ~WebFrameWidgetBase() {}
+
   virtual bool ForSubframe() const = 0;
   virtual void ScheduleAnimation() = 0;
   virtual CompositorWorkerProxyClient* CreateCompositorWorkerProxyClient() = 0;
@@ -91,6 +95,8 @@
   void RequestDecode(const PaintImage&,
                      std::unique_ptr<WTF::Function<void(bool)>> callback);
 
+  DECLARE_VIRTUAL_TRACE();
+
  protected:
   enum DragAction { kDragEnter, kDragOver };
 
@@ -111,8 +117,11 @@
   // the page is shutting down, but will be valid at all other times.
   Page* GetPage() const;
 
+  // Helper function to process events while pointer locked.
+  void PointerLockMouseEvent(const WebCoalescedInputEvent&);
+
   // A copy of the web drop data object we received from the browser.
-  Persistent<DataObject> current_drag_data_;
+  Member<DataObject> current_drag_data_;
 
   bool doing_drag_and_drop_ = false;
 
@@ -124,9 +133,6 @@
   // current drop target in this WebView (the drop target can accept the drop).
   WebDragOperation drag_operation_ = kWebDragOperationNone;
 
-  // Helper function to process events while pointer locked.
-  void PointerLockMouseEvent(const WebCoalescedInputEvent&);
-
  private:
   void CancelDrag();
   LocalFrame* FocusedLocalFrameInWidget() const;
diff --git a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp
index aa88b008..4e574b6 100644
--- a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp
+++ b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp
@@ -13,7 +13,10 @@
 WebViewFrameWidget::WebViewFrameWidget(WebWidgetClient& client,
                                        WebViewBase& web_view,
                                        WebLocalFrameBase& main_frame)
-    : client_(&client), web_view_(&web_view), main_frame_(&main_frame) {
+    : client_(&client),
+      web_view_(&web_view),
+      main_frame_(&main_frame),
+      self_keep_alive_(this) {
   main_frame_->SetFrameWidget(this);
   web_view_->SetCompositorVisibility(true);
 }
@@ -33,8 +36,7 @@
 
   // Note: this intentionally does not forward to WebView::close(), to make it
   // easier to untangle the cleanup logic later.
-
-  delete this;
+  self_keep_alive_.Clear();
 }
 
 WebSize WebViewFrameWidget::Size() {
@@ -253,4 +255,9 @@
   return web_view_->CoreHitTestResultAt(point);
 }
 
+DEFINE_TRACE(WebViewFrameWidget) {
+  visitor->Trace(main_frame_);
+  WebFrameWidgetBase::Trace(visitor);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h
index 100ca0e..1538173a 100644
--- a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h
+++ b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h
@@ -9,6 +9,7 @@
 #include "core/frame/WebFrameWidgetBase.h"
 #include "core/frame/WebLocalFrameBase.h"
 #include "platform/heap/Handle.h"
+#include "platform/heap/SelfKeepAlive.h"
 #include "platform/wtf/Noncopyable.h"
 #include "platform/wtf/RefPtr.h"
 
@@ -107,10 +108,14 @@
   WebWidgetClient* Client() const override { return client_; }
   HitTestResult CoreHitTestResultAt(const WebPoint&) override;
 
+  DECLARE_VIRTUAL_TRACE();
+
  private:
   WebWidgetClient* client_;
   RefPtr<WebViewBase> web_view_;
-  Persistent<WebLocalFrameBase> main_frame_;
+  Member<WebLocalFrameBase> main_frame_;
+
+  SelfKeepAlive<WebViewFrameWidget> self_keep_alive_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLFormControlElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLFormControlElementTest.cpp
index 11b697b0..470da5e 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormControlElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormControlElementTest.cpp
@@ -41,6 +41,8 @@
     return anchor_ == &anchor;
   }
 
+  void WillUnloadDocument(const Document&) override {}
+  void DocumentDetached(const Document&) override {}
   void WillBeDestroyed() override {}
   DEFINE_INLINE_VIRTUAL_TRACE() {
     visitor->Trace(anchor_);
diff --git a/third_party/WebKit/Source/web/tests/HTMLDocumentParserLoadingTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParserLoadingTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/HTMLDocumentParserLoadingTest.cpp
rename to third_party/WebKit/Source/core/html/parser/HTMLDocumentParserLoadingTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/DocumentLoaderTest.cpp b/third_party/WebKit/Source/core/loader/DocumentLoaderTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/DocumentLoaderTest.cpp
rename to third_party/WebKit/Source/core/loader/DocumentLoaderTest.cpp
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index 38312cd3..4a08302 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -253,9 +253,16 @@
   main_frame_ = main_frame;
 }
 
+void Page::WillUnloadDocument(const Document& document) {
+  if (validation_message_client_)
+    validation_message_client_->WillUnloadDocument(document);
+}
+
 void Page::DocumentDetached(Document* document) {
   pointer_lock_controller_->DocumentDetached(document);
   context_menu_controller_->DocumentDetached(document);
+  if (validation_message_client_)
+    validation_message_client_->DocumentDetached(*document);
   hosts_using_features_.DocumentDetached(*document);
 }
 
diff --git a/third_party/WebKit/Source/core/page/Page.h b/third_party/WebKit/Source/core/page/Page.h
index 6af63ad9..ccaea49b 100644
--- a/third_party/WebKit/Source/core/page/Page.h
+++ b/third_party/WebKit/Source/core/page/Page.h
@@ -152,6 +152,7 @@
     return ToLocalFrame(main_frame_);
   }
 
+  void WillUnloadDocument(const Document&);
   void DocumentDetached(Document*);
 
   bool OpenedByDOM() const;
diff --git a/third_party/WebKit/Source/core/page/ValidationMessageClient.h b/third_party/WebKit/Source/core/page/ValidationMessageClient.h
index 667f927..396f4b5 100644
--- a/third_party/WebKit/Source/core/page/ValidationMessageClient.h
+++ b/third_party/WebKit/Source/core/page/ValidationMessageClient.h
@@ -32,6 +32,7 @@
 
 namespace blink {
 
+class Document;
 class Element;
 
 class ValidationMessageClient : public GarbageCollectedMixin {
@@ -55,6 +56,9 @@
   // is visible.
   virtual bool IsValidationMessageVisible(const Element& anchor) = 0;
 
+  virtual void WillUnloadDocument(const Document&) = 0;
+  virtual void DocumentDetached(const Document&) = 0;
+
   virtual void WillBeDestroyed() = 0;
 
   DEFINE_INLINE_VIRTUAL_TRACE() {}
diff --git a/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.cpp b/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.cpp
index 575f9bf..f2e3c3b 100644
--- a/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.cpp
+++ b/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.cpp
@@ -115,6 +115,16 @@
   return current_anchor_ == &anchor;
 }
 
+void ValidationMessageClientImpl::WillUnloadDocument(const Document& document) {
+  if (current_anchor_ && current_anchor_->GetDocument() == document)
+    HideValidationMessage(*current_anchor_);
+}
+
+void ValidationMessageClientImpl::DocumentDetached(const Document& document) {
+  DCHECK(!current_anchor_ || current_anchor_->GetDocument() != document)
+      << "willUnloadDocument() should be called beforehand.";
+}
+
 void ValidationMessageClientImpl::CheckAnchorStatus(TimerBase*) {
   DCHECK(current_anchor_);
   if (MonotonicallyIncreasingTime() >= finish_time_ || !CurrentView()) {
diff --git a/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.h b/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.h
index 1b61b2c..0816472 100644
--- a/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.h
+++ b/third_party/WebKit/Source/core/page/ValidationMessageClientImpl.h
@@ -63,6 +63,8 @@
                              TextDirection sub_message_dir) override;
   void HideValidationMessage(const Element& anchor) override;
   bool IsValidationMessageVisible(const Element& anchor) override;
+  void WillUnloadDocument(const Document&) override;
+  void DocumentDetached(const Document&) override;
   void WillBeDestroyed() override;
 
   // PopupOpeningObserver function
diff --git a/third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
similarity index 100%
rename from third_party/WebKit/Source/web/tests/ScrollingCoordinatorTest.cpp
rename to third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
diff --git a/third_party/WebKit/Source/core/workers/InProcessWorkerBase.cpp b/third_party/WebKit/Source/core/workers/InProcessWorkerBase.cpp
index f737b142..2b5e1f7 100644
--- a/third_party/WebKit/Source/core/workers/InProcessWorkerBase.cpp
+++ b/third_party/WebKit/Source/core/workers/InProcessWorkerBase.cpp
@@ -61,7 +61,8 @@
 
   script_loader_ = WorkerScriptLoader::Create();
   script_loader_->LoadAsynchronously(
-      *context, script_url, fetch_request_mode, fetch_credentials_mode,
+      *context, script_url, WebURLRequest::kRequestContextWorker,
+      fetch_request_mode, fetch_credentials_mode,
       context->GetSecurityContext().AddressSpace(),
       WTF::Bind(&InProcessWorkerBase::OnResponse, WrapPersistent(this)),
       WTF::Bind(&InProcessWorkerBase::OnFinished, WrapPersistent(this)));
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
index f080592..4a3768d 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -192,9 +192,8 @@
 
   for (const KURL& complete_url : completed_urls) {
     RefPtr<WorkerScriptLoader> script_loader(WorkerScriptLoader::Create());
-    script_loader->SetRequestContext(WebURLRequest::kRequestContextScript);
     script_loader->LoadSynchronously(
-        execution_context, complete_url,
+        execution_context, complete_url, WebURLRequest::kRequestContextScript,
         execution_context.GetSecurityContext().AddressSpace());
 
     // If the fetching attempt failed, throw a NetworkError exception and
diff --git a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
index 2e0e5139..53423ca 100644
--- a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
@@ -51,7 +51,6 @@
 WorkerScriptLoader::WorkerScriptLoader()
     : response_callback_(nullptr),
       finished_callback_(nullptr),
-      request_context_(WebURLRequest::kRequestContextWorker),
       response_address_space_(kWebAddressSpacePublic) {}
 
 WorkerScriptLoader::~WorkerScriptLoader() {
@@ -66,11 +65,16 @@
 void WorkerScriptLoader::LoadSynchronously(
     ExecutionContext& execution_context,
     const KURL& url,
+    WebURLRequest::RequestContext request_context,
     WebAddressSpace creation_address_space) {
   url_ = url;
   execution_context_ = &execution_context;
 
-  ResourceRequest request(CreateResourceRequest(creation_address_space));
+  ResourceRequest request(url);
+  request.SetHTTPMethod(HTTPNames::GET);
+  request.SetExternalRequestStateFromRequestorAddressSpace(
+      creation_address_space);
+  request.SetRequestContext(request_context);
   request.SetFetchCredentialsMode(WebURLRequest::kFetchCredentialsModeInclude);
 
   SECURITY_DCHECK(execution_context.IsWorkerGlobalScope());
@@ -91,6 +95,7 @@
 void WorkerScriptLoader::LoadAsynchronously(
     ExecutionContext& execution_context,
     const KURL& url,
+    WebURLRequest::RequestContext request_context,
     WebURLRequest::FetchRequestMode fetch_request_mode,
     WebURLRequest::FetchCredentialsMode fetch_credentials_mode,
     WebAddressSpace creation_address_space,
@@ -102,7 +107,11 @@
   url_ = url;
   execution_context_ = &execution_context;
 
-  ResourceRequest request(CreateResourceRequest(creation_address_space));
+  ResourceRequest request(url);
+  request.SetHTTPMethod(HTTPNames::GET);
+  request.SetExternalRequestStateFromRequestorAddressSpace(
+      creation_address_space);
+  request.SetRequestContext(request_context);
   request.SetFetchCredentialsMode(fetch_credentials_mode);
 
   ThreadableLoaderOptions options;
@@ -128,16 +137,6 @@
   return response_url_;
 }
 
-ResourceRequest WorkerScriptLoader::CreateResourceRequest(
-    WebAddressSpace creation_address_space) {
-  ResourceRequest request(url_);
-  request.SetHTTPMethod(HTTPNames::GET);
-  request.SetRequestContext(request_context_);
-  request.SetExternalRequestStateFromRequestorAddressSpace(
-      creation_address_space);
-  return request;
-}
-
 void WorkerScriptLoader::DidReceiveResponse(
     unsigned long identifier,
     const ResourceResponse& response,
diff --git a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h
index 9dea16d..e4be86e 100644
--- a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h
+++ b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h
@@ -62,11 +62,13 @@
 
   void LoadSynchronously(ExecutionContext&,
                          const KURL&,
+                         WebURLRequest::RequestContext,
                          WebAddressSpace);
 
   // Note that callbacks could be invoked before loadAsynchronously() returns.
   void LoadAsynchronously(ExecutionContext&,
                           const KURL&,
+                          WebURLRequest::RequestContext,
                           WebURLRequest::FetchRequestMode,
                           WebURLRequest::FetchCredentialsMode,
                           WebAddressSpace,
@@ -117,17 +119,12 @@
   void DidFail(const ResourceError&) override;
   void DidFailRedirectCheck() override;
 
-  void SetRequestContext(WebURLRequest::RequestContext request_context) {
-    request_context_ = request_context;
-  }
-
  private:
   friend class WTF::RefCounted<WorkerScriptLoader>;
 
   WorkerScriptLoader();
   ~WorkerScriptLoader() override;
 
-  ResourceRequest CreateResourceRequest(WebAddressSpace);
   void NotifyError();
   void NotifyFinished();
 
@@ -152,7 +149,6 @@
   unsigned long identifier_ = 0;
   long long app_cache_id_ = 0;
   std::unique_ptr<Vector<char>> cached_metadata_;
-  WebURLRequest::RequestContext request_context_;
   Persistent<ContentSecurityPolicy> content_security_policy_;
   Persistent<ExecutionContext> execution_context_;
   WebAddressSpace response_address_space_;
diff --git a/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp b/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp
index f7b78ee..3d3b5cf1 100644
--- a/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/modules/exported/WebEmbeddedWorkerImpl.cpp
@@ -331,10 +331,9 @@
   main_frame_->DataSource()->SetServiceWorkerNetworkProvider(
       worker_context_client_->CreateServiceWorkerNetworkProvider());
   main_script_loader_ = WorkerScriptLoader::Create();
-  main_script_loader_->SetRequestContext(
-      WebURLRequest::kRequestContextServiceWorker);
   main_script_loader_->LoadAsynchronously(
       *main_frame_->GetFrame()->GetDocument(), worker_start_data_.script_url,
+      WebURLRequest::kRequestContextServiceWorker,
       WebURLRequest::kFetchRequestModeSameOrigin,
       WebURLRequest::kFetchCredentialsModeSameOrigin,
       worker_start_data_.address_space, nullptr,
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
index bc18d10..f719686 100644
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -84,20 +84,16 @@
   sources = [
     # FIXME: Move the tests from web/tests/ to appropriate places.
     # crbug.com/353585
+
     "tests/AccessibilityObjectModelTest.cpp",
-    "tests/BrowserControlsTest.cpp",
     "tests/ChromeClientImplTest.cpp",
     "tests/CompositorWorkerTest.cpp",
     "tests/DeferredLoadingTest.cpp",
-    "tests/DocumentLoaderTest.cpp",
     "tests/DocumentLoadingRenderingTest.cpp",
     "tests/FakeWebPlugin.cpp",
     "tests/FakeWebPlugin.h",
-    "tests/FrameSerializerTest.cpp",
-    "tests/HTMLDocumentParserLoadingTest.cpp",
     "tests/HTMLImportSheetsTest.cpp",
     "tests/ImeOnFocusTest.cpp",
-    "tests/IntersectionObserverTest.cpp",
     "tests/KeyboardTest.cpp",
     "tests/LayoutGeometryMapTest.cpp",
     "tests/LinkElementLoadingTest.cpp",
@@ -109,41 +105,27 @@
     "tests/NGInlineLayoutTest.cpp",
     "tests/PrerenderingTest.cpp",
     "tests/ProgrammaticScrollTest.cpp",
-    "tests/ResizeObserverTest.cpp",
     "tests/RootScrollerTest.cpp",
     "tests/RunAllTests.cpp",
     "tests/ScreenWakeLockTest.cpp",
     "tests/ScrollMetricsTest.cpp",
     "tests/ScrollbarsTest.cpp",
-    "tests/ScrollingCoordinatorTest.cpp",
-    "tests/ShadowDOMV0Test.cpp",
     "tests/SmoothScrollTest.cpp",
     "tests/SpinLockTest.cpp",
-    "tests/TextFinderTest.cpp",
     "tests/TextSelectionRepaintTest.cpp",
     "tests/TimerPerfTest.cpp",
     "tests/TouchActionTest.cpp",
     "tests/ViewportTest.cpp",
     "tests/VirtualTimeTest.cpp",
-    "tests/VisualViewportTest.cpp",
     "tests/WebDocumentSubresourceFilterTest.cpp",
-    "tests/WebDocumentTest.cpp",
     "tests/WebFrameSerializerSanitizationTest.cpp",
-    "tests/WebFrameSerializerTest.cpp",
     "tests/WebFrameTest.cpp",
     "tests/WebHelperPluginTest.cpp",
     "tests/WebImageTest.cpp",
-    "tests/WebInputEventConversionTest.cpp",
     "tests/WebMeaningfulLayoutsTest.cpp",
     "tests/WebPluginContainerTest.cpp",
-    "tests/WebRangeTest.cpp",
-    "tests/WebScopedWindowFocusAllowedIndicatorTest.cpp",
-    "tests/WebSearchableFormDataTest.cpp",
-    "tests/WebSelectorTest.cpp",
     "tests/WebURLRequestTest.cpp",
     "tests/WebURLResponseTest.cpp",
-    "tests/WebUserGestureTokenTest.cpp",
-    "tests/WebViewTest.cpp",
     "tests/WindowProxyTest.cpp",
     "tests/scheduler/ActiveConnectionThrottlingTest.cpp",
     "tests/scheduler/FrameThrottlingTest.cpp",
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
index 8078818..ef725e4e 100644
--- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
+++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
@@ -139,6 +139,7 @@
 DEFINE_TRACE(WebFrameWidgetImpl) {
   visitor->Trace(local_root_);
   visitor->Trace(mouse_capture_node_);
+  WebFrameWidgetBase::Trace(visitor);
 }
 
 // WebWidget ------------------------------------------------------------------
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.h b/third_party/WebKit/Source/web/WebFrameWidgetImpl.h
index 1802aa3..a3290d9 100644
--- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.h
+++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.h
@@ -62,10 +62,8 @@
 using WebFrameWidgetsSet =
     PersistentHeapHashSet<WeakMember<WebFrameWidgetImpl>>;
 
-class WebFrameWidgetImpl final
-    : public GarbageCollectedFinalized<WebFrameWidgetImpl>,
-      public WebFrameWidgetBase,
-      public PageWidgetEventHandler {
+class WebFrameWidgetImpl final : public WebFrameWidgetBase,
+                                 public PageWidgetEventHandler {
  public:
   static WebFrameWidgetImpl* Create(WebWidgetClient*, WebLocalFrame*);
 
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index e13db07d..07bff0e 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1581,7 +1581,6 @@
     blink::InterfaceRegistry* interface_registry)
     : WebLocalFrameBase(scope),
       local_frame_client_impl_(LocalFrameClientImpl::Create(this)),
-      frame_widget_(0),
       client_(client),
       autofill_client_(0),
       input_events_scale_factor_for_emulation_(1),
@@ -1619,6 +1618,7 @@
   visitor->Trace(local_frame_client_impl_);
   visitor->Trace(frame_);
   visitor->Trace(dev_tools_agent_);
+  visitor->Trace(frame_widget_);
   visitor->Trace(text_finder_);
   visitor->Trace(print_context_);
   visitor->Trace(context_menu_node_);
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.h b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
index 1d4fd88d..cf6c29b 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.h
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
@@ -485,7 +485,7 @@
 
   // This is set if the frame is the root of a local frame tree, and requires a
   // widget for layout.
-  WebFrameWidgetBase* frame_widget_;
+  Member<WebFrameWidgetBase> frame_widget_;
 
   WebFrameClient* client_;
   WebAutofillClient* autofill_client_;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 16c1736..fb56385 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -39635,6 +39635,17 @@
   </summary>
 </histogram>
 
+<histogram name="Net.ResourceDispatcherHost.PeakOutstandingRequests"
+    units="requests">
+  <owner>ksakamoto@chromium.org</owner>
+  <summary>
+    The largest number of outstanding requests handled by the resource
+    dispatcher host, during the last sample interval (60 seconds). Not logged if
+    there are no outstanding requests in the interval. This metric is temporary
+    for the Loading Dispatcher v0 (crbug.com/723233), and will be removed soon.
+  </summary>
+</histogram>
+
 <histogram name="Net.ResourceLoader.ExpectedContentSizeResult"
     enum="ResourceLoaderExpectedContentSizeResult">
   <owner>maksim.sisov@intel.com</owner>
@@ -44849,10 +44860,14 @@
 <histogram name="NewTabPage.NumberOfTiles">
   <owner>treib@chromium.org</owner>
   <summary>
-    The number of tiles that are displayed on the NTP, no matter if they are
-    thumbnails, gray tiles, or external tiles. Recorded before reloading the
-    suggestions, navigating to a URL, switching tabs, changing the active window
-    or closing the tab/shutting down Chrome.
+    The number of tiles that are on the NTP, no matter if they are thumbnails,
+    gray tiles, or external tiles. Recorded before reloading the suggestions,
+    navigating to a URL, switching tabs, changing the active window or closing
+    the tab/shutting down Chrome. The sum of this histogram does not have to
+    equal to the total count of tile impressions (such as the total count in
+    NewTabPage.TileType). The reason is that not all tiles have to be impressed
+    initially (e.g., the second row of tiles may be initially out of sight on
+    iOS).
   </summary>
 </histogram>
 
@@ -90487,6 +90502,12 @@
   <affected-histogram name="ModuleIntegrityVerification.Difference"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="MultiTabLoading" separator=".">
+  <suffix name="MultiTabLoading" label="There were multiple loading tabs."/>
+  <affected-histogram
+      name="Net.ResourceDispatcherHost.PeakOutstandingRequests"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="NatType" separator=".">
   <suffix name="NoNAT"/>
   <suffix name="UnknownNAT"/>