diff --git a/DEPS b/DEPS
index a08e612b..efab3c42 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '31550dbc9804dafb18a71c968deb513cc8857cf3',
+  'skia_revision': '6c3c1d621cb2bb3d9ed6087c8d5daaf9e2dc24b0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '973d0ea8a1dc71bcf43ffb85757f02232d66d040',
+  'v8_revision': '2e442a5c2261d20a60f06a38a33331337185b9f8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '3919ea65c283bd0480b5c7fca196acc4d571fad4',
+  'catapult_revision': 'a3798635175e53f40f7548875b4eb9cec5baf055',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/base/trace_event/memory_allocator_dump_guid.h b/base/trace_event/memory_allocator_dump_guid.h
index b6472c6..2a420a2 100644
--- a/base/trace_event/memory_allocator_dump_guid.h
+++ b/base/trace_event/memory_allocator_dump_guid.h
@@ -39,6 +39,10 @@
     return !(*this == other);
   }
 
+  bool operator<(const MemoryAllocatorDumpGuid& other) const {
+    return guid_ < other.guid_;
+  }
+
  private:
   uint64_t guid_;
 
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index d81999c..cb8d5fa7 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -301,8 +301,7 @@
   other->allocator_dumps_.clear();
 
   // Move all the edges.
-  allocator_dumps_edges_.insert(allocator_dumps_edges_.end(),
-                                other->allocator_dumps_edges_.begin(),
+  allocator_dumps_edges_.insert(other->allocator_dumps_edges_.begin(),
                                 other->allocator_dumps_edges_.end());
   other->allocator_dumps_edges_.clear();
 
@@ -341,7 +340,8 @@
   }
 
   value->BeginArray("allocators_graph");
-  for (const MemoryAllocatorDumpEdge& edge : allocator_dumps_edges_) {
+  for (const auto& it : allocator_dumps_edges_) {
+    const MemoryAllocatorDumpEdge& edge = it.second;
     value->BeginDictionary();
     value->SetString("source", edge.source.ToString());
     value->SetString("target", edge.target.ToString());
@@ -355,8 +355,10 @@
 void ProcessMemoryDump::AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
                                          const MemoryAllocatorDumpGuid& target,
                                          int importance) {
-  allocator_dumps_edges_.push_back(
-      {source, target, importance, kEdgeTypeOwnership});
+  DCHECK(allocator_dumps_edges_.count(source) == 0 ||
+         allocator_dumps_edges_[source].overridable);
+  allocator_dumps_edges_[source] = {
+      source, target, importance, kEdgeTypeOwnership, false /* overridable */};
 }
 
 void ProcessMemoryDump::AddOwnershipEdge(
@@ -365,6 +367,21 @@
   AddOwnershipEdge(source, target, 0 /* importance */);
 }
 
+void ProcessMemoryDump::AddOverridableOwnershipEdge(
+    const MemoryAllocatorDumpGuid& source,
+    const MemoryAllocatorDumpGuid& target,
+    int importance) {
+  if (allocator_dumps_edges_.count(source) == 0) {
+    allocator_dumps_edges_[source] = {
+        source, target, importance, kEdgeTypeOwnership, true /* overridable */};
+  } else {
+    // An edge between the source and target already exits. So, do nothing here
+    // since the new overridable edge is implicitly overridden by a strong edge
+    // which was created earlier.
+    DCHECK(!allocator_dumps_edges_[source].overridable);
+  }
+}
+
 void ProcessMemoryDump::AddSuballocation(const MemoryAllocatorDumpGuid& source,
                                          const std::string& target_node_name) {
   // Do not create new dumps for suballocations in background mode.
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index b16930f..ec82c10 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -7,6 +7,7 @@
 
 #include <stddef.h>
 
+#include <map>
 #include <unordered_map>
 #include <vector>
 
@@ -43,6 +44,7 @@
     MemoryAllocatorDumpGuid target;
     int importance;
     const char* type;
+    bool overridable;
   };
 
   // Maps allocator dumps absolute names (allocator_name/heap/subheap) to
@@ -53,6 +55,10 @@
   using HeapDumpsMap =
       std::unordered_map<std::string, std::unique_ptr<TracedValue>>;
 
+  // Stores allocator dump edges indexed by source allocator dump GUID.
+  using AllocatorDumpEdgesMap =
+      std::map<MemoryAllocatorDumpGuid, MemoryAllocatorDumpEdge>;
+
 #if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
   // Returns the number of bytes in a kernel memory page. Some platforms may
   // have a different value for kernel page sizes from user page sizes. It is
@@ -137,7 +143,14 @@
   void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
                         const MemoryAllocatorDumpGuid& target);
 
-  const std::vector<MemoryAllocatorDumpEdge>& allocator_dumps_edges() const {
+  // Adds edges that can be overriden by a later or earlier call to
+  // AddOwnershipEdge() with the same source and target with a different
+  // |importance| value.
+  void AddOverridableOwnershipEdge(const MemoryAllocatorDumpGuid& source,
+                                   const MemoryAllocatorDumpGuid& target,
+                                   int importance);
+
+  const AllocatorDumpEdgesMap& allocator_dumps_edges_for_testing() const {
     return allocator_dumps_edges_;
   }
 
@@ -204,7 +217,7 @@
       heap_profiler_serialization_state_;
 
   // Keeps track of relationships between MemoryAllocatorDump(s).
-  std::vector<MemoryAllocatorDumpEdge> allocator_dumps_edges_;
+  AllocatorDumpEdgesMap allocator_dumps_edges_;
 
   // Level of detail of the current dump.
   const MemoryDumpArgs dump_args_;
diff --git a/base/trace_event/process_memory_dump_unittest.cc b/base/trace_event/process_memory_dump_unittest.cc
index 70f897c..4bddb61 100644
--- a/base/trace_event/process_memory_dump_unittest.cc
+++ b/base/trace_event/process_memory_dump_unittest.cc
@@ -54,7 +54,7 @@
 
   pmd1->Clear();
   ASSERT_TRUE(pmd1->allocator_dumps().empty());
-  ASSERT_TRUE(pmd1->allocator_dumps_edges().empty());
+  ASSERT_TRUE(pmd1->allocator_dumps_edges_for_testing().empty());
   ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad1"));
   ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2"));
   ASSERT_FALSE(pmd1->has_process_totals());
@@ -126,7 +126,7 @@
 
   // Make sure that pmd2 is empty but still usable after it has been emptied.
   ASSERT_TRUE(pmd2->allocator_dumps().empty());
-  ASSERT_TRUE(pmd2->allocator_dumps_edges().empty());
+  ASSERT_TRUE(pmd2->allocator_dumps_edges_for_testing().empty());
   ASSERT_TRUE(pmd2->heap_dumps().empty());
   pmd2->CreateAllocatorDump("pmd2/this_mad_stays_with_pmd2");
   ASSERT_EQ(1u, pmd2->allocator_dumps().size());
@@ -147,7 +147,7 @@
   ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
   ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd2/mad1"));
   ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
-  ASSERT_EQ(2u, pmd1->allocator_dumps_edges().size());
+  ASSERT_EQ(2u, pmd1->allocator_dumps_edges_for_testing().size());
   ASSERT_EQ(shared_mad1, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid1));
   ASSERT_EQ(shared_mad2, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2));
   ASSERT_TRUE(MemoryAllocatorDump::Flags::WEAK & shared_mad2->flags());
@@ -164,6 +164,72 @@
   pmd1.reset();
 }
 
+TEST(ProcessMemoryDumpTest, OverrideOwnershipEdge) {
+  std::unique_ptr<ProcessMemoryDump> pmd(
+      new ProcessMemoryDump(nullptr, kDetailedDumpArgs));
+
+  auto* shm_dump1 = pmd->CreateAllocatorDump("shared_mem/seg1");
+  auto* shm_dump2 = pmd->CreateAllocatorDump("shared_mem/seg2");
+  auto* shm_dump3 = pmd->CreateAllocatorDump("shared_mem/seg3");
+  auto* shm_dump4 = pmd->CreateAllocatorDump("shared_mem/seg4");
+
+  // Create one allocation with an auto-assigned guid and mark it as a
+  // suballocation of "fakealloc/allocated_objects".
+  auto* child1_dump = pmd->CreateAllocatorDump("shared_mem/child/seg1");
+  pmd->AddOverridableOwnershipEdge(child1_dump->guid(), shm_dump1->guid(),
+                                   0 /* importance */);
+  auto* child2_dump = pmd->CreateAllocatorDump("shared_mem/child/seg2");
+  pmd->AddOwnershipEdge(child2_dump->guid(), shm_dump2->guid(),
+                        3 /* importance */);
+  MemoryAllocatorDumpGuid shared_mad_guid(1);
+  pmd->CreateSharedGlobalAllocatorDump(shared_mad_guid);
+  pmd->AddOverridableOwnershipEdge(shm_dump3->guid(), shared_mad_guid,
+                                   0 /* importance */);
+  auto* child4_dump = pmd->CreateAllocatorDump("shared_mem/child/seg4");
+  pmd->AddOverridableOwnershipEdge(child4_dump->guid(), shm_dump4->guid(),
+                                   4 /* importance */);
+
+  const ProcessMemoryDump::AllocatorDumpEdgesMap& edges =
+      pmd->allocator_dumps_edges_for_testing();
+  EXPECT_EQ(4u, edges.size());
+  EXPECT_EQ(shm_dump1->guid(), edges.find(child1_dump->guid())->second.target);
+  EXPECT_EQ(0, edges.find(child1_dump->guid())->second.importance);
+  EXPECT_TRUE(edges.find(child1_dump->guid())->second.overridable);
+  EXPECT_EQ(shm_dump2->guid(), edges.find(child2_dump->guid())->second.target);
+  EXPECT_EQ(3, edges.find(child2_dump->guid())->second.importance);
+  EXPECT_FALSE(edges.find(child2_dump->guid())->second.overridable);
+  EXPECT_EQ(shared_mad_guid, edges.find(shm_dump3->guid())->second.target);
+  EXPECT_EQ(0, edges.find(shm_dump3->guid())->second.importance);
+  EXPECT_TRUE(edges.find(shm_dump3->guid())->second.overridable);
+  EXPECT_EQ(shm_dump4->guid(), edges.find(child4_dump->guid())->second.target);
+  EXPECT_EQ(4, edges.find(child4_dump->guid())->second.importance);
+  EXPECT_TRUE(edges.find(child4_dump->guid())->second.overridable);
+
+  // These should override old edges:
+  pmd->AddOwnershipEdge(child1_dump->guid(), shm_dump1->guid(),
+                        1 /* importance */);
+  pmd->AddOwnershipEdge(shm_dump3->guid(), shared_mad_guid, 2 /* importance */);
+  // This should not change the old edges.
+  pmd->AddOverridableOwnershipEdge(child2_dump->guid(), shm_dump2->guid(),
+                                   0 /* importance */);
+  pmd->AddOwnershipEdge(child4_dump->guid(), shm_dump4->guid(),
+                        0 /* importance */);
+
+  EXPECT_EQ(4u, edges.size());
+  EXPECT_EQ(shm_dump1->guid(), edges.find(child1_dump->guid())->second.target);
+  EXPECT_EQ(1, edges.find(child1_dump->guid())->second.importance);
+  EXPECT_FALSE(edges.find(child1_dump->guid())->second.overridable);
+  EXPECT_EQ(shm_dump2->guid(), edges.find(child2_dump->guid())->second.target);
+  EXPECT_EQ(3, edges.find(child2_dump->guid())->second.importance);
+  EXPECT_FALSE(edges.find(child2_dump->guid())->second.overridable);
+  EXPECT_EQ(shared_mad_guid, edges.find(shm_dump3->guid())->second.target);
+  EXPECT_EQ(2, edges.find(shm_dump3->guid())->second.importance);
+  EXPECT_FALSE(edges.find(shm_dump3->guid())->second.overridable);
+  EXPECT_EQ(shm_dump4->guid(), edges.find(child4_dump->guid())->second.target);
+  EXPECT_EQ(0, edges.find(child4_dump->guid())->second.importance);
+  EXPECT_FALSE(edges.find(child4_dump->guid())->second.overridable);
+}
+
 TEST(ProcessMemoryDumpTest, Suballocations) {
   std::unique_ptr<ProcessMemoryDump> pmd(
       new ProcessMemoryDump(nullptr, kDetailedDumpArgs));
@@ -193,11 +259,11 @@
   // Finally check that AddSuballocation() has created also the
   // edges between the pictures and the anonymous allocator child dumps.
   bool found_edge[2]{false, false};
-  for (const auto& e : pmd->allocator_dumps_edges()) {
-    found_edge[0] |= (e.source == pic1_dump->guid() &&
-                      e.target == anon_node_1_it->second->guid());
-    found_edge[1] |= (e.source == pic2_dump->guid() &&
-                      e.target == anon_node_2_it->second->guid());
+  for (const auto& e : pmd->allocator_dumps_edges_for_testing()) {
+    found_edge[0] |= (e.first == pic1_dump->guid() &&
+                      e.second.target == anon_node_1_it->second->guid());
+    found_edge[1] |= (e.first == pic2_dump->guid() &&
+                      e.second.target == anon_node_2_it->second->guid());
   }
   ASSERT_TRUE(found_edge[0]);
   ASSERT_TRUE(found_edge[1]);
diff --git a/build/check_gn_headers.py b/build/check_gn_headers.py
index c5095e61..2c3a51a1 100755
--- a/build/check_gn_headers.py
+++ b/build/check_gn_headers.py
@@ -19,12 +19,16 @@
 import tempfile
 from multiprocessing import Process, Queue
 
+SRC_DIR = os.path.abspath(
+    os.path.join(os.path.abspath(os.path.dirname(__file__)), os.path.pardir))
+DEPOT_TOOLS_DIR = os.path.join(SRC_DIR, 'third_party', 'depot_tools')
+
 
 def GetHeadersFromNinja(out_dir, q):
   """Return all the header files from ninja_deps"""
 
   def NinjaSource():
-    cmd = ['ninja', '-C', out_dir, '-t', 'deps']
+    cmd = [os.path.join(DEPOT_TOOLS_DIR, 'ninja'), '-C', out_dir, '-t', 'deps']
     # A negative bufsize means to use the system default, which usually
     # means fully buffered.
     popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=-1)
@@ -82,7 +86,8 @@
     shutil.copy2(os.path.join(out_dir, 'args.gn'),
                  os.path.join(tmp, 'args.gn'))
     # Do "gn gen" in a temp dir to prevent dirtying |out_dir|.
-    subprocess.check_call(['gn', 'gen', tmp, '--ide=json', '-q'])
+    subprocess.check_call([
+      os.path.join(DEPOT_TOOLS_DIR, 'gn'), 'gen', tmp, '--ide=json', '-q'])
     gn_json = json.load(open(os.path.join(tmp, 'project.json')))
     ans = ParseGNProjectJSON(gn_json, out_dir, tmp)
   except Exception as e:
@@ -118,9 +123,10 @@
   """Return all the folders controlled by DEPS file"""
   prefixes, err = set(), None
   try:
-    gclient_out = subprocess.check_output(
-        ['gclient', 'recurse', '--no-progress', '-j1',
-         'python', '-c', 'import os;print os.environ["GCLIENT_DEP_PATH"]'])
+    gclient_out = subprocess.check_output([
+      os.path.join(DEPOT_TOOLS_DIR, 'gclient'),
+      'recurse', '--no-progress', '-j1',
+      'python', '-c', 'import os;print os.environ["GCLIENT_DEP_PATH"]'])
     for i in gclient_out.split('\n'):
       if i.startswith('src/'):
         i = i[4:]
@@ -131,7 +137,7 @@
 
 
 def IsBuildClean(out_dir):
-  cmd = ['ninja', '-C', out_dir, '-n']
+  cmd = [os.path.join(DEPOT_TOOLS_DIR, 'ninja'), '-C', out_dir, '-n']
   out = subprocess.check_output(cmd)
   return 'no work to do.' in out
 
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index cf617028..993571c 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1606,10 +1606,6 @@
   deps = [
     "//chrome/test/data:webui_test_resources",
   ]
-  if (!is_android && !is_ios) {
-    sources += [ "$root_gen_dir/chrome/options_test_resources.pak" ]
-    deps += [ "//chrome/browser/resources:options_test_resources" ]
-  }
 }
 
 group("strings") {
diff --git a/chrome/VERSION b/chrome/VERSION
index 5459bd9..d346d67 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=61
 MINOR=0
-BUILD=3123
+BUILD=3124
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTask.java
index 9f894c8..3d1741b3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTask.java
@@ -35,8 +35,12 @@
  */
 @JNINamespace("offline_pages::prefetch")
 public class PrefetchBackgroundTask implements BackgroundTask {
+    public static final long DEFAULT_START_DELAY_SECONDS = 15 * 60;
+
     private static final String TAG = "OPPrefetchBGTask";
 
+    private static BackgroundTaskScheduler sSchedulerInstance;
+
     private long mNativeTask = 0;
     private TaskFinishedCallback mTaskFinishedCallback = null;
 
@@ -50,6 +54,13 @@
         mProfile = profile;
     }
 
+    static BackgroundTaskScheduler getScheduler() {
+        if (sSchedulerInstance != null) {
+            return sSchedulerInstance;
+        }
+        return BackgroundTaskSchedulerFactory.getScheduler();
+    }
+
     /**
      * Schedules the default 'NWake' task for the prefetching service.
      *
@@ -57,13 +68,13 @@
      * TODO(dewittj): Handle skipping work if the battery percentage is too low.
      */
     @CalledByNative
-    public static void scheduleTask() {
-        BackgroundTaskScheduler scheduler = BackgroundTaskSchedulerFactory.getScheduler();
+    public static void scheduleTask(int additionalDelaySeconds) {
         TaskInfo taskInfo =
                 TaskInfo.createOneOffTask(TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID,
                                 PrefetchBackgroundTask.class,
                                 // Minimum time to wait
-                                TimeUnit.MINUTES.toMillis(15),
+                                TimeUnit.SECONDS.toMillis(
+                                        DEFAULT_START_DELAY_SECONDS + additionalDelaySeconds),
                                 // Maximum time to wait.  After this interval the event will fire
                                 // regardless of whether the conditions are right.
                                 TimeUnit.DAYS.toMillis(7))
@@ -71,7 +82,7 @@
                         .setIsPersisted(true)
                         .setUpdateCurrent(true)
                         .build();
-        scheduler.schedule(ContextUtils.getApplicationContext(), taskInfo);
+        getScheduler().schedule(ContextUtils.getApplicationContext(), taskInfo);
     }
 
     /**
@@ -79,8 +90,7 @@
      */
     @CalledByNative
     public static void cancelTask() {
-        BackgroundTaskScheduler scheduler = BackgroundTaskSchedulerFactory.getScheduler();
-        scheduler.cancel(
+        getScheduler().cancel(
                 ContextUtils.getApplicationContext(), TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID);
     }
 
@@ -161,7 +171,27 @@
     }
 
     @VisibleForTesting
+    static void setSchedulerForTesting(BackgroundTaskScheduler scheduler) {
+        sSchedulerInstance = scheduler;
+    }
+
+    @VisibleForTesting
+    void setTaskReschedulingForTesting(boolean reschedule, boolean backoff) {
+        if (mNativeTask == 0) return;
+        nativeSetTaskReschedulingForTesting(mNativeTask, reschedule, backoff);
+    }
+
+    @VisibleForTesting
+    void signalTaskFinishedForTesting() {
+        if (mNativeTask == 0) return;
+        nativeSignalTaskFinishedForTesting(mNativeTask);
+    }
+
+    @VisibleForTesting
     native boolean nativeStartPrefetchTask(Profile profile);
     @VisibleForTesting
     native boolean nativeOnStopTask(long nativePrefetchBackgroundTask);
+    native void nativeSetTaskReschedulingForTesting(
+            long nativePrefetchBackgroundTask, boolean reschedule, boolean backoff);
+    native void nativeSignalTaskFinishedForTesting(long nativePrefetchBackgroundTask);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/page_info/PageInfoPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/page_info/PageInfoPopup.java
index 24a005e..12efeff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/page_info/PageInfoPopup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/page_info/PageInfoPopup.java
@@ -90,11 +90,12 @@
  */
 public class PageInfoPopup implements OnClickListener {
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({OPENED_FROM_MENU, OPENED_FROM_TOOLBAR})
+    @IntDef({OPENED_FROM_MENU, OPENED_FROM_TOOLBAR, OPENED_FROM_VR})
     private @interface OpenedFromSource {}
 
     public static final int OPENED_FROM_MENU = 1;
     public static final int OPENED_FROM_TOOLBAR = 2;
+    public static final int OPENED_FROM_VR = 3;
 
     /**
      * An entry in the settings dropdown for a given permission. There are two options for each
@@ -997,6 +998,8 @@
             RecordUserAction.record("MobileWebsiteSettingsOpenedFromMenu");
         } else if (source == OPENED_FROM_TOOLBAR) {
             RecordUserAction.record("MobileWebsiteSettingsOpenedFromToolbar");
+        } else if (source == OPENED_FROM_VR) {
+            RecordUserAction.record("MobileWebsiteSettingsOpenedFromVR");
         } else {
             assert false : "Invalid source passed";
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index b0121f7..af5620d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -51,6 +51,7 @@
 import org.chromium.chrome.browser.help.HelpAndFeedback;
 import org.chromium.chrome.browser.infobar.InfoBarIdentifier;
 import org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder;
+import org.chromium.chrome.browser.page_info.PageInfoPopup;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.util.IntentUtils;
@@ -140,6 +141,9 @@
     private Boolean mInVrAtChromeLaunch;
     private boolean mShowingDaydreamDoff;
     private boolean mDoffOptional;
+    // Whether we should show the PageInfo UI. This is shown when we force exit the user
+    // out of VR when they attempt to view the PageInfo.
+    private boolean mShouldShowPageInfo;
     private boolean mExitingCct;
     private boolean mPaused;
     private int mRestoreSystemUiVisibilityFlag = -1;
@@ -486,6 +490,7 @@
             case ActivityState.RESUMED:
                 if (mInVr && activity != mActivity) {
                     if (mShowingDaydreamDoff) {
+                        mShouldShowPageInfo = false;
                         onExitVrResult(true);
                     } else {
                         // We should never reach this state currently, but just in case...
@@ -627,6 +632,7 @@
         }
         mVrClassesWrapper.setVrModeEnabled(mActivity, true);
         mInVr = true;
+        mShouldShowPageInfo = false;
         // Lock orientation to landscape after enter VR.
         mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
 
@@ -899,8 +905,12 @@
 
         // If Doff is not optional and user backed out, keep trying to exit.
         if (!mDoffOptional && !success && showDoff(false /* optional */)) return;
+
         mShowingDaydreamDoff = false;
         if (success) {
+            if (mShouldShowPageInfo) {
+                sInstance.showPageInfoPopup();
+            }
             shutdownVr(true /* disableVrMode */, false /* canReenter */,
                     !mExitingCct /* stayingInChrome */);
             if (mExitingCct) ((CustomTabActivity) mActivity).finishAndClose(false);
@@ -988,14 +998,23 @@
         if (disableVrMode) mVrClassesWrapper.setVrModeEnabled(mActivity, false);
 
         promptForFeedbackIfNeeded(stayingInChrome);
+        // We don't want to show the PageInfo prompt if we return to Chrome
+        // after shutting down for reasons other than a successful DOFF (e.g.
+        // clicking the controller home button and returning to Chrome).
+        mShouldShowPageInfo = false;
     }
 
-    /* package */ void showDoffAndExitVr() {
+    /* package */ void showDoffAndExitVr(boolean optional) {
         if (mShowingDaydreamDoff) return;
-        if (showDoff(false /* optional */)) return;
+        if (showDoff(optional)) return;
         shutdownVr(true /* disableVrMode */, false /* canReenter */, true /* stayingInChrome */);
     }
 
+    /* package */ void onUnhandledPageInfo() {
+        mShouldShowPageInfo = true;
+        showDoffAndExitVr(true);
+    }
+
     /* package */ void exitCct() {
         if (mShowingDaydreamDoff) return;
         assert mActivity instanceof CustomTabActivity;
@@ -1010,6 +1029,15 @@
         }
     }
 
+    private void showPageInfoPopup() {
+        assert mShouldShowPageInfo;
+        // Note: we don't set mShouldShowPageInfo to false here because we don't
+        // want to show the feedback prompt when the user exits VR to view PageInfo. So this gets
+        // reset in shutdownVr.
+        PageInfoPopup.show(
+                mActivity, mActivity.getActivityTab(), null, PageInfoPopup.OPENED_FROM_VR);
+    }
+
     private static void startFeedback(Tab tab) {
         // TODO(ymalik): This call will connect to the Google Services api which can be slow. Can we
         // connect to it beforehand when we know that we'll be prompting for feedback?
@@ -1051,12 +1079,14 @@
         // 1) The user hasn't explicitly opted-out of it in the past
         // 2) The user has performed VR browsing
         // 3) The user is exiting VR and going back into 2D Chrome
-        // 4) Every n'th visit (where n = mFeedbackFrequency)
+        // 4) We're not exiting to complete an unsupported VR action in 2D (e.g. viewing PageInfo)
+        // 5) Every n'th visit (where n = mFeedbackFrequency)
 
         if (!activitySupportsExitFeedback(mActivity)) return;
         if (!stayingInChrome) return;
         if (VrFeedbackStatus.getFeedbackOptOut()) return;
         if (!mVrBrowserUsed) return;
+        if (mShouldShowPageInfo) return;
 
         int exitCount = VrFeedbackStatus.getUserExitedAndEntered2DCount();
         VrFeedbackStatus.setUserExitedAndEntered2DCount((exitCount + 1) % mFeedbackFrequency);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
index 8bc205a..8824e21 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -357,7 +357,14 @@
     // Exits VR, telling the user to remove their headset, and returning to Chromium.
     @CalledByNative
     public void forceExitVr() {
-        mDelegate.showDoffAndExitVr();
+        mDelegate.showDoffAndExitVr(false);
+    }
+
+    // Called because showing PageInfo isn't supported in VR. This happens when the user clicks on
+    // the security icon in the URL bar.
+    @CalledByNative
+    public void onUnhandledPageInfo() {
+        mDelegate.onUnhandledPageInfo();
     }
 
     // Exits CCT, returning to the app that opened it.
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 0a8c250..d83835d 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1633,7 +1633,7 @@
         Chrome needs permission to access your camera and microphone for this site.
       </message>
       <message name="IDS_INFOBAR_MISSING_LOCATION_PERMISSION_TEXT" desc="Text shown in an infobar when a website has requested access to the location capabilities, but Chrome is missing the Android location permission.">
-        Chrome needs access to to your location to share your location with this site.
+        Chrome needs access to your location to share your location with this site.
       </message>
       <message name="IDS_MISSING_STORAGE_PERMISSION_DOWNLOAD_EDUCATION_TEXT" desc="Text shown educating the user that Chrome is missing the Android storage permission, which is required to download files.">
         Chrome needs storage access to download files.
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 4a03177..1232e38 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1484,6 +1484,7 @@
   "javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageRequestTest.java",
   "javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java",
   "javatests/src/org/chromium/chrome/browser/offlinepages/RecentTabsTest.java",
+  "javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskTest.java",
   "javatests/src/org/chromium/chrome/browser/omaha/ExponentialBackoffSchedulerTest.java",
   "javatests/src/org/chromium/chrome/browser/omaha/MockExponentialBackoffScheduler.java",
   "javatests/src/org/chromium/chrome/browser/omaha/OmahaBaseTest.java",
@@ -1760,7 +1761,7 @@
   "junit/src/org/chromium/chrome/browser/offlinepages/ShadowDeviceConditions.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPackerTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridgeTest.java",
-  "junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskTest.java",
+  "junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java",
   "junit/src/org/chromium/chrome/browser/omaha/ResponseParserTest.java",
   "junit/src/org/chromium/chrome/browser/omaha/VersionNumberTest.java",
   "junit/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskTest.java
new file mode 100644
index 0000000..297ec35
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskTest.java
@@ -0,0 +1,296 @@
+// 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.
+
+package org.chromium.chrome.browser.offlinepages.prefetch;
+
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.components.background_task_scheduler.BackgroundTask.TaskFinishedCallback;
+import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
+import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerDelegate;
+import org.chromium.components.background_task_scheduler.TaskIds;
+import org.chromium.components.background_task_scheduler.TaskInfo;
+import org.chromium.components.background_task_scheduler.TaskParameters;
+
+import java.util.HashMap;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/** Unit tests for {@link PrefetchBackgroundTask}. */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+        ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG})
+public class PrefetchBackgroundTaskTest {
+    @Rule
+    public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
+            new ChromeActivityTestRule<>(ChromeActivity.class);
+
+    private static final double BACKOFF_JITTER_FACTOR = 0.33;
+    private static final int SEMAPHORE_TIMEOUT_MS = 5000;
+    private TestBackgroundTaskScheduler mScheduler;
+
+    private static class TestPrefetchBackgroundTask extends PrefetchBackgroundTask {
+        private TaskInfo mTaskInfo;
+        private boolean mNeedsReschedule;
+        private Semaphore mStopSemaphore = new Semaphore(0);
+
+        public TestPrefetchBackgroundTask(TaskInfo taskInfo) {
+            super(Profile.getLastUsedProfile());
+            mTaskInfo = taskInfo;
+        }
+
+        public void startTask(Context context, final TaskFinishedCallback callback) {
+            TaskParameters.Builder builder =
+                    TaskParameters.create(TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID);
+            TaskParameters params = builder.build();
+            onStartTask(context, params, new TaskFinishedCallback() {
+                @Override
+                public void taskFinished(boolean needsReschedule) {
+                    mNeedsReschedule = needsReschedule;
+                    callback.taskFinished(needsReschedule);
+                    mStopSemaphore.release();
+                }
+            });
+        }
+
+        public void signalTaskFinished() {
+            ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+                @Override
+                public void run() {
+                    signalTaskFinishedForTesting();
+                }
+            });
+        }
+
+        public void stopTask() {
+            ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+                @Override
+                public void run() {
+                    TaskParameters.Builder builder =
+                            TaskParameters.create(TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID);
+                    TaskParameters params = builder.build();
+                    onStopTask(ContextUtils.getApplicationContext(), params);
+                }
+            });
+        }
+
+        public void setTaskRescheduling(final boolean reschedule, final boolean backoff) {
+            ThreadUtils.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    setTaskReschedulingForTesting(reschedule, backoff);
+                }
+            });
+        }
+
+        public void waitForTaskFinished() throws Exception {
+            assertTrue(mStopSemaphore.tryAcquire(SEMAPHORE_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+
+        public TaskInfo taskInfo() {
+            return mTaskInfo;
+        }
+        public boolean needsReschedule() {
+            return mNeedsReschedule;
+        }
+    }
+
+    private static class NoopBackgroundTaskSchedulerDelegate
+            implements BackgroundTaskSchedulerDelegate {
+        @Override
+        public boolean schedule(Context context, TaskInfo taskInfo) {
+            return true;
+        }
+
+        @Override
+        public void cancel(Context context, int taskId) {}
+    }
+
+    private static class TestBackgroundTaskScheduler extends BackgroundTaskScheduler {
+        private HashMap<Integer, TestPrefetchBackgroundTask> mTasks = new HashMap<>();
+        private Semaphore mStartSemaphore = new Semaphore(0);
+        private int mAddCount = 0;
+        private int mRemoveCount = 0;
+
+        public TestBackgroundTaskScheduler() {
+            super(new NoopBackgroundTaskSchedulerDelegate());
+        }
+
+        @Override
+        public boolean schedule(final Context context, final TaskInfo taskInfo) {
+            mAddCount++;
+            ThreadUtils.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    TestPrefetchBackgroundTask task = new TestPrefetchBackgroundTask(taskInfo);
+                    mTasks.put(taskInfo.getTaskId(), task);
+                    task.startTask(context, new TaskFinishedCallback() {
+                        @Override
+                        public void taskFinished(boolean needsReschedule) {
+                            removeTask(taskInfo.getTaskId());
+                        }
+                    });
+                    mStartSemaphore.release();
+                }
+            });
+            return true;
+        }
+
+        @Override
+        public void cancel(Context context, int taskId) {
+            removeTask(taskId);
+        }
+
+        public void waitForTaskStarted() throws Exception {
+            assertTrue(mStartSemaphore.tryAcquire(SEMAPHORE_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            // Reset for next task.
+            mStartSemaphore = new Semaphore(0);
+        }
+
+        public TestPrefetchBackgroundTask getTask(int taskId) {
+            return mTasks.get(taskId);
+        }
+
+        public void removeTask(int taskId) {
+            mRemoveCount++;
+            mTasks.remove(taskId);
+        }
+
+        public int addCount() {
+            return mAddCount;
+        }
+        public int removeCount() {
+            return mRemoveCount;
+        }
+    }
+
+    TestPrefetchBackgroundTask validateAndGetScheduledTask(int additionalDelaySeconds) {
+        TestPrefetchBackgroundTask scheduledTask =
+                mScheduler.getTask(TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID);
+        assertNotNull(scheduledTask);
+        TaskInfo scheduledTaskInfo = scheduledTask.taskInfo();
+        assertEquals(true, scheduledTaskInfo.isPersisted());
+        assertEquals(TaskInfo.NETWORK_TYPE_UNMETERED, scheduledTaskInfo.getRequiredNetworkType());
+
+        long defaultTaskStartTimeMs =
+                TimeUnit.SECONDS.toMillis(PrefetchBackgroundTask.DEFAULT_START_DELAY_SECONDS);
+        long currentTaskStartTimeMs = scheduledTaskInfo.getOneOffInfo().getWindowStartTimeMs();
+        if (additionalDelaySeconds == 0) {
+            assertEquals(defaultTaskStartTimeMs, currentTaskStartTimeMs);
+        } else {
+            long maxTaskStartTimeMs =
+                    defaultTaskStartTimeMs + TimeUnit.SECONDS.toMillis(additionalDelaySeconds);
+            assertTrue(currentTaskStartTimeMs <= maxTaskStartTimeMs);
+            assertTrue(currentTaskStartTimeMs >= maxTaskStartTimeMs * (1 - BACKOFF_JITTER_FACTOR));
+        }
+
+        return scheduledTask;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mScheduler = new TestBackgroundTaskScheduler();
+                PrefetchBackgroundTask.setSchedulerForTesting(mScheduler);
+            }
+        });
+    }
+
+    @Test
+    @SmallTest
+    public void testSchedule() throws Exception {
+        PrefetchBackgroundTask.scheduleTask(0);
+        mScheduler.waitForTaskStarted();
+        TestPrefetchBackgroundTask task = validateAndGetScheduledTask(0);
+        task.signalTaskFinished();
+        task.waitForTaskFinished();
+        assertFalse(task.needsReschedule());
+    }
+
+    @Test
+    @SmallTest
+    public void testScheduleWithAdditionalDelay() throws Exception {
+        final int additionalDelaySeconds = 15;
+        PrefetchBackgroundTask.scheduleTask(additionalDelaySeconds);
+        mScheduler.waitForTaskStarted();
+        TestPrefetchBackgroundTask task = validateAndGetScheduledTask(additionalDelaySeconds);
+        task.signalTaskFinished();
+        task.waitForTaskFinished();
+        assertFalse(task.needsReschedule());
+    }
+
+    @Test
+    @SmallTest
+    public void testReschedule() throws Exception {
+        PrefetchBackgroundTask.scheduleTask(0);
+        mScheduler.waitForTaskStarted();
+        TestPrefetchBackgroundTask task = validateAndGetScheduledTask(0);
+
+        // Requests a reschedule without backoff.
+        task.setTaskRescheduling(/*reschedule*/ true, /*backoff*/ false);
+        task.signalTaskFinished();
+        task.waitForTaskFinished();
+        assertTrue(task.needsReschedule());
+        mScheduler.waitForTaskStarted();
+        // No additional delay due to no backoff asked.
+        task = validateAndGetScheduledTask(0);
+
+        // Requests a reschedule with backoff.
+        task.setTaskRescheduling(/*reschedule*/ true, /*backoff*/ true);
+        task.signalTaskFinished();
+        task.waitForTaskFinished();
+        assertTrue(task.needsReschedule());
+        mScheduler.waitForTaskStarted();
+        // Adding initial delay due to backoff.
+        task = validateAndGetScheduledTask(30);
+
+        // Requests another reschedule with backoff.
+        task.setTaskRescheduling(/*reschedule*/ true, /*backoff*/ true);
+        task.signalTaskFinished();
+        task.waitForTaskFinished();
+        assertTrue(task.needsReschedule());
+        mScheduler.waitForTaskStarted();
+        // Delay doubled due to exponential backoff.
+        task = validateAndGetScheduledTask(60);
+
+        // Simulate killing the task by the system.
+        task.stopTask();
+        task.waitForTaskFinished();
+        assertTrue(task.needsReschedule());
+        mScheduler.waitForTaskStarted();
+        // Additional delay is removed if it is killed by the system.
+        task = validateAndGetScheduledTask(0);
+
+        // Finishes the task without rescheduling.
+        task.setTaskRescheduling(/*reschedule*/ false, /*backoff*/ false);
+        task.signalTaskFinished();
+        task.waitForTaskFinished();
+        assertFalse(task.needsReschedule());
+
+        assertEquals(5, mScheduler.addCount());
+        assertEquals(5, mScheduler.removeCount());
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java
similarity index 87%
rename from chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskTest.java
rename to chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java
index 14523810..3c84028 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java
@@ -40,13 +40,14 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.concurrent.TimeUnit;
 
 /** Unit tests for {@link PrefetchBackgroundTask}. */
 @RunWith(LocalRobolectricTestRunner.class)
 @Config(manifest = Config.NONE,
-        shadows = {PrefetchBackgroundTaskTest.ShadowBackgroundTaskScheduler.class,
+        shadows = {PrefetchBackgroundTaskUnitTest.ShadowBackgroundTaskScheduler.class,
                 ShadowMultiDex.class})
-public class PrefetchBackgroundTaskTest {
+public class PrefetchBackgroundTaskUnitTest {
     /**
      * Shadow of BackgroundTaskScheduler system service.
      */
@@ -103,10 +104,14 @@
 
     @Test
     public void scheduleTask() {
-        PrefetchBackgroundTask.scheduleTask();
+        final int additionalDelaySeconds = 15;
+        PrefetchBackgroundTask.scheduleTask(additionalDelaySeconds);
         TaskInfo scheduledTask =
                 mShadowTaskScheduler.getTaskInfo(TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID);
         assertNotNull(scheduledTask);
+        assertEquals(TimeUnit.SECONDS.toMillis(PrefetchBackgroundTask.DEFAULT_START_DELAY_SECONDS
+                             + additionalDelaySeconds),
+                scheduledTask.getOneOffInfo().getWindowStartTimeMs());
         assertEquals(true, scheduledTask.isPersisted());
         assertEquals(TaskInfo.NETWORK_TYPE_UNMETERED, scheduledTask.getRequiredNetworkType());
     }
@@ -117,9 +122,11 @@
                 mShadowTaskScheduler.getTaskInfo(TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID);
         assertNull(scheduledTask);
 
-        PrefetchBackgroundTask.scheduleTask();
+        PrefetchBackgroundTask.scheduleTask(0);
         scheduledTask = mShadowTaskScheduler.getTaskInfo(TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID);
         assertNotNull(scheduledTask);
+        assertEquals(TimeUnit.SECONDS.toMillis(PrefetchBackgroundTask.DEFAULT_START_DELAY_SECONDS),
+                scheduledTask.getOneOffInfo().getWindowStartTimeMs());
 
         PrefetchBackgroundTask.cancelTask();
         scheduledTask = mShadowTaskScheduler.getTaskInfo(TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID);
diff --git a/chrome/app/bookmarks_strings.grdp b/chrome/app/bookmarks_strings.grdp
index 22d0be7..528b254 100644
--- a/chrome/app/bookmarks_strings.grdp
+++ b/chrome/app/bookmarks_strings.grdp
@@ -419,6 +419,19 @@
   <message name="IDS_MD_BOOKMARK_MANAGER_TITLE" desc="Title of the bookmark manager window.">
     Bookmarks
   </message>
+  <message name="IDS_MD_BOOKMARK_MANAGER_TOAST_FOLDER_SORTED" desc="Label displayed in toast popup message when a folder's children are sorted.">
+    Folder sorted
+  </message>
+  <message name="IDS_MD_BOOKMARK_MANAGER_TOAST_ITEM_DELETED" desc="Label displayed in toast popup message when an item is deleted.">
+    '<ph name="DELETED_ITEM_NAME">$1</ph>' has been deleted
+  </message>
+  <message name="IDS_MD_BOOKMARK_MANAGER_TOAST_ITEMS_DELETED" desc="Label displayed in toast popup message when several items are deleted.">
+    {COUNT, plural,
+      other {# bookmarks deleted}}
+  </message>
+  <message name="IDS_MD_BOOKMARK_MANAGER_TOAST_URL_COPIED" desc="Label displayed in toast popup message when a URL is copied.">
+    URL copied
+  </message>
   <!-- End of material design Bookmarks Manager strings. -->
 
   <!-- Begin of Bookmarks Menu (in the Main Menu) strings. -->
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index b304bf8..a2b2b26 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -1218,7 +1218,7 @@
           Chromium needs permission to access your camera and microphone for this site.
         </message>
         <message name="IDS_INFOBAR_MISSING_LOCATION_PERMISSION_TEXT" desc="Text shown in an infobar when a website has requested access to the location capabilities, but Chrome is missing the Android location permission.">
-          Chromium needs access to to your location to share your location with this site.
+          Chromium needs access to your location to share your location with this site.
         </message>
         <message name="IDS_MISSING_STORAGE_PERMISSION_DOWNLOAD_EDUCATION_TEXT" desc="Text shown educating the user that Chrome is missing the Android storage permission, which is required to download files.">
           Chromium needs storage access to download files.
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 94382382..49acb1b 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -12160,6 +12160,12 @@
       <message name="IDS_VR_SHELL_NEW_INCOGNITO_TAB_BUTTON" desc="Text on the VR scene new incognito tab button">
         New Incognito Tab
       </message>
+      <message name="IDS_VR_SHELL_EXIT_PROMPT_DESCRIPTION" desc="Text on the exit prompt that shows up when the user clicks on URL bar security icon in VR">
+        Site information is not available in VR
+      </message>
+      <message name="IDS_VR_SHELL_EXIT_PROMPT_EXIT_VR_BUTTON" desc="Text on the exit button of the exit prompt that shows up when the user clicks on URL bar security icon in VR">
+        EXIT VR
+      </message>
     </if>
 
     <!-- Safe Browsing Subresource Filter UI strings. -->
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index ed18a2a..b3c93a2 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -1228,7 +1228,7 @@
           Chrome needs permission to access your camera and microphone for this site.
         </message>
         <message name="IDS_INFOBAR_MISSING_LOCATION_PERMISSION_TEXT" desc="Text shown in an infobar when a website has requested access to the location capabilities, but Chrome is missing the Android location permission.">
-          Chrome needs access to to your location to share your location with this site.
+          Chrome needs access to your location to share your location with this site.
         </message>
         <message name="IDS_MISSING_STORAGE_PERMISSION_DOWNLOAD_EDUCATION_TEXT" desc="Text shown educating the user that Chrome is missing the Android storage permission, which is required to download files.">
           Chrome needs storage access to download files.
diff --git a/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.cc b/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.cc
index 6e28422..6fe9189 100644
--- a/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.cc
+++ b/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.cc
@@ -4,18 +4,34 @@
 
 #include "chrome/browser/android/offline_pages/prefetch/prefetch_background_task.h"
 
+#include "base/time/time.h"
 #include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_android.h"
+#include "chrome/common/pref_names.h"
 #include "components/offline_pages/core/prefetch/prefetch_service.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
 #include "jni/PrefetchBackgroundTask_jni.h"
+#include "net/base/backoff_entry_serializer.h"
 
 using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace offline_pages {
+
+const net::BackoffEntry::Policy kBackoffPolicy = {
+    0,                 // Number of initial errors to ignore without backoff.
+    30 * 1000,         // Initial delay for backoff in ms: 30 seconds.
+    2,                 // Factor to multiply for exponential backoff.
+    0.33,              // Fuzzing percentage.
+    24 * 3600 * 1000,  // Maximum time to delay requests in ms: 1 day.
+    -1,                // Don't discard entry even if unused.
+    false              // Don't use initial delay unless the last was an error.
+};
+
 namespace prefetch {
 
 // JNI call to start request processing in scheduled mode.
@@ -31,16 +47,22 @@
     return false;
 
   prefetch_service->GetPrefetchDispatcher()->BeginBackgroundTask(
-      base::MakeUnique<PrefetchBackgroundTask>(env, jcaller, prefetch_service));
-  return true;
+      base::MakeUnique<PrefetchBackgroundTask>(env, jcaller, prefetch_service,
+                                               profile));
+  return false;  // true;
 }
 
 }  // namespace prefetch
 
+void RegisterPrefetchBackgroundTaskPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterListPref(prefs::kOfflinePrefetchBackoff);
+}
+
 // static
-void PrefetchBackgroundTask::Schedule() {
+void PrefetchBackgroundTask::Schedule(int additional_delay_seconds) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  return prefetch::Java_PrefetchBackgroundTask_scheduleTask(env);
+  return prefetch::Java_PrefetchBackgroundTask_scheduleTask(
+      env, additional_delay_seconds);
 }
 
 // static
@@ -52,29 +74,80 @@
 PrefetchBackgroundTask::PrefetchBackgroundTask(
     JNIEnv* env,
     const JavaParamRef<jobject>& java_prefetch_background_task,
-    PrefetchService* service)
+    PrefetchService* service,
+    Profile* profile)
     : java_prefetch_background_task_(java_prefetch_background_task),
-      service_(service) {
+      service_(service),
+      profile_(profile) {
   // Give the Java side a pointer to the new background task object.
   prefetch::Java_PrefetchBackgroundTask_setNativeTask(
       env, java_prefetch_background_task_, reinterpret_cast<jlong>(this));
+
+  SetupBackOff();
 }
 
 PrefetchBackgroundTask::~PrefetchBackgroundTask() {
   JNIEnv* env = base::android::AttachCurrentThread();
   prefetch::Java_PrefetchBackgroundTask_doneProcessing(
       env, java_prefetch_background_task_.obj(), needs_reschedule_);
+
+  if (needs_reschedule_) {
+    // If the task is killed due to the system, it should be rescheduled without
+    // backoff even when it is in effect because we want to rerun the task asap.
+    Schedule(task_killed_by_system_ ? 0 : GetAdditionalBackoffSeconds());
+  }
+}
+
+void PrefetchBackgroundTask::SetupBackOff() {
+  const base::ListValue* value =
+      profile_->GetPrefs()->GetList(prefs::kOfflinePrefetchBackoff);
+  if (value) {
+    backoff_ = net::BackoffEntrySerializer::DeserializeFromValue(
+        *value, &kBackoffPolicy, nullptr, base::Time::Now());
+  }
+
+  if (!backoff_)
+    backoff_ = base::MakeUnique<net::BackoffEntry>(&kBackoffPolicy);
 }
 
 bool PrefetchBackgroundTask::OnStopTask(JNIEnv* env,
                                         const JavaParamRef<jobject>& jcaller) {
-  DCHECK(jcaller.obj() == java_prefetch_background_task_.obj());
-  service_->GetPrefetchDispatcher()->StopBackgroundTask(this);
-  return needs_reschedule_;
+  task_killed_by_system_ = true;
+  needs_reschedule_ = true;
+  service_->GetPrefetchDispatcher()->StopBackgroundTask();
+  return false;
 }
 
-void PrefetchBackgroundTask::SetNeedsReschedule(bool reschedule) {
+void PrefetchBackgroundTask::SetTaskReschedulingForTesting(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jcaller,
+    jboolean reschedule,
+    jboolean backoff) {
+  SetNeedsReschedule(static_cast<bool>(reschedule), static_cast<bool>(backoff));
+}
+
+void PrefetchBackgroundTask::SignalTaskFinishedForTesting(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jcaller) {
+  service_->GetPrefetchDispatcher()->RequestFinishBackgroundTaskForTest();
+}
+
+void PrefetchBackgroundTask::SetNeedsReschedule(bool reschedule, bool backoff) {
   needs_reschedule_ = reschedule;
+
+  if (reschedule && backoff)
+    backoff_->InformOfRequest(false);
+  else
+    backoff_->Reset();
+
+  std::unique_ptr<base::Value> value =
+      net::BackoffEntrySerializer::SerializeToValue(*backoff_,
+                                                    base::Time::Now());
+  profile_->GetPrefs()->Set(prefs::kOfflinePrefetchBackoff, *value);
+}
+
+int PrefetchBackgroundTask::GetAdditionalBackoffSeconds() const {
+  return static_cast<int>(backoff_->GetTimeUntilRelease().InSeconds());
 }
 
 bool RegisterPrefetchBackgroundTask(JNIEnv* env) {
diff --git a/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.h b/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.h
index b1b74cd..06e4978 100644
--- a/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.h
+++ b/chrome/browser/android/offline_pages/prefetch/prefetch_background_task.h
@@ -7,6 +7,11 @@
 
 #include "base/android/jni_android.h"
 #include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
+#include "components/offline_pages/core/prefetch/prefetch_service.h"
+#include "net/base/backoff_entry.h"
+
+class PrefRegistrySimple;
+class Profile;
 
 namespace offline_pages {
 class PrefetchService;
@@ -19,12 +24,13 @@
   PrefetchBackgroundTask(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& j_prefetch_background_task,
-      PrefetchService* service);
+      PrefetchService* service,
+      Profile* profile);
   ~PrefetchBackgroundTask() override;
 
   // API for interacting with BackgroundTaskScheduler from native.
   // Schedules the default 'NWake' prefetching task.
-  static void Schedule();
+  static void Schedule(int additional_delay_seconds);
 
   // Cancels the default 'NWake' prefetching task.
   static void Cancel();
@@ -32,24 +38,42 @@
   // Java hooks.
   bool OnStopTask(JNIEnv* env,
                   const base::android::JavaParamRef<jobject>& jcaller);
+  void SetTaskReschedulingForTesting(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jcaller,
+      jboolean reschedule,
+      jboolean backoff);
+  void SignalTaskFinishedForTesting(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jcaller);
 
   // When this task completes, we tell the system whether the task should be
-  // rescheduled with the same parameters as last time.
-  void SetNeedsReschedule(bool reschedule) override;
+  // rescheduled with or without backoff.
+  void SetNeedsReschedule(bool reschedule, bool backoff) override;
   bool needs_reschedule() { return needs_reschedule_; }
 
  private:
-  bool needs_reschedule_ = true;
+  void SetupBackOff();
+  int GetAdditionalBackoffSeconds() const;
+
+  bool task_killed_by_system_ = false;
+  bool needs_reschedule_ = false;
 
   // A pointer to the controlling |PrefetchBackgroundTask|.
   base::android::ScopedJavaGlobalRef<jobject> java_prefetch_background_task_;
 
   // The PrefetchService owns |this|, so a raw pointer is OK.
   PrefetchService* service_;
+
+  Profile* profile_;
+
+  std::unique_ptr<net::BackoffEntry> backoff_;
 };
 
 bool RegisterPrefetchBackgroundTask(JNIEnv* env);
 
+void RegisterPrefetchBackgroundTaskPrefs(PrefRegistrySimple* registry);
+
 }  // namespace offline_pages
 
 #endif  // CHROME_BROWSER_ANDROID_OFFLINE_PAGES_PREFETCH_PREFETCH_BACKGROUND_TASK_H_
diff --git a/chrome/browser/android/vr_shell/BUILD.gn b/chrome/browser/android/vr_shell/BUILD.gn
index 4dedfb9..c886e77a 100644
--- a/chrome/browser/android/vr_shell/BUILD.gn
+++ b/chrome/browser/android/vr_shell/BUILD.gn
@@ -33,6 +33,8 @@
       "textures/button_texture.h",
       "textures/close_button_texture.cc",
       "textures/close_button_texture.h",
+      "textures/exit_prompt_texture.cc",
+      "textures/exit_prompt_texture.h",
       "textures/exit_warning_texture.cc",
       "textures/exit_warning_texture.h",
       "textures/insecure_content_permanent_texture.cc",
@@ -54,6 +56,8 @@
       "ui_elements/audio_capture_indicator.h",
       "ui_elements/button.cc",
       "ui_elements/button.h",
+      "ui_elements/exit_prompt.cc",
+      "ui_elements/exit_prompt.h",
       "ui_elements/exit_warning.cc",
       "ui_elements/exit_warning.h",
       "ui_elements/loading_indicator.cc",
@@ -198,6 +202,7 @@
     "test/paths.h",
     "textures/close_button_texture_unittest.cc",
     "textures/url_bar_texture_unittest.cc",
+    "ui_elements/exit_prompt_unittest.cc",
     "ui_elements/ui_element_unittest.cc",
     "ui_scene_manager_unittest.cc",
     "ui_scene_unittest.cc",
@@ -211,6 +216,7 @@
     "//skia",
     "//testing/gmock",
     "//testing/gtest",
+    "//ui/gfx:test_support",
     "//ui/gfx/geometry",
     "//ui/gl",
   ]
diff --git a/chrome/browser/android/vr_shell/color_scheme.cc b/chrome/browser/android/vr_shell/color_scheme.cc
index 56ec5db3..9478a7c 100644
--- a/chrome/browser/android/vr_shell/color_scheme.cc
+++ b/chrome/browser/android/vr_shell/color_scheme.cc
@@ -47,6 +47,13 @@
   normal_scheme.system_indicator_foreground =
       normal_scheme.permanent_warning_foreground;
   normal_scheme.separator = 0xFF9E9E9E;
+  normal_scheme.prompt_foreground = 0xCC000000;
+  normal_scheme.prompt_primary_button_background = 0xBFFFFFFF;
+  normal_scheme.prompt_secondary_button_background = 0x66FFFFFF;
+  normal_scheme.prompt_primary_button_forground = 0xA6000000;
+  normal_scheme.prompt_secondary_button_foreground = 0xA6000000;
+  normal_scheme.prompt_button_background_down = 0xE6FFFFFF;
+  normal_scheme.prompt_button_background_hover = 0xFFFFFFFF;
   normal_scheme.secure = gfx::kGoogleGreen700;
   normal_scheme.insecure = gfx::kGoogleRed700;
   normal_scheme.warning = 0xFF5A5A5A;
@@ -85,6 +92,13 @@
   incognito_scheme.warning = incognito_scheme.secure;
   incognito_scheme.url_emphasized = incognito_scheme.secure;
   incognito_scheme.url_deemphasized = 0xFF878787;
+  incognito_scheme.prompt_foreground = 0xCCFFFFFF;
+  incognito_scheme.prompt_primary_button_background = 0xD9FFFFFF;
+  incognito_scheme.prompt_secondary_button_background = 0x80FFFFFF;
+  incognito_scheme.prompt_primary_button_forground = 0xD9000000;
+  incognito_scheme.prompt_secondary_button_foreground = 0xD9000000;
+  incognito_scheme.prompt_button_background_hover = 0xFF8C8C8C;
+  incognito_scheme.prompt_button_background_down = 0xE6FFFFFF;
   incognito_scheme.disabled = 0x33E6E6E6;
 
   initialized = true;
diff --git a/chrome/browser/android/vr_shell/color_scheme.h b/chrome/browser/android/vr_shell/color_scheme.h
index 8457c81..1db6df5 100644
--- a/chrome/browser/android/vr_shell/color_scheme.h
+++ b/chrome/browser/android/vr_shell/color_scheme.h
@@ -50,6 +50,15 @@
   SkColor system_indicator_background;
   SkColor system_indicator_foreground;
 
+  // The colors used for text and buttons on prompts.
+  SkColor prompt_foreground;
+  SkColor prompt_primary_button_background;
+  SkColor prompt_secondary_button_background;
+  SkColor prompt_primary_button_forground;
+  SkColor prompt_secondary_button_foreground;
+  SkColor prompt_button_background_hover;
+  SkColor prompt_button_background_down;
+
   // If you have a segmented element, its separators should use this color.
   SkColor separator;
 
diff --git a/chrome/browser/android/vr_shell/textures/exit_prompt_texture.cc b/chrome/browser/android/vr_shell/textures/exit_prompt_texture.cc
new file mode 100644
index 0000000..52d59558
--- /dev/null
+++ b/chrome/browser/android/vr_shell/textures/exit_prompt_texture.cc
@@ -0,0 +1,174 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/vr_shell/textures/exit_prompt_texture.h"
+
+#include "cc/paint/skia_paint_canvas.h"
+#include "chrome/browser/android/vr_shell/color_scheme.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/render_text.h"
+
+namespace vr_shell {
+
+namespace {
+
+constexpr float kWidth = 0.672;
+constexpr float kHeight = 0.2;
+constexpr float kButtonWidth = 0.162;
+constexpr float kButtonHeight = 0.066;
+constexpr float kPromptTextButtonSeperatorHeight = 0.04;
+constexpr float kButtonsSeperatorWidth = 0.01;
+constexpr float kButtonRadiusFactor = 0.006;
+constexpr float kFontSizePromptText = 0.027;
+constexpr float kFontSizePromptButtonText = 0.024;
+
+}  // namespace
+
+ExitPromptTexture::ExitPromptTexture() = default;
+
+ExitPromptTexture::~ExitPromptTexture() = default;
+
+void ExitPromptTexture::Draw(SkCanvas* sk_canvas,
+                             const gfx::Size& texture_size) {
+  size_.set_width(texture_size.width());
+  size_.set_height(texture_size.height());
+
+  cc::SkiaPaintCanvas paint_canvas(sk_canvas);
+  gfx::Canvas gfx_canvas(&paint_canvas, 1.0f);
+  gfx::Canvas* canvas = &gfx_canvas;
+
+  // Prompt text area.
+  auto text = l10n_util::GetStringUTF16(IDS_VR_SHELL_EXIT_PROMPT_DESCRIPTION);
+  gfx::FontList fonts;
+  GetFontList(ToPixels(kFontSizePromptText), text, &fonts);
+  gfx::Rect prompt_text_size(size_.width(), 0);
+  std::vector<std::unique_ptr<gfx::RenderText>> lines = PrepareDrawStringRect(
+      text, fonts, color_scheme().prompt_foreground, &prompt_text_size,
+      kTextAlignmentCenter, kWrappingBehaviorWrap);
+  for (auto& render_text : lines)
+    render_text->Draw(canvas);
+
+  SkPaint paint;
+  gfx::Rect button_text_size(ToPixels(kButtonWidth), 0);
+  float radius = size_.width() * kButtonRadiusFactor;
+  GetFontList(ToPixels(kFontSizePromptButtonText), text, &fonts);
+
+  // Secondary button area.
+  text = l10n_util::GetStringUTF16(IDS_VR_SHELL_EXIT_PROMPT_EXIT_VR_BUTTON);
+  lines = PrepareDrawStringRect(
+      text, fonts, color_scheme().prompt_secondary_button_foreground,
+      &button_text_size, kTextAlignmentCenter, kWrappingBehaviorWrap);
+  secondary_button_rect_.SetRect(
+      ToPixels(kWidth / 2 - kButtonsSeperatorWidth - kButtonWidth),
+      prompt_text_size.height() + ToPixels(kPromptTextButtonSeperatorHeight),
+      ToPixels(kButtonWidth), ToPixels(kButtonHeight));
+  paint.setColor(GetSecondaryButtonColor());
+  canvas->Save();
+  canvas->Translate(
+      gfx::Vector2d(secondary_button_rect_.x(), secondary_button_rect_.y()));
+  sk_canvas->drawRoundRect(
+      SkRect::MakeXYWH(0, 0, ToPixels(kButtonWidth), ToPixels(kButtonHeight)),
+      radius, radius, paint);
+  canvas->Translate(gfx::Vector2d(
+      0, ToPixels(kButtonHeight) / 2 - button_text_size.height() / 2));
+  for (auto& render_text : lines)
+    render_text->Draw(canvas);
+  canvas->Restore();
+
+  // Primary button area.
+  text = l10n_util::GetStringUTF16(IDS_OK);
+  button_text_size.set_size(gfx::Size(ToPixels(kButtonWidth), 0));
+  lines = PrepareDrawStringRect(
+      text, fonts, color_scheme().prompt_primary_button_forground,
+      &button_text_size, kTextAlignmentCenter, kWrappingBehaviorWrap);
+  primary_button_rect_.SetRect(
+      ToPixels(kWidth / 2 + kButtonsSeperatorWidth),
+      prompt_text_size.height() + ToPixels(kPromptTextButtonSeperatorHeight),
+      ToPixels(kButtonWidth), ToPixels(kButtonHeight));
+  paint.setColor(GetPrimaryButtonColor());
+  canvas->Save();
+  canvas->Translate(
+      gfx::Vector2d(primary_button_rect_.x(), primary_button_rect_.y()));
+  sk_canvas->drawRoundRect(
+      SkRect::MakeXYWH(0, 0, ToPixels(kButtonWidth), ToPixels(kButtonHeight)),
+      radius, radius, paint);
+  canvas->Translate(gfx::Vector2d(
+      0, ToPixels(kButtonHeight) / 2 - button_text_size.height() / 2));
+  for (auto& render_text : lines)
+    render_text->Draw(canvas);
+  canvas->Restore();
+}
+
+float ExitPromptTexture::ToPixels(float meters) const {
+  return meters * size_.width() / kWidth;
+}
+
+gfx::PointF ExitPromptTexture::PercentToPixels(
+    const gfx::PointF& percent) const {
+  return gfx::PointF(percent.x() * size_.width(), percent.y() * size_.height());
+}
+
+SkColor ExitPromptTexture::GetPrimaryButtonColor() const {
+  if (primary_pressed_)
+    return color_scheme().prompt_button_background_down;
+  if (primary_hovered_)
+    return color_scheme().prompt_button_background_hover;
+  return color_scheme().prompt_primary_button_background;
+}
+
+SkColor ExitPromptTexture::GetSecondaryButtonColor() const {
+  if (secondary_pressed_)
+    return color_scheme().prompt_button_background_down;
+  if (secondary_hovered_)
+    return color_scheme().prompt_button_background_hover;
+  return color_scheme().prompt_secondary_button_background;
+}
+
+bool ExitPromptTexture::HitsPrimaryButton(const gfx::PointF& position) const {
+  return primary_button_rect_.Contains(PercentToPixels(position));
+}
+
+bool ExitPromptTexture::HitsSecondaryButton(const gfx::PointF& position) const {
+  return secondary_button_rect_.Contains(PercentToPixels(position));
+}
+
+void ExitPromptTexture::SetPrimaryButtonHovered(bool hovered) {
+  if (primary_hovered_ != hovered)
+    set_dirty();
+  primary_hovered_ = hovered;
+}
+
+void ExitPromptTexture::SetPrimaryButtonPressed(bool pressed) {
+  if (primary_pressed_ != pressed)
+    set_dirty();
+  primary_pressed_ = pressed;
+}
+
+void ExitPromptTexture::SetSecondaryButtonHovered(bool hovered) {
+  if (secondary_hovered_ != hovered)
+    set_dirty();
+  secondary_hovered_ = hovered;
+}
+
+void ExitPromptTexture::SetSecondaryButtonPressed(bool pressed) {
+  if (secondary_pressed_ != pressed)
+    set_dirty();
+  secondary_pressed_ = pressed;
+}
+
+gfx::Size ExitPromptTexture::GetPreferredTextureSize(int maximum_width) const {
+  return gfx::Size(maximum_width, maximum_width * kHeight / kWidth);
+}
+
+gfx::SizeF ExitPromptTexture::GetDrawnSize() const {
+  return size_;
+}
+
+}  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/textures/exit_prompt_texture.h b/chrome/browser/android/vr_shell/textures/exit_prompt_texture.h
new file mode 100644
index 0000000..8a64040
--- /dev/null
+++ b/chrome/browser/android/vr_shell/textures/exit_prompt_texture.h
@@ -0,0 +1,55 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_EXIT_PROMPT_TEXTURE_H_
+#define CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_EXIT_PROMPT_TEXTURE_H_
+
+#include "base/macros.h"
+#include "chrome/browser/android/vr_shell/textures/ui_texture.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace gfx {
+class PointF;
+}  // namespace gfx
+
+namespace vr_shell {
+
+class ExitPromptTexture : public UiTexture {
+ public:
+  ExitPromptTexture();
+  ~ExitPromptTexture() override;
+  gfx::Size GetPreferredTextureSize(int width) const override;
+  gfx::SizeF GetDrawnSize() const override;
+
+  void SetPrimaryButtonHovered(bool hovered);
+  void SetPrimaryButtonPressed(bool pressed);
+  void SetSecondaryButtonHovered(bool hovered);
+  void SetSecondaryButtonPressed(bool pressed);
+
+  virtual bool HitsSecondaryButton(const gfx::PointF& position) const;
+  virtual bool HitsPrimaryButton(const gfx::PointF& position) const;
+
+ private:
+  void Draw(SkCanvas* sk_canvas, const gfx::Size& texture_size) override;
+
+  SkColor GetPrimaryButtonColor() const;
+  SkColor GetSecondaryButtonColor() const;
+  float ToPixels(float meters) const;
+  gfx::PointF PercentToPixels(const gfx::PointF& percent) const;
+
+  gfx::RectF secondary_button_rect_;
+  gfx::RectF primary_button_rect_;
+  gfx::SizeF size_;
+
+  bool primary_hovered_ = false;
+  bool primary_pressed_ = false;
+  bool secondary_hovered_ = false;
+  bool secondary_pressed_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(ExitPromptTexture);
+};
+
+}  // namespace vr_shell
+
+#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_TEXTURES_EXIT_PROMPT_TEXTURE_H_
diff --git a/chrome/browser/android/vr_shell/textures/url_bar_texture.cc b/chrome/browser/android/vr_shell/textures/url_bar_texture.cc
index 91a06654..698f4a7ef 100644
--- a/chrome/browser/android/vr_shell/textures/url_bar_texture.cc
+++ b/chrome/browser/android/vr_shell/textures/url_bar_texture.cc
@@ -142,6 +142,19 @@
   return rect.Contains(meters) && !HitsTransparentRegion(meters, false);
 }
 
+gfx::PointF UrlBarTexture::SecurityIconPositionMeters() const {
+  float x = kBackButtonWidth + kSeparatorWidth + kSecurityFieldWidth / 2 -
+            kSecurityIconHeight / 2;
+  float y = kHeight / 2 - kSecurityIconHeight / 2;
+  return gfx::PointF(x, y);
+}
+
+bool UrlBarTexture::HitsSecurityIcon(const gfx::PointF& position) const {
+  gfx::RectF rect(SecurityIconPositionMeters(),
+                  gfx::SizeF(kSecurityIconHeight, kSecurityIconHeight));
+  return rect.Contains(percentToMeters(position));
+}
+
 bool UrlBarTexture::HitsTransparentRegion(const gfx::PointF& meters,
                                           bool left) const {
   const float radius = kHeight / 2.0f;
@@ -222,10 +235,8 @@
   // Site security state icon.
   if (!gurl_.is_empty()) {
     canvas->save();
-    canvas->translate(
-        kBackButtonWidth + kSeparatorWidth + kSecurityFieldWidth / 2,
-        kHeight / 2);
-    canvas->translate(-kSecurityIconHeight / 2, -kSecurityIconHeight / 2);
+    gfx::PointF icon_position = SecurityIconPositionMeters();
+    canvas->translate(icon_position.x(), icon_position.y());
     const gfx::VectorIcon& icon = getSecurityIcon(security_level_);
     icon_default_height = GetDefaultSizeOfVectorIcon(icon);
     icon_scale = kSecurityIconHeight / icon_default_height;
diff --git a/chrome/browser/android/vr_shell/textures/url_bar_texture.h b/chrome/browser/android/vr_shell/textures/url_bar_texture.h
index a077e733..e4e6626 100644
--- a/chrome/browser/android/vr_shell/textures/url_bar_texture.h
+++ b/chrome/browser/android/vr_shell/textures/url_bar_texture.h
@@ -44,6 +44,7 @@
 
   bool HitsBackButton(const gfx::PointF& position) const;
   bool HitsUrlBar(const gfx::PointF& position) const;
+  bool HitsSecurityIcon(const gfx::PointF& position) const;
 
   void SetHovered(bool hovered);
   void SetPressed(bool pressed);
@@ -61,6 +62,7 @@
   bool HitsTransparentRegion(const gfx::PointF& meters, bool left) const;
   void RenderUrl(const gfx::Size& texture_size, const gfx::Rect& bounds);
   void OnSetMode() override;
+  gfx::PointF SecurityIconPositionMeters() const;
 
   gfx::SizeF size_;
   bool hovered_ = false;
diff --git a/chrome/browser/android/vr_shell/ui_elements/exit_prompt.cc b/chrome/browser/android/vr_shell/ui_elements/exit_prompt.cc
new file mode 100644
index 0000000..909fd59
--- /dev/null
+++ b/chrome/browser/android/vr_shell/ui_elements/exit_prompt.cc
@@ -0,0 +1,75 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/vr_shell/ui_elements/exit_prompt.h"
+
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/android/vr_shell/textures/exit_prompt_texture.h"
+
+namespace vr_shell {
+
+ExitPrompt::ExitPrompt(int preferred_width,
+                       const base::Callback<void()>& primary_button_callback,
+                       const base::Callback<void()>& secondary_buttton_callback)
+    : TexturedElement(preferred_width),
+      texture_(base::MakeUnique<ExitPromptTexture>()),
+      primary_button_callback_(primary_button_callback),
+      secondary_buttton_callback_(secondary_buttton_callback) {}
+
+ExitPrompt::~ExitPrompt() = default;
+
+void ExitPrompt::SetTextureForTesting(ExitPromptTexture* texture) {
+  texture_.reset(texture);
+}
+
+void ExitPrompt::OnHoverEnter(const gfx::PointF& position) {
+  OnStateUpdated(position);
+}
+
+void ExitPrompt::OnHoverLeave() {
+  OnStateUpdated(gfx::PointF(std::numeric_limits<float>::max(),
+                             std::numeric_limits<float>::max()));
+}
+
+void ExitPrompt::OnMove(const gfx::PointF& position) {
+  OnStateUpdated(position);
+}
+
+void ExitPrompt::OnButtonDown(const gfx::PointF& position) {
+  if (texture_->HitsPrimaryButton(position))
+    primary_down_ = true;
+  else if (texture_->HitsSecondaryButton(position))
+    secondary_down_ = true;
+  OnStateUpdated(position);
+}
+
+void ExitPrompt::OnButtonUp(const gfx::PointF& position) {
+  if (primary_down_ && texture_->HitsPrimaryButton(position))
+    primary_button_callback_.Run();
+  else if (secondary_down_ && texture_->HitsSecondaryButton(position))
+    secondary_buttton_callback_.Run();
+
+  primary_down_ = false;
+  secondary_down_ = false;
+
+  OnStateUpdated(position);
+}
+
+void ExitPrompt::OnStateUpdated(const gfx::PointF& position) {
+  const bool primary_hovered = texture_->HitsPrimaryButton(position);
+  const bool secondary_hovered = texture_->HitsSecondaryButton(position);
+
+  texture_->SetPrimaryButtonHovered(primary_hovered);
+  texture_->SetPrimaryButtonPressed(primary_hovered ? primary_down_ : false);
+  texture_->SetSecondaryButtonHovered(secondary_hovered);
+  texture_->SetSecondaryButtonPressed(secondary_hovered ? secondary_down_
+                                                        : false);
+  UpdateTexture();
+}
+
+UiTexture* ExitPrompt::GetTexture() const {
+  return texture_.get();
+}
+
+}  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/exit_prompt.h b/chrome/browser/android/vr_shell/ui_elements/exit_prompt.h
new file mode 100644
index 0000000..51d44da7
--- /dev/null
+++ b/chrome/browser/android/vr_shell/ui_elements/exit_prompt.h
@@ -0,0 +1,51 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_EXIT_PROMPT_H_
+#define CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_EXIT_PROMPT_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "chrome/browser/android/vr_shell/ui_elements/textured_element.h"
+
+namespace vr_shell {
+
+class ExitPromptTexture;
+
+class ExitPrompt : public TexturedElement {
+ public:
+  ExitPrompt(int preferred_width,
+             const base::Callback<void()>& primary_button_callback,
+             const base::Callback<void()>& secondary_buttton_callback);
+  ~ExitPrompt() override;
+
+  void SetTextureForTesting(ExitPromptTexture* texture);
+
+  void OnHoverEnter(const gfx::PointF& position) override;
+  void OnHoverLeave() override;
+  void OnMove(const gfx::PointF& position) override;
+  void OnButtonDown(const gfx::PointF& position) override;
+  void OnButtonUp(const gfx::PointF& position) override;
+
+ private:
+  UiTexture* GetTexture() const override;
+
+  void OnStateUpdated(const gfx::PointF& position);
+
+  bool primary_down_ = false;
+  bool secondary_down_ = false;
+
+  std::unique_ptr<ExitPromptTexture> texture_;
+
+  base::Callback<void()> primary_button_callback_;
+  base::Callback<void()> secondary_buttton_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExitPrompt);
+};
+
+}  // namespace vr_shell
+
+#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENTS_EXIT_PROMPT_H_
diff --git a/chrome/browser/android/vr_shell/ui_elements/exit_prompt_unittest.cc b/chrome/browser/android/vr_shell/ui_elements/exit_prompt_unittest.cc
new file mode 100644
index 0000000..8d651168
--- /dev/null
+++ b/chrome/browser/android/vr_shell/ui_elements/exit_prompt_unittest.cc
@@ -0,0 +1,102 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/vr_shell/ui_elements/exit_prompt.h"
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/android/vr_shell/textures/exit_prompt_texture.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/test/gfx_util.h"
+
+using ::testing::Return;
+
+namespace vr_shell {
+
+namespace {
+
+class MockExitPromptTexture : public ExitPromptTexture {
+ public:
+  MockExitPromptTexture() : ExitPromptTexture() {}
+  ~MockExitPromptTexture() override {}
+
+  MOCK_CONST_METHOD1(HitsPrimaryButton, bool(const gfx::PointF&));
+  MOCK_CONST_METHOD1(HitsSecondaryButton, bool(const gfx::PointF&));
+
+  MOCK_CONST_METHOD1(GetPreferredTextureSize, gfx::Size(int));
+  MOCK_CONST_METHOD0(GetDrawnSize, gfx::SizeF());
+  MOCK_METHOD2(Draw, void(SkCanvas*, const gfx::Size&));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockExitPromptTexture);
+};
+
+}  // namespace
+
+class TestExitPrompt : public ExitPrompt {
+ public:
+  TestExitPrompt();
+  ~TestExitPrompt() override {}
+
+  bool primary_button_pressed() const { return primary_button_pressed_; }
+  bool secondary_button_pressed() const { return secondary_button_pressed_; }
+
+ private:
+  void OnPrimaryButtonPressed() { primary_button_pressed_ = true; }
+  void OnSecondaryButtonPressed() { secondary_button_pressed_ = true; }
+
+  bool primary_button_pressed_ = false;
+  bool secondary_button_pressed_ = false;
+};
+
+TestExitPrompt::TestExitPrompt()
+    : ExitPrompt(512,
+                 base::Bind(&TestExitPrompt::OnPrimaryButtonPressed,
+                            base::Unretained(this)),
+                 base::Bind(&TestExitPrompt::OnSecondaryButtonPressed,
+                            base::Unretained(this))) {}
+
+TEST(ExitPromptTest, PrimaryButtonCallbackCalled) {
+  TestExitPrompt prompt;
+  MockExitPromptTexture* texture = new MockExitPromptTexture();
+  // Called twice from OnButtonDown and twice from OnButtonUp.
+  EXPECT_CALL(*texture, HitsPrimaryButton(gfx::PointF()))
+      .Times(4)
+      .WillRepeatedly(Return(true));
+  // Called once from OnButtonDown and once from OnButtonUp (via OnStatUpdated).
+  EXPECT_CALL(*texture, HitsSecondaryButton(gfx::PointF()))
+      .Times(2)
+      .WillRepeatedly(Return(false));
+  prompt.SetTextureForTesting(std::move(texture));
+
+  prompt.OnButtonDown(gfx::PointF());
+  prompt.OnButtonUp(gfx::PointF());
+
+  EXPECT_TRUE(prompt.primary_button_pressed());
+  EXPECT_FALSE(prompt.secondary_button_pressed());
+}
+
+TEST(ExitPromptTest, SecondaryButtonCallbackCalled) {
+  TestExitPrompt prompt;
+  MockExitPromptTexture* texture = new MockExitPromptTexture();
+  // Called twice from OnButtonDown and once from OnButtonUp.
+  EXPECT_CALL(*texture, HitsPrimaryButton(gfx::PointF()))
+      .Times(3)
+      .WillRepeatedly(Return(false));
+  // Called twice from OnButtonDown and twice from OnButtonUp.
+  EXPECT_CALL(*texture, HitsSecondaryButton(gfx::PointF()))
+      .Times(4)
+      .WillRepeatedly(Return(true));
+  prompt.SetTextureForTesting(std::move(texture));
+
+  prompt.OnButtonDown(gfx::PointF());
+  prompt.OnButtonUp(gfx::PointF());
+
+  EXPECT_FALSE(prompt.primary_button_pressed());
+  EXPECT_TRUE(prompt.secondary_button_pressed());
+}
+
+}  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/ui_element_debug_id.h b/chrome/browser/android/vr_shell/ui_elements/ui_element_debug_id.h
index d32d8280..e43db65 100644
--- a/chrome/browser/android/vr_shell/ui_elements/ui_element_debug_id.h
+++ b/chrome/browser/android/vr_shell/ui_elements/ui_element_debug_id.h
@@ -25,6 +25,7 @@
   kCloseButton,
   kScreenDimmer,
   kExitWarning,
+  kExitPrompt,
 };
 
 }  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_elements/url_bar.cc b/chrome/browser/android/vr_shell/ui_elements/url_bar.cc
index 34ab3538..87fe7867 100644
--- a/chrome/browser/android/vr_shell/ui_elements/url_bar.cc
+++ b/chrome/browser/android/vr_shell/ui_elements/url_bar.cc
@@ -20,9 +20,13 @@
 }  // namespace
 
 UrlBar::UrlBar(int preferred_width,
+               const base::Callback<void()>& back_button_callback,
+               const base::Callback<void()>& security_icon_callback,
                const base::Callback<void(UiUnsupportedMode)>& failure_callback)
     : TexturedElement(preferred_width),
-      texture_(base::MakeUnique<UrlBarTexture>(failure_callback)) {}
+      texture_(base::MakeUnique<UrlBarTexture>(failure_callback)),
+      back_button_callback_(back_button_callback),
+      security_icon_callback_(security_icon_callback) {}
 
 UrlBar::~UrlBar() = default;
 
@@ -51,6 +55,8 @@
 void UrlBar::OnButtonDown(const gfx::PointF& position) {
   if (texture_->HitsBackButton(position))
     down_ = true;
+  else if (texture_->HitsSecurityIcon(position))
+    security_icon_down_ = true;
   OnStateUpdated(position);
 }
 
@@ -59,6 +65,9 @@
   OnStateUpdated(position);
   if (can_go_back_ && texture_->HitsBackButton(position))
     back_button_callback_.Run();
+  else if (security_icon_down_ && texture_->HitsSecurityIcon(position))
+    security_icon_callback_.Run();
+  security_icon_down_ = false;
 }
 
 bool UrlBar::HitTest(const gfx::PointF& position) const {
@@ -92,10 +101,6 @@
   texture_->SetSecurityLevel(level);
 }
 
-void UrlBar::SetBackButtonCallback(const base::Callback<void()>& callback) {
-  back_button_callback_ = callback;
-}
-
 void UrlBar::OnStateUpdated(const gfx::PointF& position) {
   const bool hovered = texture_->HitsBackButton(position);
   const bool pressed = hovered ? down_ : false;
diff --git a/chrome/browser/android/vr_shell/ui_elements/url_bar.h b/chrome/browser/android/vr_shell/ui_elements/url_bar.h
index 5c28acb8..77ee9784 100644
--- a/chrome/browser/android/vr_shell/ui_elements/url_bar.h
+++ b/chrome/browser/android/vr_shell/ui_elements/url_bar.h
@@ -22,6 +22,8 @@
 class UrlBar : public TexturedElement {
  public:
   UrlBar(int preferred_width,
+         const base::Callback<void()>& back_button_callback,
+         const base::Callback<void()>& security_icon_callback,
          const base::Callback<void(UiUnsupportedMode)>& failure_callback);
   ~UrlBar() override;
 
@@ -38,7 +40,6 @@
   void SetHistoryButtonsEnabled(bool can_go_back);
   void SetURL(const GURL& gurl);
   void SetSecurityLevel(security_state::SecurityLevel level);
-  void SetBackButtonCallback(const base::Callback<void()>& callback);
 
  private:
   void UpdateTexture() override;
@@ -47,9 +48,11 @@
 
   std::unique_ptr<UrlBarTexture> texture_;
   base::Callback<void()> back_button_callback_;
+  base::Callback<void()> security_icon_callback_;
   bool enabled_ = false;
   bool can_go_back_ = false;
   bool down_ = false;
+  bool security_icon_down_ = false;
   base::TimeTicks last_begin_frame_time_;
   base::TimeTicks last_update_time_;
 
diff --git a/chrome/browser/android/vr_shell/ui_scene.cc b/chrome/browser/android/vr_shell/ui_scene.cc
index 40ce66c4..f3caf40 100644
--- a/chrome/browser/android/vr_shell/ui_scene.cc
+++ b/chrome/browser/android/vr_shell/ui_scene.cc
@@ -212,6 +212,10 @@
   is_exiting_ = true;
 }
 
+void UiScene::set_is_prompting_to_exit(bool prompting) {
+  is_prompting_to_exit_ = prompting;
+}
+
 const std::vector<std::unique_ptr<UiElement>>& UiScene::GetUiElements() const {
   return ui_elements_;
 }
diff --git a/chrome/browser/android/vr_shell/ui_scene.h b/chrome/browser/android/vr_shell/ui_scene.h
index 3b6f508..df949d2c 100644
--- a/chrome/browser/android/vr_shell/ui_scene.h
+++ b/chrome/browser/android/vr_shell/ui_scene.h
@@ -80,6 +80,8 @@
 
   bool is_exiting() const { return is_exiting_; }
   void set_is_exiting();
+  bool is_prompting_to_exit() { return is_prompting_to_exit_; }
+  void set_is_prompting_to_exit(bool prompting);
 
   void OnGLInitialized();
 
@@ -95,6 +97,7 @@
   bool webvr_rendering_enabled_ = true;
   bool gl_initialized_ = false;
   bool is_exiting_ = false;
+  bool is_prompting_to_exit_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(UiScene);
 };
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.cc b/chrome/browser/android/vr_shell/ui_scene_manager.cc
index 619a61f29..f3f9026b 100644
--- a/chrome/browser/android/vr_shell/ui_scene_manager.cc
+++ b/chrome/browser/android/vr_shell/ui_scene_manager.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/android/vr_shell/ui_browser_interface.h"
 #include "chrome/browser/android/vr_shell/ui_elements/audio_capture_indicator.h"
 #include "chrome/browser/android/vr_shell/ui_elements/button.h"
+#include "chrome/browser/android/vr_shell/ui_elements/exit_prompt.h"
 #include "chrome/browser/android/vr_shell/ui_elements/exit_warning.h"
 #include "chrome/browser/android/vr_shell/ui_elements/loading_indicator.h"
 #include "chrome/browser/android/vr_shell/ui_elements/permanent_security_warning.h"
@@ -51,6 +52,10 @@
 static constexpr float kFullscreenWidth = 1.138 * kFullscreenDistance;
 static constexpr float kFullscreenVerticalOffset = -0.1 * kFullscreenDistance;
 
+static constexpr float kExitPromptWidth = 0.672 * kContentDistance;
+static constexpr float kExitPromptHeight = 0.2 * kContentDistance;
+static constexpr float kExitPromptVerticalOffset = -0.09 * kContentDistance;
+
 static constexpr float kUrlBarDistance = 2.4;
 static constexpr float kUrlBarWidth = 0.672 * kUrlBarDistance;
 static constexpr float kUrlBarHeight = 0.088 * kUrlBarDistance;
@@ -224,9 +229,26 @@
   element->set_size({kBackplaneSize, kBackplaneSize, 1.0});
   element->set_translation({0.0, 0.0, -kTextureOffset});
   element->set_parent_id(main_content_->id());
+  main_content_backplane_ = element.get();
   content_elements_.push_back(element.get());
   scene_->AddUiElement(std::move(element));
 
+  element = base::MakeUnique<ExitPrompt>(
+      512,
+      base::Bind(&UiSceneManager::OnExitPromptPrimaryButtonClicked,
+                 base::Unretained(this)),
+      base::Bind(&UiSceneManager::OnExitPromptSecondaryButtonClicked,
+                 base::Unretained(this)));
+  element->set_debug_id(kExitPrompt);
+  element->set_id(AllocateId());
+  element->set_fill(vr_shell::Fill::NONE);
+  element->set_size({kExitPromptWidth, kExitPromptHeight, 1});
+  element->set_translation({0.0, kExitPromptVerticalOffset, kTextureOffset});
+  element->set_parent_id(main_content_->id());
+  element->set_visible(false);
+  exit_prompt_ = element.get();
+  scene_->AddUiElement(std::move(element));
+
   // Limit reticle distance to a sphere based on content distance.
   scene_->SetBackgroundDistance(main_content_->translation().z() *
                                 -kBackgroundDistanceMultiplier);
@@ -246,7 +268,7 @@
   element->set_draw_phase(0);
   element->set_gridline_count(kFloorGridlineCount);
   floor_ = element.get();
-  content_elements_.push_back(element.get());
+  background_elements_.push_back(element.get());
   scene_->AddUiElement(std::move(element));
 
   // Ceiling.
@@ -259,7 +281,7 @@
   element->set_fill(vr_shell::Fill::OPAQUE_GRADIENT);
   element->set_draw_phase(0);
   ceiling_ = element.get();
-  content_elements_.push_back(element.get());
+  background_elements_.push_back(element.get());
   scene_->AddUiElement(std::move(element));
 
   UpdateBackgroundColor();
@@ -269,14 +291,15 @@
   // TODO(cjgrant): Incorporate final size and position.
   auto url_bar = base::MakeUnique<UrlBar>(
       512,
+      base::Bind(&UiSceneManager::OnBackButtonClicked, base::Unretained(this)),
+      base::Bind(&UiSceneManager::OnSecurityIconClicked,
+                 base::Unretained(this)),
       base::Bind(&UiSceneManager::OnUnsupportedMode, base::Unretained(this)));
   url_bar->set_debug_id(kUrlBar);
   url_bar->set_id(AllocateId());
   url_bar->set_translation({0, kUrlBarVerticalOffset, -kUrlBarDistance});
   url_bar->set_rotation({1.0, 0.0, 0.0, kUrlBarRotationRad});
   url_bar->set_size({kUrlBarWidth, kUrlBarHeight, 1});
-  url_bar->SetBackButtonCallback(
-      base::Bind(&UiSceneManager::OnBackButtonClicked, base::Unretained(this)));
   url_bar_ = url_bar.get();
   control_elements_.push_back(url_bar.get());
   scene_->AddUiElement(std::move(url_bar));
@@ -326,12 +349,13 @@
 
 void UiSceneManager::ConfigureScene() {
   exit_warning_->SetEnabled(scene_->is_exiting());
+  exit_prompt_->SetEnabled(scene_->is_prompting_to_exit());
   screen_dimmer_->SetEnabled(scene_->is_exiting());
 
   // Controls (URL bar, loading progress, etc).
   bool controls_visible = !web_vr_mode_ && !fullscreen_;
   for (UiElement* element : control_elements_) {
-    element->SetEnabled(controls_visible);
+    element->SetEnabled(controls_visible && !scene_->is_prompting_to_exit());
   }
 
   // Close button is a special control element that needs to be hidden when in
@@ -339,7 +363,10 @@
   close_button_->SetEnabled(!web_vr_mode_ && (fullscreen_ || in_cct_));
 
   // Content elements.
-  for (UiElement* element : content_elements_) {
+  main_content_->SetEnabled(!web_vr_mode_ && !scene_->is_prompting_to_exit());
+  main_content_backplane_->SetEnabled(!web_vr_mode_);
+  // Background elements.
+  for (UiElement* element : background_elements_) {
     element->SetEnabled(!web_vr_mode_);
   }
 
@@ -448,6 +475,24 @@
   browser_->NavigateBack();
 }
 
+void UiSceneManager::OnSecurityIconClicked() {
+  if (scene_->is_prompting_to_exit())
+    return;
+  scene_->set_is_prompting_to_exit(true);
+  ConfigureScene();
+}
+
+void UiSceneManager::OnExitPromptPrimaryButtonClicked() {
+  if (!scene_->is_prompting_to_exit())
+    return;
+  scene_->set_is_prompting_to_exit(false);
+  ConfigureScene();
+}
+
+void UiSceneManager::OnExitPromptSecondaryButtonClicked() {
+  OnUnsupportedMode(UiUnsupportedMode::kUnhandledPageInfo);
+}
+
 void UiSceneManager::SetURL(const GURL& gurl) {
   url_bar_->SetURL(gurl);
 }
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.h b/chrome/browser/android/vr_shell/ui_scene_manager.h
index f6abe57..c870835b 100644
--- a/chrome/browser/android/vr_shell/ui_scene_manager.h
+++ b/chrome/browser/android/vr_shell/ui_scene_manager.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_ANDROID_VR_SHELL_UI_SCENE_MANAGER_H_
 #define CHROME_BROWSER_ANDROID_VR_SHELL_UI_SCENE_MANAGER_H_
 
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
@@ -52,6 +53,8 @@
   void OnAppButtonGesturePerformed(UiInterface::Direction direction);
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(UiSceneManagerTest, UiUpdatesExitPrompt);
+
   void CreateScreenDimmer();
   void CreateSecurityWarnings();
   void CreateSystemIndicators();
@@ -59,13 +62,15 @@
   void CreateBackground();
   void CreateUrlBar();
   void CreateCloseButton();
-  void CreateExitWarning();
 
   void ConfigureScene();
   void ConfigureSecurityWarnings();
   void UpdateBackgroundColor();
   void OnSecurityWarningTimer();
   void OnBackButtonClicked();
+  void OnSecurityIconClicked();
+  void OnExitPromptPrimaryButtonClicked();
+  void OnExitPromptSecondaryButtonClicked();
   void OnCloseButtonClicked();
   void OnUnsupportedMode(UiUnsupportedMode mode);
   int AllocateId();
@@ -78,8 +83,10 @@
   // UI element pointers (not owned by the scene manager).
   UiElement* permanent_security_warning_ = nullptr;
   UiElement* transient_security_warning_ = nullptr;
+  UiElement* exit_prompt_ = nullptr;
   UiElement* exit_warning_ = nullptr;
   UiElement* main_content_ = nullptr;
+  UiElement* main_content_backplane_ = nullptr;
   UiElement* audio_capture_indicator_ = nullptr;
   UiElement* video_capture_indicator_ = nullptr;
   UiElement* screen_capture_indicator_ = nullptr;
@@ -95,7 +102,6 @@
   bool secure_origin_ = false;
   bool fullscreen_ = false;
   bool incognito_ = false;
-  bool is_exiting_ = false;
   bool audio_capturing_ = false;
   bool video_capturing_ = false;
   bool screen_capturing_ = false;
@@ -103,6 +109,7 @@
   int next_available_id_ = 1;
 
   std::vector<UiElement*> content_elements_;
+  std::vector<UiElement*> background_elements_;
   std::vector<UiElement*> control_elements_;
 
   base::OneShotTimer security_warning_timer_;
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc b/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc
index f5745451..5744214 100644
--- a/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc
+++ b/chrome/browser/android/vr_shell/ui_scene_manager_unittest.cc
@@ -14,8 +14,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using testing::InSequence;
-
 namespace vr_shell {
 
 namespace {
@@ -35,6 +33,9 @@
   DISALLOW_COPY_AND_ASSIGN(MockBrowserInterface);
 };
 
+std::set<UiElementDebugId> kElementsVisibleInBrowsing = {
+    kContentQuad, kBackplane, kCeiling, kFloor, kUrlBar, kLoadingIndicator};
+
 }  // namespace
 
 class UiSceneManagerTest : public testing::Test {
@@ -195,14 +196,8 @@
 }
 
 TEST_F(UiSceneManagerTest, UiUpdatesForFullscreenChanges) {
-  std::set<UiElementDebugId> visible_in_browsing = {
-      UiElementDebugId::kContentQuad, UiElementDebugId::kBackplane,
-      UiElementDebugId::kCeiling,     UiElementDebugId::kFloor,
-      UiElementDebugId::kUrlBar,      UiElementDebugId::kLoadingIndicator};
   std::set<UiElementDebugId> visible_in_fullscreen = {
-      UiElementDebugId::kContentQuad, UiElementDebugId::kCloseButton,
-      UiElementDebugId::kBackplane, UiElementDebugId::kCeiling,
-      UiElementDebugId::kFloor};
+      kContentQuad, kCloseButton, kBackplane, kCeiling, kFloor};
 
   MakeManager(kNotInCct, kNotInWebVr);
 
@@ -211,8 +206,9 @@
 
   for (const auto& element : scene_->GetUiElements()) {
     SCOPED_TRACE(element->debug_id());
-    bool should_be_visible = visible_in_browsing.find(element->debug_id()) !=
-                             visible_in_browsing.end();
+    bool should_be_visible =
+        kElementsVisibleInBrowsing.find(element->debug_id()) !=
+        kElementsVisibleInBrowsing.end();
     EXPECT_EQ(should_be_visible, element->visible());
   }
 
@@ -239,8 +235,9 @@
   // Everything should return to original state after leaving fullscreen.
   for (const auto& element : scene_->GetUiElements()) {
     SCOPED_TRACE(element->debug_id());
-    bool should_be_visible = visible_in_browsing.find(element->debug_id()) !=
-                             visible_in_browsing.end();
+    bool should_be_visible =
+        kElementsVisibleInBrowsing.find(element->debug_id()) !=
+        kElementsVisibleInBrowsing.end();
     EXPECT_EQ(should_be_visible, element->visible());
   }
   {
@@ -249,6 +246,42 @@
   }
 }
 
+TEST_F(UiSceneManagerTest, UiUpdatesExitPrompt) {
+  std::set<UiElementDebugId> visible_when_prompting = {kExitPrompt, kBackplane,
+                                                       kCeiling, kFloor};
+  MakeManager(kNotInCct, kNotInWebVr);
+
+  manager_->SetWebVrSecureOrigin(true);
+
+  // Initial state.
+  for (const auto& element : scene_->GetUiElements()) {
+    SCOPED_TRACE(element->debug_id());
+    bool should_be_visible =
+        kElementsVisibleInBrowsing.find(element->debug_id()) !=
+        kElementsVisibleInBrowsing.end();
+    EXPECT_EQ(should_be_visible, element->visible());
+  }
+
+  // Exit prompt visible state.
+  manager_->OnSecurityIconClicked();
+  for (const auto& element : scene_->GetUiElements()) {
+    SCOPED_TRACE(element->debug_id());
+    bool should_be_visible = visible_when_prompting.find(element->debug_id()) !=
+                             visible_when_prompting.end();
+    EXPECT_EQ(should_be_visible, element->visible());
+  }
+
+  // Back to initial state.
+  manager_->OnExitPromptPrimaryButtonClicked();
+  for (const auto& element : scene_->GetUiElements()) {
+    SCOPED_TRACE(element->debug_id());
+    bool should_be_visible =
+        kElementsVisibleInBrowsing.find(element->debug_id()) !=
+        kElementsVisibleInBrowsing.end();
+    EXPECT_EQ(should_be_visible, element->visible());
+  }
+}
+
 TEST_F(UiSceneManagerTest, UiUpdatesForWebVR) {
   MakeManager(kNotInCct, kInWebVr);
 
diff --git a/chrome/browser/android/vr_shell/ui_unsupported_mode.h b/chrome/browser/android/vr_shell/ui_unsupported_mode.h
index 4811b0b..731af52 100644
--- a/chrome/browser/android/vr_shell/ui_unsupported_mode.h
+++ b/chrome/browser/android/vr_shell/ui_unsupported_mode.h
@@ -13,6 +13,7 @@
 enum class UiUnsupportedMode : int {
   kUnhandledCodePoint = 0,
   kCouldNotElideURL,
+  kUnhandledPageInfo,
 
   // This must be last.
   kCount,
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc
index 1e154e2..9fce75e 100644
--- a/chrome/browser/android/vr_shell/vr_shell.cc
+++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -585,6 +585,13 @@
 }
 
 void VrShell::ExitVrDueToUnsupportedMode(UiUnsupportedMode mode) {
+  if (mode == UiUnsupportedMode::kUnhandledPageInfo) {
+    UMA_HISTOGRAM_ENUMERATION("VR.Shell.EncounteredUnsupportedMode", mode,
+                              UiUnsupportedMode::kCount);
+    JNIEnv* env = base::android::AttachCurrentThread();
+    Java_VrShellImpl_onUnhandledPageInfo(env, j_vr_shell_.obj());
+    return;
+  }
   ui_->SetIsExiting();
   main_thread_task_runner_->PostDelayedTask(
       FROM_HERE,
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 9a708c27..3601b81 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -12,7 +12,6 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_dialogs.h"
@@ -23,10 +22,6 @@
 #include "content/public/common/content_features.h"
 #include "extensions/features/features.h"
 
-#if defined(OS_ANDROID)
-#include "chrome/browser/android/chrome_feature_list.h"
-#endif
-
 bool FixupBrowserAboutURL(GURL* url,
                           content::BrowserContext* browser_context) {
   // Ensure that any cleanup done by FixupURL happens before the rewriting
@@ -54,6 +49,14 @@
   std::string host(url->host());
   std::string path;
 
+  // Handle chrome://settings.
+  if (host == chrome::kChromeUISettingsHost)
+    return true;  // Prevent further rewriting - this is a valid URL.
+
+  // Do not handle chrome://help.
+  if (host == chrome::kChromeUIHelpHost)
+    return false;  // Handled in the HandleWebUI handler.
+
   // Replace about with chrome-urls.
   if (host == chrome::kChromeUIAboutHost)
     host = chrome::kChromeUIChromeURLsHost;
@@ -90,12 +93,6 @@
   } else if (host == chrome::kChromeUIHistoryHost) {
     // Redirect chrome://history.
     path = url->path();
-  } else if (host == chrome::kChromeUISettingsHost) {
-    // Redirect chrome://settings.
-    return true;  // Prevent further rewriting - this is a valid URL.
-  } else if (host == chrome::kChromeUIHelpHost) {
-    // Redirect chrome://help, unless MD settings is enabled.
-    return false;  // Handled in the HandleWebUI handler.
   }
 
   GURL::Replacements replacements;
@@ -117,7 +114,8 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(&chrome::AttemptRestart));
     return true;
-  } else if (base::LowerCaseEqualsASCII(spec, chrome::kChromeUIQuitURL)) {
+  }
+  if (base::LowerCaseEqualsASCII(spec, chrome::kChromeUIQuitURL)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(&chrome::AttemptExit));
     return true;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index a96cff4..3c449b8c 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -294,6 +294,8 @@
             <include name="IDR_MD_BOOKMARKS_STORE_CLIENT_JS" file="resources\md_bookmarks\store_client.js" type="BINDATA" />
             <include name="IDR_MD_BOOKMARKS_STORE_HTML" file="resources\md_bookmarks\store.html" type="BINDATA" />
             <include name="IDR_MD_BOOKMARKS_STORE_JS" file="resources\md_bookmarks\store.js" type="BINDATA" />
+            <include name="IDR_MD_BOOKMARKS_TOAST_MANAGER_HTML" file="resources\md_bookmarks\toast_manager.html" type="BINDATA" />
+            <include name="IDR_MD_BOOKMARKS_TOAST_MANAGER_JS" file="resources\md_bookmarks\toast_manager.js" type="BINDATA" />
             <include name="IDR_MD_BOOKMARKS_TOOLBAR_HTML" file="resources\md_bookmarks\toolbar.html" type="BINDATA" />
             <include name="IDR_MD_BOOKMARKS_TOOLBAR_JS" file="resources\md_bookmarks\toolbar.js" type="BINDATA" />
             <include name="IDR_MD_BOOKMARKS_UTIL_HTML" file="resources\md_bookmarks\util.html" type="BINDATA" />
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 8156041e..dea9827c 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1792,7 +1792,6 @@
     "../ui/webui/chromeos/login/l10n_util_unittest.cc",
     "../ui/webui/chromeos/login/oobe_display_chooser_unittest.cc",
     "../ui/webui/chromeos/login/signin_userlist_unittest.cc",
-    "../ui/webui/options/chromeos/cros_language_options_handler_unittest.cc",
     "../ui/webui/settings/chromeos/easy_unlock_settings_handler_unittest.cc",
     "//components/drive/change_list_loader_unittest.cc",
     "//components/drive/change_list_processor_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/tracing/DEPS b/chrome/browser/chromeos/arc/tracing/DEPS
deleted file mode 100644
index e94e96a..0000000
--- a/chrome/browser/chromeos/arc/tracing/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+content/browser/tracing/arc_tracing_agent.h"
-]
diff --git a/chrome/browser/chromeos/arc/tracing/arc_tracing_bridge.h b/chrome/browser/chromeos/arc/tracing/arc_tracing_bridge.h
index b9a18e8..0c301c37 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_bridge.h
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_bridge.h
@@ -15,7 +15,7 @@
 #include "components/arc/arc_service.h"
 #include "components/arc/common/tracing.mojom.h"
 #include "components/arc/instance_holder.h"
-#include "content/browser/tracing/arc_tracing_agent.h"
+#include "content/public/browser/arc_tracing_agent.h"
 
 namespace arc {
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index d481adf..3ae29ff 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -86,6 +86,7 @@
 #include "components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h"
 #include "components/ntp_snippets/user_classifier.h"
 #include "components/ntp_tiles/most_visited_sites.h"
+#include "components/offline_pages/features/features.h"
 #include "components/omnibox/browser/zero_suggest_provider.h"
 #include "components/password_manager/core/browser/password_bubble_experiment.h"
 #include "components/password_manager/core/browser/password_manager.h"
@@ -143,6 +144,10 @@
 #include "extensions/browser/extension_prefs.h"
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+#include "chrome/browser/android/offline_pages/prefetch/prefetch_background_task.h"
+#endif
+
 #if BUILDFLAG(ENABLE_PLUGINS)
 #include "chrome/browser/plugins/plugins_resource_service.h"
 #endif
@@ -678,6 +683,10 @@
 #endif
 
   registry->RegisterDictionaryPref(kDistroDict);
+
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+  offline_pages::RegisterPrefetchBackgroundTaskPrefs(registry);
+#endif
 }
 
 void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index b4fb9ad7..16864c45 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -116,16 +116,6 @@
     output_dir = "$root_gen_dir/chrome"
   }
 
-  grit("options_test_resources") {
-    source = "options_test_resources.grd"
-    defines = chrome_grit_defines
-    outputs = [
-      "grit/options_test_resources.h",
-      "options_test_resources.pak",
-    ]
-    output_dir = "$root_gen_dir/chrome"
-  }
-
   grit("settings_resources") {
     if (use_vulcanize) {
       source = "settings/settings_resources_vulcanized.grd"
diff --git a/chrome/browser/resources/md_bookmarks/app.html b/chrome/browser/resources/md_bookmarks/app.html
index ce4aae3..9cc1c358 100644
--- a/chrome/browser/resources/md_bookmarks/app.html
+++ b/chrome/browser/resources/md_bookmarks/app.html
@@ -9,6 +9,7 @@
 <link rel="import" href="chrome://bookmarks/router.html">
 <link rel="import" href="chrome://bookmarks/shared_vars.html">
 <link rel="import" href="chrome://bookmarks/store.html">
+<link rel="import" href="chrome://bookmarks/toast_manager.html">
 <link rel="import" href="chrome://bookmarks/toolbar.html">
 <link rel="import" href="chrome://bookmarks/folder_node.html">
 <link rel="import" href="chrome://bookmarks/util.html">
@@ -76,6 +77,7 @@
     </div>
     <bookmarks-router></bookmarks-router>
     <bookmarks-command-manager></bookmarks-command-manager>
+    <bookmarks-toast-manager duration="5000"></bookmarks-toast-manager>
   </template>
   <script src="chrome://bookmarks/app.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/md_bookmarks/command_manager.js b/chrome/browser/resources/md_bookmarks/command_manager.js
index be258a32..8960d0a 100644
--- a/chrome/browser/resources/md_bookmarks/command_manager.js
+++ b/chrome/browser/resources/md_bookmarks/command_manager.js
@@ -44,6 +44,12 @@
       this.boundOnOpenItemMenu_ = this.onOpenItemMenu_.bind(this);
       document.addEventListener('open-item-menu', this.boundOnOpenItemMenu_);
 
+      /** @private {function()} */
+      this.boundOnCommandUndo_ = function() {
+        this.handle(Command.UNDO, new Set());
+      }.bind(this);
+      document.addEventListener('command-undo', this.boundOnCommandUndo_);
+
       /** @private {function(!Event)} */
       this.boundOnKeydown_ = this.onKeydown_.bind(this);
       document.addEventListener('keydown', this.boundOnKeydown_);
@@ -66,6 +72,7 @@
     detached: function() {
       CommandManager.instance_ = null;
       document.removeEventListener('open-item-menu', this.boundOnOpenItemMenu_);
+      document.removeEventListener('command-undo', this.boundOnCommandUndo_);
       document.removeEventListener('keydown', this.boundOnKeydown_);
     },
 
@@ -179,17 +186,31 @@
         case Command.COPY:
           var idList = Array.from(itemIds);
           chrome.bookmarkManagerPrivate.copy(idList, function() {
-            // TODO(jiaxi): Add toast later.
+            bookmarks.ToastManager.getInstance().show(
+                loadTimeData.getString('toastUrlCopied'), false);
           });
           break;
         case Command.DELETE:
-          chrome.bookmarkManagerPrivate.removeTrees(
-              Array.from(this.minimizeDeletionSet_(itemIds)), function() {
-                // TODO(jiaxi): Add toast later.
-              });
+          var idList = Array.from(this.minimizeDeletionSet_(itemIds));
+          var labelPromise;
+          if (idList.length == 1) {
+            // TODO(calamity): fold this separate label into
+            // 'toastItemsDeleted'.
+            labelPromise = Promise.resolve(loadTimeData.getStringF(
+                'toastItemDeleted', this.getState().nodes[idList[0]].title));
+          } else {
+            labelPromise = cr.sendWithPromise(
+                'getPluralString', 'toastItemsDeleted', idList.length);
+          }
+          chrome.bookmarkManagerPrivate.removeTrees(idList, function() {
+            labelPromise.then(function(label) {
+              bookmarks.ToastManager.getInstance().show(label, true);
+            });
+          }.bind(this));
           break;
         case Command.UNDO:
           chrome.bookmarkManagerPrivate.undo();
+          bookmarks.ToastManager.getInstance().hide();
           break;
         case Command.REDO:
           chrome.bookmarkManagerPrivate.redo();
diff --git a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
index f88af25..a1200ea 100644
--- a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
+++ b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
@@ -47,6 +47,7 @@
         '<(EXTERNS_GYP):bookmark_manager_private',
         'edit_dialog',
         'store_client',
+        'toast_manager'
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
@@ -146,6 +147,15 @@
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
     },
     {
+      'target_name': 'toast_manager',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-button/compiled_resources2.gyp:paper-button-extracted',
+      ],
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
       'target_name': 'toolbar',
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu',
diff --git a/chrome/browser/resources/md_bookmarks/list.js b/chrome/browser/resources/md_bookmarks/list.js
index cb0bdb9..0505d47 100644
--- a/chrome/browser/resources/md_bookmarks/list.js
+++ b/chrome/browser/resources/md_bookmarks/list.js
@@ -32,7 +32,16 @@
     },
 
     /** @private */
-    searchTerm_: String,
+    searchTerm_: {
+      type: String,
+      observer: 'onDisplayedListSourceChange_',
+    },
+
+    /** @private */
+    selectedFolder_: {
+      type: String,
+      observer: 'onDisplayedListSourceChange_',
+    },
   },
 
   listeners: {
@@ -49,6 +58,9 @@
     this.watch('searchTerm_', function(state) {
       return state.search.term;
     });
+    this.watch('selectedFolder_', function(state) {
+      return state.selectedFolder;
+    });
     this.updateFromStore();
 
     this.$.bookmarksCard.addEventListener(
@@ -91,6 +103,11 @@
   },
 
   /** @private */
+  onDisplayedListSourceChange_: function() {
+    this.scrollTop = 0;
+  },
+
+  /** @private */
   emptyListMessage_: function() {
     var emptyListMessage = this.searchTerm_ ? 'noSearchResults' : 'emptyList';
     return loadTimeData.getString(emptyListMessage);
@@ -130,6 +147,7 @@
     var focusMoved = false;
     var focusedIndex =
         this.getIndexForItemElement_(/** @type {HTMLElement} */ (e.target));
+    var oldFocusedIndex = focusedIndex;
     if (e.key == 'ArrowUp') {
       focusedIndex--;
       focusMoved = true;
@@ -166,6 +184,12 @@
         this.dispatch(
             bookmarks.actions.updateAnchor(this.displayedIds_[focusedIndex]));
       } else {
+        // If shift-selecting with no anchor, use the old focus index.
+        if (e.shiftKey && this.getState().selection.anchor == null) {
+          this.dispatch(bookmarks.actions.updateAnchor(
+              this.displayedIds_[oldFocusedIndex]));
+        }
+
         // If the focus moved from something other than a Ctrl + move event,
         // update the selection.
         var config = {
diff --git a/chrome/browser/resources/md_bookmarks/toast_manager.html b/chrome/browser/resources/md_bookmarks/toast_manager.html
new file mode 100644
index 0000000..bc3a643
--- /dev/null
+++ b/chrome/browser/resources/md_bookmarks/toast_manager.html
@@ -0,0 +1,60 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://bookmarks/shared_style.html">
+
+<dom-module id="bookmarks-toast-manager">
+  <template>
+    <style include="shared-style">
+      #content {
+        flex: 1;
+        margin-right: 32px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+
+      paper-button {
+        color: var(--google-blue-300);
+        font-weight: 500;
+        height: 32px;
+        margin: 0;
+        min-width: 52px;
+        padding: 8px;
+      }
+
+      #toast {
+        align-items: center;
+        background-color: #323232;
+        border-radius: 4px;
+        bottom: 0;
+        box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.28);
+        box-sizing: border-box;
+        color: #fff;
+        display: flex;
+        margin: 24px;
+        max-width: 568px;
+        min-height: 52px;
+        min-width: 288px;
+        opacity: 0;
+        padding: 0 24px;
+        position: fixed;
+        transform: translateY(100px);
+        transition: transform 300ms, opacity 300ms;
+        white-space: nowrap;
+      }
+
+      :host([open_]) #toast {
+        opacity: 1;
+        transform: translateY(0);
+      }
+    </style>
+    <div id="toast" aria-live="polite">
+      <div id="content"></div>
+      <paper-button id="button" hidden$="[[!showUndo_]]" on-tap="onUndoTap_">
+        $i18n{undo}
+      </paper-button>
+    </div>
+  </template>
+  <script src="chrome://bookmarks/toast_manager.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/md_bookmarks/toast_manager.js b/chrome/browser/resources/md_bookmarks/toast_manager.js
new file mode 100644
index 0000000..dabd5885
--- /dev/null
+++ b/chrome/browser/resources/md_bookmarks/toast_manager.js
@@ -0,0 +1,95 @@
+// 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.
+
+/**
+ * @fileoverview Element which shows toasts.
+ */
+cr.define('bookmarks', function() {
+
+  var ToastManager = Polymer({
+    is: 'bookmarks-toast-manager',
+
+    properties: {
+      duration: {
+        type: Number,
+        value: 0,
+      },
+
+      /** @private */
+      open_: {
+        type: Boolean,
+        reflectToAttribute: true,
+      },
+
+      /** @private */
+      showUndo_: Boolean,
+    },
+
+    /** @private {function(number)} */
+    clearTimeout_: window.clearTimeout.bind(window),
+
+    /** @private {function((Function|null|string), number)} */
+    setTimeout_: window.setTimeout.bind(window),
+
+    /** @private {number|null} */
+    hideTimeout_: null,
+
+    /** @override */
+    attached: function() {
+      assert(ToastManager.instance_ == null);
+      ToastManager.instance_ = this;
+    },
+
+    /** @override */
+    detached: function() {
+      ToastManager.instance_ = null;
+    },
+
+    /**
+     * @param {string} label The label to display inside the toast.
+     * @param {boolean} showUndo Whether the undo button should be shown.
+     */
+    show: function(label, showUndo) {
+      this.open_ = true;
+      // TODO(calamity): Support collapsing of long bookmark names in label.
+      this.$.content.textContent = label;
+      this.showUndo_ = showUndo;
+
+      if (!this.duration)
+        return;
+
+      if (this.hideTimeout_ != null) {
+        this.clearTimeout_(this.hideTimeout_);
+        this.hideTimeout_ = null;
+      }
+
+      this.hideTimeout_ = this.setTimeout_(function() {
+        this.open_ = false;
+        this.hideTimeout_ = null;
+      }.bind(this), this.duration);
+    },
+
+    hide: function() {
+      this.open_ = false;
+    },
+
+    /** @private */
+    onUndoTap_: function() {
+      // Will hide the toast.
+      this.fire('command-undo');
+    },
+  });
+
+  /** @private {?bookmarks.ToastManager} */
+  ToastManager.instance_ = null;
+
+  /** @return {!bookmarks.ToastManager} */
+  ToastManager.getInstance = function() {
+    return assert(ToastManager.instance_);
+  };
+
+  return {
+    ToastManager: ToastManager,
+  };
+});
diff --git a/chrome/browser/resources/md_bookmarks/toolbar.js b/chrome/browser/resources/md_bookmarks/toolbar.js
index bc48904..2ec0469 100644
--- a/chrome/browser/resources/md_bookmarks/toolbar.js
+++ b/chrome/browser/resources/md_bookmarks/toolbar.js
@@ -67,6 +67,8 @@
   onSortTap_: function() {
     chrome.bookmarkManagerPrivate.sortChildren(
         assert(this.getState().selectedFolder));
+    bookmarks.ToastManager.getInstance().show(
+        loadTimeData.getString('toastFolderSorted'), true);
     this.closeDropdownMenu_();
   },
 
diff --git a/chrome/browser/resources/options_test_resources.grd b/chrome/browser/resources/options_test_resources.grd
deleted file mode 100644
index a9220f9f..0000000
--- a/chrome/browser/resources/options_test_resources.grd
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
-  <outputs>
-    <output filename="grit/options_test_resources.h" type="rc_header">
-      <emit emit_type='prepend'></emit>
-    </output>
-    <output filename="options_test_resources.pak" type="data_package" />
-  </outputs>
-  <release seq="1">
-    <structures>
-      <structure name="IDR_OPTIONS_DELETABLE_ITEM_LIST"
-                 file="options/deletable_item_list.js"
-                 type="chrome_html" />
-      <structure name="IDR_OPTIONS_INLINE_EDITABLE_LIST"
-                 file="options/inline_editable_list.js"
-                 type="chrome_html" />
-    </structures>
-  </release>
-</grit>
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 55d9c1af..4e0b4d7 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1071,6 +1071,8 @@
       "webui/options/supervised_user_learn_more_handler.h",
       "webui/options/sync_setup_handler.cc",
       "webui/options/sync_setup_handler.h",
+      "webui/plural_string_handler.cc",
+      "webui/plural_string_handler.h",
       "webui/policy_indicator_localized_strings_provider.cc",
       "webui/policy_indicator_localized_strings_provider.h",
       "webui/profile_helper.cc",
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index d01dd7e1..ae556ea 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -304,10 +304,9 @@
   // that it's time to redraw everything.
   virtual void UserChangedTheme() = 0;
 
-  // Shows Page Info using the specified information. |virtual_url|
-  // is the virtual url of the page/frame the info applies to, |ssl| is the SSL
-  // information for that page/frame. If |show_history| is true, a section
-  // showing how many times that URL has been visited is added to the page info.
+  // Shows Page Info using the specified information. |virtual_url| is the
+  // virtual url of the page/frame the info applies to, and |security_info|
+  // contains the security state for that page/frame.
   virtual void ShowPageInfo(
       Profile* profile,
       content::WebContents* web_contents,
diff --git a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
index 76d0fec..442b54f0 100644
--- a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
+++ b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
@@ -10,6 +10,7 @@
 #include "base/strings/string16.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/md_bookmarks/bookmarks_message_handler.h"
+#include "chrome/browser/ui/webui/plural_string_handler.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
@@ -86,6 +87,13 @@
                      IDS_BOOKMARK_MANAGER_SEARCH_BUTTON);
   AddLocalizedString(source, "saveEdit", IDS_SAVE);
   AddLocalizedString(source, "title", IDS_MD_BOOKMARK_MANAGER_TITLE);
+  AddLocalizedString(source, "toastFolderSorted",
+                     IDS_MD_BOOKMARK_MANAGER_TOAST_FOLDER_SORTED);
+  AddLocalizedString(source, "toastItemDeleted",
+                     IDS_MD_BOOKMARK_MANAGER_TOAST_ITEM_DELETED);
+  AddLocalizedString(source, "toastUrlCopied",
+                     IDS_MD_BOOKMARK_MANAGER_TOAST_URL_COPIED);
+  AddLocalizedString(source, "undo", IDS_BOOKMARK_BAR_UNDO);
 
   // Resources.
 #if BUILDFLAG(USE_VULCANIZE)
@@ -134,6 +142,10 @@
   source->AddResourcePath("store_client.html",
                           IDR_MD_BOOKMARKS_STORE_CLIENT_HTML);
   source->AddResourcePath("store_client.js", IDR_MD_BOOKMARKS_STORE_CLIENT_JS);
+  source->AddResourcePath("toast_manager.html",
+                          IDR_MD_BOOKMARKS_TOAST_MANAGER_HTML);
+  source->AddResourcePath("toast_manager.js",
+                          IDR_MD_BOOKMARKS_TOAST_MANAGER_JS);
   source->AddResourcePath("toolbar.html", IDR_MD_BOOKMARKS_TOOLBAR_HTML);
   source->AddResourcePath("toolbar.js", IDR_MD_BOOKMARKS_TOOLBAR_JS);
   source->AddResourcePath("util.html", IDR_MD_BOOKMARKS_UTIL_HTML);
@@ -155,6 +167,11 @@
   content::WebUIDataSource::Add(profile,
                                 CreateMdBookmarksUIHTMLSource(profile));
 
+  auto plural_string_handler = base::MakeUnique<PluralStringHandler>();
+  plural_string_handler->AddLocalizedString(
+      "toastItemsDeleted", IDS_MD_BOOKMARK_MANAGER_TOAST_ITEMS_DELETED);
+  web_ui->AddMessageHandler(std::move(plural_string_handler));
+
   web_ui->AddMessageHandler(base::MakeUnique<BookmarksMessageHandler>());
 }
 
diff --git a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
index 2d7be60d..ae691217 100644
--- a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
+++ b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
@@ -236,7 +236,7 @@
   const base::Value* callback_id;
   CHECK(args->Get(0, &callback_id));
 
-  offline_pages::PrefetchBackgroundTask::Schedule();
+  offline_pages::PrefetchBackgroundTask::Schedule(0);
 
   ResolveJavascriptCallback(*callback_id, base::Value("Scheduled."));
 }
diff --git a/chrome/browser/ui/webui/options/autofill_options_browsertest.js b/chrome/browser/ui/webui/options/autofill_options_browsertest.js
deleted file mode 100644
index 79109af..0000000
--- a/chrome/browser/ui/webui/options/autofill_options_browsertest.js
+++ /dev/null
@@ -1,174 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * Returns the HTML element for the |field|.
- * @param {string} field The field name for the element.
- * @return {HTMLElement} The HTML element.
- */
-function getField(field) {
-  return document.querySelector(
-      '#autofill-edit-address-overlay [field=' + field + ']');
-}
-
-/**
- * Returns the size of the |list|.
- * @param {HTMLElement} list The list to check.
- * @return {number} The size of the list.
- */
-function getListSize(list) {
-  // Remove 1 for placeholder input field.
-  return list.items.length - 1;
-}
-
-/**
- * TestFixture for autofill options WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function AutofillOptionsWebUITest() {}
-
-AutofillOptionsWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Browse to autofill options.
-   * @override
-   */
-  browsePreload: 'chrome://settings-frame/autofill',
-};
-
-// TODO(crbug.com/617066) Flakes on Win.
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_testOpenAutofillOptions ' +
-    'DISABLED_testOpenAutofillOptions');
-GEN('#else');
-GEN('#define MAYBE_testOpenAutofillOptions testOpenAutofillOptions');
-GEN('#endif');
-// Test opening the autofill options has correct location.
-TEST_F('AutofillOptionsWebUITest', 'MAYBE_testOpenAutofillOptions',
-    function() {
-  assertEquals(this.browsePreload, document.location.href);
-});
-
-/**
- * TestFixture for autofill edit address overlay WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function AutofillEditAddressWebUITest() {}
-
-AutofillEditAddressWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /** @override  */
-  browsePreload: 'chrome://settings-frame/autofillEditAddress',
-};
-
-TEST_F('AutofillEditAddressWebUITest', 'testInitialFormLayout', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  var fields = ['country', 'phone', 'email', 'fullName', 'city'];
-  for (field in fields) {
-    assertEquals('', getField(fields[field]).value, 'Field: ' + fields[field]);
-  }
-
-  testDone();
-});
-
-TEST_F('AutofillEditAddressWebUITest', 'testLoadAddress', function() {
-  // http://crbug.com/434502
-  // Accessibility failure was originally (and consistently) seen on Mac OS and
-  // Chromium OS. Disabling for all OSs because of a flake in Windows. There is
-  // a possibility for flake in linux too.
-  this.disableAccessibilityChecks();
-
-  assertEquals(this.browsePreload, document.location.href);
-
-  var testAddress = {
-    guid: 'GUID Value',
-    fullName: 'Full Name 1',
-    companyName: 'Company Name Value',
-    addrLines: 'First Line Value\nSecond Line Value',
-    dependentLocality: 'Dependent Locality Value',
-    city: 'City Value',
-    state: 'State Value',
-    postalCode: 'Postal Code Value',
-    sortingCode: 'Sorting Code Value',
-    country: 'CH',
-    phone: '123',
-    email: 'a@b.c',
-    languageCode: 'de',
-    components: [[
-       {field: 'postalCode', length: 'short'},
-       {field: 'sortingCode', length: 'short'},
-       {field: 'dependentLocality', length: 'short'},
-       {field: 'city', length: 'short'},
-       {field: 'state', length: 'short'},
-       {field: 'addrLines', length: 'long'},
-       {field: 'companyName', length: 'long'},
-       {field: 'country', length: 'long'},
-       {field: 'fullName', length: 'long', placeholder: 'Add name'}
-    ]]
-  };
-  AutofillEditAddressOverlay.loadAddress(testAddress);
-
-  var overlay = AutofillEditAddressOverlay.getInstance();
-  assertEquals(testAddress.guid, overlay.guid_);
-  assertEquals(testAddress.languageCode, overlay.languageCode_);
-
-  var inputs = ['companyName', 'dependentLocality', 'city', 'state',
-                'postalCode', 'sortingCode', 'fullName', 'email', 'phone'];
-  for (var i in inputs) {
-    var field = getField(inputs[i]);
-    assertEquals(testAddress[inputs[i]], field.value);
-    assertTrue(field instanceof HTMLInputElement);
-  }
-
-  var addrLines = getField('addrLines');
-  assertEquals(testAddress.addrLines, addrLines.value);
-  assertTrue(addrLines instanceof HTMLTextAreaElement);
-
-  var country = getField('country');
-  assertEquals(testAddress.country, country.value);
-  assertTrue(country instanceof HTMLSelectElement);
-});
-
-TEST_F('AutofillEditAddressWebUITest', 'testLoadAddressComponents', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  var testInput = {
-    languageCode: 'fr',
-    components: [[{field: 'city'}],
-                 [{field: 'state'}]]
-  };
-  AutofillEditAddressOverlay.loadAddressComponents(testInput);
-
-  assertEquals('fr', AutofillEditAddressOverlay.getInstance().languageCode_);
-  expectEquals(2, $('autofill-edit-address-fields').children.length);
-});
-
-TEST_F('AutofillEditAddressWebUITest', 'testFieldValuesSaved', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  AutofillEditAddressOverlay.loadAddressComponents({
-    languageCode: 'en',
-    components: [[{field: 'city'}]]
-  });
-  getField('city').value = 'New York';
-
-  AutofillEditAddressOverlay.loadAddressComponents({
-    languageCode: 'en',
-    components: [[{field: 'state'}]]
-  });
-  assertEquals(null, getField('city'));
-
-  AutofillEditAddressOverlay.loadAddressComponents({
-    languageCode: 'en',
-    components: [[{field: 'city'}]]
-  });
-  assertEquals('New York', getField('city').value);
-});
diff --git a/chrome/browser/ui/webui/options/autofill_options_handler_unittest.cc b/chrome/browser/ui/webui/options/autofill_options_handler_unittest.cc
deleted file mode 100644
index a00cc4c..0000000
--- a/chrome/browser/ui/webui/options/autofill_options_handler_unittest.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/options/autofill_options_handler.h"
-
-#include "base/values.h"
-#include "components/autofill/core/browser/autofill_profile.h"
-#include "components/autofill/core/browser/autofill_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace options {
-
-TEST(AutofillOptionsHandlerTest, AddressToDictionary) {
-  autofill::AutofillProfile profile;
-  autofill::test::SetProfileInfoWithGuid(&profile,
-                                         "guid",
-                                         "First",
-                                         "Middle",
-                                         "Last",
-                                         "fml@example.com",
-                                         "Acme inc",
-                                         "123 Main",
-                                         "Apt 2",
-                                         "Laredo",
-                                         "TX",
-                                         "77300",
-                                         "US",
-                                         "832-555-1000");
-
-  base::DictionaryValue dictionary;
-  options::AutofillOptionsHandler::AutofillProfileToDictionary(profile,
-                                                               &dictionary);
-
-  std::string value;
-  EXPECT_TRUE(dictionary.GetString("addrLines", &value));
-  EXPECT_EQ("123 Main\nApt 2", value);
-  EXPECT_TRUE(dictionary.GetString("city", &value));
-  EXPECT_EQ("Laredo", value);
-  EXPECT_TRUE(dictionary.GetString("country", &value));
-  EXPECT_EQ("US", value);
-  EXPECT_TRUE(dictionary.GetString("dependentLocality", &value));
-  EXPECT_EQ("", value);
-  EXPECT_TRUE(dictionary.GetString("guid", &value));
-  EXPECT_EQ("guid", value);
-  EXPECT_TRUE(dictionary.GetString("languageCode", &value));
-  EXPECT_EQ("", value);
-  EXPECT_TRUE(dictionary.GetString("postalCode", &value));
-  EXPECT_EQ("77300", value);
-  EXPECT_TRUE(dictionary.GetString("sortingCode", &value));
-  EXPECT_EQ("", value);
-  EXPECT_TRUE(dictionary.GetString("state", &value));
-  EXPECT_EQ("TX", value);
-  EXPECT_TRUE(dictionary.GetString("email", &value));
-  EXPECT_EQ("fml@example.com", value);
-  EXPECT_TRUE(dictionary.GetString("fullName", &value));
-  EXPECT_EQ("First Middle Last", value);
-  EXPECT_TRUE(dictionary.GetString("phone", &value));
-  EXPECT_EQ("832-555-1000", value);
-}
-
-}  // namespace options
diff --git a/chrome/browser/ui/webui/options/browser_options_browsertest.js b/chrome/browser/ui/webui/options/browser_options_browsertest.js
deleted file mode 100644
index b5713f6..0000000
--- a/chrome/browser/ui/webui/options/browser_options_browsertest.js
+++ /dev/null
@@ -1,131 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * TestFixture for browser options WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function BrowserOptionsWebUITest() {}
-
-BrowserOptionsWebUITest.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://chrome/settings/',
-};
-
-// Test opening the browser options has correct location.
-// Times out on Mac debug only. See http://crbug.com/121030
-GEN('#if defined(OS_MACOSX) && !defined(NDEBUG)');
-GEN('#define MAYBE_testOpenBrowserOptions ' +
-    'DISABLED_testOpenBrowserOptions');
-GEN('#else');
-GEN('#define MAYBE_testOpenBrowserOptions testOpenBrowserOptions');
-GEN('#endif  // defined(OS_MACOSX)');
-TEST_F('BrowserOptionsWebUITest', 'MAYBE_testOpenBrowserOptions', function() {
-  assertEquals(this.browsePreload, document.location.href);
-  expectFalse($('navigation').classList.contains('background'));
-});
-
-/**
- * TestFixture for the uber page when the browser options page has an overlay.
- * @extends {testing.Test}
- * @constructor
- */
-function BrowserOptionsOverlayWebUITest() {}
-
-BrowserOptionsOverlayWebUITest.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://chrome/settings/autofill',
-
-  /** @override */
-  isAsync: true,
-};
-
-TEST_F('BrowserOptionsOverlayWebUITest', 'testNavigationInBackground',
-    function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  if ($('navigation').classList.contains('background')) {
-    testDone();
-    return;
-  }
-
-  // Wait for the message to be posted to the Uber page.
-  window.addEventListener('message', function(e) {
-    if (e.data.method == 'beginInterceptingEvents') {
-      window.setTimeout(function() {
-        assertTrue($('navigation').classList.contains('background'));
-        testDone();
-      });
-    }
-  });
-});
-
-/**
- * @extends {testing.Test}
- * @constructor
- */
-function BrowserOptionsFrameWebUITest() {}
-
-BrowserOptionsFrameWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://settings-frame/',
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    // Enable when failure is resolved.
-    // AX_TEXT_04: http://crbug.com/570721
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'linkWithUnclearPurpose',
-        '#sync-overview > A');
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/570723
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        '#profiles-list');
-  },
-};
-
-TEST_F('BrowserOptionsFrameWebUITest', 'testAdvancedSettingsHiddenByDefault',
-    function() {
-  assertEquals(this.browsePreload, document.location.href);
-  expectTrue($('advanced-settings').hidden);
-});
-
-/**
- * @extends {testing.Test}
- * @constructor
- */
-function AdvancedSettingsWebUITest() {}
-
-AdvancedSettingsWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://settings-frame/autofill',
-};
-
-// TODO(crbug.com/617066) Flakes on Win.
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_testAdvancedSettingsShown ' +
-    'DISABLED_testAdvancedSettingsShown');
-GEN('#else');
-GEN('#define MAYBE_testAdvancedSettingsShown testAdvancedSettingsShown');
-GEN('#endif');
-TEST_F('AdvancedSettingsWebUITest', 'MAYBE_testAdvancedSettingsShown',
-    function() {
-  assertEquals(this.browsePreload, document.location.href);
-  expectFalse($('advanced-settings').hidden);
-});
diff --git a/chrome/browser/ui/webui/options/certificate_manager_browsertest.js b/chrome/browser/ui/webui/options/certificate_manager_browsertest.js
deleted file mode 100644
index 0db9129..0000000
--- a/chrome/browser/ui/webui/options/certificate_manager_browsertest.js
+++ /dev/null
@@ -1,405 +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.
-
-// Mac and Windows go to native certificate manager, and certificate manager
-// isn't implemented if OpenSSL is used.
-GEN('#if defined(USE_NSS_CERTS)');
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * URL of the Certificates dialog in the Settings page.
- * @const
- */
-var CERTIFICATE_MANAGER_SETTINGS_PAGE_URL =
-    'chrome://settings-frame/certificates';
-
-// Standalone certificate manager dialog page is implemented only in Chrome OS.
-GEN('#if defined(OS_CHROMEOS)');
-
-/**
- * URL of the standalone certificate manager dialog page.
- * @const
- */
-var CERTIFICATE_MANAGER_STANDALONE_PAGE_URL = 'chrome://certificate-manager/';
-
-GEN('#endif  // defined(OS_CHROMEOS)');
-
-/**
- * TestFixture for certificate manager WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function CertificateManagerWebUIBaseTest() {}
-
-CertificateManagerWebUIBaseTest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /** @override */
-  preLoad: function() {
-    // We can't check cr.isChromeOS in the preLoad since "cr" doesn't exist yet.
-    // This is copied from ui/webui/resources/js/cr.js, maybe
-    // there's a better way to do this.
-    this.isChromeOS = /CrOS/.test(navigator.userAgent);
-
-    this.makeAndRegisterMockHandler(
-        [
-          'editCaCertificateTrust',
-          'exportPersonalCertificate',
-          'importPersonalCertificate',
-          'importCaCertificate',
-          'exportCertificate',
-          'deleteCertificate',
-          'populateCertificateManager',
-          'viewCertificate',
-        ]);
-  },
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    var ariaRoleNotScopedSelectors = [
-      '#tree-item-autogen-id-0',
-      '#tree-item-autogen-id-1',
-      '#tree-item-autogen-id-2',
-      '#tree-item-autogen-id-3',
-      '#tree-item-autogen-id-4',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_ARIA_09: http://crbug.com/570567
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'ariaRoleNotScoped',
-        ariaRoleNotScopedSelectors);
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/570566
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        '#caCertsTab-tree');
-
-    var focusableElementNotVisibleAndNotAriaHiddenSelectors = [
-      '#personalCertsTab-tree',
-      '#personalCertsTab-import',
-      '#personalCertsTab-import-and-bind',
-      '#certificate-confirm',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_FOCUS_01: http://crbug.com/570568
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'focusableElementNotVisibleAndNotAriaHidden',
-        focusableElementNotVisibleAndNotAriaHiddenSelectors);
-  },
-};
-
-/**
- * TestFixture for certificate manager WebUI testing.
- * @extends {CertificateManagerWebUIBaseTest}
- * @constructor
- */
-function CertificateManagerWebUIUnpopulatedTest() {}
-
-CertificateManagerWebUIUnpopulatedTest.prototype = {
-  __proto__: CertificateManagerWebUIBaseTest.prototype,
-
-  /**
-   * Browse to the certificate manager dialog in the Settings page.
-   */
-  browsePreload: CERTIFICATE_MANAGER_SETTINGS_PAGE_URL,
-
-  /** @override */
-  preLoad: function() {
-    CertificateManagerWebUIBaseTest.prototype.preLoad.call(this);
-
-    // We expect the populateCertificateManager callback, but do not reply to
-    // it. This simulates what will be displayed if retrieving the cert list
-    // from NSS is slow.
-    this.mockHandler.expects(once()).populateCertificateManager();
-  },
-};
-
-// Test opening the certificate manager has correct location and buttons have
-// correct initial states when onPopulateTree has not been called.
-TEST_F('CertificateManagerWebUIUnpopulatedTest',
-       'testUnpopulatedCertificateManager', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  // All buttons should be disabled to start.
-  expectTrue($('personalCertsTab-view').disabled);
-  expectTrue($('personalCertsTab-backup').disabled);
-  expectTrue($('personalCertsTab-delete').disabled);
-  expectTrue($('personalCertsTab-import').disabled);
-  if (this.isChromeOS)
-    expectTrue($('personalCertsTab-import-and-bind').disabled);
-
-  expectTrue($('serverCertsTab-view').disabled);
-  expectTrue($('serverCertsTab-export').disabled);
-  expectTrue($('serverCertsTab-delete').disabled);
-  expectTrue($('serverCertsTab-import').disabled);
-
-  expectTrue($('caCertsTab-view').disabled);
-  expectTrue($('caCertsTab-edit').disabled);
-  expectTrue($('caCertsTab-export').disabled);
-  expectTrue($('caCertsTab-delete').disabled);
-  expectTrue($('caCertsTab-import').disabled);
-
-  expectTrue($('otherCertsTab-view').disabled);
-  expectTrue($('otherCertsTab-export').disabled);
-  expectTrue($('otherCertsTab-delete').disabled);
-
-  Mock4JS.verifyAllMocks();
-
-  // If user database is not available, import buttons should be disabled.
-  CertificateManager.onModelReady(false /* userDbAvailable*/,
-                                  false /* tpmAvailable */);
-
-  expectTrue($('personalCertsTab-import').disabled);
-  expectTrue($('serverCertsTab-import').disabled);
-  expectTrue($('caCertsTab-import').disabled);
-
-  // Once we get the onModelReady call, the import buttons should be enabled,
-  // others should still be disabled.
-  CertificateManager.onModelReady(true /* userDbAvailable*/,
-                                  false /* tpmAvailable */);
-
-  expectTrue($('personalCertsTab-view').disabled);
-  expectTrue($('personalCertsTab-backup').disabled);
-  expectTrue($('personalCertsTab-delete').disabled);
-  expectFalse($('personalCertsTab-import').disabled);
-
-  expectTrue($('serverCertsTab-view').disabled);
-  expectTrue($('serverCertsTab-export').disabled);
-  expectTrue($('serverCertsTab-delete').disabled);
-  expectFalse($('serverCertsTab-import').disabled);
-
-  expectTrue($('caCertsTab-view').disabled);
-  expectTrue($('caCertsTab-edit').disabled);
-  expectTrue($('caCertsTab-export').disabled);
-  expectTrue($('caCertsTab-delete').disabled);
-  expectFalse($('caCertsTab-import').disabled);
-
-  expectTrue($('otherCertsTab-view').disabled);
-  expectTrue($('otherCertsTab-export').disabled);
-  expectTrue($('otherCertsTab-delete').disabled);
-
-  // On ChromeOS, the import and bind button should only be enabled if TPM is
-  // present.
-  if (this.isChromeOS) {
-    expectTrue($('personalCertsTab-import-and-bind').disabled);
-    CertificateManager.onModelReady(true /* userDbAvailable*/,
-                                    true /* tpmAvailable */);
-    expectFalse($('personalCertsTab-import-and-bind').disabled);
-  }
-});
-
-/**
- * TestFixture for certificate manager WebUI testing.
- * @extends {CertificateManagerWebUIBaseTest}
- * @constructor
- */
-function CertificateManagerWebUITest() {}
-
-CertificateManagerWebUITest.prototype = {
-  __proto__: CertificateManagerWebUIBaseTest.prototype,
-
-  /** @override */
-  preLoad: function() {
-    CertificateManagerWebUIBaseTest.prototype.preLoad.call(this);
-
-    var tpmAvailable = this.isChromeOS;
-    var userDbAvailable = true;
-    this.mockHandler.expects(once()).populateCertificateManager().will(
-        callFunction(function() {
-          CertificateManager.onModelReady(userDbAvailable, tpmAvailable);
-
-          [['personalCertsTab-tree',
-              [{'id': 'o1',
-                'name': 'org1',
-                'subnodes': [{ 'id': 'c1',
-                               'name': 'cert1',
-                               'readonly': false,
-                               'untrusted': false,
-                               'extractable': true }],
-               }],
-           ],
-           ['caCertsTab-tree',
-              [{'id': 'o2',
-                'name': 'org2',
-                'subnodes': [{ 'id': 'ca_cert0',
-                               'name': 'ca_cert0',
-                               'readonly': false,
-                               'untrusted': false,
-                               'extractable': true,
-                               'policy': false },
-                             { 'id': 'ca_cert1',
-                               'name': 'ca_cert1',
-                               'readonly': false,
-                               'untrusted': false,
-                               'extractable': true,
-                               'policy': true },
-                             { 'id': 'ca_cert2',
-                               'name': 'ca_cert2',
-                               'readonly': false,
-                               'untrusted': false,
-                               'extractable': true,
-                               'policy': false }],
-               }],
-           ]
-          ].forEach(CertificateManager.onPopulateTree);}));
-  },
-};
-
-/**
- * TestFixture for testing certificate manager WebUI in the Settings page.
- * @extends {CertificateManagerWebUITest}
- * @constructor
- */
-function CertificateManagerSettingsWebUITest() {}
-
-CertificateManagerSettingsWebUITest.prototype = {
-  __proto__: CertificateManagerWebUITest.prototype,
-
-  /**
-   * Browse to the certificate manager dialog in the Settings page.
-   */
-  browsePreload: CERTIFICATE_MANAGER_SETTINGS_PAGE_URL,
-};
-
-TEST_F('CertificateManagerSettingsWebUITest',
-       'testViewAndDeleteCert', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  this.mockHandler.expects(once()).viewCertificate(['c1']);
-
-  expectTrue($('personalCertsTab-view').disabled);
-  expectTrue($('personalCertsTab-backup').disabled);
-  expectTrue($('personalCertsTab-delete').disabled);
-  expectFalse($('personalCertsTab-import').disabled);
-  if (this.isChromeOS)
-    expectFalse($('personalCertsTab-import-and-bind').disabled);
-
-  var personalCerts = $('personalCertsTab');
-
-  // Click on the first folder.
-  personalCerts.querySelector('div.tree-item').click();
-  // Buttons should still be in same state.
-  expectTrue($('personalCertsTab-view').disabled);
-  expectTrue($('personalCertsTab-backup').disabled);
-  expectTrue($('personalCertsTab-delete').disabled);
-  expectFalse($('personalCertsTab-import').disabled);
-  if (this.isChromeOS)
-    expectFalse($('personalCertsTab-import-and-bind').disabled);
-
-  // Click on the first cert.
-  personalCerts.querySelector('div.tree-item div.tree-item').click();
-  // Buttons should now allow you to act on the cert.
-  expectFalse($('personalCertsTab-view').disabled);
-  expectFalse($('personalCertsTab-backup').disabled);
-  expectFalse($('personalCertsTab-delete').disabled);
-  expectFalse($('personalCertsTab-import').disabled);
-  if (this.isChromeOS)
-    expectFalse($('personalCertsTab-import-and-bind').disabled);
-
-  // Click on the view button.
-  $('personalCertsTab-view').click();
-
-  Mock4JS.verifyAllMocks();
-
-  this.mockHandler.expects(once()).deleteCertificate(['c1']).will(callFunction(
-      function() {
-        CertificateManager.onPopulateTree(['personalCertsTab-tree', []]);
-      }));
-
-  // Click on the delete button.
-  $('personalCertsTab-delete').click();
-
-  // Click on the cancel button to verify the confirmation overlay closes.
-  $('alertOverlayCancel').click();
-  expectTrue($('alertOverlay').parentNode.classList.contains('transparent'));
-
-  // Click on the delete button.
-  $('personalCertsTab-delete').click();
-
-  // Click on the ok button in the confirmation overlay.
-  $('alertOverlayOk').click();
-  expectTrue($('alertOverlay').parentNode.classList.contains('transparent'));
-
-  // Context sensitive buttons should be disabled.
-  expectTrue($('personalCertsTab-view').disabled);
-  expectTrue($('personalCertsTab-backup').disabled);
-  expectTrue($('personalCertsTab-delete').disabled);
-  expectFalse($('personalCertsTab-import').disabled);
-  if (this.isChromeOS)
-    expectFalse($('personalCertsTab-import-and-bind').disabled);
-  // Tree should be empty.
-  expectTrue(personalCerts.querySelector('div.tree-item') === null);
-});
-
-// Ensure certificate objects with the 'policy' property set have
-// the cert-policy CSS class appended.
-TEST_F('CertificateManagerSettingsWebUITest',
-       'testPolicyInstalledCertificate', function() {
-  // Click on the first folder and get the certificates.
-  var caCertsTab = $('caCertsTab');
-  caCertsTab.querySelector('div.tree-item').click();
-  var certs = caCertsTab.querySelectorAll('div.tree-item div.tree-item');
-
-  // First cert shouldn't show the controlled setting badge, and the
-  // edit and delete buttons should be enabled.
-  var cert0 = certs[0];
-  expectEquals('ca_cert0', cert0.data.name);
-  expectEquals(null, cert0.querySelector('.cert-policy'));
-  cert0.click();
-  expectFalse($('caCertsTab-edit').disabled);
-  expectFalse($('caCertsTab-delete').disabled);
-
-  // But the second should show the controlled setting badge, and the
-  // edit and delete buttons should be disabled.
-  var cert1 = certs[1];
-  expectEquals('ca_cert1', cert1.data.name);
-  expectNotEquals(null, cert1.querySelector('.cert-policy'));
-  cert1.click();
-  expectTrue($('caCertsTab-edit').disabled);
-  expectTrue($('caCertsTab-delete').disabled);
-});
-
-// Standalone certificate manager dialog page is implemented only in Chrome OS.
-GEN('#if defined(OS_CHROMEOS)');
-
-/**
- * TestFixture for testing standalone certificate manager WebUI.
- * @extends {CertificateManagerWebUITest}
- * @constructor
- */
-function CertificateManagerStandaloneWebUITest() {}
-
-CertificateManagerStandaloneWebUITest.prototype = {
-  __proto__: CertificateManagerWebUITest.prototype,
-
-  /**
-   * Browse to the certificate manager page.
-   */
-  browsePreload: CERTIFICATE_MANAGER_STANDALONE_PAGE_URL,
-};
-
-// Ensure that the standalone certificate manager page loads and displays the
-// ceertificates correctly.
-TEST_F('CertificateManagerStandaloneWebUITest', 'testCertsDisplaying',
-       function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  // Click on the first folder and get the certificates.
-  var caCertsTab = $('caCertsTab');
-  caCertsTab.querySelector('div.tree-item').click();
-  var certs = caCertsTab.querySelectorAll('div.tree-item div.tree-item');
-
-  // There should be exactly three certificates displayed.
-  expectEquals(certs.length, 3);
-});
-
-GEN('#endif  // defined(OS_CHROMEOS)');
-
-GEN('#endif  // defined(USE_NSS_CERTS)');
diff --git a/chrome/browser/ui/webui/options/chromeos/accounts_options_browsertest.cc b/chrome/browser/ui/webui/options/chromeos/accounts_options_browsertest.cc
deleted file mode 100644
index 34ea81b1..0000000
--- a/chrome/browser/ui/webui/options/chromeos/accounts_options_browsertest.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stddef.h>
-
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
-#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/settings/cros_settings_names.h"
-#include "components/prefs/pref_service.h"
-#include "components/user_manager/user_manager.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/test_utils.h"
-
-namespace chromeos {
-
-namespace {
-
-const char* kTestUsers[] = { "test-user1@gmail.com", "test-user2@gmail.com" };
-
-}  // namespace
-
-class AccountsOptionsTest : public LoginManagerTest {
- public:
-  AccountsOptionsTest()
-      : LoginManagerTest(false),
-        stub_settings_provider_(base::MakeUnique<StubCrosSettingsProvider>()),
-        stub_settings_provider_ptr_(static_cast<StubCrosSettingsProvider*>(
-            stub_settings_provider_.get())) {
-    stub_settings_provider_->Set(kDeviceOwner, base::Value(kTestUsers[0]));
-    for (size_t i = 0; i < arraysize(kTestUsers); ++i) {
-      test_users_.push_back(AccountId::FromUserEmail(kTestUsers[i]));
-    }
-  }
-
-  ~AccountsOptionsTest() override {}
-
-  void SetUpOnMainThread() override {
-    LoginManagerTest::SetUpOnMainThread();
-    CrosSettings* settings = CrosSettings::Get();
-    CrosSettingsProvider* device_settings_provider =
-        settings->GetProvider(kDeviceOwner);
-    device_settings_provider_ =
-        settings->RemoveSettingsProvider(device_settings_provider);
-    settings->AddSettingsProvider(std::move(stub_settings_provider_));
-
-    // Notify ChromeUserManager of ownership change.
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
-        content::Source<AccountsOptionsTest>(this),
-        content::NotificationService::NoDetails());
-  }
-
-  void TearDownOnMainThread() override {
-    CrosSettings* settings = CrosSettings::Get();
-    stub_settings_provider_ =
-        settings->RemoveSettingsProvider(stub_settings_provider_ptr_);
-    settings->AddSettingsProvider(std::move(device_settings_provider_));
-    LoginManagerTest::TearDownOnMainThread();
-  }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    LoginManagerTest::SetUpCommandLine(command_line);
-  }
-
- protected:
-  void CheckAccountsUI(const user_manager::User* user, bool is_owner) {
-    Profile* profile = ProfileHelper::Get()->GetProfileByUserUnsafe(user);
-
-    ui_test_utils::BrowserAddedObserver observer;
-    Browser* browser = CreateBrowser(profile);
-    observer.WaitForSingleNewBrowser();
-
-    ui_test_utils::NavigateToURL(browser,
-                                 GURL("chrome://settings-frame/accounts"));
-    content::WebContents* contents =
-        browser->tab_strip_model()->GetActiveWebContents();
-
-    bool warning_visible;
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        contents,
-        "var e = document.getElementById('ownerOnlyWarning');"
-        "var visible = e.offsetWidth > 0 && e.offsetHeight > 0;"
-        "window.domAutomationController.send(visible);",
-        &warning_visible));
-    EXPECT_EQ(is_owner, !warning_visible);
-
-    bool guest_option_enabled;
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        contents,
-        "var e = document.getElementById('allowBwsiCheck');"
-        "window.domAutomationController.send(!e.disabled);",
-        &guest_option_enabled));
-    EXPECT_EQ(is_owner, guest_option_enabled);
-
-    bool supervised_users_enabled;
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        contents,
-        "var e = document.getElementById('allowSupervisedCheck');"
-        "window.domAutomationController.send(!e.disabled);",
-        &supervised_users_enabled));
-    ASSERT_EQ(is_owner, supervised_users_enabled);
-
-    bool user_pods_enabled;
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        contents,
-        "var e = document.getElementById('showUserNamesCheck');"
-        "window.domAutomationController.send(!e.disabled);",
-        &user_pods_enabled));
-    EXPECT_EQ(is_owner, user_pods_enabled);
-
-    bool whitelist_enabled;
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        contents,
-        "var e = document.getElementById('useWhitelistCheck');"
-        "window.domAutomationController.send(!e.disabled);",
-        &whitelist_enabled));
-    EXPECT_EQ(is_owner, whitelist_enabled);
-  }
-
-  std::unique_ptr<CrosSettingsProvider> stub_settings_provider_;
-  StubCrosSettingsProvider* stub_settings_provider_ptr_;
-  std::unique_ptr<CrosSettingsProvider> device_settings_provider_;
-  std::vector<AccountId> test_users_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AccountsOptionsTest);
-};
-
-IN_PROC_BROWSER_TEST_F(AccountsOptionsTest, PRE_MultiProfilesAccountsOptions) {
-  RegisterUser(test_users_[0].GetUserEmail());
-  RegisterUser(test_users_[1].GetUserEmail());
-  StartupUtils::MarkOobeCompleted();
-}
-
-IN_PROC_BROWSER_TEST_F(AccountsOptionsTest, MultiProfilesAccountsOptions) {
-  LoginUser(test_users_[0].GetUserEmail());
-  UserAddingScreen::Get()->Start();
-  content::RunAllPendingInMessageLoop();
-  AddUser(test_users_[1].GetUserEmail());
-
-  user_manager::UserManager* manager = user_manager::UserManager::Get();
-  ASSERT_EQ(2u, manager->GetLoggedInUsers().size());
-
-  CheckAccountsUI(manager->FindUser(test_users_[0]), true /* is_owner */);
-  CheckAccountsUI(manager->FindUser(test_users_[1]), false /* is_owner */);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/options/chromeos/accounts_options_browsertest.js b/chrome/browser/ui/webui/options/chromeos/accounts_options_browsertest.js
deleted file mode 100644
index 381aead..0000000
--- a/chrome/browser/ui/webui/options/chromeos/accounts_options_browsertest.js
+++ /dev/null
@@ -1,42 +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.
-
-GEN_INCLUDE(['../options_browsertest_base.js']);
-
-function AccountsOptionsWebUITest() {}
-
-AccountsOptionsWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Browse to accounts options.
-   */
-  browsePreload: 'chrome://settings-frame/accounts',
-};
-
-function createEnterKeyboardEvent(type) {
-  return new KeyboardEvent(type, {
-    'bubbles': true,
-    'cancelable': true,
-    'key': 'Enter'
-  });
-}
-
-TEST_F('AccountsOptionsWebUITest', 'testNoCloseOnEnter', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  var inputField = $('userNameEdit');
-  var accountsOptionsPage = AccountsOptions.getInstance();
-
-  // Overlay is visible.
-  assertTrue(accountsOptionsPage.visible);
-
-  // Simulate pressing the enter key in the edit field.
-  inputField.dispatchEvent(createEnterKeyboardEvent('keydown'));
-  inputField.dispatchEvent(createEnterKeyboardEvent('keypress'));
-  inputField.dispatchEvent(createEnterKeyboardEvent('keyup'));
-
-  // Verify the overlay is still visible.
-  assertTrue(accountsOptionsPage.visible);
-});
diff --git a/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js b/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js
deleted file mode 100644
index 38e4c9b..0000000
--- a/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js
+++ /dev/null
@@ -1,440 +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.
-
-GEN('#if defined(OS_CHROMEOS)');
-
-GEN_INCLUDE(['../options_browsertest_base.js']);
-
-function BluetoothWebUITestAsync() {}
-
-BluetoothWebUITestAsync.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /** @override */
-  isAsync: true,
-
-  /**
-   * Start tests from the main-settings page.
-   */
-  browsePreload: 'chrome://settings-frame/',
-
-  // These entries match the fake entries in FakeBluetoothDeviceClient.
-  fakePairedDevice: {
-    address: '00:11:22:33:44:55',
-    connectable: true,
-    connected: false,
-    name: 'Fake Device (name)',
-    paired: true
-  },
-
-  fakePairedDevice2: {
-    address: '20:7D:74:00:00:04',
-    connectable: false,
-    connected: false,
-    name: 'Paired Unconnectable Device (name)',
-    paired: true
-  },
-
-  fakeUnpairedDevice: {
-    address: '28:CF:DA:00:00:00',
-    connectable: true,
-    connected: false,
-    name: 'Bluetooth 2.0 Mouse',
-    paired: false
-  },
-
-  fakeUnpairedDevice2: {
-    address: '00:24:BE:00:00:00',
-    connectable: true,
-    connected: false,
-    name: 'PIN Device',
-    paired: false
-  },
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    var unsupportedAriaAttributeSelectors = [
-      '#bluetooth-paired-devices-list',
-      '#bluetooth-unpaired-devices-list',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/570564
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        unsupportedAriaAttributeSelectors);
-  },
-
-  /**
-   * Retrieves the list item associated with a Bluetooth device.
-   * @param {!Element} listElement Element containing a list of devices.
-   * @param {string} deviceName The name of the device.
-   * @return {Element|undefined} List item matching the device name.
-   */
-  getElementForDevice: function(listElement, deviceName) {
-    var items = listElement.querySelectorAll('.bluetooth-device');
-    for (var i = 0; i < items.length; i++) {
-      var candidate = items[i];
-      var name = candidate.data.name;
-      if (name == deviceName)
-        return candidate;
-    }
-    return undefined;
-  },
-
-  /**
-   * Selects a bluetooth device from the list with the matching address.
-   * @param {!Element} listElement A list of Bluetooth devices.
-   * @param {string} address Device address.
-   */
-  selectDevice: function(listElement, address) {
-    listElement.setSelectedDevice_(address);
-    cr.dispatchSimpleEvent(listElement, 'change');
-  },
-
-  /**
-   * Fake input of a pincode or passkey.
-   * @param {!Element} element Text input field.
-   * @param {string} text New value for the input field.
-   */
-  fakeInput: function(element, text) {
-    element.value = text;
-    cr.dispatchSimpleEvent(element, 'input');
-  },
-};
-
-TEST_F('BluetoothWebUITestAsync', 'testEnableBluetooth', function() {
-  assertEquals(this.browsePreload, document.location.href);
-  expectFalse($('enable-bluetooth').checked);
-  expectTrue($('bluetooth-paired-devices-list').parentNode.hidden);
-
-  $('enable-bluetooth').click();
-
-  // The UI may not be updated until all callbacks have been handled, so
-  // send a new request that will get processed after any currently pending
-  // callbacks.
-  chrome.bluetooth.getAdapterState(function(state) {
-    expectTrue(state.powered);
-    expectFalse($('bluetooth-paired-devices-list').parentNode.hidden);
-    testDone();
-  }.bind(this));
-});
-
-// TODO(crbug.com/603499) Test is flaky.
-TEST_F('BluetoothWebUITestAsync', 'DISABLED_testAddDevice', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  // Enable bluetooth.
-  $('enable-bluetooth').click();
-
-  // Wait for the UI to process any pending messages.
-  window.setTimeout(function() {
-    // Wait for fake bluetooth impl to send any updates.
-    chrome.bluetooth.getAdapterState(function(state) {
-      var pairedDeviceList = $('bluetooth-paired-devices-list');
-      var unpairedDeviceList = $('bluetooth-unpaired-devices-list');
-
-      // Verify that devices are in the correct list.
-      var index = pairedDeviceList.find(this.fakePairedDevice.address);
-      expectEquals(1, index);
-      index = pairedDeviceList.find(this.fakePairedDevice2.address);
-      expectEquals(0, index);
-      index = pairedDeviceList.find(this.fakeUnpairedDevice.address);
-      expectEquals(undefined, index);
-      expectTrue(!!this.getElementForDevice(pairedDeviceList,
-                                            this.fakePairedDevice.name));
-      expectFalse(!!this.getElementForDevice(unpairedDeviceList,
-                                             this.fakePairedDevice.name));
-
-      // Test clicking on the 'Add a device' button. This should send a
-      // startDiscovering request.
-      $('bluetooth-add-device').click();
-      expectFalse($('bluetooth-options').hidden);
-
-      // Wait for fake bluetooth impl to send any updates.
-      chrome.bluetooth.getAdapterState(function(state) {
-        expectTrue(state.discovering);
-        expectFalse(unpairedDeviceList.parentNode.hidden);
-
-        index = unpairedDeviceList.find(this.fakeUnpairedDevice.address);
-        expectEquals(0, index);
-
-        var connectButton = $('bluetooth-add-device-apply-button');
-        expectTrue(connectButton.disabled);
-        expectFalse($('bluetooth-add-device-cancel-button').disabled);
-
-        // Test selecting an element and clicking on the connect button.
-        this.selectDevice(unpairedDeviceList, this.fakeUnpairedDevice.address);
-        expectFalse(connectButton.disabled);
-        connectButton.click();
-
-        // Wait for fake bluetooth impl to send any updates.
-        chrome.bluetooth.getAdapterState(function(state) {
-          // Verify that the pairing UI is shown.
-          expectFalse($('bluetooth-pairing').hidden);
-          testDone();
-        }.bind(this));
-      }.bind(this));
-    }.bind(this));
-  }.bind(this));
-});
-
-TEST_F('BluetoothWebUITestAsync', 'testDevicePairing', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  // Enable bluetooth.
-  $('enable-bluetooth').click();
-
-  // Wait for the UI to process any pending messages.
-  window.setTimeout(function() {
-    // Wait for fake bluetooth impl to send any updates.
-    chrome.bluetooth.getAdapterState(function(state) {
-      var pairedDeviceList = $('bluetooth-paired-devices-list');
-      var unpairedDeviceList = $('bluetooth-unpaired-devices-list');
-
-      $('bluetooth-add-device').click();
-
-      // Wait for fake bluetooth impl to send any updates.
-      chrome.bluetooth.getAdapterState(function(state) {
-        expectFalse(unpairedDeviceList.parentNode.hidden);
-
-        // Test selecting an element and clicking on the connect button.
-        var index = unpairedDeviceList.find(this.fakeUnpairedDevice2.address);
-        expectNotEquals(undefined, index);
-        this.selectDevice(unpairedDeviceList, this.fakeUnpairedDevice2.address);
-        var connectButton = $('bluetooth-add-device-apply-button');
-        expectFalse(connectButton.disabled);
-        connectButton.click();
-
-        // Wait for fake bluetooth impl to send any updates.
-        chrome.bluetooth.getAdapterState(function(state) {
-          // Verify that the pairing UI is shown.
-          expectFalse($('bluetooth-pairing').hidden);
-          expectTrue($('bluetooth-pairing-passkey-display').hidden);
-          expectTrue($('bluetooth-pairing-passkey-entry').hidden);
-          expectFalse($('bluetooth-pairing-pincode-entry').hidden);
-
-          var pincode = '123456';
-          this.fakeInput($('bluetooth-pincode'), pincode);
-          $('bluetooth-pair-device-connect-button').click();
-
-          // Wait for fake bluetooth impl to send any updates.
-          chrome.bluetooth.getAdapterState(function(state) {
-            expectTrue($('bluetooth-pairing-pincode-entry').hidden);
-            testDone();
-          }.bind(this));
-        }.bind(this));
-      }.bind(this));
-    }.bind(this));
-  }.bind(this));
-});
-
-// TODO(crbug.com/608126) Test is flaky.
-TEST_F('BluetoothWebUITestAsync', 'DISABLED_testConnect', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  // Enable bluetooth.
-  $('enable-bluetooth').click();
-
-  // Wait for the UI to process any pending messages.
-  window.setTimeout(function() {
-    // Wait for fake bluetooth impl to send any updates.
-    chrome.bluetooth.getAdapterState(function(state) {
-      var pairedDeviceList = $('bluetooth-paired-devices-list');
-      var element = this.getElementForDevice(
-          pairedDeviceList, this.fakePairedDevice.name);
-      assertTrue(!!element, this.fakePairedDevice.name);
-      expectFalse(!!element.getAttribute('connected'));
-
-      var connectButton = $('bluetooth-reconnect-device');
-      expectTrue(connectButton.disabled);
-
-      // Simulate connecting to a previously paired device.
-      this.selectDevice(pairedDeviceList, this.fakePairedDevice.address);
-      expectFalse(connectButton.disabled);
-      connectButton.click();
-
-      // Call bluetooth.getAdapterState to ensure that all state has been
-      // updated.
-      chrome.bluetooth.getAdapterState(function(state) {
-        element = this.getElementForDevice(
-            pairedDeviceList, this.fakePairedDevice.name);
-        expectTrue(!!element.getAttribute('connected'));
-        var deleteButton = element.querySelector('.row-delete-button');
-        expectTrue(!!deleteButton);
-        testDone();
-      }.bind(this));
-    }.bind(this));
-  }.bind(this));
-});
-
-TEST_F('BluetoothWebUITestAsync', 'testDisconnect', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  // Enable bluetooth.
-  $('enable-bluetooth').click();
-
-  // Wait for the UI to process any pending messages.
-  window.setTimeout(function() {
-    // Wait for fake bluetooth impl to send any updates.
-    chrome.bluetooth.getAdapterState(function(state) {
-      var pairedDeviceList = $('bluetooth-paired-devices-list');
-
-      // First connect to the device so that the fake implementation state is
-      // connected.
-      chrome.bluetoothPrivate.connect(
-          this.fakePairedDevice.address, function(result) {
-            assertEquals(
-                chrome.bluetoothPrivate.ConnectResultType.SUCCESS, result);
-
-            var element = this.getElementForDevice(
-                pairedDeviceList, this.fakePairedDevice.name);
-            assertTrue(!!element, this.fakePairedDevice.name);
-            expectTrue(!!element.getAttribute('connected'));
-
-            // Simulate disconnecting from a connected device.
-            var button = element.querySelector('.row-delete-button');
-            button.click();
-
-            // Wait for fake bluetooth impl to send any updates.
-            chrome.bluetooth.getAdapterState(function(state) {
-              element = this.getElementForDevice(
-                  pairedDeviceList, this.fakePairedDevice.name);
-              expectFalse(!!element.getAttribute('connected'));
-              button = element.querySelector('.row-delete-button');
-              expectTrue(!!button);
-              testDone();
-            }.bind(this));
-          }.bind(this));
-    }.bind(this));
-  }.bind(this));
-});
-
-// TODO(crbug.com/605090): Disabled because of flakiness.
-TEST_F('BluetoothWebUITestAsync', 'DISABLED_testForget', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  // Enable bluetooth.
-  $('enable-bluetooth').click();
-
-  // Wait for the UI to process any pending messages.
-  window.setTimeout(function() {
-    // Wait for fake bluetooth impl to send any updates.
-    chrome.bluetooth.getAdapterState(function(state) {
-      var pairedDeviceList = $('bluetooth-paired-devices-list');
-
-      var element = this.getElementForDevice(pairedDeviceList,
-                                             this.fakePairedDevice.name);
-      var button = element.querySelector('.row-delete-button');
-      button.click();
-
-      // Wait for fake bluetooth impl to send any updates.
-      chrome.bluetooth.getAdapterState(function(state) {
-        expectFalse(!!this.getElementForDevice(pairedDeviceList,
-                                               this.fakePairedDevice.name));
-        testDone();
-      }.bind(this));
-    }.bind(this));
-  }.bind(this));
-});
-
-
-TEST_F('BluetoothWebUITestAsync', 'testMaliciousInput', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  var maliciousStrings = [
-    '<SCRIPT>alert(1)</SCRIPT>',
-    '>\'>\\"><SCRIPT>alert(1)</SCRIPT>',
-    '<IMG SRC=\\"javascript:alert(1)\\">',
-    '<A HREF=\\"data:text/html;base64,' +
-        'PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pgo=\\">..</A>',
-    '<div>',
-    '<textarea>',
-    '<style>',
-    '[0xC0][0xBC]SCRIPT[0xC0][0xBE]alert(1)[0xC0][0xBC]/SCRIPT[0xC0][0xBE]',
-    '+ADw-SCRIPT+AD4-alert(1)+ADw-/SCRIPT+AD4-',
-    '&#<script>alert(1)</script>;',
-    '<!-- Hello -- world > <SCRIPT>alert(1)</SCRIPT> -->',
-    '<!<!-- Hello world > <SCRIPT>alert(1)</SCRIPT> -->',
-    '\x3CSCRIPT\x3Ealert(1)\x3C/SCRIPT\x3E',
-    '<IMG SRC=\\"j[0x00]avascript:alert(1)\\">',
-    '<BASE HREF=\\"javascript:1;/**/\\"><IMG SRC=\\"alert(1)\\">',
-    'javascript:alert(1);',
-    ' xss_injection=\\"\\" ',
-    '\\" xss_injection=\\"',
-    '\' xss_injection=\'',
-    '<!--',
-    '\'',
-    '\\"'
-  ];
-
-  var fakeEvent = {
-    device: {
-      address: '28:CF:DA:00:00:00',
-      connectable: true,
-      connected: false,
-      name: 'Bluetooth 2.0 Mouse',
-      paired: false
-    },
-    pairing: 'bluetoothStartConnecting'
-  };
-
-  var nodeCount = function(node) {
-    if (node.getAttribute)
-      assertFalse(!!node.getAttribute('xss_injection'));
-    var length = node.childNodes.length;
-    var tally = length;
-    for (var i = 0; i < length; i++) {
-      tally += nodeCount(node.childNodes[i]);
-    }
-    return tally;
-  };
-
-  // Enable bluetooth.
-  $('enable-bluetooth').click();
-
-  // Wait for the UI to process any pending messages.
-  window.setTimeout(function() {
-    // Wait for fake bluetooth impl to send any updates.
-    chrome.bluetooth.getAdapterState(function(state) {
-      var unpairedDeviceList = $('bluetooth-unpaired-devices-list');
-      var pairDeviceDialog = $('bluetooth-pairing');
-
-      // Show the pairing dialog.
-      $('bluetooth-add-device').click();
-      BluetoothPairing.showDialog(fakeEvent);
-
-      // Wait for fake bluetooth impl to send any updates.
-      chrome.bluetooth.getAdapterState(function(state) {
-        expectFalse(unpairedDeviceList.parentNode.hidden);
-
-        // Determine the expected sizes.
-        var unpairedDeviceListSize = nodeCount(unpairedDeviceList);
-        var pairDeviceDialogSize = nodeCount(pairDeviceDialog);
-
-        // Ensure that updating the device with a malicious name does not
-        // corrupt the structure of the document.  Tests the unpaired device
-        // list and bluetooth pairing dialog.
-        for (var i = 0; i < maliciousStrings.length; i++) {
-          fakeEvent.device.name = maliciousStrings[i];
-          BluetoothPairing.showDialog(fakeEvent);
-          assertEquals(unpairedDeviceListSize, nodeCount(unpairedDeviceList));
-          var element = this.getElementForDevice(
-              unpairedDeviceList, fakeEvent.device.name);
-          assertTrue(!!element, fakeEvent.device.name);
-          var label = element.querySelector('.bluetooth-device-label');
-          assertTrue(!!label);
-          assertEquals(maliciousStrings[i], label.textContent);
-          assertEquals(pairDeviceDialogSize, nodeCount(pairDeviceDialog));
-        }
-
-        testDone();
-      }.bind(this));
-    }.bind(this));
-  }.bind(this));
-});
-
-GEN('#endif');
diff --git a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler_unittest.cc b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler_unittest.cc
deleted file mode 100644
index 74dbe66..0000000
--- a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler_unittest.cc
+++ /dev/null
@@ -1,92 +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/ui/webui/options/chromeos/cros_language_options_handler.h"
-
-#include <memory>
-
-#include "base/values.h"
-#include "chrome/browser/chromeos/input_method/input_method_configuration.h"
-#include "chrome/browser/ui/webui/chromeos/login/l10n_util_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromeos {
-namespace options {
-
-class CrosLanguageOptionsHandlerTest : public testing::Test {
- public:
-  CrosLanguageOptionsHandlerTest()
-      : input_manager_(new MockInputMethodManagerWithInputMethods) {
-    chromeos::input_method::InitializeForTesting(input_manager_);
-  }
-
-  ~CrosLanguageOptionsHandlerTest() override {
-    chromeos::input_method::Shutdown();
-  }
-
-  // testing::Test:
-  void SetUp() override {
-    input_manager_->AddInputMethod("xkb:us::eng", "us", "en-US");
-    input_manager_->AddInputMethod("xkb:fr::fra", "fr", "fr");
-    input_manager_->AddInputMethod("xkb:be::fra", "be", "fr");
-    input_manager_->AddInputMethod("xkb:is::ice", "is", "is");
-  }
-
- private:
-  MockInputMethodManagerWithInputMethods* input_manager_;
-};
-
-TEST_F(CrosLanguageOptionsHandlerTest, GetInputMethodList) {
-  std::unique_ptr<base::ListValue> list(
-      CrosLanguageOptionsHandler::GetInputMethodList());
-  ASSERT_EQ(4U, list->GetSize());
-
-  base::DictionaryValue* entry = NULL;
-  base::DictionaryValue *language_code_set = NULL;
-  std::string input_method_id;
-  std::string display_name;
-  std::string language_code;
-
-  // As shown below, the list should be input method ids should appear in
-  // the same order of the descriptors.
-  ASSERT_TRUE(list->GetDictionary(0, &entry));
-  ASSERT_TRUE(entry->GetString("id", &input_method_id));
-  ASSERT_TRUE(entry->GetString("displayName", &display_name));
-  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
-  EXPECT_EQ("xkb:us::eng", input_method_id);
-  // Commented out as it depends on translation in generated_resources.grd
-  // (i.e. makes the test fragile).
-  // EXPECT_EQ("English (USA) keyboard layout", display_name);
-  ASSERT_TRUE(language_code_set->HasKey("en-US"));
-
-  ASSERT_TRUE(list->GetDictionary(1, &entry));
-  ASSERT_TRUE(entry->GetString("id", &input_method_id));
-  ASSERT_TRUE(entry->GetString("displayName", &display_name));
-  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
-  EXPECT_EQ("xkb:fr::fra", input_method_id);
-  // Commented out. See above.
-  // EXPECT_EQ("French keyboard layout", display_name);
-  ASSERT_TRUE(language_code_set->HasKey("fr"));
-
-  ASSERT_TRUE(list->GetDictionary(2, &entry));
-  ASSERT_TRUE(entry->GetString("id", &input_method_id));
-  ASSERT_TRUE(entry->GetString("displayName", &display_name));
-  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
-  EXPECT_EQ("xkb:be::fra", input_method_id);
-  // Commented out. See above.
-  // EXPECT_EQ("Belgian keyboard layout", display_name);
-  ASSERT_TRUE(language_code_set->HasKey("fr"));
-
-  ASSERT_TRUE(list->GetDictionary(3, &entry));
-  ASSERT_TRUE(entry->GetString("id", &input_method_id));
-  ASSERT_TRUE(entry->GetString("displayName", &display_name));
-  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
-  EXPECT_EQ("xkb:is::ice", input_method_id);
-  // Commented out. See above.
-  // EXPECT_EQ("Japanese input method (for US keyboard)", display_name);
-  ASSERT_TRUE(language_code_set->HasKey("is"));
-}
-
-}  // namespace options
-}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js b/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js
deleted file mode 100644
index 4f0845b..0000000
--- a/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-GEN_INCLUDE(['../options_browsertest_base.js']);
-
-GEN('#if defined(OS_CHROMEOS)');
-
-/**
- * DateTimeOptionsWebUITest tests the date and time section of the options page.
- * @constructor
- * @extends {testing.Test}
- */
-function DateTimeOptionsWebUITest() {}
-
-DateTimeOptionsWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Browse to date/time options.
-   * @override
-   */
-  browsePreload: 'chrome://settings-frame/search#date',
-};
-
-TEST_F('DateTimeOptionsWebUITest', 'testShowSetTimeButton', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  // Show button.
-  BrowserOptions.setCanSetTime(true);
-  expectFalse($('set-time').hidden);
-
-  // Hide button.
-  BrowserOptions.setCanSetTime(false);
-  expectTrue($('set-time').hidden);
-});
-
-GEN('#endif');
diff --git a/chrome/browser/ui/webui/options/chromeos/power_overlay_browsertest.js b/chrome/browser/ui/webui/options/chromeos/power_overlay_browsertest.js
deleted file mode 100644
index d49131c..0000000
--- a/chrome/browser/ui/webui/options/chromeos/power_overlay_browsertest.js
+++ /dev/null
@@ -1,175 +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.
-
-GEN_INCLUDE(['../options_browsertest_base.js']);
-
-function PowerOverlayWebUITest() {}
-
-PowerOverlayWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  browsePreload: 'chrome://settings-frame/',
-
-  commandLineSwitches: [{
-    switchName: 'enable-power-overlay',
-  }],
-
-  /** @override */
-  preLoad: function() {
-    this.makeAndRegisterMockHandler([
-      'updatePowerStatus',
-      'setPowerSource',
-    ]);
-    this.mockHandler.expects(atLeastOnce()).updatePowerStatus();
-  },
-
-  /**
-   * Sets power sources using a deep copy of |sources|.
-   * @param {Array<Object>} sources
-   * @param {string} sourceId
-   * @param {bool} isUsbCharger
-   * @param {bool} isCalculating
-   */
-  setPowerSources: function(sources, sourceId, isUsbCharger, isCalculating) {
-    var sourcesCopy = sources.map(function(source) {
-      return Object.assign({}, source);
-    });
-    options.PowerOverlay.setPowerSources(
-        sourcesCopy, sourceId, isUsbCharger, isCalculating);
-  },
-
-  /**
-   * Simulates the user selecting a power source, verifying that the overlay
-   * calls setPowerSource.
-   * @param {string} sourceId
-   */
-  selectPowerSource: function(sourceId) {
-    this.mockHandler.expects(once()).setPowerSource(eq(sourceId));
-    $('power-source-dropdown').value = sourceId;
-    expectTrue(cr.dispatchSimpleEvent($('power-source-dropdown'), 'change'));
-  },
-
-  /**
-   * Checks that the sources dropdown is visible.
-   * @param {string} sourceId The ID of the source that should be selected.
-   */
-  checkSource: function(sourceId) {
-    expectTrue($('power-source-charger').hidden);
-    expectFalse($('power-sources').hidden);
-    expectEquals(sourceId, $('power-source-dropdown').value);
-  },
-
-  checkNoSources: function() {
-    expectTrue($('power-source-charger').hidden);
-    expectTrue($('power-sources').hidden);
-  },
-
-  checkDedicatedCharger: function() {
-    expectFalse($('power-source-charger').hidden);
-    expectTrue($('power-sources').hidden);
-  },
-};
-
-TEST_F('PowerOverlayWebUITest', 'testNoPowerSources', function() {
-  assertEquals(this.browsePreload, document.location.href);
-  this.mockHandler.expects(never()).setPowerSource();
-  $('power-settings-link').click();
-
-  // This should be the initial state.
-  this.checkNoSources();
-
-  // Setting an empty sources list shouldn't change the state.
-  this.setPowerSources([], '', false, false);
-  this.checkNoSources();
-});
-
-TEST_F('PowerOverlayWebUITest', 'testDedicatedCharger', function() {
-  assertEquals(this.browsePreload, document.location.href);
-  this.mockHandler.expects(never()).setPowerSource();
-  $('power-settings-link').click();
-
-  var fakeSources = [{
-    id: 'source1',
-    description: 'Left port',
-    type: options.PowerStatusDeviceType.DEDICATED_CHARGER,
-  }];
-
-  this.setPowerSources(fakeSources, 'source1', false, false);
-  this.checkDedicatedCharger();
-
-  // Remove the charger.
-  this.setPowerSources([], '');
-  this.checkNoSources();
-
-  // Set a low-powered charger.
-  this.setPowerSources(fakeSources, 'source1', true, false);
-  this.checkDedicatedCharger();
-});
-
-TEST_F('PowerOverlayWebUITest', 'testSingleSource', function() {
-  assertEquals(this.browsePreload, document.location.href);
-  $('power-settings-link').click();
-
-  var fakeSources = [{
-    id: 'source1',
-    description: 'Left port',
-    type: options.PowerStatusDeviceType.DUAL_ROLE_USB,
-  }];
-
-  this.setPowerSources(fakeSources, '', false, false);
-  this.checkSource('');
-
-  this.selectPowerSource('source1');
-  this.checkSource('source1');
-
-  // Remove the device.
-  this.setPowerSources([], '', false, false);
-  this.checkNoSources();
-});
-
-TEST_F('PowerOverlayWebUITest', 'testMultipleSources', function() {
-  assertEquals(this.browsePreload, document.location.href);
-  $('power-settings-link').click();
-
-  var fakeSources = [{
-    id: 'source1',
-    description: 'Left port',
-    type: options.PowerStatusDeviceType.DUAL_ROLE_USB,
-  }, {
-    id: 'source2',
-    description: 'Right port',
-    type: options.PowerStatusDeviceType.DUAL_ROLE_USB,
-  }, {
-    id: 'source3',
-    description: 'Front port',
-    type: options.PowerStatusDeviceType.DUAL_ROLE_USB,
-  }, {
-    id: 'source4',
-    description: 'Rear port',
-    type: options.PowerStatusDeviceType.DUAL_ROLE_USB,
-  }];
-
-  // Use a dual-role device.
-  this.setPowerSources(fakeSources, 'source2', false, false);
-  this.checkSource('source2');
-
-  // Use a USB charger.
-  this.setPowerSources(fakeSources, 'source3', true, false);
-  this.checkSource('source3');
-
-  // Remove the currently used device.
-  fakeSources.splice(2, 1);
-  this.setPowerSources(fakeSources, 'source4', false, false);
-  this.checkSource('source4');
-
-  // Do not charge (use battery).
-  this.setPowerSources(fakeSources, '', false, false);
-  this.checkSource('');
-
-  // The user selects a device.
-  this.selectPowerSource('source1');
-
-  // The user selects the battery.
-  this.selectPowerSource('');
-});
diff --git a/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc b/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc
deleted file mode 100644
index 7e7b7fa..0000000
--- a/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc
+++ /dev/null
@@ -1,467 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stddef.h>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/login/login_manager_test.h"
-#include "chrome/browser/chromeos/login/startup_utils.h"
-#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/settings/cros_settings_names.h"
-#if defined(GOOGLE_CHROME_BUILD)
-#include "components/spellcheck/browser/pref_names.h"
-#endif
-#include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "components/user_manager/user_manager.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/test_utils.h"
-
-namespace chromeos {
-
-namespace {
-
-// Because policy is not needed in this test it is better to use e-mails that
-// are definitely not enterprise. This lets us to avoid faking of policy fetch
-// procedure.
-const char* kTestOwner = "test-owner@gmail.com";
-const char* kTestNonOwner = "test-user1@gmail.com";
-
-const char* kKnownSettings[] = {
-  kDeviceOwner,
-  kAccountsPrefAllowGuest,
-  kAccountsPrefAllowNewUser,
-  kAccountsPrefDeviceLocalAccounts,
-  kAccountsPrefShowUserNamesOnSignIn,
-  kAccountsPrefSupervisedUsersEnabled,
-};
-
-// Stub settings provider that only handles the settings we need to control.
-// StubCrosSettingsProvider handles more settings but leaves many of them unset
-// which the Settings page doesn't expect.
-class StubAccountSettingsProvider : public StubCrosSettingsProvider {
- public:
-  StubAccountSettingsProvider() {
-  }
-
-  ~StubAccountSettingsProvider() override {}
-
-  // StubCrosSettingsProvider implementation.
-  bool HandlesSetting(const std::string& path) const override {
-    const char** end = kKnownSettings + arraysize(kKnownSettings);
-    return std::find(kKnownSettings, end, path) != end;
-  }
-};
-
-struct PrefTest {
-  const char* pref_name;
-  bool owner_only;
-  bool indicator;
-};
-
-const PrefTest kPrefTests[] = {
-  { kSystemTimezone, false, false },
-  { prefs::kUse24HourClock, false, false },
-  { kAttestationForContentProtectionEnabled, true, true },
-  { kAccountsPrefAllowGuest, true, false },
-  { kAccountsPrefAllowNewUser, true, false },
-  { kAccountsPrefShowUserNamesOnSignIn, true, false },
-  { kAccountsPrefSupervisedUsersEnabled, true, false },
-#if defined(GOOGLE_CHROME_BUILD)
-  { kStatsReportingPref, true, true },
-  { spellcheck::prefs::kSpellCheckUseSpellingService, false, false },
-#endif
-};
-
-}  // namespace
-
-class SharedOptionsTest : public LoginManagerTest {
- public:
-  SharedOptionsTest()
-      : LoginManagerTest(false),
-        stub_settings_provider_(base::MakeUnique<StubCrosSettingsProvider>()),
-        stub_settings_provider_ptr_(static_cast<StubCrosSettingsProvider*>(
-            stub_settings_provider_.get())),
-        test_owner_account_id_(AccountId::FromUserEmail(kTestOwner)),
-        test_non_owner_account_id_(AccountId::FromUserEmail(kTestNonOwner)) {
-    stub_settings_provider_->Set(kDeviceOwner, base::Value(kTestOwner));
-  }
-
-  ~SharedOptionsTest() override {}
-
-  void SetUpOnMainThread() override {
-    LoginManagerTest::SetUpOnMainThread();
-
-    CrosSettings* settings = CrosSettings::Get();
-
-    // Add the stub settings provider, moving the device settings provider
-    // behind it so our stub takes precedence.
-    std::unique_ptr<CrosSettingsProvider> device_settings_provider =
-        settings->RemoveSettingsProvider(settings->GetProvider(kDeviceOwner));
-    settings->AddSettingsProvider(std::move(stub_settings_provider_));
-    settings->AddSettingsProvider(std::move(device_settings_provider));
-
-    // Notify ChromeUserManager of ownership change.
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
-        content::Source<SharedOptionsTest>(this),
-        content::NotificationService::NoDetails());
-  }
-
-  void TearDownOnMainThread() override {
-    CrosSettings* settings = CrosSettings::Get();
-    settings->RemoveSettingsProvider(stub_settings_provider_ptr_);
-    LoginManagerTest::TearDownOnMainThread();
-  }
-
- protected:
-  void CheckOptionsUI(const user_manager::User* user,
-                      bool is_owner,
-                      bool is_primary) {
-    ASSERT_NE(nullptr, user);
-    Browser* browser = CreateBrowserForUser(user);
-    content::WebContents* contents =
-        browser->tab_strip_model()->GetActiveWebContents();
-
-    for (size_t i = 0; i < sizeof(kPrefTests) / sizeof(kPrefTests[0]); i++) {
-      bool disabled = !is_owner && kPrefTests[i].owner_only;
-      if (strcmp(kPrefTests[i].pref_name, kSystemTimezone) == 0) {
-        disabled = ProfileHelper::Get()
-                       ->GetProfileByUser(user)
-                       ->GetPrefs()
-                       ->GetBoolean(prefs::kResolveTimezoneByGeolocation);
-      }
-
-      CheckPreference(
-          contents, kPrefTests[i].pref_name, disabled,
-          !is_owner && kPrefTests[i].indicator ? "owner" : std::string());
-    }
-    CheckBanner(contents, is_primary);
-    CheckSharedSections(contents, is_primary);
-    CheckAccountsOverlay(contents, is_owner);
-  }
-
-  // Creates a browser and navigates to the Settings page.
-  Browser* CreateBrowserForUser(const user_manager::User* user) {
-    Profile* profile = ProfileHelper::Get()->GetProfileByUser(user);
-    SigninManagerFactory::GetForProfile(profile)->SetAuthenticatedAccountInfo(
-        GetGaiaIDForUserID(user->GetAccountId().GetUserEmail()),
-        user->GetAccountId().GetUserEmail());
-
-    ui_test_utils::BrowserAddedObserver observer;
-    Browser* browser = CreateBrowser(profile);
-    observer.WaitForSingleNewBrowser();
-
-    ui_test_utils::NavigateToURL(browser,
-                                 GURL("chrome://settings-frame"));
-    return browser;
-  }
-
-  // Verifies a preference's disabled state and controlled-by indicator.
-  void CheckPreference(content::WebContents* contents,
-                       std::string pref_name,
-                       bool disabled,
-                       std::string controlled_by) {
-    bool success;
-    std::string js_expression = base::StringPrintf(
-        "var prefSelector = '[pref=\"%s\"]';"
-        "var controlledBy = '%s';"
-        "var input = document.querySelector("
-        "    'input' + prefSelector + ', select' + prefSelector);"
-        "var success = false;"
-        "if (input) {"
-        "  success = input.disabled == %d;"
-        "  var indicator = input.parentNode.parentNode.querySelector("
-        "      '.controlled-setting-indicator');"
-        "  if (controlledBy) {"
-        "    success = success && indicator &&"
-        "              indicator.getAttribute('controlled-by') == controlledBy;"
-        "  } else {"
-        "    success = success && (!indicator ||"
-        "              !indicator.hasAttribute('controlled-by') ||"
-        "              indicator.getAttribute('controlled-by') == '')"
-        "  }"
-        "}"
-        "window.domAutomationController.send(!!success);",
-        pref_name.c_str(), controlled_by.c_str(), disabled);
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        contents, js_expression, &success));
-    EXPECT_TRUE(success);
-  }
-
-  // Verifies a checkbox's disabled state, controlled-by indicator and value.
-  void CheckBooleanPreference(content::WebContents* contents,
-                              std::string pref_name,
-                              bool disabled,
-                              std::string controlled_by,
-                              bool expected_value) {
-    CheckPreference(contents, pref_name, disabled, controlled_by);
-    bool actual_value;
-    std::string js_expression = base::StringPrintf(
-        "window.domAutomationController.send(document.querySelector('"
-        "    input[type=\"checkbox\"][pref=\"%s\"]').checked);",
-        pref_name.c_str());
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        contents, js_expression, &actual_value));
-    EXPECT_EQ(expected_value, actual_value);
-  }
-
-  // Verifies that the shared settings banner is visible only for
-  // secondary users.
-  void CheckBanner(content::WebContents* contents,
-                   bool is_primary) {
-    bool banner_visible;
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        contents,
-        "var e = $('secondary-user-banner');"
-        "window.domAutomationController.send(e && !e.hidden);",
-        &banner_visible));
-    EXPECT_EQ(!is_primary, banner_visible);
-  }
-
-  // Verifies that sections of shared settings have the appropriate indicator.
-  void CheckSharedSections(content::WebContents* contents,
-                           bool is_primary) {
-    // This only applies to the Internet options section.
-    std::string controlled_by;
-    ASSERT_TRUE(content::ExecuteScriptAndExtractString(
-        contents,
-        "var e = document.querySelector("
-        "    '#network-section-header span.controlled-setting-indicator');"
-        "if (!e || !e.getAttribute('controlled-by')) {"
-        "  window.domAutomationController.send('');"
-        "} else {"
-        "  window.domAutomationController.send("
-        "      e.getAttribute('controlled-by'));"
-        "}",
-        &controlled_by));
-    EXPECT_EQ(!is_primary ? "shared" : std::string(), controlled_by);
-  }
-
-  // Checks the Accounts header and non-checkbox inputs.
-  void CheckAccountsOverlay(content::WebContents* contents, bool is_owner) {
-    // Set cros.accounts.allowGuest to false so we can test the accounts list.
-    // This has to be done after the PRE_* test or we can't add the owner.
-    stub_settings_provider_ptr_->Set(kAccountsPrefAllowNewUser,
-                                     base::Value(false));
-
-    bool success;
-    std::string js_expression = base::StringPrintf(
-        "var controlled = %d;"
-        "var warning = $('ownerOnlyWarning');"
-        "var userList = $('userList');"
-        "var input = $('userNameEdit');"
-        "var success;"
-        "if (controlled)"
-        "  success = warning && !warning.hidden && userList.disabled &&"
-        "            input.disabled;"
-        "else"
-        "  success = (!warning || warning.hidden) && !userList.disabled &&"
-        "            !input.disabled;"
-        "window.domAutomationController.send(!!success);",
-        !is_owner);
-    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        contents, js_expression, &success));
-    EXPECT_TRUE(success) << "Accounts overlay incorrect for " <<
-        (is_owner ? "owner." : "non-owner.");
-  }
-
-  std::unique_ptr<CrosSettingsProvider> stub_settings_provider_;
-  StubCrosSettingsProvider* stub_settings_provider_ptr_;
-
-  const AccountId test_owner_account_id_;
-  const AccountId test_non_owner_account_id_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SharedOptionsTest);
-};
-
-IN_PROC_BROWSER_TEST_F(SharedOptionsTest, PRE_SharedOptions) {
-  RegisterUser(test_owner_account_id_.GetUserEmail());
-  RegisterUser(test_non_owner_account_id_.GetUserEmail());
-  StartupUtils::MarkOobeCompleted();
-}
-
-IN_PROC_BROWSER_TEST_F(SharedOptionsTest, SharedOptions) {
-  // Log in the owner first, then add a secondary user.
-  LoginUser(test_owner_account_id_.GetUserEmail());
-  UserAddingScreen::Get()->Start();
-  content::RunAllPendingInMessageLoop();
-  AddUser(test_non_owner_account_id_.GetUserEmail());
-
-  user_manager::UserManager* manager = user_manager::UserManager::Get();
-  ASSERT_EQ(2u, manager->GetLoggedInUsers().size());
-  {
-    SCOPED_TRACE("Checking settings for owner, primary user.");
-    CheckOptionsUI(manager->FindUser(manager->GetOwnerAccountId()), true, true);
-  }
-  {
-    SCOPED_TRACE("Checking settings for non-owner, secondary user.");
-    CheckOptionsUI(manager->FindUser(test_non_owner_account_id_), false, false);
-  }
-  // TODO(michaelpg): Add tests for non-primary owner and primary non-owner
-  // when the owner-only multiprofile restriction is removed, probably M38.
-}
-
-IN_PROC_BROWSER_TEST_F(SharedOptionsTest, PRE_ScreenLockPreferencePrimary) {
-  RegisterUser(test_owner_account_id_.GetUserEmail());
-  RegisterUser(test_non_owner_account_id_.GetUserEmail());
-  StartupUtils::MarkOobeCompleted();
-}
-
-// Tests the shared setting indicator for the primary user's auto-lock setting
-// when the secondary user has enabled or disabled their preference.
-// (The checkbox is unset if the current user's preference is false, but if any
-// other signed-in user has enabled this preference, the shared setting
-// indicator explains this.)
-IN_PROC_BROWSER_TEST_F(SharedOptionsTest, ScreenLockPreferencePrimary) {
-  LoginUser(test_owner_account_id_.GetUserEmail());
-  UserAddingScreen::Get()->Start();
-  content::RunAllPendingInMessageLoop();
-  AddUser(test_non_owner_account_id_.GetUserEmail());
-
-  user_manager::UserManager* manager = user_manager::UserManager::Get();
-  const user_manager::User* user1 = manager->FindUser(test_owner_account_id_);
-  const user_manager::User* user2 =
-      manager->FindUser(test_non_owner_account_id_);
-
-  PrefService* prefs1 =
-      ProfileHelper::Get()->GetProfileByUser(user1)->GetPrefs();
-  PrefService* prefs2 =
-      ProfileHelper::Get()->GetProfileByUser(user2)->GetPrefs();
-
-  // Set both users' preference to false, then change the secondary user's to
-  // true. We'll do the opposite in the next test. Doesn't provide 100% coverage
-  // but reloading the settings page is super slow on debug builds.
-  prefs1->SetBoolean(prefs::kEnableAutoScreenLock, false);
-  prefs2->SetBoolean(prefs::kEnableAutoScreenLock, false);
-
-  Browser* browser = CreateBrowserForUser(user1);
-  content::WebContents* contents =
-      browser->tab_strip_model()->GetActiveWebContents();
-
-  bool disabled = false;
-  bool expected_value;
-  std::string empty_controlled;
-  std::string shared_controlled("shared");
-
-  {
-    SCOPED_TRACE("Screen lock false for both users");
-    expected_value = false;
-    CheckBooleanPreference(contents, prefs::kEnableAutoScreenLock, disabled,
-                           empty_controlled, expected_value);
-  }
-
-  // Set the secondary user's preference to true, and reload the primary user's
-  // browser to see the updated controlled-by indicator.
-  prefs2->SetBoolean(prefs::kEnableAutoScreenLock, true);
-  chrome::Reload(browser, WindowOpenDisposition::CURRENT_TAB);
-  content::WaitForLoadStop(contents);
-  {
-    SCOPED_TRACE("Screen lock false for primary user");
-    expected_value = false;
-    CheckBooleanPreference(contents, prefs::kEnableAutoScreenLock, disabled,
-                           shared_controlled, expected_value);
-  }
-
-  // Set the preference to true for the primary user and check that the
-  // indicator disappears.
-  prefs1->SetBoolean(prefs::kEnableAutoScreenLock, true);
-  {
-    SCOPED_TRACE("Screen lock true for both users");
-    expected_value = true;
-    CheckBooleanPreference(contents, prefs::kEnableAutoScreenLock, disabled,
-                           empty_controlled, expected_value);
-  }
-}
-
-IN_PROC_BROWSER_TEST_F(SharedOptionsTest, PRE_ScreenLockPreferenceSecondary) {
-  RegisterUser(test_owner_account_id_.GetUserEmail());
-  RegisterUser(test_non_owner_account_id_.GetUserEmail());
-  StartupUtils::MarkOobeCompleted();
-}
-
-// Tests the shared setting indicator for the secondary user's auto-lock setting
-// when the primary user has enabled or disabled their preference.
-// (The checkbox is unset if the current user's preference is false, but if any
-// other signed-in user has enabled this preference, the shared setting
-// indicator explains this.)
-IN_PROC_BROWSER_TEST_F(SharedOptionsTest, ScreenLockPreferenceSecondary) {
-  LoginUser(test_owner_account_id_.GetUserEmail());
-  UserAddingScreen::Get()->Start();
-  content::RunAllPendingInMessageLoop();
-  AddUser(test_non_owner_account_id_.GetUserEmail());
-
-  user_manager::UserManager* manager = user_manager::UserManager::Get();
-  const user_manager::User* user1 = manager->FindUser(test_owner_account_id_);
-  const user_manager::User* user2 =
-      manager->FindUser(test_non_owner_account_id_);
-
-  PrefService* prefs1 =
-      ProfileHelper::Get()->GetProfileByUser(user1)->GetPrefs();
-  PrefService* prefs2 =
-      ProfileHelper::Get()->GetProfileByUser(user2)->GetPrefs();
-
-  // Set both users' preference to true, then change the secondary user's to
-  // false.
-  prefs1->SetBoolean(prefs::kEnableAutoScreenLock, true);
-  prefs2->SetBoolean(prefs::kEnableAutoScreenLock, true);
-
-  Browser* browser = CreateBrowserForUser(user2);
-  content::WebContents* contents =
-      browser->tab_strip_model()->GetActiveWebContents();
-
-  bool disabled = false;
-  bool expected_value;
-  std::string empty_controlled;
-  std::string shared_controlled("shared");
-
-  {
-    SCOPED_TRACE("Screen lock true for both users");
-    expected_value = true;
-    CheckBooleanPreference(contents, prefs::kEnableAutoScreenLock, disabled,
-                           empty_controlled, expected_value);
-  }
-
-  // Set the secondary user's preference to false and check that the
-  // controlled-by indicator is shown.
-  prefs2->SetBoolean(prefs::kEnableAutoScreenLock, false);
-  {
-    SCOPED_TRACE("Screen lock false for secondary user");
-    expected_value = false;
-    CheckBooleanPreference(contents, prefs::kEnableAutoScreenLock, disabled,
-                           shared_controlled, expected_value);
-  }
-
-  // Set the preference to false for the primary user and check that the
-  // indicator disappears.
-  prefs1->SetBoolean(prefs::kEnableAutoScreenLock, false);
-  chrome::Reload(browser, WindowOpenDisposition::CURRENT_TAB);
-  content::WaitForLoadStop(contents);
-  {
-    SCOPED_TRACE("Screen lock false for both users");
-    expected_value = false;
-    CheckBooleanPreference(contents, prefs::kEnableAutoScreenLock, disabled,
-                           empty_controlled, expected_value);
-  }
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/options/content_options_browsertest.js b/chrome/browser/ui/webui/options/content_options_browsertest.js
deleted file mode 100644
index 863fb28f..0000000
--- a/chrome/browser/ui/webui/options/content_options_browsertest.js
+++ /dev/null
@@ -1,27 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * TestFixture for content options WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function ContentOptionsWebUITest() {}
-
-ContentOptionsWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Browse to content options.
-   * @override
-   */
-  browsePreload: 'chrome://settings-frame/content',
-};
-
-// Test opening the content options has correct location.
-TEST_F('ContentOptionsWebUITest', 'testOpenContentOptions', function() {
-  assertEquals(this.browsePreload, document.location.href);
-});
diff --git a/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js b/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js
deleted file mode 100644
index 7cfc1ed..0000000
--- a/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js
+++ /dev/null
@@ -1,109 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * TestFixture for content settings exception area WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function ContentSettingsExceptionAreaWebUITest() {}
-
-ContentSettingsExceptionAreaWebUITest.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://settings-frame/contentExceptions',
-};
-
-// See crbug.com/579666 for OS_LINUX and crbug.com/588586 for Windows and
-// crbug.com/718947 for Mac.
-GEN('#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN) || ' +
-        'defined(OS_MACOSX)');
-GEN('#define MAYBE_testOpenContentSettingsExceptionArea ' +
-        'DISABLED_testOpenContentSettingsExceptionArea');
-GEN('#else');
-GEN('#define MAYBE_testOpenContentSettingsExceptionArea ' +
-        'testOpenContentSettingsExceptionArea');
-GEN('#endif  // defined(OS_CHROMEOS) || defined(OS_LINUX)');
-// Test opening the content settings exception area has correct location.
-TEST_F('ContentSettingsExceptionAreaWebUITest',
-       'MAYBE_testOpenContentSettingsExceptionArea', function() {
-  assertEquals(this.browsePreload, document.location.href);
-});
-
-/**
- * A class to asynchronously test the content settings exception area dialog.
- * @extends {testing.Test}
- * @constructor
- */
-function ContentSettingsExceptionsAreaAsyncWebUITest() {}
-
-ContentSettingsExceptionsAreaAsyncWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://settings-frame/contentExceptions',
-
-  /** @override */
-  isAsync: true,
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    // Enable when failure is resolved.
-    // AX_TEXT_01: http://crbug.com/570562
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'controlsWithoutLabel',
-        '#content-settings-exceptions-area > .content-area > *');
-
-    // Enable when failure is resolved.
-    // AX_TEXT_04: http://crbug.com/570563
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'linkWithUnclearPurpose',
-        '#content-settings-exceptions-area > .action-area > *');
-  },
-};
-
-// Adds and removes a location content setting exception.
-TEST_F('ContentSettingsExceptionsAreaAsyncWebUITest',
-       'testAddRemoveLocationExceptions', function() {
-  assertEquals(this.browsePreload, document.location.href);
-
-  /** @const */ var origin = 'http://google.com:80';
-  /** @const */ var setExceptions = ContentSettings.setExceptions;
-
-  var list = ContentSettings.getExceptionsList('cookies', 'normal');
-  assertEquals(1, list.items.length);
-
-  var setExceptionsCounter = 0;
-  var setExceptionsCallback = function() {
-    setExceptionsCounter++;
-    if (setExceptionsCounter == 1) {
-      // The first item is now the exception (edit items are always last).
-      expectEquals('block', list.dataModel.item(0).setting);
-      expectEquals(origin, list.dataModel.item(0).origin);
-
-      // Delete the item and verify it worked.
-      list.deleteItemAtIndex(0);
-    } else if (setExceptionsCounter == 2) {
-      // Verify the item was deleted, restore the original method, and finish.
-      expectEquals(1, list.items.length);
-      ContentSettings.setExceptions = setExceptions;
-      testDone();
-    }
-  };
-
-  // NOTE: if this test doesn't succeed, |ContentSettings.setExceptions| may not
-  // be restored to its original method. I know no easy way to fix this.
-  ContentSettings.setExceptions = function() {
-    setExceptions.apply(ContentSettings, arguments);
-    setExceptionsCallback();
-  };
-
-  // Add an item to the location exception area to start the test.
-  list.items[0].finishEdit(origin, 'block');
-});
diff --git a/chrome/browser/ui/webui/options/cookies_view_browsertest.js b/chrome/browser/ui/webui/options/cookies_view_browsertest.js
deleted file mode 100644
index e2c094d..0000000
--- a/chrome/browser/ui/webui/options/cookies_view_browsertest.js
+++ /dev/null
@@ -1,60 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * TestFixture for cookies view WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function CookiesViewWebUITest() {}
-
-CookiesViewWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Browse to the cookies view.
-   */
-  browsePreload: 'chrome://settings-frame/cookies',
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    // Enable when failure is resolved.
-    // AX_TEXT_01: http://crbug.com/570560
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'controlsWithoutLabel',
-        '#cookies-view-page > .content-area.cookies-list-content-area > *');
-
-    var requiredOwnedAriaRoleMissingSelectors = [
-        '#default-search-engine-list',
-        '#other-search-engine-list',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_ARIA_08: http://crbug.com/605689
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'requiredOwnedAriaRoleMissing',
-        requiredOwnedAriaRoleMissingSelectors);
-  },
-};
-
-// Test opening the cookies view has correct location.
-TEST_F('CookiesViewWebUITest', 'testOpenCookiesView', function() {
-  assertEquals(this.browsePreload, document.location.href);
-});
-
-TEST_F('CookiesViewWebUITest', 'testNoCloseOnSearchEnter', function() {
-  var cookiesView = CookiesView.getInstance();
-  assertTrue(cookiesView.visible);
-  var searchBox = cookiesView.pageDiv.querySelector('.cookies-search-box');
-  searchBox.dispatchEvent(new KeyboardEvent('keydown', {
-    'bubbles': true,
-    'cancelable': true,
-    'key': 'Enter'
-  }));
-  assertTrue(cookiesView.visible);
-});
diff --git a/chrome/browser/ui/webui/options/edit_dictionary_browsertest.js b/chrome/browser/ui/webui/options/edit_dictionary_browsertest.js
deleted file mode 100644
index 5bcb0e0b..0000000
--- a/chrome/browser/ui/webui/options/edit_dictionary_browsertest.js
+++ /dev/null
@@ -1,166 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * TestFixture for EditDictionaryOverlay WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function EditDictionaryWebUITest() {}
-
-EditDictionaryWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Browse to the edit dictionary page & call our preLoad().
-   */
-  browsePreload: 'chrome://settings-frame/editDictionary',
-
-  /**
-   * Register a mock dictionary handler.
-   */
-  preLoad: function() {
-    this.makeAndRegisterMockHandler(
-        ['refreshDictionaryWords',
-         'addDictionaryWord',
-         'removeDictionaryWord',
-        ]);
-    this.mockHandler.stubs().refreshDictionaryWords().
-        will(callFunction(function() {
-          EditDictionaryOverlay.setWordList([]);
-        }));
-    this.mockHandler.stubs().addDictionaryWord(ANYTHING);
-    this.mockHandler.stubs().removeDictionaryWord(ANYTHING);
-  },
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    // Enable when failure is resolved.
-    // AX_TEXT_01: http://crbug.com/570556
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'controlsWithoutLabel',
-        '#language-dictionary-overlay-word-list > .deletable-item > *');
-
-    var unsupportedAriaAttributeSelectors = [
-      '#language-dictionary-overlay-word-list',
-      '#language-options-list',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/570559
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        unsupportedAriaAttributeSelectors);
-  },
-};
-
-// Verify that users can add and remove words in the dictionary.
-TEST_F('EditDictionaryWebUITest', 'testAddRemoveWords', function() {
-  var testWord = 'foo';
-  $('language-dictionary-overlay-word-list').querySelector('input').value =
-      testWord;
-
-  this.mockHandler.expects(once()).addDictionaryWord([testWord]).
-      will(callFunction(function() {
-          EditDictionaryOverlay.setWordList([testWord]);
-      }));
-  var addWordItem = EditDictionaryOverlay.getWordListForTesting().items[0];
-  addWordItem.onEditCommitted_({currentTarget: addWordItem});
-
-  this.mockHandler.expects(once()).removeDictionaryWord([testWord]).
-      will(callFunction(function() {
-          EditDictionaryOverlay.setWordList([]);
-      }));
-  EditDictionaryOverlay.getWordListForTesting().deleteItemAtIndex(0);
-});
-
-// Verify that users can search words in the dictionary.
-TEST_F('EditDictionaryWebUITest', 'testSearch', function() {
-  EditDictionaryOverlay.setWordList(['foo', 'bar']);
-  expectEquals(3, EditDictionaryOverlay.getWordListForTesting().items.length);
-
-  /**
-   * @param {Element} el The element to dispatch an event on.
-   * @param {string} value The text of the search event.
-   */
-  var fakeSearchEvent = function(el, value) {
-    el.value = value;
-    cr.dispatchSimpleEvent(el, 'search');
-  };
-  var searchField = $('language-dictionary-overlay-search-field');
-  fakeSearchEvent(searchField, 'foo');
-  expectEquals(2, EditDictionaryOverlay.getWordListForTesting().items.length);
-
-  fakeSearchEvent(searchField, '');
-  expectEquals(3, EditDictionaryOverlay.getWordListForTesting().items.length);
-});
-
-TEST_F('EditDictionaryWebUITest', 'testNoCloseOnSearchEnter', function() {
-  var editDictionaryPage = EditDictionaryOverlay.getInstance();
-  assertTrue(editDictionaryPage.visible);
-  var searchField = $('language-dictionary-overlay-search-field');
-  searchField.dispatchEvent(new KeyboardEvent('keydown', {
-    'bubbles': true,
-    'cancelable': true,
-    'key': 'Enter'
-  }));
-  assertTrue(editDictionaryPage.visible);
-});
-
-// Verify that dictionary shows newly added words that arrived in a
-// notification, but ignores duplicate add notifications.
-TEST_F('EditDictionaryWebUITest', 'testAddNotification', function() {
-  // Begin with an empty dictionary.
-  EditDictionaryOverlay.setWordList([]);
-  expectEquals(1, EditDictionaryOverlay.getWordListForTesting().items.length);
-
-  // User adds word 'foo'.
-  EditDictionaryOverlay.getWordListForTesting().addDictionaryWord_('foo');
-  expectEquals(2, EditDictionaryOverlay.getWordListForTesting().items.length);
-
-  // Backend notifies UI that the word 'foo' has been added. UI ignores this
-  // notification, because the word is displayed immediately after user added
-  // it.
-  EditDictionaryOverlay.updateWords(['foo'], []);
-  expectEquals(2, EditDictionaryOverlay.getWordListForTesting().items.length);
-
-  // Backend notifies UI that the words 'bar' and 'baz' were added. UI shows
-  // these new words.
-  EditDictionaryOverlay.updateWords(['bar', 'baz'], []);
-  expectEquals(4, EditDictionaryOverlay.getWordListForTesting().items.length);
-});
-
-// Verify that dictionary hides newly removed words that arrived in a
-// notification, but ignores duplicate remove notifications.
-// TODO(crbug.com/631940): Flaky on Win 7.
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_testRemoveNotification DISABLED_testRemoveNotification');
-GEN('#else');
-GEN('#define MAYBE_testRemoveNotification testRemoveNotification');
-GEN('#endif  // defined(OS_WIN)');
-TEST_F('EditDictionaryWebUITest', 'MAYBE_testRemoveNotification', function() {
-  // Begin with a dictionary with words 'foo', 'bar', 'baz', and 'baz'. The
-  // second instance of 'baz' appears because the user added the word twice.
-  // The backend keeps only one copy of the word.
-  EditDictionaryOverlay.setWordList(['foo', 'bar', 'baz', 'baz']);
-  expectEquals(5, EditDictionaryOverlay.getWordListForTesting().items.length);
-
-  // User deletes the second instance of 'baz'.
-  EditDictionaryOverlay.getWordListForTesting().deleteItemAtIndex(3);
-  expectEquals(4, EditDictionaryOverlay.getWordListForTesting().items.length);
-
-  // Backend notifies UI that the word 'baz' has been removed. UI ignores this
-  // notification.
-  EditDictionaryOverlay.updateWords([], ['baz']);
-  expectEquals(4, EditDictionaryOverlay.getWordListForTesting().items.length);
-
-  // Backend notifies UI that words 'foo' and 'bar' have been removed. UI
-  // removes these words.
-  EditDictionaryOverlay.updateWords([], ['foo', 'bar']);
-  expectEquals(2, EditDictionaryOverlay.getWordListForTesting().items.length);
-});
diff --git a/chrome/browser/ui/webui/options/font_settings_browsertest.js b/chrome/browser/ui/webui/options/font_settings_browsertest.js
deleted file mode 100644
index 6e419a2..0000000
--- a/chrome/browser/ui/webui/options/font_settings_browsertest.js
+++ /dev/null
@@ -1,66 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * TestFixture for font settings WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function FontSettingsWebUITest() {}
-
-FontSettingsWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Browse to the font settings page.
-   */
-  browsePreload: 'chrome://settings-frame/fonts',
-
-  /** @override */
-  preLoad: function() {
-    this.makeAndRegisterMockHandler(['openAdvancedFontSettingsOptions']);
-  },
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    var controlsWithoutLabelSelectors = [
-      '#standard-font-size',
-      '#minimum-font-size',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_TEXT_01: http://crbug.com/570555
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'controlsWithoutLabel',
-        controlsWithoutLabelSelectors);
-  },
-};
-
-// Test opening font settings has correct location.
-TEST_F('FontSettingsWebUITest', 'testOpenFontSettings', function() {
-  assertEquals(this.browsePreload, document.location.href);
-});
-
-// Test setup of the Advanced Font Settings links.
-TEST_F('FontSettingsWebUITest', 'testAdvancedFontSettingsLink', function() {
-  var installElement = $('advanced-font-settings-install');
-  var optionsElement = $('advanced-font-settings-options');
-  var expectedUrl = 'https://chrome.google.com/webstore/detail/' +
-      'caclkomlalccbpcdllchkeecicepbmbm';
-
-  FontSettings.notifyAdvancedFontSettingsAvailability(false);
-  assertFalse(installElement.hidden);
-  assertEquals(expectedUrl, installElement.querySelector('a').href);
-  assertTrue(optionsElement.hidden);
-
-  FontSettings.notifyAdvancedFontSettingsAvailability(true);
-  assertTrue(installElement.hidden);
-  assertFalse(optionsElement.hidden);
-  this.mockHandler.expects(once()).openAdvancedFontSettingsOptions();
-  optionsElement.click();
-});
diff --git a/chrome/browser/ui/webui/options/font_settings_utils_unittest.cc b/chrome/browser/ui/webui/options/font_settings_utils_unittest.cc
deleted file mode 100644
index 2c274d1..0000000
--- a/chrome/browser/ui/webui/options/font_settings_utils_unittest.cc
+++ /dev/null
@@ -1,30 +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.
-
-#include "chrome/browser/ui/webui/options/font_settings_utils.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace options {
-
-TEST(FontSettingsUtilitiesTest, ResolveFontList) {
-  EXPECT_TRUE(FontSettingsUtilities::ResolveFontList("").empty());
-
-  // Returns the first available font if starts with ",".
-  EXPECT_EQ("Arial",
-            FontSettingsUtilities::ResolveFontList(",not exist, Arial"));
-
-  // Returns the first font if no fonts are available.
-  EXPECT_EQ("not exist",
-            FontSettingsUtilities::ResolveFontList(",not exist, not exist 2"));
-
-  // Otherwise returns any strings as they were set.
-  std::string non_lists[] = {
-      "Arial", "not exist", "not exist, Arial",
-  };
-  for (const std::string& name : non_lists)
-    EXPECT_EQ(name, FontSettingsUtilities::ResolveFontList(name));
-}
-
-}  // namespace options
diff --git a/chrome/browser/ui/webui/options/language_options_browsertest.js b/chrome/browser/ui/webui/options/language_options_browsertest.js
deleted file mode 100644
index bfd3acb6..0000000
--- a/chrome/browser/ui/webui/options/language_options_browsertest.js
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * TestFixture for language options WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function LanguageOptionsWebUITest() {}
-
-LanguageOptionsWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://settings-frame/languages',
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/559266
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        '#language-options-list');
-
-    // Enable when failure is resolved.
-    // AX_TEXT_04: http://crbug.com/559271
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'linkWithUnclearPurpose',
-        '#languagePage > .content-area > .language-options-header > A');
-  }
-};
-
-// Test opening language options has correct location.
-TEST_F('LanguageOptionsWebUITest', 'testOpenLanguageOptions', function() {
-  assertEquals(this.browsePreload, document.location.href);
-});
-
-GEN('#if defined(OS_WIN) || defined(OS_CHROMEOS)');
-// Test reselecting the same language as the current UI locale. This should show
-// a "Chrome is displayed in this language" message rather than a restart banner
-// or a [ Display Chrome in this language ] button.
-TEST_F('LanguageOptionsWebUITest', 'reselectUILocale', function() {
-  var currentLang = loadTimeData.getString('currentUiLanguageCode');
-  $('language-options-list').selectLanguageByCode(currentLang);
-  LanguageOptions.uiLanguageSaved(currentLang);
-
-  expectTrue($('language-options-ui-language-button').hidden);
-  expectFalse($('language-options-ui-language-message').hidden);
-  expectTrue($('language-options-ui-notification-bar').hidden);
-});
-GEN('#endif');  // defined(OS_WIN) || defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/options/language_options_dictionary_download_browsertest.js b/chrome/browser/ui/webui/options/language_options_dictionary_download_browsertest.js
deleted file mode 100644
index 174b323..0000000
--- a/chrome/browser/ui/webui/options/language_options_dictionary_download_browsertest.js
+++ /dev/null
@@ -1,129 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * TestFixture for testing messages of dictionary download progress in language
- * options WebUI.
- * @extends {testing.Test}
- * @constructor
- */
-function LanguagesOptionsDictionaryDownloadWebUITest() {}
-
-LanguagesOptionsDictionaryDownloadWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Browse to languages options.
-   */
-  browsePreload: 'chrome://settings-frame/languages',
-
-  /**
-   * Register a mock dictionary handler.
-   */
-  preLoad: function() {
-    this.makeAndRegisterMockHandler(['retryDictionaryDownload']);
-    this.mockHandler.stubs().retryDictionaryDownload().
-        will(callFunction(function() {
-          options.LanguageOptions.onDictionaryDownloadBegin('en-US');
-        }));
-  },
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/570554
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        '#language-options-list');
-
-    // Enable when failure is resolved.
-    // AX_TEXT_04: http://crbug.com/570553
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'linkWithUnclearPurpose',
-        '#languagePage > .content-area > .language-options-header > A');
-  },
-};
-
-// Verify that dictionary download success does not show, "This language can't
-// be used for spellchecking." or "Download failed."
-// Disabled due to flakiness (crbug.com/616550).
-TEST_F('LanguagesOptionsDictionaryDownloadWebUITest',
-       'DISABLED_testdictionaryDownloadSuccess',
-       function() {
-  options.LanguageOptions.onDictionaryDownloadSuccess('en-US');
-  expectTrue($('spellcheck-language-message').hidden);
-  expectTrue($('language-options-dictionary-downloading-message').hidden);
-  expectTrue($('language-options-dictionary-download-failed-message').hidden);
-  expectTrue(
-      $('language-options-dictionary-download-fail-help-message').hidden);
-});
-
-// Verify that dictionary download in progress shows 'Downloading spell check
-// language' message.
-// Disabled due to flakiness (crbug.com/616550).
-TEST_F('LanguagesOptionsDictionaryDownloadWebUITest',
-       'DISABLED_testdictionaryDownloadProgress',
-       function() {
-  options.LanguageOptions.onDictionaryDownloadBegin('en-US');
-  expectTrue($('spellcheck-language-message').hidden);
-  expectFalse($('language-options-dictionary-downloading-message').hidden);
-  expectTrue($('language-options-dictionary-download-failed-message').hidden);
-  expectTrue(
-      $('language-options-dictionary-download-fail-help-message').hidden);
-});
-
-// Verify that failure in dictionary download shows 'Dictionary download failed'
-// message.
-TEST_F('LanguagesOptionsDictionaryDownloadWebUITest',
-       'testdictionaryDownloadFailed',
-       function() {
-  // Clear the failure counter:
-  options.LanguageOptions.onDictionaryDownloadSuccess('en-US');
-
-  // First failure shows a short error message.
-  options.LanguageOptions.onDictionaryDownloadFailure('en-US');
-  expectTrue($('spellcheck-language-message').hidden);
-  expectTrue($('language-options-dictionary-downloading-message').hidden);
-  expectFalse($('language-options-dictionary-download-failed-message').hidden);
-  expectTrue(
-      $('language-options-dictionary-download-fail-help-message').hidden);
-
-  // Second and all following failures show a longer error message.
-  options.LanguageOptions.onDictionaryDownloadFailure('en-US');
-  expectTrue($('spellcheck-language-message').hidden);
-  expectTrue($('language-options-dictionary-downloading-message').hidden);
-  expectFalse($('language-options-dictionary-download-failed-message').hidden);
-  expectFalse(
-      $('language-options-dictionary-download-fail-help-message').hidden);
-
-  options.LanguageOptions.onDictionaryDownloadFailure('en-US');
-  expectTrue($('spellcheck-language-message').hidden);
-  expectTrue($('language-options-dictionary-downloading-message').hidden);
-  expectFalse($('language-options-dictionary-download-failed-message').hidden);
-  expectFalse(
-      $('language-options-dictionary-download-fail-help-message').hidden);
-});
-
-// Verify that clicking the retry button calls the handler.
-// This test is flaky on Windows. https://crbug.com/616791
-GEN('#if defined(OS_WIN)');
-GEN('#define MAYBE_testdictionaryDownloadRetry ' +
-    'DISABLED_testdictionaryDownloadRetry');
-GEN('#else');
-GEN('#define MAYBE_testdictionaryDownloadRetry testdictionaryDownloadRetry');
-GEN('#endif  // defined(OS_WIN)');
-TEST_F('LanguagesOptionsDictionaryDownloadWebUITest',
-       'MAYBE_testdictionaryDownloadRetry',
-       function() {
-  this.mockHandler.expects(once()).retryDictionaryDownload('en-US').
-      will(callFunction(function() {
-        options.LanguageOptions.onDictionaryDownloadBegin('en-US');
-      }));
-  options.LanguageOptions.onDictionaryDownloadFailure('en-US');
-  $('dictionary-download-retry-button').click();
-});
diff --git a/chrome/browser/ui/webui/options/language_options_handler_unittest.cc b/chrome/browser/ui/webui/options/language_options_handler_unittest.cc
deleted file mode 100644
index e290a98..0000000
--- a/chrome/browser/ui/webui/options/language_options_handler_unittest.cc
+++ /dev/null
@@ -1,28 +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/ui/webui/options/language_options_handler.h"
-
-#include <string>
-
-#include "base/values.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if !defined(OS_MACOSX)
-TEST(LanguageOptionsHandlerTest, GetUILanguageCodeSet) {
-  std::unique_ptr<base::DictionaryValue> dictionary(
-      options::LanguageOptionsHandler::GetUILanguageCodeSet());
-  EXPECT_TRUE(dictionary->HasKey("en-US"));
-  // Note that we don't test a false case, as such an expectation will
-  // fail when we add support for the language.
-  // EXPECT_FALSE(dictionary->HasKey("no"));
-}
-#endif  // !defined(OS_MACOSX)
-
-TEST(LanguageOptionsHandlerTest, GetSpellCheckLanguageCodeSet) {
-  std::unique_ptr<base::DictionaryValue> dictionary(
-      options::LanguageOptionsHandler::GetSpellCheckLanguageCodeSet());
-  EXPECT_TRUE(dictionary->HasKey("en-US"));
-}
diff --git a/chrome/browser/ui/webui/options/manage_profile_browsertest.js b/chrome/browser/ui/webui/options/manage_profile_browsertest.js
deleted file mode 100644
index d4144e0..0000000
--- a/chrome/browser/ui/webui/options/manage_profile_browsertest.js
+++ /dev/null
@@ -1,672 +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.
-
-// None of these tests is relevant for Chrome OS.
-GEN('#if !defined(OS_CHROMEOS)');
-
-/**
- * TestFixture for ManageProfileOverlay and CreateProfileOverlay WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function ManageProfileUITest() {}
-
-ManageProfileUITest.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://settings-frame/manageProfile',
-
-  /**
-   * No need to run these for every OptionsPage test, since they'll cover the
-   * whole consolidated page each time.
-   * @override
-   */
-  runAccessibilityChecks: false,
-
-  /**
-   * Some default profile infos.
-   */
-  defaultIconURLs: [],
-  defaultNames: [],
-
-  /**
-   * Returns a test profile-info object with configurable "supervised" status.
-   * @param {boolean} supervised If true, the test profile will be marked as
-   *     supervised.
-   * @return {Object} A test profile-info object.
-   */
-  testProfileInfo_: function(supervised) {
-    return {
-      name: 'Test Profile',
-      iconURL: 'chrome://path/to/icon/image',
-      filePath: '/path/to/profile/data/on/disk',
-      isCurrentProfile: true,
-      isSupervised: supervised
-    };
-  },
-
-  /**
-   * Overrides WebUI methods that provide profile info, making them return a
-   * test profile-info object.
-   * @param {boolean} supervised Whether the test profile should be marked
-   *     as supervised.
-   * @param {string} mode The mode of the overlay (either 'manage' or 'create').
-   */
-  setProfileSupervised_: function(supervised, mode) {
-    // Override the BrowserOptions method to return the fake info.
-    BrowserOptions.getCurrentProfile = function() {
-      return this.testProfileInfo_(supervised);
-    }.bind(this);
-    // Set the profile info in the overlay.
-    ManageProfileOverlay.setProfileInfo(this.testProfileInfo_(supervised),
-                                        mode);
-  },
-
-  /**
-   * Set some default profile infos (icon URLs and names).
-   * @param {boolean} supervised Whether the test profile should be marked as
-   *     supervised.
-   * @param {string} mode The mode of the overlay (either 'manage' or 'create').
-   */
-  initDefaultProfiles_: function(mode) {
-    PageManager.showPageByName(mode + 'Profile');
-
-    var defaultProfile = {
-      name: 'Default Name',
-      iconURL: '/default/path',
-    };
-    this.defaultIconURLs = ['/some/path',
-                            defaultProfile.iconURL,
-                            '/another/path',
-                            '/one/more/path'];
-    this.defaultNames = ['Some Name', defaultProfile.name, '', 'Another Name'];
-    ManageProfileOverlay.receiveDefaultProfileIconsAndNames(
-        mode, this.defaultIconURLs, this.defaultNames);
-    ManageProfileOverlay.receiveNewProfileDefaults(defaultProfile);
-
-    // Make sure the correct item in the icon grid was selected.
-    var gridEl = $(mode + '-profile-icon-grid');
-    expectEquals(defaultProfile.iconURL, gridEl.selectedItem);
-  },
-};
-
-// Receiving the new profile defaults in the manage-user overlay shouldn't mess
-// up the focus in a visible higher-level overlay.
-TEST_F('ManageProfileUITest', 'NewProfileDefaultsFocus', function() {
-  var self = this;
-
-  function checkFocus(pageName, expectedFocus, initialFocus) {
-    PageManager.showPageByName(pageName);
-    initialFocus.focus();
-    expectEquals(initialFocus, document.activeElement, pageName);
-
-    ManageProfileOverlay.receiveNewProfileDefaults(
-        self.testProfileInfo_(false));
-    expectEquals(expectedFocus, document.activeElement, pageName);
-    PageManager.closeOverlay();
-  }
-
-  // Receiving new profile defaults sets focus to the name field if the create
-  // overlay is open, and should not change focus at all otherwise.
-  checkFocus('manageProfile',
-             $('manage-profile-cancel'),
-             $('manage-profile-cancel'));
-  checkFocus('createProfile',
-             $('create-profile-name'),
-             $('create-profile-cancel'));
-  checkFocus('supervisedUserLearnMore',
-             $('supervised-user-learn-more-done'),
-             $('supervised-user-learn-more-done'));
-  checkFocus('supervisedUserLearnMore',
-             document.querySelector('#supervised-user-learn-more-text a'),
-             document.querySelector('#supervised-user-learn-more-text a'));
-});
-
-// The default options should be reset each time the creation overlay is shown.
-TEST_F('ManageProfileUITest', 'DefaultCreateOptions', function() {
-  PageManager.showPageByName('createProfile');
-  var shortcutsAllowed = loadTimeData.getBoolean('profileShortcutsEnabled');
-  var createShortcut = $('create-shortcut');
-  var createSupervised = $('create-profile-supervised');
-  assertEquals(shortcutsAllowed, createShortcut.checked);
-  assertFalse(createSupervised.checked);
-
-  createShortcut.checked = !shortcutsAllowed;
-  createSupervised.checked = true;
-  PageManager.closeOverlay();
-  PageManager.showPageByName('createProfile');
-  assertEquals(shortcutsAllowed, createShortcut.checked);
-  assertFalse(createSupervised.checked);
-});
-
-// The checkbox label should change depending on whether the user is signed in.
-TEST_F('ManageProfileUITest', 'CreateSupervisedUserText', function() {
-  var signedInText = $('create-profile-supervised-signed-in');
-  var notSignedInText = $('create-profile-supervised-not-signed-in');
-
-  ManageProfileOverlay.getInstance().initializePage();
-
-  var custodianEmail = 'chrome.playpen.test@gmail.com';
-  CreateProfileOverlay.updateSignedInStatus(custodianEmail);
-  assertEquals(custodianEmail,
-               CreateProfileOverlay.getInstance().signedInEmail_);
-  assertFalse(signedInText.hidden);
-  assertTrue(notSignedInText.hidden);
-  // Make sure the email is in the string somewhere, without depending on the
-  // exact details of the message.
-  assertNotEquals(-1, signedInText.textContent.indexOf(custodianEmail));
-
-  CreateProfileOverlay.updateSignedInStatus('');
-  assertEquals('', CreateProfileOverlay.getInstance().signedInEmail_);
-  assertTrue(signedInText.hidden);
-  assertFalse(notSignedInText.hidden);
-  assertFalse($('create-profile-supervised').checked);
-  assertTrue($('create-profile-supervised').disabled);
-});
-
-function ManageProfileUITestAsync() {}
-
-ManageProfileUITestAsync.prototype = {
-  __proto__: ManageProfileUITest.prototype,
-
-  isAsync: true,
-};
-
-// The import link should show up if the user tries to create a profile with the
-// same name as an existing supervised user profile.
-TEST_F('ManageProfileUITestAsync', 'CreateExistingSupervisedUser', function() {
-  // Initialize the list of existing supervised users.
-  var supervisedUsers = [
-    {
-      id: 'supervisedUser1',
-      name: 'Rosalie',
-      iconURL: 'chrome://path/to/icon/image',
-      onCurrentDevice: false,
-      needAvatar: false
-    },
-    {
-      id: 'supervisedUser2',
-      name: 'Fritz',
-      iconURL: 'chrome://path/to/icon/image',
-      onCurrentDevice: false,
-      needAvatar: true
-    },
-    {
-      id: 'supervisedUser3',
-      name: 'Test',
-      iconURL: 'chrome://path/to/icon/image',
-      onCurrentDevice: true,
-      needAvatar: false
-    },
-    {
-      id: 'supervisedUser4',
-      name: 'RepeatingName',
-      iconURL: 'chrome://path/to/icon/image',
-      onCurrentDevice: true,
-      needAvatar: false
-    },
-    {
-      id: 'supervisedUser5',
-      name: 'RepeatingName',
-      iconURL: 'chrome://path/to/icon/image',
-      onCurrentDevice: false,
-      needAvatar: false
-    }];
-  var promise = Promise.resolve(supervisedUsers);
-  options.SupervisedUserListData.getInstance().promise_ = promise;
-
-  // Initialize the ManageProfileOverlay.
-  ManageProfileOverlay.getInstance().initializePage();
-  var custodianEmail = 'chrome.playpen.test@gmail.com';
-  CreateProfileOverlay.updateSignedInStatus(custodianEmail);
-  assertEquals(custodianEmail,
-               CreateProfileOverlay.getInstance().signedInEmail_);
-  this.setProfileSupervised_(false, 'create');
-
-  // Also add the names 'Test' and 'RepeatingName' to |existingProfileNames_| to
-  // simulate that profiles with those names exist on the device.
-  ManageProfileOverlay.getInstance().existingProfileNames_.Test = true;
-  ManageProfileOverlay.getInstance().existingProfileNames_.RepeatingName = true;
-
-  // Initially, the ok button should be enabled and the import link should not
-  // exist.
-  assertFalse($('create-profile-ok').disabled);
-  assertTrue($('supervised-user-import-existing') == null);
-
-  // Now try to create profiles with the names of existing supervised users.
-  $('create-profile-supervised').checked = true;
-  var nameField = $('create-profile-name');
-  // A profile which already has an avatar.
-  nameField.value = 'Rosalie';
-  ManageProfileOverlay.getInstance().onNameChanged_('create');
-  // Need to wait until the promise resolves.
-  promise.then(function() {
-    assertTrue($('create-profile-ok').disabled);
-    assertFalse($('supervised-user-import-existing') == null);
-
-    // A profile which doesn't have an avatar yet.
-    nameField.value = 'Fritz';
-    ManageProfileOverlay.getInstance().onNameChanged_('create');
-    return options.SupervisedUserListData.getInstance().promise_;
-  }).then(function() {
-    assertTrue($('create-profile-ok').disabled);
-    assertFalse($('supervised-user-import-existing') == null);
-
-    // A profile which already exists on the device.
-    nameField.value = 'Test';
-    ManageProfileOverlay.getInstance().onNameChanged_('create');
-    return options.SupervisedUserListData.getInstance().promise_;
-  }).then(function() {
-    assertTrue($('create-profile-ok').disabled);
-    assertTrue($('supervised-user-import-existing') == null);
-
-    // A supervised user profile that is on the device, but has the same name
-    // as a supervised user profile that is not imported.
-    // This can happen due to a bug (https://crbug.com/557445)
-    nameField.value = 'RepeatingName';
-    ManageProfileOverlay.getInstance().onNameChanged_('create');
-    return options.SupervisedUserListData.getInstance().promise_;
-  }).then(function() {
-    assertTrue($('create-profile-ok').disabled);
-    assertFalse($('supervised-user-import-existing') == null);
-
-    // A profile which does not exist yet.
-    nameField.value = 'NewProfileName';
-    ManageProfileOverlay.getInstance().onNameChanged_('create');
-    return options.SupervisedUserListData.getInstance().promise_;
-  }).then(function() {
-    assertFalse($('create-profile-ok').disabled);
-    assertTrue($('supervised-user-import-existing') == null);
-    testDone();
-  });
-});
-
-// Supervised users should not be able to edit their profile names, and the
-// initial focus should be adjusted accordingly.
-TEST_F('ManageProfileUITest', 'EditSupervisedUserNameAllowed', function() {
-  var nameField = $('manage-profile-name');
-
-  this.setProfileSupervised_(false, 'manage');
-  ManageProfileOverlay.showManageDialog();
-  expectFalse(nameField.disabled);
-  expectEquals(nameField, document.activeElement);
-
-  PageManager.closeOverlay();
-
-  this.setProfileSupervised_(true, 'manage');
-  ManageProfileOverlay.showManageDialog();
-  expectTrue(nameField.disabled);
-  expectEquals($('manage-profile-ok'), document.activeElement);
-});
-
-// Setting profile information should allow the confirmation to be shown.
-TEST_F('ManageProfileUITest', 'ShowCreateConfirmation', function() {
-  var testProfile = this.testProfileInfo_(true);
-  testProfile.custodianEmail = 'foo@bar.example.com';
-  SupervisedUserCreateConfirmOverlay.setProfileInfo(testProfile);
-  assertTrue(SupervisedUserCreateConfirmOverlay.getInstance().canShowPage());
-  PageManager.showPageByName('supervisedUserCreateConfirm', false);
-  assertEquals('supervisedUserCreateConfirm',
-               PageManager.getTopmostVisiblePage().name);
-});
-
-// Trying to show a confirmation dialog with no profile information should fall
-// back to the default (main) settings page.
-TEST_F('ManageProfileUITest', 'NoEmptyConfirmation', function() {
-  assertEquals('manageProfile', PageManager.getTopmostVisiblePage().name);
-  assertFalse(SupervisedUserCreateConfirmOverlay.getInstance().canShowPage());
-  PageManager.showPageByName('supervisedUserCreateConfirm', true);
-  assertEquals('settings', PageManager.getTopmostVisiblePage().name);
-});
-
-// A confirmation dialog should be shown after creating a new supervised user.
-TEST_F('ManageProfileUITest', 'ShowCreateConfirmationOnSuccess', function() {
-  PageManager.showPageByName('createProfile');
-  assertEquals('createProfile', PageManager.getTopmostVisiblePage().name);
-  CreateProfileOverlay.onSuccess(this.testProfileInfo_(false));
-  assertEquals('settings', PageManager.getTopmostVisiblePage().name);
-
-  PageManager.showPageByName('createProfile');
-  assertEquals('createProfile', PageManager.getTopmostVisiblePage().name);
-  CreateProfileOverlay.onSuccess(this.testProfileInfo_(true));
-  assertEquals('supervisedUserCreateConfirm',
-               PageManager.getTopmostVisiblePage().name);
-  expectEquals($('supervised-user-created-switch'), document.activeElement);
-});
-
-// An error should be shown if creating a new supervised user fails.
-TEST_F('ManageProfileUITest', 'NoCreateConfirmationOnError', function() {
-  PageManager.showPageByName('createProfile');
-  assertEquals('createProfile', PageManager.getTopmostVisiblePage().name);
-  var errorBubble = $('create-profile-error-bubble');
-  assertTrue(errorBubble.hidden);
-
-  CreateProfileOverlay.onError('An Error Message!');
-  assertEquals('createProfile', PageManager.getTopmostVisiblePage().name);
-  assertFalse(errorBubble.hidden);
-});
-
-// The name and email should be inserted into the confirmation dialog.
-TEST_F('ManageProfileUITest', 'CreateConfirmationText', function() {
-  var self = this;
-  var custodianEmail = 'foo@example.com';
-
-  // Checks the strings in the confirmation dialog. If |expectedNameText| is
-  // given, it should be present in the dialog's textContent; otherwise the name
-  // is expected. If |expectedNameHtml| is given, it should be present in the
-  // dialog's innerHTML; otherwise the expected text is expected in the HTML
-  // too.
-  function checkDialog(name, expectedNameText, expectedNameHtml) {
-    var expectedText = expectedNameText || name;
-    var expectedHtml = expectedNameHtml || expectedText;
-
-    // Configure the test profile and show the confirmation dialog.
-    var testProfile = self.testProfileInfo_(true);
-    testProfile.name = name;
-    CreateProfileOverlay.onSuccess(testProfile);
-    assertEquals('supervisedUserCreateConfirm',
-                 PageManager.getTopmostVisiblePage().name);
-
-    // Check for the presence of the name and email in the UI, without depending
-    // on the details of the messages.
-    assertNotEquals(-1,
-        $('supervised-user-created-title').textContent.indexOf(expectedText));
-    assertNotEquals(-1,
-        $('supervised-user-created-switch').textContent.indexOf(expectedText));
-    var message = $('supervised-user-created-text');
-    assertNotEquals(-1, message.textContent.indexOf(expectedText));
-    assertNotEquals(-1, message.textContent.indexOf(custodianEmail));
-
-    // The name should be properly HTML-escaped.
-    assertNotEquals(-1, message.innerHTML.indexOf(expectedHtml));
-
-    PageManager.closeOverlay();
-    assertEquals('settings', PageManager.getTopmostVisiblePage().name, name);
-  }
-
-  // Show and configure the create-profile dialog.
-  PageManager.showPageByName('createProfile');
-  CreateProfileOverlay.updateSignedInStatus(custodianEmail);
-  assertEquals('createProfile', PageManager.getTopmostVisiblePage().name);
-
-  checkDialog('OneWord');
-  checkDialog('Multiple Words');
-  checkDialog('It\'s "<HTML> injection" & more!',
-              'It\'s "<HTML> injection" & more!',
-              // The innerHTML getter doesn't escape quotation marks,
-              // independent of whether they were escaped in the setter.
-              'It\'s "&lt;HTML&gt; injection" &amp; more!');
-
-  // Test elision. MAX_LENGTH = 50, minus 1 for the ellipsis.
-  var name49Characters = '0123456789012345678901234567890123456789012345678';
-  var name50Characters = name49Characters + '9';
-  var name51Characters = name50Characters + '0';
-  var name60Characters = name51Characters + '123456789';
-  checkDialog(name49Characters, name49Characters);
-  checkDialog(name50Characters, name50Characters);
-  checkDialog(name51Characters, name49Characters + '\u2026');
-  checkDialog(name60Characters, name49Characters + '\u2026');
-
-  // Test both elision and HTML escaping. The allowed string length is the
-  // visible length, not the length including the entity names.
-  name49Characters = name49Characters.replace('0', '&').replace('1', '>');
-  name60Characters = name60Characters.replace('0', '&').replace('1', '>');
-  var escaped = name49Characters.replace('&', '&amp;').replace('>', '&gt;');
-  checkDialog(
-      name60Characters, name49Characters + '\u2026', escaped + '\u2026');
-});
-
-// The confirmation dialog should close if the new supervised user is deleted.
-TEST_F('ManageProfileUITest', 'CloseConfirmationOnDelete', function() {
-  // Configure the test profile and show the confirmation dialog.
-  var testProfile = this.testProfileInfo_(true);
-  CreateProfileOverlay.onSuccess(testProfile);
-  assertEquals('supervisedUserCreateConfirm',
-               PageManager.getTopmostVisiblePage().name);
-
-  SupervisedUserCreateConfirmOverlay.onDeletedProfile(testProfile.filePath);
-  assertEquals('settings', PageManager.getTopmostVisiblePage().name, name);
-});
-
-// The confirmation dialog should update if the new supervised user's name is
-// changed.
-TEST_F('ManageProfileUITest', 'UpdateConfirmationOnRename', function() {
-  // Configure the test profile and show the confirmation dialog.
-  var testProfile = this.testProfileInfo_(true);
-  CreateProfileOverlay.onSuccess(testProfile);
-  assertEquals('supervisedUserCreateConfirm',
-               PageManager.getTopmostVisiblePage().name);
-
-  var oldName = testProfile.name;
-  var newName = 'New Name';
-  SupervisedUserCreateConfirmOverlay.onUpdatedProfileName(testProfile.filePath,
-                                                          newName);
-  assertEquals('supervisedUserCreateConfirm',
-               PageManager.getTopmostVisiblePage().name);
-
-  var titleElement = $('supervised-user-created-title');
-  var switchElement = $('supervised-user-created-switch');
-  var messageElement = $('supervised-user-created-text');
-
-  assertEquals(-1, titleElement.textContent.indexOf(oldName));
-  assertEquals(-1, switchElement.textContent.indexOf(oldName));
-  assertEquals(-1, messageElement.textContent.indexOf(oldName));
-
-  assertNotEquals(-1, titleElement.textContent.indexOf(newName));
-  assertNotEquals(-1, switchElement.textContent.indexOf(newName));
-  assertNotEquals(-1, messageElement.textContent.indexOf(newName));
-});
-
-// An additional warning should be shown when deleting a supervised user.
-TEST_F('ManageProfileUITest', 'DeleteSupervisedUserWarning', function() {
-  var addendum = $('delete-supervised-profile-addendum');
-
-  ManageProfileOverlay.showDeleteDialog(this.testProfileInfo_(true));
-  assertFalse(addendum.hidden);
-
-  ManageProfileOverlay.showDeleteDialog(this.testProfileInfo_(false));
-  assertTrue(addendum.hidden);
-});
-
-// The policy prohibiting supervised users should update the UI dynamically.
-TEST_F('ManageProfileUITest', 'PolicyDynamicRefresh', function() {
-  ManageProfileOverlay.getInstance().initializePage();
-
-  var custodianEmail = 'chrome.playpen.test@gmail.com';
-  CreateProfileOverlay.updateSignedInStatus(custodianEmail);
-  CreateProfileOverlay.updateSupervisedUsersAllowed(true);
-  var checkbox = $('create-profile-supervised');
-  var signInPromo = $('create-profile-supervised-not-signed-in');
-  var signInLink = $('create-profile-supervised-sign-in-link');
-  var indicator = $('create-profile-supervised-indicator');
-
-  assertFalse(checkbox.disabled, 'allowed and signed in');
-  assertTrue(signInPromo.hidden, 'allowed and signed in');
-  assertEquals('none', window.getComputedStyle(indicator, null).display,
-               'allowed and signed in');
-
-  CreateProfileOverlay.updateSignedInStatus('');
-  CreateProfileOverlay.updateSupervisedUsersAllowed(true);
-  assertTrue(checkbox.disabled, 'allowed, not signed in');
-  assertFalse(signInPromo.hidden, 'allowed, not signed in');
-  assertTrue(signInLink.enabled, 'allowed, not signed in');
-  assertEquals('none', window.getComputedStyle(indicator, null).display,
-               'allowed, not signed in');
-
-  CreateProfileOverlay.updateSignedInStatus('');
-  CreateProfileOverlay.updateSupervisedUsersAllowed(false);
-  assertTrue(checkbox.disabled, 'disallowed, not signed in');
-  assertFalse(signInPromo.hidden, 'disallowed, not signed in');
-  assertFalse(signInLink.enabled, 'disallowed, not signed in');
-  assertEquals('inline-block', window.getComputedStyle(indicator, null).display,
-               'disallowed, not signed in');
-  assertEquals('policy', indicator.getAttribute('controlled-by'));
-
-  CreateProfileOverlay.updateSignedInStatus(custodianEmail);
-  CreateProfileOverlay.updateSupervisedUsersAllowed(false);
-  assertTrue(checkbox.disabled, 'disallowed, signed in');
-  assertTrue(signInPromo.hidden, 'disallowed, signed in');
-  assertEquals('inline-block', window.getComputedStyle(indicator, null).display,
-               'disallowed, signed in');
-  assertEquals('policy', indicator.getAttribute('controlled-by'));
-
-  CreateProfileOverlay.updateSignedInStatus(custodianEmail);
-  CreateProfileOverlay.updateSupervisedUsersAllowed(true);
-  assertFalse(checkbox.disabled, 're-allowed and signed in');
-  assertTrue(signInPromo.hidden, 're-allowed and signed in');
-  assertEquals('none', window.getComputedStyle(indicator, null).display,
-               're-allowed and signed in');
-});
-
-// The supervised user checkbox should correctly update its state during profile
-// creation and afterwards.
-TEST_F('ManageProfileUITest', 'CreateInProgress', function() {
-  ManageProfileOverlay.getInstance().initializePage();
-
-  var custodianEmail = 'chrome.playpen.test@gmail.com';
-  CreateProfileOverlay.updateSignedInStatus(custodianEmail);
-  CreateProfileOverlay.updateSupervisedUsersAllowed(true);
-  var checkbox = $('create-profile-supervised');
-  var signInPromo = $('create-profile-supervised-not-signed-in');
-  var indicator = $('create-profile-supervised-indicator');
-
-  assertFalse(checkbox.disabled, 'allowed and signed in');
-  assertTrue(signInPromo.hidden, 'allowed and signed in');
-  assertEquals('none', window.getComputedStyle(indicator, null).display,
-               'allowed and signed in');
-  assertFalse(indicator.hasAttribute('controlled-by'));
-
-  CreateProfileOverlay.updateCreateInProgress(true);
-  assertTrue(checkbox.disabled, 'creation in progress');
-
-  // A no-op update to the sign-in status should not change the UI.
-  CreateProfileOverlay.updateSignedInStatus(custodianEmail);
-  CreateProfileOverlay.updateSupervisedUsersAllowed(true);
-  assertTrue(checkbox.disabled, 'creation in progress');
-
-  CreateProfileOverlay.updateCreateInProgress(false);
-  assertFalse(checkbox.disabled, 'creation finished');
-});
-
-// Supervised users should be able to open the delete dialog, but not the
-// create dialog.
-TEST_F('ManageProfileUITest', 'SupervisedShowCreate', function() {
-  this.setProfileSupervised_(false, 'create');
-
-  ManageProfileOverlay.showCreateDialog();
-  assertEquals('createProfile', PageManager.getTopmostVisiblePage().name);
-  PageManager.closeOverlay();
-  assertEquals('settings', PageManager.getTopmostVisiblePage().name);
-  ManageProfileOverlay.showDeleteDialog(this.testProfileInfo_(false));
-  assertEquals('manageProfile', PageManager.getTopmostVisiblePage().name);
-  assertFalse($('manage-profile-overlay-delete').hidden);
-  PageManager.closeOverlay();
-  assertEquals('settings', PageManager.getTopmostVisiblePage().name);
-
-  this.setProfileSupervised_(true, 'create');
-  ManageProfileOverlay.showCreateDialog();
-  assertEquals('settings', PageManager.getTopmostVisiblePage().name);
-  ManageProfileOverlay.showDeleteDialog(this.testProfileInfo_(false));
-  assertEquals('manageProfile', PageManager.getTopmostVisiblePage().name);
-});
-
-// Selecting a different avatar image should update the suggested profile name.
-TEST_F('ManageProfileUITest', 'Create_NameUpdateOnAvatarSelected', function() {
-  var mode = 'create';
-  this.initDefaultProfiles_(mode);
-
-  var gridEl = $(mode + '-profile-icon-grid');
-  var nameEl = $(mode + '-profile-name');
-
-  // Select another icon and check that the profile name was updated.
-  assertNotEquals(gridEl.selectedItem, this.defaultIconURLs[0]);
-  gridEl.selectedItem = this.defaultIconURLs[0];
-  expectEquals(this.defaultNames[0], nameEl.value);
-
-  // Select icon without an associated name; the profile name shouldn't change.
-  var oldName = nameEl.value;
-  assertEquals('', this.defaultNames[2]);
-  gridEl.selectedItem = this.defaultIconURLs[2];
-  expectEquals(oldName, nameEl.value);
-
-  // Select another icon with a name and check that the name is updated again.
-  assertNotEquals('', this.defaultNames[1]);
-  gridEl.selectedItem = this.defaultIconURLs[1];
-  expectEquals(this.defaultNames[1], nameEl.value);
-
-  PageManager.closeOverlay();
-});
-
-// After the user edited the profile name, selecting a different avatar image
-// should not update the suggested name anymore.
-TEST_F('ManageProfileUITest', 'Create_NoNameUpdateOnAvatarSelectedAfterEdit',
-    function() {
-  var mode = 'create';
-  this.initDefaultProfiles_(mode);
-
-  var gridEl = $(mode + '-profile-icon-grid');
-  var nameEl = $(mode + '-profile-name');
-
-  // After the user manually entered a name, it should not be changed anymore
-  // (even if the entered name is another default name).
-  nameEl.value = this.defaultNames[3];
-  nameEl.oninput();
-  gridEl.selectedItem = this.defaultIconURLs[0];
-  expectEquals(this.defaultNames[3], nameEl.value);
-
-  PageManager.closeOverlay();
-});
-
-// After the user edited the profile name, selecting a different avatar image
-// should not update the suggested name anymore even if the original suggestion
-// is entered again.
-TEST_F('ManageProfileUITest', 'Create_NoNameUpdateOnAvatarSelectedAfterRevert',
-    function() {
-  var mode = 'create';
-  this.initDefaultProfiles_(mode);
-
-  var gridEl = $(mode + '-profile-icon-grid');
-  var nameEl = $(mode + '-profile-name');
-
-  // After the user manually entered a name, it should not be changed anymore,
-  // even if the user then reverts to the original suggestion.
-  var oldName = nameEl.value;
-  nameEl.value = 'Custom Name';
-  nameEl.oninput();
-  nameEl.value = oldName;
-  nameEl.oninput();
-  // Now select another avatar and check that the name remained the same.
-  assertNotEquals(gridEl.selectedItem, this.defaultIconURLs[0]);
-  gridEl.selectedItem = this.defaultIconURLs[0];
-  expectEquals(oldName, nameEl.value);
-
-  PageManager.closeOverlay();
-});
-
-// In the manage dialog, the name should never be updated on avatar selection.
-TEST_F('ManageProfileUITest', 'Manage_NoNameUpdateOnAvatarSelected',
-    function() {
-  var mode = 'manage';
-  this.setProfileSupervised_(false, mode);
-  PageManager.showPageByName(mode + 'Profile');
-
-  var testProfile = this.testProfileInfo_(false);
-  var iconURLs = [testProfile.iconURL, '/some/path', '/another/path'];
-  var names = [testProfile.name, 'Some Name', ''];
-  ManageProfileOverlay.receiveDefaultProfileIconsAndNames(
-     mode, iconURLs, names);
-
-  var gridEl = $(mode + '-profile-icon-grid');
-  var nameEl = $(mode + '-profile-name');
-
-  // Select another icon and check if the profile name was updated.
-  var oldName = nameEl.value;
-  gridEl.selectedItem = iconURLs[1];
-  expectEquals(oldName, nameEl.value);
-
-  PageManager.closeOverlay();
-});
-
-GEN('#endif  // OS_CHROMEOS');
diff --git a/chrome/browser/ui/webui/options/multilanguage_options_browsertest.cc b/chrome/browser/ui/webui/options/multilanguage_options_browsertest.cc
deleted file mode 100644
index 4c95d59f..0000000
--- a/chrome/browser/ui/webui/options/multilanguage_options_browsertest.cc
+++ /dev/null
@@ -1,48 +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.
-
-#include "chrome/browser/ui/webui/options/multilanguage_options_browsertest.h"
-
-#include <string>
-
-#include "base/command_line.h"
-#include "build/build_config.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "components/spellcheck/browser/pref_names.h"
-
-MultilanguageOptionsBrowserTest::MultilanguageOptionsBrowserTest() {
-}
-
-MultilanguageOptionsBrowserTest::~MultilanguageOptionsBrowserTest() {
-}
-
-void MultilanguageOptionsBrowserTest::ClearSpellcheckDictionaries() {
-  SetDictionariesPref(base::ListValue());
-}
-
-void MultilanguageOptionsBrowserTest::SetUpOnMainThread() {
-  WebUIBrowserTest::SetUpOnMainThread();
-#if defined(OS_CHROMEOS)
-  std::string setting_name = prefs::kLanguagePreferredLanguages;
-#else
-  std::string setting_name = prefs::kAcceptLanguages;
-#endif
-
-  PrefService* pref_service = browser()->profile()->GetPrefs();
-  pref_service->SetString(setting_name, "fr,es,de,en");
-  base::ListValue dictionaries;
-  dictionaries.AppendString("fr");
-  SetDictionariesPref(dictionaries);
-  pref_service->SetString(spellcheck::prefs::kSpellCheckDictionary,
-                          std::string());
-}
-
-void MultilanguageOptionsBrowserTest::SetDictionariesPref(
-    const base::ListValue& value) {
-  browser()->profile()->GetPrefs()->Set(
-      spellcheck::prefs::kSpellCheckDictionaries, value);
-}
diff --git a/chrome/browser/ui/webui/options/multilanguage_options_browsertest.h b/chrome/browser/ui/webui/options/multilanguage_options_browsertest.h
deleted file mode 100644
index 2ea4c66e..0000000
--- a/chrome/browser/ui/webui/options/multilanguage_options_browsertest.h
+++ /dev/null
@@ -1,29 +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 CHROME_BROWSER_UI_WEBUI_OPTIONS_MULTILANGUAGE_OPTIONS_BROWSERTEST_H_
-#define CHROME_BROWSER_UI_WEBUI_OPTIONS_MULTILANGUAGE_OPTIONS_BROWSERTEST_H_
-
-#include "base/macros.h"
-#include "chrome/test/base/web_ui_browser_test.h"
-
-// This is a helper class used by multilanguage_options_webui_browsertest.js
-// to flip the enable-multilingual-spellchecker command line switch and set
-// the AcceptLanguages and SpellcheckDictionaries preferences.
-class MultilanguageOptionsBrowserTest : public WebUIBrowserTest {
- public:
-  MultilanguageOptionsBrowserTest();
-  ~MultilanguageOptionsBrowserTest() override;
-  // Set the kSpellCheckDictionaries preference to an empty list value.
-  void ClearSpellcheckDictionaries();
-
- private:
-  // WebUIBrowserTest implementation.
-  void SetUpOnMainThread() override;
-  void SetDictionariesPref(const base::ListValue& value);
-
-  DISALLOW_COPY_AND_ASSIGN(MultilanguageOptionsBrowserTest);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_OPTIONS_MULTILANGUAGE_OPTIONS_BROWSERTEST_H_
diff --git a/chrome/browser/ui/webui/options/multilanguage_options_webui_browsertest.js b/chrome/browser/ui/webui/options/multilanguage_options_webui_browsertest.js
deleted file mode 100644
index 222016cd4..0000000
--- a/chrome/browser/ui/webui/options/multilanguage_options_webui_browsertest.js
+++ /dev/null
@@ -1,212 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-GEN('#include "chrome/browser/ui/webui/options/' +
-    'multilanguage_options_browsertest.h"');
-
-/**
- * Test C++ fixture for Language Options WebUI testing.
- * @constructor
- * @extends {testing.Test}
- */
-function MultilanguageOptionsWebUIBrowserTest() {}
-
-MultilanguageOptionsWebUIBrowserTest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://settings-frame/languages',
-
-  /** @override */
-  typedefCppFixture: 'MultilanguageOptionsBrowserTest',
-
-  /** @override */
-  accessibilityIssuesAreErrors: true,
-
-  /** @param {string} expected Sorted currently selected languages. */
-  expectCurrentlySelected: function(expected) {
-    var languages = LanguageOptions.getInstance().spellCheckLanguages_;
-    expectEquals(expected, Object.keys(languages).sort().join());
-  },
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    assertFalse(cr.isMac);
-    expectFalse($('edit-custom-dictionary-button').hidden);
-    this.expectEnableSpellcheckCheckboxVisible();
-    this.expectCurrentlySelected('fr');
-
-    var requiredOwnedAriaRoleMissingSelectors = [
-      '#default-search-engine-list',
-      '#other-search-engine-list',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_ARIA_08: http://crbug.com/559320
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'requiredOwnedAriaRoleMissing',
-        requiredOwnedAriaRoleMissingSelectors);
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/559266
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        '#language-options-list');
-
-    // Enable when failure is resolved.
-    // AX_TEXT_04: http://crbug.com/559271
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'linkWithUnclearPurpose',
-        '#languagePage > .content-area > .language-options-header > A');
-  },
-
-  /** @override */
-  tearDown: function() {
-    testing.Test.prototype.tearDown.call(this);
-    this.expectEnableSpellcheckCheckboxVisible();
-  },
-
-  /** Make sure the 'Enable spell checking' checkbox is visible. */
-  expectEnableSpellcheckCheckboxVisible: function() {
-    if ($('enable-spellcheck-container'))
-      expectFalse($('enable-spellcheck-container').hidden);
-  },
-};
-
-// Test that opening language options has the correct location.
-TEST_F('MultilanguageOptionsWebUIBrowserTest', 'TestOpenLanguageOptions',
-       function() {
-  expectEquals('chrome://settings-frame/languages', document.location.href);
-});
-
-// Test that only certain languages can be selected and used for spellchecking.
-// prefs::kLanguagePreferredLanguages/prefs::kAcceptLanguages is set to
-// 'fr,es,de,en' and prefs::kSpellCheckDictionaries is just 'fr'
-TEST_F('MultilanguageOptionsWebUIBrowserTest', 'ChangeSpellcheckLanguages',
-       function() {
-  expectTrue($('language-options-list').selectLanguageByCode('es'));
-  expectFalse($('spellcheck-language-checkbox').checked, 'es');
-
-  // Click 'es' and ensure that it gets checked and 'fr' stays checked.
-  $('spellcheck-language-checkbox').click();
-  expectTrue($('spellcheck-language-checkbox').checked, 'es');
-  expectTrue($('language-options-list').selectLanguageByCode('fr'));
-  expectTrue($('spellcheck-language-checkbox').checked, 'fr');
-  this.expectCurrentlySelected('es,fr');
-
-  // Click 'fr' and ensure that it gets unchecked and 'es' stays checked.
-  $('spellcheck-language-checkbox').click();
-  expectFalse($('spellcheck-language-checkbox').checked, 'fr');
-  $('language-options-list').selectLanguageByCode('es');
-  expectTrue($('spellcheck-language-checkbox').checked, 'es');
-  this.expectCurrentlySelected('es');
-});
-
-// Make sure 'am' cannot be selected as a language and 'fr' stays selected.
-TEST_F('MultilanguageOptionsWebUIBrowserTest', 'NotAcceptLanguage', function() {
-  expectFalse($('language-options-list').selectLanguageByCode('am'));
-  expectTrue($('language-options-list').selectLanguageByCode('fr'));
-  expectTrue($('spellcheck-language-checkbox').checked, 'fr');
-  this.expectCurrentlySelected('fr');
-});
-
-// Make sure 'en' cannot be used as a language and 'fr' stays selected.
-TEST_F('MultilanguageOptionsWebUIBrowserTest', 'UnusableLanguage', function() {
-  expectTrue($('language-options-list').selectLanguageByCode('en'));
-  expectTrue($('spellcheck-language-checkbox-container').hidden);
-  expectFalse($('spellcheck-language-checkbox').checked, 'en');
-  this.expectCurrentlySelected('fr');
-});
-
-/**
- * Test C++ fixture for Language Options WebUI testing.
- * @constructor
- * @extends {MultilanguageOptionsWebUIBrowserTest}
- */
-function MultilanguagePreferenceWebUIBrowserTest() {}
-
-MultilanguagePreferenceWebUIBrowserTest.prototype = {
-  __proto__: MultilanguageOptionsWebUIBrowserTest.prototype,
-
-  /** @override */
-  testGenPreamble: function() {
-    GEN('ClearSpellcheckDictionaries();');
-  },
-
-  /** @override */
-  isAsync: true,
-
-  /**
-   * @param {string} expected Sorted languages in the kSpellCheckDictionaries
-   * preference.
-   */
-  expectRegisteredDictionariesPref: function(expected) {
-    var registeredPrefs =
-        options.Preferences.getInstance().registeredPreferences_;
-    expectEquals(expected,
-        registeredPrefs['spellcheck.dictionaries'].orig.value.sort().join());
-  },
-
-  /**
-   * Watch for a change to the preference |pref| and then call |callback|.
-   * @param {string} pref The preference to listen for a change on.
-   * @param {function} callback The function to run after a listener event.
-   */
-  addPreferenceListener: function(pref, callback) {
-    options.Preferences.getInstance().addEventListener(pref, callback);
-  },
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    assertFalse(cr.isMac);
-    expectTrue($('edit-custom-dictionary-button').hidden);
-    this.expectEnableSpellcheckCheckboxVisible();
-    this.expectCurrentlySelected('');
-    this.expectRegisteredDictionariesPref('');
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/559266
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        '#language-options-list');
-
-    // Enable when failure is resolved.
-    // AX_TEXT_04: http://crbug.com/559271
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'linkWithUnclearPurpose',
-        '#languagePage > .content-area > .language-options-header > A');
-
-    // Enable when failure is resolved.
-    // AX_FOCUS_01: http://crbug.com/570046
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'focusableElementNotVisibleAndNotAriaHidden',
-        '#offer-to-translate-in-this-language');
-  },
-};
-
-// Make sure the case where no languages are selected is handled properly.
-TEST_F('MultilanguagePreferenceWebUIBrowserTest', 'SelectFromBlank',
-       function() {
-  expectTrue($('language-options-list').selectLanguageByCode('fr'));
-  expectFalse($('spellcheck-language-checkbox').checked, 'fr');
-  expectTrue($('edit-custom-dictionary-button').hidden);
-
-  // Add a preference change event listener which ensures that the preference is
-  // updated correctly and that 'fr' is the only thing in the dictionary object.
-  this.addPreferenceListener('spellcheck.dictionaries', function() {
-    expectTrue($('spellcheck-language-checkbox').checked, 'fr');
-    this.expectRegisteredDictionariesPref('fr');
-    this.expectCurrentlySelected('fr');
-    expectFalse($('edit-custom-dictionary-button').hidden);
-    testDone();
-  }.bind(this));
-
-  // Click 'fr' and trigger the preference listener.
-  $('spellcheck-language-checkbox').click();
-});
diff --git a/chrome/browser/ui/webui/options/options_browsertest.cc b/chrome/browser/ui/webui/options/options_browsertest.cc
deleted file mode 100644
index 6eca2fc2..0000000
--- a/chrome/browser/ui/webui/options/options_browsertest.cc
+++ /dev/null
@@ -1,70 +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/ui/webui/options/options_browsertest.h"
-
-#include "base/bind.h"
-#include "base/values.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "components/prefs/pref_service.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "url/gurl.h"
-
-using content::NavigationController;
-using content::NavigationEntry;
-using content::WebUIMessageHandler;
-
-OptionsBrowserTest::OptionsBrowserTest() {
-}
-
-OptionsBrowserTest::~OptionsBrowserTest() {
-}
-
-void OptionsBrowserTest::RegisterMessages() {
-  web_ui()->RegisterMessageCallback(
-      "optionsTestReportHistory", base::Bind(&OptionsBrowserTest::ReportHistory,
-                                             base::Unretained(this)));
-
-  web_ui()->RegisterMessageCallback(
-      "optionsTestSetPref", base::Bind(&OptionsBrowserTest::HandleSetPref,
-                                       base::Unretained(this)));
-}
-
-// Includes the current entry.
-void OptionsBrowserTest::ReportHistory(const base::ListValue* list_value) {
-  const NavigationController& controller =
-      browser()->tab_strip_model()->GetActiveWebContents()->GetController();
-  base::ListValue history;
-  const int current = controller.GetCurrentEntryIndex();
-  for (int i = 0; i <= current; ++i) {
-    GURL url = controller.GetEntryAtIndex(i)->GetVirtualURL();
-    history.AppendString(url.spec());
-  }
-  web_ui()->CallJavascriptFunctionUnsafe(
-      "OptionsWebUIExtendedTest.verifyHistoryCallback", history);
-}
-
-void OptionsBrowserTest::ClearPref(const char* path) {
-  browser()->profile()->GetPrefs()->ClearPref(path);
-}
-
-void OptionsBrowserTest::HandleSetPref(const base::ListValue* args) {
-  ASSERT_EQ(2u, args->GetSize());
-
-  std::string pref_name;
-  ASSERT_TRUE(args->GetString(0, &pref_name));
-  const base::Value* pref_value;
-  ASSERT_TRUE(args->Get(1, &pref_value));
-
-  browser()->profile()->GetPrefs()->Set(pref_name.c_str(), *pref_value);
-}
-
-content::WebUIMessageHandler* OptionsBrowserTest::GetMockMessageHandler() {
-  return this;
-}
diff --git a/chrome/browser/ui/webui/options/options_browsertest.h b/chrome/browser/ui/webui/options/options_browsertest.h
deleted file mode 100644
index d8135a8..0000000
--- a/chrome/browser/ui/webui/options/options_browsertest.h
+++ /dev/null
@@ -1,45 +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_UI_WEBUI_OPTIONS_OPTIONS_BROWSERTEST_H_
-#define CHROME_BROWSER_UI_WEBUI_OPTIONS_OPTIONS_BROWSERTEST_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "chrome/test/base/web_ui_browser_test.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-// This is a helper class used by options_browsertest.js to feed the navigation
-// history back to the test.
-class OptionsBrowserTest : public WebUIBrowserTest,
-                           public content::WebUIMessageHandler {
- public:
-  OptionsBrowserTest();
-  ~OptionsBrowserTest() override;
-
- protected:
-  // Clears the preference at the given |path|.
-  void ClearPref(const char* path);
-
- private:
-  // WebUIMessageHandler implementation.
-  void RegisterMessages() override;
-
-  // WebUIBrowserTest implementation.
-  content::WebUIMessageHandler* GetMockMessageHandler() override;
-
-  // A callback for the 'optionsTestReportHistory' message, this sends the
-  // URLs in the "back" tab history, including the current entry, back to the
-  // WebUI via a callback.
-  void ReportHistory(const base::ListValue* list_value);
-
-  // A callback for the 'optionsTestSetPref' message. The first argument should
-  // be a pref path (e.g., "profile.managed_users"); the second, the new value
-  // to set for that pref.
-  void HandleSetPref(const base::ListValue* args);
-
-  DISALLOW_COPY_AND_ASSIGN(OptionsBrowserTest);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_OPTIONS_OPTIONS_BROWSERTEST_H_
diff --git a/chrome/browser/ui/webui/options/options_browsertest.js b/chrome/browser/ui/webui/options/options_browsertest.js
deleted file mode 100644
index 05dfd8c96b..0000000
--- a/chrome/browser/ui/webui/options/options_browsertest.js
+++ /dev/null
@@ -1,969 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-GEN('#include "chrome/browser/ui/webui/options/options_browsertest.h"');
-
-/** @const */ var SUPERVISED_USERS_PREF = 'profile.managed_users';
-
-/**
- * Wait for the method specified by |methodName|, on the |object| object, to be
- * called, then execute |afterFunction|.
- * @param {*} object Object with callable property named |methodName|.
- * @param {string} methodName The name of the property on |object| to use as a
- *     callback.
- * @param {!Function} afterFunction A function to call after object.methodName()
- *     is called.
- */
-function waitForResponse(object, methodName, afterFunction) {
-  var originalCallback = object[methodName];
-
-  // Install a wrapper that temporarily replaces the original function.
-  object[methodName] = function() {
-    object[methodName] = originalCallback;
-    originalCallback.apply(this, arguments);
-    afterFunction();
-  };
-}
-
-/**
-  * Wait for the global window.onpopstate callback to be called (after a tab
-  * history navigation), then execute |afterFunction|.
-  * @param {!Function} afterFunction A function to call after pop state events.
-  */
-function waitForPopstate(afterFunction) {
-  waitForResponse(window, 'onpopstate', afterFunction);
-}
-
-/**
- * TestFixture for OptionsPage WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function OptionsWebUITest() {}
-
-OptionsWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Browse to the options page & call our preLoad().
-   * @override
-   */
-  browsePreload: 'chrome://settings-frame',
-
-  /** @override */
-  isAsync: true,
-
-  /**
-   * Register a mock handler to ensure expectations are met and options pages
-   * behave correctly.
-   */
-  preLoad: function() {
-    this.makeAndRegisterMockHandler(
-        ['defaultZoomFactorAction',
-         'fetchPrefs',
-         'observePrefs',
-         'setBooleanPref',
-         'setIntegerPref',
-         'setDoublePref',
-         'setStringPref',
-         'setObjectPref',
-         'clearPref',
-         'coreOptionsUserMetricsAction',
-        ]);
-
-    // Register stubs for methods expected to be called before/during tests.
-    // Specific expectations can be made in the tests themselves.
-    this.mockHandler.stubs().fetchPrefs(ANYTHING);
-    this.mockHandler.stubs().observePrefs(ANYTHING);
-    this.mockHandler.stubs().coreOptionsUserMetricsAction(ANYTHING);
-  },
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/559329
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        '#profiles-list');
-
-    var linkWithUnclearPurposeSelectors = [
-      '#sync-overview > A',
-      '#privacy-explanation > A',
-      '#languages-section > .settings-row > A',
-      '#cloudprint-options-mdns > .settings-row > A',
-      '#cups-printers-section > .settings-row > A',
-      '#do-not-track-confirm-overlay > .action-area > .hbox.stretch > A',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_TEXT_04: http://crbug.com/559318
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'linkWithUnclearPurpose',
-        linkWithUnclearPurposeSelectors);
-
-    // Causes testDefaultZoomFactor to flake. See http://crbug.com/611233.
-    var requiredOwnedAriaRoleMissingSelectors = [
-      '#default-search-engine-list',
-      '#other-search-engine-list',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_ARIA_08: http://crbug.com/606657
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'requiredOwnedAriaRoleMissing',
-        requiredOwnedAriaRoleMissingSelectors);
-  },
-};
-
-/**
- * Wait for all targets to be hidden.
- * @param {Array<Element>} targets
- */
-function waitUntilHidden(targets) {
-  function isHidden(el) { return el.hidden; }
-  function ensureTransition(el) { ensureTransitionEndEvent(el, 500); }
-
-  document.addEventListener('transitionend', function f(e) {
-    if (targets.indexOf(e.target) >= 0 && targets.every(isHidden)) {
-      document.removeEventListener(f, 'transitionend');
-      testDone();
-    }
-  });
-
-  targets.forEach(ensureTransition);
-}
-
-// Crashes on Mac only. See http://crbug.com/79181
-GEN('#if defined(OS_MACOSX)');
-GEN('#define MAYBE_testSetBooleanPrefTriggers ' +
-    'DISABLED_testSetBooleanPrefTriggers');
-GEN('#else');
-GEN('#define MAYBE_testSetBooleanPrefTriggers testSetBooleanPrefTriggers');
-GEN('#endif  // defined(OS_MACOSX)');
-
-TEST_F('OptionsWebUITest', 'MAYBE_testSetBooleanPrefTriggers', function() {
-  // TODO(dtseng): make generic to click all buttons.
-  var showHomeButton =
-      document.querySelector('input[pref="browser.show_home_button"]');
-  var trueListValue = [
-    'browser.show_home_button',
-    true,
-    'Options_Homepage_HomeButton',
-  ];
-  // Note: this expectation is checked in testing::Test::tearDown.
-  this.mockHandler.expects(once()).setBooleanPref(trueListValue);
-
-  // Cause the handler to be called.
-  showHomeButton.click();
-  showHomeButton.blur();
-  testDone();
-});
-
-// Not meant to run on ChromeOS at this time.
-// Not finishing in windows. http://crbug.com/81723
-TEST_F('OptionsWebUITest', 'DISABLED_testRefreshStaysOnCurrentPage',
-    function() {
-  assertTrue($('search-engine-manager-page').hidden);
-  var item = $('manage-default-search-engines');
-  item.click();
-
-  assertFalse($('search-engine-manager-page').hidden);
-
-  window.location.reload();
-
-  assertEquals('chrome://settings-frame/searchEngines', document.location.href);
-  assertFalse($('search-engine-manager-page').hidden);
-  testDone();
-});
-
-/**
- * Test the default zoom factor select element.
- */
-TEST_F('OptionsWebUITest', 'testDefaultZoomFactor', function() {
-  // The expected minimum length of the |defaultZoomFactor| element.
-  var defaultZoomFactorMinimumLength = 10;
-  // Verify that the zoom factor element exists.
-  var defaultZoomFactor = $('defaultZoomFactor');
-  assertNotEquals(defaultZoomFactor, null);
-
-  // Verify that the zoom factor element has a reasonable number of choices.
-  expectGE(defaultZoomFactor.options.length, defaultZoomFactorMinimumLength);
-
-  // Simulate a change event, selecting the highest zoom value.  Verify that
-  // the javascript handler was invoked once.
-  this.mockHandler.expects(once()).defaultZoomFactorAction(NOT_NULL).
-      will(callFunction(function() { }));
-  defaultZoomFactor.selectedIndex = defaultZoomFactor.options.length - 1;
-  var event = {target: defaultZoomFactor};
-  if (defaultZoomFactor.onchange) defaultZoomFactor.onchange(event);
-  testDone();
-});
-
-/**
- * If |confirmInterstitial| is true, the OK button of the Do Not Track
- * interstitial is pressed, otherwise the abort button is pressed.
- * @param {boolean} confirmInterstitial Whether to confirm the Do Not Track
- *     interstitial.
- */
-OptionsWebUITest.prototype.testDoNotTrackInterstitial =
-    function(confirmInterstitial) {
-  Preferences.prefsFetchedCallback({'enable_do_not_track': {'value': false}});
-  var buttonToClick = confirmInterstitial ? $('do-not-track-confirm-ok') :
-                                            $('do-not-track-confirm-cancel');
-  var dntCheckbox = $('do-not-track-enabled');
-  var dntOverlay = PageManager.registeredOverlayPages['donottrackconfirm'];
-  assertFalse(dntCheckbox.checked);
-
-  var visibleChangeCounter = 0;
-  var visibleChangeHandler = function() {
-    ++visibleChangeCounter;
-    switch (visibleChangeCounter) {
-      case 1:
-        window.setTimeout(function() {
-          assertTrue(dntOverlay.visible);
-          buttonToClick.click();
-        }, 0);
-        break;
-      case 2:
-        window.setTimeout(function() {
-          assertFalse(dntOverlay.visible);
-          assertEquals(confirmInterstitial, dntCheckbox.checked);
-          dntOverlay.removeEventListener('visibleChange', visibleChangeHandler);
-          testDone();
-        }, 0);
-        break;
-      default:
-        assertTrue(false);
-    }
-  };
-  dntOverlay.addEventListener('visibleChange', visibleChangeHandler);
-
-  if (confirmInterstitial) {
-    this.mockHandler.expects(once()).setBooleanPref(
-        ['enable_do_not_track', true, 'Options_DoNotTrackCheckbox']);
-  } else {
-    // The mock handler complains if setBooleanPref is called even though
-    // it should not be.
-  }
-
-  dntCheckbox.click();
-};
-
-TEST_F('OptionsWebUITest', 'EnableDoNotTrackAndConfirmInterstitial',
-       function() {
-  this.testDoNotTrackInterstitial(true);
-});
-
-TEST_F('OptionsWebUITest', 'EnableDoNotTrackAndCancelInterstitial',
-       function() {
-  this.testDoNotTrackInterstitial(false);
-});
-
-// Check that the "Do not Track" preference can be correctly disabled.
-// In order to do that, we need to enable it first.
-TEST_F('OptionsWebUITest', 'EnableAndDisableDoNotTrack', function() {
-  Preferences.prefsFetchedCallback({'enable_do_not_track': {'value': false}});
-  var dntCheckbox = $('do-not-track-enabled');
-  var dntOverlay = PageManager.registeredOverlayPages.donottrackconfirm;
-  assertFalse(dntCheckbox.checked);
-
-  var visibleChangeCounter = 0;
-  var visibleChangeHandler = function() {
-    ++visibleChangeCounter;
-    switch (visibleChangeCounter) {
-      case 1:
-        window.setTimeout(function() {
-          assertTrue(dntOverlay.visible);
-          $('do-not-track-confirm-ok').click();
-        }, 0);
-        break;
-      case 2:
-        window.setTimeout(function() {
-          assertFalse(dntOverlay.visible);
-          assertTrue(dntCheckbox.checked);
-          dntOverlay.removeEventListener('visibleChange', visibleChangeHandler);
-          dntCheckbox.click();
-        }, 0);
-        break;
-      default:
-        assertNotReached();
-    }
-  };
-  dntOverlay.addEventListener('visibleChange', visibleChangeHandler);
-
-  this.mockHandler.expects(once()).setBooleanPref(
-      eq(['enable_do_not_track', true, 'Options_DoNotTrackCheckbox']));
-
-  var verifyCorrectEndState = function() {
-    window.setTimeout(function() {
-      assertFalse(dntOverlay.visible);
-      assertFalse(dntCheckbox.checked);
-      testDone();
-    }, 0);
-  };
-  this.mockHandler.expects(once()).setBooleanPref(
-      eq(['enable_do_not_track', false, 'Options_DoNotTrackCheckbox'])).will(
-          callFunction(verifyCorrectEndState));
-
-  dntCheckbox.click();
-});
-
-// Fails on chromeos, http://crbug.com/660867
-// Verify that preventDefault() is called on 'Enter' keydown events that trigger
-// the default button. If this doesn't happen, other elements that may get
-// focus (by the overlay closing for instance), will execute in addition to the
-// default button. See crbug.com/268336.
-TEST_F('OptionsWebUITest', 'DISABLED_EnterPreventsDefault', function() {
-  var page = HomePageOverlay.getInstance();
-  PageManager.showPageByName(page.name);
-  var event = new KeyboardEvent('keydown', {
-    'bubbles': true,
-    'cancelable': true,
-    'key': 'Enter'
-  });
-  assertFalse(event.defaultPrevented);
-  page.pageDiv.dispatchEvent(event);
-  assertTrue(event.defaultPrevented);
-  testDone();
-});
-
-// Verifies that sending an empty list of indexes to move doesn't crash chrome.
-TEST_F('OptionsWebUITest', 'emptySelectedIndexesDoesntCrash', function() {
-  chrome.send('dragDropStartupPage', [0, []]);
-  setTimeout(testDone);
-});
-
-// This test turns out to be flaky on all platforms.
-// See http://crbug.com/315250.
-
-// An overlay's position should remain the same as it shows.
-TEST_F('OptionsWebUITest', 'DISABLED_OverlayShowDoesntShift', function() {
-  var overlayName = 'startup';
-  var overlay = $('startup-overlay');
-  var frozenPages = document.getElementsByClassName('frozen');  // Gets updated.
-  expectEquals(0, frozenPages.length);
-
-  document.addEventListener('transitionend', function(e) {
-    if (e.target != overlay)
-      return;
-
-    assertFalse(overlay.classList.contains('transparent'));
-    expectEquals(numFrozenPages, frozenPages.length);
-    testDone();
-  });
-
-  PageManager.showPageByName(overlayName);
-  var numFrozenPages = frozenPages.length;
-  expectGT(numFrozenPages, 0);
-});
-
-GEN('#if defined(OS_CHROMEOS)');
-// Verify that range inputs respond to touch events. Currently only Chrome OS
-// uses slider options.
-TEST_F('OptionsWebUITest', 'RangeInputHandlesTouchEvents', function() {
-  this.mockHandler.expects(once()).setIntegerPref([
-    'settings.touchpad.sensitivity2', 1]);
-
-  var touchpadRange = $('touchpad-sensitivity-range');
-  var event = document.createEvent('UIEvent');
-  event.initUIEvent('touchstart', true, true, window);
-  touchpadRange.dispatchEvent(event);
-
-  event = document.createEvent('UIEvent');
-  event.initUIEvent('touchmove', true, true, window);
-  touchpadRange.dispatchEvent(event);
-
-  touchpadRange.value = 1;
-
-  event = document.createEvent('UIEvent');
-  event.initUIEvent('touchend', true, true, window);
-  touchpadRange.dispatchEvent(event);
-
-  // touchcancel should also trigger the handler, since it
-  // changes the slider position.
-  this.mockHandler.expects(once()).setIntegerPref([
-    'settings.touchpad.sensitivity2', 2]);
-
-  event = document.createEvent('UIEvent');
-  event.initUIEvent('touchstart', true, true, window);
-  touchpadRange.dispatchEvent(event);
-
-  touchpadRange.value = 2;
-
-  event = document.createEvent('UIEvent');
-  event.initUIEvent('touchcancel', true, true, window);
-  touchpadRange.dispatchEvent(event);
-
-  testDone();
-});
-GEN('#endif');  // defined(OS_CHROMEOS)
-
-/**
- * TestFixture for OptionsPage WebUI testing including tab history and support
- * for preference manipulation. If you don't need the features in the C++
- * fixture, use the simpler OptionsWebUITest (above) instead.
- * @extends {testing.Test}
- * @constructor
- */
-function OptionsWebUIExtendedTest() {}
-
-OptionsWebUIExtendedTest.prototype = {
-  __proto__: OptionsWebUITest.prototype,
-
-  /** @override */
-  typedefCppFixture: 'OptionsBrowserTest',
-
-  /** @override */
-  setUp: function() {
-    OptionsWebUITest.prototype.setUp.call(this);
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/559329
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        '#profiles-list');
-
-    var controlsWithoutLabelSelectors = [
-      '#cookies-view-page > .content-area.cookies-list-content-area > *',
-      '#other-search-engine-list > .deletable-item > DIV > *',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_TEXT_01: http://crbug.com/559330
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'controlsWithoutLabel',
-        controlsWithoutLabelSelectors);
-
-    var linkWithUnclearPurposeSelectors = [
-      '#sync-overview > A',
-      '#privacy-explanation > A',
-      '#languages-section > .settings-row > A',
-      '#cloudprint-options-mdns > .settings-row > A',
-      // Selectors below only affect ChromeOS tests.
-      '#privacy-section > DIV > DIV:nth-of-type(9) > A',
-      '#accessibility-learn-more',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_TEXT_04: http://crbug.com/559326
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'linkWithUnclearPurpose',
-        linkWithUnclearPurposeSelectors);
-
-    var requiredOwnedAriaRoleMissingSelectors = [
-        '#default-search-engine-list',
-        '#other-search-engine-list',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_ARIA_08: http://crbug.com/605689
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'requiredOwnedAriaRoleMissing',
-        requiredOwnedAriaRoleMissingSelectors);
-  },
-
-  testGenPreamble: function() {
-    // Start with no supervised users managed by this profile.
-    GEN('  ClearPref("' + SUPERVISED_USERS_PREF + '");');
-  },
-
-  /**
-   * Asserts that two non-nested arrays are equal. The arrays must contain only
-   * plain data types, no nested arrays or other objects.
-   * @param {Array} expected An array of expected values.
-   * @param {Array} result An array of actual values.
-   * @param {boolean} doSort If true, the arrays will be sorted before being
-   *     compared.
-   * @param {string} description A brief description for the array of actual
-   *     values, to use in an error message if the arrays differ.
-   * @private
-   */
-  compareArrays_: function(expected, result, doSort, description) {
-    var errorMessage = '\n' + description + ': ' + result +
-                       '\nExpected: ' + expected;
-    assertEquals(expected.length, result.length, errorMessage);
-
-    var expectedSorted = expected.slice();
-    var resultSorted = result.slice();
-    if (doSort) {
-      expectedSorted.sort();
-      resultSorted.sort();
-    }
-
-    for (var i = 0; i < expectedSorted.length; ++i) {
-      assertEquals(expectedSorted[i], resultSorted[i], errorMessage);
-    }
-  },
-
-  /**
-   * Verifies that the correct pages are currently open/visible.
-   * @param {!Array<string>} expectedPages An array of page names expected to
-   *     be open, with the topmost listed last.
-   * @param {string=} opt_expectedUrl The URL path, including hash, expected to
-   *     be open. If undefined, the topmost (last) page name in |expectedPages|
-   *     will be used. In either case, 'chrome://settings-frame/' will be
-   *     prepended.
-   * @private
-   */
-  verifyOpenPages_: function(expectedPages, opt_expectedUrl) {
-    // Check the topmost page.
-    expectEquals(null, PageManager.getVisibleBubble());
-    var currentPage = PageManager.getTopmostVisiblePage();
-
-    var lastExpected = expectedPages[expectedPages.length - 1];
-    expectEquals(lastExpected, currentPage.name);
-    // We'd like to check the title too, but we have to load the settings-frame
-    // instead of the outer settings page in order to have access to
-    // OptionsPage, and setting the title from within the settings-frame fails
-    // because of cross-origin access restrictions.
-    // TODO(pamg): Add a test fixture that loads chrome://settings and uses
-    // UI elements to access sub-pages, so we can test the titles and
-    // search-page URLs.
-    var expectedUrl = (typeof opt_expectedUrl == 'undefined') ?
-        lastExpected : opt_expectedUrl;
-    var fullExpectedUrl = 'chrome://settings-frame/' + expectedUrl;
-    expectEquals(fullExpectedUrl, window.location.href);
-
-    // Collect open pages.
-    var allPageNames = Object.keys(PageManager.registeredPages).concat(
-                       Object.keys(PageManager.registeredOverlayPages));
-    var openPages = [];
-    for (var i = 0; i < allPageNames.length; ++i) {
-      var name = allPageNames[i];
-      var page = PageManager.registeredPages[name] ||
-                 PageManager.registeredOverlayPages[name];
-      if (page.visible)
-        openPages.push(page.name);
-    }
-
-    this.compareArrays_(expectedPages, openPages, true, 'Open pages');
-  },
-
-  /*
-   * Verifies that the correct URLs are listed in the history. Asynchronous.
-   * @param {!Array<string>} expectedHistory An array of URL paths expected to
-   *     be in the tab navigation history, sorted by visit time, including the
-   *     current page as the last entry. The base URL (chrome://settings-frame/)
-   *     will be prepended to each. An initial 'about:blank' history entry is
-   *     assumed and should not be included in this list.
-   * @param {Function=} callback A function to be called after the history has
-   *     been verified successfully. May be undefined.
-   * @private
-   */
-  verifyHistory_: function(expectedHistory, callback) {
-    var self = this;
-    OptionsWebUIExtendedTest.verifyHistoryCallback = function(results) {
-      // The history always starts with a blank page.
-      assertEquals('about:blank', results.shift());
-      var fullExpectedHistory = [];
-      for (var i = 0; i < expectedHistory.length; ++i) {
-        fullExpectedHistory.push(
-            'chrome://settings-frame/' + expectedHistory[i]);
-      }
-      self.compareArrays_(fullExpectedHistory, results, false, 'History');
-      callback();
-    };
-
-    // The C++ fixture will call verifyHistoryCallback with the results.
-    chrome.send('optionsTestReportHistory');
-  },
-
-  /**
-   * Overrides the page callbacks for the given PageManager overlay to verify
-   * that they are not called.
-   * @param {Object} overlay The singleton instance of the overlay.
-   * @private
-   */
-  prohibitChangesToOverlay_: function(overlay) {
-    overlay.initializePage =
-        overlay.didShowPage =
-        overlay.didClosePage = function() {
-          assertTrue(false,
-                     'Overlay was affected when changes were prohibited.');
-        };
-  },
-};
-
-/**
- * Set by verifyHistory_ to incorporate a followup callback, then called by the
- * C++ fixture with the navigation history to be verified.
- * @type {Function}
- */
-OptionsWebUIExtendedTest.verifyHistoryCallback = null;
-
-// Show the search page with no query string, to fall back to the settings page.
-// Test disabled because it's flaky. crbug.com/303841
-TEST_F('OptionsWebUIExtendedTest', 'DISABLED_ShowSearchPageNoQuery',
-       function() {
-  PageManager.showPageByName('search');
-  this.verifyOpenPages_(['settings']);
-  this.verifyHistory_(['settings'], testDone);
-});
-
-// Manipulate the search page via the search field.
-TEST_F('OptionsWebUIExtendedTest', 'ShowSearchFromField', function() {
-  $('search-field').onsearch({currentTarget: {value: 'query'}});
-  this.verifyOpenPages_(['settings', 'search'], 'search#query');
-  this.verifyHistory_(['', 'search#query'], function() {
-    $('search-field').onsearch({currentTarget: {value: 'query2'}});
-    this.verifyOpenPages_(['settings', 'search'], 'search#query2');
-    this.verifyHistory_(['', 'search#query', 'search#query2'], function() {
-      $('search-field').onsearch({currentTarget: {value: ''}});
-      this.verifyOpenPages_(['settings'], '');
-      this.verifyHistory_(['', 'search#query', 'search#query2', ''], testDone);
-    }.bind(this));
-  }.bind(this));
-});
-
-// Show a page without updating history.
-TEST_F('OptionsWebUIExtendedTest', 'ShowPageNoHistory', function() {
-  this.verifyOpenPages_(['settings'], '');
-  PageManager.showPageByName('search', true, {hash: '#query'});
-
-  // The settings page is also still "open" (i.e., visible), in order to show
-  // the search results. Furthermore, the URL hasn't been updated in the parent
-  // page, because we've loaded the chrome-settings frame instead of the whole
-  // settings page, so the cross-origin call to set the URL fails.
-  this.verifyOpenPages_(['settings', 'search'], 'search#query');
-  var self = this;
-  this.verifyHistory_(['', 'search#query'], function() {
-    PageManager.showPageByName('settings', false);
-    self.verifyOpenPages_(['settings'], 'search#query');
-    self.verifyHistory_(['', 'search#query'], testDone);
-  });
-});
-
-TEST_F('OptionsWebUIExtendedTest', 'ShowPageWithHistory', function() {
-  PageManager.showPageByName('search', true, {hash: '#query'});
-  var self = this;
-  this.verifyHistory_(['', 'search#query'], function() {
-    PageManager.showPageByName('settings', true);
-    self.verifyOpenPages_(['settings'], '');
-    self.verifyHistory_(['', 'search#query', ''],
-                        testDone);
-  });
-});
-
-TEST_F('OptionsWebUIExtendedTest', 'ShowPageReplaceHistory', function() {
-  PageManager.showPageByName('search', true, {hash: '#query'});
-  var self = this;
-  this.verifyHistory_(['', 'search#query'], function() {
-    PageManager.showPageByName('settings', true, {'replaceState': true});
-    self.verifyOpenPages_(['settings'], '');
-    self.verifyHistory_(['', ''], testDone);
-  });
-});
-
-// This should be identical to ShowPageWithHisory.
-TEST_F('OptionsWebUIExtendedTest', 'NavigateToPage', function() {
-  PageManager.showPageByName('search', true, {hash: '#query'});
-  var self = this;
-  this.verifyHistory_(['', 'search#query'], function() {
-    PageManager.showPageByName('settings');
-    self.verifyOpenPages_(['settings'], '');
-    self.verifyHistory_(['', 'search#query', ''], testDone);
-  });
-});
-
-// Settings overlays are much more straightforward than settings pages, opening
-// normally with none of the latter's quirks in the expected history or URL.
-TEST_F('OptionsWebUIExtendedTest', 'ShowOverlayNoHistory', function() {
-  // Open a layer-1 overlay, not updating history.
-  PageManager.showPageByName('languages', false);
-  this.verifyOpenPages_(['settings', 'languages'], '');
-
-  var self = this;
-  this.verifyHistory_([''], function() {
-    // Open a layer-2 overlay for which the layer-1 is a parent, not updating
-    // history.
-    PageManager.showPageByName('addLanguage', false);
-    self.verifyOpenPages_(['settings', 'languages', 'addLanguage'],
-                          '');
-    self.verifyHistory_([''], testDone);
-  });
-});
-
-TEST_F('OptionsWebUIExtendedTest', 'ShowOverlayWithHistory', function() {
-  // Open a layer-1 overlay, updating history.
-  PageManager.showPageByName('languages', true);
-  this.verifyOpenPages_(['settings', 'languages']);
-
-  var self = this;
-  this.verifyHistory_(['', 'languages'], function() {
-    // Open a layer-2 overlay, updating history.
-    PageManager.showPageByName('addLanguage', true);
-    self.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
-    self.verifyHistory_(['', 'languages', 'addLanguage'], testDone);
-  });
-});
-
-TEST_F('OptionsWebUIExtendedTest', 'ShowOverlayReplaceHistory', function() {
-  // Open a layer-1 overlay, updating history.
-  PageManager.showPageByName('languages', true);
-  var self = this;
-  this.verifyHistory_(['', 'languages'], function() {
-    // Open a layer-2 overlay, replacing history.
-    PageManager.showPageByName('addLanguage', true, {'replaceState': true});
-    self.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
-    self.verifyHistory_(['', 'addLanguage'], testDone);
-  });
-});
-
-// Directly show an overlay further above this page, i.e. one for which the
-// current page is an ancestor but not a parent.
-TEST_F('OptionsWebUIExtendedTest', 'ShowOverlayFurtherAbove', function() {
-  // Open a layer-2 overlay directly.
-  PageManager.showPageByName('addLanguage', true);
-  this.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
-  var self = this;
-  this.verifyHistory_(['', 'addLanguage'], testDone);
-});
-
-// Directly show a layer-2 overlay for which the layer-1 overlay is not a
-// parent.
-TEST_F('OptionsWebUIExtendedTest', 'ShowUnrelatedOverlay', function() {
-  // Open a layer-1 overlay.
-  PageManager.showPageByName('languages', true);
-  this.verifyOpenPages_(['settings', 'languages']);
-
-  var self = this;
-  this.verifyHistory_(['', 'languages'], function() {
-    // Open an unrelated layer-2 overlay.
-    PageManager.showPageByName('cookies', true);
-    self.verifyOpenPages_(['settings', 'content', 'cookies']);
-    self.verifyHistory_(['', 'languages', 'cookies'], testDone);
-  });
-});
-
-// Close an overlay.
-TEST_F('OptionsWebUIExtendedTest', 'CloseOverlay', function() {
-  // Open a layer-1 overlay, then a layer-2 overlay on top of it.
-  PageManager.showPageByName('languages', true);
-  this.verifyOpenPages_(['settings', 'languages']);
-  PageManager.showPageByName('addLanguage', true);
-  this.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
-
-  var self = this;
-  this.verifyHistory_(['', 'languages', 'addLanguage'], function() {
-    // Close the layer-2 overlay.
-    PageManager.closeOverlay();
-    self.verifyOpenPages_(['settings', 'languages']);
-    self.verifyHistory_(
-        ['', 'languages', 'addLanguage', 'languages'],
-        function() {
-      // Close the layer-1 overlay.
-      PageManager.closeOverlay();
-      self.verifyOpenPages_(['settings'], '');
-      self.verifyHistory_(
-          ['', 'languages', 'addLanguage', 'languages', ''],
-          function noop() {});
-      waitUntilHidden([$('overlay-container-1'), $('overlay-container-2')]);
-    });
-  });
-});
-
-// Hashes are maintained separately for each page and are preserved when
-// overlays close.
-TEST_F('OptionsWebUIExtendedTest', 'CloseOverlayWithHashes', function() {
-  // Open an overlay on top of the search page.
-  PageManager.showPageByName('search', true, {hash: '#1'});
-  this.verifyOpenPages_(['settings', 'search'], 'search#1');
-  PageManager.showPageByName('languages', true, {hash: '#2'});
-  this.verifyOpenPages_(['settings', 'search', 'languages'],
-                        'languages#2');
-  PageManager.showPageByName('addLanguage', true, {hash: '#3'});
-  this.verifyOpenPages_(['settings', 'search', 'languages', 'addLanguage'],
-                       'addLanguage#3');
-
-  this.verifyHistory_(['', 'search#1', 'languages#2', 'addLanguage#3'],
-                      function() {
-    // Close the layer-2 overlay.
-    PageManager.closeOverlay();
-    this.verifyOpenPages_(['settings', 'search', 'languages'], 'languages#2');
-    this.verifyHistory_(
-        ['', 'search#1', 'languages#2', 'addLanguage#3', 'languages#2'],
-        function() {
-      // Close the layer-1 overlay.
-      PageManager.closeOverlay();
-      this.verifyOpenPages_(['settings', 'search'], 'search#1');
-      this.verifyHistory_(
-          ['', 'search#1', 'languages#2', 'addLanguage#3', 'languages#2',
-           'search#1'],
-          function noop() {});
-      waitUntilHidden([$('overlay-container-1'), $('overlay-container-2')]);
-    }.bind(this));
-  }.bind(this));
-});
-
-// Test that closing an overlay that did not push history when opening does not
-// again push history.
-TEST_F('OptionsWebUIExtendedTest', 'CloseOverlayNoHistory', function() {
-  // Open the do not track confirmation prompt.
-  PageManager.showPageByName('doNotTrackConfirm', false);
-
-  // Opening the prompt does not add to the history.
-  this.verifyHistory_([''], function() {
-    // Close the overlay.
-    PageManager.closeOverlay();
-    // Still no history changes.
-    this.verifyHistory_([''], function noop() {});
-    waitUntilHidden([$('overlay-container-1')]);
-  }.bind(this));
-});
-
-// Make sure an overlay isn't closed (even temporarily) when another overlay is
-// opened on top.
-TEST_F('OptionsWebUIExtendedTest', 'OverlayAboveNoReset', function() {
-  // Open a layer-1 overlay.
-  PageManager.showPageByName('languages', true);
-  this.verifyOpenPages_(['settings', 'languages']);
-
-  // Open a layer-2 overlay on top. This should not close 'languages'.
-  this.prohibitChangesToOverlay_(options.LanguageOptions.getInstance());
-  PageManager.showPageByName('addLanguage', true);
-  this.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
-  testDone();
-});
-
-TEST_F('OptionsWebUIExtendedTest', 'OverlayTabNavigation', function() {
-  // Open a layer-1 overlay, then a layer-2 overlay on top of it.
-  PageManager.showPageByName('languages', true);
-  PageManager.showPageByName('addLanguage', true);
-  var self = this;
-
-  // Go back twice, then forward twice.
-  self.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
-  self.verifyHistory_(['', 'languages', 'addLanguage'], function() {
-    window.history.back();
-    waitForPopstate(function() {
-      self.verifyOpenPages_(['settings', 'languages']);
-      self.verifyHistory_(['', 'languages'], function() {
-        window.history.back();
-        waitForPopstate(function() {
-          self.verifyOpenPages_(['settings'], '');
-          self.verifyHistory_([''], function() {
-            window.history.forward();
-            waitForPopstate(function() {
-              self.verifyOpenPages_(['settings', 'languages']);
-              self.verifyHistory_(['', 'languages'], function() {
-                window.history.forward();
-                waitForPopstate(function() {
-                  self.verifyOpenPages_(
-                      ['settings', 'languages', 'addLanguage']);
-                  self.verifyHistory_(
-                      ['', 'languages', 'addLanguage'], testDone);
-                });
-              });
-            });
-          });
-        });
-      });
-    });
-  });
-});
-
-// Going "back" to an overlay that's a child of the current overlay shouldn't
-// close the current one.
-TEST_F('OptionsWebUIExtendedTest', 'OverlayBackToChild', function() {
-  // Open a layer-1 overlay, then a layer-2 overlay on top of it.
-  PageManager.showPageByName('languages', true);
-  PageManager.showPageByName('addLanguage', true);
-  var self = this;
-
-  self.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
-  self.verifyHistory_(['', 'languages', 'addLanguage'], function() {
-    // Close the top overlay, then go back to it.
-    PageManager.closeOverlay();
-    self.verifyOpenPages_(['settings', 'languages']);
-    self.verifyHistory_(
-        ['', 'languages', 'addLanguage', 'languages'],
-        function() {
-      // Going back to the 'addLanguage' page should not close 'languages'.
-      self.prohibitChangesToOverlay_(options.LanguageOptions.getInstance());
-      window.history.back();
-      waitForPopstate(function() {
-        self.verifyOpenPages_(['settings', 'languages', 'addLanguage']);
-        self.verifyHistory_(['', 'languages', 'addLanguage'],
-                            testDone);
-      });
-    });
-  });
-});
-
-// Going back to an unrelated overlay should close the overlay and its parent.
-TEST_F('OptionsWebUIExtendedTest', 'OverlayBackToUnrelated', function() {
-  // Open a layer-1 overlay, then an unrelated layer-2 overlay.
-  PageManager.showPageByName('languages', true);
-  PageManager.showPageByName('cookies', true);
-  var self = this;
-  self.verifyOpenPages_(['settings', 'content', 'cookies']);
-  self.verifyHistory_(['', 'languages', 'cookies'], function() {
-    window.history.back();
-    waitForPopstate(function() {
-      self.verifyOpenPages_(['settings', 'languages']);
-      testDone();
-    });
-  });
-});
-
-// Verify history changes properly while the page is loading.
-TEST_F('OptionsWebUIExtendedTest', 'HistoryUpdatedAfterLoading', function() {
-  var loc = location.href;
-
-  document.documentElement.classList.add('loading');
-  assertTrue(PageManager.isLoading());
-  PageManager.showPageByName('searchEngines');
-  expectNotEquals(loc, location.href);
-
-  document.documentElement.classList.remove('loading');
-  assertFalse(PageManager.isLoading());
-  PageManager.showDefaultPage();
-  expectEquals(loc, location.href);
-
-  testDone();
-});
-
-// A tip should be shown or hidden depending on whether this profile manages any
-// supervised users.
-TEST_F('OptionsWebUIExtendedTest', 'SupervisingUsers', function() {
-  // We start managing no supervised users.
-  assertTrue($('profiles-supervised-dashboard-tip').hidden);
-
-  // Remove all supervised users, then add some, watching for the pref change
-  // notifications and UI updates in each case. Any non-empty pref dictionary
-  // is interpreted as having supervised users.
-  chrome.send('optionsTestSetPref', [SUPERVISED_USERS_PREF, {key: 'value'}]);
-  waitForResponse(BrowserOptions, 'updateManagesSupervisedUsers', function() {
-    assertFalse($('profiles-supervised-dashboard-tip').hidden);
-    chrome.send('optionsTestSetPref', [SUPERVISED_USERS_PREF, {}]);
-    waitForResponse(BrowserOptions, 'updateManagesSupervisedUsers', function() {
-      assertTrue($('profiles-supervised-dashboard-tip').hidden);
-      testDone();
-    });
-  });
-});
-
-/**
- * TestFixture that loads the options page at a bogus URL.
- * @extends {OptionsWebUIExtendedTest}
- * @constructor
- */
-function OptionsWebUIRedirectTest() {
-  OptionsWebUIExtendedTest.call(this);
-}
-
-OptionsWebUIRedirectTest.prototype = {
-  __proto__: OptionsWebUIExtendedTest.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://settings-frame/nonexistantPage',
-};
-
-TEST_F('OptionsWebUIRedirectTest', 'TestURL', function() {
-  assertEquals('chrome://settings-frame/', document.location.href);
-  this.verifyHistory_([''], testDone);
-});
diff --git a/chrome/browser/ui/webui/options/options_browsertest_base.js b/chrome/browser/ui/webui/options/options_browsertest_base.js
deleted file mode 100644
index 073c7dc..0000000
--- a/chrome/browser/ui/webui/options/options_browsertest_base.js
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @constructor
- * @extends {testing.Test}
- */
-function OptionsBrowsertestBase() {}
-
-OptionsBrowsertestBase.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /** @override */
-  runAccessibilityChecks: true,
-
-  /** @override */
-  accessibilityIssuesAreErrors: true,
-
-  /** @override */
-  setUp: function() {
-    testing.Test.prototype.setUp.call(this);
-
-    var requiredOwnedAriaRoleMissingSelectors = [
-      '#address-list',
-      '#creditcard-list',
-      '#home-page-overlay > .autocomplete-suggestions',
-      '#language-options-list',
-      '#manage-profile-icon-grid',
-      '#create-profile-icon-grid',
-      '#saved-passwords-list',
-      '#password-exceptions-list',
-      '#extension-keyword-list',
-      '#startup-overlay > .autocomplete-suggestions',
-      '#content-settings-exceptions-area > .content-area > *',
-      '#cookies-list',
-      '#handlers-list',
-      '#ignored-handlers-list',
-      '#supervised-user-list',
-      '#select-avatar-grid',
-      '#language-dictionary-overlay-word-list',
-      // Selectors below only affect ChromeOS tests.
-      '#bluetooth-unpaired-devices-list',
-      '#ignored-host-list',
-      '#remembered-network-list',
-      '#bluetooth-paired-devices-list',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_ARIA_08: http://crbug.com/559265
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'requiredOwnedAriaRoleMissing',
-        requiredOwnedAriaRoleMissingSelectors);
-
-    var tabIndexGreaterThanZeroSelectors = [
-      '#user-image-grid',
-      '#discard-photo',
-      '#take-photo',
-      '#flip-photo',
-      '#change-picture-overlay-confirm',
-    ];
-
-    // Enable when failure is resolved.
-    // AX_FOCUS_03: http://crbug.com/560910
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'tabIndexGreaterThanZero',
-        tabIndexGreaterThanZeroSelectors);
-
-    // Enable when audit has improved performance.
-    // AX_HTML_02:
-    // https://github.com/GoogleChrome/accessibility-developer-tools/issues/263
-    this.accessibilityAuditConfig.auditRulesToIgnore.push(
-        'duplicateId');
-
-    // Enable when failure is resolved.
-    // AX_ARIA_02: http://crbug.com/591547
-    this.accessibilityAuditConfig.ignoreSelectors(
-         'nonExistentAriaRelatedElement', '#input');
-
-    // Enable when failure is resolved.
-    // AX_ARIA_04: http://crbug.com/591550
-    this.accessibilityAuditConfig.ignoreSelectors(
-         'badAriaAttributeValue', '#input');
-
-  },
-};
diff --git a/chrome/browser/ui/webui/options/password_manager_browsertest.js b/chrome/browser/ui/webui/options/password_manager_browsertest.js
deleted file mode 100644
index e94a72b9..0000000
--- a/chrome/browser/ui/webui/options/password_manager_browsertest.js
+++ /dev/null
@@ -1,26 +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.
-
-/**
- * TestFixture for password manager WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function PasswordManagerWebUITest() {}
-
-PasswordManagerWebUITest.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /**
-   * Browse to the password manager.
-   */
-  browsePreload: 'chrome://settings-frame/passwords',
-};
-
-// Test opening the password manager has correct location.
-// Fails on Linux and Windows.  http://crbug.com/467916
-TEST_F('PasswordManagerWebUITest', 'DISABLED_testOpenPasswordManager',
-       function() {
-         assertEquals(this.browsePreload, document.location.href);
-       });
diff --git a/chrome/browser/ui/webui/options/password_manager_handler_unittest.cc b/chrome/browser/ui/webui/options/password_manager_handler_unittest.cc
deleted file mode 100644
index bdd275e..0000000
--- a/chrome/browser/ui/webui/options/password_manager_handler_unittest.cc
+++ /dev/null
@@ -1,244 +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.
-
-#include "chrome/browser/ui/webui/options/password_manager_handler.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/statistics_recorder.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/password_manager/password_store_factory.h"
-#include "chrome/browser/ui/passwords/password_manager_presenter.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/password_manager/core/browser/mock_password_store.h"
-#include "components/password_manager/core/browser/password_manager_test_utils.h"
-#include "content/public/test/test_web_ui.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/shell_dialogs/select_file_dialog.h"
-#include "ui/shell_dialogs/select_file_dialog_factory.h"
-#include "ui/shell_dialogs/select_file_policy.h"
-
-using password_manager::MockPasswordStore;
-
-namespace {
-
-class TestSelectFileDialogFactory final : public ui::SelectFileDialogFactory {
- public:
-  TestSelectFileDialogFactory() {}
-  ~TestSelectFileDialogFactory() override {}
-  ui::SelectFileDialog* Create(ui::SelectFileDialog::Listener* listener,
-                               ui::SelectFilePolicy* policy) override {
-    delete policy;  // Ignore the policy, replace it with a test one.
-    return new TestSelectFileDialog(listener, new TestSelectFilePolicy);
-  }
-
- private:
-  class TestSelectFilePolicy : public ui::SelectFilePolicy {
-   public:
-    bool CanOpenSelectFileDialog() override { return true; }
-    void SelectFileDenied() override {}
-  };
-
-  class TestSelectFileDialog : public ui::SelectFileDialog {
-   public:
-    TestSelectFileDialog(Listener* listener, ui::SelectFilePolicy* policy)
-        : ui::SelectFileDialog(listener, policy) {}
-
-   protected:
-    void SelectFileImpl(Type type,
-                        const base::string16& title,
-                        const base::FilePath& default_path,
-                        const FileTypeInfo* file_types,
-                        int file_type_index,
-                        const base::FilePath::StringType& default_extension,
-                        gfx::NativeWindow owning_window,
-                        void* params) override {
-      listener_->FileSelected(default_path, file_type_index, params);
-    }
-    bool IsRunning(gfx::NativeWindow owning_window) const override {
-      return false;
-    }
-    void ListenerDestroyed() override {}
-    bool HasMultipleFileTypeChoicesImpl() override { return false; }
-    ~TestSelectFileDialog() override {}
-  };
-};
-
-class CallbackTestWebUI : public content::TestWebUI {
- public:
-  CallbackTestWebUI() {}
-  ~CallbackTestWebUI() override {}
-  void RegisterMessageCallback(const std::string& message,
-                               const MessageCallback& callback) override;
-  void ProcessWebUIMessage(const GURL& source_url,
-                           const std::string& message,
-                           const base::ListValue& args) override;
-
-  MOCK_CONST_METHOD0(GetWebContents, content::WebContents*());
-
- private:
-  std::map<std::string, MessageCallback> message_callbacks_;
-};
-
-void CallbackTestWebUI::RegisterMessageCallback(
-    const std::string& message,
-    const MessageCallback& callback) {
-  message_callbacks_.insert(std::make_pair(message, callback));
-}
-
-void CallbackTestWebUI::ProcessWebUIMessage(const GURL& source_url,
-                                            const std::string& message,
-                                            const base::ListValue& args) {
-  std::map<std::string, MessageCallback>::const_iterator callback =
-      message_callbacks_.find(message);
-  if (callback != message_callbacks_.end()) {
-    callback->second.Run(&args);
-  }
-}
-
-class TestPasswordManagerHandler : public options::PasswordManagerHandler {
- public:
-  TestPasswordManagerHandler(
-      std::unique_ptr<PasswordManagerPresenter> presenter,
-      CallbackTestWebUI* web_ui)
-      : PasswordManagerHandler(std::move(presenter)) {
-    set_web_ui(web_ui);
-  }
-  ~TestPasswordManagerHandler() override {}
-#if !defined(OS_ANDROID)
-  gfx::NativeWindow GetNativeWindow() const override;
-#endif
-
-  MOCK_METHOD3(FileSelected, void(const base::FilePath& path, int, void*));
-};
-#if !defined(OS_ANDROID)
-gfx::NativeWindow TestPasswordManagerHandler::GetNativeWindow() const {
-  return NULL;
-}
-#endif
-
-class MockPasswordManagerPresenter : public PasswordManagerPresenter {
- public:
-  explicit MockPasswordManagerPresenter(PasswordUIView* handler)
-      : PasswordManagerPresenter(handler) {}
-  ~MockPasswordManagerPresenter() override {}
-
-  MOCK_METHOD0(IsUserAuthenticated, bool());
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerPresenter);
-};
-
-class DummyPasswordManagerHandler : public PasswordUIView {
- public:
-  explicit DummyPasswordManagerHandler(Profile* profile)
-      : profile_(profile), password_manager_presenter_(this) {
-    password_manager_presenter_.Initialize();
-  }
-  ~DummyPasswordManagerHandler() override {}
-  Profile* GetProfile() override;
-
-  void ShowPassword(size_t,
-                    const std::string&,
-                    const std::string&,
-                    const base::string16&) override {}
-  void SetPasswordList(
-      const std::vector<std::unique_ptr<autofill::PasswordForm>>&) override {}
-  void SetPasswordExceptionList(
-      const std::vector<std::unique_ptr<autofill::PasswordForm>>&) override {}
-
-#if !defined(OS_ANDROID)
-  gfx::NativeWindow GetNativeWindow() const override;
-#endif
- private:
-  Profile* profile_;
-  PasswordManagerPresenter password_manager_presenter_;
-
-  DISALLOW_COPY_AND_ASSIGN(DummyPasswordManagerHandler);
-};
-
-#if !defined(OS_ANDROID)
-gfx::NativeWindow DummyPasswordManagerHandler::GetNativeWindow() const {
-  return NULL;
-}
-#endif
-
-Profile* DummyPasswordManagerHandler::GetProfile() {
-  return profile_;
-}
-
-}  // namespace
-
-class PasswordManagerHandlerTest : public ChromeRenderViewHostTestHarness {
- protected:
-  PasswordManagerHandlerTest() {}
-  ~PasswordManagerHandlerTest() override {}
-
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-    dummy_handler_.reset(new DummyPasswordManagerHandler(profile()));
-    presenter_raw_ = new MockPasswordManagerPresenter(dummy_handler_.get());
-    handler_.reset(new TestPasswordManagerHandler(
-        base::WrapUnique(presenter_raw_), &web_ui_));
-    handler_->RegisterMessages();
-    ui::SelectFileDialog::SetFactory(new TestSelectFileDialogFactory);
-    handler_->InitializeHandler();
-    web_ui_.set_web_contents(web_contents());
-  }
-
-  void TearDown() override {
-    handler_.reset();
-    dummy_handler_.reset();
-    ChromeRenderViewHostTestHarness::TearDown();
-  }
-
-  void ExportPassword() {
-    base::ListValue tmp;
-    web_ui_.ProcessWebUIMessage(GURL(), "exportPassword", tmp);
-  }
-
-  void ImportPassword() {
-    base::ListValue tmp;
-    web_ui_.ProcessWebUIMessage(GURL(), "importPassword", tmp);
-  }
-
-  PasswordManagerPresenter* presenter_raw_;
-  CallbackTestWebUI web_ui_;
-  std::unique_ptr<DummyPasswordManagerHandler> dummy_handler_;
-  std::unique_ptr<TestPasswordManagerHandler> handler_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PasswordManagerHandlerTest);
-};
-
-MATCHER(IsEmptyPath, "") {
-  return arg.empty();
-}
-
-TEST_F(PasswordManagerHandlerTest, PasswordImport) {
-  EXPECT_CALL(web_ui_, GetWebContents())
-      .WillRepeatedly(testing::Return(web_contents()));
-  EXPECT_CALL(
-      *handler_,
-      FileSelected(IsEmptyPath(), 1,
-                   reinterpret_cast<void*>(
-                       TestPasswordManagerHandler::IMPORT_FILE_SELECTED)));
-  ImportPassword();
-}
-
-TEST_F(PasswordManagerHandlerTest, PasswordExport) {
-  const base::FilePath file_path;
-  EXPECT_CALL(*(static_cast<MockPasswordManagerPresenter*>(presenter_raw_)),
-              IsUserAuthenticated())
-      .Times(testing::AtLeast(1))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(
-      *handler_,
-      FileSelected(IsEmptyPath(), 1,
-                   reinterpret_cast<void*>(
-                       TestPasswordManagerHandler::EXPORT_FILE_SELECTED)));
-  ExportPassword();
-}
diff --git a/chrome/browser/ui/webui/options/pepper_flash_content_settings_utils_unittest.cc b/chrome/browser/ui/webui/options/pepper_flash_content_settings_utils_unittest.cc
deleted file mode 100644
index dd1317c..0000000
--- a/chrome/browser/ui/webui/options/pepper_flash_content_settings_utils_unittest.cc
+++ /dev/null
@@ -1,137 +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/ui/webui/options/pepper_flash_content_settings_utils.h"
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using options::MediaException;
-using options::MediaExceptions;
-using options::PepperFlashContentSettingsUtils;
-
-namespace {
-
-MediaExceptions ConvertAndSort(const MediaException* items, size_t count) {
-  MediaExceptions result(items, items + count);
-  PepperFlashContentSettingsUtils::SortMediaExceptions(&result);
-  return result;
-}
-
-}  // namespace
-
-TEST(PepperFlashContentSettingsUtilsTest, SortMediaExceptions) {
-  MediaException entry_1(ContentSettingsPattern::FromString("www.google.com"),
-                         CONTENT_SETTING_ALLOW);
-  MediaException entry_2(ContentSettingsPattern::FromString("www.youtube.com"),
-                         CONTENT_SETTING_BLOCK);
-  MediaException entry_3(ContentSettingsPattern::Wildcard(),
-                         CONTENT_SETTING_ASK);
-  MediaException entry_4(ContentSettingsPattern(),
-                         CONTENT_SETTING_SESSION_ONLY);
-
-  MediaExceptions list_1;
-  list_1.push_back(entry_1);
-  list_1.push_back(entry_2);
-  list_1.push_back(entry_3);
-  list_1.push_back(entry_4);
-
-  MediaExceptions list_2;
-  list_2.push_back(entry_1);
-  list_2.push_back(entry_3);
-  list_2.push_back(entry_2);
-  list_2.push_back(entry_4);
-
-  MediaExceptions list_3;
-  list_3.push_back(entry_4);
-  list_3.push_back(entry_1);
-  list_3.push_back(entry_2);
-  list_3.push_back(entry_3);
-
-  EXPECT_NE(list_1, list_2);
-  EXPECT_NE(list_2, list_3);
-  EXPECT_NE(list_3, list_1);
-
-  PepperFlashContentSettingsUtils::SortMediaExceptions(&list_1);
-  PepperFlashContentSettingsUtils::SortMediaExceptions(&list_2);
-  PepperFlashContentSettingsUtils::SortMediaExceptions(&list_3);
-
-  EXPECT_EQ(list_1, list_2);
-  EXPECT_EQ(list_2, list_3);
-}
-
-TEST(PepperFlashContentSettingsUtilsTest, AreMediaExceptionsEqual) {
-  {
-    // Empty lists are equal.
-    // Default settings are not compared directly, so it is possible to return
-    // true when they are different.
-    EXPECT_TRUE(PepperFlashContentSettingsUtils::AreMediaExceptionsEqual(
-        CONTENT_SETTING_BLOCK,
-        MediaExceptions(),
-        CONTENT_SETTING_ASK,
-        MediaExceptions()));
-  }
-
-  {
-    MediaException exceptions_1[] = {
-      MediaException(ContentSettingsPattern::FromString("www.google.com"),
-                     CONTENT_SETTING_ALLOW),
-      MediaException(ContentSettingsPattern::FromString("www.youtube.com"),
-                     CONTENT_SETTING_ASK)
-    };
-
-    MediaException exceptions_2[] = {
-      MediaException(ContentSettingsPattern::FromString("www.google.com"),
-                     CONTENT_SETTING_ALLOW)
-    };
-
-    // The exception of "www.youtube.com" in |exceptions_1| should not affect
-    // the result, because it has the same settings as |default_setting_2|.
-    EXPECT_TRUE(PepperFlashContentSettingsUtils::AreMediaExceptionsEqual(
-        CONTENT_SETTING_ALLOW,
-        ConvertAndSort(exceptions_1, arraysize(exceptions_1)),
-        CONTENT_SETTING_ASK,
-        ConvertAndSort(exceptions_2, arraysize(exceptions_2))));
-    EXPECT_TRUE(PepperFlashContentSettingsUtils::AreMediaExceptionsEqual(
-        CONTENT_SETTING_ASK,
-        ConvertAndSort(exceptions_2, arraysize(exceptions_2)),
-        CONTENT_SETTING_ALLOW,
-        ConvertAndSort(exceptions_1, arraysize(exceptions_1))));
-    // Changing |default_setting_2| should change the result.
-    EXPECT_FALSE(PepperFlashContentSettingsUtils::AreMediaExceptionsEqual(
-        CONTENT_SETTING_ALLOW,
-        ConvertAndSort(exceptions_1, arraysize(exceptions_1)),
-        CONTENT_SETTING_ALLOW,
-        ConvertAndSort(exceptions_2, arraysize(exceptions_2))));
-  }
-
-  {
-    // Similar to the previous block, but reoder the exceptions. The outcome
-    // should be the same.
-    MediaException exceptions_1[] = {
-      MediaException(ContentSettingsPattern::FromString("www.youtube.com"),
-                     CONTENT_SETTING_ASK),
-      MediaException(ContentSettingsPattern::FromString("www.google.com"),
-                     CONTENT_SETTING_ALLOW)
-    };
-
-    MediaException exceptions_2[] = {
-      MediaException(ContentSettingsPattern::FromString("www.google.com"),
-                     CONTENT_SETTING_ALLOW)
-    };
-
-    EXPECT_TRUE(PepperFlashContentSettingsUtils::AreMediaExceptionsEqual(
-        CONTENT_SETTING_ALLOW,
-        ConvertAndSort(exceptions_1, arraysize(exceptions_1)),
-        CONTENT_SETTING_ASK,
-        ConvertAndSort(exceptions_2, arraysize(exceptions_2))));
-    EXPECT_FALSE(PepperFlashContentSettingsUtils::AreMediaExceptionsEqual(
-        CONTENT_SETTING_ALLOW,
-        ConvertAndSort(exceptions_1, arraysize(exceptions_1)),
-        CONTENT_SETTING_ALLOW,
-        ConvertAndSort(exceptions_2, arraysize(exceptions_2))));
-  }
-}
diff --git a/chrome/browser/ui/webui/options/preferences_browsertest.cc b/chrome/browser/ui/webui/options/preferences_browsertest.cc
deleted file mode 100644
index 3cc4c0b..0000000
--- a/chrome/browser/ui/webui/options/preferences_browsertest.cc
+++ /dev/null
@@ -1,1106 +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/ui/webui/options/preferences_browsertest.h"
-
-#include <stddef.h>
-
-#include <iostream>
-#include <memory>
-#include <sstream>
-#include <utility>
-
-#include "base/callback.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/memory/ptr_util.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/policy/core/browser/browser_policy_connector.h"
-#include "components/policy/core/common/external_data_fetcher.h"
-#include "components/policy/core/common/policy_map.h"
-#include "components/policy/core/common/policy_types.h"
-#include "components/policy/policy_constants.h"
-#include "components/prefs/pref_service.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/browser_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-#if defined(OS_CHROMEOS)
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/proxy_cros_settings_parser.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/chromeos/settings/stub_install_attributes.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/shill_profile_client.h"
-#include "chromeos/dbus/shill_service_client.h"
-#include "chromeos/network/network_state.h"
-#include "chromeos/network/network_state_handler.h"
-#include "chromeos/network/proxy/proxy_config_handler.h"
-#include "chromeos/settings/cros_settings_names.h"
-#include "components/onc/onc_pref_names.h"
-#include "components/proxy_config/proxy_config_dictionary.h"
-#include "components/proxy_config/proxy_config_pref_names.h"
-#include "content/public/test/test_utils.h"
-#include "third_party/cros_system_api/dbus/service_constants.h"
-#endif
-
-using testing::AllOf;
-using testing::Mock;
-using testing::Property;
-using testing::Return;
-using testing::_;
-
-namespace base {
-
-// Helper for pretty-printing the contents of base::Value in case of failures.
-void PrintTo(const base::Value& value, std::ostream* stream) {
-  std::string json;
-  JSONWriter::Write(value, &json);
-  *stream << json;
-}
-
-}  // namespace base
-
-// Googlemock matcher for base::Value.
-MATCHER_P(EqualsValue, expected, "") {
-  return arg && arg->Equals(expected);
-}
-
-PreferencesBrowserTest::PreferencesBrowserTest() {
-}
-
-PreferencesBrowserTest::~PreferencesBrowserTest() {
-}
-
-PrefService* PreferencesBrowserTest::pref_service() {
-  DCHECK(pref_change_registrar_);
-  return pref_change_registrar_->prefs();
-}
-
-// Navigates to the settings page, causing the JavaScript pref handling code to
-// load and injects JavaScript testing code.
-void PreferencesBrowserTest::SetUpOnMainThread() {
-  ui_test_utils::NavigateToURL(browser(),
-                               GURL(chrome::kChromeUISettingsFrameURL));
-  SetUpPrefs();
-}
-
-void PreferencesBrowserTest::TearDownOnMainThread() {
-  pref_change_registrar_.reset();
-}
-
-void PreferencesBrowserTest::SetUpPrefs() {
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  render_view_host_ = web_contents->GetRenderViewHost();
-  ASSERT_TRUE(render_view_host_);
-
-  DCHECK(!pref_change_registrar_);
-  pref_change_registrar_.reset(new PrefChangeRegistrar);
-  pref_change_registrar_->Init(browser()->profile()->GetPrefs());
-
-  ASSERT_TRUE(content::ExecuteScript(render_view_host_,
-      "function TestEnv() {"
-      "  this.sentinelName_ = 'download.prompt_for_download';"
-      "  this.prefs_ = [];"
-      "  TestEnv.instance_ = this;"
-      "}"
-      ""
-      "TestEnv.handleEvent = function(event) {"
-      "  var env = TestEnv.instance_;"
-      "  var name = event.type;"
-      "  env.removePrefListener_(name);"
-      "  if (name == TestEnv.sentinelName_)"
-      "    env.sentinelValue_ = event.value.value;"
-      "  else"
-      "    env.reply_[name] = event.value;"
-      "  if (env.fetching_ && !--env.fetching_ ||"
-      "      !env.fetching_ && name == env.sentinelName_) {"
-      "    env.removePrefListeners_();"
-      "    window.domAutomationController.send(JSON.stringify(env.reply_));"
-      "    delete env.reply_;"
-      "  }"
-      "};"
-      ""
-      "TestEnv.prototype = {"
-      "  addPrefListener_: function(name) {"
-      "    Preferences.getInstance().addEventListener(name,"
-      "                                               TestEnv.handleEvent);"
-      "  },"
-      ""
-      "  addPrefListeners_: function() {"
-      "    for (var i in this.prefs_)"
-      "      this.addPrefListener_(this.prefs_[i]);"
-      "  },"
-      ""
-      "  removePrefListener_: function(name) {"
-      "    Preferences.getInstance().removeEventListener(name,"
-      "                                                  TestEnv.handleEvent);"
-      "  },"
-      ""
-      "  removePrefListeners_: function() {"
-      "    for (var i in this.prefs_)"
-      "      this.removePrefListener_(this.prefs_[i]);"
-      "  },"
-      ""
-      ""
-      "  addPref: function(name) {"
-      "    this.prefs_.push(name);"
-      "  },"
-      ""
-      "  setupAndReply: function() {"
-      "    this.reply_ = {};"
-      "    Preferences.instance_ = new Preferences();"
-      "    this.addPref(this.sentinelName_);"
-      "    this.fetching_ = this.prefs_.length;"
-      "    this.addPrefListeners_();"
-      "    Preferences.getInstance().initialize();"
-      "  },"
-      ""
-      "  runAndReply: function(test) {"
-      "    this.reply_ = {};"
-      "    this.addPrefListeners_();"
-      "    test();"
-      "    this.sentinelValue_ = !this.sentinelValue_;"
-      "    Preferences.setBooleanPref(this.sentinelName_, this.sentinelValue_,"
-      "                               true);"
-      "  },"
-      ""
-      "  startObserving: function() {"
-      "    this.reply_ = {};"
-      "    this.addPrefListeners_();"
-      "  },"
-      ""
-      "  finishObservingAndReply: function() {"
-      "    this.sentinelValue_ = !this.sentinelValue_;"
-      "    Preferences.setBooleanPref(this.sentinelName_, this.sentinelValue_,"
-      "                               true);"
-      "  }"
-      "};"));
-}
-
-// Forwards notifications received when pref values change in the backend.
-void PreferencesBrowserTest::OnPreferenceChanged(const std::string& pref_name) {
-  OnCommit(pref_service()->FindPreference(pref_name.c_str()));
-}
-
-void PreferencesBrowserTest::SetUpInProcessBrowserTestFixture() {
-  // Sets up a mock policy provider for user and device policies.
-  EXPECT_CALL(policy_provider_, IsInitializationComplete(_))
-      .WillRepeatedly(Return(true));
-  policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
-      &policy_provider_);
-}
-
-void PreferencesBrowserTest::SetUserPolicies(
-    const std::vector<std::string>& names,
-    const std::vector<std::unique_ptr<base::Value>>& values,
-    policy::PolicyLevel level) {
-  policy::PolicyMap map;
-  for (size_t i = 0; i < names.size(); ++i) {
-    map.Set(names[i], level, policy::POLICY_SCOPE_USER,
-            policy::POLICY_SOURCE_CLOUD, values[i]->CreateDeepCopy(), nullptr);
-  }
-  policy_provider_.UpdateChromePolicy(map);
-}
-
-void PreferencesBrowserTest::ClearUserPolicies() {
-  policy::PolicyMap empty_policy_map;
-  policy_provider_.UpdateChromePolicy(empty_policy_map);
-}
-
-void PreferencesBrowserTest::SetUserValues(
-    const std::vector<std::string>& names,
-    const std::vector<std::unique_ptr<base::Value>>& values) {
-  for (size_t i = 0; i < names.size(); ++i) {
-    pref_service()->Set(names[i].c_str(), *values[i]);
-  }
-}
-
-void PreferencesBrowserTest::VerifyKeyValue(const base::DictionaryValue& dict,
-                                            const std::string& key,
-                                            const base::Value& expected) {
-  const base::Value* actual = NULL;
-  EXPECT_TRUE(dict.Get(key, &actual)) << "Was checking key: " << key;
-  if (actual)
-    EXPECT_EQ(expected, *actual) << "Was checking key: " << key;
-}
-
-void PreferencesBrowserTest::VerifyPref(
-    const base::DictionaryValue* prefs,
-    const std::string& name,
-    const std::unique_ptr<base::Value>& value,
-    const std::string& controlledBy,
-    bool disabled,
-    bool uncommitted) {
-  const base::Value* pref = NULL;
-  const base::DictionaryValue* dict = NULL;
-  ASSERT_TRUE(prefs->GetWithoutPathExpansion(name, &pref));
-  ASSERT_TRUE(pref->GetAsDictionary(&dict));
-  VerifyKeyValue(*dict, "value", *value);
-  if (!controlledBy.empty())
-    VerifyKeyValue(*dict, "controlledBy", base::Value(controlledBy));
-  else
-    EXPECT_FALSE(dict->HasKey("controlledBy"));
-
-  if (disabled)
-    VerifyKeyValue(*dict, "disabled", base::Value(true));
-  else if (dict->HasKey("disabled"))
-    VerifyKeyValue(*dict, "disabled", base::Value(false));
-
-  if (uncommitted)
-    VerifyKeyValue(*dict, "uncommitted", base::Value(true));
-  else if (dict->HasKey("uncommitted"))
-    VerifyKeyValue(*dict, "uncommitted", base::Value(false));
-}
-
-void PreferencesBrowserTest::VerifyObservedPref(
-    const std::string& json,
-    const std::string& name,
-    const std::unique_ptr<base::Value>& value,
-    const std::string& controlledBy,
-    bool disabled,
-    bool uncommitted) {
-  std::unique_ptr<base::Value> observed_value_ptr =
-      base::JSONReader::Read(json);
-  const base::DictionaryValue* observed_dict;
-  ASSERT_TRUE(observed_value_ptr.get());
-  ASSERT_TRUE(observed_value_ptr->GetAsDictionary(&observed_dict));
-  VerifyPref(observed_dict, name, value, controlledBy, disabled, uncommitted);
-}
-
-void PreferencesBrowserTest::VerifyObservedPrefs(
-    const std::string& json,
-    const std::vector<std::string>& names,
-    const std::vector<std::unique_ptr<base::Value>>& values,
-    const std::string& controlledBy,
-    bool disabled,
-    bool uncommitted) {
-  std::unique_ptr<base::Value> observed_value_ptr =
-      base::JSONReader::Read(json);
-  const base::DictionaryValue* observed_dict;
-  ASSERT_TRUE(observed_value_ptr.get());
-  ASSERT_TRUE(observed_value_ptr->GetAsDictionary(&observed_dict));
-  for (size_t i = 0; i < names.size(); ++i) {
-    VerifyPref(observed_dict, names[i], values[i], controlledBy, disabled,
-               uncommitted);
-  }
-}
-
-void PreferencesBrowserTest::ExpectNoCommit(const std::string& name) {
-  pref_change_registrar_->Add(
-      name.c_str(),
-      base::Bind(&PreferencesBrowserTest::OnPreferenceChanged,
-                 base::Unretained(this)));
-  EXPECT_CALL(*this, OnCommit(Property(&PrefService::Preference::name, name)))
-      .Times(0);
-}
-
-void PreferencesBrowserTest::ExpectSetCommit(
-    const std::string& name,
-    const std::unique_ptr<base::Value>& value) {
-  pref_change_registrar_->Add(
-      name.c_str(),
-      base::Bind(&PreferencesBrowserTest::OnPreferenceChanged,
-                 base::Unretained(this)));
-  EXPECT_CALL(
-      *this,
-      OnCommit(AllOf(Property(&PrefService::Preference::name, name),
-                     Property(&PrefService::Preference::IsUserControlled, true),
-                     Property(&PrefService::Preference::GetValue,
-                              EqualsValue(value.get())))));
-}
-
-void PreferencesBrowserTest::ExpectClearCommit(const std::string& name) {
-  pref_change_registrar_->Add(
-      name.c_str(),
-      base::Bind(&PreferencesBrowserTest::OnPreferenceChanged,
-                 base::Unretained(this)));
-  EXPECT_CALL(*this, OnCommit(AllOf(
-      Property(&PrefService::Preference::name, name),
-      Property(&PrefService::Preference::IsUserControlled, false))));
-}
-
-void PreferencesBrowserTest::VerifyAndClearExpectations() {
-  Mock::VerifyAndClearExpectations(this);
-  pref_change_registrar_->RemoveAll();
-}
-
-void PreferencesBrowserTest::SetupJavaScriptTestEnvironment(
-    const std::vector<std::string>& pref_names,
-    std::string* observed_json) const {
-  std::stringstream javascript;
-  javascript << "var testEnv = new TestEnv();";
-  for (const auto& name : pref_names) {
-    javascript << "testEnv.addPref('" << name.c_str() << "');";
-  }
-  javascript << "testEnv.setupAndReply();";
-  std::string temp_observed_json;
-  if (!observed_json)
-    observed_json = &temp_observed_json;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
-      render_view_host_, javascript.str(), observed_json));
-}
-
-void PreferencesBrowserTest::SetPref(const std::string& name,
-                                     const std::string& type,
-                                     const std::unique_ptr<base::Value>& value,
-                                     bool commit,
-                                     std::string* observed_json) {
-  std::unique_ptr<base::Value> commit_ptr(new base::Value(commit));
-  std::stringstream javascript;
-  javascript << "testEnv.runAndReply(function() {"
-             << "  Preferences.set" << type << "Pref("
-             << "      '" << name << "',"
-             << "      " << *value << ","
-             << "      " << *commit_ptr << ");"
-             << "});";
-  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
-      render_view_host_, javascript.str(), observed_json));
-}
-
-void PreferencesBrowserTest::VerifySetPref(
-    const std::string& name,
-    const std::string& type,
-    const std::unique_ptr<base::Value>& value,
-    bool commit) {
-  if (commit)
-    ExpectSetCommit(name, value);
-  else
-    ExpectNoCommit(name);
-  std::string observed_json;
-  SetPref(name, type, value, commit, &observed_json);
-  VerifyObservedPref(observed_json, name, value, std::string(), false, !commit);
-  VerifyAndClearExpectations();
-}
-
-void PreferencesBrowserTest::VerifyClearPref(
-    const std::string& name,
-    const std::unique_ptr<base::Value>& value,
-    bool commit) {
-  if (commit)
-    ExpectClearCommit(name);
-  else
-    ExpectNoCommit(name);
-  std::string commit_json;
-  base::JSONWriter::Write(base::Value(commit), &commit_json);
-  std::stringstream javascript;
-  javascript << "testEnv.runAndReply(function() {"
-             << "    Preferences.clearPref("
-             << "      '" << name.c_str() << "',"
-             << "      " << commit_json.c_str() << ");});";
-  std::string observed_json;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
-      render_view_host_, javascript.str(), &observed_json));
-  VerifyObservedPref(observed_json, name, value, "recommended", false, !commit);
-  VerifyAndClearExpectations();
-}
-
-void PreferencesBrowserTest::VerifyCommit(
-    const std::string& name,
-    const std::unique_ptr<base::Value>& value,
-    const std::string& controlledBy) {
-  std::stringstream javascript;
-  javascript << "testEnv.runAndReply(function() {"
-             << "    Preferences.getInstance().commitPref("
-             << "        '" << name.c_str() << "');});";
-  std::string observed_json;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
-      render_view_host_, javascript.str(), &observed_json));
-  VerifyObservedPref(observed_json, name, value, controlledBy, false, false);
-}
-
-void PreferencesBrowserTest::VerifySetCommit(
-    const std::string& name,
-    const std::unique_ptr<base::Value>& value) {
-  ExpectSetCommit(name, value);
-  VerifyCommit(name, value, std::string());
-  VerifyAndClearExpectations();
-}
-
-void PreferencesBrowserTest::VerifyClearCommit(
-    const std::string& name,
-    const std::unique_ptr<base::Value>& value) {
-  ExpectClearCommit(name);
-  VerifyCommit(name, value, "recommended");
-  VerifyAndClearExpectations();
-}
-
-void PreferencesBrowserTest::VerifyRollback(
-    const std::string& name,
-    const std::unique_ptr<base::Value>& value,
-    const std::string& controlledBy) {
-  ExpectNoCommit(name);
-  std::stringstream javascript;
-  javascript << "testEnv.runAndReply(function() {"
-             << "    Preferences.getInstance().rollbackPref("
-             << "        '" << name.c_str() << "');});";
-  std::string observed_json;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
-      render_view_host_, javascript.str(), &observed_json));
-  VerifyObservedPref(observed_json, name, value, controlledBy, false, true);
-  VerifyAndClearExpectations();
-}
-
-void PreferencesBrowserTest::StartObserving() {
-  ASSERT_TRUE(content::ExecuteScript(
-      render_view_host_, "testEnv.startObserving();"));
-}
-
-void PreferencesBrowserTest::FinishObserving(std::string* observed_json) {
-  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
-      render_view_host_,
-      "testEnv.finishObservingAndReply();",
-      observed_json));
-}
-
-void PreferencesBrowserTest::UseDefaultTestPrefs(bool includeListPref) {
-  // Boolean pref.
-  types_.push_back("Boolean");
-  pref_names_.push_back(prefs::kAlternateErrorPagesEnabled);
-  policy_names_.push_back(policy::key::kAlternateErrorPagesEnabled);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(false));
-
-  // Integer pref.
-  types_.push_back("Integer");
-  pref_names_.push_back(prefs::kRestoreOnStartup);
-  policy_names_.push_back(policy::key::kRestoreOnStartup);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(4));
-
-  // List pref.
-  if (includeListPref) {
-    types_.push_back("List");
-    pref_names_.push_back(prefs::kURLsToRestoreOnStartup);
-    policy_names_.push_back(policy::key::kRestoreOnStartupURLs);
-    auto list = base::MakeUnique<base::ListValue>();
-    list->AppendString("http://www.example.com");
-    list->AppendString("http://example.com");
-    non_default_values_.push_back(std::move(list));
-  }
-
-  // Retrieve default values.
-  for (const auto& name : pref_names_) {
-    default_values_.push_back(
-        pref_service()->GetDefaultPrefValue(name.c_str())->CreateDeepCopy());
-  }
-}
-
-// Verifies that initializing the JavaScript Preferences class fires the correct
-// notifications in JavaScript.
-IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, FetchPrefs) {
-  UseDefaultTestPrefs(true);
-  std::string observed_json;
-
-  // Verify notifications when default values are in effect.
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, default_values_,
-                      std::string(), false, false);
-
-  // Verify notifications when recommended values are in effect.
-  SetUserPolicies(policy_names_, non_default_values_,
-                  policy::POLICY_LEVEL_RECOMMENDED);
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_,
-                      "recommended", false, false);
-
-  // Verify notifications when mandatory values are in effect.
-  SetUserPolicies(policy_names_, non_default_values_,
-                  policy::POLICY_LEVEL_MANDATORY);
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, "policy",
-                      true, false);
-
-  // Verify notifications when user-modified values are in effect.
-  ClearUserPolicies();
-  SetUserValues(pref_names_, non_default_values_);
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_,
-                      std::string(), false, false);
-}
-
-// Verifies that setting a user-modified pref value through the JavaScript
-// Preferences class fires the correct notification in JavaScript and causes the
-// change to be committed to the C++ backend.
-IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, SetPrefs) {
-  UseDefaultTestPrefs(false);
-
-  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
-  for (size_t i = 0; i < pref_names_.size(); ++i) {
-    VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], true);
-  }
-}
-
-// Verifies that clearing a user-modified pref value through the JavaScript
-// Preferences class fires the correct notification in JavaScript and causes the
-// change to be committed to the C++ backend.
-IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, ClearPrefs) {
-  UseDefaultTestPrefs(false);
-
-  SetUserPolicies(policy_names_, default_values_,
-                  policy::POLICY_LEVEL_RECOMMENDED);
-  SetUserValues(pref_names_, non_default_values_);
-  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
-  for (size_t i = 0; i < pref_names_.size(); ++i) {
-    VerifyClearPref(pref_names_[i], default_values_[i], true);
-  }
-}
-
-// Verifies that when the user-modified value of a dialog pref is set and the
-// change then committed through the JavaScript Preferences class, the correct
-// notifications fire and a commit to the C++ backend occurs in the latter step
-// only.
-IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsSetCommit) {
-  UseDefaultTestPrefs(false);
-
-  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
-  for (size_t i = 0; i < pref_names_.size(); ++i) {
-    VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false);
-    VerifySetCommit(pref_names_[i], non_default_values_[i]);
-  }
-}
-
-// Verifies that when the user-modified value of a dialog pref is set and the
-// change then rolled back through the JavaScript Preferences class, the correct
-// notifications fire and no commit to the C++ backend occurs.
-IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsSetRollback) {
-  UseDefaultTestPrefs(false);
-
-  // Verify behavior when default values are in effect.
-  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
-  for (size_t i = 0; i < pref_names_.size(); ++i) {
-    VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false);
-    VerifyRollback(pref_names_[i], default_values_[i], std::string());
-  }
-
-  // Verify behavior when recommended values are in effect.
-  SetUserPolicies(policy_names_, default_values_,
-                  policy::POLICY_LEVEL_RECOMMENDED);
-  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
-  for (size_t i = 0; i < pref_names_.size(); ++i) {
-    VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false);
-    VerifyRollback(pref_names_[i], default_values_[i], "recommended");
-  }
-}
-
-// Verifies that when the user-modified value of a dialog pref is cleared and
-// the change then committed through the JavaScript Preferences class, the
-// correct notifications fire and a commit to the C++ backend occurs in the
-// latter step only.
-IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsClearCommit) {
-  UseDefaultTestPrefs(false);
-
-  SetUserPolicies(policy_names_, default_values_,
-                  policy::POLICY_LEVEL_RECOMMENDED);
-  SetUserValues(pref_names_, non_default_values_);
-  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
-  for (size_t i = 0; i < pref_names_.size(); ++i) {
-    VerifyClearPref(pref_names_[i], default_values_[i], false);
-    VerifyClearCommit(pref_names_[i], default_values_[i]);
-  }
-}
-
-// Verifies that when the user-modified value of a dialog pref is cleared and
-// the change then rolled back through the JavaScript Preferences class, the
-// correct notifications fire and no commit to the C++ backend occurs.
-IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsClearRollback) {
-  UseDefaultTestPrefs(false);
-
-  SetUserPolicies(policy_names_, default_values_,
-                  policy::POLICY_LEVEL_RECOMMENDED);
-  SetUserValues(pref_names_, non_default_values_);
-  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
-  for (size_t i = 0; i < pref_names_.size(); ++i) {
-    VerifyClearPref(pref_names_[i], default_values_[i], false);
-    VerifyRollback(pref_names_[i], non_default_values_[i], std::string());
-  }
-}
-
-// Verifies that when preference values change in the C++ backend, the correct
-// notifications fire in JavaScript.
-IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, NotificationsOnBackendChanges) {
-  UseDefaultTestPrefs(false);
-  std::string observed_json;
-
-  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
-
-  // Verify notifications when recommended values come into effect.
-  StartObserving();
-  SetUserPolicies(policy_names_, non_default_values_,
-                  policy::POLICY_LEVEL_RECOMMENDED);
-  FinishObserving(&observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_,
-                      "recommended", false, false);
-
-  // Verify notifications when mandatory values come into effect.
-  StartObserving();
-  SetUserPolicies(policy_names_, non_default_values_,
-                  policy::POLICY_LEVEL_MANDATORY);
-  FinishObserving(&observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, "policy",
-                      true, false);
-
-  // Verify notifications when default values come into effect.
-  StartObserving();
-  ClearUserPolicies();
-  FinishObserving(&observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, default_values_,
-                      std::string(), false, false);
-
-  // Verify notifications when user-modified values come into effect.
-  StartObserving();
-  SetUserValues(pref_names_, non_default_values_);
-  FinishObserving(&observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_,
-                      std::string(), false, false);
-}
-
-#if defined(OS_CHROMEOS)
-
-// Verifies that initializing the JavaScript Preferences class fires the correct
-// notifications in JavaScript for pref values handled by the
-// CoreChromeOSOptionsHandler class.
-IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, ChromeOSDeviceFetchPrefs) {
-  std::string observed_json;
-
-  // Boolean pref.
-  pref_names_.push_back(chromeos::kAccountsPrefAllowGuest);
-  default_values_.push_back(base::MakeUnique<base::Value>(true));
-
-  // String pref.
-  pref_names_.push_back(chromeos::kReleaseChannel);
-  default_values_.push_back(base::MakeUnique<base::Value>(""));
-
-  // List pref.
-  pref_names_.push_back(chromeos::kAccountsPrefUsers);
-  default_values_.push_back(base::MakeUnique<base::ListValue>());
-
-  // Verify notifications when default values are in effect.
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, default_values_, "owner",
-                      true, false);
-}
-
-// Verifies that initializing the JavaScript Preferences class fires the correct
-// notifications in JavaScript for non-privileged pref values handled by the
-// CoreChromeOSOptionsHandler class.
-IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest,
-                       ChromeOSDeviceFetchNonPrivilegedPrefs) {
-  std::vector<std::unique_ptr<base::Value>> decorated_non_default_values;
-  std::string observed_json;
-
-  // Non-privileged string pref.
-  pref_names_.push_back(chromeos::kSystemTimezone);
-  default_values_.push_back(
-      base::MakeUnique<base::Value>("America/Los_Angeles"));
-  non_default_values_.push_back(
-      base::MakeUnique<base::Value>("America/New_York"));
-  decorated_non_default_values.push_back(
-      non_default_values_.back()->CreateDeepCopy());
-
-  // Verify notifications when default values are in effect.
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, default_values_,
-                      std::string(), false, false);
-
-  chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get();
-  cros_settings->Set(pref_names_[0], *non_default_values_[0]);
-
-  // Verify notifications when non-default values are in effect.
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, decorated_non_default_values,
-                      std::string(), false, false);
-}
-
-class ManagedPreferencesBrowserTest : public PreferencesBrowserTest {
- protected:
-  // PreferencesBrowserTest implementation:
-  void SetUpInProcessBrowserTestFixture() override {
-    // Set up fake install attributes.
-    std::unique_ptr<chromeos::StubInstallAttributes> attributes =
-        base::MakeUnique<chromeos::StubInstallAttributes>();
-    attributes->SetCloudManaged("example.com", "fake-id");
-    policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
-        attributes.release());
-
-    PreferencesBrowserTest::SetUpInProcessBrowserTestFixture();
-  }
-};
-
-// Verifies that initializing the JavaScript Preferences class fires the correct
-// notifications in JavaScript for pref values handled by the
-// CoreChromeOSOptionsHandler class for a managed device.
-IN_PROC_BROWSER_TEST_F(ManagedPreferencesBrowserTest,
-                       ChromeOSDeviceFetchPrefs) {
-  std::vector<std::unique_ptr<base::Value>> decorated_non_default_values;
-  std::string observed_json;
-
-  // Boolean pref.
-  pref_names_.push_back(chromeos::kAccountsPrefAllowGuest);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(false));
-  decorated_non_default_values.push_back(
-      non_default_values_.back()->CreateDeepCopy());
-
-  // String pref.
-  pref_names_.push_back(chromeos::kReleaseChannel);
-  non_default_values_.push_back(
-      base::MakeUnique<base::Value>("stable-channel"));
-  decorated_non_default_values.push_back(
-      non_default_values_.back()->CreateDeepCopy());
-
-  // List pref.
-  pref_names_.push_back(chromeos::kAccountsPrefUsers);
-  auto list = base::MakeUnique<base::ListValue>();
-  list->AppendString("me@google.com");
-  list->AppendString("you@google.com");
-  non_default_values_.push_back(std::move(list));
-  list = base::MakeUnique<base::ListValue>();
-  auto dict = base::MakeUnique<base::DictionaryValue>();
-  dict->SetString("username", "me@google.com");
-  dict->SetString("name", "me@google.com");
-  dict->SetString("email", "");
-  dict->SetBoolean("owner", false);
-  list->Append(std::move(dict));
-  dict = base::MakeUnique<base::DictionaryValue>();
-  dict->SetString("username", "you@google.com");
-  dict->SetString("name", "you@google.com");
-  dict->SetString("email", "");
-  dict->SetBoolean("owner", false);
-  list->Append(std::move(dict));
-  decorated_non_default_values.push_back(std::move(list));
-
-  chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get();
-  for (size_t i = 0; i < pref_names_.size(); ++i) {
-    cros_settings->Set(pref_names_[i], *non_default_values_[i]);
-  }
-
-  // Verify notifications when mandatory values are in effect.
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, decorated_non_default_values,
-                      "policy", true, false);
-}
-
-// Verifies that initializing the JavaScript Preferences class fires the correct
-// notifications in JavaScript for non-privileged pref values handled by the
-// CoreChromeOSOptionsHandler class for a managed device.
-IN_PROC_BROWSER_TEST_F(ManagedPreferencesBrowserTest,
-                       ChromeOSDeviceFetchNonPrivilegedPrefs) {
-  std::vector<std::unique_ptr<base::Value>> decorated_non_default_values;
-  std::string observed_json;
-
-  // Non-privileged string pref.
-  pref_names_.push_back(chromeos::kSystemTimezone);
-  non_default_values_.push_back(
-      base::MakeUnique<base::Value>("America/New_York"));
-  decorated_non_default_values.push_back(
-      non_default_values_.back()->CreateDeepCopy());
-
-  // Verify notifications when mandatory values are in effect.
-  chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get();
-  cros_settings->Set(pref_names_[0], *non_default_values_[0]);
-
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, decorated_non_default_values,
-                      std::string(), false, false);
-}
-
-namespace {
-
-const char* kUserProfilePath = "user_profile";
-
-}  // namespace
-
-class ProxyPreferencesBrowserTest : public PreferencesBrowserTest {
- public:
-  void SetUpOnMainThread() override {
-    SetupNetworkEnvironment();
-    content::RunAllPendingInMessageLoop();
-
-    std::unique_ptr<base::DictionaryValue> proxy_config_dict(
-        ProxyConfigDictionary::CreateFixedServers("127.0.0.1:8080",
-                                                  "*.google.com, 1.2.3.4:22"));
-
-    ProxyConfigDictionary proxy_config(std::move(proxy_config_dict));
-
-    const chromeos::NetworkState* network = GetDefaultNetwork();
-    ASSERT_TRUE(network);
-    chromeos::proxy_config::SetProxyConfigForNetwork(proxy_config, *network);
-
-    std::string url = base::StringPrintf("%s?network=%s",
-                                         chrome::kChromeUIProxySettingsURL,
-                                         network->guid().c_str());
-
-    ui_test_utils::NavigateToURL(browser(), GURL(url));
-    SetUpPrefs();
-  }
-
- protected:
-  void SetupNetworkEnvironment() {
-    chromeos::ShillProfileClient::TestInterface* profile_test =
-        chromeos::DBusThreadManager::Get()->GetShillProfileClient()
-            ->GetTestInterface();
-    chromeos::ShillServiceClient::TestInterface* service_test =
-        chromeos::DBusThreadManager::Get()->GetShillServiceClient()
-            ->GetTestInterface();
-
-    profile_test->AddProfile(kUserProfilePath, "user");
-
-    service_test->ClearServices();
-    service_test->AddService("stub_ethernet",
-                             "stub_ethernet_guid",
-                             "eth0",
-                             shill::kTypeEthernet,
-                             shill::kStateOnline,
-                             true /* add_to_visible */ );
-    service_test->SetServiceProperty("stub_ethernet", shill::kProfileProperty,
-                                     base::Value(kUserProfilePath));
-    profile_test->AddService(kUserProfilePath, "stub_wifi2");
-  }
-
-  void SetONCPolicy(const char* policy_name, policy::PolicyScope scope) {
-    std::string onc_policy =
-        "{ \"NetworkConfigurations\": ["
-        "    { \"GUID\": \"stub_ethernet_guid\","
-        "      \"Type\": \"Ethernet\","
-        "      \"Name\": \"My Ethernet\","
-        "      \"Ethernet\": {"
-        "        \"Authentication\": \"None\" },"
-        "      \"ProxySettings\": {"
-        "        \"PAC\": \"http://domain.com/x\","
-        "        \"Type\": \"PAC\" }"
-        "    }"
-        "  ],"
-        "  \"Type\": \"UnencryptedConfiguration\""
-        "}";
-
-    policy::PolicyMap map;
-    map.Set(policy_name, policy::POLICY_LEVEL_MANDATORY, scope,
-            policy::POLICY_SOURCE_CLOUD,
-            base::MakeUnique<base::Value>(onc_policy), nullptr);
-    policy_provider_.UpdateChromePolicy(map);
-
-    content::RunAllPendingInMessageLoop();
-  }
-
-  const chromeos::NetworkState* GetDefaultNetwork() {
-    chromeos::NetworkStateHandler* handler =
-        chromeos::NetworkHandler::Get()->network_state_handler();
-    return handler->DefaultNetwork();
-  }
-
-  void SetProxyPref(const std::string& name, const base::Value& value) {
-    std::string type;
-    switch (value.GetType()) {
-      case base::Value::Type::BOOLEAN:
-        type = "Boolean";
-        break;
-      case base::Value::Type::INTEGER:
-        type = "Integer";
-        break;
-      case base::Value::Type::STRING:
-        type = "String";
-        break;
-      default:
-        ASSERT_TRUE(false);
-    }
-
-    std::string observed_json;
-    SetPref(name, type, value.CreateDeepCopy(), true, &observed_json);
-  }
-
-  void VerifyCurrentProxyServer(const std::string& expected_server,
-                                onc::ONCSource expected_source) {
-    const chromeos::NetworkState* network = GetDefaultNetwork();
-    ASSERT_TRUE(network);
-    onc::ONCSource actual_source;
-    std::unique_ptr<ProxyConfigDictionary> proxy_dict =
-        chromeos::proxy_config::GetProxyConfigForNetwork(
-            g_browser_process->local_state(), pref_service(), *network,
-            &actual_source);
-    ASSERT_TRUE(proxy_dict);
-    std::string actual_proxy_server;
-    EXPECT_TRUE(proxy_dict->GetProxyServer(&actual_proxy_server));
-    EXPECT_EQ(expected_server, actual_proxy_server);
-    EXPECT_EQ(expected_source, actual_source);
-  }
-};
-
-// Verifies that proxy settings are correctly pushed to JavaScript during
-// initialization of the proxy settings page.
-IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSInitializeProxy) {
-  // Boolean pref.
-  pref_names_.push_back(chromeos::proxy_cros_settings_parser::kProxySingle);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(true));
-
-  // Integer prefs.
-  pref_names_.push_back(
-      chromeos::proxy_cros_settings_parser::kProxySingleHttpPort);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(8080));
-
-  // String pref.
-  pref_names_.push_back(chromeos::proxy_cros_settings_parser::kProxySingleHttp);
-  non_default_values_.push_back(base::MakeUnique<base::Value>("127.0.0.1"));
-
-  // List pref.
-  pref_names_.push_back(chromeos::proxy_cros_settings_parser::kProxyIgnoreList);
-  auto list = base::MakeUnique<base::ListValue>();
-  list->AppendString("*.google.com");
-  list->AppendString("1.2.3.4:22");
-  non_default_values_.push_back(std::move(list));
-
-  // Verify that no policy is presented to the UI. This must be verified on the
-  // kProxyType and the kUseSharedProxies prefs.
-  pref_names_.push_back(chromeos::proxy_cros_settings_parser::kProxyType);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(2));
-
-  pref_names_.push_back(proxy_config::prefs::kUseSharedProxies);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(false));
-
-  std::string observed_json;
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, "",
-                      false, false);
-}
-
-IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ONCPolicy) {
-  SetONCPolicy(policy::key::kOpenNetworkConfiguration,
-               policy::POLICY_SCOPE_USER);
-
-  // Verify that per-network policy is presented to the UI. This must be
-  // verified on the kProxyType.
-  pref_names_.push_back(chromeos::proxy_cros_settings_parser::kProxyType);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(3));
-
-  std::string observed_json;
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, "policy",
-                      true, false);
-
-  // Verify that 'use-shared-proxies' is not affected by per-network policy.
-  pref_names_.clear();
-  non_default_values_.clear();
-  pref_names_.push_back(proxy_config::prefs::kUseSharedProxies);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(false));
-
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, "",
-                      false, false);
-}
-
-IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, DeviceONCPolicy) {
-  SetONCPolicy(policy::key::kDeviceOpenNetworkConfiguration,
-               policy::POLICY_SCOPE_MACHINE);
-
-  // Verify that the policy is presented to the UI. This verification must be
-  // done on the kProxyType pref.
-  pref_names_.push_back(chromeos::proxy_cros_settings_parser::kProxyType);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(3));
-
-  std::string observed_json;
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, "policy",
-                      true, false);
-
-  // Verify that 'use-shared-proxies' is not affected by per-network policy.
-  pref_names_.clear();
-  non_default_values_.clear();
-  pref_names_.push_back(proxy_config::prefs::kUseSharedProxies);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(false));
-
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, "",
-                      false, false);
-}
-
-IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, UserProxyPolicy) {
-  policy_names_.push_back(policy::key::kProxyMode);
-  default_values_.push_back(
-      base::MakeUnique<base::Value>(ProxyPrefs::kAutoDetectProxyModeName));
-  SetUserPolicies(policy_names_, default_values_,
-                  policy::POLICY_LEVEL_MANDATORY);
-  content::RunAllPendingInMessageLoop();
-
-  // Verify that the policy is presented to the UI. This verification must be
-  // done on the kProxyType pref.
-  pref_names_.push_back(chromeos::proxy_cros_settings_parser::kProxyType);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(3));
-
-  // Verify that 'use-shared-proxies' is controlled by the policy.
-  pref_names_.push_back(proxy_config::prefs::kUseSharedProxies);
-  non_default_values_.push_back(base::MakeUnique<base::Value>(false));
-
-  std::string observed_json;
-  SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
-  VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, "policy",
-                      true, false);
-}
-
-// Verifies that modifications to the proxy settings are correctly pushed from
-// JavaScript to the ProxyConfig property stored in the network configuration.
-IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSSetProxy) {
-  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
-
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxySingleHttpPort,
-               base::Value(123));
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxySingleHttp,
-               base::Value("www.adomain.xy"));
-
-  VerifyCurrentProxyServer("www.adomain.xy:123",
-                           onc::ONC_SOURCE_NONE);
-}
-
-// Verify that default proxy ports are used and that ports can be updated
-// without affecting the previously set hosts.
-IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSProxyDefaultPorts) {
-  ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
-
-  // Set to manual, per scheme proxy.
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxySingle,
-               base::Value(false));
-
-  // Set hosts but no ports.
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxyHttpUrl,
-               base::Value("a.com"));
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxyHttpsUrl,
-               base::Value("4.3.2.1"));
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxyFtpUrl,
-               base::Value("c.com"));
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxySocks,
-               base::Value("d.com"));
-
-  // Verify default ports.
-  VerifyCurrentProxyServer(
-      "http=a.com:80;https=4.3.2.1:80;ftp=c.com:80;socks=socks4://d.com:1080",
-      onc::ONC_SOURCE_NONE);
-
-  // Set and verify the ports.
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxyHttpPort,
-               base::Value(1));
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxyHttpsPort,
-               base::Value(2));
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxyFtpPort,
-               base::Value(3));
-  SetProxyPref(chromeos::proxy_cros_settings_parser::kProxySocksPort,
-               base::Value(4));
-
-  VerifyCurrentProxyServer(
-      "http=a.com:1;https=4.3.2.1:2;ftp=c.com:3;socks=socks4://d.com:4",
-      onc::ONC_SOURCE_NONE);
-}
-
-#endif
diff --git a/chrome/browser/ui/webui/options/preferences_browsertest.h b/chrome/browser/ui/webui/options/preferences_browsertest.h
deleted file mode 100644
index d2136d3..0000000
--- a/chrome/browser/ui/webui/options/preferences_browsertest.h
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS_PREFERENCES_BROWSERTEST_H_
-#define CHROME_BROWSER_UI_WEBUI_OPTIONS_PREFERENCES_BROWSERTEST_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "components/policy/core/common/mock_configuration_policy_provider.h"
-#include "components/policy/core/common/policy_types.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/prefs/pref_service.h"
-#include "content/public/browser/notification_observer.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace base {
-class DictionaryValue;
-class Value;
-}
-
-namespace content {
-class RenderViewHost;
-}
-
-// Tests verifying that the JavaScript Preferences class, the underlying C++
-// CoreOptionsHandler and the specialized classes handling Chrome OS device and
-// proxy prefs behave correctly.
-class PreferencesBrowserTest : public InProcessBrowserTest {
- public:
-  PreferencesBrowserTest();
-  ~PreferencesBrowserTest() override;
-
-  // InProcessBrowserTest implementation:
-  void SetUpOnMainThread() override;
-  void TearDownOnMainThread() override;
-
-  void OnPreferenceChanged(const std::string& pref_name);
-
- protected:
-  MOCK_METHOD1(OnCommit, void(const PrefService::Preference*));
-
-  // The pref service that holds the current pref values in the C++ backend.
-  PrefService* pref_service();
-
-  void SetUpPrefs();
-
-  // InProcessBrowserTest implementation:
-  void SetUpInProcessBrowserTestFixture() override;
-
-  // Sets user policies through the mock policy provider.
-  void SetUserPolicies(const std::vector<std::string>& names,
-                       const std::vector<std::unique_ptr<base::Value>>& values,
-                       policy::PolicyLevel level);
-  // Clears user policies.
-  void ClearUserPolicies();
-  // Set user-modified pref values directly in the C++ backend.
-  void SetUserValues(const std::vector<std::string>& names,
-                     const std::vector<std::unique_ptr<base::Value>>& values);
-
-  // Verifies that a dictionary contains a (key, value) pair. Takes ownership of
-  // |expected|.
-  void VerifyKeyValue(const base::DictionaryValue& dict,
-                      const std::string& key,
-                      const base::Value& expected);
-  // Verifies that a dictionary contains a given pref and that its value has
-  // been decorated correctly.
-  void VerifyPref(const base::DictionaryValue* prefs,
-                  const std::string& name,
-                  const std::unique_ptr<base::Value>& value,
-                  const std::string& controlledBy,
-                  bool disabled,
-                  bool uncommitted);
-  // Verifies that a notification received from the JavaScript Preferences
-  // class contains a given pref and that its value has been decorated
-  // correctly.
-  void VerifyObservedPref(const std::string& observed_json,
-                          const std::string& name,
-                          const std::unique_ptr<base::Value>& value,
-                          const std::string& controlledBy,
-                          bool disabled,
-                          bool uncommitted);
-  // Verifies that notifications received from the JavaScript Preferences class
-  // contain the given prefs and that their values have been decorated
-  // correctly.
-  void VerifyObservedPrefs(
-      const std::string& observed_json,
-      const std::vector<std::string>& names,
-      const std::vector<std::unique_ptr<base::Value>>& values,
-      const std::string& controlledBy,
-      bool disabled,
-      bool uncommitted);
-
-  // Sets up the expectation that the JavaScript Preferences class will make no
-  // change to a user-modified pref value in the C++ backend.
-  void ExpectNoCommit(const std::string& name);
-  // Sets up the expectation that the JavaScript Preferences class will set a
-  // user-modified pref value in the C++ backend.
-  void ExpectSetCommit(const std::string& name,
-                       const std::unique_ptr<base::Value>& value);
-  // Sets up the expectation that the JavaScript Preferences class will clear a
-  // user-modified pref value in the C++ backend.
-  void ExpectClearCommit(const std::string& name);
-  // Verifies that previously set expectations are met and clears them.
-  void VerifyAndClearExpectations();
-
-  // Sets up the JavaScript part of the test environment.
-  void SetupJavaScriptTestEnvironment(
-      const std::vector<std::string>& pref_names,
-      std::string* observed_json) const;
-
-  // Sets a value through the JavaScript Preferences class as if the user had
-  // modified it. Returns the observation which can be verified using the
-  // VerifyObserved* methods.
-  void SetPref(const std::string& name,
-               const std::string& type,
-               const std::unique_ptr<base::Value>& value,
-               bool commit,
-               std::string* observed_json);
-
-  // Verifies that setting a user-modified pref value through the JavaScript
-  // Preferences class fires the correct notification in JavaScript and commits
-  // the change to C++ if |commit| is true.
-  void VerifySetPref(const std::string& name,
-                     const std::string& type,
-                     const std::unique_ptr<base::Value>& value,
-                     bool commit);
-  // Verifies that clearing a user-modified pref value through the JavaScript
-  // Preferences class fires the correct notification in JavaScript and does
-  // respectively does not cause the change to be committed to the C++ backend.
-  void VerifyClearPref(const std::string& name,
-                       const std::unique_ptr<base::Value>& value,
-                       bool commit);
-  // Verifies that committing a previously made change of a user-modified pref
-  // value through the JavaScript Preferences class fires the correct
-  // notification in JavaScript.
-  void VerifyCommit(const std::string& name,
-                    const std::unique_ptr<base::Value>& value,
-                    const std::string& controlledBy);
-  // Verifies that committing a previously set user-modified pref value through
-  // the JavaScript Preferences class fires the correct notification in
-  // JavaScript and causes the change to be committed to the C++ backend.
-  void VerifySetCommit(const std::string& name,
-                       const std::unique_ptr<base::Value>& value);
-  // Verifies that committing the previously cleared user-modified pref value
-  // through the JavaScript Preferences class fires the correct notification in
-  // JavaScript and causes the change to be committed to the C++ backend.
-  void VerifyClearCommit(const std::string& name,
-                         const std::unique_ptr<base::Value>& value);
-  // Verifies that rolling back a previously made change of a user-modified pref
-  // value through the JavaScript Preferences class fires the correct
-  // notification in JavaScript and does not cause the change to be committed to
-  // the C++ backend.
-  void VerifyRollback(const std::string& name,
-                      const std::unique_ptr<base::Value>& value,
-                      const std::string& controlledBy);
-  // Start observing notifications sent by the JavaScript Preferences class for
-  // pref values changes.
-  void StartObserving();
-  // Change the value of a sentinel pref in the C++ backend and finish observing
-  // notifications sent by the JavaScript Preferences class when the
-  // notification for this pref is received.
-  void FinishObserving(std::string* observed_json);
-
-  // Populate the lists of test prefs and corresponding policies with default
-  // values used by most tests.
-  void UseDefaultTestPrefs(bool includeListPref);
-
-  // The current tab's render view host, required to inject JavaScript code into
-  // the tab.
-  content::RenderViewHost* render_view_host_;
-
-  // Mock policy provider for both user and device policies.
-  policy::MockConfigurationPolicyProvider policy_provider_;
-
-  // Pref change registrar that detects changes to user-modified pref values
-  // made in the C++ backend by the JavaScript Preferences class.
-  std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
-
-  // The prefs and corresponding policies used by the current test.
-  std::vector<std::string> types_;
-  std::vector<std::string> pref_names_;
-  std::vector<std::string> policy_names_;
-  std::vector<std::unique_ptr<base::Value>> default_values_;
-  std::vector<std::unique_ptr<base::Value>> non_default_values_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PreferencesBrowserTest);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_OPTIONS_PREFERENCES_BROWSERTEST_H_
diff --git a/chrome/browser/ui/webui/options/profile_settings_reset_browsertest.js b/chrome/browser/ui/webui/options/profile_settings_reset_browsertest.js
deleted file mode 100644
index 2bd7a05..0000000
--- a/chrome/browser/ui/webui/options/profile_settings_reset_browsertest.js
+++ /dev/null
@@ -1,38 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * TestFixture for profile settings reset WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function ProfileSettingsResetWebUITest() {}
-
-ProfileSettingsResetWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Browse to the reset profile settings page.
-   */
-  browsePreload: 'chrome://settings-frame/resetProfileSettings',
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    // Enable when failure is resolved.
-    // AX_TEXT_04: http://crbug.com/570551
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'linkWithUnclearPurpose',
-        '#reset-profile-settings-overlay > .action-area > .hbox.stretch > A');
-  },
-};
-
-// Test opening the profile settings reset has correct location.
-TEST_F('ProfileSettingsResetWebUITest', 'testOpenProfileSettingsReset',
-       function() {
-         assertEquals(this.browsePreload, document.location.href);
-       });
diff --git a/chrome/browser/ui/webui/options/search_engine_manager_browsertest.js b/chrome/browser/ui/webui/options/search_engine_manager_browsertest.js
deleted file mode 100644
index 88b4a27..0000000
--- a/chrome/browser/ui/webui/options/search_engine_manager_browsertest.js
+++ /dev/null
@@ -1,26 +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.
-
-/**
- * TestFixture for search engine manager WebUI testing.
- * @extends {testing.Test}
- * @constructor
- */
-function SearchEngineManagerWebUITest() {}
-
-SearchEngineManagerWebUITest.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /**
-   * Browse to the search engine manager.
-   */
-  browsePreload: 'chrome://settings-frame/searchEngines',
-};
-
-// Disabled due to flaky timeouts; see crbug.com/205693 .
-// Test opening the search engine manager has correct location.
-TEST_F('SearchEngineManagerWebUITest', 'DISABLED_testOpenSearchEngineManager',
-       function() {
-         assertEquals(this.browsePreload, document.location.href);
-       });
diff --git a/chrome/browser/ui/webui/options/settings_format_browsertest.js b/chrome/browser/ui/webui/options/settings_format_browsertest.js
deleted file mode 100644
index a84873f..0000000
--- a/chrome/browser/ui/webui/options/settings_format_browsertest.js
+++ /dev/null
@@ -1,176 +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.
-
-GEN_INCLUDE(['options_browsertest_base.js']);
-
-/**
- * TestFixture for testing the formatting of settings pages.
- * @extends {testing.Test}
- * @constructor
- */
-function SettingsFormatWebUITest() {}
-
-/**
- * Map of rule exemptions grouped by test.
- * @const
- */
-SettingsFormatWebUITest.Filters = {
-  /**
-   * Exemption for checkboxes that do not require an id or pref property.
-   * Input methods use inputMethodId instead of id for unique identification.
-   */
-  'pref': ['language-options-input-method-template',
-           'language-options-input-method-list']
-};
-
-/**
- * Collection of error messages.
- * @const
- */
-SettingsFormatWebUITest.Messages = {
-    MISSING_CHECK_WRAPPER: 'Element $1 should be enclosed in <div class="$2">',
-    MISSING_ID_OR_PREF: 'Missing id or pref preoperty for checkbox $1.',
-    MISSING_RADIO_BUTTON_NAME: 'Radio button $1 is missing the name property',
-    MISSING_RADIO_BUTTON_VALUE: 'Radio button $1 is missing the value property',
-};
-
-SettingsFormatWebUITest.prototype = {
-  __proto__: OptionsBrowsertestBase.prototype,
-
-  /**
-   * Navigate to browser settings.
-   */
-  browsePreload: 'chrome://settings-frame/',
-
-  /**
-   * List of errors generated during a test. Used instead of expect* functions
-   * to suppress verbosity. The implementation of errorsToMessage in the
-   * testing API generates a call stack for each error produced which greatly
-   * reduces readability.
-   * @type {Array<string>}
-   */
-  errors: null,
-
-  /** @override */
-  setUp: function() {
-    OptionsBrowsertestBase.prototype.setUp.call(this);
-
-    this.errors = [];
-
-    // Enable when failure is resolved.
-    // AX_TEXT_04: http://crbug.com/570727
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'linkWithUnclearPurpose',
-        '#sync-overview > A');
-
-    // Enable when failure is resolved.
-    // AX_ARIA_10: http://crbug.com/570725
-    this.accessibilityAuditConfig.ignoreSelectors(
-        'unsupportedAriaAttribute',
-        '#profiles-list');
-  },
-
-  tearDown: function() {
-    assertTrue(this.errors.length == 0, '\n' + this.errors.join('\n'));
-  },
-
-  /**
-   * Generates a failure message. During tear down of the test, the accumulation
-   * of pending messages triggers a test failure.
-   * @param {string} key Label of the message formatting string.
-   * @param {!Element} element The element that triggered the failure.
-   * @param {...string} args Additional arguments for formatting the message.
-   */
-  fail: function(key, element, args) {
-    var subs = [this.getLabel(element)].concat(
-        Array.prototype.slice.call(arguments, 2));
-    var message = SettingsFormatWebUITest.Messages[key].replace(
-        /\$\d/g,
-        function(m) {
-      return subs[m[1] - 1] || '$' + m[1];
-    });
-    assertFalse(/\$\d/.test(message), 'found unreplaced subs');
-    this.errors.push(message);
-  },
-
- /**
-  * String for identifying a node within an error message.
-  * @param {!Element} element The target element to identify.
-  * @return {string} Name to facilitate tracking down the element.
-  */
-  getLabel: function(element) {
-    if (element.id)
-      return element.id;
-
-    if (element.pref)
-      return element.pref;
-
-    if (element.name && element.value)
-      return element.name + '-' + element.value;
-
-    return this.getLabel(element.parentNode);
-  },
-
-
-  /**
-   * Checks if the node is exempt from following the formatting rule.
-   * @param {!Element} element The candidate element.
-   * @param {Array<string>} filters List of exemptions.
-   * @return {boolean} True if the element is exempt.
-   */
-  isExempt: function(element, filters) {
-    var target = this.getLabel(element);
-    for (var i = 0; i < filters.length; i++) {
-      if (filters[i] == target)
-        return true;
-    }
-    return false;
-  }
-};
-
-/**
- * Ensure that radio and checkbox buttons have consistent layout.
- */
-TEST_F('SettingsFormatWebUITest', 'RadioCheckboxStyleCheck', function() {
-  var settings = $('settings');
-  assertTrue(settings != null, 'Unable to access settings');
-  var query = 'input[type=checkbox], input[type=radio]';
-  var elements = document.querySelectorAll(query);
-  assertTrue(elements.length > 0);
-  for (var i = 0; i < elements.length; i++) {
-    var element = elements[i];
-    if (!findAncestorByClass(element, element.type))
-      this.fail('MISSING_CHECK_WRAPPER', element, element.type);
-  }
-});
-
-/**
- * Each checkbox requires an id or pref property.
- */
-// Flaky crashes on all platforms; http://crbug.com/613034.
-TEST_F('SettingsFormatWebUITest', 'DISABLED_CheckboxIdOrPrefCheck', function() {
-  var query =
-      'input[type=checkbox]:not([pref]):not([id]):not(.spacer-checkbox)';
-  var elements = document.querySelectorAll(query);
-  for (var i = 0; i < elements.length; i++) {
-    var element = elements[i];
-    if (!this.isExempt(element, SettingsFormatWebUITest.Filters['pref']))
-      this.fail('MISSING_ID_OR_PREF', element);
-  }
-});
-
-/**
- * Each radio button requires name and value properties.
- */
-TEST_F('SettingsFormatWebUITest', 'RadioButtonNameValueCheck', function() {
-  var elements = document.querySelectorAll('input[type=radio]');
-  for (var i = 0; i < elements.length; i++) {
-    var element = elements[i];
-    if (!element.name)
-      this.fail('MISSING_RADIO_BUTTON_NAME', element);
-
-    if (!element.getAttribute('value'))
-      this.fail('MISSING_RADIO_BUTTON_VALUE', element);
-  }
-});
diff --git a/chrome/browser/ui/webui/options/startup_page_list_browsertest.js b/chrome/browser/ui/webui/options/startup_page_list_browsertest.js
deleted file mode 100644
index 1df6e28..0000000
--- a/chrome/browser/ui/webui/options/startup_page_list_browsertest.js
+++ /dev/null
@@ -1,151 +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.
-
-/**
- * Fixture for startup pages WebUI tests.
- * @extends {testing.Test}
- * @constructor
- */
-function StartupPageListWebUITest() {}
-
-StartupPageListWebUITest.prototype = {
-  __proto__: testing.Test.prototype,
-
-  /**
-   * Browse to the options page & call our preLoad().
-   * @override
-   */
-  browsePreload: 'chrome://settings-frame/startup',
-
-  /** @override */
-  setUp: function() {
-    StartupOverlay.updateStartupPages(this.fakeStartupList);
-    // 1 item for entering data, 1+ from |this.fakeStartupList|.
-    assertGE(this.getList().items.length, 2);
-  },
-
-  /**
-   * Returns the list to be tested.
-   * @return {Element} The start-up pages list.
-   * @protected
-   */
-  getList: function() {
-    return $('startupPagesList');
-  },
-
-  /**
-   * Register a mock handler to ensure expectations are met and options pages
-   * behave correctly.
-   * @override
-   */
-  preLoad: function() {
-    this.makeAndRegisterMockHandler(['addStartupPage',
-                                     'dragDropStartupPage']);
-  },
-
-  /**
-   * A fake list of startup pages to send to the overlay.
-   * @protected
-   */
-  fakeStartupList: [
-    {
-      title: 'Yahoo!',
-      url: 'http://yahoo.com',
-      tooltip: 'Yahoo! homepage',
-      modelIndex: 0
-    },
-    {
-      title: 'Facebook',
-      url: 'http://facebook.com',
-      tooltip: 'Facebook :: Sign In',
-      modelIndex: 1
-    }
-  ],
-};
-
-(function() {
-
-/**
- * A mock data transfer object for drag/drop events.
- * @constructor
- */
-function MockDataTransfer() {
-  /**
-   * The data this dataTransfer object knows about.
-   * @type {!Object<string>}
-   * @private
-   */
-  this.data_ = {};
-}
-
-/**
- * Installs a lazily created MockDataTransfer on event#dataTransfer.
- * @param {!Event} event An event to modify.
- */
-MockDataTransfer.install = function(event) {
-  event.__defineGetter__('dataTransfer', function() {
-    event.dataTransfer_ = event.dataTransfer_ || new MockDataTransfer;
-    return event.dataTransfer_;
-  });
-};
-
-MockDataTransfer.prototype = {
-  /**
-   * The URL data in this mock drop event.
-   * @param {string} type The text of data being set.
-   * @param {*} val The data to set. Will be stringified.
-   */
-  setData: function(type, val) {
-    this.data_[type] = String(val);
-  },
-
-  /**
-   * Gets data associated with this fake data transfer.
-   * @param {string} type The type of data to get.
-   * @return {string} The requested type of data or '' if not set.
-   */
-  getData: function(type) {
-    return this.data_[type] || '';
-  },
-};
-
-/**
- * Creates a fake bubbling, cancelable mouse event with a mock data transfer
- * installed.
- * @param {string} type A type of mouse event (e.g. 'drop').
- * @return {!Event} A fake mouse event.
- */
-function createMouseEvent(type) {
-  var event = new MouseEvent(type, {bubbles: true, cancelable: true});
-  MockDataTransfer.install(event);
-  return event;
-}
-
-// Disabled due to: crbug.com/419370
-TEST_F('StartupPageListWebUITest', 'DISABLED_testDropFromOutsideSource',
-       function() {
-  /** @const */ var NEW_PAGE = 'http://google.com';
-
-  var mockDropEvent = createMouseEvent('drop');
-  mockDropEvent.dataTransfer.setData('url', NEW_PAGE);
-
-  this.mockHandler.expects(once()).addStartupPage([NEW_PAGE, 0]);
-
-  this.getList().items[0].dispatchEvent(mockDropEvent);
-
-  expectTrue(mockDropEvent.defaultPrevented);
-});
-
-// Disabled due to: crbug.com/419370
-TEST_F('StartupPageListWebUITest', 'DISABLED_testDropToReorder', function() {
-  // TODO(dbeam): mock4js doesn't handle complex arguments well. Fix this.
-  this.mockHandler.expects(once()).dragDropStartupPage([0, [1].join()]);
-
-  this.getList().selectionModel.selectedIndex = 1;
-  expectEquals(1, this.getList().selectionModel.selectedIndexes.length);
-
-  this.getList().items[0].dispatchEvent(createMouseEvent('drop'));
-});
-
-}());
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
deleted file mode 100644
index e24b055d..0000000
--- a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
+++ /dev/null
@@ -1,951 +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/ui/webui/options/sync_setup_handler.h"
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/json/json_writer.h"
-#include "base/macros.h"
-#include "base/stl_util.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "chrome/browser/signin/fake_signin_manager_builder.h"
-#include "chrome/browser/signin/signin_error_controller_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/sync/profile_sync_test_util.h"
-#include "chrome/browser/ui/webui/signin/login_ui_service.h"
-#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/base/scoped_testing_local_state.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/fake_auth_status_provider.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "components/sync/base/sync_prefs.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/test/test_browser_thread.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "content/public/test/test_web_ui.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/layout.h"
-
-using ::testing::_;
-using ::testing::Mock;
-using ::testing::Return;
-using ::testing::ReturnRef;
-using ::testing::Values;
-using browser_sync::ProfileSyncService;
-using browser_sync::ProfileSyncServiceMock;
-
-typedef GoogleServiceAuthError AuthError;
-
-namespace {
-
-MATCHER_P(ModelTypeSetMatches, value, "") {
-  return arg == value;
-}
-
-const char kTestUser[] = "chrome.p13n.test@gmail.com";
-
-// Returns a ModelTypeSet with all user selectable types set.
-syncer::ModelTypeSet GetAllTypes() {
-  return syncer::UserSelectableTypes();
-}
-
-enum SyncAllDataConfig {
-  SYNC_ALL_DATA,
-  CHOOSE_WHAT_TO_SYNC
-};
-
-enum EncryptAllConfig {
-  ENCRYPT_ALL_DATA,
-  ENCRYPT_PASSWORDS
-};
-
-enum PaymentsIntegrationConfig {
-  PAYMENTS_INTEGRATION_ENABLED,
-  PAYMENTS_INTEGRATION_DISABLED
-};
-
-// Create a json-format string with the key/value pairs appropriate for a call
-// to HandleConfigure(). If |extra_values| is non-null, then the values from
-// the passed dictionary are added to the json.
-std::string GetConfiguration(const base::DictionaryValue* extra_values,
-                             SyncAllDataConfig sync_all,
-                             syncer::ModelTypeSet types,
-                             const std::string& passphrase,
-                             EncryptAllConfig encrypt_all,
-                             PaymentsIntegrationConfig payments_integration) {
-  base::DictionaryValue result;
-  if (extra_values)
-    result.MergeDictionary(extra_values);
-  result.SetBoolean("syncAllDataTypes", sync_all == SYNC_ALL_DATA);
-  result.SetBoolean("encryptAllData", encrypt_all == ENCRYPT_ALL_DATA);
-  result.SetBoolean("usePassphrase", !passphrase.empty());
-  if (!passphrase.empty())
-    result.SetString("passphrase", passphrase);
-  // Add all of our data types.
-  result.SetBoolean("appsSynced", types.Has(syncer::APPS));
-  result.SetBoolean("autofillSynced", types.Has(syncer::AUTOFILL));
-  result.SetBoolean("bookmarksSynced", types.Has(syncer::BOOKMARKS));
-  result.SetBoolean("extensionsSynced", types.Has(syncer::EXTENSIONS));
-  result.SetBoolean("passwordsSynced", types.Has(syncer::PASSWORDS));
-  result.SetBoolean("preferencesSynced", types.Has(syncer::PREFERENCES));
-  result.SetBoolean("tabsSynced", types.Has(syncer::PROXY_TABS));
-  result.SetBoolean("themesSynced", types.Has(syncer::THEMES));
-  result.SetBoolean("typedUrlsSynced", types.Has(syncer::TYPED_URLS));
-  result.SetBoolean("paymentsIntegrationEnabled",
-                    payments_integration == PAYMENTS_INTEGRATION_ENABLED);
-  std::string args;
-  base::JSONWriter::Write(result, &args);
-  return args;
-}
-
-// Checks whether the passed |dictionary| contains a |key| with the given
-// |expected_value|. If |omit_if_false| is true, then the value should only
-// be present if |expected_value| is true.
-void CheckBool(const base::DictionaryValue* dictionary,
-               const std::string& key,
-               bool expected_value,
-               bool omit_if_false) {
-  if (omit_if_false && !expected_value) {
-    EXPECT_FALSE(dictionary->HasKey(key)) <<
-        "Did not expect to find value for " << key;
-  } else {
-    bool actual_value;
-    EXPECT_TRUE(dictionary->GetBoolean(key, &actual_value)) <<
-        "No value found for " << key;
-    EXPECT_EQ(expected_value, actual_value) <<
-        "Mismatch found for " << key;
-  }
-}
-
-void CheckBool(const base::DictionaryValue* dictionary,
-               const std::string& key,
-               bool expected_value) {
-  return CheckBool(dictionary, key, expected_value, false);
-}
-
-// Checks to make sure that the values stored in |dictionary| match the values
-// expected by the showSyncSetupPage() JS function for a given set of data
-// types.
-void CheckConfigDataTypeArguments(const base::DictionaryValue* dictionary,
-                                  SyncAllDataConfig config,
-                                  syncer::ModelTypeSet types) {
-  CheckBool(dictionary, "syncAllDataTypes", config == SYNC_ALL_DATA);
-  CheckBool(dictionary, "appsSynced", types.Has(syncer::APPS));
-  CheckBool(dictionary, "autofillSynced", types.Has(syncer::AUTOFILL));
-  CheckBool(dictionary, "bookmarksSynced", types.Has(syncer::BOOKMARKS));
-  CheckBool(dictionary, "extensionsSynced", types.Has(syncer::EXTENSIONS));
-  CheckBool(dictionary, "passwordsSynced", types.Has(syncer::PASSWORDS));
-  CheckBool(dictionary, "preferencesSynced", types.Has(syncer::PREFERENCES));
-  CheckBool(dictionary, "tabsSynced", types.Has(syncer::PROXY_TABS));
-  CheckBool(dictionary, "themesSynced", types.Has(syncer::THEMES));
-  CheckBool(dictionary, "typedUrlsSynced", types.Has(syncer::TYPED_URLS));
-}
-
-
-}  // namespace
-
-class TestingSyncSetupHandler : public SyncSetupHandler {
- public:
-  TestingSyncSetupHandler(content::WebUI* web_ui, Profile* profile)
-      : profile_(profile) {
-    set_web_ui(web_ui);
-  }
-  ~TestingSyncSetupHandler() override { set_web_ui(NULL); }
-
-  void FocusUI() override {}
-
-  Profile* GetProfile() const override { return profile_; }
-
-  using SyncSetupHandler::is_configuring_sync;
-
- private:
-#if !defined(OS_CHROMEOS)
-  void DisplayGaiaLoginInNewTabOrWindow(
-      signin_metrics::AccessPoint access_point) override {}
-#endif
-
-  // Weak pointer to parent profile.
-  Profile* profile_;
-  DISALLOW_COPY_AND_ASSIGN(TestingSyncSetupHandler);
-};
-
-// The boolean parameter indicates whether the test is run with ClientOAuth
-// or not.  The test parameter is a bool: whether or not to test with/
-// /ClientLogin enabled or not.
-class SyncSetupHandlerTest : public testing::Test {
- public:
-  SyncSetupHandlerTest() : error_(GoogleServiceAuthError::NONE) {}
-  void SetUp() override {
-    error_ = GoogleServiceAuthError::AuthErrorNone();
-
-    TestingProfile::Builder builder;
-    builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
-                              BuildFakeSigninManagerBase);
-    profile_ = builder.Build();
-
-    // Sign in the user.
-    mock_signin_ = static_cast<SigninManagerBase*>(
-        SigninManagerFactory::GetForProfile(profile_.get()));
-    std::string username = GetTestUser();
-    if (!username.empty())
-      mock_signin_->SetAuthenticatedAccountInfo(username, username);
-
-    mock_pss_ = static_cast<ProfileSyncServiceMock*>(
-        ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-            profile_.get(), BuildMockProfileSyncService));
-    EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
-    ON_CALL(*mock_pss_, GetPassphraseType())
-        .WillByDefault(Return(syncer::PassphraseType::IMPLICIT_PASSPHRASE));
-    ON_CALL(*mock_pss_, GetExplicitPassphraseTime()).WillByDefault(
-        Return(base::Time()));
-    ON_CALL(*mock_pss_, GetRegisteredDataTypes())
-        .WillByDefault(Return(syncer::ModelTypeSet()));
-
-    mock_pss_->Initialize();
-
-    handler_.reset(new TestingSyncSetupHandler(&web_ui_, profile_.get()));
-  }
-
-  // Setup the expectations for calls made when displaying the config page.
-  void SetDefaultExpectationsForConfigPage() {
-    EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true));
-    EXPECT_CALL(*mock_pss_, GetRegisteredDataTypes())
-        .WillRepeatedly(Return(GetAllTypes()));
-    EXPECT_CALL(*mock_pss_, GetPreferredDataTypes())
-        .WillRepeatedly(Return(GetAllTypes()));
-    EXPECT_CALL(*mock_pss_, GetActiveDataTypes())
-        .WillRepeatedly(Return(GetAllTypes()));
-    EXPECT_CALL(*mock_pss_, IsEncryptEverythingAllowed())
-        .WillRepeatedly(Return(true));
-    EXPECT_CALL(*mock_pss_, IsEncryptEverythingEnabled())
-        .WillRepeatedly(Return(false));
-  }
-
-  void SetupInitializedProfileSyncService() {
-    // An initialized ProfileSyncService will have already completed sync setup
-    // and will have an initialized sync engine.
-    ASSERT_TRUE(mock_signin_->IsInitialized());
-    EXPECT_CALL(*mock_pss_, IsEngineInitialized()).WillRepeatedly(Return(true));
-  }
-
-  void ExpectConfig() {
-    ASSERT_EQ(1U, web_ui_.call_data().size());
-    const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-    EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name());
-    std::string page;
-    ASSERT_TRUE(data.arg1()->GetAsString(&page));
-    EXPECT_EQ(page, "configure");
-  }
-
-  void ExpectDone() {
-    ASSERT_EQ(1U, web_ui_.call_data().size());
-    const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-    EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name());
-    std::string page;
-    ASSERT_TRUE(data.arg1()->GetAsString(&page));
-    EXPECT_EQ(page, "done");
-  }
-
-  void ExpectSpinnerAndClose() {
-    // We expect a call to SyncSetupOverlay.showSyncSetupPage.
-    EXPECT_EQ(1U, web_ui_.call_data().size());
-    const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-    EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name());
-
-    std::string page;
-    ASSERT_TRUE(data.arg1()->GetAsString(&page));
-    EXPECT_EQ(page, "spinner");
-    // Cancelling the spinner dialog will cause CloseSyncSetup().
-    handler_->CloseSyncSetup();
-    EXPECT_EQ(NULL,
-              LoginUIServiceFactory::GetForProfile(
-                  profile_.get())->current_login_ui());
-  }
-
-  // It's difficult to notify sync listeners when using a ProfileSyncServiceMock
-  // so this helper routine dispatches an OnStateChanged() notification to the
-  // SyncStartupTracker.
-  void NotifySyncListeners() {
-    if (handler_->sync_startup_tracker_)
-      handler_->sync_startup_tracker_->OnStateChanged(mock_pss_);
-  }
-
-  virtual std::string GetTestUser() {
-    return std::string(kTestUser);
-  }
-
-  content::TestBrowserThreadBundle thread_bundle_;
-  std::unique_ptr<Profile> profile_;
-  ProfileSyncServiceMock* mock_pss_;
-  GoogleServiceAuthError error_;
-  SigninManagerBase* mock_signin_;
-  content::TestWebUI web_ui_;
-  std::unique_ptr<TestingSyncSetupHandler> handler_;
-};
-
-class SyncSetupHandlerFirstSigninTest : public SyncSetupHandlerTest {
-  std::string GetTestUser() override { return std::string(); }
-};
-
-TEST_F(SyncSetupHandlerTest, Basic) {
-}
-
-#if !defined(OS_CHROMEOS)
-TEST_F(SyncSetupHandlerFirstSigninTest, DisplayBasicLogin) {
-  EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false));
-  // Ensure that the user is not signed in before calling |HandleStartSignin()|.
-  SigninManager* manager = static_cast<SigninManager*>(mock_signin_);
-  manager->SignOut(signin_metrics::SIGNOUT_TEST,
-                   signin_metrics::SignoutDelete::IGNORE_METRIC);
-  base::ListValue list_args;
-  handler_->HandleStartSignin(&list_args);
-
-  // Sync setup hands off control to the gaia login tab.
-  EXPECT_EQ(NULL,
-            LoginUIServiceFactory::GetForProfile(
-                profile_.get())->current_login_ui());
-
-  ASSERT_FALSE(handler_->is_configuring_sync());
-
-  handler_->CloseSyncSetup();
-  EXPECT_EQ(NULL,
-            LoginUIServiceFactory::GetForProfile(
-                profile_.get())->current_login_ui());
-}
-
-TEST_F(SyncSetupHandlerTest, ShowSyncSetupWhenNotSignedIn) {
-  EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false));
-  handler_->HandleShowSetupUI(NULL);
-
-  // We expect a call to SyncSetupOverlay.showSyncSetupPage.
-  ASSERT_EQ(1U, web_ui_.call_data().size());
-  const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-  EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name());
-
-  ASSERT_FALSE(handler_->is_configuring_sync());
-  EXPECT_EQ(NULL,
-            LoginUIServiceFactory::GetForProfile(
-                profile_.get())->current_login_ui());
-}
-#endif  // !defined(OS_CHROMEOS)
-
-// Verifies that the sync setup is terminated correctly when the
-// sync is disabled.
-TEST_F(SyncSetupHandlerTest, HandleSetupUIWhenSyncDisabled) {
-  EXPECT_CALL(*mock_pss_, IsManaged()).WillRepeatedly(Return(true));
-  handler_->HandleShowSetupUI(NULL);
-
-  // Sync setup is closed when sync is disabled.
-  EXPECT_EQ(NULL,
-            LoginUIServiceFactory::GetForProfile(
-                profile_.get())->current_login_ui());
-  ASSERT_FALSE(handler_->is_configuring_sync());
-}
-
-// Verifies that the handler correctly handles a cancellation when
-// it is displaying the spinner to the user.
-TEST_F(SyncSetupHandlerTest, DisplayConfigureWithEngineDisabledAndCancel) {
-  EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false));
-  error_ = GoogleServiceAuthError::AuthErrorNone();
-  EXPECT_CALL(*mock_pss_, IsEngineInitialized()).WillRepeatedly(Return(false));
-
-  // We're simulating a user setting up sync, which would cause the engine to
-  // kick off initialization, but not download user data types. The sync
-  // engine will try to download control data types (e.g encryption info), but
-  // that won't finish for this test as we're simulating cancelling while the
-  // spinner is showing.
-  handler_->HandleShowSetupUI(NULL);
-
-  EXPECT_EQ(handler_.get(),
-            LoginUIServiceFactory::GetForProfile(
-                profile_.get())->current_login_ui());
-
-  ExpectSpinnerAndClose();
-}
-
-// Verifies that the handler correctly transitions from showing the spinner
-// to showing a configuration page when sync setup completes successfully.
-TEST_F(SyncSetupHandlerTest,
-       DisplayConfigureWithEngineDisabledAndSyncStartupCompleted) {
-  EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false));
-  error_ = GoogleServiceAuthError::AuthErrorNone();
-  // Sync engine is stopped initially, and will start up.
-  EXPECT_CALL(*mock_pss_, IsEngineInitialized()).WillRepeatedly(Return(false));
-  SetDefaultExpectationsForConfigPage();
-
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  // We expect a call to SyncSetupOverlay.showSyncSetupPage.
-  EXPECT_EQ(1U, web_ui_.call_data().size());
-
-  const content::TestWebUI::CallData& data0 = *web_ui_.call_data()[0];
-  EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data0.function_name());
-  std::string page;
-  ASSERT_TRUE(data0.arg1()->GetAsString(&page));
-  EXPECT_EQ(page, "spinner");
-
-  Mock::VerifyAndClearExpectations(mock_pss_);
-  // Now, act as if the ProfileSyncService has started up.
-  SetDefaultExpectationsForConfigPage();
-  EXPECT_CALL(*mock_pss_, IsEngineInitialized()).WillRepeatedly(Return(true));
-  error_ = GoogleServiceAuthError::AuthErrorNone();
-  EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
-  NotifySyncListeners();
-
-  // We expect a second call to SyncSetupOverlay.showSyncSetupPage.
-  EXPECT_EQ(2U, web_ui_.call_data().size());
-  const content::TestWebUI::CallData& data1 = *web_ui_.call_data().back();
-  EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data1.function_name());
-  ASSERT_TRUE(data1.arg1()->GetAsString(&page));
-  EXPECT_EQ(page, "configure");
-  const base::DictionaryValue* dictionary = nullptr;
-  ASSERT_TRUE(data1.arg2()->GetAsDictionary(&dictionary));
-  CheckBool(dictionary, "passphraseFailed", false);
-  CheckBool(dictionary, "syncAllDataTypes", true);
-  CheckBool(dictionary, "encryptAllDataAllowed", true);
-  CheckBool(dictionary, "encryptAllData", false);
-  CheckBool(dictionary, "usePassphrase", false);
-}
-
-// Verifies the case where the user cancels after the sync engine has
-// initialized (meaning it already transitioned from the spinner to a proper
-// configuration page, tested by
-// DisplayConfigureWithEngineDisabledAndSyncStartupCompleted), but before the
-// user has continued on.
-TEST_F(SyncSetupHandlerTest,
-       DisplayConfigureWithEngineDisabledAndCancelAfterSigninSuccess) {
-  EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false));
-  error_ = GoogleServiceAuthError::AuthErrorNone();
-  EXPECT_CALL(*mock_pss_, IsEngineInitialized())
-      .WillOnce(Return(false))
-      .WillRepeatedly(Return(true));
-  SetDefaultExpectationsForConfigPage();
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  // It's important to tell sync the user cancelled the setup flow before we
-  // tell it we're through with the setup progress.
-  testing::InSequence seq;
-  EXPECT_CALL(*mock_pss_, RequestStop(ProfileSyncService::CLEAR_DATA));
-  EXPECT_CALL(*mock_pss_, OnSetupInProgressHandleDestroyed());
-
-  handler_->CloseSyncSetup();
-  EXPECT_EQ(NULL,
-            LoginUIServiceFactory::GetForProfile(
-                profile_.get())->current_login_ui());
-}
-
-TEST_F(SyncSetupHandlerTest,
-       DisplayConfigureWithEngineDisabledAndSigninFailed) {
-  EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false));
-  error_ = GoogleServiceAuthError::AuthErrorNone();
-  EXPECT_CALL(*mock_pss_, IsEngineInitialized()).WillRepeatedly(Return(false));
-
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-  const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-  EXPECT_EQ("SyncSetupOverlay.showSyncSetupPage", data.function_name());
-  std::string page;
-  ASSERT_TRUE(data.arg1()->GetAsString(&page));
-  EXPECT_EQ(page, "spinner");
-  Mock::VerifyAndClearExpectations(mock_pss_);
-  error_ = GoogleServiceAuthError(
-      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
-  EXPECT_CALL(*mock_pss_, GetAuthError()).WillRepeatedly(ReturnRef(error_));
-  NotifySyncListeners();
-
-  // On failure, the dialog will be closed.
-  EXPECT_EQ(NULL,
-            LoginUIServiceFactory::GetForProfile(
-                profile_.get())->current_login_ui());
-}
-
-#if !defined(OS_CHROMEOS)
-
-class SyncSetupHandlerNonCrosTest : public SyncSetupHandlerTest {
- public:
-  SyncSetupHandlerNonCrosTest() {}
-};
-
-TEST_F(SyncSetupHandlerNonCrosTest, HandleGaiaAuthFailure) {
-  EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, HasUnrecoverableError())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false));
-  // Open the web UI.
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  ASSERT_FALSE(handler_->is_configuring_sync());
-}
-
-// TODO(kochi): We need equivalent tests for ChromeOS.
-TEST_F(SyncSetupHandlerNonCrosTest, UnrecoverableErrorInitializingSync) {
-  EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false));
-  // Open the web UI.
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  ASSERT_FALSE(handler_->is_configuring_sync());
-}
-
-TEST_F(SyncSetupHandlerNonCrosTest, GaiaErrorInitializingSync) {
-  EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false));
-  // Open the web UI.
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  ASSERT_FALSE(handler_->is_configuring_sync());
-}
-
-#endif  // #if !defined(OS_CHROMEOS)
-
-TEST_F(SyncSetupHandlerTest, TestSyncEverything) {
-  std::string args =
-      GetConfiguration(NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(),
-                       ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED);
-  base::ListValue list_args;
-  list_args.AppendString(args);
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(true, _));
-  handler_->HandleConfigure(&list_args);
-
-  // Ensure that we navigated to the "done" state since we don't need a
-  // passphrase.
-  ExpectDone();
-}
-
-TEST_F(SyncSetupHandlerTest, TurnOnEncryptAll) {
-  std::string args =
-      GetConfiguration(NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(),
-                       ENCRYPT_ALL_DATA, PAYMENTS_INTEGRATION_ENABLED);
-  base::ListValue list_args;
-  list_args.AppendString(args);
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsEncryptEverythingAllowed())
-      .WillRepeatedly(Return(true));
-  SetupInitializedProfileSyncService();
-  EXPECT_CALL(*mock_pss_, EnableEncryptEverything());
-  EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(true, _));
-  handler_->HandleConfigure(&list_args);
-
-  // Ensure that we navigated to the "done" state since we don't need a
-  // passphrase.
-  ExpectDone();
-}
-
-TEST_F(SyncSetupHandlerTest, TestPassphraseStillRequired) {
-  std::string args =
-      GetConfiguration(NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(),
-                       ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED);
-  base::ListValue list_args;
-  list_args.AppendString(args);
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(_, _));
-  SetDefaultExpectationsForConfigPage();
-
-  // We should navigate back to the configure page since we need a passphrase.
-  handler_->HandleConfigure(&list_args);
-
-  ExpectConfig();
-}
-
-TEST_F(SyncSetupHandlerTest, SuccessfullySetPassphrase) {
-  base::DictionaryValue dict;
-  dict.SetBoolean("isGooglePassphrase", true);
-  std::string args =
-      GetConfiguration(&dict, SYNC_ALL_DATA, GetAllTypes(), "gaiaPassphrase",
-                       ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED);
-  base::ListValue list_args;
-  list_args.AppendString(args);
-  // Act as if an encryption passphrase is required the first time, then never
-  // again after that.
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired()).WillOnce(Return(true));
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(_, _));
-  EXPECT_CALL(*mock_pss_, SetDecryptionPassphrase("gaiaPassphrase")).
-      WillOnce(Return(true));
-
-  handler_->HandleConfigure(&list_args);
-  // We should navigate to "done" page since we finished configuring.
-  ExpectDone();
-}
-
-TEST_F(SyncSetupHandlerTest, SelectCustomEncryption) {
-  base::DictionaryValue dict;
-  dict.SetBoolean("isGooglePassphrase", false);
-  std::string args =
-      GetConfiguration(&dict, SYNC_ALL_DATA, GetAllTypes(), "custom_passphrase",
-                       ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED);
-  base::ListValue list_args;
-  list_args.AppendString(args);
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(_, _));
-  EXPECT_CALL(*mock_pss_,
-              SetEncryptionPassphrase("custom_passphrase",
-                                      ProfileSyncService::EXPLICIT));
-
-  handler_->HandleConfigure(&list_args);
-  // We should navigate to "done" page since we finished configuring.
-  ExpectDone();
-}
-
-TEST_F(SyncSetupHandlerTest, UnsuccessfullySetPassphrase) {
-  base::DictionaryValue dict;
-  dict.SetBoolean("isGooglePassphrase", true);
-  std::string args = GetConfiguration(&dict, SYNC_ALL_DATA, GetAllTypes(),
-                                      "invalid_passphrase", ENCRYPT_PASSWORDS,
-                                      PAYMENTS_INTEGRATION_ENABLED);
-  base::ListValue list_args;
-  list_args.AppendString(args);
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(_, _));
-  EXPECT_CALL(*mock_pss_, SetDecryptionPassphrase("invalid_passphrase")).
-      WillOnce(Return(false));
-
-  SetDefaultExpectationsForConfigPage();
-  // We should navigate back to the configure page since we need a passphrase.
-  handler_->HandleConfigure(&list_args);
-
-  ExpectConfig();
-
-  // Make sure we display an error message to the user due to the failed
-  // passphrase.
-  const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-  const base::DictionaryValue* dictionary = nullptr;
-  ASSERT_TRUE(data.arg2()->GetAsDictionary(&dictionary));
-  CheckBool(dictionary, "passphraseFailed", true);
-}
-
-// Walks through each user selectable type, and tries to sync just that single
-// data type.
-TEST_F(SyncSetupHandlerTest, TestSyncIndividualTypes) {
-  syncer::ModelTypeSet user_selectable_types = GetAllTypes();
-  syncer::ModelTypeSet::Iterator it;
-  for (it = user_selectable_types.First(); it.Good(); it.Inc()) {
-    syncer::ModelTypeSet type_to_set;
-    type_to_set.Put(it.Get());
-    std::string args =
-        GetConfiguration(NULL, CHOOSE_WHAT_TO_SYNC, type_to_set, std::string(),
-                         ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED);
-    base::ListValue list_args;
-    list_args.AppendString(args);
-    EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
-        .WillRepeatedly(Return(false));
-    EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-        .WillRepeatedly(Return(false));
-    SetupInitializedProfileSyncService();
-    EXPECT_CALL(*mock_pss_,
-                OnUserChoseDatatypes(false, ModelTypeSetMatches(type_to_set)));
-    handler_->HandleConfigure(&list_args);
-
-    ExpectDone();
-    Mock::VerifyAndClearExpectations(mock_pss_);
-    web_ui_.ClearTrackedCalls();
-  }
-}
-
-TEST_F(SyncSetupHandlerTest, TestSyncAllManually) {
-  std::string args =
-      GetConfiguration(NULL, CHOOSE_WHAT_TO_SYNC, GetAllTypes(), std::string(),
-                       ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED);
-  base::ListValue list_args;
-  list_args.AppendString(args);
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  EXPECT_CALL(*mock_pss_,
-              OnUserChoseDatatypes(false, ModelTypeSetMatches(GetAllTypes())));
-  handler_->HandleConfigure(&list_args);
-
-  ExpectDone();
-}
-
-TEST_F(SyncSetupHandlerTest, ShowSyncSetup) {
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  // This should display the sync setup dialog (not login).
-  SetDefaultExpectationsForConfigPage();
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  ExpectConfig();
-}
-
-// We do not display signin on chromeos in the case of auth error.
-TEST_F(SyncSetupHandlerTest, ShowSigninOnAuthError) {
-  // Initialize the system to a signed in state, but with an auth error.
-  error_ = GoogleServiceAuthError(
-      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
-
-  SetupInitializedProfileSyncService();
-  mock_signin_->SetAuthenticatedAccountInfo(kTestUser, kTestUser);
-  FakeAuthStatusProvider provider(
-      SigninErrorControllerFactory::GetForProfile(profile_.get()));
-  provider.SetAuthError(kTestUser, error_);
-  EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsEngineInitialized()).WillRepeatedly(Return(false));
-
-#if defined(OS_CHROMEOS)
-  // On ChromeOS, auth errors are ignored - instead we just try to start the
-  // sync engine (which will fail due to the auth error). This should only
-  // happen if the user manually navigates to chrome://settings/syncSetup -
-  // clicking on the button in the UI will sign the user out rather than
-  // displaying a spinner. Should be no visible UI on ChromeOS in this case.
-  EXPECT_EQ(NULL, LoginUIServiceFactory::GetForProfile(
-      profile_.get())->current_login_ui());
-#else
-
-  // On ChromeOS, this should display the spinner while we try to startup the
-  // sync engine, and on desktop this displays the login dialog.
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  // Sync setup is closed when re-auth is in progress.
-  EXPECT_EQ(NULL,
-            LoginUIServiceFactory::GetForProfile(
-                profile_.get())->current_login_ui());
-
-  ASSERT_FALSE(handler_->is_configuring_sync());
-#endif
-}
-
-TEST_F(SyncSetupHandlerTest, ShowSetupSyncEverything) {
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  SetDefaultExpectationsForConfigPage();
-  // This should display the sync setup dialog (not login).
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  ExpectConfig();
-  const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-  const base::DictionaryValue* dictionary = nullptr;
-  ASSERT_TRUE(data.arg2()->GetAsDictionary(&dictionary));
-  CheckBool(dictionary, "syncAllDataTypes", true);
-  CheckBool(dictionary, "appsRegistered", true);
-  CheckBool(dictionary, "autofillRegistered", true);
-  CheckBool(dictionary, "bookmarksRegistered", true);
-  CheckBool(dictionary, "extensionsRegistered", true);
-  CheckBool(dictionary, "passwordsRegistered", true);
-  CheckBool(dictionary, "preferencesRegistered", true);
-  CheckBool(dictionary, "tabsRegistered", true);
-  CheckBool(dictionary, "themesRegistered", true);
-  CheckBool(dictionary, "typedUrlsRegistered", true);
-  CheckBool(dictionary, "paymentsIntegrationEnabled", true);
-  CheckBool(dictionary, "showPassphrase", false);
-  CheckBool(dictionary, "usePassphrase", false);
-  CheckBool(dictionary, "passphraseFailed", false);
-  CheckBool(dictionary, "encryptAllData", false);
-  CheckConfigDataTypeArguments(dictionary, SYNC_ALL_DATA, GetAllTypes());
-}
-
-TEST_F(SyncSetupHandlerTest, ShowSetupManuallySyncAll) {
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  syncer::SyncPrefs sync_prefs(profile_->GetPrefs());
-  sync_prefs.SetKeepEverythingSynced(false);
-  SetDefaultExpectationsForConfigPage();
-  // This should display the sync setup dialog (not login).
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  ExpectConfig();
-  const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-  const base::DictionaryValue* dictionary = nullptr;
-  ASSERT_TRUE(data.arg2()->GetAsDictionary(&dictionary));
-  CheckConfigDataTypeArguments(dictionary, CHOOSE_WHAT_TO_SYNC, GetAllTypes());
-}
-
-TEST_F(SyncSetupHandlerTest, ShowSetupSyncForAllTypesIndividually) {
-  syncer::ModelTypeSet user_selectable_types = GetAllTypes();
-  syncer::ModelTypeSet::Iterator it;
-  for (it = user_selectable_types.First(); it.Good(); it.Inc()) {
-    EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-        .WillRepeatedly(Return(false));
-    EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-        .WillRepeatedly(Return(false));
-    SetupInitializedProfileSyncService();
-    syncer::SyncPrefs sync_prefs(profile_->GetPrefs());
-    sync_prefs.SetKeepEverythingSynced(false);
-    SetDefaultExpectationsForConfigPage();
-    syncer::ModelTypeSet types;
-    types.Put(it.Get());
-    EXPECT_CALL(*mock_pss_, GetPreferredDataTypes()).
-        WillRepeatedly(Return(types));
-
-    // This should display the sync setup dialog (not login).
-    handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-    ExpectConfig();
-    // Close the config overlay.
-    LoginUIServiceFactory::GetForProfile(profile_.get())->LoginUIClosed(
-        handler_.get());
-    const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-    const base::DictionaryValue* dictionary = nullptr;
-    ASSERT_TRUE(data.arg2()->GetAsDictionary(&dictionary));
-    CheckConfigDataTypeArguments(dictionary, CHOOSE_WHAT_TO_SYNC, types);
-    Mock::VerifyAndClearExpectations(mock_pss_);
-    // Clean up so we can loop back to display the dialog again.
-    web_ui_.ClearTrackedCalls();
-  }
-}
-
-TEST_F(SyncSetupHandlerTest, ShowSetupGaiaPassphraseRequired) {
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  SetDefaultExpectationsForConfigPage();
-
-  // This should display the sync setup dialog (not login).
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  ExpectConfig();
-  const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-  const base::DictionaryValue* dictionary = nullptr;
-  ASSERT_TRUE(data.arg2()->GetAsDictionary(&dictionary));
-  CheckBool(dictionary, "showPassphrase", true);
-  CheckBool(dictionary, "usePassphrase", false);
-  CheckBool(dictionary, "passphraseFailed", false);
-}
-
-TEST_F(SyncSetupHandlerTest, ShowSetupCustomPassphraseRequired) {
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(*mock_pss_, GetPassphraseType())
-      .WillRepeatedly(Return(syncer::PassphraseType::CUSTOM_PASSPHRASE));
-  SetupInitializedProfileSyncService();
-  SetDefaultExpectationsForConfigPage();
-
-  // This should display the sync setup dialog (not login).
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  ExpectConfig();
-  const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-  const base::DictionaryValue* dictionary = nullptr;
-  ASSERT_TRUE(data.arg2()->GetAsDictionary(&dictionary));
-  CheckBool(dictionary, "showPassphrase", true);
-  CheckBool(dictionary, "usePassphrase", true);
-  CheckBool(dictionary, "passphraseFailed", false);
-}
-
-TEST_F(SyncSetupHandlerTest, ShowSetupEncryptAll) {
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  SetDefaultExpectationsForConfigPage();
-  EXPECT_CALL(*mock_pss_, IsEncryptEverythingEnabled())
-      .WillRepeatedly(Return(true));
-
-  // This should display the sync setup dialog (not login).
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  ExpectConfig();
-  const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-  const base::DictionaryValue* dictionary = nullptr;
-  ASSERT_TRUE(data.arg2()->GetAsDictionary(&dictionary));
-  CheckBool(dictionary, "encryptAllData", true);
-}
-
-TEST_F(SyncSetupHandlerTest, ShowSetupEncryptAllDisallowed) {
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsUsingSecondaryPassphrase())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  SetDefaultExpectationsForConfigPage();
-  EXPECT_CALL(*mock_pss_, IsEncryptEverythingAllowed())
-      .WillRepeatedly(Return(false));
-
-  // This should display the sync setup dialog (not login).
-  handler_->OpenSyncSetup(false /* creating_supervised_user */);
-
-  ExpectConfig();
-  const content::TestWebUI::CallData& data = *web_ui_.call_data()[0];
-  const base::DictionaryValue* dictionary = nullptr;
-  ASSERT_TRUE(data.arg2()->GetAsDictionary(&dictionary));
-  CheckBool(dictionary, "encryptAllData", false);
-  CheckBool(dictionary, "encryptAllDataAllowed", false);
-}
-
-TEST_F(SyncSetupHandlerTest, TurnOnEncryptAllDisallowed) {
-  std::string args =
-      GetConfiguration(NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(),
-                       ENCRYPT_ALL_DATA, PAYMENTS_INTEGRATION_ENABLED);
-  base::ListValue list_args;
-  list_args.AppendString(args);
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, IsPassphraseRequired())
-      .WillRepeatedly(Return(false));
-  SetupInitializedProfileSyncService();
-  EXPECT_CALL(*mock_pss_, IsEncryptEverythingAllowed())
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*mock_pss_, EnableEncryptEverything()).Times(0);
-  EXPECT_CALL(*mock_pss_, OnUserChoseDatatypes(true, _));
-  handler_->HandleConfigure(&list_args);
-
-  // Ensure that we navigated to the "done" state since we don't need a
-  // passphrase.
-  ExpectDone();
-}
diff --git a/chrome/browser/ui/webui/plural_string_handler.cc b/chrome/browser/ui/webui/plural_string_handler.cc
new file mode 100644
index 0000000..4693d19
--- /dev/null
+++ b/chrome/browser/ui/webui/plural_string_handler.cc
@@ -0,0 +1,45 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/plural_string_handler.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/values.h"
+#include "content/public/browser/web_ui.h"
+#include "ui/base/l10n/l10n_util.h"
+
+PluralStringHandler::PluralStringHandler() {}
+
+PluralStringHandler::~PluralStringHandler() {}
+
+void PluralStringHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "getPluralString", base::Bind(&PluralStringHandler::HandleGetPluralString,
+                                    base::Unretained(this)));
+}
+
+void PluralStringHandler::AddLocalizedString(const std::string& name, int id) {
+  name_to_id_[name] = id;
+}
+
+void PluralStringHandler::HandleGetPluralString(const base::ListValue* args) {
+  AllowJavascript();
+  CHECK_EQ(3U, args->GetSize());
+  const base::Value* callback_id;
+  CHECK(args->Get(0, &callback_id));
+
+  std::string message_name;
+  CHECK(args->GetString(1, &message_name));
+
+  int count;
+  CHECK(args->GetInteger(2, &count));
+
+  auto message_id_it = name_to_id_.find(message_name);
+  CHECK(name_to_id_.end() != message_id_it);
+
+  ResolveJavascriptCallback(*callback_id,
+                            base::Value(l10n_util::GetPluralStringFUTF8(
+                                message_id_it->second, count)));
+}
diff --git a/chrome/browser/ui/webui/plural_string_handler.h b/chrome/browser/ui/webui/plural_string_handler.h
new file mode 100644
index 0000000..c953524
--- /dev/null
+++ b/chrome/browser/ui/webui/plural_string_handler.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 CHROME_BROWSER_UI_WEBUI_PLURAL_STRING_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_PLURAL_STRING_HANDLER_H_
+
+#include "base/macros.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+// A handler which provides pluralized strings.
+class PluralStringHandler : public content::WebUIMessageHandler {
+ public:
+  PluralStringHandler();
+  ~PluralStringHandler() override;
+
+  void AddLocalizedString(const std::string& name, int id);
+
+  // WebUIMessageHandler:
+  void RegisterMessages() override;
+
+ private:
+  void HandleGetPluralString(const base::ListValue* args);
+
+  std::map<std::string, int> name_to_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(PluralStringHandler);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_PLURAL_STRING_HANDLER_H_
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 2222d7e79..b1a7c44 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -611,6 +611,7 @@
     "//base/third_party/dynamic_annotations",
     "//components/bookmarks/common",
     "//components/nacl/common:switches",
+    "//components/offline_pages/features",
     "//media:cdm_paths",  # Needed by chrome_paths.cc.
     "//media:media_features",
     "//ppapi/features",
diff --git a/chrome/common/DEPS b/chrome/common/DEPS
index bc3c673..63fb8e2 100644
--- a/chrome/common/DEPS
+++ b/chrome/common/DEPS
@@ -19,7 +19,7 @@
   "+components/metrics/metrics_pref_names.h",
   "+components/nacl/common",
   "+components/ntp_tiles",
-  "+components/offline_pages/offline_page_feature.h",
+  "+components/offline_pages/features",
   "+components/password_manager/core/common",
   "+components/policy/core/common",
   "+components/printing/common",
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 7b2eb7f..15adf88 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -2556,4 +2556,8 @@
 const char kClipboardLastModifiedTime[] = "ui.clipboard.last_modified_time";
 #endif
 
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+const char kOfflinePrefetchBackoff[] = "offline_prefetch.backoff";
+#endif
+
 }  // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index d6b5718..8343198 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -11,6 +11,7 @@
 
 #include "build/build_config.h"
 #include "chrome/common/features.h"
+#include "components/offline_pages/features/features.h"
 #include "extensions/features/features.h"
 #include "media/media_features.h"
 #include "ppapi/features/features.h"
@@ -921,6 +922,10 @@
 extern const char kClipboardLastModifiedTime[];
 #endif
 
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+extern const char kOfflinePrefetchBackoff[];
+#endif
+
 }  // namespace prefs
 
 #endif  // CHROME_COMMON_PREF_NAMES_H_
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 07f4346..99331b11 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1714,12 +1714,6 @@
       "../browser/ui/webui/net_internals/net_internals_ui_browsertest.cc",
       "../browser/ui/webui/net_internals/net_internals_ui_browsertest.h",
       "../browser/ui/webui/ntp/new_tab_ui_browsertest.cc",
-      "../browser/ui/webui/options/multilanguage_options_browsertest.cc",
-      "../browser/ui/webui/options/multilanguage_options_browsertest.h",
-      "../browser/ui/webui/options/options_browsertest.cc",
-      "../browser/ui/webui/options/options_browsertest.h",
-      "../browser/ui/webui/options/preferences_browsertest.cc",
-      "../browser/ui/webui/options/preferences_browsertest.h",
       "../browser/ui/webui/password_manager_internals/password_manager_internals_ui_browsertest.cc",
       "../browser/ui/webui/policy_ui_browsertest.cc",
       "../browser/ui/webui/prefs_internals_browsertest.cc",
@@ -2275,8 +2269,6 @@
         "../browser/ui/views/arc_app_dialog_view_browsertest.cc",
         "../browser/ui/views/frame/browser_frame_ash_browsertest.cc",
         "../browser/ui/webui/chromeos/keyboard_overlay_ui_browsertest.cc",
-        "../browser/ui/webui/options/chromeos/accounts_options_browsertest.cc",
-        "../browser/ui/webui/options/chromeos/shared_options_browsertest.cc",
       ]
       sources -= [
         "../../apps/load_and_launch_browsertest.cc",
@@ -3644,12 +3636,6 @@
       "../browser/ui/webui/help/version_updater_chromeos_unittest.cc",
       "../browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc",
       "../browser/ui/webui/md_downloads/md_downloads_dom_handler_unittest.cc",
-      "../browser/ui/webui/options/autofill_options_handler_unittest.cc",
-      "../browser/ui/webui/options/font_settings_utils_unittest.cc",
-      "../browser/ui/webui/options/language_options_handler_unittest.cc",
-      "../browser/ui/webui/options/password_manager_handler_unittest.cc",
-      "../browser/ui/webui/options/pepper_flash_content_settings_utils_unittest.cc",
-      "../browser/ui/webui/options/sync_setup_handler_unittest.cc",
       "../browser/ui/webui/settings/downloads_handler_unittest.cc",
       "../browser/ui/webui/settings/md_settings_ui_unittest.cc",
       "../browser/ui/webui/settings/metrics_reporting_handler_unittest.cc",
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 7e1fb87..aae34597 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -42,29 +42,6 @@
     "../../../browser/ui/webui/extensions/extension_settings_browsertest.js",
     "../../../browser/ui/webui/help/help_browsertest.js",
     "../../../browser/ui/webui/identity_internals_ui_browsertest.js",
-    "../../../browser/ui/webui/options/autofill_options_browsertest.js",
-    "../../../browser/ui/webui/options/browser_options_browsertest.js",
-    "../../../browser/ui/webui/options/certificate_manager_browsertest.js",
-    "../../../browser/ui/webui/options/chromeos/accounts_options_browsertest.js",
-    "../../../browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js",
-    "../../../browser/ui/webui/options/chromeos/date_time_options_browsertest.js",
-    "../../../browser/ui/webui/options/chromeos/power_overlay_browsertest.js",
-    "../../../browser/ui/webui/options/content_options_browsertest.js",
-    "../../../browser/ui/webui/options/content_settings_exception_area_browsertest.js",
-    "../../../browser/ui/webui/options/cookies_view_browsertest.js",
-    "../../../browser/ui/webui/options/edit_dictionary_browsertest.js",
-    "../../../browser/ui/webui/options/font_settings_browsertest.js",
-    "../../../browser/ui/webui/options/language_options_browsertest.js",
-    "../../../browser/ui/webui/options/language_options_dictionary_download_browsertest.js",
-    "../../../browser/ui/webui/options/manage_profile_browsertest.js",
-    "../../../browser/ui/webui/options/multilanguage_options_webui_browsertest.js",
-    "../../../browser/ui/webui/options/options_browsertest.js",
-    "../../../browser/ui/webui/options/options_browsertest_base.js",
-    "../../../browser/ui/webui/options/password_manager_browsertest.js",
-    "../../../browser/ui/webui/options/profile_settings_reset_browsertest.js",
-    "../../../browser/ui/webui/options/search_engine_manager_browsertest.js",
-    "../../../browser/ui/webui/options/settings_format_browsertest.js",
-    "../../../browser/ui/webui/options/startup_page_list_browsertest.js",
     "../../../browser/ui/webui/sync_internals_browsertest.js",
     "../../../browser/ui/webui/sync_setup_browsertest.js",
     "../chromeos/oobe_webui_browsertest.js",
@@ -130,18 +107,6 @@
   } else {
     sources -= [ "md_user_manager/user_manager_browsertest.js" ]
   }
-  if (is_mac) {
-    sources -= [
-      # TODO(rouslan): This test depends on the custom dictionary UI,
-      # which is disabled on Mac.
-      "../../../browser/ui/webui/options/edit_dictionary_browsertest.js",
-
-      # TODO(rouslan): This test depends on hunspell and we cannot run it
-      # on Mac, which does not use hunspell by default.
-      "../../../browser/ui/webui/options/language_options_dictionary_download_browsertest.js",
-      "../../../browser/ui/webui/options/multilanguage_options_webui_browsertest.js",
-    ]
-  }
   if (!enable_app_list) {
     sources -=
         [ "../../../browser/ui/webui/app_list/start_page_browsertest.js" ]
diff --git a/chrome/test/data/webui/inline_editable_list_test.html b/chrome/test/data/webui/inline_editable_list_test.html
deleted file mode 100644
index fe1181d..0000000
--- a/chrome/test/data/webui/inline_editable_list_test.html
+++ /dev/null
@@ -1,152 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-
-<script>
-
-function setUp() {
-  loadTimeData.data = { 
-    'deletableItemDeleteButtonTitle': 'test_deletable_button_title'
-  };
-  
-  cr.define('options', function() {
-    /** @const */ var InlineEditableItemList = options.InlineEditableItemList;
-    /** @const */ var InlineEditableItem = options.InlineEditableItem;
-  
-    /**
-     * Creates a test list item.
-     * @param {string} name This item's name.
-     * @constructor
-     * @extends {options.InlineEditableItem}
-     */
-    function TestItem(name) {
-      var el = cr.doc.createElement('div');
-      el.name_ = name;
-      TestItem.decorate(el);
-      return el;
-    }
-    
-    /**
-     * Decorates an element as a test list item.
-     * @param {!HTMLElement} el The element to decorate.
-     */
-    TestItem.decorate = function(el) {
-      el.__proto__ = TestItem.prototype;
-      el.decorate();
-    };
-    
-    TestItem.prototype = {
-      __proto__: InlineEditableItem.prototype,
-    
-      /**
-       * Item name. Used to set the item's text fields.
-       * @type {string}
-       * @private
-       */
-      name_: null,
-    
-      /** @override */
-      decorate: function() {
-        InlineEditableItem.prototype.decorate.call(this);
-  
-        var fieldEl = this.createEditableTextCell(this.name_);
-        this.contentElement.appendChild(fieldEl);
-  
-        fieldEl = this.createEditableTextCell(this.name_ + '_two');
-        this.contentElement.appendChild(fieldEl);
-      },
-    };
-  
-    /**
-     * @constructor
-     * @extends {options.InlineEditableItemList}
-     */
-    var TestItemList = cr.ui.define('list');
-    
-     TestItemList.prototype = {
-      __proto__: InlineEditableItemList.prototype,
-    
-      /**
-       * @override
-       * @param {string} name
-       */
-      createItem: function(name) {
-        return new TestItem(name);
-      },
-  
-      /**
-       * @param {!Element} el
-       * @return {boolean} True if |el| or any of its children are focusable. 
-       * @private
-       */
-      hasFocusableElement_: function(el) {
-        return el.querySelectorAll('[tabindex="0"]').length > 0;
-      },
-  
-      /**
-       * @param {number} itemIndex
-       * @return {boolean} True if item at |itemIndex| has a focusable element
-       *     and no other items have focusable elements.
-       */      
-      hasExactlyOneItemFocusable: function(itemIndex) {
-        var length = this.items.length;
-        for(var i = 0; i < length; ++i) {
-          if (this.hasFocusableElement_(this.items[i]) != (i == itemIndex))
-            return false;
-        }
-        return true;
-      },
-    };
-  
-    // Export.
-    return {
-      TestItemList: TestItemList
-    };
-  
-  })
-}
-
-/**
- * @param {!EventTarget} target Where to send the event. 
- * @param {!string} key Which key to send.
- */      
-function sendKeyDownEvent(target, key) {
-  var event = new KeyboardEvent('keydown',
-    {bubbles: true, cancelable: true, key: key});
-  target.dispatchEvent(event);  
-}
-
-/**
- * Test that exactly one item in the list is focusable after navigating the
- * list using up and down arrow keys.
- */
-function testUpDownFocus() {
-  var list = document.createElement('ul');
-  list.style.position = 'absolute';
-  list.style.width = '800px';
-  list.style.height = '800px';
-  options.TestItemList.decorate(list);
-  document.body.appendChild(list);
-
-  var model = new cr.ui.ArrayDataModel(['itemA', 'itemB', 'itemC']);
-  list.dataModel = model;
-  list.selectionModel.setIndexSelected(0, true);
-  list.selectionModel.leadIndex = 0;
-
-  assertTrue(list.hasExactlyOneItemFocusable(0));
-  sendKeyDownEvent(list, 'ArrowDown');
-  assertTrue(list.hasExactlyOneItemFocusable(1));
-  sendKeyDownEvent(list, 'ArrowDown');
-  assertTrue(list.hasExactlyOneItemFocusable(2));
-  sendKeyDownEvent(list, 'ArrowUp');
-  assertTrue(list.hasExactlyOneItemFocusable(1));
-  sendKeyDownEvent(list, 'ArrowUp');
-  assertTrue(list.hasExactlyOneItemFocusable(0));
-  sendKeyDownEvent(list, 'ArrowDown');
-  assertTrue(list.hasExactlyOneItemFocusable(1));
-}
-
-</script>
-
-</body>
-</html>
diff --git a/chrome/test/data/webui/md_bookmarks/command_manager_test.js b/chrome/test/data/webui/md_bookmarks/command_manager_test.js
index 2eab6fea..a616a69 100644
--- a/chrome/test/data/webui/md_bookmarks/command_manager_test.js
+++ b/chrome/test/data/webui/md_bookmarks/command_manager_test.js
@@ -43,6 +43,8 @@
 
     commandManager = new TestCommandManager();
     replaceBody(commandManager);
+    document.body.appendChild(
+        document.createElement('bookmarks-toast-manager'));
 
     Polymer.dom.flush();
   });
diff --git a/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js b/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
index 7b89786..524b1be 100644
--- a/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
+++ b/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
@@ -172,6 +172,20 @@
   mocha.run();
 });
 
+function MaterialBookmarksToastManagerTest() {}
+
+MaterialBookmarksToastManagerTest.prototype = {
+  __proto__: MaterialBookmarksBrowserTest.prototype,
+
+  extraLibraries: MaterialBookmarksBrowserTest.prototype.extraLibraries.concat([
+    'toast_manager_test.js',
+  ]),
+};
+
+TEST_F('MaterialBookmarksToastManagerTest', 'All', function() {
+  mocha.run();
+});
+
 function MaterialBookmarksPolicyTest() {}
 
 MaterialBookmarksPolicyTest.prototype = {
diff --git a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
index f19ebf5..5c186542 100644
--- a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
+++ b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
@@ -280,14 +280,16 @@
     });
 
     test('shift selection', function() {
-      // TODO(calamity): Make the first item the anchor index when a new folder
-      // is selected.
       var focusedItem = items[0];
       focusedItem.focus();
 
-      keydown(focusedItem, 'ArrowDown');
+      keydown(focusedItem, 'ArrowDown', 'shift');
       focusedItem = items[1];
-      assertDeepEquals(['3'], normalizeSet(store.data.selection.items));
+      assertDeepEquals(['2', '3'], normalizeSet(store.data.selection.items));
+
+      keydown(focusedItem, 'Escape');
+      focusedItem = items[1];
+      assertDeepEquals([], normalizeSet(store.data.selection.items));
 
       keydown(focusedItem, 'ArrowUp', 'shift');
       focusedItem = items[0];
diff --git a/chrome/test/data/webui/md_bookmarks/toast_manager_test.js b/chrome/test/data/webui/md_bookmarks/toast_manager_test.js
new file mode 100644
index 0000000..8830c8b2
--- /dev/null
+++ b/chrome/test/data/webui/md_bookmarks/toast_manager_test.js
@@ -0,0 +1,59 @@
+// 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.
+
+suite('<bookmarks-toast-manager>', function() {
+  var toastManager;
+  var store;
+
+  setup(function() {
+    toastManager = document.createElement('bookmarks-toast-manager');
+    replaceBody(toastManager);
+  });
+
+  test('simple show/hide', function() {
+    toastManager.show('test', false);
+    assertTrue(toastManager.open_);
+    assertEquals('test', toastManager.$.content.textContent);
+    assertTrue(toastManager.$$('paper-button').hidden);
+
+    toastManager.hide();
+    assertFalse(toastManager.open_);
+
+    toastManager.show('test', true);
+    assertFalse(toastManager.$$('paper-button').hidden);
+  });
+
+  test('auto hide', function() {
+    toastManager.duration = 100;
+
+    var timeoutFunc = null;
+    var timeoutCounter = 0;
+    var clearedTimeout = null;
+    toastManager.setTimeout_ = function(f) {
+      timeoutFunc = f;
+      return timeoutCounter++;
+    };
+    toastManager.clearTimeout_ = function(n) {
+      clearedTimeout = n;
+    };
+
+    toastManager.show('test', false);
+    assertEquals(0, toastManager.hideTimeout_);
+    assertTrue(toastManager.open_);
+
+    timeoutFunc();
+    assertEquals(null, toastManager.hideTimeout_);
+    assertFalse(toastManager.open_);
+
+    // Check that multiple shows reset the timeout.
+    toastManager.show('test', false);
+    assertEquals(1, toastManager.hideTimeout_);
+    assertTrue(toastManager.open_);
+
+    toastManager.show('test2', false);
+    assertEquals(1, clearedTimeout);
+    assertEquals(2, toastManager.hideTimeout_);
+    assertTrue(toastManager.open_);
+  });
+});
diff --git a/chrome/test/data/webui/webui_resource_browsertest.cc b/chrome/test/data/webui/webui_resource_browsertest.cc
index 8ad1818..b83d4ed 100644
--- a/chrome/test/data/webui/webui_resource_browsertest.cc
+++ b/chrome/test/data/webui/webui_resource_browsertest.cc
@@ -7,7 +7,6 @@
 #include "base/path_service.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/grit/options_test_resources.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chrome/test/data/grit/webui_test_resources.h"
@@ -149,22 +148,6 @@
       "list_single_selection_model_test.html")));
 }
 
-IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, InlineEditableListTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_EVENT_TARGET);
-  AddLibrary(IDR_WEBUI_JS_CR_UI);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_ARRAY_DATA_MODEL);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_ITEM);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_SELECTION_CONTROLLER);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_SELECTION_MODEL);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST);
-  AddLibrary(IDR_WEBUI_JS_LOAD_TIME_DATA);
-  AddLibrary(IDR_OPTIONS_DELETABLE_ITEM_LIST);
-  AddLibrary(IDR_OPTIONS_INLINE_EDITABLE_LIST);
-  LoadFile(base::FilePath(FILE_PATH_LITERAL(
-      "inline_editable_list_test.html")));
-}
-
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, MenuTest) {
   AddLibrary(IDR_WEBUI_JS_ASSERT);
   AddLibrary(IDR_WEBUI_JS_CR);
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskScheduler.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskScheduler.java
index bf85375..f78859a 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskScheduler.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskScheduler.java
@@ -11,6 +11,7 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
 
 import java.lang.reflect.Constructor;
 import java.util.Set;
@@ -60,7 +61,9 @@
 
     private final BackgroundTaskSchedulerDelegate mSchedulerDelegate;
 
-    BackgroundTaskScheduler(BackgroundTaskSchedulerDelegate schedulerDelegate) {
+    /** Public constructor that allows null delegate, for testing only */
+    @VisibleForTesting
+    public BackgroundTaskScheduler(BackgroundTaskSchedulerDelegate schedulerDelegate) {
         assert schedulerDelegate != null;
         mSchedulerDelegate = schedulerDelegate;
     }
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerDelegate.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerDelegate.java
index 87538f9..9ab0bee 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerDelegate.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerDelegate.java
@@ -11,7 +11,7 @@
  * system APIs ({@link android.app.job.JobScheduler} on newer platforms and GCM
  * ({@link com.google.android.gms.gcm.GcmNetworkManager}) on older platforms.
  */
-interface BackgroundTaskSchedulerDelegate {
+public interface BackgroundTaskSchedulerDelegate {
     /**
      * Schedules a background task. See {@link TaskInfo} for information on what types of tasks that
      * can be scheduled.
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher.h b/components/offline_pages/core/prefetch/prefetch_dispatcher.h
index b8d68de..37403f1a 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher.h
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher.h
@@ -29,9 +29,9 @@
     ScopedBackgroundTask() = default;
     virtual ~ScopedBackgroundTask() = default;
 
-    // Used on destruction to inform the system about whether rescheduling is
-    // required.
-    virtual void SetNeedsReschedule(bool reschedule) = 0;
+    // Used on destruction to inform the system about whether rescheduling with
+    // or without backoff is required.
+    virtual void SetNeedsReschedule(bool reschedule, bool backoff) = 0;
   };
 
   virtual ~PrefetchDispatcher() = default;
@@ -65,7 +65,10 @@
   // Called when a task must stop immediately due to system constraints. After
   // this call completes, the system will reschedule the task based on whether
   // SetNeedsReschedule has been called.
-  virtual void StopBackgroundTask(ScopedBackgroundTask* task) = 0;
+  virtual void StopBackgroundTask() = 0;
+
+  // Used by the test to signal the completion of the background task.
+  virtual void RequestFinishBackgroundTaskForTest() = 0;
 };
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
index bad8687..5952f2b 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -4,13 +4,23 @@
 
 #include "components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h"
 
+#include "base/bind.h"
 #include "base/memory/ptr_util.h"
+#include "base/task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "components/offline_pages/core/prefetch/add_unique_urls_task.h"
 #include "components/offline_pages/core/prefetch/prefetch_service.h"
 #include "url/gurl.h"
 
 namespace offline_pages {
 
+namespace {
+void DeleteBackgroundTaskHelper(
+    std::unique_ptr<PrefetchDispatcher::ScopedBackgroundTask> task) {
+  task.reset();
+}
+}  // namespace
+
 PrefetchDispatcherImpl::PrefetchDispatcherImpl() = default;
 
 PrefetchDispatcherImpl::~PrefetchDispatcherImpl() = default;
@@ -39,11 +49,23 @@
 
 void PrefetchDispatcherImpl::BeginBackgroundTask(
     std::unique_ptr<ScopedBackgroundTask> task) {
-  NOTIMPLEMENTED();
+  task_ = std::move(task);
 }
 
-void PrefetchDispatcherImpl::StopBackgroundTask(ScopedBackgroundTask* task) {
-  NOTIMPLEMENTED();
+void PrefetchDispatcherImpl::StopBackgroundTask() {
+  DisposeTask();
+}
+
+void PrefetchDispatcherImpl::RequestFinishBackgroundTaskForTest() {
+  DisposeTask();
+}
+
+void PrefetchDispatcherImpl::DisposeTask() {
+  DCHECK(task_);
+  // Delay the deletion till the caller finishes.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&DeleteBackgroundTaskHelper, base::Passed(std::move(task_))));
 }
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
index 3764a5b..d303dcf 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
@@ -26,13 +26,17 @@
   void RemoveAllUnprocessedPrefetchURLs(const std::string& name_space) override;
   void RemovePrefetchURLsByClientId(const ClientId& client_id) override;
   void BeginBackgroundTask(std::unique_ptr<ScopedBackgroundTask> task) override;
-  void StopBackgroundTask(ScopedBackgroundTask* task) override;
+  void StopBackgroundTask() override;
+  void RequestFinishBackgroundTaskForTest() override;
 
  private:
   friend class PrefetchDispatcherTest;
 
+  void DisposeTask();
+
   PrefetchService* service_;
   TaskQueue task_queue_;
+  std::unique_ptr<ScopedBackgroundTask> task_;
 
   DISALLOW_COPY_AND_ASSIGN(PrefetchDispatcherImpl);
 };
diff --git a/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc b/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc
index 6ed4c1b..de04af6 100644
--- a/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc
+++ b/components/offline_pages/core/prefetch/suggested_articles_observer_unittest.cc
@@ -55,7 +55,8 @@
 
   void BeginBackgroundTask(
       std::unique_ptr<ScopedBackgroundTask> task) override {}
-  void StopBackgroundTask(ScopedBackgroundTask* task) override {}
+  void StopBackgroundTask() override {}
+  void RequestFinishBackgroundTaskForTest() override {}
 
   std::vector<PrefetchURL> latest_prefetch_urls;
   ClientId last_removed_client_id;
diff --git a/components/translate/ios/browser/ios_translate_driver.h b/components/translate/ios/browser/ios_translate_driver.h
index e9c0f08..7043de1 100644
--- a/components/translate/ios/browser/ios_translate_driver.h
+++ b/components/translate/ios/browser/ios_translate_driver.h
@@ -25,6 +25,7 @@
 namespace translate {
 
 class TranslateManager;
+class LanguageModel;
 
 // Content implementation of TranslateDriver.
 class IOSTranslateDriver : public TranslateDriver,
@@ -33,7 +34,8 @@
  public:
   IOSTranslateDriver(web::WebState* web_state,
                      web::NavigationManager* navigation_manager,
-                     TranslateManager* translate_manager);
+                     TranslateManager* translate_manager,
+                     LanguageModel* language_model);
   ~IOSTranslateDriver() override;
 
   LanguageDetectionController* language_detection_controller() {
@@ -98,6 +100,9 @@
   // The navigation manager of the tab we are associated with.
   web::NavigationManager* navigation_manager_;
 
+  // Model to be notified about detected language of every page visited.
+  translate::LanguageModel* language_model_;
+
   base::WeakPtr<TranslateManager> translate_manager_;
   std::unique_ptr<TranslateController> translate_controller_;
   std::unique_ptr<LanguageDetectionController> language_detection_controller_;
diff --git a/components/translate/ios/browser/ios_translate_driver.mm b/components/translate/ios/browser/ios_translate_driver.mm
index dc5a9203..e2d79467 100644
--- a/components/translate/ios/browser/ios_translate_driver.mm
+++ b/components/translate/ios/browser/ios_translate_driver.mm
@@ -9,6 +9,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "components/translate/core/browser/language_model.h"
 #include "components/translate/core/browser/translate_client.h"
 #include "components/translate/core/browser/translate_manager.h"
 #include "components/translate/core/common/translate_constants.h"
@@ -49,9 +50,11 @@
 IOSTranslateDriver::IOSTranslateDriver(
     web::WebState* web_state,
     web::NavigationManager* navigation_manager,
-    TranslateManager* translate_manager)
+    TranslateManager* translate_manager,
+    LanguageModel* language_model)
     : web::WebStateObserver(web_state),
       navigation_manager_(navigation_manager),
+      language_model_(language_model),
       translate_manager_(translate_manager->GetWeakPtr()),
       page_seq_no_(0),
       pending_page_seq_no_(0),
@@ -92,6 +95,11 @@
   translate_manager_->GetLanguageState().LanguageDetermined(
       details.adopted_language, true);
 
+  // Update language model.
+  if (language_model_ && details.is_cld_reliable) {
+    language_model_->OnPageVisited(details.cld_language);
+  }
+
   if (web_state())
     translate_manager_->InitiateTranslation(details.adopted_language);
 }
diff --git a/components/translate/ios/browser/language_detection_controller.h b/components/translate/ios/browser/language_detection_controller.h
index c3271e82..f4c3936 100644
--- a/components/translate/ios/browser/language_detection_controller.h
+++ b/components/translate/ios/browser/language_detection_controller.h
@@ -34,7 +34,14 @@
 class LanguageDetectionController : public web::WebStateObserver {
  public:
   // Language detection details, passed to language detection callbacks.
+  // TODO(crbug.com/715447): Investigate if we can use the existing
+  // detection_details under
+  // components/translate/core/common/language_detection_details.h.
   struct DetectionDetails {
+    DetectionDetails();
+    DetectionDetails(const DetectionDetails& other);
+    ~DetectionDetails();
+
     // The language detected by the content (Content-Language).
     std::string content_language;
 
@@ -43,6 +50,12 @@
 
     // The adopted language.
     std::string adopted_language;
+
+    // The language detected by CLD.
+    std::string cld_language;
+
+    // Whether the CLD detection is reliable or not.
+    bool is_cld_reliable;
   };
 
   LanguageDetectionController(web::WebState* web_state,
diff --git a/components/translate/ios/browser/language_detection_controller.mm b/components/translate/ios/browser/language_detection_controller.mm
index 4c23553..642377ae 100644
--- a/components/translate/ios/browser/language_detection_controller.mm
+++ b/components/translate/ios/browser/language_detection_controller.mm
@@ -52,6 +52,14 @@
 LanguageDetectionController::~LanguageDetectionController() {
 }
 
+LanguageDetectionController::DetectionDetails::DetectionDetails()
+    : is_cld_reliable(false) {}
+
+LanguageDetectionController::DetectionDetails::DetectionDetails(
+    const DetectionDetails& other) = default;
+
+LanguageDetectionController::DetectionDetails::~DetectionDetails() = default;
+
 std::unique_ptr<LanguageDetectionController::CallbackList::Subscription>
 LanguageDetectionController::RegisterLanguageDetectionCallback(
     const Callback& callback) {
@@ -115,11 +123,13 @@
     const std::string& http_content_language,
     const std::string& html_lang,
     const base::string16& text_content) {
+  std::string cld_language;
+  bool is_cld_reliable;
   std::string language = translate::DeterminePageLanguage(
       http_content_language, html_lang,
       GetStringByClippingLastWord(text_content,
                                   language_detection::kMaxIndexChars),
-      nullptr /* cld_language */, nullptr /* is_cld_reliable */);
+      &cld_language, &is_cld_reliable);
   if (language.empty())
     return;  // No language detected.
 
@@ -127,6 +137,8 @@
   details.content_language = http_content_language;
   details.html_root_language = html_lang;
   details.adopted_language = language;
+  details.cld_language = cld_language;
+  details.is_cld_reliable = is_cld_reliable;
   language_detection_callbacks_.Notify(details);
 }
 
diff --git a/components/translate/ios/browser/language_detection_controller_unittest.mm b/components/translate/ios/browser/language_detection_controller_unittest.mm
index 0593ba8..c74861b4 100644
--- a/components/translate/ios/browser/language_detection_controller_unittest.mm
+++ b/components/translate/ios/browser/language_detection_controller_unittest.mm
@@ -59,6 +59,7 @@
 TEST_F(LanguageDetectionControllerTest, OnTextCaptured) {
   const std::string kRootLanguage("en");
   const std::string kContentLanguage("fr");
+  const std::string kUndefined("und");
 
   __block bool block_was_called = false;
   auto subscription =
@@ -67,6 +68,8 @@
             block_was_called = true;
             EXPECT_EQ(kRootLanguage, details.html_root_language);
             EXPECT_EQ(kContentLanguage, details.content_language);
+            EXPECT_FALSE(details.is_cld_reliable);
+            EXPECT_EQ(kUndefined, details.cld_language);
           }));
 
   base::DictionaryValue command;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index a249d77f..b16b295c 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1595,12 +1595,6 @@
       "tracing/power_tracing_agent.h",
     ]
   }
-  if (is_chromeos) {
-    sources += [
-      "tracing/arc_tracing_agent.cc",
-      "tracing/arc_tracing_agent.h",
-    ]
-  }
 
   if (enable_webrtc) {
     sources += [
diff --git a/content/browser/blob_storage/blob_url_loader_factory.cc b/content/browser/blob_storage/blob_url_loader_factory.cc
index 8267654e..1dbcb19 100644
--- a/content/browser/blob_storage/blob_url_loader_factory.cc
+++ b/content/browser/blob_storage/blob_url_loader_factory.cc
@@ -359,15 +359,12 @@
                      std::move(blob_storage_context_getter)));
 }
 
-mojom::URLLoaderFactoryPtr BlobURLLoaderFactory::CreateFactory() {
+void BlobURLLoaderFactory::HandleRequest(
+    mojom::URLLoaderFactoryRequest request) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  mojom::URLLoaderFactoryPtr factory;
-  mojom::URLLoaderFactoryRequest request = mojo::MakeRequest(&factory);
   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
                           base::BindOnce(&BlobURLLoaderFactory::BindOnIO, this,
                                          std::move(request)));
-
-  return factory;
 }
 
 BlobURLLoaderFactory::~BlobURLLoaderFactory() {}
diff --git a/content/browser/blob_storage/blob_url_loader_factory.h b/content/browser/blob_storage/blob_url_loader_factory.h
index cea4f06..edfa7f3 100644
--- a/content/browser/blob_storage/blob_url_loader_factory.h
+++ b/content/browser/blob_storage/blob_url_loader_factory.h
@@ -35,7 +35,7 @@
 
   // Creates a URLLoaderFactory interface pointer for serving blob requests.
   // Called on the UI thread.
-  mojom::URLLoaderFactoryPtr CreateFactory();
+  void HandleRequest(mojom::URLLoaderFactoryRequest request);
 
   // mojom::URLLoaderFactory implementation:
   void CreateLoaderAndStart(mojom::URLLoaderAssociatedRequest loader,
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index 2b37721a..b557e43 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -59,11 +59,10 @@
 
 // Kept around during the lifetime of the navigation request, and is
 // responsible for dispatching a ResourceRequest to the appropriate
-// URLLoaderFactory.  In order to get the right URLLoaderFactory it
-// builds a vector of URLLoaderRequestHandler's and successively calls
-// MaybeCreateLoaderFactory on each until the request is successfully
-// handled. The same sequence may be performed multiple times when
-// redirects happen.
+// URLLoader.  In order to get the right URLLoader it builds a vector
+// of URLLoaderRequestHandler's and successively calls MaybeCreateLoader
+// on each until the request is successfully handled. The same sequence
+// may be performed multiple times when redirects happen.
 class NavigationURLLoaderNetworkService::URLLoaderRequestController {
  public:
   URLLoaderRequestController(
@@ -143,35 +142,38 @@
     url_loader_request_ = std::move(url_loader_request);
     url_loader_client_ptr_ = std::move(url_loader_client_ptr);
     handler_index_ = 0;
-    MaybeStartLoader(nullptr);
+    MaybeStartLoader(StartLoaderCallback());
   }
 
-  void MaybeStartLoader(mojom::URLLoaderFactory* factory) {
+  void MaybeStartLoader(StartLoaderCallback start_loader_callback) {
     DCHECK(url_loader_client_ptr_.is_bound());
 
-    if (factory) {
-      factory->CreateLoaderAndStart(
-          std::move(url_loader_request_), 0 /* routing_id? */,
-          0 /* request_id? */, mojom::kURLLoadOptionSendSSLInfo,
-          *resource_request_, std::move(url_loader_client_ptr_));
+    if (start_loader_callback) {
+      std::move(start_loader_callback)
+          .Run(std::move(url_loader_request_),
+               std::move(url_loader_client_ptr_));
       return;
     }
 
     if (handler_index_ < handlers_.size()) {
-      handlers_[handler_index_++]->MaybeCreateLoaderFactory(
+      handlers_[handler_index_++]->MaybeCreateLoader(
           *resource_request_, resource_context_,
           base::BindOnce(&URLLoaderRequestController::MaybeStartLoader,
                          base::Unretained(this)));
       return;
     }
 
+    mojom::URLLoaderFactory* factory = nullptr;
     DCHECK_EQ(handlers_.size(), handler_index_);
     if (resource_request_->url.SchemeIs(url::kBlobScheme)) {
       factory = url_loader_factory_getter_->GetBlobFactory()->get();
     } else {
       factory = url_loader_factory_getter_->GetNetworkFactory()->get();
     }
-    MaybeStartLoader(factory);
+    factory->CreateLoaderAndStart(
+        std::move(url_loader_request_), 0 /* routing_id? */,
+        0 /* request_id? */, mojom::kURLLoadOptionSendSSLInfo,
+        *resource_request_, std::move(url_loader_client_ptr_));
   }
 
  private:
diff --git a/content/browser/loader/url_loader_request_handler.h b/content/browser/loader/url_loader_request_handler.h
index f72cc2a..d2b4684 100644
--- a/content/browser/loader/url_loader_request_handler.h
+++ b/content/browser/loader/url_loader_request_handler.h
@@ -5,17 +5,21 @@
 #ifndef CONTENT_BROWSER_LOADER_URL_LOADER_REQUEST_HANDLER_H_
 #define CONTENT_BROWSER_LOADER_URL_LOADER_REQUEST_HANDLER_H_
 
+#include <memory>
 #include "base/callback_forward.h"
 #include "base/macros.h"
-#include "content/common/url_loader_factory.mojom.h"
+#include "content/common/url_loader.mojom.h"
 
 namespace content {
 
 class ResourceContext;
 struct ResourceRequest;
 
-using LoaderFactoryCallback =
-    base::OnceCallback<void(mojom::URLLoaderFactory*)>;
+using StartLoaderCallback =
+    base::OnceCallback<void(mojom::URLLoaderAssociatedRequest request,
+                            mojom::URLLoaderClientPtr client)>;
+
+using LoaderCallback = base::OnceCallback<void(StartLoaderCallback)>;
 
 // An instance of this class is a per-request object and kept around during
 // the lifetime of a request (including multiple redirect legs) on IO thread.
@@ -24,21 +28,11 @@
   URLLoaderRequestHandler() = default;
   virtual ~URLLoaderRequestHandler() = default;
 
-  // Calls |callback| with non-null factory if this handler can handle
-  // the request, calls it with nullptr otherwise.
-  // Some implementation notes:
-  // 1) The returned pointer needs to be valid only until a single
-  // CreateLoaderAndStart call is made, and it is okay to do CHECK(false) for
-  // any subsequent calls.
-  // 2) The implementor is not supposed to set up and return URLLoaderFactory
-  // until it finds out that the handler is really going to handle the
-  // request. (For example ServiceWorker's request handler would not need to
-  // call the callback until it gets response from SW, and it may still
-  // call the callback with nullptr if it turns out that it needs to fallback
-  // to the network.)
-  virtual void MaybeCreateLoaderFactory(const ResourceRequest& resource_request,
-                                        ResourceContext* resource_context,
-                                        LoaderFactoryCallback callback) = 0;
+  // Calls |callback| with a non-null StartLoaderCallback if this handler
+  // can handle the request, calls it with null callback otherwise.
+  virtual void MaybeCreateLoader(const ResourceRequest& resource_request,
+                                 ResourceContext* resource_context,
+                                 LoaderCallback callback) = 0;
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 5dc4d9f..7c98454 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -61,6 +61,7 @@
 #include "content/browser/background_sync/background_sync_service_impl.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/blob_storage/blob_dispatcher_host.h"
+#include "content/browser/blob_storage/blob_url_loader_factory.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/broadcast_channel/broadcast_channel_provider.h"
 #include "content/browser/browser_child_process_host_impl.h"
@@ -948,6 +949,7 @@
       never_signaled_(base::WaitableEvent::ResetPolicy::MANUAL,
                       base::WaitableEvent::InitialState::NOT_SIGNALED),
 #endif
+      renderer_host_binding_(this),
       instance_weak_factory_(
           new base::WeakPtrFactory<RenderProcessHostImpl>(this)),
       frame_sink_provider_(id_),
@@ -1563,6 +1565,10 @@
       ->AddInterface(base::Bind(&RenderProcessHostImpl::BindRouteProvider,
                                 base::Unretained(this)));
 
+  AddUIThreadInterface(registry.get(),
+                       base::Bind(&RenderProcessHostImpl::CreateRendererHost,
+                                  base::Unretained(this)));
+
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableNetworkService)) {
     AddUIThreadInterface(
@@ -1606,6 +1612,17 @@
     listener->OnAssociatedInterfaceRequest(name, request.PassHandle());
 }
 
+void RenderProcessHostImpl::GetBlobURLLoaderFactory(
+    mojom::URLLoaderFactoryRequest request) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableNetworkService)) {
+    NOTREACHED();
+    return;
+  }
+  storage_partition_impl_->GetBlobURLLoaderFactory()->HandleRequest(
+      std::move(request));
+}
+
 void RenderProcessHostImpl::CreateMusGpuRequest(
     const service_manager::BindSourceInfo& source_info,
     ui::mojom::GpuRequest request) {
@@ -1643,6 +1660,12 @@
   }
 }
 
+void RenderProcessHostImpl::CreateRendererHost(
+    const service_manager::BindSourceInfo& source_info,
+    mojom::RendererHostRequest request) {
+  renderer_host_binding_.Bind(std::move(request));
+}
+
 void RenderProcessHostImpl::CreateURLLoaderFactory(
     const service_manager::BindSourceInfo& source_info,
     mojom::URLLoaderFactoryRequest request) {
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 871a6e8..9690094 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -33,6 +33,7 @@
 #include "content/common/indexed_db/indexed_db.mojom.h"
 #include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
 #include "content/common/renderer.mojom.h"
+#include "content/common/renderer_host.mojom.h"
 #include "content/common/storage_partition_service.mojom.h"
 #include "content/common/url_loader_factory.mojom.h"
 #include "content/public/browser/render_process_host.h"
@@ -110,7 +111,8 @@
       public ChildProcessLauncher::Client,
       public ui::GpuSwitchingObserver,
       public NON_EXPORTED_BASE(mojom::RouteProvider),
-      public NON_EXPORTED_BASE(mojom::AssociatedInterfaceProvider) {
+      public NON_EXPORTED_BASE(mojom::AssociatedInterfaceProvider),
+      public NON_EXPORTED_BASE(mojom::RendererHost) {
  public:
   RenderProcessHostImpl(BrowserContext* browser_context,
                         StoragePartitionImpl* storage_partition_impl,
@@ -383,6 +385,9 @@
       const std::string& name,
       mojom::AssociatedInterfaceAssociatedRequest request) override;
 
+  // mojom::RendererHost
+  void GetBlobURLLoaderFactory(mojom::URLLoaderFactoryRequest request) override;
+
   void BindRouteProvider(mojom::RouteProviderAssociatedRequest request);
 
   void CreateMusGpuRequest(const service_manager::BindSourceInfo& source_info,
@@ -395,6 +400,8 @@
   void CreateStoragePartitionService(
       const service_manager::BindSourceInfo& source_info,
       mojom::StoragePartitionServiceRequest request);
+  void CreateRendererHost(const service_manager::BindSourceInfo& source_info,
+                          mojom::RendererHostRequest request);
   void CreateURLLoaderFactory(
       const service_manager::BindSourceInfo& source_info,
       mojom::URLLoaderFactoryRequest request);
@@ -682,6 +689,7 @@
 
   mojom::RouteProviderAssociatedPtr remote_route_provider_;
   mojom::RendererAssociatedPtr renderer_interface_;
+  mojo::Binding<mojom::RendererHost> renderer_host_binding_;
 
   // Tracks active audio streams within the render process; used to determine if
   // if a process should be backgrounded.
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index fd15aa2..2af53da 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -159,10 +159,10 @@
   return job.release();
 }
 
-void ServiceWorkerControlleeRequestHandler::MaybeCreateLoaderFactory(
+void ServiceWorkerControlleeRequestHandler::MaybeCreateLoader(
     const ResourceRequest& resource_request,
     ResourceContext* resource_context,
-    base::OnceCallback<void(mojom::URLLoaderFactory*)> factory_callback) {
+    LoaderCallback callback) {
   DCHECK(is_main_resource_load_);
   ClearJob();
 
@@ -171,7 +171,7 @@
 
   if (!context_ || !provider_host_) {
     // We can't do anything other than to fall back to network.
-    std::move(factory_callback).Run(nullptr);
+    std::move(callback).Run(StartLoaderCallback());
     return;
   }
 
@@ -180,8 +180,7 @@
   DCHECK(!use_network_);
 
   url_job_ = base::MakeUnique<ServiceWorkerURLJobWrapper>(
-      std::move(factory_callback), this, resource_request,
-      blob_storage_context_);
+      std::move(callback), this, resource_request, blob_storage_context_);
 
   resource_context_ = resource_context;
 
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.h b/content/browser/service_worker/service_worker_controllee_request_handler.h
index ee78639..e3bb52d 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.h
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -68,10 +68,9 @@
   // cases. (In fallback-to-network cases we basically forward the request
   // to the request to the next request handler)
   // URLLoaderRequestHandler overrides:
-  void MaybeCreateLoaderFactory(
-      const ResourceRequest& request,
-      ResourceContext* resource_context,
-      base::OnceCallback<void(mojom::URLLoaderFactory*)> callback) override;
+  void MaybeCreateLoader(const ResourceRequest& request,
+                         ResourceContext* resource_context,
+                         LoaderCallback callback) override;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerControlleeRequestHandlerTest,
diff --git a/content/browser/service_worker/service_worker_request_handler.cc b/content/browser/service_worker/service_worker_request_handler.cc
index b1240cf..f27f2420 100644
--- a/content/browser/service_worker/service_worker_request_handler.cc
+++ b/content/browser/service_worker/service_worker_request_handler.cc
@@ -237,12 +237,12 @@
   return handler ? handler->provider_host_.get() : nullptr;
 }
 
-void ServiceWorkerRequestHandler::MaybeCreateLoaderFactory(
+void ServiceWorkerRequestHandler::MaybeCreateLoader(
     const ResourceRequest& request,
     ResourceContext* resource_context,
-    LoaderFactoryCallback callback) {
+    LoaderCallback callback) {
   NOTREACHED();
-  std::move(callback).Run(nullptr);
+  std::move(callback).Run(StartLoaderCallback());
 }
 
 void ServiceWorkerRequestHandler::PrepareForCrossSiteTransfer(
diff --git a/content/browser/service_worker/service_worker_request_handler.h b/content/browser/service_worker/service_worker_request_handler.h
index b6adb61..d193eee5 100644
--- a/content/browser/service_worker/service_worker_request_handler.h
+++ b/content/browser/service_worker/service_worker_request_handler.h
@@ -129,9 +129,9 @@
       ResourceContext* context) = 0;
 
   // URLLoaderRequestHandler overrides.
-  void MaybeCreateLoaderFactory(const ResourceRequest& request,
-                                ResourceContext* resource_context,
-                                LoaderFactoryCallback callback) override;
+  void MaybeCreateLoader(const ResourceRequest& request,
+                         ResourceContext* resource_context,
+                         LoaderCallback callback) override;
 
   // Methods to support cross site navigations.
   void PrepareForCrossSiteTransfer(int old_process_id);
diff --git a/content/browser/service_worker/service_worker_url_job_wrapper.cc b/content/browser/service_worker/service_worker_url_job_wrapper.cc
index 57ec426..342a01e 100644
--- a/content/browser/service_worker/service_worker_url_job_wrapper.cc
+++ b/content/browser/service_worker/service_worker_url_job_wrapper.cc
@@ -22,6 +22,19 @@
 
 class URLLoaderImpl : public mojom::URLLoader {
  public:
+  static void Start(
+      const ServiceWorkerResponse& response,
+      blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
+      base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+      mojom::URLLoaderAssociatedRequest request,
+      mojom::URLLoaderClientPtr client) {
+    mojo::MakeStrongAssociatedBinding(
+        base::MakeUnique<URLLoaderImpl>(response, std::move(body_as_stream),
+                                        blob_storage_context,
+                                        std::move(client)),
+        std::move(request));
+  }
+
   URLLoaderImpl(const ServiceWorkerResponse& response,
                 blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
                 base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
@@ -102,46 +115,6 @@
 
 }  // namespace
 
-class ServiceWorkerURLJobWrapper::Factory : public mojom::URLLoaderFactory {
- public:
-  Factory(const ServiceWorkerResponse& response,
-          blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
-          base::WeakPtr<storage::BlobStorageContext> blob_storage_context)
-      : response_(response),
-        body_as_stream_(std::move(body_as_stream)),
-        blob_storage_context_(blob_storage_context) {}
-
-  void CreateLoaderAndStart(mojom::URLLoaderAssociatedRequest request,
-                            int32_t routing_id,
-                            int32_t request_id,
-                            uint32_t options,
-                            const ResourceRequest& url_request,
-                            mojom::URLLoaderClientPtr client) override {
-    // Note that url_request is ignored here, as we've already processed the
-    // fetch before even creating the factory.
-    // TODO(scottmg): Use options.
-    mojo::MakeStrongAssociatedBinding(
-        base::MakeUnique<URLLoaderImpl>(response_, std::move(body_as_stream_),
-                                        blob_storage_context_,
-                                        std::move(client)),
-        std::move(request));
-  }
-
-  void SyncLoad(int32_t routing_id,
-                int32_t request_id,
-                const ResourceRequest& url_request,
-                SyncLoadCallback callback) override {
-    NOTREACHED();
-  }
-
- private:
-  ServiceWorkerResponse response_;
-  blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream_;
-  base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
-
-  DISALLOW_COPY_AND_ASSIGN(Factory);
-};
-
 ServiceWorkerURLJobWrapper::ServiceWorkerURLJobWrapper(
     base::WeakPtr<ServiceWorkerURLRequestJob> url_request_job)
     : job_type_(JobType::kURLRequest),
@@ -149,12 +122,12 @@
       weak_factory_(this) {}
 
 ServiceWorkerURLJobWrapper::ServiceWorkerURLJobWrapper(
-    LoaderFactoryCallback callback,
+    LoaderCallback callback,
     Delegate* delegate,
     const ResourceRequest& resource_request,
     base::WeakPtr<storage::BlobStorageContext> blob_storage_context)
     : job_type_(JobType::kURLLoader),
-      loader_factory_callback_(std::move(callback)),
+      loader_callback_(std::move(callback)),
       delegate_(delegate),
       resource_request_(resource_request),
       blob_storage_context_(blob_storage_context),
@@ -173,8 +146,8 @@
     // call this synchronously here and don't wait for a separate async
     // StartRequest cue like what URLRequestJob case does.
     // TODO(kinuko): Make sure this is ok or we need to make this async.
-    if (!loader_factory_callback_.is_null()) {
-      std::move(loader_factory_callback_).Run(nullptr);
+    if (!loader_callback_.is_null()) {
+      std::move(loader_callback_).Run(StartLoaderCallback());
     }
   } else {
     url_request_job_->FallbackToNetwork();
@@ -240,7 +213,7 @@
 
 bool ServiceWorkerURLJobWrapper::WasCanceled() const {
   if (job_type_ == JobType::kURLLoader) {
-    return loader_factory_callback_.is_null();
+    return loader_callback_.is_null();
   } else {
     return !url_request_job_;
   }
@@ -302,14 +275,14 @@
     blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
     const scoped_refptr<ServiceWorkerVersion>& version) {
   if (fetch_result == SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK) {
-    std::move(loader_factory_callback_).Run(nullptr);
+    std::move(loader_callback_).Run(StartLoaderCallback());
     return;
   }
   DCHECK_EQ(fetch_result, SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE);
-
-  factory_ = base::MakeUnique<Factory>(response, std::move(body_as_stream),
-                                       blob_storage_context_);
-  std::move(loader_factory_callback_).Run(factory_.get());
+  std::move(loader_callback_)
+      .Run(base::Bind(&URLLoaderImpl::Start, response,
+                      base::Passed(std::move(body_as_stream)),
+                      blob_storage_context_));
 }
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_url_job_wrapper.h b/content/browser/service_worker/service_worker_url_job_wrapper.h
index e090cd1..891d13d 100644
--- a/content/browser/service_worker/service_worker_url_job_wrapper.h
+++ b/content/browser/service_worker/service_worker_url_job_wrapper.h
@@ -17,9 +17,9 @@
 
 // This class is a helper to support having
 // ServiceWorkerControlleeRequestHandler work with both URLRequestJobs and
-// mojom::URLLoaderFactorys (that is, both with and without
-// --enable-network-service). It wraps either a ServiceWorkerURLRequestJob or a
-// callback for URLLoaderFactory and forwards to the underlying implementation.
+// mojom::URLLoaders (that is, both with and without --enable-network-service).
+// It wraps either a ServiceWorkerURLRequestJob or a callback for
+// URLLoader and forwards to the underlying implementation.
 class ServiceWorkerURLJobWrapper {
  public:
   class Delegate {
@@ -38,7 +38,7 @@
   // TODO(kinuko): Implement this as a separate job class rather
   // than in a wrapper.
   ServiceWorkerURLJobWrapper(
-      LoaderFactoryCallback loader_factory_callback,
+      LoaderCallback loader_callback,
       Delegate* delegate,
       const ResourceRequest& resource_request,
       base::WeakPtr<storage::BlobStorageContext> blob_storage_context);
@@ -75,7 +75,6 @@
 
   // Used only for URLLoader case.
   // For FORWARD_TO_SERVICE_WORKER case.
-  class Factory;
   void StartRequest();
 
   void DidPrepareFetchEvent(scoped_refptr<ServiceWorkerVersion> version);
@@ -94,12 +93,11 @@
   JobType job_type_;
 
   ServiceWorkerResponseType response_type_ = NOT_DETERMINED;
-  LoaderFactoryCallback loader_factory_callback_;
+  LoaderCallback loader_callback_;
 
   base::WeakPtr<ServiceWorkerURLRequestJob> url_request_job_;
 
   Delegate* delegate_;
-  std::unique_ptr<Factory> factory_;
   ResourceRequest resource_request_;
   base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
   std::unique_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index f5c6e52..ca3cffe 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -50,7 +50,7 @@
 #if defined(OS_CHROMEOS)
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon_client.h"
-#include "content/browser/tracing/arc_tracing_agent.h"
+#include "content/public/browser/arc_tracing_agent.h"
 #endif
 
 #if defined(OS_WIN)
diff --git a/content/browser/url_loader_factory_getter.cc b/content/browser/url_loader_factory_getter.cc
index 9f16c054..4cf6d39 100644
--- a/content/browser/url_loader_factory_getter.cc
+++ b/content/browser/url_loader_factory_getter.cc
@@ -18,8 +18,9 @@
   partition->network_context()->CreateURLLoaderFactory(
       MakeRequest(&network_factory), 0);
 
-  mojom::URLLoaderFactoryPtr blob_factory =
-      partition->GetBlobURLLoaderFactory()->CreateFactory();
+  mojom::URLLoaderFactoryPtr blob_factory;
+  partition->GetBlobURLLoaderFactory()->HandleRequest(
+      mojo::MakeRequest(&blob_factory));
 
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 5a37ace..ac802f9 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -620,6 +620,7 @@
     "render_message_filter.mojom",
     "render_widget_window_tree_client_factory.mojom",
     "renderer.mojom",
+    "renderer_host.mojom",
     "service_worker/embedded_worker.mojom",
     "service_worker/service_worker.mojom",
     "service_worker/service_worker_event_dispatcher.mojom",
diff --git a/content/common/renderer_host.mojom b/content/common/renderer_host.mojom
new file mode 100644
index 0000000..b2a271a5
--- /dev/null
+++ b/content/common/renderer_host.mojom
@@ -0,0 +1,14 @@
+// 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.
+
+module content.mojom;
+
+import "content/common/url_loader_factory.mojom";
+
+// The primordial interface implemented by a render process host. This should be
+// used for implementing renderer-to-browser messages.
+interface RendererHost {
+  // Requests a URLLoaderFactory for the blob scheme.
+  GetBlobURLLoaderFactory(URLLoaderFactory& loader);
+};
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 4128f75..95311487 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -27,9 +27,10 @@
           "blink::mojom::PermissionService",
           "blink::mojom::WebSocket",
           "content::mojom::FieldTrialRecorder",
+          "content::mojom::FrameSinkProvider",
           "content::mojom::MemoryCoordinatorHandle",
           "content::mojom::PushMessaging",
-          "content::mojom::FrameSinkProvider",
+          "content::mojom::RendererHost",
           "content::mojom::ServiceWorkerDispatcherHost",
           "content::mojom::StoragePartitionService",
           "content::mojom::URLLoaderFactory",
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index 976f5d3..31b35c1 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -346,4 +346,11 @@
       "zoom_level_delegate.h",
     ]
   }
+
+  if (is_chromeos) {
+    sources += [
+      "arc_tracing_agent.cc",
+      "arc_tracing_agent.h",
+    ]
+  }
 }
diff --git a/content/browser/tracing/arc_tracing_agent.cc b/content/public/browser/arc_tracing_agent.cc
similarity index 98%
rename from content/browser/tracing/arc_tracing_agent.cc
rename to content/public/browser/arc_tracing_agent.cc
index 0df2e2cc..8a2d1dd 100644
--- a/content/browser/tracing/arc_tracing_agent.cc
+++ b/content/public/browser/arc_tracing_agent.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/tracing/arc_tracing_agent.h"
+#include "content/public/browser/arc_tracing_agent.h"
 
 #include <memory>
 #include <string>
diff --git a/content/browser/tracing/arc_tracing_agent.h b/content/public/browser/arc_tracing_agent.h
similarity index 91%
rename from content/browser/tracing/arc_tracing_agent.h
rename to content/public/browser/arc_tracing_agent.h
index 297a74c..2607ee81 100644
--- a/content/browser/tracing/arc_tracing_agent.h
+++ b/content/public/browser/arc_tracing_agent.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_TRACING_ARC_TRACING_AGENT_H_
-#define CONTENT_BROWSER_TRACING_ARC_TRACING_AGENT_H_
+#ifndef CONTENT_PUBLIC_BROWSER_ARC_TRACING_AGENT_H_
+#define CONTENT_PUBLIC_BROWSER_ARC_TRACING_AGENT_H_
 
 #include "base/callback_forward.h"
 #include "base/files/scoped_file.h"
@@ -57,4 +57,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_TRACING_ARC_TRACING_AGENT_H_
+#endif  // CONTENT_PUBLIC_BROWSER_ARC_TRACING_AGENT_H_
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 98d81103..c36999d9 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4317,7 +4317,18 @@
     }
   }
 
-  extra_data->set_url_loader_factory_override(url_loader_factory_.get());
+  // TODO: generalize how non-network schemes are sent to the renderer and used.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableNetworkService)) {
+    if (request.Url().ProtocolIs(url::kBlobScheme)) {
+      extra_data->set_url_loader_factory_override(
+          RenderThreadImpl::current()->GetBlobURLLoaderFactory());
+    }
+  }
+
+  if (!extra_data->url_loader_factory_override())
+    extra_data->set_url_loader_factory_override(url_loader_factory_.get());
+
   // TODO(kinuko, yzshen): We need to set up throttles for some worker cases
   // that don't go through here.
   extra_data->set_url_loader_throttles(std::move(throttles));
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index fe54aff..6733690 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1084,6 +1084,22 @@
   return storage_partition_service_.get();
 }
 
+mojom::RendererHost* RenderThreadImpl::GetRendererHost() {
+  if (!renderer_host_) {
+    GetConnector()->BindInterface(mojom::kBrowserServiceName,
+                                  mojo::MakeRequest(&renderer_host_));
+  }
+  return renderer_host_.get();
+}
+
+mojom::URLLoaderFactory* RenderThreadImpl::GetBlobURLLoaderFactory() {
+  if (!blob_url_loader_factory_) {
+    GetRendererHost()->GetBlobURLLoaderFactory(
+        mojo::MakeRequest(&blob_url_loader_factory_));
+  }
+  return blob_url_loader_factory_.get();
+}
+
 int RenderThreadImpl::GenerateRoutingID() {
   int32_t routing_id = MSG_ROUTING_NONE;
   render_message_filter()->GenerateRoutingID(&routing_id);
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index ecf995c..7c12d95 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -40,7 +40,9 @@
 #include "content/common/render_frame_message_filter.mojom.h"
 #include "content/common/render_message_filter.mojom.h"
 #include "content/common/renderer.mojom.h"
+#include "content/common/renderer_host.mojom.h"
 #include "content/common/storage_partition_service.mojom.h"
+#include "content/common/url_loader_factory.mojom.h"
 #include "content/public/renderer/render_thread.h"
 #include "content/renderer/gpu/compositor_dependencies.h"
 #include "content/renderer/layout_test_dependencies.h"
@@ -489,6 +491,8 @@
       mojom::FrameHostInterfaceBrokerPtr host);
 
   mojom::StoragePartitionService* GetStoragePartitionService();
+  mojom::RendererHost* GetRendererHost();
+  mojom::URLLoaderFactory* GetBlobURLLoaderFactory();
 
   // ChildMemoryCoordinatorDelegate implementation.
   void OnTrimMemoryImmediately() override;
@@ -783,6 +787,8 @@
   PendingFrameCreateMap pending_frame_creates_;
 
   mojom::StoragePartitionServicePtr storage_partition_service_;
+  mojom::RendererHostPtr renderer_host_;
+  mojom::URLLoaderFactoryPtr blob_url_loader_factory_;
 
   AssociatedInterfaceRegistryImpl associated_interfaces_;
 
diff --git a/ios/chrome/browser/browsing_data/BUILD.gn b/ios/chrome/browser/browsing_data/BUILD.gn
index eb4b15e..ee16ec9d 100644
--- a/ios/chrome/browser/browsing_data/BUILD.gn
+++ b/ios/chrome/browser/browsing_data/BUILD.gn
@@ -27,6 +27,7 @@
     "//components/password_manager/core/browser",
     "//components/prefs",
     "//components/sessions",
+    "//components/translate/core/browser:browser",
     "//ios/chrome/browser",
     "//ios/chrome/browser/autofill",
     "//ios/chrome/browser/browser_state",
@@ -37,6 +38,7 @@
     "//ios/chrome/browser/sessions:serialisation",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/translate:translate",
     "//ios/net",
     "//ios/public/provider/chrome/browser",
     "//ios/web",
diff --git a/ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.mm b/ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.mm
index 1600961..a9f0d06 100644
--- a/ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.mm
+++ b/ios/chrome/browser/browsing_data/ios_chrome_browsing_data_remover.mm
@@ -24,6 +24,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/sessions/core/tab_restore_service.h"
+#include "components/translate/core/browser/language_model.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
@@ -33,6 +34,7 @@
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h"
+#include "ios/chrome/browser/translate/language_model_factory.h"
 #include "ios/chrome/browser/web_data_service_factory.h"
 #include "ios/net/http_cache_helper.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
@@ -245,6 +247,12 @@
         data_manager->Refresh();
     }
 
+    // Remove language model history.
+    translate::LanguageModel* language_model =
+        LanguageModelFactory::GetForBrowserState(browser_state_);
+    if (language_model) {
+      language_model->ClearHistory(delete_begin_, delete_end_);
+    }
   }
 
   if (remove_mask & REMOVE_COOKIES) {
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index 3cda610..6539c99 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -32,6 +32,7 @@
 #include "components/ssl_config/ssl_config_service_manager.h"
 #include "components/strings/grit/components_locale_settings.h"
 #include "components/sync/base/sync_prefs.h"
+#include "components/translate/core/browser/language_model.h"
 #include "components/translate/core/browser/translate_pref_names.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/update_client/update_client.h"
@@ -113,6 +114,7 @@
   PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry);
   syncer::SyncPrefs::RegisterProfilePrefs(registry);
   TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
+  translate::LanguageModel::RegisterProfilePrefs(registry);
   translate::TranslatePrefs::RegisterProfilePrefs(registry);
   variations::VariationsService::RegisterProfilePrefs(registry);
   ZeroSuggestProvider::RegisterProfilePrefs(registry);
diff --git a/ios/chrome/browser/translate/BUILD.gn b/ios/chrome/browser/translate/BUILD.gn
index 8f70c26..abc6ff6 100644
--- a/ios/chrome/browser/translate/BUILD.gn
+++ b/ios/chrome/browser/translate/BUILD.gn
@@ -10,6 +10,8 @@
     "before_translate_infobar_controller.mm",
     "chrome_ios_translate_client.h",
     "chrome_ios_translate_client.mm",
+    "language_model_factory.cc",
+    "language_model_factory.h",
     "never_translate_infobar_controller.h",
     "never_translate_infobar_controller.mm",
     "translate_accept_languages_factory.cc",
@@ -48,6 +50,7 @@
     "//ui/gfx",
     "//url",
   ]
+
   allow_circular_includes_from = [ "//ios/chrome/browser/infobars" ]
 }
 
@@ -56,6 +59,7 @@
   testonly = true
   sources = [
     "js_language_detection_manager_unittest.mm",
+    "language_model_factory_unittest.cc",
     "translate_service_ios_unittest.cc",
   ]
   deps = [
@@ -64,11 +68,13 @@
     "//base/test:test_support",
     "//components/translate/ios/browser",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/browser/web:test_support",
     "//ios/chrome/common",
     "//ios/public/provider/chrome/browser:test_support",
     "//ios/web",
     "//ios/web/public/test",
+    "//testing/gmock:gmock",
     "//testing/gtest",
     "//url",
   ]
diff --git a/ios/chrome/browser/translate/chrome_ios_translate_client.mm b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
index 85b3d34..b474a280 100644
--- a/ios/chrome/browser/translate/chrome_ios_translate_client.mm
+++ b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
@@ -24,6 +24,7 @@
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/translate/after_translate_infobar_controller.h"
 #import "ios/chrome/browser/translate/before_translate_infobar_controller.h"
+#include "ios/chrome/browser/translate/language_model_factory.h"
 #import "ios/chrome/browser/translate/never_translate_infobar_controller.h"
 #include "ios/chrome/browser/translate/translate_accept_languages_factory.h"
 #import "ios/chrome/browser/translate/translate_message_infobar_controller.h"
@@ -46,7 +47,10 @@
           prefs::kAcceptLanguages)),
       translate_driver_(web_state,
                         web_state->GetNavigationManager(),
-                        translate_manager_.get()) {}
+                        translate_manager_.get(),
+                        LanguageModelFactory::GetForBrowserState(
+                            ios::ChromeBrowserState::FromBrowserState(
+                                web_state->GetBrowserState()))) {}
 
 ChromeIOSTranslateClient::~ChromeIOSTranslateClient() {
 }
diff --git a/ios/chrome/browser/translate/language_model_factory.cc b/ios/chrome/browser/translate/language_model_factory.cc
new file mode 100644
index 0000000..45b3ec28
--- /dev/null
+++ b/ios/chrome/browser/translate/language_model_factory.cc
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/translate/language_model_factory.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/translate/core/browser/language_model.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+
+// static
+LanguageModelFactory* LanguageModelFactory::GetInstance() {
+  return base::Singleton<LanguageModelFactory>::get();
+}
+
+// static
+translate::LanguageModel* LanguageModelFactory::GetForBrowserState(
+    ios::ChromeBrowserState* const state) {
+  return static_cast<translate::LanguageModel*>(
+      GetInstance()->GetServiceForBrowserState(state, true));
+}
+
+LanguageModelFactory::LanguageModelFactory()
+    : BrowserStateKeyedServiceFactory(
+          "LanguageModel",
+          BrowserStateDependencyManager::GetInstance()) {}
+
+LanguageModelFactory::~LanguageModelFactory() {}
+
+std::unique_ptr<KeyedService> LanguageModelFactory::BuildServiceInstanceFor(
+    web::BrowserState* context) const {
+  ios::ChromeBrowserState* browser_state =
+      ios::ChromeBrowserState::FromBrowserState(context);
+  return base::MakeUnique<translate::LanguageModel>(browser_state->GetPrefs());
+}
diff --git a/ios/chrome/browser/translate/language_model_factory.h b/ios/chrome/browser/translate/language_model_factory.h
new file mode 100644
index 0000000..a128a98
--- /dev/null
+++ b/ios/chrome/browser/translate/language_model_factory.h
@@ -0,0 +1,41 @@
+// 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_CHROME_BROWSER_TRANSLATE_LANGUAGE_MODEL_FACTORY_H
+#define IOS_CHROME_BROWSER_TRANSLATE_LANGUAGE_MODEL_FACTORY_H
+
+#include <memory>
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+namespace ios {
+class ChromeBrowserState;
+}
+
+namespace translate {
+class LanguageModel;
+}
+
+class LanguageModelFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  static LanguageModelFactory* GetInstance();
+  static translate::LanguageModel* GetForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+
+ private:
+  friend struct base::DefaultSingletonTraits<LanguageModelFactory>;
+
+  LanguageModelFactory();
+  ~LanguageModelFactory() override;
+
+  // BrowserStateKeyedServiceFactory implementation.
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(LanguageModelFactory);
+};
+
+#endif  // IOS_CHROME_BROWSER_TRANSLATE_LANGUAGE_MODEL_FACTORY_H
diff --git a/ios/chrome/browser/translate/language_model_factory_unittest.cc b/ios/chrome/browser/translate/language_model_factory_unittest.cc
new file mode 100644
index 0000000..a5b84cd
--- /dev/null
+++ b/ios/chrome/browser/translate/language_model_factory_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/translate/language_model_factory.h"
+
+#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#include "ios/web/public/test/test_web_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::IsNull;
+using testing::Not;
+
+class LanguageModelFactoryTest : public testing::Test {
+ public:
+  LanguageModelFactoryTest() {
+    TestChromeBrowserState::Builder browser_state_builder;
+    chrome_browser_state_ = browser_state_builder.Build();
+  }
+
+  ~LanguageModelFactoryTest() override { chrome_browser_state_.reset(); }
+
+  ios::ChromeBrowserState* chrome_browser_state() {
+    return chrome_browser_state_.get();
+  }
+
+ private:
+  web::TestWebThreadBundle thread_bundle_;
+  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
+};
+
+TEST_F(LanguageModelFactoryTest, NotCreatedInIncognito) {
+  EXPECT_THAT(LanguageModelFactory::GetForBrowserState(chrome_browser_state()),
+              Not(IsNull()));
+
+  ios::ChromeBrowserState* otr_browser_state =
+      chrome_browser_state()->GetOffTheRecordChromeBrowserState();
+  translate::LanguageModel* language_model =
+      LanguageModelFactory::GetForBrowserState(otr_browser_state);
+  EXPECT_THAT(language_model, IsNull());
+}
diff --git a/ios/chrome/browser/ui/ntp/google_landing_mediator.mm b/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
index 47ae5c4..46028db3 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
+++ b/ios/chrome/browser/ui/ntp/google_landing_mediator.mm
@@ -383,11 +383,7 @@
 #pragma mark - Private
 
 - (void)useFreshData {
-  if (self.freshMostVisitedData.size() == 0) {
-    return;
-  }
   _mostVisitedData = self.freshMostVisitedData;
-  self.freshMostVisitedData.clear();
   [self.consumer mostVisitedDataUpdated];
 }
 
diff --git a/ios/web_view/internal/translate/web_view_translate_client.mm b/ios/web_view/internal/translate/web_view_translate_client.mm
index 20af5637..ddc9bed 100644
--- a/ios/web_view/internal/translate/web_view_translate_client.mm
+++ b/ios/web_view/internal/translate/web_view_translate_client.mm
@@ -34,6 +34,9 @@
 
 namespace ios_web_view {
 
+// TODO(crbug.com/729859): Support logging histogram data on detected language
+// page, by passing a valid language_model, when histogram logging is available
+// on ios/web_view.
 WebViewTranslateClient::WebViewTranslateClient(web::WebState* web_state)
     : web::WebStateObserver(web_state),
       translate_manager_(base::MakeUnique<translate::TranslateManager>(
@@ -44,7 +47,8 @@
           prefs::kAcceptLanguages)),
       translate_driver_(web_state,
                         web_state->GetNavigationManager(),
-                        translate_manager_.get()) {}
+                        translate_manager_.get(),
+                        nullptr /* language_model */) {}
 
 WebViewTranslateClient::~WebViewTranslateClient() = default;
 
diff --git a/mojo/edk/js/tests/BUILD.gn b/mojo/edk/js/tests/BUILD.gn
index 21c9bfc4..b3b87392 100644
--- a/mojo/edk/js/tests/BUILD.gn
+++ b/mojo/edk/js/tests/BUILD.gn
@@ -15,44 +15,10 @@
 group("tests") {
   testonly = true
   deps = [
-    ":mojo_js_integration_tests",
     ":mojo_js_unittests",
   ]
 }
 
-test("mojo_js_integration_tests") {
-  deps = [
-    ":js_to_cpp_bindings",
-    "//base/test:test_support",
-    "//gin:gin_test",
-    "//mojo/common",
-    "//mojo/edk/js",
-    "//mojo/edk/test:run_all_unittests",
-    "//mojo/public/cpp/bindings",
-    "//mojo/public/cpp/system",
-    "//mojo/public/js:bindings",
-  ]
-
-  sources = [
-    "js_to_cpp_tests.cc",
-  ]
-
-  data = [
-    "js_to_cpp_tests.js",
-  ]
-
-  configs += [ "//v8:external_startup_data" ]
-}
-
-mojom("js_to_cpp_bindings") {
-  sources = [
-    "js_to_cpp.mojom",
-  ]
-
-  # TODO(crbug.com/699569): Convert to use the new JS bindings.
-  use_new_js_bindings = false
-}
-
 test("mojo_js_unittests") {
   deps = [
     "//base",
diff --git a/mojo/edk/js/tests/js_to_cpp_tests.cc b/mojo/edk/js/tests/js_to_cpp_tests.cc
deleted file mode 100644
index d193ffc..0000000
--- a/mojo/edk/js/tests/js_to_cpp_tests.cc
+++ /dev/null
@@ -1,459 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-#include <utility>
-
-#include "base/at_exit.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_task_environment.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "gin/array_buffer.h"
-#include "gin/public/isolate_holder.h"
-#include "gin/v8_initializer.h"
-#include "mojo/common/data_pipe_utils.h"
-#include "mojo/edk/js/mojo_runner_delegate.h"
-#include "mojo/edk/js/tests/js_to_cpp.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/lib/validation_errors.h"
-#include "mojo/public/cpp/system/core.h"
-#include "mojo/public/cpp/system/wait.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-// Global value updated by some checks to prevent compilers from optimizing
-// reads out of existence.
-uint32_t g_waste_accumulator = 0;
-
-namespace {
-
-// Negative numbers with different values in each byte, the last of
-// which can survive promotion to double and back.
-const int8_t kExpectedInt8Value = -65;
-const int16_t kExpectedInt16Value = -16961;
-const int32_t kExpectedInt32Value = -1145258561;
-const int64_t kExpectedInt64Value = -77263311946305LL;
-
-// Positive numbers with different values in each byte, the last of
-// which can survive promotion to double and back.
-const uint8_t kExpectedUInt8Value = 65;
-const uint16_t kExpectedUInt16Value = 16961;
-const uint32_t kExpectedUInt32Value = 1145258561;
-const uint64_t kExpectedUInt64Value = 77263311946305LL;
-
-// Double/float values, including special case constants.
-const double kExpectedDoubleVal = 3.14159265358979323846;
-const double kExpectedDoubleInf = std::numeric_limits<double>::infinity();
-const double kExpectedDoubleNan = std::numeric_limits<double>::quiet_NaN();
-const float kExpectedFloatVal = static_cast<float>(kExpectedDoubleVal);
-const float kExpectedFloatInf = std::numeric_limits<float>::infinity();
-const float kExpectedFloatNan = std::numeric_limits<float>::quiet_NaN();
-
-// NaN has the property that it is not equal to itself.
-#define EXPECT_NAN(x) EXPECT_NE(x, x)
-
-void CheckDataPipe(ScopedDataPipeConsumerHandle data_pipe_handle) {
-  std::string buffer;
-  bool result = common::BlockingCopyToString(std::move(data_pipe_handle),
-                                             &buffer);
-  EXPECT_TRUE(result);
-  EXPECT_EQ(64u, buffer.size());
-  for (int i = 0; i < 64; ++i) {
-    EXPECT_EQ(i, buffer[i]);
-  }
-}
-
-void CheckMessagePipe(MessagePipeHandle message_pipe_handle) {
-  unsigned char buffer[100];
-  uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
-  MojoResult result = Wait(message_pipe_handle, MOJO_HANDLE_SIGNAL_READABLE);
-  EXPECT_EQ(MOJO_RESULT_OK, result);
-  result = ReadMessageRaw(
-      message_pipe_handle, buffer, &buffer_size, 0, 0, 0);
-  EXPECT_EQ(MOJO_RESULT_OK, result);
-  EXPECT_EQ(64u, buffer_size);
-  for (int i = 0; i < 64; ++i) {
-    EXPECT_EQ(255 - i, buffer[i]);
-  }
-}
-
-js_to_cpp::EchoArgsPtr BuildSampleEchoArgs() {
-  js_to_cpp::EchoArgsPtr args(js_to_cpp::EchoArgs::New());
-  args->si64 = kExpectedInt64Value;
-  args->si32 = kExpectedInt32Value;
-  args->si16 = kExpectedInt16Value;
-  args->si8 = kExpectedInt8Value;
-  args->ui64 = kExpectedUInt64Value;
-  args->ui32 = kExpectedUInt32Value;
-  args->ui16 = kExpectedUInt16Value;
-  args->ui8 = kExpectedUInt8Value;
-  args->float_val = kExpectedFloatVal;
-  args->float_inf = kExpectedFloatInf;
-  args->float_nan = kExpectedFloatNan;
-  args->double_val = kExpectedDoubleVal;
-  args->double_inf = kExpectedDoubleInf;
-  args->double_nan = kExpectedDoubleNan;
-  args->name.emplace("coming");
-  args->string_array.emplace(3);
-  (*args->string_array)[0] = "one";
-  (*args->string_array)[1] = "two";
-  (*args->string_array)[2] = "three";
-  return args;
-}
-
-void CheckSampleEchoArgs(js_to_cpp::EchoArgsPtr arg) {
-  EXPECT_EQ(kExpectedInt64Value, arg->si64);
-  EXPECT_EQ(kExpectedInt32Value, arg->si32);
-  EXPECT_EQ(kExpectedInt16Value, arg->si16);
-  EXPECT_EQ(kExpectedInt8Value, arg->si8);
-  EXPECT_EQ(kExpectedUInt64Value, arg->ui64);
-  EXPECT_EQ(kExpectedUInt32Value, arg->ui32);
-  EXPECT_EQ(kExpectedUInt16Value, arg->ui16);
-  EXPECT_EQ(kExpectedUInt8Value, arg->ui8);
-  EXPECT_EQ(kExpectedFloatVal, arg->float_val);
-  EXPECT_EQ(kExpectedFloatInf, arg->float_inf);
-  EXPECT_NAN(arg->float_nan);
-  EXPECT_EQ(kExpectedDoubleVal, arg->double_val);
-  EXPECT_EQ(kExpectedDoubleInf, arg->double_inf);
-  EXPECT_NAN(arg->double_nan);
-  EXPECT_EQ(std::string("coming"), *arg->name);
-  EXPECT_EQ(std::string("one"), (*arg->string_array)[0]);
-  EXPECT_EQ(std::string("two"), (*arg->string_array)[1]);
-  EXPECT_EQ(std::string("three"), (*arg->string_array)[2]);
-  CheckDataPipe(std::move(arg->data_handle));
-  CheckMessagePipe(arg->message_handle.get());
-}
-
-void CheckSampleEchoArgsList(const js_to_cpp::EchoArgsListPtr& list) {
-  if (list.is_null())
-    return;
-  CheckSampleEchoArgs(std::move(list->item));
-  CheckSampleEchoArgsList(list->next);
-}
-
-// More forgiving checks are needed in the face of potentially corrupt
-// messages. The values don't matter so long as all accesses are within
-// bounds.
-void CheckCorruptedString(const std::string& arg) {
-  for (size_t i = 0; i < arg.size(); ++i)
-    g_waste_accumulator += arg[i];
-}
-
-void CheckCorruptedString(const base::Optional<std::string>& arg) {
-  if (!arg)
-    return;
-  CheckCorruptedString(*arg);
-}
-
-void CheckCorruptedStringArray(
-    const base::Optional<std::vector<std::string>>& string_array) {
-  if (!string_array)
-    return;
-  for (size_t i = 0; i < string_array->size(); ++i)
-    CheckCorruptedString((*string_array)[i]);
-}
-
-void CheckCorruptedDataPipe(MojoHandle data_pipe_handle) {
-  unsigned char buffer[100];
-  uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
-  MojoResult result = MojoReadData(
-      data_pipe_handle, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE);
-  if (result != MOJO_RESULT_OK)
-    return;
-  for (uint32_t i = 0; i < buffer_size; ++i)
-    g_waste_accumulator += buffer[i];
-}
-
-void CheckCorruptedMessagePipe(MojoHandle message_pipe_handle) {
-  unsigned char buffer[100];
-  uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
-  MojoResult result = MojoReadMessage(
-      message_pipe_handle, buffer, &buffer_size, 0, 0, 0);
-  if (result != MOJO_RESULT_OK)
-    return;
-  for (uint32_t i = 0; i < buffer_size; ++i)
-    g_waste_accumulator += buffer[i];
-}
-
-void CheckCorruptedEchoArgs(const js_to_cpp::EchoArgsPtr& arg) {
-  if (arg.is_null())
-    return;
-  CheckCorruptedString(arg->name);
-  CheckCorruptedStringArray(arg->string_array);
-  if (arg->data_handle.is_valid())
-    CheckCorruptedDataPipe(arg->data_handle.get().value());
-  if (arg->message_handle.is_valid())
-    CheckCorruptedMessagePipe(arg->message_handle.get().value());
-}
-
-void CheckCorruptedEchoArgsList(const js_to_cpp::EchoArgsListPtr& list) {
-  if (list.is_null())
-    return;
-  CheckCorruptedEchoArgs(list->item);
-  CheckCorruptedEchoArgsList(list->next);
-}
-
-// Base Provider implementation class. It's expected that tests subclass and
-// override the appropriate Provider functions. When test is done quit the
-// run_loop().
-class CppSideConnection : public js_to_cpp::CppSide {
- public:
-  CppSideConnection()
-      : run_loop_(nullptr),
-        js_side_(nullptr),
-        mishandled_messages_(0),
-        binding_(this) {}
-  ~CppSideConnection() override {}
-
-  void set_run_loop(base::RunLoop* run_loop) { run_loop_ = run_loop; }
-  base::RunLoop* run_loop() { return run_loop_; }
-
-  void set_js_side(js_to_cpp::JsSide* js_side) { js_side_ = js_side; }
-  js_to_cpp::JsSide* js_side() { return js_side_; }
-
-  void Bind(InterfaceRequest<js_to_cpp::CppSide> request) {
-    binding_.Bind(std::move(request));
-    // Keep the pipe open even after validation errors.
-    binding_.EnableTestingMode();
-  }
-
-  // js_to_cpp::CppSide:
-  void StartTest() override { NOTREACHED(); }
-
-  void TestFinished() override { NOTREACHED(); }
-
-  void PingResponse() override { mishandled_messages_ += 1; }
-
-  void EchoResponse(js_to_cpp::EchoArgsListPtr list) override {
-    mishandled_messages_ += 1;
-  }
-
-  void BitFlipResponse(
-      js_to_cpp::EchoArgsListPtr list,
-      js_to_cpp::ForTestingAssociatedPtrInfo not_used) override {
-    mishandled_messages_ += 1;
-  }
-
-  void BackPointerResponse(js_to_cpp::EchoArgsListPtr list) override {
-    mishandled_messages_ += 1;
-  }
-
- protected:
-  base::RunLoop* run_loop_;
-  js_to_cpp::JsSide* js_side_;
-  int mishandled_messages_;
-  mojo::Binding<js_to_cpp::CppSide> binding_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CppSideConnection);
-};
-
-// Trivial test to verify a message sent from JS is received.
-class PingCppSideConnection : public CppSideConnection {
- public:
-  PingCppSideConnection() : got_message_(false) {}
-  ~PingCppSideConnection() override {}
-
-  // js_to_cpp::CppSide:
-  void StartTest() override { js_side_->Ping(); }
-
-  void PingResponse() override {
-    got_message_ = true;
-    run_loop()->Quit();
-  }
-
-  bool DidSucceed() {
-    return got_message_ && !mishandled_messages_;
-  }
-
- private:
-  bool got_message_;
-  DISALLOW_COPY_AND_ASSIGN(PingCppSideConnection);
-};
-
-// Test that parameters are passed with correct values.
-class EchoCppSideConnection : public CppSideConnection {
- public:
-  EchoCppSideConnection() :
-      message_count_(0),
-      termination_seen_(false) {
-  }
-  ~EchoCppSideConnection() override {}
-
-  // js_to_cpp::CppSide:
-  void StartTest() override {
-    js_side_->Echo(kExpectedMessageCount, BuildSampleEchoArgs());
-  }
-
-  void EchoResponse(js_to_cpp::EchoArgsListPtr list) override {
-    const js_to_cpp::EchoArgsPtr& special_arg = list->item;
-    message_count_ += 1;
-    EXPECT_EQ(-1, special_arg->si64);
-    EXPECT_EQ(-1, special_arg->si32);
-    EXPECT_EQ(-1, special_arg->si16);
-    EXPECT_EQ(-1, special_arg->si8);
-    EXPECT_EQ(std::string("going"), *special_arg->name);
-    CheckSampleEchoArgsList(list->next);
-  }
-
-  void TestFinished() override {
-    termination_seen_ = true;
-    run_loop()->Quit();
-  }
-
-  bool DidSucceed() {
-    return termination_seen_ &&
-        !mishandled_messages_ &&
-        message_count_ == kExpectedMessageCount;
-  }
-
- private:
-  static const int kExpectedMessageCount = 10;
-  int message_count_;
-  bool termination_seen_;
-  DISALLOW_COPY_AND_ASSIGN(EchoCppSideConnection);
-};
-
-// Test that corrupted messages don't wreak havoc.
-class BitFlipCppSideConnection : public CppSideConnection {
- public:
-  BitFlipCppSideConnection() : termination_seen_(false) {}
-  ~BitFlipCppSideConnection() override {}
-
-  // js_to_cpp::CppSide:
-  void StartTest() override { js_side_->BitFlip(BuildSampleEchoArgs()); }
-
-  void BitFlipResponse(
-      js_to_cpp::EchoArgsListPtr list,
-      js_to_cpp::ForTestingAssociatedPtrInfo not_used) override {
-    CheckCorruptedEchoArgsList(list);
-  }
-
-  void TestFinished() override {
-    termination_seen_ = true;
-    run_loop()->Quit();
-  }
-
-  bool DidSucceed() {
-    return termination_seen_;
-  }
-
- private:
-  bool termination_seen_;
-  DISALLOW_COPY_AND_ASSIGN(BitFlipCppSideConnection);
-};
-
-// Test that severely random messages don't wreak havoc.
-class BackPointerCppSideConnection : public CppSideConnection {
- public:
-  BackPointerCppSideConnection() : termination_seen_(false) {}
-  ~BackPointerCppSideConnection() override {}
-
-  // js_to_cpp::CppSide:
-  void StartTest() override { js_side_->BackPointer(BuildSampleEchoArgs()); }
-
-  void BackPointerResponse(js_to_cpp::EchoArgsListPtr list) override {
-    CheckCorruptedEchoArgsList(list);
-  }
-
-  void TestFinished() override {
-    termination_seen_ = true;
-    run_loop()->Quit();
-  }
-
-  bool DidSucceed() {
-    return termination_seen_;
-  }
-
- private:
-  bool termination_seen_;
-  DISALLOW_COPY_AND_ASSIGN(BackPointerCppSideConnection);
-};
-
-}  // namespace
-
-class JsToCppTest : public testing::Test {
- public:
-  JsToCppTest() {}
-
-  void RunTest(const std::string& test, CppSideConnection* cpp_side) {
-    cpp_side->set_run_loop(&run_loop_);
-
-    js_to_cpp::JsSidePtr js_side;
-    auto js_side_proxy = MakeRequest(&js_side);
-
-    cpp_side->set_js_side(js_side.get());
-    js_to_cpp::CppSidePtr cpp_side_ptr;
-    cpp_side->Bind(MakeRequest(&cpp_side_ptr));
-
-    js_side->SetCppSide(std::move(cpp_side_ptr));
-
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
-    gin::V8Initializer::LoadV8Snapshot();
-    gin::V8Initializer::LoadV8Natives();
-#endif
-
-    gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
-                                   gin::IsolateHolder::kStableV8Extras,
-                                   gin::ArrayBufferAllocator::SharedInstance());
-    gin::IsolateHolder instance(base::ThreadTaskRunnerHandle::Get());
-    MojoRunnerDelegate delegate;
-    gin::ShellRunner runner(&delegate, instance.isolate());
-    delegate.Start(&runner, js_side_proxy.PassMessagePipe().release().value(),
-                   test);
-
-    run_loop_.Run();
-  }
-
- private:
-  base::ShadowingAtExitManager at_exit_;
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
-  base::RunLoop run_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(JsToCppTest);
-};
-
-TEST_F(JsToCppTest, Ping) {
-  PingCppSideConnection cpp_side_connection;
-  RunTest("mojo/edk/js/tests/js_to_cpp_tests", &cpp_side_connection);
-  EXPECT_TRUE(cpp_side_connection.DidSucceed());
-}
-
-TEST_F(JsToCppTest, Echo) {
-  EchoCppSideConnection cpp_side_connection;
-  RunTest("mojo/edk/js/tests/js_to_cpp_tests", &cpp_side_connection);
-  EXPECT_TRUE(cpp_side_connection.DidSucceed());
-}
-
-TEST_F(JsToCppTest, BitFlip) {
-  // These tests generate a lot of expected validation errors. Suppress logging.
-  mojo::internal::ScopedSuppressValidationErrorLoggingForTests log_suppression;
-
-  BitFlipCppSideConnection cpp_side_connection;
-  RunTest("mojo/edk/js/tests/js_to_cpp_tests", &cpp_side_connection);
-  EXPECT_TRUE(cpp_side_connection.DidSucceed());
-}
-
-TEST_F(JsToCppTest, BackPointer) {
-  // These tests generate a lot of expected validation errors. Suppress logging.
-  mojo::internal::ScopedSuppressValidationErrorLoggingForTests log_suppression;
-
-  BackPointerCppSideConnection cpp_side_connection;
-  RunTest("mojo/edk/js/tests/js_to_cpp_tests", &cpp_side_connection);
-  EXPECT_TRUE(cpp_side_connection.DidSucceed());
-}
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index e8d493e..ab79ff6 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -11711,6 +11711,40 @@
         },
         "test": "content_browsertests"
       }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "--additional-driver-flag=--enable-network-service"
+        ],
+        "isolate_name": "webkit_layout_tests_exparchive",
+        "merge": {
+          "args": [
+            "--verbose",
+            "--results-json-override-with-build-property",
+            "build_number",
+            "buildnumber",
+            "--results-json-override-with-build-property",
+            "builder_name",
+            "buildername",
+            "--results-json-override-with-build-property",
+            "chromium_revision",
+            "got_revision_cp"
+          ],
+          "script": "//third_party/WebKit/Tools/Scripts/merge-layout-test-results"
+        },
+        "name": "webkit_layout_tests",
+        "results_handler": "layout tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-14.04"
+            }
+          ],
+          "shards": 6
+        }
+      }
     ]
   },
   "Mojo Windows": {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 70f6fa72..1d5b2959 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -3901,12 +3901,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "mojo_js_integration_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "mojo_js_unittests"
       },
       {
@@ -4582,12 +4576,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "mojo_js_integration_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "mojo_js_unittests"
       },
       {
diff --git a/testing/buildbot/client.v8.chromium.json b/testing/buildbot/client.v8.chromium.json
index bb493a0..09e30211 100644
--- a/testing/buildbot/client.v8.chromium.json
+++ b/testing/buildbot/client.v8.chromium.json
@@ -236,12 +236,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "mojo_js_integration_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "mojo_js_unittests"
       },
       {
diff --git a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
index cc09ada3..8034949 100644
--- a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
@@ -33,10 +33,6 @@
 -ServiceWorkerVersionBrowserTest.ServiceWorkerScriptHeader
 -ServiceWorkerVersionBrowserTest.StartNotFound
 
-# http://crbug.com/715677
-# Needs blob fetching for subresources
--BlobStorageBrowserTest.BlobCombinations
-
 # http://crbug.com/715630
 -DownloadContentTest.*
 
@@ -61,7 +57,6 @@
 -DataUrlNavigationBrowserTest.UnknownMimeType_WindowOpen_Download
 -DevToolsProtocolTest.CertificateError
 -DevToolsProtocolTest.SubresourceWithCertificateError
--FrameTreeBrowserTest.NavigateGrandchildToBlob
 -GenericSensorBrowserTest.AmbientLightSensorTest
 -HostZoomMapImplBrowserTest.GetZoomForView_Host
 -HostZoomMapImplBrowserTest.GetZoomForView_HostAndScheme
@@ -85,6 +80,7 @@
 -NavigationControllerBrowserTest.NavigateFromLoadDataWithBaseURL
 -NavigationControllerBrowserTest.NoDialogsFromSwappedOutFrames
 -NavigationControllerBrowserTest.RefererStoredForSubFrame
+-NavigationHandleImplBrowserTest.ErrorCodeOnRedirect
 -ParallelDownloadTest.ParallelDownloadComplete
 -PaymentAppBrowserTest.PaymentAppInvocation
 -PaymentAppBrowserTest.PaymentAppOpenWindowFailed
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 3f8a6f08..3db232d8 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -704,10 +704,6 @@
     "label": "//mojo/common:mojo_common_unittests",
     "type": "console_test_launcher",
   },
-  "mojo_js_integration_tests": {
-    "label": "//mojo/edk/js/tests:mojo_js_integration_tests",
-    "type": "console_test_launcher",
-  },
   "mojo_js_unittests": {
     "label": "//mojo/edk/js/tests:mojo_js_unittests",
     "type": "console_test_launcher",
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
index 6a8900c..5be456d 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
@@ -34,6 +34,15 @@
 Bug(none) bluetooth/requestDevice/request-from-iframe.html [ Timeout ]
 Bug(none) bluetooth/requestDevice/same-device.html [ Timeout ]
 Bug(none) bluetooth/requestDevice/single-filter-single-service.html [ Timeout ]
+Bug(none) bluetooth/server/connect/connection-succeeds.html [ Timeout ]
+Bug(none) bluetooth/server/connect/garbage-collection-ran-during-success.html [ Timeout ]
+Bug(none) bluetooth/server/connect/get-same-gatt-server.html [ Timeout ]
+Bug(none) bluetooth/server/device-same-object.html [ Timeout ]
+Bug(none) bluetooth/server/getPrimaryService/gen-invalid-service-name.html [ Timeout ]
+Bug(none) bluetooth/server/getPrimaryService/gen-no-permission-for-any-service.html [ Timeout ]
+Bug(none) bluetooth/server/getPrimaryServices/gen-invalid-service-name.html [ Timeout ]
+Bug(none) bluetooth/server/getPrimaryServices/gen-no-permission-for-any-service.html [ Timeout ]
+Bug(none) bluetooth/server/getPrimaryServices/gen-no-permission-for-any-service-with-uuid.html [ Timeout ]
 Bug(none) compositing/iframes/iframe-in-composited-layer.html [ Failure ]
 Bug(none) compositing/layers-inside-overflow-scroll.html [ Timeout ]
 Bug(none) compositing/self-painting-layers2.html [ Timeout ]
@@ -610,6 +619,7 @@
 Bug(none) external/wpt/payment-request/allowpaymentrequest/setting-allowpaymentrequest.https.sub.html [ Timeout ]
 Bug(none) external/wpt/payment-request/historical.https.html [ Timeout ]
 Bug(none) external/wpt/payment-request/interfaces.https.html [ Timeout ]
+Bug(none) external/wpt/payment-request/payment-request-abort-method.https.html [ Timeout ]
 Bug(none) external/wpt/payment-request/payment-request-constructor.https.html [ Timeout ]
 Bug(none) external/wpt/payment-request/payment-request-id.https.html [ Timeout ]
 Bug(none) external/wpt/payment-request/payment-request-show-method.https.html [ Timeout ]
@@ -1258,70 +1268,7 @@
 Bug(none) external/wpt/workers/constructors/Worker/Blob-url.html [ Timeout ]
 Bug(none) external/wpt/workers/name-property.html [ Failure Timeout ]
 Bug(none) external/wpt/workers/SharedWorker_blobUrl.html [ Timeout ]
-Bug(none) external/wpt/XMLHttpRequest/abort-during-done.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/anonymous-mode-unsupported.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/event-upload-progress-crossorigin.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/event-upload-progress.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/formdata-blob.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/formdata.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/getallresponseheaders-cl.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/headers-normalize-response.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-method-case-insensitive.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-method-case-sensitive.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-open-sync-send.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-referer.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-url-about-blank-window.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-url-base-inserted-after-open.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-url-base-inserted.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-url-base.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-url-encoding.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-url-fragment.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-url-javascript-window-2.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-url-javascript-window.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/open-url-worker-origin.htm [ Timeout ]
-Bug(none) external/wpt/XMLHttpRequest/overridemimetype-blob.html [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/response-data-blob.htm [ Timeout ]
-Bug(none) external/wpt/XMLHttpRequest/response-data-deflate.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/response-data-gzip.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/response-data-progress.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/response-method.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/responsetype.html [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/responseurl.html [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/responsexml-basic.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/responsexml-media-type.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/responsexml-non-well-formed.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-accept-language.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-accept.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-after-setting-document-domain.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-authentication-basic-repeat-no-args.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-authentication-basic-setrequestheader-and-arguments.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-authentication-basic-setrequestheader-existing-session.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-authentication-basic-setrequestheader.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-authentication-basic.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-authentication-competing-names-passwords.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-authentication-prompt-manual.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-blob-with-no-mime-type.html [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-conditional.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-content-type-charset.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-content-type-string.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-data-blob.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-entity-body-basic.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-entity-body-empty.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-entity-body-get-head.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-entity-body-none.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-redirect-infinite.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-redirect-post-upload.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-response-upload-event-loadend.htm [ Timeout ]
-Bug(none) external/wpt/XMLHttpRequest/send-response-upload-event-progress.htm [ Timeout ]
-Bug(none) external/wpt/XMLHttpRequest/send-sync-blocks-async.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-sync-no-response-event-load.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-sync-no-response-event-loadend.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-sync-no-response-event-order.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-sync-response-event-order.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/send-sync-timeout.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/setrequestheader-case-insensitive.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/setrequestheader-header-forbidden.htm [ Failure ]
-Bug(none) external/wpt/XMLHttpRequest/status-basic.htm [ Failure ]
+Bug(none) external/wpt/XMLHttpRequest [ Failure Timeout ]
 Bug(none) fast/canvas/canvas-createImageBitmap-blob-in-workers.html [ Timeout ]
 Bug(none) fast/canvas/canvas-createImageBitmap-drawImage.html [ Failure ]
 Bug(none) fast/canvas/canvas-createImageBitmap-from-canvas-toBlob.html [ Timeout ]
@@ -1424,7 +1371,7 @@
 Bug(none) fast/files/read-blob-async.html [ Failure ]
 Bug(none) fast/files/read-file-async.html [ Failure ]
 Bug(none) fast/files/workers/inline-worker-via-blob-url.html [ Timeout ]
-Bug(none) fast/files/workers/worker-apply-blob-url-to-xhr.html [ Timeout ]
+Bug(none) fast/files/workers/worker-apply-blob-url-to-xhr.html [ Failure Timeout ]
 Bug(none) fast/files/workers/worker-read-blob-async.html [ Failure ]
 Bug(none) fast/files/workers/worker-read-blob-sync.html [ Failure ]
 Bug(none) fast/files/workers/worker-read-file-async.html [ Failure ]
@@ -1517,6 +1464,10 @@
 Bug(none) fast/xpath/4XPath/Borrowed/od_20000608.html [ Failure ]
 Bug(none) fast/xsl/document-function.xml [ Failure ]
 Bug(none) fast/xsl/dtd-in-source-document.xml [ Failure ]
+Bug(none) fast/xsl/import-after-comment.xml [ Skip ]
+Bug(none) fast/xsl/xslt-multiple-relative-import.xml [ Skip ]
+Bug(none) fast/xsl/xslt-nested-stylesheets.xml [ Skip ]
+Bug(none) fast/xsl/xslt-second-level-import.xml [ Skip ]
 Bug(none) fast/xsl/transform-xhr-doc.xhtml [ Failure ]
 Bug(none) fast/xsl/xslt-import-depth.xml [ Failure ]
 Bug(none) fast/xsl/xslt-import-enc16.xml [ Failure ]
@@ -2363,191 +2314,7 @@
 Bug(none) http/tests/websocket/workers/worker-reload.html [ Timeout ]
 Bug(none) http/tests/workers/shared-worker-secure-context.https.html [ Timeout ]
 Bug(none) http/tests/workers/text-encoding.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/abort-should-destroy-responseText.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-allow-lists-starting-with-comma.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-allow-access-control-origin-header-data-url.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-allow-access-control-origin-header.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-allow-star.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-allow.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-denied.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-get-fail-non-simple.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-non-simple-allow.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-non-simple-deny-cached.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-post-fail-non-simple-content-type.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-whitelist-request-headers.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-basic-whitelist-response-headers.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-preflight-async-header-denied.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/access-control-preflight-async-method-denied.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/access-control-preflight-async-not-supported.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/access-control-preflight-credential-sync.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/access-control-preflight-headers-async.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/access-control-preflight-headers-sync.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-preflight-request-must-not-contain-cookie.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/access-control-preflight-sync-header-denied.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-preflight-sync-method-denied.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-preflight-sync-not-supported.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-response-with-body-sync.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-sandboxed-iframe-allow-origin-null.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-sandboxed-iframe-allow.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-sandboxed-iframe-denied-without-wildcard.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/access-control-sandboxed-iframe-denied.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/async-xhr-revalidate-after-sync-xhr.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/authorization-header.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/binary-x-user-defined.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/blob-response-type-warm-cache.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/broken-xml-encoding.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/cache-override.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/cookies.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/cross-origin-cookie-storage.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/cross-origin-preflight-get-response-type-blob.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/cross-site-denied-response-sync-2.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/cross-site-denied-response-sync.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/document-domain-set.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/duplicate-revalidation-reload.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/encode-request-url-2.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/encode-request-url.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/encoding-send-latin-1.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/event-target.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/exceptions.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/extra-parameters.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/failed-auth.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/filename-encoding.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/get-dangerous-headers.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/logout.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/methods-lower-case.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/methods.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/newline-in-request-uri.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/null-auth.php [ Failure ]
-Bug(none) http/tests/xmlhttprequest/onloadend-event-after-sync-requests.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/open-async-overload.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/00.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/01.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/02.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/03.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/04.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/05.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/06.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/07.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/08.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/09.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/10.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/11.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/12.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/13.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/14.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/15.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/16.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/17.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/18.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/19.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/20.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/21.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/22.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/23.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/24.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/25.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/26.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/27.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/28.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/29.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/30.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/31.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/32.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/33.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/34.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/35.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/36.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/37.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/38.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/39.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/40.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/41.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/42.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/43.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/44.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/45.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/46.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-exact-matching/47.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-header-cross-origin-get-sync.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-header-cross-origin-post-sync.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-header-same-origin-get-sync.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-header-same-origin-post-sync.html [ Timeout Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-whitelisting-all.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-whitelisting-exact-match.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-whitelisting-https.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-whitelisting-removal.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/post-blob-content-type-sync.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/post-content-type.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/post-formdata.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/post-with-boundary.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/redirect-cross-origin-tripmine.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/referer.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/remember-bad-password.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/reopen-encoding.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/request-encoding.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/request-encoding2.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/request-encoding3.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/request-encoding4.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/response-blob-mimetype.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/response-blob-size.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/response-encoding.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/response-encoding2.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/send-entity-body-basic.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/send-entity-body-charset.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/serialize-document.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/set-dangerous-headers.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/simple-cross-origin-denied-events-post-sync.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/simple-cross-origin-denied-events-sync.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/state-after-network-error.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/sync-after-async-same-resource.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/sync-repeated-and-caching.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/sync-xhr-revalidate-after-async-xhr.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-aborted.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-twice.html [ Failure Timeout ]
-Bug(none) http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-aborted.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-simple.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-synconworker.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-twice.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/upload-onload-event.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/upload-onloadend-event-after-abort.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/upload-onloadend-event-after-load.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/upload-onloadend-event-after-sync-requests.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/upload-onprogress-event.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/upload-progress-events.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/web-apps/002-simple.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/002.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/003.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/004.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/005.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/007.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/008.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/010.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/011.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/012.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/014.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/015.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/web-apps/018.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/withCredentials-after-send.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/workers/post-formdata.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/workers/shared-worker-response-type-blob-sync.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/workers/shared-worker-response-type-blob.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/workers/upload-onprogress-event.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/workers/xmlhttprequest-response-type-blob-sync.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/workers/xmlhttprequest-response-type-blob.html [ Timeout ]
-Bug(none) http/tests/xmlhttprequest/xhr-to-blob-in-isolated-world.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/xml-encoding.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/xmlhttprequest-latin1.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/xmlhttprequest-missing-file-exception.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/xmlhttprequest-response-type-blob.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/xmlhttprequest-setrequestheader-no-value.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/xmlhttprequest-sync-no-progress-events.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/xmlhttprequest-sync-no-timers.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/xmlhttprequest-sync-vs-async-assertion-failure.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/xmlhttprequest-unload-sync.html [ Failure ]
-Bug(none) http/tests/xmlhttprequest/zero-length-response-sync.html [ Failure ]
+Bug(none) http/tests/xmlhttprequest [ Failure Timeout ]
 Bug(none) imagecapture/getPhotoCapabilities.html [ Timeout ]
 Bug(none) imagecapture/MediaStreamTrack-applyConstraints-getSettings.html [ Timeout ]
 Bug(none) imagecapture/MediaStreamTrack-applyConstraints-reject.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 1b9b127..a55a5a2 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -88,6 +88,8 @@
 crbug.com/728566 virtual/gpu-rasterization/images/color-profile-background-image-cross-fade.html [ NeedsManualRebaseline ]
 crbug.com/728566 virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ NeedsManualRebaseline ]
 
+crbug.com/722000 virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill.html [ NeedsManualRebaseline ]
+
 ########## Bugs to fix ##########
 # This is a missing event and increasing the timeout or using run-after-layout-and-paint doesn't
 # seem to fix it.
diff --git a/third_party/WebKit/LayoutTests/dom/README.md b/third_party/WebKit/LayoutTests/dom/README.md
index 43589e6..6e6ea5e 100644
--- a/third_party/WebKit/LayoutTests/dom/README.md
+++ b/third_party/WebKit/LayoutTests/dom/README.md
@@ -22,6 +22,10 @@
 
     See [legacy_dom_conformance/README.md](legacy_dom_conformance/README.md)
 
+*   node/
+
+    For [Node interface](https://dom.spec.whatwg.org/#interface-node)
+
 *   parent_node/
 
     For [ParentNode mixin](https://dom.spec.whatwg.org/#interface-parentnode)
diff --git a/third_party/WebKit/LayoutTests/dom/node/replace_child_recheck.html b/third_party/WebKit/LayoutTests/dom/node/replace_child_recheck.html
new file mode 100644
index 0000000..26941413b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/dom/node/replace_child_recheck.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div id="parent"><br id="child"><br id="next"></div>
+<script>
+test(() => {
+  let parent = document.querySelector('#parent');
+  parent.addEventListener('DOMSubtreeModified', () => {
+    document.body.appendChild(document.querySelector('#next'));
+  }, {once: true});
+  let new_node = document.createElement('span');
+  assert_throws('NotFoundError', () => {
+    parent.replaceChild(new_node, document.querySelector('#child'));
+  });
+  assert_equals(parent.firstChild, null);
+  assert_equals(new_node.parentNode, null);
+  assert_equals(new_node.nextSibling, null);
+}, 'Re-parenting a reference node should not crash replaceChild().');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-insertBefore-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-insertBefore-expected.txt
deleted file mode 100644
index 884f0500..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-insertBefore-expected.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-This is a testharness.js-based test.
-PASS Calling insertBefore with a non-Node first argument must throw TypeError. 
-PASS Calling insertBefore with a non-Node first argument on a leaf node DocumentType must throw TypeError. 
-PASS Calling insertBefore an a leaf node DocumentType must throw HIERARCHY_REQUEST_ERR. 
-PASS Calling insertBefore with a non-Node first argument on a leaf node Text must throw TypeError. 
-PASS Calling insertBefore an a leaf node Text must throw HIERARCHY_REQUEST_ERR. 
-PASS Calling insertBefore with a non-Node first argument on a leaf node Comment must throw TypeError. 
-PASS Calling insertBefore an a leaf node Comment must throw HIERARCHY_REQUEST_ERR. 
-PASS Calling insertBefore with a non-Node first argument on a leaf node ProcessingInstruction must throw TypeError. 
-PASS Calling insertBefore an a leaf node ProcessingInstruction must throw HIERARCHY_REQUEST_ERR. 
-PASS Calling insertBefore with an inclusive ancestor of the context object must throw HIERARCHY_REQUEST_ERR. 
-PASS Calling insertBefore with a reference child whose parent is not the context node must throw a NotFoundError. 
-PASS If the context node is a document, inserting a document or text node should throw a HierarchyRequestError. 
-PASS If the context node is a document, appending a DocumentFragment that contains a text node or too many elements should throw a HierarchyRequestError. 
-PASS If the context node is a document, inserting a DocumentFragment that contains a text node or too many elements should throw a HierarchyRequestError. 
-PASS If the context node is a document, inserting a DocumentFragment with an element if there already is an element child should throw a HierarchyRequestError. 
-FAIL If the context node is a document and a doctype is following the reference child, inserting a DocumentFragment with an element should throw a HierarchyRequestError. assert_throws: function "function () {
-    doc.insertBefore(df, doc.doctype);
-  }" did not throw
-FAIL If the context node is a document, inserting a DocumentFragment with an element before the doctype should throw a HierarchyRequestError. assert_throws: function "function () {
-    doc.insertBefore(df, comment);
-  }" did not throw
-PASS If the context node is a document, inserting an element if there already is an element child should throw a HierarchyRequestError. 
-FAIL If the context node is a document, inserting an element before the doctype should throw a HierarchyRequestError. assert_throws: function "function () {
-    doc.insertBefore(a, doc.doctype);
-  }" did not throw
-FAIL If the context node is a document and a doctype is following the reference child, inserting an element should throw a HierarchyRequestError. assert_throws: function "function () {
-    doc.insertBefore(a, comment);
-  }" did not throw
-PASS If the context node is a document, inserting a doctype if there already is a doctype child should throw a HierarchyRequestError. 
-FAIL If the context node is a document, inserting a doctype after the document element should throw a HierarchyRequestError. assert_throws: function "function () {
-    doc.insertBefore(doctype, comment);
-  }" did not throw
-FAIL If the context node is a document with and element child, appending a doctype should throw a HierarchyRequestError. assert_throws: function "function () {
-    doc.insertBefore(doctype, null);
-  }" did not throw
-PASS If the context node is a DocumentFragment, inserting a document or a doctype should throw a HierarchyRequestError. 
-PASS If the context node is an element, inserting a document or a doctype should throw a HierarchyRequestError. 
-PASS Inserting a node before itself should not move the node 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-replaceChild-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-replaceChild-expected.txt
deleted file mode 100644
index 51224a08..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/nodes/Node-replaceChild-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-This is a testharness.js-based test.
-PASS Passing null to replaceChild should throw a TypeError. 
-PASS If child's parent is not the context node, a NotFoundError exception should be thrown 
-PASS If the context node is not a node that can contain children, a NotFoundError exception should be thrown 
-PASS If node is an inclusive ancestor of the context node, a HierarchyRequestError should be thrown. 
-PASS If the context node is a document, inserting a document or text node should throw a HierarchyRequestError. 
-PASS If the context node is a document, inserting a DocumentFragment that contains a text node or too many elements should throw a HierarchyRequestError. 
-PASS If the context node is a document (without element children), inserting a DocumentFragment that contains multiple elements should throw a HierarchyRequestError. 
-PASS If the context node is a document, inserting a DocumentFragment with an element if there already is an element child should throw a HierarchyRequestError. 
-FAIL If the context node is a document, inserting a DocumentFragment with an element before the doctype should throw a HierarchyRequestError. assert_throws: function "function () {
-    doc.replaceChild(df, comment);
-  }" did not throw
-PASS If the context node is a document, inserting an element if there already is an element child should throw a HierarchyRequestError. 
-FAIL If the context node is a document, inserting an element before the doctype should throw a HierarchyRequestError. assert_throws: function "function () {
-    doc.replaceChild(a, comment);
-  }" did not throw
-PASS If the context node is a document, inserting a doctype if there already is a doctype child should throw a HierarchyRequestError. 
-FAIL If the context node is a document, inserting a doctype after the document element should throw a HierarchyRequestError. assert_throws: function "function () {
-    doc.replaceChild(doctype, comment);
-  }" did not throw
-PASS If the context node is a DocumentFragment, inserting a document or a doctype should throw a HierarchyRequestError. 
-PASS If the context node is an element, inserting a document or a doctype should throw a HierarchyRequestError. 
-PASS Replacing a node with its next sibling should work (2 children) 
-PASS Replacing a node with its next sibling should work (4 children) 
-PASS Replacing a node with itself should not move the node 
-PASS If the context node is a document, inserting a new doctype should work. 
-PASS Replacing the document element with a DocumentFragment containing a single element should work. 
-PASS Replacing the document element with a DocumentFragment containing a single element and comments should work. 
-PASS Replacing the document element with a single element should work. 
-PASS replaceChild should work in the presence of mutation events. 
-PASS Replacing an element with a DocumentFragment should allow a child of the DocumentFragment to be found by Id. 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/Source/build/scripts/make_css_property_apis.py b/third_party/WebKit/Source/build/scripts/make_css_property_apis.py
index 1b9448c..4c9fb60 100755
--- a/third_party/WebKit/Source/build/scripts/make_css_property_apis.py
+++ b/third_party/WebKit/Source/build/scripts/make_css_property_apis.py
@@ -45,7 +45,6 @@
         self._outputs = {
             'CSSPropertyDescriptor.cpp': self.generate_property_descriptor_cpp,
             'CSSPropertyDescriptor.h': self.generate_property_descriptor_h,
-            'CSSPropertyAPI.h': self.generate_property_api,
         }
 
         # Stores a map of API method name -> (return_type, parameters)
@@ -116,13 +115,6 @@
             'all_api_methods': self.all_api_methods,
         }
 
-    @template_expander.use_jinja('CSSPropertyAPI.h.tmpl')
-    def generate_property_api(self):
-        return {
-            'ordered_api_method_names': self.ordered_api_method_names,
-            'all_api_methods': self.all_api_methods,
-        }
-
     # Provides a function object given the classname of the property.
     def generate_property_api_h_builder(self, api_classname, property_name):
         @template_expander.use_jinja('CSSPropertyAPIFiles.h.tmpl')
diff --git a/third_party/WebKit/Source/build/scripts/templates/CSSPropertyAPI.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/CSSPropertyAPI.h.tmpl
deleted file mode 100644
index e5ee163ef0..0000000
--- a/third_party/WebKit/Source/build/scripts/templates/CSSPropertyAPI.h.tmpl
+++ /dev/null
@@ -1,48 +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 CSSPropertyAPI_h
-#define CSSPropertyAPI_h
-
-#include "core/CSSPropertyNames.h"
-#include "platform/wtf/Allocator.h"
-
-namespace blink {
-
-class CSSValue;
-class CSSParserContext;
-class CSSParserLocalContext;
-class CSSParserTokenRange;
-
-// Base class for property APIs that contain logic for handling individual
-// properties.
-// The methods declared here are standard methods among property APIs, and can
-// be called on a particular property API through a CSSPropertyDescriptor
-// object.
-// Note that not all methods are implemented by all property APIs. Methods that
-// are not implemented on a property API will return nullptr when accessed
-// through a CSSPropertyDescriptor.
-// See the api_methods field on properties defined in CSSProperties.json5 for a
-// definition of which methods are implemented on a property.
-//
-// Status (5th May 2017): Eventually, all property specific logic will be
-// contained within property APIs that inherit from CSSPropertyAPI.
-// Currently, the code base is in a transitional state and property specific
-// logic is still scattered around the code base.
-class CSSPropertyAPI {
-  STATIC_ONLY(CSSPropertyAPI);
-
- public:
-  {% for api_method_name in ordered_api_method_names %}
-  {% set api_method = all_api_methods[api_method_name] %}
-  {% if api_method.description %}
-  // {{api_method.description}}
-  {% endif %}
-  static {{api_method.return_type}} {{api_method_name}}{{api_method.parameters}};
-  {% endfor %}
-};
-
-} // namespace blink
-
-#endif // CSSPropertyAPI_h
diff --git a/third_party/WebKit/Source/build/scripts/templates/CSSPropertyAPIFiles.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/CSSPropertyAPIFiles.h.tmpl
index b6c1b68..8213a8a2 100644
--- a/third_party/WebKit/Source/build/scripts/templates/CSSPropertyAPIFiles.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/CSSPropertyAPIFiles.h.tmpl
@@ -6,13 +6,13 @@
 #define {{api_classname}}_h
 
 #include "core/CSSPropertyNames.h"
-#include "core/css/properties/CSSPropertyAPI.h"
 
 namespace blink {
 
 class CSSParserTokenRange;
 class CSSParserContext;
 class CSSParserLocalContext;
+class CSSValue;
 
 // {{api_classname}} is the API that contains logic
 // for handling the {{property_name}} property.
@@ -23,7 +23,7 @@
 // {{property_name}} property will be contained within
 // {{api_classname}}. Currently, the code base is in a transitional
 // state and property specific logic is still scattered around the code base.
-class {{api_classname}} : public CSSPropertyAPI {
+class {{api_classname}} {
  public:
   {% for api_method in all_api_methods if api_method in methods_for_class %}
   static {{all_api_methods[api_method].return_type}} {{api_method}}{{all_api_methods[api_method].parameters}};
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 9e24917..389b4fa 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -450,11 +450,9 @@
     "../build/scripts/templates/CSSPropertyDescriptor.cpp.tmpl",
     "../build/scripts/templates/CSSPropertyDescriptor.h.tmpl",
     "../build/scripts/templates/CSSPropertyAPIFiles.h.tmpl",
-    "../build/scripts/templates/CSSPropertyAPI.h.tmpl",
   ]
   in_files = [ "css/properties/CSSPropertyAPIMethods.json5" ]
   outputs = [
-    "$blink_core_output_dir/css/properties/CSSPropertyAPI.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIAlignItems.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIAlignOrJustifyContent.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIAlignOrJustifySelf.h",
@@ -1446,6 +1444,7 @@
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/WebKit/Source/core/editing:unit_tests",
+    "//third_party/WebKit/Source/core/mojo:unit_tests",
   ]
 }
 
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 7fd6171..d9b981b 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -38,7 +38,7 @@
     // - api_class: true|"classname"
     // Specifies the existence (and optionally name) of a CSSPropertyAPI
     // implementation for the property to be used by make_css_property_apis.py.
-    // See core/css/properties/CSSPropertyAPI.h for API details.
+    // See core/css/properties/CSSPropertyAPI<PropertyName>.h for API details.
     // * Add this flag if the API has been implemented for this property.
     // * If the classname for this is different to the name of the property, specify a
     //   value for this flag. e.g. api_class=CSSPropertyAPIWebkitPadding
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 1f9836b..b1910ec 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -40,7 +40,6 @@
 #include "core/css/parser/CSSVariableParser.h"
 #include "core/css/parser/FontVariantLigaturesParser.h"
 #include "core/css/parser/FontVariantNumericParser.h"
-#include "core/css/properties/CSSPropertyAPI.h"
 #include "core/css/properties/CSSPropertyAlignmentUtils.h"
 #include "core/css/properties/CSSPropertyAnimationNameUtils.h"
 #include "core/css/properties/CSSPropertyColumnUtils.h"
diff --git a/third_party/WebKit/Source/core/css/properties/README.md b/third_party/WebKit/Source/core/css/properties/README.md
index 35fad85..ae1a2ad 100644
--- a/third_party/WebKit/Source/core/css/properties/README.md
+++ b/third_party/WebKit/Source/core/css/properties/README.md
@@ -21,6 +21,26 @@
 [design doc](https://docs.google.com/document/d/1ywjUTmnxF5FXlpUTuLpint0w4TdSsjJzdWJqmhNzlss/edit#heading=h.1ckibme4i78b)
 for details of progress.
 
+## Methods implemented by each property API
+
+Methods implemented by a property API depends on whether it is a longhand or shorthand property.
+They implement different methods because a shorthand property will cease to exist after parsing is done.
+It will not be relevant in subsequent operations, except for serialization.
+
+Each <LonghandProperty> has a property API called CSSPropertyAPI<LonghandProperty> and each <ShorthandProperty>
+has a property API called CSSShorthandPropertyAPI<ShorthandProperty>.
+
+1.  CSSPropertyAPI<LonghandProperty>
+    Aims to implement all property-specific logic for this longhand property. Currently(7/6/2017) it implements:
+    1. static const CSSValue* parseSingleValue(CSSParserTokenRange&, const CSSParserContext&, const CSSParserLocalContext&);
+       - Parses a single CSS property and returns the corresponding CSSValue. If the input is invalid it returns nullptr.
+
+2.  CSSShorthandPropertyAPI<ShorthandProperty>
+    Aims to implement all property-specific logic for this shorthand property. Currently(7/6/2017) it implements:
+    1. static bool parseShorthand(bool important, CSSParserTokenRange&, const CSSParserContext*, HeapVector<CSSProperty, 256>& properties);
+       - Returns true if the property can be parsed as a shorthand. It also adds parsed properties to the `properties` set.
+
+
 ## How to add a new property API
 
 1.  Add a .cpp file to this directory named
@@ -28,7 +48,7 @@
 2.  Implement the property API in the .cpp file
     1.  Add `#include "core/css/properties/CSSPropertyAPI<Property/GroupName>.h"`
         (this will be a generated file)
-    2.  Implement the required methods on the API, e.g. `parseSingleValue`
+    2.  Implement the required methods on the API.
 3.  If logic is required by multiple property APIs you may need to create a new
     Utils file.
 4.  Add the new property to `core/css/CSSProperties.json5`. Ensure that you
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index ffd506dd..071f762 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -115,8 +115,10 @@
 
 DISABLE_CFI_PERF
 bool ContainerNode::CheckAcceptChild(const Node* new_child,
+                                     const Node* next,
                                      const Node* old_child,
                                      ExceptionState& exception_state) const {
+  DCHECK(!(next && old_child));
   // Not mentioned in spec: throw NotFoundError if newChild is null
   if (!new_child) {
     exception_state.ThrowDOMException(kNotFoundError,
@@ -145,16 +147,17 @@
     return false;
   }
 
-  return CheckAcceptChildGuaranteedNodeTypes(*new_child, old_child,
+  return CheckAcceptChildGuaranteedNodeTypes(*new_child, next, old_child,
                                              exception_state);
 }
 
 bool ContainerNode::CheckAcceptChildGuaranteedNodeTypes(
     const Node& new_child,
+    const Node* next,
     const Node* old_child,
     ExceptionState& exception_state) const {
   if (IsDocumentNode())
-    return ToDocument(this)->CanAcceptChild(new_child, old_child,
+    return ToDocument(this)->CanAcceptChild(new_child, next, old_child,
                                             exception_state);
   // Skip containsIncludingHostElements() if !newChild.parentNode() &&
   // isConnected(). |newChild| typically has no parentNode(), and it means
@@ -212,7 +215,7 @@
       // node.  Firefox and Edge don't throw in this case.
       return false;
     }
-    if (!CheckAcceptChildGuaranteedNodeTypes(*child, old_child,
+    if (!CheckAcceptChildGuaranteedNodeTypes(*child, next, old_child,
                                              exception_state))
       return false;
   }
@@ -320,7 +323,7 @@
   }
 
   // Make sure adding the new child is OK.
-  if (!CheckAcceptChild(new_child, 0, exception_state))
+  if (!CheckAcceptChild(new_child, ref_child, nullptr, exception_state))
     return new_child;
   DCHECK(new_child);
 
@@ -388,7 +391,7 @@
     return true;
   // TODO(esprehn): Are there other conditions where the parser can create
   // invalid trees?
-  return ToDocument(*this).CanAcceptChild(new_child, nullptr,
+  return ToDocument(*this).CanAcceptChild(new_child, nullptr, nullptr,
                                           IGNORE_EXCEPTION_FOR_TESTING);
 }
 
@@ -450,7 +453,7 @@
   // doctype and parent is not a document, throw a HierarchyRequestError.
   // 6. If parent is a document, and any of the statements below, switched on
   // node, are true, throw a HierarchyRequestError.
-  if (!CheckAcceptChild(new_child, old_child, exception_state))
+  if (!CheckAcceptChild(new_child, nullptr, old_child, exception_state))
     return old_child;
 
   // 3. If child’s parent is not parent, then throw a NotFoundError.
@@ -499,9 +502,18 @@
         return nullptr;
     }
 
-    // Does this one more time because removeChild() fires a MutationEvent.
-    if (!CheckAcceptChild(new_child, old_child, exception_state))
+    // Check DOM structure one more time because removeChild() above fires
+    // synchronous events.
+    if (!CheckAcceptChild(new_child, nullptr, old_child, exception_state))
       return old_child;
+    if (next && next->parentNode() != this) {
+      exception_state.ThrowDOMException(
+          kNotFoundError,
+          "The node before which the new node is to "
+          "be inserted is not a child of this "
+          "node.");
+      return old_child;
+    }
 
     // 13. Let nodes be node’s children if node is a DocumentFragment node, and
     // a list containing solely node otherwise.
@@ -734,7 +746,7 @@
 Node* ContainerNode::AppendChild(Node* new_child,
                                  ExceptionState& exception_state) {
   // Make sure adding the new child is ok
-  if (!CheckAcceptChild(new_child, 0, exception_state))
+  if (!CheckAcceptChild(new_child, nullptr, nullptr, exception_state))
     return new_child;
   DCHECK(new_child);
 
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.h b/third_party/WebKit/Source/core/dom/ContainerNode.h
index 397c2e2..72db2f3 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.h
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.h
@@ -419,9 +419,11 @@
       NodeVector&,
       ExceptionState&) const;
   inline bool CheckAcceptChildGuaranteedNodeTypes(const Node& new_child,
+                                                  const Node* next,
                                                   const Node* old_child,
                                                   ExceptionState&) const;
   inline bool CheckAcceptChild(const Node* new_child,
+                               const Node* next,
                                const Node* old_child,
                                ExceptionState&) const;
   inline bool CheckParserAcceptChild(const Node& new_child) const;
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 4e88854..dd13c4ad 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -3868,27 +3868,68 @@
   return false;
 }
 
+// This is an implementation of step 6 of
+// https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
+// and https://dom.spec.whatwg.org/#concept-node-replace .
+//
+// 6. If parent is a document, and any of the statements below, switched on
+// node, are true, throw a HierarchyRequestError.
+//  -> DocumentFragment node
+//     If node has more than one element child or has a Text node child.
+//     Otherwise, if node has one element child and either parent has an element
+//     child, child is a doctype, or child is not null and a doctype is
+//     following child.
+//  -> element
+//     parent has an element child, child is a doctype, or child is not null and
+//     a doctype is following child.
+//  -> doctype
+//     parent has a doctype child, child is non-null and an element is preceding
+//     child, or child is null and parent has an element child.
+//
+// 6. If parent is a document, and any of the statements below, switched on
+// node, are true, throw a HierarchyRequestError.
+//  -> DocumentFragment node
+//     If node has more than one element child or has a Text node child.
+//     Otherwise, if node has one element child and either parent has an element
+//     child that is not child or a doctype is following child.
+//  -> element
+//     parent has an element child that is not child or a doctype is following
+//     child.
+//  -> doctype
+//     parent has a doctype child that is not child, or an element is preceding
+//     child.
 bool Document::CanAcceptChild(const Node& new_child,
+                              const Node* next,
                               const Node* old_child,
                               ExceptionState& exception_state) const {
+  DCHECK(!(next && old_child));
   if (old_child && old_child->getNodeType() == new_child.getNodeType())
     return true;
 
   int num_doctypes = 0;
   int num_elements = 0;
+  bool has_doctype_after_reference_node = false;
+  bool has_element_after_reference_node = false;
 
   // First, check how many doctypes and elements we have, not counting
   // the child we're about to remove.
+  bool saw_reference_node = false;
   for (Node& child : NodeTraversal::ChildrenOf(*this)) {
-    if (old_child && *old_child == child)
+    if (old_child && *old_child == child) {
+      saw_reference_node = true;
       continue;
+    }
+    if (&child == next)
+      saw_reference_node = true;
 
     switch (child.getNodeType()) {
       case kDocumentTypeNode:
         num_doctypes++;
+        has_doctype_after_reference_node = saw_reference_node;
         break;
       case kElementNode:
         num_elements++;
+        has_element_after_reference_node = saw_reference_node;
         break;
       default:
         break;
@@ -3918,6 +3959,12 @@
           break;
         case kElementNode:
           num_elements++;
+          if (has_doctype_after_reference_node) {
+            exception_state.ThrowDOMException(
+                kHierarchyRequestError,
+                "Can't insert an element before a doctype.");
+            return false;
+          }
           break;
       }
     }
@@ -3938,9 +3985,21 @@
         return true;
       case kDocumentTypeNode:
         num_doctypes++;
+        if (num_elements > 0 && !has_element_after_reference_node) {
+          exception_state.ThrowDOMException(
+              kHierarchyRequestError,
+              "Can't insert a doctype before the root element.");
+          return false;
+        }
         break;
       case kElementNode:
         num_elements++;
+        if (has_doctype_after_reference_node) {
+          exception_state.ThrowDOMException(
+              kHierarchyRequestError,
+              "Can't insert an element before a doctype.");
+          return false;
+        }
         break;
     }
   }
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index b95f82ec..efed3a4 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -766,6 +766,7 @@
   // nodeWillBeRemoved is only safe when removing one node at a time.
   void NodeWillBeRemoved(Node&);
   bool CanAcceptChild(const Node& new_child,
+                      const Node* next,
                       const Node* old_child,
                       ExceptionState&) const;
 
diff --git a/third_party/WebKit/Source/core/mojo/BUILD.gn b/third_party/WebKit/Source/core/mojo/BUILD.gn
index 202d78e..aaa52ac 100644
--- a/third_party/WebKit/Source/core/mojo/BUILD.gn
+++ b/third_party/WebKit/Source/core/mojo/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//mojo/public/tools/bindings/mojom.gni")
 import("//third_party/WebKit/Source/core/core.gni")
 
 blink_core_sources("mojo") {
@@ -23,3 +24,39 @@
     "//services/service_manager/public/cpp",
   ]
 }
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "tests/JsToCppTest.cpp",
+  ]
+
+  data = [
+    "tests/JsToCppTest.js",
+  ]
+
+  configs += [
+    "//third_party/WebKit/Source/core:blink_core_pch",
+    "//third_party/WebKit/Source:config",
+    "//third_party/WebKit/Source:inside_blink",
+  ]
+
+  deps = [
+    ":test_bindings_blink",
+    "//mojo/public/cpp/bindings",
+    "//testing/gtest",
+    "//third_party/WebKit/Source/core:core",
+    "//third_party/WebKit/Source/core:testing",
+  ]
+
+  data_deps = [
+    ":test_bindings",  # For JS bindings: crbug.com/729649.
+    "//mojo/public/js:new_bindings",
+  ]
+}
+
+mojom("test_bindings") {
+  sources = [
+    "tests/JsToCpp.mojom",
+  ]
+}
diff --git a/mojo/edk/js/tests/js_to_cpp.mojom b/third_party/WebKit/Source/core/mojo/tests/JsToCpp.mojom
similarity index 100%
rename from mojo/edk/js/tests/js_to_cpp.mojom
rename to third_party/WebKit/Source/core/mojo/tests/JsToCpp.mojom
diff --git a/third_party/WebKit/Source/core/mojo/tests/JsToCppTest.cpp b/third_party/WebKit/Source/core/mojo/tests/JsToCppTest.cpp
new file mode 100644
index 0000000..2b7ada7a0
--- /dev/null
+++ b/third_party/WebKit/Source/core/mojo/tests/JsToCppTest.cpp
@@ -0,0 +1,435 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "bindings/core/v8/ScriptController.h"
+#include "bindings/core/v8/ScriptSourceCode.h"
+#include "bindings/core/v8/V8BindingForCore.h"
+#include "bindings/core/v8/V8BindingForTesting.h"
+#include "bindings/core/v8/V8ScriptRunner.h"
+#include "core/frame/Settings.h"
+#include "core/mojo/MojoHandle.h"
+#include "core/page/Page.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/wait.h"
+#include "platform/testing/UnitTestHelpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/Source/core/mojo/tests/JsToCpp.mojom-blink.h"
+
+namespace blink {
+namespace {
+
+// Global value updated by some checks to prevent compilers from optimizing
+// reads out of existence.
+uint32_t g_waste_accumulator = 0;
+
+// Negative numbers with different values in each byte, the last of
+// which can survive promotion to double and back.
+const int8_t kExpectedInt8Value = -65;
+const int16_t kExpectedInt16Value = -16961;
+const int32_t kExpectedInt32Value = -1145258561;
+const int64_t kExpectedInt64Value = -77263311946305LL;
+
+// Positive numbers with different values in each byte, the last of
+// which can survive promotion to double and back.
+const uint8_t kExpectedUInt8Value = 65;
+const uint16_t kExpectedUInt16Value = 16961;
+const uint32_t kExpectedUInt32Value = 1145258561;
+const uint64_t kExpectedUInt64Value = 77263311946305LL;
+
+// Double/float values, including special case constants.
+const double kExpectedDoubleVal = 3.14159265358979323846;
+const double kExpectedDoubleInf = std::numeric_limits<double>::infinity();
+const double kExpectedDoubleNan = std::numeric_limits<double>::quiet_NaN();
+const float kExpectedFloatVal = static_cast<float>(kExpectedDoubleVal);
+const float kExpectedFloatInf = std::numeric_limits<float>::infinity();
+const float kExpectedFloatNan = std::numeric_limits<float>::quiet_NaN();
+
+// NaN has the property that it is not equal to itself.
+#define EXPECT_NAN(x) EXPECT_NE(x, x)
+
+String MojoBindingsScriptPath() {
+  String filepath = testing::ExecutableDir();
+  filepath.append("/gen/mojo/public/js/mojo_bindings.js");
+  return filepath;
+}
+
+String TestBindingsScriptPath() {
+  String filepath = testing::ExecutableDir();
+  filepath.append(
+      "/gen/third_party/WebKit/Source/core/mojo/tests/JsToCpp.mojom.js");
+  return filepath;
+}
+
+String TestScriptPath() {
+  String filepath = testing::BlinkRootDir();
+  filepath.append("/Source/core/mojo/tests/JsToCppTest.js");
+  return filepath;
+}
+
+v8::Local<v8::Value> ExecuteScript(const String& script_path,
+                                   LocalFrame& frame) {
+  RefPtr<SharedBuffer> script_src = testing::ReadFromFile(script_path);
+  return frame.GetScriptController().ExecuteScriptInMainWorldAndReturnValue(
+      ScriptSourceCode(String(script_src->Data(), script_src->size())));
+}
+
+void CheckDataPipe(mojo::DataPipeConsumerHandle data_pipe_handle) {
+  const void* buffer = nullptr;
+  unsigned num_bytes = 0;
+  MojoResult result = Wait(data_pipe_handle, MOJO_HANDLE_SIGNAL_READABLE);
+  EXPECT_EQ(MOJO_RESULT_OK, result);
+  result = BeginReadDataRaw(data_pipe_handle, &buffer, &num_bytes,
+                            MOJO_READ_DATA_FLAG_NONE);
+  EXPECT_EQ(MOJO_RESULT_OK, result);
+  EXPECT_EQ(64u, num_bytes);
+  for (unsigned i = 0; i < num_bytes; ++i) {
+    EXPECT_EQ(i, static_cast<unsigned>(static_cast<const char*>(buffer)[i]));
+  }
+  EndReadDataRaw(data_pipe_handle, num_bytes);
+}
+
+void CheckMessagePipe(mojo::MessagePipeHandle message_pipe_handle) {
+  unsigned char buffer[100];
+  uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
+  MojoResult result = Wait(message_pipe_handle, MOJO_HANDLE_SIGNAL_READABLE);
+  EXPECT_EQ(MOJO_RESULT_OK, result);
+  result = ReadMessageRaw(message_pipe_handle, buffer, &buffer_size, 0, 0, 0);
+  EXPECT_EQ(MOJO_RESULT_OK, result);
+  EXPECT_EQ(64u, buffer_size);
+  for (int i = 0; i < 64; ++i) {
+    EXPECT_EQ(255 - i, buffer[i]);
+  }
+}
+
+js_to_cpp::blink::EchoArgsPtr BuildSampleEchoArgs() {
+  auto args = js_to_cpp::blink::EchoArgs::New();
+  args->si64 = kExpectedInt64Value;
+  args->si32 = kExpectedInt32Value;
+  args->si16 = kExpectedInt16Value;
+  args->si8 = kExpectedInt8Value;
+  args->ui64 = kExpectedUInt64Value;
+  args->ui32 = kExpectedUInt32Value;
+  args->ui16 = kExpectedUInt16Value;
+  args->ui8 = kExpectedUInt8Value;
+  args->float_val = kExpectedFloatVal;
+  args->float_inf = kExpectedFloatInf;
+  args->float_nan = kExpectedFloatNan;
+  args->double_val = kExpectedDoubleVal;
+  args->double_inf = kExpectedDoubleInf;
+  args->double_nan = kExpectedDoubleNan;
+  args->name = "coming";
+  args->string_array.emplace(3);
+  (*args->string_array)[0] = "one";
+  (*args->string_array)[1] = "two";
+  (*args->string_array)[2] = "three";
+  return args;
+}
+
+void CheckSampleEchoArgs(const js_to_cpp::blink::EchoArgsPtr& arg) {
+  EXPECT_EQ(kExpectedInt64Value, arg->si64);
+  EXPECT_EQ(kExpectedInt32Value, arg->si32);
+  EXPECT_EQ(kExpectedInt16Value, arg->si16);
+  EXPECT_EQ(kExpectedInt8Value, arg->si8);
+  EXPECT_EQ(kExpectedUInt64Value, arg->ui64);
+  EXPECT_EQ(kExpectedUInt32Value, arg->ui32);
+  EXPECT_EQ(kExpectedUInt16Value, arg->ui16);
+  EXPECT_EQ(kExpectedUInt8Value, arg->ui8);
+  EXPECT_EQ(kExpectedFloatVal, arg->float_val);
+  EXPECT_EQ(kExpectedFloatInf, arg->float_inf);
+  EXPECT_NAN(arg->float_nan);
+  EXPECT_EQ(kExpectedDoubleVal, arg->double_val);
+  EXPECT_EQ(kExpectedDoubleInf, arg->double_inf);
+  EXPECT_NAN(arg->double_nan);
+  EXPECT_EQ(String("coming"), arg->name);
+  EXPECT_EQ(String("one"), (*arg->string_array)[0]);
+  EXPECT_EQ(String("two"), (*arg->string_array)[1]);
+  EXPECT_EQ(String("three"), (*arg->string_array)[2]);
+  CheckDataPipe(arg->data_handle.get());
+  CheckMessagePipe(arg->message_handle.get());
+}
+
+void CheckSampleEchoArgsList(const js_to_cpp::blink::EchoArgsListPtr& list) {
+  if (list.is_null())
+    return;
+  CheckSampleEchoArgs(list->item);
+  CheckSampleEchoArgsList(list->next);
+}
+
+// More forgiving checks are needed in the face of potentially corrupt
+// messages. The values don't matter so long as all accesses are within
+// bounds.
+void CheckCorruptedString(const String& arg) {
+  for (size_t i = 0; i < arg.length(); ++i)
+    g_waste_accumulator += arg[i];
+}
+
+void CheckCorruptedStringArray(const Optional<Vector<String>>& string_array) {
+  if (!string_array)
+    return;
+  for (size_t i = 0; i < string_array->size(); ++i)
+    CheckCorruptedString((*string_array)[i]);
+}
+
+void CheckCorruptedDataPipe(mojo::DataPipeConsumerHandle data_pipe_handle) {
+  unsigned char buffer[100];
+  uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
+  MojoResult result = ReadDataRaw(data_pipe_handle, buffer, &buffer_size,
+                                  MOJO_READ_DATA_FLAG_NONE);
+  if (result != MOJO_RESULT_OK)
+    return;
+  for (uint32_t i = 0; i < buffer_size; ++i)
+    g_waste_accumulator += buffer[i];
+}
+
+void CheckCorruptedMessagePipe(mojo::MessagePipeHandle message_pipe_handle) {
+  unsigned char buffer[100];
+  uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
+  MojoResult result =
+      ReadMessageRaw(message_pipe_handle, buffer, &buffer_size, 0, 0, 0);
+  if (result != MOJO_RESULT_OK)
+    return;
+  for (uint32_t i = 0; i < buffer_size; ++i)
+    g_waste_accumulator += buffer[i];
+}
+
+void CheckCorruptedEchoArgs(const js_to_cpp::blink::EchoArgsPtr& arg) {
+  if (arg.is_null())
+    return;
+  CheckCorruptedString(arg->name);
+  CheckCorruptedStringArray(arg->string_array);
+  if (arg->data_handle.is_valid())
+    CheckCorruptedDataPipe(arg->data_handle.get());
+  if (arg->message_handle.is_valid())
+    CheckCorruptedMessagePipe(arg->message_handle.get());
+}
+
+void CheckCorruptedEchoArgsList(const js_to_cpp::blink::EchoArgsListPtr& list) {
+  if (list.is_null())
+    return;
+  CheckCorruptedEchoArgs(list->item);
+  CheckCorruptedEchoArgsList(list->next);
+}
+
+// Base Provider implementation class. It's expected that tests subclass and
+// override the appropriate Provider functions. When test is done quit the
+// run_loop().
+class CppSideConnection : public js_to_cpp::blink::CppSide {
+ public:
+  CppSideConnection() : mishandled_messages_(0), binding_(this) {}
+  ~CppSideConnection() override {}
+
+  void set_js_side(js_to_cpp::blink::JsSidePtr js_side) {
+    js_side_ = std::move(js_side);
+  }
+  js_to_cpp::blink::JsSide* js_side() { return js_side_.get(); }
+
+  void Bind(mojo::InterfaceRequest<js_to_cpp::blink::CppSide> request) {
+    binding_.Bind(std::move(request));
+    // Keep the pipe open even after validation errors.
+    binding_.EnableTestingMode();
+  }
+
+  // js_to_cpp::CppSide:
+  void StartTest() override { NOTREACHED(); }
+
+  void TestFinished() override { NOTREACHED(); }
+
+  void PingResponse() override { mishandled_messages_ += 1; }
+
+  void EchoResponse(js_to_cpp::blink::EchoArgsListPtr list) override {
+    mishandled_messages_ += 1;
+  }
+
+  void BitFlipResponse(
+      js_to_cpp::blink::EchoArgsListPtr list,
+      js_to_cpp::blink::ForTestingAssociatedPtrInfo not_used) override {
+    mishandled_messages_ += 1;
+  }
+
+  void BackPointerResponse(js_to_cpp::blink::EchoArgsListPtr list) override {
+    mishandled_messages_ += 1;
+  }
+
+ protected:
+  js_to_cpp::blink::JsSidePtr js_side_;
+  int mishandled_messages_;
+  mojo::Binding<js_to_cpp::blink::CppSide> binding_;
+};
+
+// Trivial test to verify a message sent from JS is received.
+class PingCppSideConnection : public CppSideConnection {
+ public:
+  PingCppSideConnection() : got_message_(false) {}
+  ~PingCppSideConnection() override {}
+
+  // js_to_cpp::CppSide:
+  void StartTest() override { js_side_->Ping(); }
+
+  void PingResponse() override {
+    got_message_ = true;
+    testing::ExitRunLoop();
+  }
+
+  bool DidSucceed() { return got_message_ && !mishandled_messages_; }
+
+ private:
+  bool got_message_;
+};
+
+// Test that parameters are passed with correct values.
+class EchoCppSideConnection : public CppSideConnection {
+ public:
+  EchoCppSideConnection() : message_count_(0), termination_seen_(false) {}
+  ~EchoCppSideConnection() override {}
+
+  // js_to_cpp::CppSide:
+  void StartTest() override {
+    js_side_->Echo(kExpectedMessageCount, BuildSampleEchoArgs());
+  }
+
+  void EchoResponse(js_to_cpp::blink::EchoArgsListPtr list) override {
+    message_count_ += 1;
+
+    const js_to_cpp::blink::EchoArgsPtr& special_arg = list->item;
+    EXPECT_EQ(-1, special_arg->si64);
+    EXPECT_EQ(-1, special_arg->si32);
+    EXPECT_EQ(-1, special_arg->si16);
+    EXPECT_EQ(-1, special_arg->si8);
+    EXPECT_EQ(String("going"), special_arg->name);
+    CheckDataPipe(special_arg->data_handle.get());
+    CheckMessagePipe(special_arg->message_handle.get());
+
+    CheckSampleEchoArgsList(list->next);
+  }
+
+  void TestFinished() override {
+    termination_seen_ = true;
+    testing::ExitRunLoop();
+  }
+
+  bool DidSucceed() {
+    return termination_seen_ && !mishandled_messages_ &&
+           message_count_ == kExpectedMessageCount;
+  }
+
+ private:
+  static const int kExpectedMessageCount = 10;
+  int message_count_;
+  bool termination_seen_;
+};
+
+// Test that corrupted messages don't wreak havoc.
+class BitFlipCppSideConnection : public CppSideConnection {
+ public:
+  BitFlipCppSideConnection() : termination_seen_(false) {}
+  ~BitFlipCppSideConnection() override {}
+
+  // js_to_cpp::CppSide:
+  void StartTest() override { js_side_->BitFlip(BuildSampleEchoArgs()); }
+
+  void BitFlipResponse(
+      js_to_cpp::blink::EchoArgsListPtr list,
+      js_to_cpp::blink::ForTestingAssociatedPtrInfo not_used) override {
+    CheckCorruptedEchoArgsList(list);
+  }
+
+  void TestFinished() override {
+    termination_seen_ = true;
+    testing::ExitRunLoop();
+  }
+
+  bool DidSucceed() { return termination_seen_; }
+
+ private:
+  bool termination_seen_;
+};
+
+// Test that severely random messages don't wreak havoc.
+class BackPointerCppSideConnection : public CppSideConnection {
+ public:
+  BackPointerCppSideConnection() : termination_seen_(false) {}
+  ~BackPointerCppSideConnection() override {}
+
+  // js_to_cpp::CppSide:
+  void StartTest() override { js_side_->BackPointer(BuildSampleEchoArgs()); }
+
+  void BackPointerResponse(js_to_cpp::blink::EchoArgsListPtr list) override {
+    CheckCorruptedEchoArgsList(list);
+  }
+
+  void TestFinished() override {
+    termination_seen_ = true;
+    testing::ExitRunLoop();
+  }
+
+  bool DidSucceed() { return termination_seen_; }
+
+ private:
+  bool termination_seen_;
+};
+
+class JsToCppTest : public ::testing::Test {
+ public:
+  void RunTest(CppSideConnection* cpp_side) {
+    js_to_cpp::blink::CppSidePtr cpp_side_ptr;
+    cpp_side->Bind(MakeRequest(&cpp_side_ptr));
+
+    js_to_cpp::blink::JsSidePtr js_side_ptr;
+    auto js_side_request = MakeRequest(&js_side_ptr);
+    js_side_ptr->SetCppSide(std::move(cpp_side_ptr));
+    cpp_side->set_js_side(std::move(js_side_ptr));
+
+    V8TestingScope scope;
+    scope.GetPage().GetSettings().SetScriptEnabled(true);
+    ExecuteScript(MojoBindingsScriptPath(), scope.GetFrame());
+    ExecuteScript(TestBindingsScriptPath(), scope.GetFrame());
+
+    v8::Local<v8::Value> start_fn =
+        ExecuteScript(TestScriptPath(), scope.GetFrame());
+    ASSERT_FALSE(start_fn.IsEmpty());
+    ASSERT_TRUE(start_fn->IsFunction());
+    v8::Local<v8::Object> global_proxy = scope.GetContext()->Global();
+    v8::Local<v8::Value> args[1] = {
+        ToV8(MojoHandle::Create(
+                 mojo::ScopedHandle::From(js_side_request.PassMessagePipe())),
+             global_proxy, scope.GetIsolate())};
+    V8ScriptRunner::CallFunction(
+        start_fn.As<v8::Function>(), scope.GetExecutionContext(), global_proxy,
+        WTF_ARRAY_LENGTH(args), args, scope.GetIsolate());
+    testing::EnterRunLoop();
+  }
+};
+
+TEST_F(JsToCppTest, Ping) {
+  PingCppSideConnection cpp_side_connection;
+  RunTest(&cpp_side_connection);
+  EXPECT_TRUE(cpp_side_connection.DidSucceed());
+}
+
+TEST_F(JsToCppTest, Echo) {
+  EchoCppSideConnection cpp_side_connection;
+  RunTest(&cpp_side_connection);
+  EXPECT_TRUE(cpp_side_connection.DidSucceed());
+}
+
+TEST_F(JsToCppTest, BitFlip) {
+  // These tests generate a lot of expected validation errors. Suppress logging.
+  mojo::internal::ScopedSuppressValidationErrorLoggingForTests log_suppression;
+
+  BitFlipCppSideConnection cpp_side_connection;
+  RunTest(&cpp_side_connection);
+  EXPECT_TRUE(cpp_side_connection.DidSucceed());
+}
+
+TEST_F(JsToCppTest, BackPointer) {
+  // These tests generate a lot of expected validation errors. Suppress logging.
+  mojo::internal::ScopedSuppressValidationErrorLoggingForTests log_suppression;
+
+  BackPointerCppSideConnection cpp_side_connection;
+  RunTest(&cpp_side_connection);
+  EXPECT_TRUE(cpp_side_connection.DidSucceed());
+}
+
+}  // namespace
+}  // namespace blink
diff --git a/mojo/edk/js/tests/js_to_cpp_tests.js b/third_party/WebKit/Source/core/mojo/tests/JsToCppTest.js
similarity index 74%
rename from mojo/edk/js/tests/js_to_cpp_tests.js
rename to third_party/WebKit/Source/core/mojo/tests/JsToCppTest.js
index 6ffce09..139687a 100644
--- a/mojo/edk/js/tests/js_to_cpp_tests.js
+++ b/third_party/WebKit/Source/core/mojo/tests/JsToCppTest.js
@@ -2,26 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-define('mojo/edk/js/tests/js_to_cpp_tests', [
-  'console',
-  'mojo/edk/js/tests/js_to_cpp.mojom',
-  'mojo/public/js/bindings',
-  'mojo/public/js/connector',
-  'mojo/public/js/core',
-], function (console, jsToCpp, bindings, connector, core) {
+(function () {
   var retainedJsSide;
-  var retainedJsSideStub;
   var sampleData;
   var sampleMessage;
   var BAD_VALUE = 13;
   var DATA_PIPE_PARAMS = {
-    flags: core.CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
     elementNumBytes: 1,
     capacityNumBytes: 64
   };
 
   function JsSideConnection() {
-    this.binding = new bindings.Binding(jsToCpp.JsSide, this);
+    this.binding = new mojo.Binding(jsToCpp.JsSide, this);
   }
 
   JsSideConnection.prototype.setCppSide = function(cppSide) {
@@ -55,13 +47,13 @@
       arg.si8 = BAD_VALUE;
 
     for (i = 0; i < numIterations; ++i) {
-      dataPipe1 = core.createDataPipe(DATA_PIPE_PARAMS);
-      dataPipe2 = core.createDataPipe(DATA_PIPE_PARAMS);
-      messagePipe1 = core.createMessagePipe();
-      messagePipe2 = core.createMessagePipe();
+      dataPipe1 = Mojo.createDataPipe(DATA_PIPE_PARAMS);
+      dataPipe2 = Mojo.createDataPipe(DATA_PIPE_PARAMS);
+      messagePipe1 = Mojo.createMessagePipe();
+      messagePipe2 = Mojo.createMessagePipe();
 
-      arg.data_handle = dataPipe1.consumerHandle;
-      arg.message_handle = messagePipe1.handle1;
+      arg.dataHandle = dataPipe1.consumer;
+      arg.messageHandle = messagePipe1.handle1;
 
       specialArg = new jsToCpp.EchoArgs();
       specialArg.si64 = -1;
@@ -69,20 +61,19 @@
       specialArg.si16 = -1;
       specialArg.si8 = -1;
       specialArg.name = 'going';
-      specialArg.data_handle = dataPipe2.consumerHandle;
-      specialArg.message_handle = messagePipe2.handle1;
+      specialArg.dataHandle = dataPipe2.consumer;
+      specialArg.messageHandle = messagePipe2.handle1;
 
       writeDataPipe(dataPipe1, sampleData);
       writeDataPipe(dataPipe2, sampleData);
       writeMessagePipe(messagePipe1, sampleMessage);
       writeMessagePipe(messagePipe2, sampleMessage);
-
       this.cppSide_.echoResponse(createEchoArgsList(specialArg, arg));
 
-      core.close(dataPipe1.producerHandle);
-      core.close(dataPipe2.producerHandle);
-      core.close(messagePipe1.handle0);
-      core.close(messagePipe2.handle0);
+      dataPipe1.producer.close();
+      dataPipe2.producer.close();
+      messagePipe1.handle0.close();
+      messagePipe2.handle0.close();
     }
     this.cppSide_.testFinished();
   };
@@ -91,7 +82,7 @@
     var iteration = 0;
     var dataPipe;
     var messagePipe;
-    var proto = connector.Connector.prototype;
+    var proto = mojo.internal.Connector.prototype;
     var stopSignalled = false;
 
     proto.realAccept = proto.accept;
@@ -110,13 +101,13 @@
     };
 
     while (!stopSignalled) {
-      messagePipe = core.createMessagePipe();
+      messagePipe = Mojo.createMessagePipe();
       writeMessagePipe(messagePipe, sampleMessage);
-      arg.message_handle = messagePipe.handle1;
+      arg.messageHandle = messagePipe.handle1;
 
       this.cppSide_.bitFlipResponse(createEchoArgsList(arg), null);
 
-      core.close(messagePipe.handle0);
+      messagePipe.handle0.close();
       iteration += 1;
     }
 
@@ -129,7 +120,7 @@
     var iteration = 0;
     var dataPipe;
     var messagePipe;
-    var proto = connector.Connector.prototype;
+    var proto = mojo.internal.Connector.prototype;
     var stopSignalled = false;
 
     proto.realAccept = proto.accept;
@@ -146,13 +137,13 @@
     };
 
     while (!stopSignalled) {
-      messagePipe = core.createMessagePipe();
+      messagePipe = Mojo.createMessagePipe();
       writeMessagePipe(messagePipe, sampleMessage);
-      arg.message_handle = messagePipe.handle1;
+      arg.messageHandle = messagePipe.handle1;
 
       this.cppSide_.backPointerResponse(createEchoArgsList(arg));
 
-      core.close(messagePipe.handle0);
+      messagePipe.handle0.close();
       iteration += 1;
     }
 
@@ -162,10 +153,9 @@
   };
 
   function writeDataPipe(pipe, data) {
-    var writeResult = core.writeData(
-      pipe.producerHandle, data, core.WRITE_DATA_FLAG_ALL_OR_NONE);
+    var writeResult = pipe.producer.writeData(data);
 
-    if (writeResult.result != core.RESULT_OK) {
+    if (writeResult.result != Mojo.RESULT_OK) {
       console.log('ERROR: Data pipe write result was ' + writeResult.result);
       return false;
     }
@@ -177,8 +167,8 @@
   }
 
   function writeMessagePipe(pipe, arrayBuffer) {
-    var result = core.writeMessage(pipe.handle0, arrayBuffer, [], 0);
-    if (result != core.RESULT_OK) {
+    var result = pipe.handle0.writeMessage(arrayBuffer, []);
+    if (result != Mojo.RESULT_OK) {
       console.log('ERROR: Message pipe write result was ' + result);
       return false;
     }
@@ -212,4 +202,4 @@
     retainedJsSide = new JsSideConnection;
     retainedJsSide.binding.bind(jsSideRequestHandle);
   };
-});
+})();
diff --git a/third_party/WebKit/Source/core/mojo/tests/OWNERS b/third_party/WebKit/Source/core/mojo/tests/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/third_party/WebKit/Source/core/mojo/tests/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
index 9c3ea0f..f165b66 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
@@ -711,6 +711,19 @@
 UI._windowFocused = function(document, event) {
   if (event.target.document.nodeType === Node.DOCUMENT_NODE)
     document.body.classList.remove('inactive');
+  UI._keyboardFocus = true;
+  var listener = () => {
+    var activeElement = document.deepActiveElement();
+    if (activeElement)
+      activeElement.removeAttribute('data-keyboard-focus');
+    UI._keyboardFocus = false;
+  };
+  document.defaultView.requestAnimationFrame(() => {
+    UI._keyboardFocus = false;
+    document.removeEventListener('mousedown', listener, true);
+  });
+  document.addEventListener('mousedown', listener, true);
+
 };
 
 /**
diff --git a/third_party/WebKit/Source/platform/instrumentation/tracing/web_process_memory_dump_test.cc b/third_party/WebKit/Source/platform/instrumentation/tracing/web_process_memory_dump_test.cc
index 94dfc59..a3e3353 100644
--- a/third_party/WebKit/Source/platform/instrumentation/tracing/web_process_memory_dump_test.cc
+++ b/third_party/WebKit/Source/platform/instrumentation/tracing/web_process_memory_dump_test.cc
@@ -115,10 +115,12 @@
   auto wmad4 = wpmd1->CreateMemoryAllocatorDump("1/4");
   wpmd1->AddOwnershipEdge(wmad4->Guid(), guid);
   auto allocator_dumps_edges =
-      wpmd1->process_memory_dump()->allocator_dumps_edges();
+      wpmd1->process_memory_dump()->allocator_dumps_edges_for_testing();
   ASSERT_EQ(1u, allocator_dumps_edges.size());
-  ASSERT_EQ(wmad4->Guid(), allocator_dumps_edges[0].source.ToUint64());
-  ASSERT_EQ(guid, allocator_dumps_edges[0].target.ToUint64());
+  auto it = allocator_dumps_edges.begin();
+  ASSERT_NE(allocator_dumps_edges.end(), it);
+  ASSERT_EQ(wmad4->Guid(), it->first.ToUint64());
+  ASSERT_EQ(guid, it->second.target.ToUint64());
 
   // Check that createDumpAdapterForSkia() works.
   auto skia_trace_memory_dump = wpmd1->CreateDumpAdapterForSkia("1/skia");
diff --git a/third_party/WebKit/Source/platform/testing/UnitTestHelpers.cpp b/third_party/WebKit/Source/platform/testing/UnitTestHelpers.cpp
index d0e10b6..2f6d1541 100644
--- a/third_party/WebKit/Source/platform/testing/UnitTestHelpers.cpp
+++ b/third_party/WebKit/Source/platform/testing/UnitTestHelpers.cpp
@@ -89,6 +89,12 @@
   return FilePathToWebString(BlinkRootFilePath());
 }
 
+String ExecutableDir() {
+  base::FilePath path;
+  base::PathService::Get(base::DIR_EXE, &path);
+  return FilePathToWebString(base::MakeAbsoluteFilePath(path));
+}
+
 String WebTestDataPath(const String& relative_path) {
   return FilePathToWebString(
       BlinkRootFilePath()
diff --git a/third_party/WebKit/Source/platform/testing/UnitTestHelpers.h b/third_party/WebKit/Source/platform/testing/UnitTestHelpers.h
index 3b94f961..6f18cad 100644
--- a/third_party/WebKit/Source/platform/testing/UnitTestHelpers.h
+++ b/third_party/WebKit/Source/platform/testing/UnitTestHelpers.h
@@ -52,6 +52,9 @@
 // /src/third_party/WebKit.
 String BlinkRootDir();
 
+// Returns directory containing the current executable as absolute path.
+String ExecutableDir();
+
 // Returns test data absolute path for webkit_unit_tests, i.e.
 // <blinkRootDir>/Source/web/tests/data/<relativePath>.
 // It returns the top web test directory if |relativePath| was not specified.
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
index 3a276ad..a03ded1d 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
@@ -259,17 +259,12 @@
       inspected_frames_(
           InspectedFrames::Create(web_local_frame_impl_->GetFrame())),
       resource_container_(new InspectorResourceContainer(inspected_frames_)),
-      page_agent_(nullptr),
-      network_agent_(nullptr),
-      layer_tree_agent_(nullptr),
-      tracing_agent_(nullptr),
-      trace_events_agent_(new InspectorTraceEvents()),
-      overlay_agent_(nullptr),
+      trace_events_(new InspectorTraceEvents()),
       include_view_agents_(include_view_agents),
       layer_tree_id_(0) {
   DCHECK(IsMainThread());
   DCHECK(web_local_frame_impl_->GetFrame());
-  probe_sink_->addInspectorTraceEvents(trace_events_agent_);
+  probe_sink_->addInspectorTraceEvents(trace_events_);
 }
 
 WebDevToolsAgentImpl::~WebDevToolsAgentImpl() {
@@ -282,138 +277,149 @@
   visitor->Trace(resource_content_loader_);
   visitor->Trace(inspected_frames_);
   visitor->Trace(resource_container_);
-  visitor->Trace(page_agent_);
-  visitor->Trace(network_agent_);
-  visitor->Trace(layer_tree_agent_);
-  visitor->Trace(tracing_agent_);
-  visitor->Trace(trace_events_agent_);
-  visitor->Trace(overlay_agent_);
-  visitor->Trace(session_);
+  visitor->Trace(trace_events_);
+  visitor->Trace(page_agents_);
+  visitor->Trace(network_agents_);
+  visitor->Trace(layer_tree_agents_);
+  visitor->Trace(tracing_agents_);
+  visitor->Trace(overlay_agents_);
+  visitor->Trace(sessions_);
 }
 
 void WebDevToolsAgentImpl::WillBeDestroyed() {
   DCHECK(web_local_frame_impl_->GetFrame());
   DCHECK(inspected_frames_->Root()->View());
-  probe_sink_->removeInspectorTraceEvents(trace_events_agent_);
-  trace_events_agent_ = nullptr;
-  if (session_)
-    Detach(session_->SessionId());
+  probe_sink_->removeInspectorTraceEvents(trace_events_);
+  trace_events_ = nullptr;
+
+  Vector<int> session_ids;
+  for (int session_id : sessions_.Keys())
+    session_ids.push_back(session_id);
+  for (int session_id : session_ids)
+    Detach(session_id);
+
   resource_content_loader_->Dispose();
   client_ = nullptr;
 }
 
-void WebDevToolsAgentImpl::InitializeSession(int session_id,
-                                             const String& host_id,
-                                             String* state) {
+InspectorSession* WebDevToolsAgentImpl::InitializeSession(int session_id,
+                                                          const String& host_id,
+                                                          String* state) {
   DCHECK(client_);
   ClientMessageLoopAdapter::EnsureMainThreadDebuggerCreated(client_);
   MainThreadDebugger* main_thread_debugger = MainThreadDebugger::Instance();
   v8::Isolate* isolate = V8PerIsolateData::MainThreadIsolate();
 
-  session_ = new InspectorSession(
+  InspectorSession* session = new InspectorSession(
       this, probe_sink_.Get(), session_id,
       main_thread_debugger->GetV8Inspector(),
       main_thread_debugger->ContextGroupId(inspected_frames_->Root()), state);
 
   InspectorDOMAgent* dom_agent = new InspectorDOMAgent(
-      isolate, inspected_frames_.Get(), session_->V8Session());
-  session_->Append(dom_agent);
+      isolate, inspected_frames_.Get(), session->V8Session());
+  session->Append(dom_agent);
 
   InspectorLayerTreeAgent* layer_tree_agent =
       InspectorLayerTreeAgent::Create(inspected_frames_.Get());
-  layer_tree_agent_ = layer_tree_agent;
-  session_->Append(layer_tree_agent);
+  layer_tree_agents_.Set(session_id, layer_tree_agent);
+  session->Append(layer_tree_agent);
 
   InspectorNetworkAgent* network_agent =
       InspectorNetworkAgent::Create(inspected_frames_.Get());
-  network_agent_ = network_agent;
-  session_->Append(network_agent);
+  network_agents_.Set(session_id, network_agent);
+  session->Append(network_agent);
 
   InspectorCSSAgent* css_agent = InspectorCSSAgent::Create(
-      dom_agent, inspected_frames_.Get(), network_agent_,
+      dom_agent, inspected_frames_.Get(), network_agent,
       resource_content_loader_.Get(), resource_container_.Get());
-  session_->Append(css_agent);
+  session->Append(css_agent);
 
-  session_->Append(new InspectorAnimationAgent(
-      inspected_frames_.Get(), css_agent, session_->V8Session()));
+  session->Append(new InspectorAnimationAgent(inspected_frames_.Get(),
+                                              css_agent, session->V8Session()));
 
-  session_->Append(InspectorMemoryAgent::Create());
+  session->Append(InspectorMemoryAgent::Create());
 
-  session_->Append(
+  session->Append(
       InspectorApplicationCacheAgent::Create(inspected_frames_.Get()));
 
-  session_->Append(new InspectorIndexedDBAgent(inspected_frames_.Get(),
-                                               session_->V8Session()));
+  session->Append(new InspectorIndexedDBAgent(inspected_frames_.Get(),
+                                              session->V8Session()));
 
   InspectorWorkerAgent* worker_agent =
       new InspectorWorkerAgent(inspected_frames_.Get());
-  session_->Append(worker_agent);
+  session->Append(worker_agent);
 
   InspectorTracingAgent* tracing_agent = InspectorTracingAgent::Create(
       this, worker_agent, inspected_frames_.Get());
-  tracing_agent_ = tracing_agent;
-  session_->Append(tracing_agent);
+  tracing_agents_.Set(session_id, tracing_agent);
+  session->Append(tracing_agent);
 
-  session_->Append(
-      new InspectorDOMDebuggerAgent(isolate, dom_agent, session_->V8Session()));
+  session->Append(
+      new InspectorDOMDebuggerAgent(isolate, dom_agent, session->V8Session()));
 
-  session_->Append(InspectorInputAgent::Create(inspected_frames_.Get()));
+  session->Append(InspectorInputAgent::Create(inspected_frames_.Get()));
 
   InspectorPageAgent* page_agent = InspectorPageAgent::Create(
       inspected_frames_.Get(), this, resource_content_loader_.Get(),
-      session_->V8Session());
-  page_agent_ = page_agent;
-  session_->Append(page_agent);
+      session->V8Session());
+  page_agents_.Set(session_id, page_agent);
+  session->Append(page_agent);
 
-  session_->Append(new InspectorLogAgent(
+  session->Append(new InspectorLogAgent(
       &inspected_frames_->Root()->GetPage()->GetConsoleMessageStorage(),
       inspected_frames_->Root()->GetPerformanceMonitor()));
 
-  session_->Append(
-      new DeviceOrientationInspectorAgent(inspected_frames_.Get()));
+  session->Append(new DeviceOrientationInspectorAgent(inspected_frames_.Get()));
 
   InspectorOverlayAgent* overlay_agent =
       new InspectorOverlayAgent(web_local_frame_impl_, inspected_frames_.Get(),
-                                session_->V8Session(), dom_agent);
-  overlay_agent_ = overlay_agent;
-  session_->Append(overlay_agent);
+                                session->V8Session(), dom_agent);
+  overlay_agents_.Set(session_id, overlay_agent);
+  session->Append(overlay_agent);
 
-  tracing_agent_->SetLayerTreeId(layer_tree_id_);
-  network_agent_->SetHostId(host_id);
+  tracing_agent->SetLayerTreeId(layer_tree_id_);
+  network_agent->SetHostId(host_id);
 
   if (include_view_agents_) {
     // TODO(dgozman): we should actually pass the view instead of frame, but
     // during remote->local transition we cannot access mainFrameImpl() yet, so
     // we have to store the frame which will become the main frame later.
-    session_->Append(
+    session->Append(
         InspectorEmulationAgent::Create(web_local_frame_impl_, this));
     // TODO(dgozman): migrate each of the following agents to frame once module
     // is ready.
     Page* page = web_local_frame_impl_->ViewImpl()->GetPage();
-    session_->Append(InspectorDatabaseAgent::Create(page));
-    session_->Append(new InspectorAccessibilityAgent(page, dom_agent));
-    session_->Append(InspectorDOMStorageAgent::Create(page));
-    session_->Append(InspectorCacheStorageAgent::Create());
+    session->Append(InspectorDatabaseAgent::Create(page));
+    session->Append(new InspectorAccessibilityAgent(page, dom_agent));
+    session->Append(InspectorDOMStorageAgent::Create(page));
+    session->Append(InspectorCacheStorageAgent::Create());
   }
 
-  Platform::Current()->CurrentThread()->AddTaskObserver(this);
+  if (!sessions_.size())
+    Platform::Current()->CurrentThread()->AddTaskObserver(this);
+
+  sessions_.Set(session_id, session);
+  return session;
 }
 
-void WebDevToolsAgentImpl::DestroySession() {
-  overlay_agent_.Clear();
-  tracing_agent_.Clear();
-  layer_tree_agent_.Clear();
-  network_agent_.Clear();
-  page_agent_.Clear();
+void WebDevToolsAgentImpl::DestroySession(int session_id) {
+  overlay_agents_.erase(session_id);
+  tracing_agents_.erase(session_id);
+  layer_tree_agents_.erase(session_id);
+  network_agents_.erase(session_id);
+  page_agents_.erase(session_id);
 
-  session_->Dispose();
-  session_.Clear();
+  auto session_it = sessions_.find(session_id);
+  DCHECK(session_it != sessions_.end());
+  session_it->value->Dispose();
+  sessions_.erase(session_it);
 
-  Platform::Current()->CurrentThread()->RemoveTaskObserver(this);
+  if (!sessions_.size())
+    Platform::Current()->CurrentThread()->RemoveTaskObserver(this);
 }
 
 void WebDevToolsAgentImpl::Attach(const WebString& host_id, int session_id) {
-  if (Attached())
+  if (!session_id || sessions_.find(session_id) != sessions_.end())
     return;
   InitializeSession(session_id, host_id, nullptr);
 }
@@ -421,17 +427,17 @@
 void WebDevToolsAgentImpl::Reattach(const WebString& host_id,
                                     int session_id,
                                     const WebString& saved_state) {
-  if (Attached())
+  if (!session_id || sessions_.find(session_id) != sessions_.end())
     return;
   String state = saved_state;
-  InitializeSession(session_id, host_id, &state);
-  session_->Restore();
+  InspectorSession* session = InitializeSession(session_id, host_id, &state);
+  session->Restore();
 }
 
 void WebDevToolsAgentImpl::Detach(int session_id) {
-  if (!Attached() || session_id != session_->SessionId())
+  if (!session_id || sessions_.find(session_id) == sessions_.end())
     return;
-  DestroySession();
+  DestroySession(session_id);
 }
 
 void WebDevToolsAgentImpl::ContinueProgram() {
@@ -441,39 +447,45 @@
 void WebDevToolsAgentImpl::DidCommitLoadForLocalFrame(LocalFrame* frame) {
   resource_container_->DidCommitLoadForLocalFrame(frame);
   resource_content_loader_->DidCommitLoadForLocalFrame(frame);
-  if (session_)
-    session_->DidCommitLoadForLocalFrame(frame);
+  for (auto& it : sessions_)
+    it.value->DidCommitLoadForLocalFrame(frame);
 }
 
 void WebDevToolsAgentImpl::DidStartProvisionalLoad(LocalFrame* frame) {
-  if (session_ && inspected_frames_->Root() == frame)
-    session_->V8Session()->resume();
+  if (inspected_frames_->Root() == frame) {
+    for (auto& it : sessions_)
+      it.value->V8Session()->resume();
+  }
 }
 
 bool WebDevToolsAgentImpl::ScreencastEnabled() {
-  return page_agent_ && page_agent_->ScreencastEnabled();
+  for (auto& it : page_agents_) {
+    if (it.value->ScreencastEnabled())
+      return true;
+  }
+  return false;
 }
 
 void WebDevToolsAgentImpl::WillAddPageOverlay(const GraphicsLayer* layer) {
-  if (layer_tree_agent_)
-    layer_tree_agent_->WillAddPageOverlay(layer);
+  for (auto& it : layer_tree_agents_)
+    it.value->WillAddPageOverlay(layer);
 }
 
 void WebDevToolsAgentImpl::DidRemovePageOverlay(const GraphicsLayer* layer) {
-  if (layer_tree_agent_)
-    layer_tree_agent_->DidRemovePageOverlay(layer);
+  for (auto& it : layer_tree_agents_)
+    it.value->DidRemovePageOverlay(layer);
 }
 
 void WebDevToolsAgentImpl::RootLayerCleared() {
-  if (tracing_agent_)
-    tracing_agent_->RootLayerCleared();
+  for (auto& it : tracing_agents_)
+    it.value->RootLayerCleared();
 }
 
 void WebDevToolsAgentImpl::LayerTreeViewChanged(
     WebLayerTreeView* layer_tree_view) {
   layer_tree_id_ = layer_tree_view ? layer_tree_view->LayerTreeId() : 0;
-  if (tracing_agent_)
-    tracing_agent_->SetLayerTreeId(layer_tree_id_);
+  for (auto& it : tracing_agents_)
+    it.value->SetLayerTreeId(layer_tree_id_);
 }
 
 void WebDevToolsAgentImpl::EnableTracing(const String& category_filter) {
@@ -487,13 +499,13 @@
 }
 
 void WebDevToolsAgentImpl::ShowReloadingBlanket() {
-  if (overlay_agent_)
-    overlay_agent_->ShowReloadingBlanket();
+  for (auto& it : overlay_agents_)
+    it.value->ShowReloadingBlanket();
 }
 
 void WebDevToolsAgentImpl::HideReloadingBlanket() {
-  if (overlay_agent_)
-    overlay_agent_->HideReloadingBlanket();
+  for (auto& it : overlay_agents_)
+    it.value->HideReloadingBlanket();
 }
 
 void WebDevToolsAgentImpl::SetCPUThrottlingRate(double rate) {
@@ -517,17 +529,23 @@
 void WebDevToolsAgentImpl::DispatchMessageFromFrontend(int session_id,
                                                        const String& method,
                                                        const String& message) {
-  if (!Attached() || session_id != session_->SessionId())
+  if (!session_id)
+    return;
+  auto session_it = sessions_.find(session_id);
+  if (session_it == sessions_.end())
     return;
   InspectorTaskRunner::IgnoreInterruptsScope scope(
       MainThreadDebugger::Instance()->TaskRunner());
-  session_->DispatchProtocolMessage(method, message);
+  session_it->value->DispatchProtocolMessage(method, message);
 }
 
 void WebDevToolsAgentImpl::InspectElementAt(
     int session_id,
     const WebPoint& point_in_root_frame) {
-  if (!overlay_agent_ || !session_ || session_->SessionId() != session_id)
+  if (!session_id)
+    return;
+  auto agent_it = overlay_agents_.find(session_id);
+  if (agent_it == overlay_agents_.end())
     return;
   HitTestRequest::HitTestRequestType hit_type =
       HitTestRequest::kMove | HitTestRequest::kReadOnly |
@@ -547,7 +565,7 @@
   Node* node = result.InnerNode();
   if (!node && web_local_frame_impl_->GetFrame()->GetDocument())
     node = web_local_frame_impl_->GetFrame()->GetDocument()->documentElement();
-  overlay_agent_->Inspect(node);
+  agent_it->value->Inspect(node);
 }
 
 void WebDevToolsAgentImpl::FailedToRequestDevTools() {
@@ -564,8 +582,8 @@
 }
 
 void WebDevToolsAgentImpl::PageLayoutInvalidated(bool resized) {
-  if (overlay_agent_)
-    overlay_agent_->PageLayoutInvalidated(resized);
+  for (auto& it : overlay_agents_)
+    it.value->PageLayoutInvalidated(resized);
 }
 
 void WebDevToolsAgentImpl::WaitForCreateWindow(LocalFrame* frame) {
@@ -578,37 +596,41 @@
 
 WebString WebDevToolsAgentImpl::EvaluateInWebInspectorOverlay(
     const WebString& script) {
-  if (!overlay_agent_)
-    return WebString();
-
-  return overlay_agent_->EvaluateInOverlayForTest(script);
+  WebString result;
+  for (auto& it : overlay_agents_)
+    result = it.value->EvaluateInOverlayForTest(script);
+  return result;
 }
 
 void WebDevToolsAgentImpl::PaintOverlay() {
-  if (overlay_agent_)
-    overlay_agent_->PaintOverlay();
+  for (auto& it : overlay_agents_)
+    it.value->PaintOverlay();
 }
 
 void WebDevToolsAgentImpl::LayoutOverlay() {
-  if (overlay_agent_)
-    overlay_agent_->LayoutOverlay();
+  for (auto& it : overlay_agents_)
+    it.value->LayoutOverlay();
 }
 
 bool WebDevToolsAgentImpl::HandleInputEvent(const WebInputEvent& event) {
-  if (overlay_agent_)
-    return overlay_agent_->HandleInputEvent(event);
+  for (auto& it : overlay_agents_) {
+    if (it.value->HandleInputEvent(event))
+      return true;
+  }
   return false;
 }
 
 bool WebDevToolsAgentImpl::CacheDisabled() {
-  if (!network_agent_)
-    return false;
-  return network_agent_->CacheDisabled();
+  for (auto& it : network_agents_) {
+    if (it.value->CacheDisabled())
+      return true;
+  }
+  return false;
 }
 
 void WebDevToolsAgentImpl::FlushProtocolNotifications() {
-  if (session_)
-    session_->flushProtocolNotifications();
+  for (auto& it : sessions_)
+    it.value->flushProtocolNotifications();
 }
 
 void WebDevToolsAgentImpl::WillProcessTask() {
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
index 3d04b7b..5cb35e1 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
@@ -132,8 +132,10 @@
   void WillProcessTask() override;
   void DidProcessTask() override;
 
-  void InitializeSession(int session_id, const String& host_id, String* state);
-  void DestroySession();
+  InspectorSession* InitializeSession(int session_id,
+                                      const String& host_id,
+                                      String* state);
+  void DestroySession(int session_id);
   void DispatchMessageFromFrontend(int session_id,
                                    const String& method,
                                    const String& message);
@@ -143,7 +145,7 @@
       int session_id,
       std::unique_ptr<WebDevToolsAgent::MessageDescriptor>);
 
-  bool Attached() const { return session_.Get(); }
+  bool Attached() const { return !!sessions_.size(); }
 
   WebDevToolsAgentClient* client_;
   Member<WebLocalFrameBase> web_local_frame_impl_;
@@ -152,15 +154,15 @@
   Member<InspectorResourceContentLoader> resource_content_loader_;
   Member<InspectedFrames> inspected_frames_;
   Member<InspectorResourceContainer> resource_container_;
+  Member<InspectorTraceEvents> trace_events_;
 
-  Member<InspectorPageAgent> page_agent_;
-  Member<InspectorNetworkAgent> network_agent_;
-  Member<InspectorLayerTreeAgent> layer_tree_agent_;
-  Member<InspectorTracingAgent> tracing_agent_;
-  Member<InspectorTraceEvents> trace_events_agent_;
-  Member<InspectorOverlayAgent> overlay_agent_;
+  HeapHashMap<int, Member<InspectorPageAgent>> page_agents_;
+  HeapHashMap<int, Member<InspectorNetworkAgent>> network_agents_;
+  HeapHashMap<int, Member<InspectorLayerTreeAgent>> layer_tree_agents_;
+  HeapHashMap<int, Member<InspectorTracingAgent>> tracing_agents_;
+  HeapHashMap<int, Member<InspectorOverlayAgent>> overlay_agents_;
 
-  Member<InspectorSession> session_;
+  HeapHashMap<int, Member<InspectorSession>> sessions_;
   bool include_view_agents_;
   int layer_tree_id_;
 };
diff --git a/tools/determinism/deterministic_build_whitelist.pyl b/tools/determinism/deterministic_build_whitelist.pyl
index 5721b9d..c9c4472 100644
--- a/tools/determinism/deterministic_build_whitelist.pyl
+++ b/tools/determinism/deterministic_build_whitelist.pyl
@@ -119,7 +119,6 @@
     'message_center_unittests',
     'midi_unittests',
     'mojo_common_unittests',
-    'mojo_js_integration_tests',
     'mojo_js_unittests',
     'mojo_public_bindings_unittests',
     'mojo_public_system_unittests',
@@ -276,7 +275,6 @@
     'midi_unittests.exe',
     'mini_installer.exe',
     'mksnapshot.exe',
-    'mojo_js_integration_tests.exe',
     'mojo_js_unittests.exe',
     'mojo_message_pipe_perftests.exe',
     'mojo_public_bindings_perftests.exe',
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index 25abc65..090fabd 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -100,9 +100,6 @@
     "includes": [11940],
     "structures": [11950],
   },
-  "chrome/browser/resources/options_test_resources.grd": {
-    "structures": [12000],
-  },
   "chrome/browser/resources/password_manager_internals_resources.grd": {
     "includes": [12010],
   },
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index a246254..7dd1f1d 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -10799,6 +10799,13 @@
   </description>
 </action>
 
+<action name="MobileWebsiteSettingsOpenedFromVR">
+  <owner>ymalik@chromium.org</owner>
+  <description>
+    Page Info opened via the toolbar page info (i.e. https lock) icon in VR.
+  </description>
+</action>
+
 <action name="MostVisited0">
   <obsolete>No longer recorded.</obsolete>
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a98b41e..67e489f 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -37224,6 +37224,7 @@
 <enum name="VRUnsupportedMode" type="int">
   <int value="0" label="Unhandled code point in URL"/>
   <int value="1" label="Could not elide URL"/>
+  <int value="2" label="Unhandled PageInfo"/>
 </enum>
 
 <enum name="VRViewerType" type="int">
diff --git a/ui/events/devices/mojo/BUILD.gn b/ui/events/devices/mojo/BUILD.gn
index cfdbf86..fe65d7d1 100644
--- a/ui/events/devices/mojo/BUILD.gn
+++ b/ui/events/devices/mojo/BUILD.gn
@@ -22,7 +22,4 @@
   public_deps = [
     ":mojo",
   ]
-
-  # TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
-  use_once_callback = false
 }
diff --git a/ui/events/devices/mojo/device_struct_traits_unittest.cc b/ui/events/devices/mojo/device_struct_traits_unittest.cc
index 04ed725..c47a52f1 100644
--- a/ui/events/devices/mojo/device_struct_traits_unittest.cc
+++ b/ui/events/devices/mojo/device_struct_traits_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/files/file_path.h"
 #include "base/message_loop/message_loop.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
@@ -28,14 +30,13 @@
  private:
   // mojom::DeviceStructTraitsTest:
   void EchoInputDevice(const InputDevice& in,
-                       const EchoInputDeviceCallback& callback) override {
-    callback.Run(in);
+                       EchoInputDeviceCallback callback) override {
+    std::move(callback).Run(in);
   }
 
-  void EchoTouchscreenDevice(
-      const TouchscreenDevice& in,
-      const EchoTouchscreenDeviceCallback& callback) override {
-    callback.Run(in);
+  void EchoTouchscreenDevice(const TouchscreenDevice& in,
+                             EchoTouchscreenDeviceCallback callback) override {
+    std::move(callback).Run(in);
   }
 
   base::MessageLoop loop_;  // A MessageLoop is needed for mojo IPC to work.
diff --git a/ui/events/mojo/BUILD.gn b/ui/events/mojo/BUILD.gn
index 3015a85d..34b89eb 100644
--- a/ui/events/mojo/BUILD.gn
+++ b/ui/events/mojo/BUILD.gn
@@ -26,7 +26,4 @@
   public_deps = [
     ":interfaces",
   ]
-
-  # TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
-  use_once_callback = false
 }
diff --git a/ui/events/mojo/struct_traits_unittest.cc b/ui/events/mojo/struct_traits_unittest.cc
index 3ec4376..48a3654 100644
--- a/ui/events/mojo/struct_traits_unittest.cc
+++ b/ui/events/mojo/struct_traits_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/message_loop/message_loop.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -28,8 +30,8 @@
  private:
   // TraitsTestService:
   void EchoEvent(std::unique_ptr<ui::Event> e,
-                 const EchoEventCallback& callback) override {
-    callback.Run(std::move(e));
+                 EchoEventCallback callback) override {
+    std::move(callback).Run(std::move(e));
   }
 
   base::MessageLoop loop_;
diff --git a/ui/latency/mojo/BUILD.gn b/ui/latency/mojo/BUILD.gn
index dc8f800..0840e693 100644
--- a/ui/latency/mojo/BUILD.gn
+++ b/ui/latency/mojo/BUILD.gn
@@ -24,7 +24,4 @@
   public_deps = [
     ":interfaces",
   ]
-
-  # TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
-  use_once_callback = false
 }
diff --git a/ui/latency/mojo/struct_traits_unittest.cc b/ui/latency/mojo/struct_traits_unittest.cc
index 3efa55f0..31a063d2 100644
--- a/ui/latency/mojo/struct_traits_unittest.cc
+++ b/ui/latency/mojo/struct_traits_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/message_loop/message_loop.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -23,21 +25,20 @@
 
  private:
   // TraitsTestService:
-  void EchoLatencyComponent(
-      const LatencyInfo::LatencyComponent& l,
-      const EchoLatencyComponentCallback& callback) override {
-    callback.Run(l);
+  void EchoLatencyComponent(const LatencyInfo::LatencyComponent& l,
+                            EchoLatencyComponentCallback callback) override {
+    std::move(callback).Run(l);
   }
 
   void EchoLatencyComponentId(
       const std::pair<LatencyComponentType, int64_t>& id,
-      const EchoLatencyComponentIdCallback& callback) override {
-    callback.Run(id);
+      EchoLatencyComponentIdCallback callback) override {
+    std::move(callback).Run(id);
   }
 
   void EchoLatencyInfo(const LatencyInfo& info,
-                       const EchoLatencyInfoCallback& callback) override {
-    callback.Run(info);
+                       EchoLatencyInfoCallback callback) override {
+    std::move(callback).Run(info);
   }
 
   base::MessageLoop loop_;
diff --git a/ui/message_center/mojo/BUILD.gn b/ui/message_center/mojo/BUILD.gn
index 6bdef07..a19b11a 100644
--- a/ui/message_center/mojo/BUILD.gn
+++ b/ui/message_center/mojo/BUILD.gn
@@ -25,9 +25,6 @@
   public_deps = [
     ":mojo",
   ]
-
-  # TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
-  use_once_callback = false
 }
 
 source_set("struct_traits") {
diff --git a/ui/message_center/mojo/struct_traits_unittest.cc b/ui/message_center/mojo/struct_traits_unittest.cc
index 9e39789..c86745d 100644
--- a/ui/message_center/mojo/struct_traits_unittest.cc
+++ b/ui/message_center/mojo/struct_traits_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
@@ -36,8 +38,8 @@
  private:
   // TraitsTestService:
   void EchoNotification(const Notification& n,
-                        const EchoNotificationCallback& callback) override {
-    callback.Run(n);
+                        EchoNotificationCallback callback) override {
+    std::move(callback).Run(n);
   }
 
   base::MessageLoop loop_;