diff --git a/AUTHORS b/AUTHORS
index 467bd50..9936ab97 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -33,6 +33,7 @@
 Alex Gartrell <agartrell@cmu.edu>
 Alex Henrie <alexhenrie24@gmail.com>
 Alex Scheele <alexscheele@gmail.com>
+Alexander Douglas <agdoug@amazon.com>
 Alexander Shalamov <alexander.shalamov@intel.com>
 Alexander Sulfrian <alexander@sulfrian.net>
 Alexandre Abreu <wiss1976@gmail.com>
diff --git a/BUILD.gn b/BUILD.gn
index 64eb29d8..5fdb6c5f 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -736,7 +736,7 @@
   # TODO(https://crbug.com/731217): This can't practically be in //v8 without
   # duplicating all the Fuchsia running infrastructure there.
   fuchsia_executable_runner("d8_fuchsia") {
-    exe_name = "d8"
+    exe_target = "//v8:d8"
   }
 }
 
diff --git a/DEPS b/DEPS
index a93f161..5580276 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': 'a523d2d1554441a79319eb46960d7b5c2dc85d9d',
+  'skia_revision': 'e750391c349ff1fa1c179fbf2f5af27fb4405cef',
   # 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': 'cecaeb86ee39dd47907eeec3bc6c0b382c86a0e8',
+  'v8_revision': '1f89195e08248806f934a2ec098daa8639ef6055',
   # 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.
@@ -52,7 +52,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '77d4d4da902464aeffcbaa7ade5b42c2012d63ee',
+  'angle_revision': 'e8ef2bc4bd019fd6080db5a1a5f0dd18bc0ccd25',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '304eefb58759e56be3fb357c78204accd4fa98fc',
+  'pdfium_revision': '980a3ea30872cef9ada360aa85e7c3573d7668b5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -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': '021853793c96f0b0fecadf76d38928f00220262b',
+  'catapult_revision': 'db0acc015b848d841d705a9128f3adfbb9baca7b',
   # 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/android_webview/browser/net/aw_cookie_store_wrapper.cc b/android_webview/browser/net/aw_cookie_store_wrapper.cc
index 7a671e88..6eca03e 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper.cc
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.cc
@@ -356,6 +356,14 @@
   return subscription->Subscribe(url, name, callback);
 }
 
+std::unique_ptr<net::CookieStore::CookieChangedSubscription>
+AwCookieStoreWrapper::AddCallbackForAllChanges(
+    const CookieChangedCallback& callback) {
+  // TODO(rdsmith): Implement when needed by Android Webview consumer.
+  CHECK(false);
+  return nullptr;
+}
+
 bool AwCookieStoreWrapper::IsEphemeral() {
   return GetCookieStore()->IsEphemeral();
 }
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.h b/android_webview/browser/net/aw_cookie_store_wrapper.h
index 6094b1c..a22c506 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper.h
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.h
@@ -89,6 +89,8 @@
       const GURL& url,
       const std::string& name,
       const CookieChangedCallback& callback) override;
+  std::unique_ptr<CookieChangedSubscription> AddCallbackForAllChanges(
+      const CookieChangedCallback& callback) override;
   bool IsEphemeral() override;
 
  private:
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper_unittest.cc b/android_webview/browser/net/aw_cookie_store_wrapper_unittest.cc
index a80d03b9..afe51c8c 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper_unittest.cc
+++ b/android_webview/browser/net/aw_cookie_store_wrapper_unittest.cc
@@ -37,6 +37,7 @@
   static const bool filters_schemes = true;
   static const bool has_path_prefix_bug = false;
   static const bool forbids_setting_empty_name = false;
+  static const bool supports_global_cookie_tracking = false;
   static const int creation_time_granularity_in_ms = 0;
 };
 
diff --git a/android_webview/glue/glue.gni b/android_webview/glue/glue.gni
index 0a3ce579..cdc293d4 100644
--- a/android_webview/glue/glue.gni
+++ b/android_webview/glue/glue.gni
@@ -15,7 +15,3 @@
   "//net/android:net_java",
   "//ui/android:ui_java",
 ]
-
-# Omit downstream *ForO classes.
-# TODO(paulmiller): Remove this after removing those downstream classes.
-unpublished_apis_upstream = true
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
index 4a3b8e4..3a38732 100644
--- a/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/tools/system_webview_shell/test/data/webexposed/global-interface-listing-expected.txt
@@ -3009,6 +3009,7 @@
     getter bluetooth
     getter connection
     getter cookieEnabled
+    getter deviceMemory
     getter doNotTrack
     getter geolocation
     getter hardwareConcurrency
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index d663f70..43b0b7d5 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -401,8 +401,10 @@
 }
 
 void PaletteTray::AnchorUpdated() {
-  if (bubble_)
+  if (bubble_) {
+    UpdateClippingWindowBounds();
     bubble_->bubble_view()->UpdateBubble();
+  }
 }
 
 void PaletteTray::Initialize() {
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index 7df446b..3b3676d 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -531,6 +531,7 @@
 
 void SystemTray::AnchorUpdated() {
   if (system_bubble_) {
+    UpdateClippingWindowBounds();
     system_bubble_->bubble_view()->UpdateBubble();
     UpdateBubbleViewArrow(system_bubble_->bubble_view());
   }
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index cbe9adc5..b065e96 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -361,7 +361,10 @@
       GetLocalBounds().InsetsFrom(paint_bounds)));
 }
 
-void TrayBackgroundView::AnchorUpdated() {}
+void TrayBackgroundView::AnchorUpdated() {
+  if (GetBubbleView())
+    UpdateClippingWindowBounds();
+}
 
 void TrayBackgroundView::BubbleResized(
     const views::TrayBubbleView* bubble_view) {}
@@ -439,6 +442,11 @@
   }
 }
 
+void TrayBackgroundView::UpdateClippingWindowBounds() {
+  if (clipping_window_.get())
+    clipping_window_->SetBounds(shelf_->GetUserWorkAreaBounds());
+}
+
 aura::Window* TrayBackgroundView::GetBubbleWindowContainer() {
   aura::Window* container = Shell::GetContainer(
       tray_container()->GetWidget()->GetNativeWindow()->GetRootWindow(),
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h
index 8ef054f..cbd40eb6f 100644
--- a/ash/system/tray/tray_background_view.h
+++ b/ash/system/tray/tray_background_view.h
@@ -116,6 +116,9 @@
   // tray_container().
   gfx::Insets GetBubbleAnchorInsets() const;
 
+  // Updates the |clipping_window_| bounds if the anchor moved or changed.
+  void UpdateClippingWindowBounds();
+
   // Returns the container window for the bubble (on the proper display).
   aura::Window* GetBubbleWindowContainer();
 
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc
index f4be7f9..deaa572 100644
--- a/ash/system/web_notification/web_notification_tray.cc
+++ b/ash/system/web_notification/web_notification_tray.cc
@@ -405,6 +405,7 @@
 
 void WebNotificationTray::AnchorUpdated() {
   if (message_center_bubble()) {
+    UpdateClippingWindowBounds();
     message_center_bubble()->bubble_view()->UpdateBubble();
     UpdateBubbleViewArrow(message_center_bubble()->bubble_view());
   }
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index a70ccdc..c45da1c4 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -60,7 +60,10 @@
   item_->SetBounds(bounds, OverviewAnimationType::OVERVIEW_ANIMATION_NONE);
   previous_event_location_ = location_in_screen;
 
-  UpdatePhantomWindowAndWindowGrid(location_in_screen);
+  // Attempt to show phantom window and move window grid only if the window is
+  // snappable.
+  if (wm::GetWindowState(item_->GetWindow())->CanSnap())
+    UpdatePhantomWindowAndWindowGrid(location_in_screen);
 }
 
 void OverviewWindowDragController::CompleteDrag() {
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 0603220..ff7a90c 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -2070,6 +2070,48 @@
   ToggleOverview();
 }
 
+// Tests dragging a unsnappable window.
+TEST_F(WindowSelectorTest, DraggingNonSnapableAppWithSplitView) {
+  // Enable split view, enter maximize mode, add a unsnappable window and enter
+  // overview mode.
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableTabletSplitView);
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+
+  const gfx::Rect bounds(0, 0, 400, 400);
+  std::unique_ptr<aura::Window> unsnappable_window(CreateWindow(bounds));
+  unsnappable_window->SetProperty(aura::client::kResizeBehaviorKey,
+                                  ui::mojom::kResizeBehaviorNone);
+
+  // The grid bounds should be the size of the root window minus the shelf.
+  const gfx::Rect root_window_bounds =
+      Shell::Get()->GetPrimaryRootWindow()->GetBoundsInScreen();
+  const gfx::Rect shelf_bounds =
+      Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())->GetIdealBounds();
+  const gfx::Rect expected_grid_bounds =
+      SubtractRects(root_window_bounds, shelf_bounds);
+
+  ToggleOverview();
+  ASSERT_TRUE(window_selector_controller()->IsSelecting());
+
+  // Verify that after dragging the unsnappable window to the left and right,
+  // the window grid bounds do not change.
+  WindowSelectorItem* selector_item =
+      GetWindowItemForWindow(0, unsnappable_window.get());
+  window_selector()->InitiateDrag(selector_item,
+                                  selector_item->target_bounds().CenterPoint());
+  window_selector()->Drag(selector_item, gfx::Point(0, 0));
+  EXPECT_EQ(expected_grid_bounds, GetGridBounds());
+  window_selector()->Drag(selector_item,
+                          gfx::Point(root_window_bounds.right(), 0));
+  EXPECT_EQ(expected_grid_bounds, GetGridBounds());
+  window_selector()->Drag(selector_item,
+                          gfx::Point(root_window_bounds.right() / 2, 0));
+  EXPECT_EQ(expected_grid_bounds, GetGridBounds());
+
+  ToggleOverview();
+}
+
 // Tests that if there is only one window in the MRU window list in the overview
 // mode, snapping the window to one side of the screen will end the overview
 // mode since there is no more window left in the overview window grid.
diff --git a/base/containers/circular_deque.h b/base/containers/circular_deque.h
index 3eec347..714a980 100644
--- a/base/containers/circular_deque.h
+++ b/base/containers/circular_deque.h
@@ -1064,12 +1064,25 @@
   size_type end_ = 0;
 
 #if DCHECK_IS_ON()
-  // Incremented every time a modification that could affect iterator
+  // Incremented every time a modification is made that could affect iterator
   // invalidations.
   uint64_t generation_ = 0;
 #endif
 };
 
+// Implementations of base::Erase[If] (see base/stl_util.h).
+template <class T, class Value>
+void Erase(circular_deque<T>& container, const Value& value) {
+  container.erase(std::remove(container.begin(), container.end(), value),
+                  container.end());
+}
+
+template <class T, class Predicate>
+void EraseIf(circular_deque<T>& container, Predicate pred) {
+  container.erase(std::remove_if(container.begin(), container.end(), pred),
+                  container.end());
+}
+
 }  // namespace base
 
 #endif  // BASE_CONTAINERS_CIRCULAR_DEQUE_H_
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index 4da50fdc7..0d802d8 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -601,27 +601,29 @@
       logging.info('Could not get tests from pickle: %s', e)
     logging.info('Getting tests by having %s list them.',
                  self._test_instance.junit4_runner_class)
-    def list_tests(dev):
-      with device_temp_file.DeviceTempFile(
-          dev.adb, suffix='.json',
-          dir=dev.GetExternalStoragePath()) as dev_test_list_json:
-        junit4_runner_class = self._test_instance.junit4_runner_class
-        test_package = self._test_instance.test_package
-        extras = {}
-        extras['log'] = 'true'
-        extras[_EXTRA_TEST_LIST] = dev_test_list_json.name
-        target = '%s/%s' % (test_package, junit4_runner_class)
-        test_list_run_output = dev.StartInstrumentation(
-            target, extras=extras)
-        if any(test_list_run_output):
-          logging.error('Unexpected output while listing tests:')
-          for line in test_list_run_output:
-            logging.error('  %s', line)
-        with tempfile_ext.NamedTemporaryDirectory() as host_dir:
-          host_file = os.path.join(host_dir, 'list_tests.json')
-          dev.PullFile(dev_test_list_json.name, host_file)
-          with open(host_file, 'r') as host_file:
-              return json.load(host_file)
+    def list_tests(d):
+      def _run(dev):
+        with device_temp_file.DeviceTempFile(
+            dev.adb, suffix='.json',
+            dir=dev.GetExternalStoragePath()) as dev_test_list_json:
+          junit4_runner_class = self._test_instance.junit4_runner_class
+          test_package = self._test_instance.test_package
+          extras = {}
+          extras['log'] = 'true'
+          extras[_EXTRA_TEST_LIST] = dev_test_list_json.name
+          target = '%s/%s' % (test_package, junit4_runner_class)
+          test_list_run_output = dev.StartInstrumentation(
+              target, extras=extras)
+          if any(test_list_run_output):
+            logging.error('Unexpected output while listing tests:')
+            for line in test_list_run_output:
+              logging.error('  %s', line)
+          with tempfile_ext.NamedTemporaryDirectory() as host_dir:
+            host_file = os.path.join(host_dir, 'list_tests.json')
+            dev.PullFile(dev_test_list_json.name, host_file)
+            with open(host_file, 'r') as host_file:
+                return json.load(host_file)
+      return crash_handler.RetryOnSystemCrash(_run, d)
 
     raw_test_lists = self._env.parallel_devices.pMap(list_tests).pGet(None)
 
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index f31f287..c91da09 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2980,6 +2980,11 @@
                     rebase_path(_info_path, root_build_dir),
                   ])
     }
+
+    # If "gn gen" is failing on the following line, you need to generate an
+    # .info file for your new target by running:
+    #   gn gen --args='target_os="android" update_android_aar_prebuilts=true' out/tmp
+    #   rm -r out/tmp
     _scanned_files = read_file(_info_path, "scope")
 
     assert(_ignore_aidl || _scanned_files.aidl == [],
diff --git a/build/config/fuchsia/rules.gni b/build/config/fuchsia/rules.gni
index 5737557..0a10f2a 100644
--- a/build/config/fuchsia/rules.gni
+++ b/build/config/fuchsia/rules.gni
@@ -7,10 +7,10 @@
 template("generate_runner_script") {
   # This runtime_deps file is used at runtime and thus cannot go in
   # target_gen_dir.
-  _target_dir_name = get_label_info(":$target_name", "dir")
-  _runtime_deps_file =
-      "$root_out_dir/gen.runtime/$_target_dir_name/$target_name.runtime_deps"
-  _runtime_deps_target = "${target_name}__write_deps"
+  _target_dir_name = get_label_info(invoker.exe_target, "dir")
+  _target_shortname = get_label_info(invoker.exe_target, "name")
+  _runtime_deps_file = "$root_out_dir/gen.runtime/$_target_dir_name/$_target_shortname.runtime_deps"
+  _runtime_deps_target = "${_target_shortname}__write_deps"
   group(_runtime_deps_target) {
     forward_variables_from(invoker,
                            [
@@ -45,7 +45,7 @@
     data = []
     runner_args = []
 
-    generated_script = "$root_build_dir/bin/run_${target}"
+    generated_script = "$root_build_dir/bin/run_${_target_shortname}"
     outputs = [
       generated_script,
     ]
@@ -74,7 +74,7 @@
       "--script-output-path",
       rebase_path(generated_script, root_build_dir),
       "--exe-name",
-      target,
+      _target_shortname,
     ]
 
     if (defined(invoker.use_test_server) && invoker.use_test_server) {
@@ -91,19 +91,29 @@
   generate_runner_script(target_name) {
     testonly = true
     runner_script = "test_runner.py"
-    target = invoker.test_name
+    exe_target = invoker.test_name
     forward_variables_from(invoker, "*")
   }
 }
 
 # This template is used to generate a runner script for arbitrary executables
-# into the build dir for Fuchsia. The template should be instantiated alongside
-# an "executable" target, and referenced from the executable via its "deps"
-# attribute.
+# into the build dir for Fuchsia. The template should reference an "executable"
+# target using the "exe_target" attribute.
+#
+# Example usage:
+#
+#   executable("foo") {
+#     sources = [ "foo_main.cc" ]
+#   }
+#   fuchsia_executable_runner("foo_fuchsia") {
+#     exe_target = ":foo"
+#   }
 template("fuchsia_executable_runner") {
   generate_runner_script(target_name) {
+    forward_variables_from(invoker, [ "exe_target" ])
     runner_script = "exe_runner.py"
-    target = invoker.exe_name
-    forward_variables_from(invoker, "*")
+    data_deps = [
+      exe_target,
+    ]
   }
 }
diff --git a/chrome/android/java/res/layout/chrome_home_iph_header.xml b/chrome/android/java/res/layout/chrome_home_iph_header.xml
new file mode 100644
index 0000000..7aa4d23
--- /dev/null
+++ b/chrome/android/java/res/layout/chrome_home_iph_header.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:chrome="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/modern_light_grey"
+    android:orientation="horizontal"
+    android:paddingStart="16dp" >
+
+    <!-- Top and bottom padding is used to achieve layout that best matches
+         UX spec.
+         While the text matches @style/BlankHint2, text size and color
+         are set explicitly. When shown in the overflow menu, the header
+         is inflated using the OverflowMenuTheme. The theme's textAppearance
+         will override any textAppearance set on this element. -->
+    <TextView
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:paddingTop="9dp"
+        android:paddingBottom="9dp"
+        android:text="@string/bottom_sheet_app_menu_iph"
+        android:textColor="@color/black_alpha_54"
+        android:textSize="@dimen/text_size_medium" />
+
+    <FrameLayout
+        android:layout_width="40dp"
+        android:layout_height="40dp"
+        android:layout_gravity="center_vertical" >
+
+        <org.chromium.chrome.browser.widget.TintedImageView
+            android:layout_width="18dp"
+            android:layout_height="18dp"
+            android:layout_gravity="center_vertical|center_horizontal"
+            android:scaleType="centerInside"
+            android:src="@drawable/ic_help_white_24dp"
+            chrome:chrometint="@color/black_alpha_38" />
+
+    </FrameLayout>
+
+</LinearLayout>
diff --git a/chrome/android/java/res/layout/personalized_signin_promo_view_modern_content_suggestions.xml b/chrome/android/java/res/layout/personalized_signin_promo_view_modern_content_suggestions.xml
new file mode 100644
index 0000000..f0d3992d
--- /dev/null
+++ b/chrome/android/java/res/layout/personalized_signin_promo_view_modern_content_suggestions.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<org.chromium.chrome.browser.signin.SigninPromoView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/signin_promo_view_container"
+    style="@style/SuggestionCardModern"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_horizontal"
+    android:orientation="vertical"
+    android:paddingBottom="12dp"
+    android:paddingEnd="16dp"
+    android:paddingStart="16dp"
+    android:paddingTop="12dp">
+
+    <include layout="@layout/signin_promo_view_impl"/>
+
+</org.chromium.chrome.browser.signin.SigninPromoView>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/personalized_signin_promo_view_ntp_content_suggestions.xml b/chrome/android/java/res/layout/personalized_signin_promo_view_ntp_content_suggestions.xml
index af384cb..d6cb3140 100644
--- a/chrome/android/java/res/layout/personalized_signin_promo_view_ntp_content_suggestions.xml
+++ b/chrome/android/java/res/layout/personalized_signin_promo_view_ntp_content_suggestions.xml
@@ -8,7 +8,6 @@
     android:id="@+id/signin_promo_view_container"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:background="@drawable/ntp_signin_promo_card_single"
     android:gravity="center_horizontal"
     android:orientation="vertical"
     android:paddingBottom="12dp"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index d1730aa9..8c70f9d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1475,15 +1475,38 @@
 
             @Override
             public int getFooterResourceId() {
-                if (getBottomSheet() != null) {
-                    boolean isPageMenu = !isTablet() && !isInOverviewMode();
-                    return isPageMenu ? R.layout.icon_row_menu_footer : 0;
+                if (getBottomSheet() != null
+                        && getAppMenuPropertiesDelegate().shouldShowPageMenu()) {
+                    return R.layout.icon_row_menu_footer;
                 }
 
                 return showDataSaverFooter() ? R.layout.data_reduction_main_menu_footer : 0;
             }
 
             @Override
+            public int getHeaderResourceId() {
+                if (getBottomSheet() != null
+                        && getAppMenuPropertiesDelegate().shouldShowPageMenu()) {
+                    return R.layout.chrome_home_iph_header;
+                }
+
+                return 0;
+            }
+
+            @Override
+            public OnClickListener getHeaderOnClickListener() {
+                return new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        getBottomSheet()
+                                .getBottomSheetMetrics()
+                                .recordInProductHelpMenuItemClicked();
+                        getBottomSheet().showHelpBubble(true);
+                    }
+                };
+            }
+
+            @Override
             public boolean shouldShowFooter(int maxMenuHeight) {
                 if (showDataSaverFooter()) {
                     return maxMenuHeight >= getResources().getDimension(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
index 56ef6ad..892bb146 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
@@ -7,7 +7,6 @@
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorSet;
-import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
@@ -23,6 +22,7 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.View.MeasureSpec;
+import android.view.View.OnClickListener;
 import android.view.View.OnKeyListener;
 import android.view.ViewGroup;
 import android.view.ViewStub;
@@ -144,25 +144,33 @@
     /**
      * Creates and shows the app menu anchored to the specified view.
      *
-     * @param context             The context of the AppMenu (ensure the proper theme is set on this
-     * context).
-     * @param anchorView          The anchor {@link View} of the {@link ListPopupWindow}.
-     * @param isByPermanentButton Whether or not permanent hardware button triggered it. (oppose to
-     *                            software button or keyboard).
-     * @param screenRotation      Current device screen rotation.
-     * @param visibleDisplayFrame The display area rect in which AppMenu is supposed to fit in.
-     * @param screenHeight        Current device screen height.
-     * @param footerResourceId    The resource id for a view to add to the end of the menu list. Can
-     *                            be 0 if no such view is required.
-     * @param highlightedItemId   The resource id of the menu item that should be highlighted.  Can
-     *                            be {@code null} if no item should be highlighted.  Note that
-     *                            {@code 0} is dedicated to custom menu items and can be declared by
-     *                            external apps.
+     * @param context               The context of the AppMenu (ensure the proper theme is set on
+     *                              this context).
+     * @param anchorView            The anchor {@link View} of the {@link PopupWindow}.
+     * @param isByPermanentButton   Whether or not permanent hardware button triggered it. (oppose
+     *                              to software button or keyboard).
+     * @param screenRotation        Current device screen rotation.
+     * @param visibleDisplayFrame   The display area rect in which AppMenu is supposed to fit in.
+     * @param screenHeight          Current device screen height.
+     * @param footerResourceId      The resource id for a view to add as a fixed view at the bottom
+     *                              of the menu.  Can be 0 if no such view is required.  The footer
+     *                              is always visible and overlays other app menu items if
+     *                              necessary.
+     * @param headerResourceId      The resource id for a view to add as the first item in menu
+     *                              list.  Can be 0 if no such view is required.
+     *                              See {@link ListView#addHeaderView(View)}.
+     * @param headerOnClickListener The {@link OnClickListener} to notify when the header view is
+     *                              clicked.  May be null if nothing should happen when the header
+     *                              is clicked.
+     * @param highlightedItemId     The resource id of the menu item that should be highlighted.
+     *                              Can be {@code null} if no item should be highlighted.  Note that
+     *                              {@code 0} is dedicated to custom menu items and can be declared
+     *                              by external apps.
      */
-    @SuppressLint("ResourceType")
     void show(Context context, final View anchorView, boolean isByPermanentButton,
             int screenRotation, Rect visibleDisplayFrame, int screenHeight,
-            @IdRes int footerResourceId, Integer highlightedItemId) {
+            @IdRes int footerResourceId, int headerResourceId,
+            OnClickListener headerOnClickListener, Integer highlightedItemId) {
         mPopup = new PopupWindow(context);
         mPopup.setFocusable(true);
         if (!isByPermanentButton) mPopup.setClippingEnabled(false);
@@ -174,7 +182,6 @@
         }
 
         boolean anchorAtBottom = isAnchorAtBottom(anchorView, visibleDisplayFrame);
-        int footerHeight = 0;
         mPopup.setOnDismissListener(() -> {
             if (anchorView instanceof ImageButton) {
                 ((ImageButton) anchorView).setSelected(false);
@@ -245,25 +252,13 @@
         mListView = (ListView) contentView.findViewById(R.id.app_menu_list);
         mListView.setAdapter(mAdapter);
 
-        if (footerResourceId != 0) {
-            // TODO(crbug.com/635567): Fix lint error properly.
-            ViewStub footerStub = (ViewStub) contentView.findViewById(R.id.app_menu_footer_stub);
-            footerStub.setLayoutResource(footerResourceId);
-            mFooterView = footerStub.inflate();
-            int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-            int widthMeasureSpec = MeasureSpec.makeMeasureSpec(menuWidth, MeasureSpec.EXACTLY);
-            mFooterView.measure(widthMeasureSpec, heightMeasureSpec);
-            footerHeight = mFooterView.getMeasuredHeight();
-            if (highlightedItemId != null) {
-                View viewToHighlight = mFooterView.findViewById(highlightedItemId);
-                ViewHighlighter.turnOnHighlight(viewToHighlight, viewToHighlight != mFooterView);
-            }
-        } else {
-            mFooterView = null;
-        }
+        int footerHeight =
+                inflateFooter(footerResourceId, contentView, menuWidth, highlightedItemId);
+        int headerHeight =
+                inflateHeader(headerResourceId, headerOnClickListener, context, menuWidth);
 
         int popupHeight = setMenuHeight(menuItems.size(), visibleDisplayFrame, screenHeight,
-                sizingPadding, footerHeight, anchorView);
+                sizingPadding, footerHeight, headerHeight, anchorView);
         int[] popupPosition = getPopupPosition(mCurrentScreenRotation, visibleDisplayFrame,
                 sizingPadding, anchorView, anchorAtBottom, popupWidth, popupHeight);
 
@@ -474,7 +469,7 @@
     }
 
     private int setMenuHeight(int numMenuItems, Rect appDimensions, int screenHeight, Rect padding,
-            int footerHeight, View anchorView) {
+            int footerHeight, int headerHeight, View anchorView) {
         int menuHeight;
         anchorView.getLocationOnScreen(mTempLocation);
         int anchorViewY = mTempLocation[1] - appDimensions.top;
@@ -498,7 +493,7 @@
         // Fade out the last item if we cannot fit all items.
         if (numCanFit < numMenuItems) {
             int spaceForFullItems = numCanFit * (mItemRowHeight + mItemDividerHeight);
-            spaceForFullItems += footerHeight;
+            spaceForFullItems += footerHeight + headerHeight;
 
             int spaceForPartialItem = (int) (LAST_ITEM_SHOW_FRACTION * mItemRowHeight);
             // Determine which item needs hiding.
@@ -510,7 +505,7 @@
             }
         } else {
             int spaceForFullItems = numMenuItems * (mItemRowHeight + mItemDividerHeight);
-            spaceForFullItems += footerHeight;
+            spaceForFullItems += footerHeight + headerHeight;
             menuHeight = spaceForFullItems + padding.top + padding.bottom;
         }
         mPopup.setHeight(menuHeight);
@@ -537,4 +532,55 @@
         mMenuItemEnterAnimator.addListener(mAnimationHistogramRecorder);
         mMenuItemEnterAnimator.start();
     }
+
+    private int inflateFooter(
+            int footerResourceId, View contentView, int menuWidth, Integer highlightedItemId) {
+        if (footerResourceId == 0) {
+            mFooterView = null;
+            return 0;
+        }
+
+        ViewStub footerStub = (ViewStub) contentView.findViewById(R.id.app_menu_footer_stub);
+        footerStub.setLayoutResource(footerResourceId);
+        mFooterView = footerStub.inflate();
+
+        int widthMeasureSpec = MeasureSpec.makeMeasureSpec(menuWidth, MeasureSpec.EXACTLY);
+        int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        mFooterView.measure(widthMeasureSpec, heightMeasureSpec);
+
+        if (highlightedItemId != null) {
+            View viewToHighlight = mFooterView.findViewById(highlightedItemId);
+            ViewHighlighter.turnOnHighlight(viewToHighlight, viewToHighlight != mFooterView);
+        }
+
+        return mFooterView.getMeasuredHeight();
+    }
+
+    private int inflateHeader(int headerResourceId, OnClickListener headerOnClickListener,
+            Context context, int menuWidth) {
+        if (headerResourceId == 0) return 0;
+
+        View headerView = LayoutInflater.from(context).inflate(headerResourceId, null);
+
+        headerView.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // If an OnClickListener for the header isn't provided, do nothing. Setting a no-op
+                // OnClickListener on headerView ensures that a touch on the header view doesn't
+                // go to the first menu item.
+                if (headerOnClickListener == null) return;
+
+                dismiss();
+                headerOnClickListener.onClick(v);
+            }
+        });
+
+        int widthMeasureSpec = MeasureSpec.makeMeasureSpec(menuWidth, MeasureSpec.EXACTLY);
+        int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        headerView.measure(widthMeasureSpec, heightMeasureSpec);
+
+        mListView.addHeaderView(headerView);
+
+        return headerView.getMeasuredHeight();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java
index ca4c2e4..d2d3525 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java
@@ -166,7 +166,8 @@
             footerResourceId = mDelegate.getFooterResourceId();
         }
         mAppMenu.show(wrapper, anchorView, isByPermanentButton, rotation, appRect, pt.y,
-                footerResourceId, mHighlightMenuId);
+                footerResourceId, mDelegate.getHeaderResourceId(),
+                mDelegate.getHeaderOnClickListener(), mHighlightMenuId);
         mAppMenuDragHelper.onShow(startDragging);
         mDelegate.onShow(mAppMenu);
         setMenuHighlight(null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
index 2c6f446..eb5366d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
@@ -15,6 +15,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.View.OnClickListener;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.CommandLine;
@@ -66,6 +67,22 @@
     }
 
     /**
+     * @return Whether the app menu for a web page should be shown.
+     */
+    public boolean shouldShowPageMenu() {
+        boolean isOverview = mActivity.isInOverviewMode();
+
+        if (mActivity.isTablet()) {
+            boolean hasTabs = mActivity.getCurrentTabModel().getCount() != 0;
+            return hasTabs && !isOverview;
+        } else {
+            boolean isBottomSheetNtpMenu = mActivity.getBottomSheet() != null
+                    && mActivity.getBottomSheet().isShowingNewTab();
+            return !isBottomSheetNtpMenu && !isOverview;
+        }
+    }
+
+    /**
      * Allows the delegate to show and hide items before the App Menu is shown. It is called every
      * time the menu is shown. This assumes that the provided menu contains all the items expected
      * in the application menu (i.e. that the main menu has been inflated into it).
@@ -73,7 +90,7 @@
      */
     public void prepareMenu(Menu menu) {
         // Exactly one of these will be true, depending on the type of menu showing.
-        boolean isPageMenu;
+        boolean isPageMenu = shouldShowPageMenu();
         boolean isOverviewMenu;
         boolean isTabletEmptyModeMenu;
         boolean isBottomSheetNtpMenu =
@@ -86,11 +103,9 @@
         // Determine which menu to show.
         if (mActivity.isTablet()) {
             boolean hasTabs = mActivity.getCurrentTabModel().getCount() != 0;
-            isPageMenu = hasTabs && !isOverview;
             isOverviewMenu = hasTabs && isOverview;
             isTabletEmptyModeMenu = !hasTabs;
         } else {
-            isPageMenu = !isBottomSheetNtpMenu && !isOverview;
             isOverviewMenu = !isBottomSheetNtpMenu && isOverview;
             isTabletEmptyModeMenu = false;
         }
@@ -334,13 +349,33 @@
     }
 
     /**
-     * @return Resource layout id for the footer if there should be one. O otherwise.
+     * @return Resource layout id for the footer if there should be one. O otherwise. The footer
+     *         is shown at a fixed position at the bottom the app menu. It is always visible and
+     *         overlays other app menu items if necessary.
      */
     public int getFooterResourceId() {
         return 0;
     }
 
     /**
+     * @return Resource layout id for the header if there should be one. O otherwise. The header
+     *         will be displayed as the first item in the app menu. It will be scrolled off as the
+     *         menu scrolls.
+     */
+    public int getHeaderResourceId() {
+        return 0;
+    }
+
+    /**
+     * @return The {@link OnClickListener} to notify when the header view is clicked. May be null if
+     *         nothing should happen when the header is clicked.
+     */
+    @Nullable
+    public OnClickListener getHeaderOnClickListener() {
+        return null;
+    }
+
+    /**
      * Determines whether the header should be shown based on the maximum available menu height.
      * @param maxMenuHeight The maximum available height for the menu to draw.
      * @return Whether the footer, as specified in {@link #getFooterResourceId()}, should be shown.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
index d7ef055..236927f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
@@ -45,8 +45,7 @@
  * Shows a card prompting the user to sign in. This item is also an {@link OptionalLeaf}, and sign
  * in state changes control its visibility.
  */
-public class SignInPromo extends OptionalLeaf
-        implements StatusCardViewHolder.DataSource, ImpressionTracker.Listener {
+public class SignInPromo extends OptionalLeaf implements ImpressionTracker.Listener {
     /**
      * Whether the promo had been previously dismissed, before creating an instance of the
      * {@link SignInPromo}.
@@ -82,8 +81,10 @@
     private final boolean mArePersonalizedPromosEnabled;
     private final @Nullable SigninPromoController mSigninPromoController;
     private final @Nullable ProfileDataCache mProfileDataCache;
+    private final @Nullable StatusCardViewHolder.DataSource mGenericPromoData;
 
     public SignInPromo(SuggestionsUiDelegate uiDelegate) {
+        Context context = ContextUtils.getApplicationContext();
         mArePersonalizedPromosEnabled =
                 ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SIGNIN_PROMOS);
 
@@ -95,7 +96,7 @@
         }
 
         SuggestionsSource suggestionsSource = uiDelegate.getSuggestionsSource();
-        SigninManager signinManager = SigninManager.get(ContextUtils.getApplicationContext());
+        SigninManager signinManager = SigninManager.get(context);
 
         mCanSignIn = signinManager.isSignInAllowed() && !signinManager.isSignedInOnNative();
         mCanShowPersonalizedSuggestions = suggestionsSource.areRemoteSuggestionsEnabled();
@@ -107,19 +108,21 @@
             mSigninObserver = null;
             mProfileDataCache = null;
             mSigninPromoController = null;
+            mGenericPromoData = null;
             return;
         }
 
         if (mArePersonalizedPromosEnabled) {
-            Context context = ContextUtils.getApplicationContext();
             int imageSize = context.getResources().getDimensionPixelSize(R.dimen.user_picture_size);
             mProfileDataCache =
                     new ProfileDataCache(context, Profile.getLastUsedProfile(), imageSize);
             mSigninPromoController = new SigninPromoController(
                     mProfileDataCache, SigninAccessPoint.NTP_CONTENT_SUGGESTIONS);
+            mGenericPromoData = null;
         } else {
             mProfileDataCache = null;
             mSigninPromoController = null;
+            mGenericPromoData = new GenericSigninPromoData();
         }
 
         mSigninObserver = new SigninObserver(signinManager, suggestionsSource);
@@ -160,7 +163,7 @@
         if (mArePersonalizedPromosEnabled) {
             ((PersonalizedPromoViewHolder) holder).onBindViewHolder();
         } else {
-            ((GenericPromoViewHolder) holder).onBindViewHolder(this);
+            ((GenericPromoViewHolder) holder).onBindViewHolder(mGenericPromoData);
         }
 
         mImpressionTracker.reset(mImpressionTracker.wasTriggered() ? null : holder.itemView);
@@ -172,29 +175,6 @@
     }
 
     @Override
-    @StringRes
-    public int getHeader() {
-        return R.string.snippets_disabled_generic_prompt;
-    }
-
-    @Override
-    public String getDescription() {
-        return ContextUtils.getApplicationContext().getString(
-                R.string.snippets_disabled_signed_out_instructions);
-    }
-
-    @Override
-    @StringRes
-    public int getActionLabel() {
-        return R.string.sign_in_button;
-    }
-
-    @Override
-    public void performAction(Context context) {
-        AccountSigninActivity.startIfAllowed(context, SigninAccessPoint.NTP_CONTENT_SUGGESTIONS);
-    }
-
-    @Override
     public void onImpression() {
         assert !mWasDismissed;
         if (mArePersonalizedPromosEnabled) {
@@ -221,15 +201,18 @@
         mDismissed = true;
         updateVisibility();
 
+        final @StringRes int promoHeader;
         ChromePreferenceManager preferenceManager = ChromePreferenceManager.getInstance();
         if (mArePersonalizedPromosEnabled) {
             preferenceManager.setNewTabPagePersonalizedSigninPromoDismissed(true);
+            promoHeader = mSigninPromoController.getDescriptionStringId();
         } else {
             preferenceManager.setNewTabPageGenericSigninPromoDismissed(true);
+            promoHeader = mGenericPromoData.getHeader();
         }
 
         mSigninObserver.unregister();
-        itemRemovedCallback.onResult(ContextUtils.getApplicationContext().getString(getHeader()));
+        itemRemovedCallback.onResult(ContextUtils.getApplicationContext().getString(promoHeader));
     }
 
     @VisibleForTesting
@@ -347,8 +330,10 @@
         public PersonalizedPromoViewHolder(SuggestionsRecyclerView parent,
                 ContextMenuManager contextMenuManager, UiConfig config,
                 ProfileDataCache profileDataCache, SigninPromoController signinPromoController) {
-            super(R.layout.personalized_signin_promo_view_ntp_content_suggestions, parent, config,
-                    contextMenuManager);
+            super(FeatureUtilities.isChromeHomeModernEnabled()
+                            ? R.layout.personalized_signin_promo_view_modern_content_suggestions
+                            : R.layout.personalized_signin_promo_view_ntp_content_suggestions,
+                    parent, config, contextMenuManager);
             getParams().topMargin = parent.getResources().getDimensionPixelSize(
                     R.dimen.ntp_sign_in_promo_margin_top);
 
@@ -362,6 +347,14 @@
             updatePersonalizedSigninPromo();
         }
 
+        @DrawableRes
+        @Override
+        protected int selectBackground(boolean hasCardAbove, boolean hasCardBelow) {
+            // Modern does not update the card background.
+            assert !FeatureUtilities.isChromeHomeModernEnabled();
+            return R.drawable.ntp_signin_promo_card_single;
+        }
+
         private void updatePersonalizedSigninPromo() {
             Account[] accounts = AccountManagerFacade.get().tryGetGoogleAccounts();
             String defaultAccountName = accounts.length == 0 ? null : accounts[0].name;
@@ -377,6 +370,34 @@
         }
     }
 
+    /** Defines the appearance and the behaviour of a generic Sign In Promo card. */
+    @VisibleForTesting
+    public static class GenericSigninPromoData implements StatusCardViewHolder.DataSource {
+        @Override
+        @StringRes
+        public int getHeader() {
+            return R.string.snippets_disabled_generic_prompt;
+        }
+
+        @Override
+        public String getDescription() {
+            return ContextUtils.getApplicationContext().getString(
+                    R.string.snippets_disabled_signed_out_instructions);
+        }
+
+        @Override
+        @StringRes
+        public int getActionLabel() {
+            return R.string.sign_in_button;
+        }
+
+        @Override
+        public void performAction(Context context) {
+            AccountSigninActivity.startIfAllowed(
+                    context, SigninAccessPoint.NTP_CONTENT_SUGGESTIONS);
+        }
+    }
+
     /**
      * View Holder for {@link SignInPromo} if the generic promo is to be shown.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java
index e61bd3c..e71b484 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java
@@ -39,7 +39,8 @@
             "signin_promo_impressions_count_bookmarks";
     private static final String SIGNIN_PROMO_IMPRESSIONS_COUNT_SETTINGS =
             "signin_promo_impressions_count_settings";
-    private static final int MAX_IMPRESSIONS = 20;
+    private static final int MAX_IMPRESSIONS_BOOKMARKS = 20;
+    private static final int MAX_IMPRESSIONS_SETTINGS = 5;
 
     private String mAccountName;
     private final ProfileDataCache mProfileDataCache;
@@ -64,7 +65,7 @@
         switch (accessPoint) {
             case SigninAccessPoint.BOOKMARK_MANAGER:
                 return sharedPreferences.getInt(SIGNIN_PROMO_IMPRESSIONS_COUNT_BOOKMARKS, 0)
-                        < MAX_IMPRESSIONS;
+                        < MAX_IMPRESSIONS_BOOKMARKS;
             case SigninAccessPoint.NTP_CONTENT_SUGGESTIONS:
                 // There is no impression limit for NTP content suggestions.
                 return true;
@@ -73,7 +74,7 @@
                 return true;
             case SigninAccessPoint.SETTINGS:
                 return sharedPreferences.getInt(SIGNIN_PROMO_IMPRESSIONS_COUNT_SETTINGS, 0)
-                        < MAX_IMPRESSIONS;
+                        < MAX_IMPRESSIONS_SETTINGS;
             default:
                 assert false : "Unexpected value for access point: " + accessPoint;
                 return false;
@@ -192,6 +193,11 @@
         mAccountName = accountName;
     }
 
+    /** @return the resource used for the text displayed as promo description. */
+    public @StringRes int getDescriptionStringId() {
+        return mDescriptionStringId;
+    }
+
     private void setupColdState(final Context context, SigninPromoView view) {
         view.getImage().setImageResource(R.drawable.chrome_sync_logo);
         setImageSize(context, view, R.dimen.signin_promo_cold_state_image_size);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java
index 264eb718..8923155 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContextualSuggestionsCardViewHolder.java
@@ -45,9 +45,8 @@
             public void onClick(View v) {
                 // TODO(fhorschig): Add metrics to be recorded for the contextual suggestions.
                 int windowDisposition = WindowOpenDisposition.CURRENT_TAB;
-                mUiDelegate.getEventReporter().onSuggestionOpened(
-                        mSuggestion, windowDisposition, mUiDelegate.getSuggestionsRanker());
-                mUiDelegate.getNavigationDelegate().openSnippet(windowDisposition, mSuggestion);
+                mUiDelegate.getNavigationDelegate().navigateToSuggestionUrl(
+                        windowDisposition, mSuggestion.mUrl);
             }
         });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegate.java
index 773b4c5..6699f35 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegate.java
@@ -32,6 +32,9 @@
     /** Opens the help page for the content suggestions in the current tab. */
     void navigateToHelpPage();
 
+    /** Opens the suggestion page without recording metrics. */
+    void navigateToSuggestionUrl(int windowOpenDisposition, String url);
+
     /**
      * Opens a content suggestion and records related metrics.
      * @param windowOpenDisposition How to open (current tab, new tab, new window etc).
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
index 07461ba..0b8311a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
@@ -96,6 +96,12 @@
     }
 
     @Override
+    public void navigateToSuggestionUrl(int windowOpenDisposition, String url) {
+        LoadUrlParams loadUrlParams = new LoadUrlParams(url, PageTransition.AUTO_BOOKMARK);
+        openUrl(windowOpenDisposition, loadUrlParams);
+    }
+
+    @Override
     public void openSnippet(int windowOpenDisposition, SnippetArticle article) {
         NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_SNIPPET);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
index f200dae..347cf9f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
@@ -16,8 +16,6 @@
 import org.chromium.chrome.browser.snackbar.Snackbar;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
-import org.chromium.content_public.browser.LoadUrlParams;
-import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.mojom.WindowOpenDisposition;
 
 import java.util.List;
@@ -64,8 +62,7 @@
             recordOpenedTile(item);
         }
 
-        mNavigationDelegate.openUrl(
-                windowDisposition, new LoadUrlParams(url, PageTransition.AUTO_BOOKMARK));
+        mNavigationDelegate.navigateToSuggestionUrl(windowDisposition, url);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index fee165f..a3c1170 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -1600,43 +1600,58 @@
             @Override
             public void onResult(Boolean success) {
                 if (!success) return;
-                if (!tracker.shouldTriggerHelpUI(FeatureConstants.CHROME_HOME_EXPAND_FEATURE)) {
-                    return;
-                }
 
-                boolean showExpandButtonHelpBubble =
-                        ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME_EXPAND_BUTTON);
-
-                View anchorView = showExpandButtonHelpBubble
-                        ? mControlContainer.findViewById(R.id.expand_sheet_button)
-                        : mControlContainer;
-                int stringId = showExpandButtonHelpBubble
-                        ? R.string.bottom_sheet_expand_button_help_bubble_message
-                        : R.string.bottom_sheet_help_bubble_message;
-                int accessibilityStringId = showExpandButtonHelpBubble
-                        ? R.string.bottom_sheet_accessibility_expand_button_help_bubble_message
-                        : R.string.bottom_sheet_accessibility_help_bubble_message;
-
-                ViewAnchoredTextBubble helpBubble = new ViewAnchoredTextBubble(
-                        getContext(), anchorView, stringId, accessibilityStringId);
-                helpBubble.setDismissOnTouchInteraction(true);
-                helpBubble.addOnDismissListener(new OnDismissListener() {
-                    @Override
-                    public void onDismiss() {
-                        tracker.dismissed(FeatureConstants.CHROME_HOME_EXPAND_FEATURE);
-                        ViewHighlighter.turnOffHighlight(anchorView);
-                    }
-                });
-
-                if (showExpandButtonHelpBubble) {
-                    ViewHighlighter.turnOnHighlight(anchorView, true);
-                }
-
-                int inset = getContext().getResources().getDimensionPixelSize(
-                        R.dimen.bottom_sheet_help_bubble_inset);
-                helpBubble.setInsetPx(0, inset, 0, inset);
-                helpBubble.show();
+                showHelpBubble(false);
             }
         });
     }
+
+    /**
+     * Show the in-product help bubble for the {@link BottomSheet} regardless of whether it has
+     * been shown before. This method must be called after the toolbar has had at least one layout
+     * pass and ChromeFeatureList has been initialized.
+     * @param fromMenu Whether the help bubble is being displayed in response to a click on the
+     *                 IPH menu header.
+     */
+    public void showHelpBubble(boolean fromMenu) {
+        final Tracker tracker = TrackerFactory.getTrackerForProfile(Profile.getLastUsedProfile());
+
+        boolean notifyDismissed =
+                tracker.shouldTriggerHelpUI(FeatureConstants.CHROME_HOME_EXPAND_FEATURE);
+        if (!fromMenu && !notifyDismissed) return;
+
+        boolean showExpandButtonHelpBubble =
+                ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_HOME_EXPAND_BUTTON);
+
+        View anchorView = showExpandButtonHelpBubble
+                ? mControlContainer.findViewById(R.id.expand_sheet_button)
+                : mControlContainer;
+        int stringId = showExpandButtonHelpBubble
+                ? R.string.bottom_sheet_expand_button_help_bubble_message
+                : R.string.bottom_sheet_help_bubble_message;
+        int accessibilityStringId = showExpandButtonHelpBubble
+                ? R.string.bottom_sheet_accessibility_expand_button_help_bubble_message
+                : R.string.bottom_sheet_accessibility_help_bubble_message;
+
+        ViewAnchoredTextBubble helpBubble = new ViewAnchoredTextBubble(
+                getContext(), anchorView, stringId, accessibilityStringId);
+        helpBubble.setDismissOnTouchInteraction(true);
+        helpBubble.addOnDismissListener(new OnDismissListener() {
+            @Override
+            public void onDismiss() {
+                if (notifyDismissed) tracker.dismissed(FeatureConstants.CHROME_HOME_EXPAND_FEATURE);
+
+                ViewHighlighter.turnOffHighlight(anchorView);
+            }
+        });
+
+        if (showExpandButtonHelpBubble) {
+            ViewHighlighter.turnOnHighlight(anchorView, true);
+        }
+
+        int inset = getContext().getResources().getDimensionPixelSize(
+                R.dimen.bottom_sheet_help_bubble_inset);
+        helpBubble.setInsetPx(0, inset, 0, inset);
+        helpBubble.show();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java
index 714b938..e17f3669 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java
@@ -204,4 +204,11 @@
     public void recordNativeNewTabPageShown() {
         RecordUserAction.record("Android.ChromeHome.NativeNTPShown");
     }
+
+    /**
+     * Records that the user tapped the app menu item that triggers the in-product help bubble.
+     */
+    public void recordInProductHelpMenuItemClicked() {
+        RecordUserAction.record("Android.ChromeHome.IPHMenuItemClicked");
+    }
 }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 7cc72f5..5c9bc12 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3175,6 +3175,9 @@
       <message name="IDS_BOTTOM_SHEET_HOME_TAB" desc="Accessibility string read when the home tab is selected.">
         Home tab selected
       </message>
+      <message name="IDS_BOTTOM_SHEET_APP_MENU_IPH" desc="Label for in-product help that appears in the Chrome three-dot menu (navigation menu). In previous versions of Chrome, the menu contained Bookmarks, Downloads, and History. In this version of Chrome, these three items have been moved out of the menu. Tapping this help text will show the user where they can find these three items. 'Bookmarks', 'Downloads', and 'History' should use the same translations as in Chrome settings and menu items. The tone of this string is that of the user asking Chrome, 'where are these 3 things?'">
+        Where are bookmarks, downloads, and history?
+      </message>
 
       <!-- Photo picker -->
       <message name="IDS_PHOTO_PICKER_SELECT_IMAGES" desc="The label in the title bar of the Photo Picker dialog, suggesting which action the user should take.">
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
index 6932908..6de9f4a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -284,7 +284,7 @@
 
             mSigninPromo = new SignInPromo.GenericPromoViewHolder(
                     mRecyclerView, contextMenuManager, mUiConfig);
-            mSigninPromo.onBindViewHolder(new SignInPromo(mUiDelegate));
+            mSigninPromo.onBindViewHolder(new SignInPromo.GenericSigninPromoData());
             mContentView.addView(mSigninPromo.itemView);
         });
 
diff --git a/chrome/browser/android/vr_shell/BUILD.gn b/chrome/browser/android/vr_shell/BUILD.gn
index 1595d4b3..136ba649 100644
--- a/chrome/browser/android/vr_shell/BUILD.gn
+++ b/chrome/browser/android/vr_shell/BUILD.gn
@@ -17,8 +17,6 @@
     "android_ui_gesture_target.h",
     "android_vsync_helper.cc",
     "android_vsync_helper.h",
-    "elbow_model.cc",
-    "elbow_model.h",
     "gl_browser_interface.h",
     "gvr_util.cc",
     "gvr_util.h",
diff --git a/chrome/browser/android/vr_shell/elbow_model.cc b/chrome/browser/android/vr_shell/elbow_model.cc
deleted file mode 100644
index 9fd8acd..0000000
--- a/chrome/browser/android/vr_shell/elbow_model.cc
+++ /dev/null
@@ -1,160 +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.
-
-// Adapted from:
-// https://github.com/googlevr/gvr-unity-sdk/blob/master/Samples/DaydreamLabsControllerPlayground/Assets/GoogleVR/Scripts/Controller/GvrArmModel.cs
-
-#include "chrome/browser/android/vr_shell/elbow_model.h"
-
-#include <cmath>
-
-#include "cc/base/math_util.h"
-
-namespace vr_shell {
-
-namespace {
-
-constexpr gfx::Quaternion kNoRotation = {0.0f, 0.0f, 0.0f, 1.0f};
-constexpr gfx::Point3F kDefaultShoulderRight = {0.19f, -0.19f, 0.03f};
-constexpr float kFadeDistanceFromFace = 0.34f;
-constexpr gfx::Point3F kDefaultRelativeElbow = {0.195f, -0.5f, 0.075f};
-constexpr gfx::Point3F kDefaultRelativeWrist = {0.0f, 0.0f, -0.25f};
-constexpr gfx::Vector3dF kForward = {0.0f, 0.0f, -1.0f};
-constexpr gfx::Vector3dF kUp = {0.0f, 1.0f, 0.0f};
-constexpr gfx::Vector3dF kDefaultArmExtensionOffset = {-0.13f, 0.14f, -0.08f};
-constexpr float kMinExtensionAngle = 7.0f;
-constexpr float kMaxExtenstionAngle = 60.0f;
-constexpr float kExtensionWeight = 0.4f;
-constexpr float kDeltaAlpha = 3.0f;
-constexpr float kDefaultElbowRotationRatio = 0.4f;
-
-gfx::Vector3dF Slerp(const gfx::Vector3dF& a,
-                     const gfx::Vector3dF& b,
-                     double t) {
-  gfx::Vector3dF start;
-  gfx::Vector3dF end;
-  a.GetNormalized(&start);
-  b.GetNormalized(&end);
-  float dot =
-      cc::MathUtil::ClampToRange(gfx::DotProduct(start, end), -1.0f, 1.0f);
-  float theta = acos(dot) * t;
-  gfx::Vector3dF relative_vec = end - gfx::ScaleVector3d(start, dot);
-  relative_vec.GetNormalized(&relative_vec);
-  return gfx::ScaleVector3d(start, cos(theta)) +
-         gfx::ScaleVector3d(relative_vec, sin(theta));
-}
-
-}  // namespace
-
-ElbowModel::ElbowModel(gvr::ControllerHandedness handedness)
-    : handedness_(handedness), alpha_value_(1.0f), torso_direction_(kForward) {
-  UpdateHandedness();
-}
-
-ElbowModel::~ElbowModel() = default;
-
-void ElbowModel::SetHandedness(gvr::ControllerHandedness handedness) {
-  if (handedness == handedness_)
-    return;
-  handedness_ = handedness;
-  UpdateHandedness();
-}
-
-void ElbowModel::UpdateHandedness() {
-  handed_multiplier_ = {
-      handedness_ == GVR_CONTROLLER_RIGHT_HANDED ? 1.0f : -1.0f, 1.0f, 1.0f};
-  shoulder_rotation_ = kNoRotation;
-  shoulder_position_ =
-      gfx::ScalePoint(kDefaultShoulderRight, handed_multiplier_);
-}
-
-void ElbowModel::Update(const UpdateData& update) {
-  UpdateTorsoDirection(update);
-  ApplyArmModel(update);
-  UpdateTransparency(update);
-}
-
-void ElbowModel::UpdateTorsoDirection(const UpdateData& update) {
-  auto head_direction = update.head_direction;
-  head_direction.set_y(0);
-  head_direction.GetNormalized(&head_direction);
-
-  // Determine the gaze direction horizontally.
-  float angular_velocity = update.gyro.Length();
-  float gaze_filter_strength =
-      cc::MathUtil::ClampToRange((angular_velocity - 0.2f) / 45.0f, 0.0f, 0.1f);
-  torso_direction_ =
-      Slerp(torso_direction_, head_direction, gaze_filter_strength);
-
-  // Rotate the fixed joints.
-  gfx::Quaternion gaze_rotation(kForward, torso_direction_);
-  shoulder_rotation_ = gaze_rotation;
-  gfx::Vector3dF to_shoulder = shoulder_position_ - gfx::Point3F();
-  gfx::Transform(gaze_rotation).TransformVector(&to_shoulder);
-  shoulder_position_ = gfx::PointAtOffsetFromOrigin(to_shoulder);
-}
-
-void ElbowModel::ApplyArmModel(const UpdateData& update) {
-  // Controller's orientation relative to the user.
-  auto controller_orientation = update.orientation;
-  controller_orientation =
-      shoulder_rotation_.inverse() * controller_orientation;
-
-  // Relative positions of the joints.
-  elbow_position_ = gfx::ScalePoint(kDefaultRelativeElbow, handed_multiplier_);
-  wrist_position_ = gfx::ScalePoint(kDefaultRelativeWrist, handed_multiplier_);
-  auto arm_extension_offset =
-      gfx::ScaleVector3d(kDefaultArmExtensionOffset, handed_multiplier_);
-
-  // Extract just the x rotation angle.
-  gfx::Transform controller_orientation_mat(controller_orientation);
-
-  gfx::Vector3dF controller_forward = kForward;
-  controller_orientation_mat.TransformVector(&controller_forward);
-
-  float x_angle =
-      90.0f - gfx::AngleBetweenVectorsInDegrees(controller_forward, kUp);
-
-  // Remove the z rotation from the controller
-  gfx::Quaternion x_y_rotation(kForward, controller_forward);
-
-  // Offset the elbow by the extension.
-  float normalized_angle = (x_angle - kMinExtensionAngle) /
-                           (kMaxExtenstionAngle - kMinExtensionAngle);
-  float extension_ratio =
-      cc::MathUtil::ClampToRange(normalized_angle, 0.0f, 1.0f);
-  elbow_position_ = elbow_position_ +
-                    gfx::ScaleVector3d(arm_extension_offset, extension_ratio);
-
-  // Calculate the lerp interpolation factor.
-  // TODO(vollick): this code incorrectly assumes that the angle is in degrees.
-  double total_angle = (kNoRotation * x_y_rotation.inverse()).w();
-  float lerp_suppresion = 1.0f - pow(total_angle / 180.0f, 6);
-  float lerp_value = lerp_suppresion * (kDefaultElbowRotationRatio +
-                                        (1.0f - kDefaultElbowRotationRatio) *
-                                            extension_ratio * kExtensionWeight);
-
-  // Apply the absolute rotations to the joints.
-  auto lerp_rotation = kNoRotation.Lerp(x_y_rotation, lerp_value);
-  elbow_rotation_ =
-      (shoulder_rotation_ * lerp_rotation.inverse()) * controller_orientation;
-  wrist_rotation_ = shoulder_rotation_ * controller_orientation;
-
-  // Determine the relative positions.
-  gfx::Transform(shoulder_rotation_).TransformPoint(&elbow_position_);
-  gfx::Vector3dF to_wrist = wrist_position_ - gfx::Point3F();
-  gfx::Transform(elbow_rotation_).TransformVector(&to_wrist);
-  wrist_position_ = elbow_position_ + to_wrist;
-}
-
-void ElbowModel::UpdateTransparency(const UpdateData& update) {
-  float distance_to_face = (wrist_position_ - gfx::Point3F()).Length();
-  float alpha_change = kDeltaAlpha * update.delta_time_seconds;
-  alpha_value_ = cc::MathUtil::ClampToRange(
-      distance_to_face < kFadeDistanceFromFace ? alpha_value_ - alpha_change
-                                               : alpha_value_ + alpha_change,
-      0.0f, 1.0f);
-}
-
-}  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/elbow_model.h b/chrome/browser/android/vr_shell/elbow_model.h
deleted file mode 100644
index 34568ab..0000000
--- a/chrome/browser/android/vr_shell/elbow_model.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.
-
-// Adapted from:
-// https://github.com/googlevr/gvr-unity-sdk/blob/master/Samples/DaydreamLabsControllerPlayground/Assets/GoogleVR/Scripts/Controller/GvrArmModel.cs
-
-#ifndef CHROME_BROWSER_ANDROID_VR_SHELL_ELBOW_MODEL_H_
-#define CHROME_BROWSER_ANDROID_VR_SHELL_ELBOW_MODEL_H_
-
-#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
-#include "ui/gfx/geometry/point3_f.h"
-#include "ui/gfx/geometry/quaternion.h"
-#include "ui/gfx/geometry/vector3d_f.h"
-#include "ui/gfx/transform.h"
-
-namespace vr_shell {
-
-class ElbowModel {
- public:
-  struct UpdateData {
-    bool connected;
-    gfx::Quaternion orientation;
-    gfx::Vector3dF gyro;
-    gfx::Vector3dF head_direction;
-    float delta_time_seconds;
-  };
-
-  explicit ElbowModel(gvr::ControllerHandedness handedness);
-  ~ElbowModel();
-
-  const gfx::Point3F& GetControllerPosition() const { return wrist_position_; }
-  const gfx::Quaternion& GetControllerRotation() const {
-    return wrist_rotation_;
-  }
-  float GetAlphaValue() const { return alpha_value_; }
-
-  void Update(const UpdateData& update);
-  void SetHandedness(gvr::ControllerHandedness handedness);
-
- private:
-  void UpdateHandedness();
-  void UpdateTorsoDirection(const UpdateData& update);
-  void ApplyArmModel(const UpdateData& update);
-  void UpdateTransparency(const UpdateData& update);
-
-  gvr::ControllerHandedness handedness_;
-
-  gfx::Point3F wrist_position_;
-  gfx::Quaternion wrist_rotation_;
-  float alpha_value_;
-
-  gfx::Point3F elbow_position_;
-  gfx::Quaternion elbow_rotation_;
-  gfx::Point3F shoulder_position_;
-  gfx::Quaternion shoulder_rotation_;
-  gfx::Vector3dF torso_direction_;
-  gfx::Vector3dF handed_multiplier_;
-};
-
-}  // namespace vr_shell
-
-#endif  // CHROME_BROWSER_ANDROID_VR_SHELL_ELBOW_MODEL_H_
diff --git a/chrome/browser/android/vr_shell/vr_controller.cc b/chrome/browser/android/vr_shell/vr_controller.cc
index 4593863e..dd44fa29 100644
--- a/chrome/browser/android/vr_shell/vr_controller.cc
+++ b/chrome/browser/android/vr_shell/vr_controller.cc
@@ -11,7 +11,6 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "cc/base/math_util.h"
-#include "chrome/browser/android/vr_shell/elbow_model.h"
 #include "third_party/WebKit/public/platform/WebGestureEvent.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
@@ -48,6 +47,9 @@
 // Distance from the center of the controller to start rendering the laser.
 constexpr float kLaserStartDisplacement = 0.045;
 
+constexpr float kFadeDistanceFromFace = 0.34f;
+constexpr float kDeltaAlpha = 3.0f;
+
 void ClampTouchpadPosition(gfx::Vector2dF* position) {
   position->set_x(cc::MathUtil::ClampToRange(position->x(), 0.0f, 1.0f));
   position->set_y(cc::MathUtil::ClampToRange(position->y(), 0.0f, 1.0f));
@@ -70,6 +72,8 @@
 
   int32_t options = gvr::ControllerApi::DefaultOptions();
 
+  options |= GVR_CONTROLLER_ENABLE_ARM_MODEL;
+
   // Enable non-default options - WebVR needs gyro and linear acceleration, and
   // since VrShell implements GvrGamepadDataProvider we need this always.
   options |= GVR_CONTROLLER_ENABLE_GYRO;
@@ -79,7 +83,6 @@
   controller_api_->Resume();
 
   handedness_ = gvr_api_->GetUserPrefs().GetControllerHandedness();
-  elbow_model_ = base::MakeUnique<ElbowModel>(handedness_);
 
   Reset();
   last_timestamp_nanos_ =
@@ -94,7 +97,6 @@
   if (controller_api_) {
     controller_api_->Resume();
     handedness_ = gvr_api_->GetUserPrefs().GetControllerHandedness();
-    elbow_model_->SetHandedness(handedness_);
   }
 }
 
@@ -170,23 +172,27 @@
                          orientation.qw);
 }
 
+gfx::Point3F VrController::Position() const {
+  gvr::Vec3f position = controller_state_->GetPosition();
+  return gfx::Point3F(position.x, position.y, position.z);
+}
+
 void VrController::GetTransform(gfx::Transform* out) const {
-  *out = gfx::Transform(elbow_model_->GetControllerRotation());
-  gfx::Point3F p = elbow_model_->GetControllerPosition();
-  out->matrix().postTranslate(p.x(), p.y(), p.z());
+  *out = gfx::Transform(Orientation());
+  gvr::Vec3f position = controller_state_->GetPosition();
+  out->matrix().postTranslate(position.x, position.y, position.z);
 }
 
 float VrController::GetOpacity() const {
-  return elbow_model_->GetAlphaValue();
+  return alpha_value_;
 }
 
 gfx::Point3F VrController::GetPointerStart() const {
-  gfx::Point3F controller_position = elbow_model_->GetControllerPosition();
   gfx::Vector3dF pointer_direction{0.0f, -sin(kErgoAngleOffset),
                                    -cos(kErgoAngleOffset)};
   gfx::Transform rotation_mat(Orientation());
   rotation_mat.TransformVector(&pointer_direction);
-  return controller_position +
+  return Position() +
          gfx::ScaleVector3d(pointer_direction, kLaserStartDisplacement);
 }
 
@@ -224,7 +230,9 @@
   return controller_state_->GetConnectionState() == gvr::kControllerConnected;
 }
 
-void VrController::UpdateState(const gfx::Vector3dF& head_direction) {
+void VrController::UpdateState(const gvr::Mat4f& head_direction) {
+  controller_api_->ApplyArmModel(handedness_, gvr::kArmModelBehaviorFollowGaze,
+                                 head_direction);
   const int32_t old_status = controller_state_->GetApiStatus();
   const int32_t old_connection_state = controller_state_->GetConnectionState();
   // Read current controller state.
@@ -236,12 +244,7 @@
             << gvr_controller_connection_state_to_string(
                    controller_state_->GetConnectionState());
   }
-
-  const gvr::Vec3f& gvr_gyro = controller_state_->GetGyro();
-  elbow_model_->Update({IsConnected(), Orientation(),
-                        gfx::Vector3dF(gvr_gyro.x, gvr_gyro.y, gvr_gyro.z),
-                        head_direction,
-                        DeltaTimeSeconds(last_timestamp_nanos_)});
+  UpdateAlpha();
 }
 
 void VrController::UpdateTouchInfo() {
@@ -465,4 +468,13 @@
                       ScaleVector2d(velocity, weight);
 }
 
+void VrController::UpdateAlpha() {
+  float distance_to_face = (Position() - gfx::Point3F()).Length();
+  float alpha_change = kDeltaAlpha * DeltaTimeSeconds(last_timestamp_nanos_);
+  alpha_value_ = cc::MathUtil::ClampToRange(
+      distance_to_face < kFadeDistanceFromFace ? alpha_value_ - alpha_change
+                                               : alpha_value_ + alpha_change,
+      0.0f, 1.0f);
+}
+
 }  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/vr_controller.h b/chrome/browser/android/vr_shell/vr_controller.h
index ffc3440..a499ad6 100644
--- a/chrome/browser/android/vr_shell/vr_controller.h
+++ b/chrome/browser/android/vr_shell/vr_controller.h
@@ -32,8 +32,6 @@
 
 namespace vr_shell {
 
-class ElbowModel;
-
 // Angle (radians) the beam down from the controller axis, for wrist comfort.
 constexpr float kErgoAngleOffset = 0.26f;
 
@@ -53,8 +51,8 @@
 
   device::GvrGamepadData GetGamepadData();
 
-  // Must be called when the GL renderer gets OnDrawFrame().
-  void UpdateState(const gfx::Vector3dF& head_direction);
+  // Called once per frame to update controller state.
+  void UpdateState(const gvr::Mat4f& head_direction);
 
   std::unique_ptr<GestureList> DetectGestures();
 
@@ -65,6 +63,7 @@
   float TouchPosY();
 
   gfx::Quaternion Orientation() const;
+  gfx::Point3F Position() const;
   void GetTransform(gfx::Transform* out) const;
   float GetOpacity() const;
   gfx::Point3F GetPointerStart() const;
@@ -143,6 +142,8 @@
 
   void UpdateOverallVelocity();
 
+  void UpdateAlpha();
+
   // State of gesture detector.
   GestureDetectorState state_;
 
@@ -188,7 +189,7 @@
   // Number of consecutively extrapolated touch points
   int extrapolated_touch_ = 0;
 
-  std::unique_ptr<ElbowModel> elbow_model_;
+  float alpha_value_ = 1.0f;
 
   DISALLOW_COPY_AND_ASSIGN(VrController);
 };
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc
index 3a1431d..a44a6e0 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -485,15 +485,15 @@
 
 void VrShellGl::UpdateController(const gfx::Transform& head_pose) {
   TRACE_EVENT0("gpu", "VrShellGl::UpdateController");
-  gfx::Vector3dF head_direction = GetForwardVector(head_pose);
-
-  controller_->UpdateState(head_direction);
+  gvr::Mat4f gvr_head_pose;
+  TransformToGvrMat(head_pose, &gvr_head_pose);
+  controller_->UpdateState(gvr_head_pose);
   controller_info_.laser_origin = controller_->GetPointerStart();
 
   device::GvrGamepadData controller_data = controller_->GetGamepadData();
   browser_->UpdateGamepadData(controller_data);
 
-  HandleControllerInput(head_direction);
+  HandleControllerInput(GetForwardVector(head_pose));
 }
 
 void VrShellGl::HandleControllerInput(const gfx::Vector3dF& head_direction) {
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc
index 4fb631f..6ea184f5 100644
--- a/chrome/browser/chrome_navigation_browsertest.cc
+++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -804,3 +804,115 @@
   EXPECT_TRUE(NavigateIframeToURL(web_contents, "test", signin_url));
   EXPECT_TRUE(IsInSyntheticTrialGroup(kSyntheticTrialName, "ForceDisabled"));
 }
+
+// Helper class. Track one navigation and tell whether a response from the
+// server has been received or not. It is useful for discerning navigations
+// blocked after or before the request has been sent.
+class WillProcessResponseObserver : public content::WebContentsObserver {
+ public:
+  explicit WillProcessResponseObserver(content::WebContents* web_contents,
+                                       const GURL& url)
+      : content::WebContentsObserver(web_contents), url_(url) {}
+  ~WillProcessResponseObserver() override {}
+
+  bool WillProcessResponseCalled() { return will_process_response_called_; }
+
+ private:
+  GURL url_;
+  bool will_process_response_called_ = false;
+
+  // Is used to set |will_process_response_called_| to true when
+  // NavigationThrottle::WillProcessResponse() is called.
+  class WillProcessResponseObserverThrottle
+      : public content::NavigationThrottle {
+   public:
+    WillProcessResponseObserverThrottle(content::NavigationHandle* handle,
+                                        bool* will_process_response_called)
+        : NavigationThrottle(handle),
+          will_process_response_called_(will_process_response_called) {}
+
+    const char* GetNameForLogging() override {
+      return "WillProcessResponseObserverThrottle";
+    }
+
+   private:
+    bool* will_process_response_called_;
+    NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
+      *will_process_response_called_ = true;
+      return NavigationThrottle::PROCEED;
+    }
+  };
+
+  // WebContentsObserver
+  void DidStartNavigation(content::NavigationHandle* handle) override {
+    if (handle->GetURL() == url_) {
+      handle->RegisterThrottleForTesting(
+          std::make_unique<WillProcessResponseObserverThrottle>(
+              handle, &will_process_response_called_));
+    }
+  }
+};
+
+// In HTTP/HTTPS documents, check that no request with the "ftp:" scheme are
+// submitted to load an iframe.
+// See https://crbug.com/757809.
+// Note: This test couldn't be a content_browsertests, since there would be
+// not handler defined for the "ftp" protocol in
+// URLRequestJobFactoryImpl::protocol_handler_map_.
+IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest, BlockLegacySubresources) {
+  net::SpawnedTestServer ftp_server(
+      net::SpawnedTestServer::TYPE_FTP,
+      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+  ASSERT_TRUE(ftp_server.Start());
+
+  GURL main_url_http(embedded_test_server()->GetURL("/iframe.html"));
+  GURL main_url_ftp(ftp_server.GetURL("iframe.html"));
+  GURL iframe_url_http(embedded_test_server()->GetURL("/simple.html"));
+  GURL iframe_url_ftp(ftp_server.GetURL("simple.html"));
+  GURL redirect_url(embedded_test_server()->GetURL("/server-redirect?"));
+
+  struct {
+    GURL main_url;
+    GURL iframe_url;
+    bool allowed;
+  } kTestCases[] = {
+      {main_url_http, iframe_url_http, true},
+      {main_url_http, iframe_url_ftp, false},
+      {main_url_ftp, iframe_url_http, true},
+      {main_url_ftp, iframe_url_ftp, true},
+  };
+  for (const auto test_case : kTestCases) {
+    // Blocking the request should work, even after a redirect.
+    for (bool redirect : {false, true}) {
+      GURL iframe_url =
+          redirect ? GURL(redirect_url.spec() + test_case.iframe_url.spec())
+                   : test_case.iframe_url;
+      SCOPED_TRACE(::testing::Message()
+                   << std::endl
+                   << "- main_url = " << test_case.main_url << std::endl
+                   << "- iframe_url = " << iframe_url << std::endl);
+
+      ui_test_utils::NavigateToURL(browser(), test_case.main_url);
+      content::WebContents* web_contents =
+          browser()->tab_strip_model()->GetActiveWebContents();
+      content::NavigationHandleObserver navigation_handle_observer(web_contents,
+                                                                   iframe_url);
+      WillProcessResponseObserver will_process_response_observer(web_contents,
+                                                                 iframe_url);
+      EXPECT_TRUE(NavigateIframeToURL(web_contents, "test", iframe_url));
+
+      if (test_case.allowed) {
+        EXPECT_TRUE(will_process_response_observer.WillProcessResponseCalled());
+        EXPECT_FALSE(navigation_handle_observer.is_error());
+        EXPECT_EQ(test_case.iframe_url,
+                  navigation_handle_observer.last_committed_url());
+      } else {
+        EXPECT_FALSE(
+            will_process_response_observer.WillProcessResponseCalled());
+        EXPECT_TRUE(navigation_handle_observer.is_error());
+        EXPECT_EQ(net::ERR_ABORTED,
+                  navigation_handle_observer.net_error_code());
+      }
+    }
+  }
+}
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 0964d238..1f0ee7b1 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1707,6 +1707,7 @@
     "arc/optin/arc_terms_of_service_default_negotiator_unittest.cc",
     "arc/policy/arc_policy_bridge_unittest.cc",
     "arc/process/arc_process_unittest.cc",
+    "arc/tts/arc_tts_service_unittest.cc",
     "attestation/attestation_ca_client_unittest.cc",
     "attestation/attestation_policy_observer_unittest.cc",
     "attestation/fake_certificate.cc",
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_util.h b/chrome/browser/chromeos/arc/policy/arc_policy_util.h
index 417d040c..fe74cee 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_util.h
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_util.h
@@ -24,10 +24,17 @@
   // Wipe the user home and start again.
   kWipe = 2,
   // Ask the user if migration should be performed.
-  kAskUser = 3
+  kAskUser = 3,
+  // Minimal migration - similar to kWipe, but runs migration code with a small
+  // whitelist of files to preserve authentication data.
+  kMinimalMigrate = 4,
+  // Special case for EDU default: Behaves like kAskUser if the device model
+  // supported ARC on ecryptfs and ARC is enabled. Otherwise, behaves like
+  // kDisallowMigration.
+  kAskForEcryptfsArcUsers = 5,
 };
-constexpr size_t kEcryptfsMigrationActionCount =
-    static_cast<size_t>(EcryptfsMigrationAction::kAskUser);
+constexpr size_t kEcryptfsMigrationActionMaxValue =
+    static_cast<size_t>(EcryptfsMigrationAction::kAskForEcryptfsArcUsers);
 
 // Returns true if the account is managed. Otherwise false.
 bool IsAccountManaged(Profile* profile);
diff --git a/chrome/browser/chromeos/arc/tts/arc_tts_service.cc b/chrome/browser/chromeos/arc/tts/arc_tts_service.cc
index c2c6791f5..5602235 100644
--- a/chrome/browser/chromeos/arc/tts/arc_tts_service.cc
+++ b/chrome/browser/chromeos/arc/tts/arc_tts_service.cc
@@ -37,6 +37,11 @@
 }  // namespace
 
 // static
+BrowserContextKeyedServiceFactory* ArcTtsService::GetFactory() {
+  return ArcTtsServiceFactory::GetInstance();
+}
+
+// static
 ArcTtsService* ArcTtsService::GetForBrowserContext(
     content::BrowserContext* context) {
   return ArcTtsServiceFactory::GetForBrowserContext(context);
@@ -44,7 +49,9 @@
 
 ArcTtsService::ArcTtsService(content::BrowserContext* context,
                              ArcBridgeService* bridge_service)
-    : arc_bridge_service_(bridge_service), binding_(this) {
+    : arc_bridge_service_(bridge_service),
+      binding_(this),
+      tts_controller_(nullptr) {
   arc_bridge_service_->tts()->AddObserver(this);
 }
 
@@ -65,8 +72,15 @@
                                mojom::TtsEventType event_type,
                                uint32_t char_index,
                                const std::string& error_msg) {
-  if (!TtsController::GetInstance())
-    return;
+  if (!tts_controller_) {
+    // GetInstance() returns a base::Singleton<> object which always outlives
+    // |this| object.
+    tts_controller_ = TtsController::GetInstance();
+    if (!tts_controller_) {
+      LOG(WARNING) << "TtsController is not available.";
+      return;
+    }
+  }
 
   TtsEventType chrome_event_type;
   switch (event_type) {
@@ -83,8 +97,7 @@
       chrome_event_type = TTS_EVENT_ERROR;
       break;
   }
-  TtsController::GetInstance()->OnTtsEvent(id, chrome_event_type, char_index,
-                                           error_msg);
+  tts_controller_->OnTtsEvent(id, chrome_event_type, char_index, error_msg);
 }
 
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/tts/arc_tts_service.h b/chrome/browser/chromeos/arc/tts/arc_tts_service.h
index ff0f234f..7b33692 100644
--- a/chrome/browser/chromeos/arc/tts/arc_tts_service.h
+++ b/chrome/browser/chromeos/arc/tts/arc_tts_service.h
@@ -13,6 +13,9 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
+class BrowserContextKeyedServiceFactory;
+class TtsController;
+
 namespace content {
 class BrowserContext;
 }  // namespace content
@@ -27,6 +30,9 @@
                       public InstanceHolder<mojom::TtsInstance>::Observer,
                       public mojom::TtsHost {
  public:
+  // Returns the factory instance for this class.
+  static BrowserContextKeyedServiceFactory* GetFactory();
+
   // Returns singleton instance for the given BrowserContext,
   // or nullptr if the browser |context| is not allowed to use ARC.
   static ArcTtsService* GetForBrowserContext(content::BrowserContext* context);
@@ -44,10 +50,15 @@
                   uint32_t char_index,
                   const std::string& error_msg) override;
 
+  void set_tts_controller_for_testing(TtsController* tts_controller) {
+    tts_controller_ = tts_controller;
+  }
+
  private:
   ArcBridgeService* const arc_bridge_service_;  // Owned by ArcServiceManager.
 
   mojo::Binding<mojom::TtsHost> binding_;
+  TtsController* tts_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(ArcTtsService);
 };
diff --git a/chrome/browser/chromeos/arc/tts/arc_tts_service_unittest.cc b/chrome/browser/chromeos/arc/tts/arc_tts_service_unittest.cc
new file mode 100644
index 0000000..29147a5
--- /dev/null
+++ b/chrome/browser/chromeos/arc/tts/arc_tts_service_unittest.cc
@@ -0,0 +1,128 @@
+// 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/chromeos/arc/tts/arc_tts_service.h"
+
+#include <memory>
+
+#include "base/threading/platform_thread.h"
+#include "chrome/browser/chromeos/arc/arc_session_manager.h"
+#include "chrome/browser/speech/tts_controller_impl.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/arc/arc_service_manager.h"
+#include "components/arc/test/fake_arc_session.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace arc {
+
+namespace {
+
+class TestableTtsController : public TtsControllerImpl {
+ public:
+  TestableTtsController() = default;
+  ~TestableTtsController() override = default;
+
+  void OnTtsEvent(int utterance_id,
+                  TtsEventType event_type,
+                  int char_index,
+                  const std::string& error_message) override {
+    last_utterance_id_ = utterance_id;
+    last_event_type_ = event_type;
+    last_char_index_ = char_index;
+    last_error_message_ = error_message;
+  }
+
+  int last_utterance_id_;
+  TtsEventType last_event_type_;
+  int last_char_index_;
+  std::string last_error_message_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestableTtsController);
+};
+
+class ArcTtsServiceTest : public testing::Test {
+ public:
+  ArcTtsServiceTest() = default;
+  ~ArcTtsServiceTest() override = default;
+
+  void SetUp() override {
+    arc_service_manager_ = base::MakeUnique<ArcServiceManager>();
+    testing_profile_ = base::MakeUnique<TestingProfile>();
+    arc_session_manager_ = base::MakeUnique<ArcSessionManager>(
+        base::MakeUnique<ArcSessionRunner>(base::Bind(FakeArcSession::Create)));
+    tts_controller_ = base::MakeUnique<TestableTtsController>();
+
+    ArcTtsService::GetFactory()->SetTestingFactoryAndUse(
+        testing_profile_.get(),
+        [](content::BrowserContext* context) -> std::unique_ptr<KeyedService> {
+          return base::MakeUnique<ArcTtsService>(
+              context, ArcServiceManager::Get()->arc_bridge_service());
+        });
+    tts_service_ = ArcTtsService::GetForBrowserContext(testing_profile_.get());
+    tts_service_->set_tts_controller_for_testing(tts_controller_.get());
+  }
+
+  void TearDown() override {
+    tts_service_->Shutdown();
+
+    tts_controller_.reset();
+    arc_session_manager_.reset();
+    testing_profile_.reset();
+    arc_service_manager_.reset();
+  }
+
+ protected:
+  ArcTtsService* tts_service() const { return tts_service_; }
+  TestableTtsController* tts_controller() const {
+    return tts_controller_.get();
+  }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+  std::unique_ptr<ArcServiceManager> arc_service_manager_;
+  std::unique_ptr<TestingProfile> testing_profile_;
+  std::unique_ptr<ArcSessionManager> arc_session_manager_;
+  std::unique_ptr<TestableTtsController> tts_controller_;
+  ArcTtsService* tts_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcTtsServiceTest);
+};
+
+// Tests that ArcTtsService can be constructed and destructed.
+TEST_F(ArcTtsServiceTest, TestConstructDestruct) {}
+
+// Tests that OnTtsEvent() properly calls into TtsController::OnTtsEvent().
+TEST_F(ArcTtsServiceTest, TestOnTtsEvent) {
+  tts_service()->OnTtsEvent(1, mojom::TtsEventType::START, 0, "");
+  EXPECT_EQ(1, tts_controller()->last_utterance_id_);
+  EXPECT_EQ(TTS_EVENT_START, tts_controller()->last_event_type_);
+  EXPECT_EQ(0, tts_controller()->last_char_index_);
+  EXPECT_EQ("", tts_controller()->last_error_message_);
+
+  tts_service()->OnTtsEvent(1, mojom::TtsEventType::END, 10, "");
+  EXPECT_EQ(1, tts_controller()->last_utterance_id_);
+  EXPECT_EQ(TTS_EVENT_END, tts_controller()->last_event_type_);
+  EXPECT_EQ(10, tts_controller()->last_char_index_);
+  EXPECT_EQ("", tts_controller()->last_error_message_);
+
+  tts_service()->OnTtsEvent(2, mojom::TtsEventType::INTERRUPTED, 0, "");
+  EXPECT_EQ(2, tts_controller()->last_utterance_id_);
+  EXPECT_EQ(TTS_EVENT_INTERRUPTED, tts_controller()->last_event_type_);
+  EXPECT_EQ(0, tts_controller()->last_char_index_);
+  EXPECT_EQ("", tts_controller()->last_error_message_);
+
+  tts_service()->OnTtsEvent(3, mojom::TtsEventType::ERROR, 0, "");
+  EXPECT_EQ(3, tts_controller()->last_utterance_id_);
+  EXPECT_EQ(TTS_EVENT_ERROR, tts_controller()->last_event_type_);
+  EXPECT_EQ(0, tts_controller()->last_char_index_);
+  EXPECT_EQ("", tts_controller()->last_error_message_);
+}
+
+}  // namespace
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 143d93f..6edf09c 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -234,8 +234,8 @@
     return false;
 
   if (policy_proto.value() < 0 ||
-      policy_proto.value() >=
-          static_cast<int64_t>(apu::kEcryptfsMigrationActionCount)) {
+      policy_proto.value() >
+          static_cast<int64_t>(apu::kEcryptfsMigrationActionMaxValue)) {
     return false;
   }
 
@@ -1020,12 +1020,7 @@
     if (!DecodeMigrationActionFromPolicy(policy_payload.get(), &action)) {
       // User policy was present, but the EcryptfsMigrationStrategy policy value
       // was not there. Stay on the safe side and don't start migration.
-
-      // TODO(pmarko): bug747930: Temporarily, we default to ASK_USER for
-      // managed users who don't have the policy value, so testing migration is
-      // possible before the policy is supported server-side. This must be
-      // reverted before M61 goes stable.
-      action = apu::EcryptfsMigrationAction::kAskUser;
+      action = apu::EcryptfsMigrationAction::kDisallowMigration;
     }
   } else {
     // We don't know if the user has policy or not. Stay on the safe side and
@@ -1047,6 +1042,9 @@
                                     EncryptionMigrationMode::ASK_USER);
       break;
 
+    case apu::EcryptfsMigrationAction::kMinimalMigrate:
+    // Fall-through intended. Minimal migration behaves as Wipe for Chrome OS
+    // versions which don't support it yet.
     case apu::EcryptfsMigrationAction::kWipe:
       cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
           cryptohome::Identification(user_context.GetAccountId()),
@@ -1054,6 +1052,9 @@
                      weak_factory_.GetWeakPtr(), user_context));
       break;
 
+    case apu::EcryptfsMigrationAction::kAskForEcryptfsArcUsers:
+    // TODO(igorcov): Fall-through intended. This behaves as Disallow Migration
+    // until it's implemented.
     case apu::EcryptfsMigrationAction::kDisallowMigration:
       ContinuePerformLoginWithoutMigration(login_performer_->auth_mode(),
                                            user_context);
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
index 38ad4b2b..3a20732 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -334,8 +334,7 @@
     started_load_at_ = base::Time::Now();
 
     if (default_) {
-      manager->DoSetDefaultWallpaper(account_id_, true /* update_wallpaper */,
-                                     std::move(on_finish_));
+      manager->DoSetDefaultWallpaper(account_id_, std::move(on_finish_));
     } else if (!user_wallpaper_.isNull()) {
       SetWallpaper(user_wallpaper_, info_);
     } else if (!wallpaper_path_.empty()) {
@@ -348,8 +347,7 @@
                          base::Passed(std::move(on_finish_)),
                          manager->weak_factory_.GetWeakPtr()));
     } else if (!info_.location.empty()) {
-      manager->LoadWallpaper(account_id_, info_, true /* update_wallpaper */,
-                             std::move(on_finish_));
+      manager->LoadWallpaper(account_id_, info_, true, std::move(on_finish_));
     } else {
       // PendingWallpaper was created and never initialized?
       NOTREACHED();
@@ -698,7 +696,6 @@
 
 void WallpaperManager::DoSetDefaultWallpaper(
     const AccountId& account_id,
-    bool update_wallpaper,
     MovableOnDestroyCallbackHolder on_finish) {
   // There is no visible wallpaper in kiosk mode.
   if (user_manager::UserManager::Get()->IsLoggedInAsKioskApp())
@@ -732,26 +729,21 @@
     default_wallpaper_image_.reset();
     if (!file->empty()) {
       loaded_wallpapers_for_test_++;
-      StartLoadAndSetDefaultWallpaper(*file, layout, update_wallpaper,
-                                      std::move(on_finish),
+      StartLoadAndSetDefaultWallpaper(*file, layout, std::move(on_finish),
                                       &default_wallpaper_image_);
       return;
     }
 
     CreateSolidDefaultWallpaper();
   }
+  // 1x1 wallpaper is actually solid color, so it should be stretched.
+  if (default_wallpaper_image_->image().width() == 1 &&
+      default_wallpaper_image_->image().height() == 1)
+    layout = wallpaper::WALLPAPER_LAYOUT_STRETCH;
 
-  if (update_wallpaper) {
-    // 1x1 wallpaper is actually solid color, so it should be stretched.
-    if (default_wallpaper_image_->image().width() == 1 &&
-        default_wallpaper_image_->image().height() == 1) {
-      layout = wallpaper::WALLPAPER_LAYOUT_STRETCH;
-    }
-
-    WallpaperInfo info(default_wallpaper_image_->file_path().value(), layout,
-                       wallpaper::DEFAULT, base::Time::Now().LocalMidnight());
-    SetWallpaper(default_wallpaper_image_->image(), info);
-  }
+  WallpaperInfo info(default_wallpaper_image_->file_path().value(), layout,
+                     wallpaper::DEFAULT, base::Time::Now().LocalMidnight());
+  SetWallpaper(default_wallpaper_image_->image(), info);
 }
 
 void WallpaperManager::SetUserWallpaperInfo(const AccountId& account_id,
@@ -1271,7 +1263,9 @@
         "", wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED, wallpaper::DEFAULT,
         base::Time::Now().LocalMidnight());
     SetUserWallpaperInfo(account_id, default_info, true);
-    DoSetDefaultWallpaper(account_id, update_wallpaper, std::move(on_finish));
+
+    if (update_wallpaper)
+      DoSetDefaultWallpaper(account_id, std::move(on_finish));
     return;
   }
 
@@ -1410,7 +1404,6 @@
 void WallpaperManager::OnDefaultWallpaperDecoded(
     const base::FilePath& path,
     const wallpaper::WallpaperLayout layout,
-    bool update_wallpaper,
     std::unique_ptr<user_manager::UserImage>* result_out,
     MovableOnDestroyCallbackHolder on_finish,
     std::unique_ptr<user_manager::UserImage> user_image) {
@@ -1420,24 +1413,21 @@
   }
 
   *result_out = std::move(user_image);
-  if (update_wallpaper) {
-    WallpaperInfo info(path.value(), layout, wallpaper::DEFAULT,
-                       base::Time::Now().LocalMidnight());
-    SetWallpaper((*result_out)->image(), info);
-  }
+  WallpaperInfo info(path.value(), layout, wallpaper::DEFAULT,
+                     base::Time::Now().LocalMidnight());
+  SetWallpaper((*result_out)->image(), info);
 }
 
 void WallpaperManager::StartLoadAndSetDefaultWallpaper(
     const base::FilePath& path,
     const wallpaper::WallpaperLayout layout,
-    bool update_wallpaper,
     MovableOnDestroyCallbackHolder on_finish,
     std::unique_ptr<user_manager::UserImage>* result_out) {
   user_image_loader::StartWithFilePath(
       task_runner_, path, ImageDecoder::ROBUST_JPEG_CODEC,
       0,  // Do not crop.
       base::Bind(&WallpaperManager::OnDefaultWallpaperDecoded,
-                 weak_factory_.GetWeakPtr(), path, layout, update_wallpaper,
+                 weak_factory_.GetWeakPtr(), path, layout,
                  base::Unretained(result_out),
                  base::Passed(std::move(on_finish))));
 }
@@ -1479,8 +1469,8 @@
     }
   }
 
-  DoSetDefaultWallpaper(EmptyAccountId(), need_update_screen,
-                        MovableOnDestroyCallbackHolder());
+  if (need_update_screen)
+    DoSetDefaultWallpaper(EmptyAccountId(), MovableOnDestroyCallbackHolder());
 }
 
 void WallpaperManager::RecordWallpaperAppType() {
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
index 8715439..3de3f1e 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
@@ -82,7 +82,6 @@
   void SetDefaultWallpaperDelayed(const AccountId& account_id) override;
   void DoSetDefaultWallpaper(
       const AccountId& account_id,
-      bool update_wallpaper,
       wallpaper::MovableOnDestroyCallbackHolder on_finish) override;
   void SetUserWallpaperInfo(const AccountId& account_id,
                             const wallpaper::WallpaperInfo& info,
@@ -201,14 +200,12 @@
   void OnDefaultWallpaperDecoded(
       const base::FilePath& path,
       const wallpaper::WallpaperLayout layout,
-      bool update_wallpaper,
       std::unique_ptr<user_manager::UserImage>* result,
       wallpaper::MovableOnDestroyCallbackHolder on_finish,
       std::unique_ptr<user_manager::UserImage> user_image) override;
   void StartLoadAndSetDefaultWallpaper(
       const base::FilePath& path,
       const wallpaper::WallpaperLayout layout,
-      bool update_wallpaper,
       wallpaper::MovableOnDestroyCallbackHolder on_finish,
       std::unique_ptr<user_manager::UserImage>* result_out) override;
   void SetDefaultWallpaperPath(
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
index 2e970e5..68f80ca 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
@@ -851,63 +851,4 @@
   EXPECT_FALSE(WallpaperManager::Get()->IsPendingWallpaper(
       wallpaper::WallpaperResizer::GetImageId(image)));
 }
-
-// Tests that if there are multiple users on the device and if one user lost his
-// wallpaper somehow, the wallpapers should still show correctly on lock/login
-// screen.
-IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, CustomWallpaperLostTest) {
-  UpdateDisplay("640x480");
-  WallpaperManager* wallpaper_manager = WallpaperManager::Get();
-
-  LogIn(test_account_id1_, kTestUser1Hash);
-  wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
-
-  // Now log in |test_account_id2_| to make it the current active user.
-  LogIn(test_account_id2_, kTestUser2Hash);
-  wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
-  EXPECT_EQ(user_manager::UserManager::Get()->GetActiveUser()->GetAccountId(),
-            test_account_id2_);
-
-  // Set a different wallpaper for |test_account_id2_|.
-  std::string id = std::to_string(
-      std::abs((base::Time::Now() - base::Time::Now().LocalMidnight())
-                   .InMilliseconds()));
-  base::FilePath small_wallpaper_path = GetCustomWallpaperPath(
-      wallpaper::kSmallWallpaperSubDir, test_account2_wallpaper_files_id_, id);
-  ASSERT_TRUE(wallpaper_manager_test_utils::WriteJPEGFile(
-      small_wallpaper_path, kSmallWallpaperWidth, kSmallWallpaperHeight,
-      wallpaper_manager_test_utils::kCustomWallpaperColor));
-  std::string relative_path2 =
-      base::FilePath(test_account2_wallpaper_files_id_.id()).Append(id).value();
-  WallpaperInfo info2 = {relative_path2, WALLPAPER_LAYOUT_CENTER_CROPPED,
-                         wallpaper::CUSTOMIZED,
-                         base::Time::Now().LocalMidnight()};
-  wallpaper_manager->SetUserWallpaperInfo(test_account_id2_, info2, true);
-  wallpaper_manager->SetUserWallpaperNow(test_account_id2_);
-  wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
-  EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
-      controller_->GetWallpaper(),
-      wallpaper_manager_test_utils::kCustomWallpaperColor));
-
-  // Now simulate the lost of |test_account_id1_|'s wallpaper by only updating
-  // its WallpaperInfo but not providing its wallpaper. In this case we just
-  // fallback to the default wallpaper.
-  std::string relative_path =
-      base::FilePath(test_account1_wallpaper_files_id_.id()).Append(id).value();
-  // Saves wallpaper info to local state for user |test_account_id1_|.
-  WallpaperInfo info = {relative_path, WALLPAPER_LAYOUT_CENTER_CROPPED,
-                        wallpaper::CUSTOMIZED,
-                        base::Time::Now().LocalMidnight()};
-  wallpaper_manager->SetUserWallpaperInfo(test_account_id1_, info, true);
-
-  // Now simulate lock/login screen. On lock/login screen all user's wallpapers
-  // will be cached. Test that caching |test_account_id1_| wallpaper won't
-  // change the current wallpaper (|teset_account_id2_|'s wallpaper).
-  CacheUserWallpaper(test_account_id1_);
-  wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
-  EXPECT_TRUE(wallpaper_manager_test_utils::ImageIsNearColor(
-      controller_->GetWallpaper(),
-      wallpaper_manager_test_utils::kCustomWallpaperColor));
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/system_logs/single_log_file_log_source.cc b/chrome/browser/chromeos/system_logs/single_log_file_log_source.cc
index 33ea341..e94185d 100644
--- a/chrome/browser/chromeos/system_logs/single_log_file_log_source.cc
+++ b/chrome/browser/chromeos/system_logs/single_log_file_log_source.cc
@@ -44,6 +44,8 @@
       return base::FilePath("ui/ui.LATEST");
     case SupportedSource::kAtrusLog:
       return base::FilePath("atrus.log");
+    case SupportedSource::kNetLog:
+      return base::FilePath("net.log");
   }
   NOTREACHED();
   return base::FilePath();
@@ -85,6 +87,7 @@
   switch (source_type) {
     case SupportedSource::kMessages:
     case SupportedSource::kAtrusLog:
+    case SupportedSource::kNetLog:
       return true;
     case SupportedSource::kUiLatest:
       return false;
diff --git a/chrome/browser/chromeos/system_logs/single_log_file_log_source.h b/chrome/browser/chromeos/system_logs/single_log_file_log_source.h
index e3ee9e3..e180158 100644
--- a/chrome/browser/chromeos/system_logs/single_log_file_log_source.h
+++ b/chrome/browser/chromeos/system_logs/single_log_file_log_source.h
@@ -32,6 +32,9 @@
 
     // For /var/log/atrus.log.
     kAtrusLog,
+
+    // For /var/log/net.log.
+    kNetLog,
   };
 
   explicit SingleLogFileLogSource(SupportedSource source);
diff --git a/chrome/browser/content_settings/host_content_settings_map_factory.cc b/chrome/browser/content_settings/host_content_settings_map_factory.cc
index 3febe81af..d852f57f 100644
--- a/chrome/browser/content_settings/host_content_settings_map_factory.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_factory.cc
@@ -115,17 +115,20 @@
 #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 
 #if defined(OS_ANDROID)
-  if (base::FeatureList::IsEnabled(features::kSiteNotificationChannels)) {
     auto channels_provider =
         base::MakeUnique<NotificationChannelsProviderAndroid>();
-    channels_provider->MigrateToChannelsIfNecessary(
-        profile->GetPrefs(), settings_map->GetPrefProvider());
-    settings_map->RegisterUserModifiableProvider(
-        HostContentSettingsMap::NOTIFICATION_ANDROID_PROVIDER,
-        std::move(channels_provider));
+    if (base::FeatureList::IsEnabled(features::kSiteNotificationChannels)) {
+      channels_provider->MigrateToChannelsIfNecessary(
+          profile->GetPrefs(), settings_map->GetPrefProvider());
+      settings_map->RegisterUserModifiableProvider(
+          HostContentSettingsMap::NOTIFICATION_ANDROID_PROVIDER,
+          std::move(channels_provider));
+    } else {
+      // TODO(crbug.com/758553): Remove this unmigration code and the feature
+      // flag once we're confident a kill-switch is no longer necessary (M63?).
+      channels_provider->UnmigrateChannelsIfNecessary(
+          profile->GetPrefs(), settings_map->GetPrefProvider());
   }
-// TODO(crbug.com/700377): Should delete site channels if feature becomes
-// disabled.
 #endif  // defined (OS_ANDROID)
   return settings_map;
 }
diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
index 8933b58c..930346a 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
+++ b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
@@ -442,8 +442,10 @@
   if (delegate) {
 #if defined(USE_AURA)
     ui::AXActionData data;
-    ConvertToAXActionData(params.get(), &data);
+    ExtensionFunction::ResponseAction result =
+        ConvertToAXActionData(params.get(), &data);
     delegate->PerformAction(data);
+    return result;
 #else
     NOTREACHED();
     return RespondNow(Error("Unexpected action on desktop automation tree;"
diff --git a/chrome/browser/notifications/notification_channels_provider_android.cc b/chrome/browser/notifications/notification_channels_provider_android.cc
index 3e961aa..d7e450ff 100644
--- a/chrome/browser/notifications/notification_channels_provider_android.cc
+++ b/chrome/browser/notifications/notification_channels_provider_android.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/time/default_clock.h"
+#include "base/values.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
@@ -146,10 +147,8 @@
 // static
 void NotificationChannelsProviderAndroid::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
-  if (base::FeatureList::IsEnabled(features::kSiteNotificationChannels)) {
-    registry->RegisterBooleanPref(prefs::kMigratedToSiteNotificationChannels,
-                                  false);
-  }
+  registry->RegisterBooleanPref(prefs::kMigratedToSiteNotificationChannels,
+                                false);
 }
 
 NotificationChannel::NotificationChannel(const std::string& id,
@@ -193,6 +192,30 @@
   prefs->SetBoolean(prefs::kMigratedToSiteNotificationChannels, true);
 }
 
+void NotificationChannelsProviderAndroid::UnmigrateChannelsIfNecessary(
+    PrefService* prefs,
+    content_settings::ProviderInterface* pref_provider) {
+  if (!should_use_channels_ ||
+      !prefs->GetBoolean(prefs::kMigratedToSiteNotificationChannels)) {
+    return;
+  }
+  std::unique_ptr<content_settings::RuleIterator> it(
+      GetRuleIterator(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
+                      false /* incognito */));
+  while (it && it->HasNext()) {
+    const content_settings::Rule& rule = it->Next();
+    pref_provider->SetWebsiteSetting(rule.primary_pattern,
+                                     rule.secondary_pattern,
+                                     CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                                     content_settings::ResourceIdentifier(),
+                                     new base::Value(rule.value->Clone()));
+  }
+  for (auto& channel : bridge_->GetChannels())
+    bridge_->DeleteChannel(channel.id);
+
+  prefs->SetBoolean(prefs::kMigratedToSiteNotificationChannels, false);
+}
+
 std::unique_ptr<content_settings::RuleIterator>
 NotificationChannelsProviderAndroid::GetRuleIterator(
     ContentSettingsType content_type,
diff --git a/chrome/browser/notifications/notification_channels_provider_android.h b/chrome/browser/notifications/notification_channels_provider_android.h
index 4fcf69f..27ef04f4 100644
--- a/chrome/browser/notifications/notification_channels_provider_android.h
+++ b/chrome/browser/notifications/notification_channels_provider_android.h
@@ -73,6 +73,12 @@
       PrefService* prefs,
       content_settings::ProviderInterface* pref_provider);
 
+  // Undoes the migration done by |MigrateToChannelsIfNecessary|, if we
+  // previously migrated to channels and did not already un-migrate.
+  void UnmigrateChannelsIfNecessary(
+      PrefService* prefs,
+      content_settings::ProviderInterface* pref_provider);
+
   // UserModifiableProvider methods.
   std::unique_ptr<content_settings::RuleIterator> GetRuleIterator(
       ContentSettingsType content_type,
diff --git a/chrome/browser/notifications/notification_channels_provider_android_unittest.cc b/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
index 8234c6a..d08210b 100644
--- a/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
+++ b/chrome/browser/notifications/notification_channels_provider_android_unittest.cc
@@ -618,3 +618,56 @@
                                                    old_provider.get());
   EXPECT_EQ(fake_bridge_->GetChannels().size(), 0u);
 }
+
+TEST_F(NotificationChannelsProviderAndroidTest,
+       UnmigrateChannels_DeletesChannelsAndUpdatesPrefProvider) {
+  InitChannelsProvider(true /* should_use_channels */);
+  auto mock_pref_provider = base::MakeUnique<content_settings::MockProvider>();
+  profile_->GetPrefs()->SetBoolean(prefs::kMigratedToSiteNotificationChannels,
+                                   true);
+
+  // Give the channels provider some notification settings to provide.
+  ContentSettingsPattern blocked_pattern =
+      ContentSettingsPattern::FromURLNoWildcard(GURL("https://blocked.com"));
+  ContentSettingsPattern allowed_pattern =
+      ContentSettingsPattern::FromURLNoWildcard(GURL("https://allowed.com"));
+  channels_provider_->SetWebsiteSetting(
+      blocked_pattern, ContentSettingsPattern::Wildcard(),
+      CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
+      new base::Value(CONTENT_SETTING_BLOCK));
+  channels_provider_->SetWebsiteSetting(
+      allowed_pattern, ContentSettingsPattern::Wildcard(),
+      CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
+      new base::Value(CONTENT_SETTING_ALLOW));
+  ASSERT_EQ(fake_bridge_->GetChannels().size(), 2u);
+
+  channels_provider_->UnmigrateChannelsIfNecessary(profile_->GetPrefs(),
+                                                   mock_pref_provider.get());
+  EXPECT_EQ(fake_bridge_->GetChannels().size(), 0u);
+
+  std::unique_ptr<content_settings::RuleIterator> it =
+      mock_pref_provider->GetRuleIterator(
+          CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+          content_settings::ResourceIdentifier(), false /* incognito */);
+  bool checked_allowed = false;
+  bool checked_blocked = false;
+  for (size_t i = 0; i < 2; ++i) {
+    ASSERT_TRUE(it->HasNext());
+    const content_settings::Rule& rule = it->Next();
+    if (rule.primary_pattern == allowed_pattern) {
+      ASSERT_FALSE(checked_allowed);
+      EXPECT_EQ(CONTENT_SETTING_ALLOW,
+                content_settings::ValueToContentSetting(rule.value.get()));
+      checked_allowed = true;
+    } else {
+      ASSERT_FALSE(checked_blocked);
+      ASSERT_EQ(rule.primary_pattern, blocked_pattern);
+      EXPECT_EQ(CONTENT_SETTING_BLOCK,
+                content_settings::ValueToContentSetting(rule.value.get()));
+      checked_blocked = true;
+    }
+  }
+  EXPECT_FALSE(it->HasNext());
+  EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(
+      prefs::kMigratedToSiteNotificationChannels));
+}
diff --git a/chrome/browser/password_manager/password_manager_util_win.cc b/chrome/browser/password_manager/password_manager_util_win.cc
index c883e8f..d01d2b7 100644
--- a/chrome/browser/password_manager/password_manager_util_win.cc
+++ b/chrome/browser/password_manager/password_manager_util_win.cc
@@ -5,6 +5,7 @@
 // windows.h must be first otherwise Win8 SDK breaks.
 #include <windows.h>
 #include <LM.h>
+#include <objbase.h>  // For CoTaskMemFree()
 #include <stddef.h>
 #include <stdint.h>
 #include <wincred.h>
@@ -21,10 +22,12 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/time/time.h"
+#include "base/win/win_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/grit/chromium_strings.h"
 #include "components/password_manager/core/browser/password_manager.h"
@@ -71,6 +74,28 @@
   bool blank_password_;
 };
 
+// A WCHAR string buffer that securely zeros itself out on desctruction.
+class SecureStringBuffer {
+ public:
+  // Allocates a WCHAR string buffer of |length| characters.
+  explicit SecureStringBuffer(DWORD length)
+      : buffer_(new WCHAR[length]), length_(length) {}
+  ~SecureStringBuffer() {
+    SecureZeroMemory(buffer_.get(), length_ * sizeof(WCHAR));
+  }
+
+  WCHAR* get() { return buffer_.get(); }
+
+ private:
+  std::unique_ptr<WCHAR[]> buffer_;
+  DWORD length_;
+};
+
+// TODO(crbug.com/574581) Remove this feature once this is confirmed to work
+// as expected.
+const base::Feature kCredUIPromptForWindowsCredentialsFeature{
+    "CredUIPromptForWindowsCredentials", base::FEATURE_ENABLED_BY_DEFAULT};
+
 void PasswordCheckPrefs::Read(PrefService* local_state) {
   blank_password_ =
       local_state->GetBoolean(password_manager::prefs::kOsPasswordBlank);
@@ -211,15 +236,10 @@
                  base::Passed(&status)));
 }
 
-}  // namespace
-
-void DelayReportOsPassword() {
-  content::BrowserThread::PostDelayedTask(content::BrowserThread::UI, FROM_HERE,
-                                          base::Bind(&GetOsPasswordStatus),
-                                          base::TimeDelta::FromSeconds(40));
-}
-
-bool AuthenticateUser(gfx::NativeWindow window) {
+// Authenticate the user using the old Windows credential prompt.
+// TODO(crbug.com/574581) Remove this feature once this is confirmed to work
+// as expected.
+bool AuthenticateUserOld(gfx::NativeWindow window) {
   bool retval = false;
   CREDUI_INFO cui = {};
   WCHAR username[CREDUI_MAX_USERNAME_LENGTH+1] = {};
@@ -312,4 +332,151 @@
   return retval;
 }
 
+// Authenticate the user using the new Windows credential prompt.  The new
+// prompt allows the user to authenticate using additional credential providers,
+// such as PINs, smartcards, fingerprint scanners, and so on.  It also still
+// allows the user to authenticate with their password.  This old prompt only
+// supported password authentication which is not enough for enterprise
+// environments.
+bool AuthenticateUserNew(gfx::NativeWindow window) {
+  bool retval = false;
+  WCHAR cur_username[CREDUI_MAX_USERNAME_LENGTH + 1] = {};
+  DWORD cur_username_length = arraysize(cur_username);
+
+  // The SAM compatible username works on both standalone workstations and
+  // domain joined machines.  The form is "DOMAIN\username", where DOMAIN is the
+  // the name of the machine for standalone workstations.
+  if (!GetUserNameEx(NameSamCompatible, cur_username, &cur_username_length)) {
+    DLOG(ERROR) << "Unable to obtain username " << GetLastError();
+    return false;
+  }
+
+  // If this is a standlone workstation, it's possible the current user has no
+  // password, so check here and allow it.
+  if (!base::win::IsEnrolledToDomain() && CheckBlankPassword(cur_username))
+    return true;
+
+  // Build the strings to display in the credential UI.  If these strings are
+  // left empty on domain joined machines, CredUIPromptForWindowsCredentials()
+  // fails to run.
+  base::string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
+  base::string16 password_prompt =
+      l10n_util::GetStringUTF16(IDS_PASSWORDS_PAGE_AUTHENTICATION_PROMPT);
+  CREDUI_INFO cui;
+  cui.cbSize = sizeof(cui);
+  cui.hwndParent = window->GetHost()->GetAcceleratedWidget();
+  cui.pszMessageText = password_prompt.c_str();
+  cui.pszCaptionText = product_name.c_str();
+  cui.hbmBanner = nullptr;
+
+  DWORD err = 0;
+  size_t tries = 0;
+  do {
+    tries++;
+
+    // Show credential prompt, displaying error from previous try if needed.
+    // TODO(wfh): Make sure we support smart cards here.
+    ULONG auth_package = 0;
+    LPVOID cred_buffer = nullptr;
+    ULONG cred_buffer_size = 0;
+    err = CredUIPromptForWindowsCredentials(
+        &cui, err, &auth_package, nullptr, 0, &cred_buffer, &cred_buffer_size,
+        nullptr, CREDUIWIN_ENUMERATE_CURRENT_USER);
+    if (err != ERROR_SUCCESS)
+      break;
+
+    // Try to unpack the authentication buffer.  If this fails, try again.
+    // By not using the flag CRED_PACK_PROTECTED_CREDENTIALS, the password
+    // in |cred_password| remains encrypted.  That's OK though, the call to
+    // LogonUser() below handles that correctly.
+    WCHAR cred_username[CREDUI_MAX_USERNAME_LENGTH + 1] = {};
+    DWORD cred_username_length = arraysize(cred_username);
+    WCHAR cred_domain[CREDUI_MAX_USERNAME_LENGTH + 1] = {};
+    DWORD cred_domain_length = arraysize(cred_domain);
+    DWORD cred_password_length = CREDUI_MAX_USERNAME_LENGTH + 1;
+    SecureStringBuffer cred_password(cred_password_length);
+    BOOL ret = CredUnPackAuthenticationBuffer(
+        0, cred_buffer, cred_buffer_size, cred_username, &cred_username_length,
+        cred_domain, &cred_domain_length, cred_password.get(),
+        &cred_password_length);
+    SecureZeroMemory(cred_buffer, cred_buffer_size);
+    CoTaskMemFree(cred_buffer);
+    if (!ret) {
+      err = GetLastError();
+      continue;
+    }
+
+    // While CredUIPromptForWindowsCredentials() shows the currently logged
+    // on user by default, it can be changed at runtime.  This is important,
+    // as it allows users to change to a different type of authentication
+    // mechanism, such as PIN or smartcard.  However, this also allows the user
+    // to change to a completely different account on the machine.  Make sure
+    // the user authenticated with the credentials of the currently logged on
+    // user.
+    //
+    // When the buffer returned by CredUIPromptForWindowsCredentials() is
+    // unpacked, |cred_username| is of the form "DOMAIN\username" and
+    // |cred_domain| is empty.  I have tested this on both standalone
+    // workstations and domain joined machines.  This seems to be different
+    // behaviour than CredUIPromptForCredentials().  This makes |cred_username|
+    // comparable to |cur_username| above.
+    if (wcsicmp(cred_username, cur_username) != 0) {
+      err = ERROR_LOGON_FAILURE;
+      continue;
+    }
+
+    // As explained above, extract the domain from |cred_username|.  The code
+    // does not use |cred_domain_length| to determine the length of the domain
+    // string because CredUnPackAuthenticationBuffer() will not update it, and
+    // will leave |cred_domain| untouched, when the domain is returned as part
+    // of the username.
+    // TODO(rogerta): Figure out when |cred_domain| buffer is actually used,
+    // I could not find a case where it was.
+    WCHAR username[CREDUI_MAX_USERNAME_LENGTH + 1] = {};
+    WCHAR domain[CREDUI_MAX_USERNAME_LENGTH + 1] = {};
+    LPWSTR backslash = wcschr(cred_username, L'\\');
+    if (wcslen(cred_domain) == 0 && backslash != nullptr) {
+      *backslash = 0;
+      wcscpy_s(domain, CREDUI_MAX_USERNAME_LENGTH, cred_username);
+      wcscpy_s(username, CREDUI_MAX_USERNAME_LENGTH, backslash + 1);
+    } else {
+      DLOG(ERROR) << "Unexpected domain and/or username";
+      break;
+    }
+
+    // Validate the returned credentials by trying to logon.
+    HANDLE handle = INVALID_HANDLE_VALUE;
+    if (LogonUser(username, domain, cred_password.get(),
+                  LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
+                  &handle)) {
+      retval = true;
+      CloseHandle(handle);
+    } else {
+      err = GetLastError();
+      if (err == ERROR_ACCOUNT_RESTRICTION && cred_password_length == 0) {
+        // Password is blank, so permit.
+        retval = true;
+      } else {
+        DLOG(ERROR) << "Unable to authenticate " << GetLastError();
+      }
+    }
+  } while (!retval && tries < kMaxPasswordRetries);
+
+  return retval;
+}
+
+}  // namespace
+
+void DelayReportOsPassword() {
+  content::BrowserThread::PostDelayedTask(content::BrowserThread::UI, FROM_HERE,
+                                          base::Bind(&GetOsPasswordStatus),
+                                          base::TimeDelta::FromSeconds(40));
+}
+
+bool AuthenticateUser(gfx::NativeWindow window) {
+  return base::FeatureList::IsEnabled(kCredUIPromptForWindowsCredentialsFeature)
+             ? AuthenticateUserNew(window)
+             : AuthenticateUserOld(window);
+}
+
 }  // namespace password_manager_util_win
diff --git a/chrome/browser/profiling_host/profiling_process_host.cc b/chrome/browser/profiling_host/profiling_process_host.cc
index 187a0423..6fd08ae 100644
--- a/chrome/browser/profiling_host/profiling_process_host.cc
+++ b/chrome/browser/profiling_host/profiling_process_host.cc
@@ -12,6 +12,8 @@
 #include "base/task_scheduler/post_task.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "build/build_config.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/tracing/crash_service_uploader.h"
 #include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/profiling/constants.mojom.h"
@@ -54,6 +56,10 @@
 
 const size_t kMaxTraceSizeUploadInBytes = 10 * 1024 * 1024;
 
+void OnTraceUploadComplete(TraceCrashServiceUploader* uploader,
+                           bool success,
+                           const std::string& feedback);
+
 void UploadTraceToCrashServer(base::FilePath file_path) {
   std::string file_contents;
   if (!base::ReadFileToStringWithMaxSize(file_path, &file_contents,
@@ -62,8 +68,21 @@
     return;
   }
 
-  // TODO(bug 753514): Upload the trace |file_contents| to crash server (slow
-  // reports).
+  TraceCrashServiceUploader* uploader = new TraceCrashServiceUploader(
+      g_browser_process->system_request_context());
+
+  uploader->DoUpload(file_contents, content::TraceUploader::UNCOMPRESSED_UPLOAD,
+                     nullptr, content::TraceUploader::UploadProgressCallback(),
+                     base::Bind(&OnTraceUploadComplete, base::Owned(uploader)));
+}
+
+void OnTraceUploadComplete(TraceCrashServiceUploader* uploader,
+                           bool success,
+                           const std::string& feedback) {
+  if (!success) {
+    LOG(ERROR) << "Cannot upload trace file: " << feedback;
+    return;
+  }
 }
 
 }  // namespace
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
index 259fda5..395bb9e 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
@@ -345,7 +345,7 @@
   // Ignore some roles.
   return AutomationPredicate.leaf(node) && (AutomationPredicate.roles([
            Role.CLIENT, Role.COLUMN, Role.GENERIC_CONTAINER, Role.GROUP,
-           Role.IMAGE, Role.STATIC_TEXT, Role.SVG_ROOT,
+           Role.IMAGE, Role.PARAGRAPH, Role.STATIC_TEXT, Role.SVG_ROOT,
            Role.TABLE_HEADER_CONTAINER, Role.UNKNOWN
          ])(node));
 };
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
index 3ca03d3..0ff8b5fb 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
@@ -800,9 +800,8 @@
           };
           scrollable.addEventListener(
               EventType.SCROLL_POSITION_CHANGED, innerCallback, true);
-        } else {
-          ChromeVoxState.instance.navigateToRange(current, false, speechProps);
         }
+        ChromeVoxState.instance.navigateToRange(current, false, speechProps);
       };
 
       if (dir == Dir.FORWARD)
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index 8cab4a4..5243c50 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -69,14 +69,12 @@
   // items.
   void OnNewTabPageOpened();
 
-  // Most visited item API.
-
+  // Most visited item APIs.
+  //
   // Invoked when the Instant page wants to delete a Most Visited item.
   void DeleteMostVisitedItem(const GURL& url);
-
   // Invoked when the Instant page wants to undo the deletion.
   void UndoMostVisitedDeletion(const GURL& url);
-
   // Invoked when the Instant page wants to undo all Most Visited deletions.
   void UndoAllMostVisitedDeletions();
 
diff --git a/chrome/browser/ui/browser_instant_controller.cc b/chrome/browser/ui/browser_instant_controller.cc
index c1a543a..73c8bfb 100644
--- a/chrome/browser/ui/browser_instant_controller.cc
+++ b/chrome/browser/ui/browser_instant_controller.cc
@@ -147,9 +147,9 @@
     prerenderer->Cancel();
 }
 
-void BrowserInstantController::ModelChanged(SearchModel::Origin old_origin,
-                                            SearchModel::Origin new_origin) {
-  instant_.SearchModeChanged(old_origin, new_origin);
+void BrowserInstantController::ModelChanged(const SearchMode& old_mode,
+                                            const SearchMode& new_mode) {
+  instant_.SearchModeChanged(old_mode, new_mode);
 }
 
 void BrowserInstantController::DefaultSearchProviderChanged(
@@ -174,8 +174,7 @@
       continue;
 
     SearchModel* model = SearchTabHelper::FromWebContents(contents)->model();
-    if (google_base_url_domain_changed &&
-        model->origin() == SearchModel::Origin::NTP) {
+    if (google_base_url_domain_changed && model->mode().is_origin_ntp()) {
       GURL local_ntp_url(chrome::kChromeSearchLocalNtpUrl);
       // Replace the server NTP with the local NTP.
       content::NavigationController::LoadURLParams params(local_ntp_url);
diff --git a/chrome/browser/ui/browser_instant_controller.h b/chrome/browser/ui/browser_instant_controller.h
index 52e0169..3f9ba5f 100644
--- a/chrome/browser/ui/browser_instant_controller.h
+++ b/chrome/browser/ui/browser_instant_controller.h
@@ -43,8 +43,8 @@
 
  private:
   // SearchModelObserver:
-  void ModelChanged(SearchModel::Origin old_origin,
-                    SearchModel::Origin new_origin) override;
+  void ModelChanged(const SearchMode& old_mode,
+                    const SearchMode& new_mode) override;
 
   // InstantServiceObserver:
   void DefaultSearchProviderChanged(
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
index b42afba..3e0d3192 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
@@ -28,7 +28,6 @@
 
 // Common icon that shows next to most rows in the list.
 @property(readonly, retain, nonatomic) NSImage* image;
-@property(retain, nonatomic) NSImage* incognitoImage;
 
 // Uncommon icon that only shows on answer rows (e.g. weather).
 @property(readonly, retain, nonatomic) NSImage* answerImage;
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
index 658cbd32..c5b4af0f 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
@@ -378,7 +378,6 @@
 @synthesize description = description_;
 @synthesize prefix = prefix_;
 @synthesize image = image_;
-@synthesize incognitoImage = incognitoImage_;
 @synthesize answerImage = answerImage_;
 @synthesize isContentsRTL = isContentsRTL_;
 @synthesize isAnswer = isAnswer_;
@@ -497,20 +496,18 @@
   NSWindow* parentWindow = [[controlView window] parentWindow];
   BOOL isDarkTheme = [parentWindow hasDarkTheme];
   NSRect imageRect = cellFrame;
-  NSImage* theImage =
-      isDarkTheme ? [cellData incognitoImage] : [cellData image];
-  imageRect.size = [theImage size];
+  imageRect.size = [[cellData image] size];
   imageRect.origin.x += kMaterialImageXOffset + [tableView contentLeftPadding];
   imageRect.origin.y +=
       GetVerticalMargin() + kMaterialExtraVerticalImagePadding;
   if (isVerticalLayout)
     imageRect.origin.y += halfLineHeight;
-  [theImage drawInRect:FlipIfRTL(imageRect, cellFrame)
-              fromRect:NSZeroRect
-             operation:NSCompositeSourceOver
-              fraction:1.0
-        respectFlipped:YES
-                 hints:nil];
+  [[cellData image] drawInRect:FlipIfRTL(imageRect, cellFrame)
+                      fromRect:NSZeroRect
+                     operation:NSCompositeSourceOver
+                      fraction:1.0
+                respectFlipped:YES
+                         hints:nil];
 
   CGFloat left = kMaterialTextStartOffset + [tableView contentLeftPadding];
   NSPoint origin = NSMakePoint(left, GetVerticalMargin());
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
index 0b70e65..fbd49ec 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
@@ -42,8 +42,6 @@
                      image:popupView.ImageForMatch(match)
                answerImage:(match.answer ? answerImage : nil)
               forDarkTheme:isDarkTheme]);
-    if (isDarkTheme)
-      [cellData setIncognitoImage:popupView.ImageForMatch(match)];
     [array addObject:cellData];
   }
 
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
index fa294af..1021811 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
@@ -40,6 +40,7 @@
   void InvalidateLine(size_t line) override {}
   void OnLineSelected(size_t line) override {}
   void UpdatePopupAppearance() override;
+  void SetMatchIcon(size_t match_index, const gfx::Image& icon) override;
   gfx::Rect GetTargetBounds() override;
   // This is only called by model in SetSelectedLine() after updating
   // everything.  Popup should already be visible.
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
index 3b0ab4d2..d9af395 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
@@ -132,6 +132,11 @@
   PositionPopup(NSHeight([matrix_ frame]));
 }
 
+void OmniboxPopupViewMac::SetMatchIcon(size_t match_index,
+                                       const gfx::Image& icon) {
+  // TODO(tommycli): Implement favicons for Cocoa.
+}
+
 gfx::Rect OmniboxPopupViewMac::GetTargetBounds() {
   // Flip the coordinate system before returning.
   NSScreen* screen = [[NSScreen screens] firstObject];
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
index 1038d795..4a92758b0 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
@@ -60,6 +60,7 @@
   void InvalidateLine(size_t line) override {}
   void OnLineSelected(size_t line) override {}
   void UpdatePopupAppearance() override {}
+  void SetMatchIcon(size_t match_index, const gfx::Image& icon) override {}
   gfx::Rect GetTargetBounds() override { return gfx::Rect(); }
   void PaintUpdatesNow() override {}
   void OnDragCanceled() override {}
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
index f6875cb..94160c7 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/bookmarks/bookmark_stats.h"
 #include "chrome/browser/command_updater.h"
 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/net/predictor.h"
 #include "chrome/browser/predictors/autocomplete_action_predictor.h"
 #include "chrome/browser/predictors/autocomplete_action_predictor_factory.h"
@@ -40,6 +41,8 @@
 #include "chrome/common/search/instant_types.h"
 #include "chrome/common/url_constants.h"
 #include "components/favicon/content/content_favicon_driver.h"
+#include "components/favicon/core/favicon_service.h"
+#include "components/favicon_base/favicon_types.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_result.h"
 #include "components/omnibox/browser/search_provider.h"
@@ -119,6 +122,11 @@
   callback_.Run(image);
 }
 
+void OnFaviconFetched(const FaviconFetchedCallback& on_favicon_fetched,
+                      const favicon_base::FaviconImageResult& result) {
+  on_favicon_fetched.Run(result.image);
+}
+
 }  // namespace
 
 ChromeOmniboxClient::ChromeOmniboxClient(OmniboxEditController* controller,
@@ -275,7 +283,7 @@
 void ChromeOmniboxClient::OnResultChanged(
     const AutocompleteResult& result,
     bool default_match_changed,
-    const base::Callback<void(const SkBitmap& bitmap)>& on_bitmap_fetched) {
+    const BitmapFetchedCallback& on_bitmap_fetched) {
   if (search::IsInstantExtendedAPIEnabled() &&
       (default_match_changed && result.default_match() != result.end())) {
     InstantSuggestion prefetch_suggestion;
@@ -350,6 +358,22 @@
   }
 }
 
+void ChromeOmniboxClient::GetFaviconForPageUrl(
+    base::CancelableTaskTracker* tracker,
+    const GURL& page_url,
+    const FaviconFetchedCallback& on_favicon_fetched) {
+  favicon::FaviconService* favicon_service =
+      FaviconServiceFactory::GetForProfile(profile_,
+                                           ServiceAccessType::EXPLICIT_ACCESS);
+  if (!favicon_service)
+    return;
+
+  // TODO(tommycli): Investigate using the version of this method that specifies
+  // the desired size.
+  favicon_service->GetFaviconImageForPageURL(
+      page_url, base::Bind(&OnFaviconFetched, on_favicon_fetched), tracker);
+}
+
 void ChromeOmniboxClient::OnCurrentMatchChanged(
     const AutocompleteMatch& match) {
   if (!prerender::IsOmniboxEnabled(profile_))
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.h b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
index 787397c..f7a88bd 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.h
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
@@ -55,8 +55,11 @@
                       OmniboxFocusChangeReason reason) override;
   void OnResultChanged(const AutocompleteResult& result,
                        bool default_match_changed,
-                       const base::Callback<void(const SkBitmap& bitmap)>&
-                           on_bitmap_fetched) override;
+                       const BitmapFetchedCallback& on_bitmap_fetched) override;
+  void GetFaviconForPageUrl(
+      base::CancelableTaskTracker* tracker,
+      const GURL& page_url,
+      const FaviconFetchedCallback& on_favicon_fetched) override;
   void OnCurrentMatchChanged(const AutocompleteMatch& match) override;
   void OnTextChanged(const AutocompleteMatch& current_match,
                      bool user_input_in_progress,
diff --git a/chrome/browser/ui/search/instant_controller.cc b/chrome/browser/ui/search/instant_controller.cc
index f6fb998..46a6ced1 100644
--- a/chrome/browser/ui/search/instant_controller.cc
+++ b/chrome/browser/ui/search/instant_controller.cc
@@ -21,12 +21,12 @@
 
 InstantController::~InstantController() = default;
 
-void InstantController::SearchModeChanged(SearchModel::Origin old_origin,
-                                          SearchModel::Origin new_origin) {
-  LogDebugEvent(base::StringPrintf("SearchModeChanged: %d to %d", old_origin,
-                                   new_origin));
+void InstantController::SearchModeChanged(const SearchMode& old_mode,
+                                          const SearchMode& new_mode) {
+  LogDebugEvent(base::StringPrintf("SearchModeChanged: %d to %d",
+                                   old_mode.origin, new_mode.origin));
 
-  search_origin_ = new_origin;
+  search_mode_ = new_mode;
   ResetInstantTab();
 }
 
@@ -65,7 +65,7 @@
 }
 
 void InstantController::ResetInstantTab() {
-  if (search_origin_ == SearchModel::Origin::NTP) {
+  if (search_mode_.is_origin_ntp()) {
     content::WebContents* active_tab = browser_->GetActiveWebContents();
     if (!instant_tab_ || active_tab != instant_tab_->web_contents()) {
       instant_tab_ = base::MakeUnique<InstantTab>(this, active_tab);
diff --git a/chrome/browser/ui/search/instant_controller.h b/chrome/browser/ui/search/instant_controller.h
index e7c97f9d..b5edc38 100644
--- a/chrome/browser/ui/search/instant_controller.h
+++ b/chrome/browser/ui/search/instant_controller.h
@@ -15,7 +15,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "chrome/browser/ui/search/instant_tab.h"
-#include "chrome/browser/ui/search/search_model.h"
+#include "chrome/common/search/search_types.h"
 
 class BrowserInstantController;
 
@@ -36,8 +36,8 @@
 
   // The search mode in the active tab has changed. Bind |instant_tab_| if the
   // |new_mode| reflects an Instant NTP.
-  void SearchModeChanged(SearchModel::Origin old_origin,
-                         SearchModel::Origin new_origin);
+  void SearchModeChanged(const SearchMode& old_mode,
+                         const SearchMode& new_mode);
 
   // The user switched tabs. Bind |instant_tab_| if the newly active tab is an
   // Instant NTP.
@@ -82,7 +82,7 @@
   std::unique_ptr<InstantTab> instant_tab_;
 
   // The search model mode for the active tab.
-  SearchModel::Origin search_origin_;
+  SearchMode search_mode_;
 
   // List of events and their timestamps, useful in debugging Instant behaviour.
   mutable std::list<std::pair<int64_t, std::string>> debug_events_;
diff --git a/chrome/browser/ui/search/search_delegate.cc b/chrome/browser/ui/search/search_delegate.cc
index e71f803b..d9f4310 100644
--- a/chrome/browser/ui/search/search_delegate.cc
+++ b/chrome/browser/ui/search/search_delegate.cc
@@ -14,16 +14,16 @@
   DCHECK(!tab_model_) << "All tabs should have been deactivated or closed.";
 }
 
-void SearchDelegate::ModelChanged(SearchModel::Origin old_origin,
-                                  SearchModel::Origin new_origin) {
-  browser_model_->SetOrigin(new_origin);
+void SearchDelegate::ModelChanged(const SearchMode& old_mode,
+                                  const SearchMode& new_mode) {
+  browser_model_->SetMode(new_mode);
 }
 
 void SearchDelegate::OnTabActivated(content::WebContents* web_contents) {
   if (tab_model_)
     tab_model_->RemoveObserver(this);
   tab_model_ = SearchTabHelper::FromWebContents(web_contents)->model();
-  browser_model_->SetOrigin(tab_model_->origin());
+  browser_model_->SetMode(tab_model_->mode());
   tab_model_->AddObserver(this);
 }
 
diff --git a/chrome/browser/ui/search/search_delegate.h b/chrome/browser/ui/search/search_delegate.h
index c1f41382..752c301 100644
--- a/chrome/browser/ui/search/search_delegate.h
+++ b/chrome/browser/ui/search/search_delegate.h
@@ -27,8 +27,8 @@
   ~SearchDelegate() override;
 
   // Overrides for SearchModelObserver:
-  void ModelChanged(SearchModel::Origin old_origin,
-                    SearchModel::Origin new_origin) override;
+  void ModelChanged(const SearchMode& old_mode,
+                    const SearchMode& new_mode) override;
 
   // When the active tab is changed, the model state of this new active tab is
   // propagated to the browser.
diff --git a/chrome/browser/ui/search/search_delegate_unittest.cc b/chrome/browser/ui/search/search_delegate_unittest.cc
index 1e6a22b..0db0e78 100644
--- a/chrome/browser/ui/search/search_delegate_unittest.cc
+++ b/chrome/browser/ui/search/search_delegate_unittest.cc
@@ -14,15 +14,15 @@
 // the browser's search model.
 TEST_F(SearchDelegateTest, SearchModel) {
   // Initial state.
-  EXPECT_EQ(SearchModel::Origin::DEFAULT, browser()->search_model()->origin());
+  EXPECT_TRUE(browser()->search_model()->mode().is_origin_default());
 
   // Propagate change from tab's search model to browser's search model.
   AddTab(browser(), GURL("http://foo/0"));
   content::WebContents* first_tab =
       browser()->tab_strip_model()->GetWebContentsAt(0);
-  SearchTabHelper::FromWebContents(first_tab)->model()->SetOrigin(
-      SearchModel::Origin::NTP);
-  EXPECT_EQ(SearchModel::Origin::NTP, browser()->search_model()->origin());
+  SearchTabHelper::FromWebContents(first_tab)->model()->SetMode(
+      SearchMode(SearchMode::ORIGIN_NTP));
+  EXPECT_TRUE(browser()->search_model()->mode().is_origin_ntp());
 
   // Add second tab (it gets inserted at index 0), make it active, and make sure
   // its mode changes propagate to the browser's search model.
@@ -31,14 +31,14 @@
       browser()->tab_strip_model()->GetWebContentsAt(0);
   ASSERT_NE(first_tab, second_tab);
   browser()->tab_strip_model()->ActivateTabAt(0, true);
-  EXPECT_EQ(SearchModel::Origin::DEFAULT, browser()->search_model()->origin());
+  EXPECT_TRUE(browser()->search_model()->mode().is_origin_default());
   SearchTabHelper::FromWebContents(second_tab)
       ->model()
-      ->SetOrigin(SearchModel::Origin::NTP);
-  EXPECT_EQ(SearchModel::Origin::NTP, browser()->search_model()->origin());
+      ->SetMode(SearchMode(SearchMode::ORIGIN_NTP));
+  EXPECT_TRUE(browser()->search_model()->mode().is_origin_ntp());
 
   // The first tab is not active so changes should not propagate.
-  SearchTabHelper::FromWebContents(first_tab)->model()->SetOrigin(
-      SearchModel::Origin::DEFAULT);
-  EXPECT_EQ(SearchModel::Origin::NTP, browser()->search_model()->origin());
+  SearchTabHelper::FromWebContents(first_tab)->model()->SetMode(
+      SearchMode(SearchMode::ORIGIN_DEFAULT));
+  EXPECT_TRUE(browser()->search_model()->mode().is_origin_ntp());
 }
diff --git a/chrome/browser/ui/search/search_model.cc b/chrome/browser/ui/search/search_model.cc
index aa51e105..2e1498f 100644
--- a/chrome/browser/ui/search/search_model.cc
+++ b/chrome/browser/ui/search/search_model.cc
@@ -7,23 +7,23 @@
 #include "chrome/browser/ui/search/search_model_observer.h"
 #include "components/search/search.h"
 
-SearchModel::SearchModel() : origin_(Origin::DEFAULT) {}
+SearchModel::SearchModel() = default;
 
 SearchModel::~SearchModel() = default;
 
-void SearchModel::SetOrigin(Origin origin) {
+void SearchModel::SetMode(const SearchMode& new_mode) {
   DCHECK(search::IsInstantExtendedAPIEnabled())
       << "Please do not try to set the SearchModel mode without first "
       << "checking if Search is enabled.";
 
-  if (origin_ == origin)
+  if (mode_ == new_mode)
     return;
 
-  const Origin old_origin = origin_;
-  origin_ = origin;
+  const SearchMode old_mode = mode_;
+  mode_ = new_mode;
 
   for (SearchModelObserver& observer : observers_)
-    observer.ModelChanged(old_origin, origin_);
+    observer.ModelChanged(old_mode, mode_);
 }
 
 void SearchModel::AddObserver(SearchModelObserver* observer) {
diff --git a/chrome/browser/ui/search/search_model.h b/chrome/browser/ui/search/search_model.h
index 1196bda..1be3ad3 100644
--- a/chrome/browser/ui/search/search_model.h
+++ b/chrome/browser/ui/search/search_model.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/observer_list.h"
+#include "chrome/common/search/search_types.h"
 
 class SearchModelObserver;
 
@@ -14,30 +15,24 @@
 // changes.
 class SearchModel {
  public:
-  enum class Origin {
-    // The user is on some page other than the NTP.
-    DEFAULT = 0,
-
-    // The user is on the NTP.
-    NTP,
-  };
-
   SearchModel();
   ~SearchModel();
 
-  // Change the origin.  Change notifications are sent to observers.
-  void SetOrigin(Origin origin);
+  // Change the mode.  Change notifications are sent to observers.
+  void SetMode(const SearchMode& mode);
 
-  // Get the active origin.
-  Origin origin() const { return origin_; }
+  // Get the active mode.
+  const SearchMode& mode() const { return mode_; }
 
   // Add and remove observers.
   void AddObserver(SearchModelObserver* observer);
   void RemoveObserver(SearchModelObserver* observer);
 
  private:
-  Origin origin_;
+  // Current state of model.
+  SearchMode mode_;
 
+  // Observers.
   base::ObserverList<SearchModelObserver> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchModel);
diff --git a/chrome/browser/ui/search/search_model_observer.h b/chrome/browser/ui/search/search_model_observer.h
index 371aa00..4303f26 100644
--- a/chrome/browser/ui/search/search_model_observer.h
+++ b/chrome/browser/ui/search/search_model_observer.h
@@ -11,8 +11,8 @@
 class SearchModelObserver {
  public:
   // Informs the observer that the model's state has changed.
-  virtual void ModelChanged(SearchModel::Origin old_origin,
-                            SearchModel::Origin new_origin) = 0;
+  virtual void ModelChanged(const SearchMode& old_mode,
+                            const SearchMode& new_mode) = 0;
 
  protected:
   virtual ~SearchModelObserver() {}
diff --git a/chrome/browser/ui/search/search_model_unittest.cc b/chrome/browser/ui/search/search_model_unittest.cc
index dbf6e8e..35cabe0 100644
--- a/chrome/browser/ui/search/search_model_unittest.cc
+++ b/chrome/browser/ui/search/search_model_unittest.cc
@@ -8,6 +8,8 @@
 #include "base/macros.h"
 #include "chrome/browser/ui/search/search_model_observer.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/search/search_types.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 
 namespace {
@@ -17,11 +19,11 @@
   MockSearchModelObserver();
   ~MockSearchModelObserver() override;
 
-  void ModelChanged(SearchModel::Origin old_origin,
-                    SearchModel::Origin new_origin) override;
+  void ModelChanged(const SearchMode& old_mode,
+                    const SearchMode& new_mode) override;
 
-  void VerifySearchModelStates(SearchModel::Origin expected_old_origin,
-                               SearchModel::Origin expected_new_origin);
+  void VerifySearchModelStates(const SearchMode& expected_old_mode,
+                               const SearchMode& expected_new_mode);
 
   void VerifyNotificationCount(int expected_count);
 
@@ -29,8 +31,8 @@
   // How many times we've seen search model changed notifications.
   int modelchanged_notification_count_;
 
-  SearchModel::Origin actual_old_origin_;
-  SearchModel::Origin actual_new_origin_;
+  SearchMode actual_old_mode_;
+  SearchMode actual_new_mode_;
 
   DISALLOW_COPY_AND_ASSIGN(MockSearchModelObserver);
 };
@@ -42,18 +44,18 @@
 MockSearchModelObserver::~MockSearchModelObserver() {
 }
 
-void MockSearchModelObserver::ModelChanged(SearchModel::Origin old_origin,
-                                           SearchModel::Origin new_origin) {
-  actual_old_origin_ = old_origin;
-  actual_new_origin_ = new_origin;
+void MockSearchModelObserver::ModelChanged(const SearchMode& old_mode,
+                                           const SearchMode& new_mode) {
+  actual_old_mode_ = old_mode;
+  actual_new_mode_ = new_mode;
   modelchanged_notification_count_++;
 }
 
 void MockSearchModelObserver::VerifySearchModelStates(
-    SearchModel::Origin expected_old_origin,
-    SearchModel::Origin expected_new_origin) {
-  EXPECT_TRUE(actual_old_origin_ == expected_old_origin);
-  EXPECT_TRUE(actual_new_origin_ == expected_new_origin);
+    const SearchMode& expected_old_mode,
+    const SearchMode& expected_new_mode) {
+  EXPECT_TRUE(actual_old_mode_ == expected_old_mode);
+  EXPECT_TRUE(actual_new_mode_ == expected_new_mode);
 }
 
 void MockSearchModelObserver::VerifyNotificationCount(int expected_count) {
@@ -88,20 +90,18 @@
 
 TEST_F(SearchModelTest, UpdateSearchModelOrigin) {
   mock_observer.VerifyNotificationCount(0);
-  SearchModel::Origin origin = SearchModel::Origin::NTP;
-  SearchModel::Origin expected_old_origin = model->origin();
-  SearchModel::Origin expected_new_origin = origin;
-  model->SetOrigin(origin);
-  mock_observer.VerifySearchModelStates(expected_old_origin,
-                                        expected_new_origin);
+  SearchMode search_mode(SearchMode::ORIGIN_NTP);
+  SearchMode expected_old_mode = model->mode();
+  SearchMode expected_new_mode = search_mode;
+  model->SetMode(search_mode);
+  mock_observer.VerifySearchModelStates(expected_old_mode, expected_new_mode);
   mock_observer.VerifyNotificationCount(1);
 
-  origin = SearchModel::Origin::DEFAULT;
-  expected_old_origin = expected_new_origin;
-  expected_new_origin = origin;
-  model->SetOrigin(origin);
-  mock_observer.VerifySearchModelStates(expected_old_origin,
-                                        expected_new_origin);
+  search_mode.origin = SearchMode::ORIGIN_DEFAULT;
+  expected_old_mode = expected_new_mode;
+  expected_new_mode = search_mode;
+  model->SetMode(search_mode);
+  mock_observer.VerifySearchModelStates(expected_old_mode, expected_new_mode);
   mock_observer.VerifyNotificationCount(2);
-  EXPECT_EQ(expected_new_origin, model->origin());
+  EXPECT_TRUE(model->mode() == expected_new_mode);
 }
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index cb64c5c1..5d5ed8f 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -435,12 +435,11 @@
 }
 
 void SearchTabHelper::UpdateMode() {
-  bool is_ntp = IsNTP(web_contents_);
+  SearchMode::Origin origin = IsNTP(web_contents_) ? SearchMode::ORIGIN_NTP
+                                                   : SearchMode::ORIGIN_DEFAULT;
+  model_.SetMode(SearchMode(origin));
 
-  model_.SetOrigin(is_ntp ? SearchModel::Origin::NTP
-                          : SearchModel::Origin::DEFAULT);
-
-  if (is_ntp)
+  if (model_.mode().is_origin_ntp())
     ipc_router_.SetInputInProgress(IsInputInProgress());
 }
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 51f0d669..f9fec81f 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -318,6 +318,12 @@
   Layout();
 }
 
+void OmniboxPopupContentsView::SetMatchIcon(size_t match_index,
+                                            const gfx::Image& icon) {
+  OmniboxResultView* view = result_view_at(match_index);
+  view->SetCustomIcon(icon.AsImageSkia());
+}
+
 gfx::Rect OmniboxPopupContentsView::GetTargetBounds() {
   return target_bounds_;
 }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h
index 91d5629..114f1bb 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h
@@ -46,6 +46,7 @@
   void InvalidateLine(size_t line) override;
   void OnLineSelected(size_t line) override;
   void UpdatePopupAppearance() override;
+  void SetMatchIcon(size_t match_index, const gfx::Image& icon) override;
   gfx::Rect GetTargetBounds() override;
   void PaintUpdatesNow() override;
   void OnDragCanceled() override;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index bf6d529..bdb8769 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -505,6 +505,11 @@
   return contents_rendertext_->GetContentWidth();
 }
 
+void OmniboxResultView::SetCustomIcon(const gfx::ImageSkia& icon) {
+  custom_icon_ = icon;
+  SchedulePaint();
+}
+
 void OmniboxResultView::SetAnswerImage(const gfx::ImageSkia& image) {
   answer_image_ = image;
   SchedulePaint();
@@ -515,10 +520,15 @@
 }
 
 gfx::ImageSkia OmniboxResultView::GetIcon() const {
+  // TODO(tommycli): Consolidate the extension icons, custom icons, and vector
+  // icons into a single concept at the cross-platform layer.
   const gfx::Image image = model_->GetIconIfExtensionMatch(model_index_);
   if (!image.IsEmpty())
     return image.AsImageSkia();
 
+  if (!custom_icon_.isNull())
+    return custom_icon_;
+
   return GetVectorIcon(model_->IsStarredMatch(match_)
                            ? omnibox::kStarIcon
                            : AutocompleteMatch::TypeToVectorIcon(match_.type));
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.h b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
index bea63c1d..1fee668 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
@@ -83,6 +83,9 @@
   // Returns the display width required for the match contents.
   int GetMatchContentsWidth() const;
 
+  // Stores a custom icon as a local data member and schedules a repaint.
+  void SetCustomIcon(const gfx::ImageSkia& icon);
+
   // Stores the image in a local data member and schedules a repaint.
   void SetAnswerImage(const gfx::ImageSkia& image);
 
@@ -211,6 +214,8 @@
 
   std::unique_ptr<gfx::SlideAnimation> animation_;
 
+  gfx::ImageSkia custom_icon_;
+
   // If the answer has an icon, cache the image.
   gfx::ImageSkia answer_image_;
 
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 633f1eae..3ddcd54 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -44,7 +44,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
 #include "ui/gfx/animation/animation_container.h"
-#include "ui/gfx/animation/throb_animation.h"
+#include "ui/gfx/animation/tween.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_analysis.h"
 #include "ui/gfx/favicon_size.h"
@@ -433,13 +433,14 @@
       detached_(false),
       favicon_hiding_offset_(0),
       should_display_crashed_favicon_(false),
-      pulse_animation_(new gfx::ThrobAnimation(this)),
-      crash_icon_animation_(new FaviconCrashAnimation(this)),
+      pulse_animation_(this),
+      crash_icon_animation_(this),
       animation_container_(container),
       throbber_(nullptr),
       alert_indicator_button_(nullptr),
       close_button_(nullptr),
       title_(new views::Label()),
+      title_animation_(this),
       tab_activated_with_last_tap_down_(false),
       hover_controller_(this),
       showing_icon_(false),
@@ -494,8 +495,11 @@
   set_context_menu_controller(this);
 
   const int kPulseDurationMs = 200;
-  pulse_animation_->SetSlideDuration(kPulseDurationMs);
-  pulse_animation_->SetContainer(animation_container_.get());
+  pulse_animation_.SetSlideDuration(kPulseDurationMs);
+  pulse_animation_.SetContainer(animation_container_.get());
+
+  title_animation_.SetDuration(base::TimeDelta::FromMilliseconds(100));
+  title_animation_.SetContainer(animation_container_.get());
 
   hover_controller_.SetAnimationContainer(animation_container_.get());
 }
@@ -545,13 +549,13 @@
   title_->SetText(title);
 
   if (!data_.IsCrashed()) {
-    crash_icon_animation_->Stop();
+    crash_icon_animation_.Stop();
     SetShouldDisplayCrashedFavicon(false);
     favicon_hiding_offset_ = 0;
   } else if (!should_display_crashed_favicon_ &&
-             !crash_icon_animation_->is_animating()) {
+             !crash_icon_animation_.is_animating()) {
     data_.alert_state = TabAlertState::NONE;
-    crash_icon_animation_->Start();
+    crash_icon_animation_.Start();
   }
 
   if (data_.alert_state != old.alert_state)
@@ -574,11 +578,11 @@
 }
 
 void Tab::StartPulse() {
-  pulse_animation_->StartThrobbing(std::numeric_limits<int>::max());
+  pulse_animation_.StartThrobbing(std::numeric_limits<int>::max());
 }
 
 void Tab::StopPulse() {
-  pulse_animation_->Stop();
+  pulse_animation_.Stop();
 }
 
 void Tab::SetTabNeedsAttention(bool value) {
@@ -656,10 +660,20 @@
 // Tab, AnimationDelegate overrides:
 
 void Tab::AnimationProgressed(const gfx::Animation* animation) {
+  if (animation == &title_animation_) {
+    title_->SetBoundsRect(gfx::Tween::RectValueBetween(
+        gfx::Tween::CalculateValue(gfx::Tween::FAST_OUT_SLOW_IN,
+                                   animation->GetCurrentValue()),
+        start_title_bounds_, target_title_bounds_));
+    return;
+  }
+
   // Ignore if the pulse animation is being performed on active tab because
   // it repaints the same image. See PaintTab().
-  if ((animation != pulse_animation_.get()) || !IsActive())
-    SchedulePaint();
+  if (animation == &pulse_animation_ && IsActive())
+    return;
+
+  SchedulePaint();
 }
 
 void Tab::AnimationCanceled(const gfx::Animation* animation) {
@@ -667,7 +681,10 @@
 }
 
 void Tab::AnimationEnded(const gfx::Animation* animation) {
-  SchedulePaint();
+  if (animation == &title_animation_)
+    title_->SetBoundsRect(target_title_bounds_);
+  else
+    SchedulePaint();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -748,6 +765,7 @@
 
 void Tab::Layout() {
   const gfx::Rect lb = GetContentsBounds();
+  const bool was_showing_icon = showing_icon_;
   showing_icon_ = ShouldShowIcon();
   // See comments in IconCapacity().
   const int extra_padding =
@@ -822,8 +840,19 @@
     // The Label will automatically center the font's cap height within the
     // provided vertical space.
     const gfx::Rect title_bounds(title_left, lb.y(), title_width, lb.height());
-    title_->SetBoundsRect(title_bounds);
     show_title = title_width > 0;
+
+    if (title_bounds != target_title_bounds_) {
+      target_title_bounds_ = title_bounds;
+      if (was_showing_icon == showing_icon_ || title_->bounds().IsEmpty() ||
+          title_bounds.IsEmpty()) {
+        title_animation_.Stop();
+        title_->SetBoundsRect(title_bounds);
+      } else if (!title_animation_.is_animating()) {
+        start_title_bounds_ = title_->bounds();
+        title_animation_.Start();
+      }
+    }
   }
   title_->SetVisible(show_title);
 }
@@ -1385,8 +1414,8 @@
   const double offset =
       is_selected ? (kSelectedTabThrobScale * kHoverOpacity) : kHoverOpacity;
 
-  if (pulse_animation_->is_animating())
-    val += pulse_animation_->GetCurrentValue() * offset;
+  if (pulse_animation_.is_animating())
+    val += pulse_animation_.GetCurrentValue() * offset;
   else if (hover_controller_.ShouldDraw())
     val += hover_controller_.GetAnimationValue() * offset;
   return val;
@@ -1433,7 +1462,7 @@
     return;
 
   // Extends the area to the bottom when the crash animation is in progress.
-  if (crash_icon_animation_->is_animating())
+  if (crash_icon_animation_.is_animating())
     bounds.set_height(height() - bounds.y());
   SchedulePaintInRect(GetMirroredRect(bounds));
 }
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 634d3165..e567427f 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
 #include "ui/base/layout.h"
 #include "ui/gfx/animation/animation_delegate.h"
+#include "ui/gfx/animation/linear_animation.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/paint_throbber.h"
@@ -323,17 +324,23 @@
   bool showing_attention_indicator_ = false;
 
   // Whole-tab throbbing "pulse" animation.
-  std::unique_ptr<gfx::ThrobAnimation> pulse_animation_;
+  gfx::ThrobAnimation pulse_animation_;
 
   // Crash icon animation (in place of favicon).
-  std::unique_ptr<gfx::LinearAnimation> crash_icon_animation_;
+  gfx::LinearAnimation crash_icon_animation_;
 
   scoped_refptr<gfx::AnimationContainer> animation_container_;
 
   ThrobberView* throbber_;
   AlertIndicatorButton* alert_indicator_button_;
   views::ImageButton* close_button_;
+
   views::Label* title_;
+  // The title's bounds are animated when switching between showing and hiding
+  // the tab's favicon/throbber.
+  gfx::Rect start_title_bounds_;
+  gfx::Rect target_title_bounds_;
+  gfx::LinearAnimation title_animation_;
 
   bool tab_activated_with_last_tap_down_;
 
diff --git a/chrome/browser/ui/views/touch_events_interactive_uitest_win.cc b/chrome/browser/ui/views/touch_events_interactive_uitest_win.cc
index 0d7f41f..6276558f 100644
--- a/chrome/browser/ui/views/touch_events_interactive_uitest_win.cc
+++ b/chrome/browser/ui/views/touch_events_interactive_uitest_win.cc
@@ -11,6 +11,7 @@
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/test/ui_controls.h"
+#include "ui/events/gestures/gesture_recognizer_impl.h"
 #include "ui/views/controls/menu/menu_runner.h"
 
 namespace {
@@ -94,6 +95,39 @@
   DISALLOW_COPY_AND_ASSIGN(TouchEventHandler);
 };
 
+class TestingGestureRecognizer : public ui::GestureRecognizerImpl {
+ public:
+  TestingGestureRecognizer() = default;
+  ~TestingGestureRecognizer() override = default;
+
+  int num_touch_press_events() const { return num_touch_press_events_; }
+  int num_touch_release_events() const { return num_touch_release_events_; }
+
+ protected:
+  // Overriden from GestureRecognizerImpl:
+  bool ProcessTouchEventPreDispatch(ui::TouchEvent* event,
+                                    ui::GestureConsumer* consumer) override {
+    switch (event->type()) {
+      case ui::ET_TOUCH_PRESSED:
+        num_touch_press_events_++;
+        break;
+      case ui::ET_TOUCH_RELEASED:
+        num_touch_release_events_++;
+        break;
+      default:
+        break;
+    }
+
+    return ui::GestureRecognizerImpl::ProcessTouchEventPreDispatch(event,
+                                                                   consumer);
+  }
+
+ private:
+  int num_touch_press_events_ = 0;
+  int num_touch_release_events_ = 0;
+  DISALLOW_COPY_AND_ASSIGN(TestingGestureRecognizer);
+};
+
 }  // namespace
 
 class TouchEventsViewTest : public ViewEventTestBase {
@@ -103,11 +137,15 @@
   // ViewEventTestBase:
   void SetUp() override {
     touch_view_ = new views::View();
+    initial_gr_ = ui::GestureRecognizer::Get();
+    gesture_recognizer_ = std::make_unique<TestingGestureRecognizer>();
+    ui::SetGestureRecognizerForTesting(gesture_recognizer_.get());
     ViewEventTestBase::SetUp();
   }
 
   void TearDown() override {
     touch_view_ = nullptr;
+    ui::SetGestureRecognizerForTesting(initial_gr_);
     ViewEventTestBase::TearDown();
   }
 
@@ -140,6 +178,11 @@
     EXPECT_EQ(touch_pointer_count, touch_event_handler.num_touch_presses());
     EXPECT_EQ(0, touch_event_handler.num_pointers_down());
 
+    EXPECT_EQ(touch_pointer_count,
+              gesture_recognizer_->num_touch_press_events());
+    EXPECT_EQ(touch_pointer_count,
+              gesture_recognizer_->num_touch_release_events());
+
     GetWidget()->GetNativeWindow()->GetHost()->window()->RemovePreTargetHandler(
         &touch_event_handler);
     Done();
@@ -147,6 +190,8 @@
 
  protected:
   views::View* touch_view_ = nullptr;
+  std::unique_ptr<TestingGestureRecognizer> gesture_recognizer_;
+  ui::GestureRecognizer* initial_gr_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(TouchEventsViewTest);
 };
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 653e769..e3dc174 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -168,6 +168,7 @@
     "search/instant_types.cc",
     "search/instant_types.h",
     "search/ntp_logging_events.h",
+    "search/search_types.h",
     "search/search_urls.cc",
     "search/search_urls.h",
     "secure_origin_whitelist.cc",
diff --git a/chrome/common/search/search_types.h b/chrome/common/search/search_types.h
new file mode 100644
index 0000000..4d04b048
--- /dev/null
+++ b/chrome/common/search/search_types.h
@@ -0,0 +1,42 @@
+// 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_COMMON_SEARCH_SEARCH_TYPES_H_
+#define CHROME_COMMON_SEARCH_SEARCH_TYPES_H_
+
+// The Mode structure encodes the visual states encountered when interacting
+// with the NTP and the Omnibox.
+// TODO(treib): Replace this struct by just the enum Origin. crbug.com/627747
+struct SearchMode {
+  // The kind of page from which the user initiated the current search.
+  enum Origin {
+    // The user is searching from some random page.
+    ORIGIN_DEFAULT = 0,
+
+    // The user is searching from the NTP.
+    ORIGIN_NTP,
+  };
+
+  SearchMode() : origin(ORIGIN_DEFAULT) {}
+
+  explicit SearchMode(Origin in_origin) : origin(in_origin) {}
+
+  bool operator==(const SearchMode& rhs) const { return origin == rhs.origin; }
+
+  bool operator!=(const SearchMode& rhs) const {
+    return !(*this == rhs);
+  }
+
+  bool is_origin_default() const {
+    return origin == ORIGIN_DEFAULT;
+  }
+
+  bool is_origin_ntp() const {
+    return origin == ORIGIN_NTP;
+  }
+
+  Origin origin;
+};
+
+#endif  // CHROME_COMMON_SEARCH_SEARCH_TYPES_H_
diff --git a/chrome/test/chromedriver/VERSION b/chrome/test/chromedriver/VERSION
index 3125d73..0f34dc7 100644
--- a/chrome/test/chromedriver/VERSION
+++ b/chrome/test/chromedriver/VERSION
@@ -1 +1 @@
-2.31
+2.32
diff --git a/chromecast/browser/android/BUILD.gn b/chromecast/browser/android/BUILD.gn
index 708752ed..823ea11e 100644
--- a/chromecast/browser/android/BUILD.gn
+++ b/chromecast/browser/android/BUILD.gn
@@ -95,6 +95,7 @@
   srcjar_deps = [ ":cast_shell_build_config_gen" ]
 
   deps = [
+    ":cast_intents_java",
     ":cast_shell_java",
     "//base:base_java_test_support",
     "//content/public/android:content_java",
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
index 2a5371c..1fe92e2 100644
--- a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
+++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
@@ -74,7 +74,7 @@
         Assume.assumeFalse(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE);
 
         BroadcastReceiver receiver = Mockito.mock(BroadcastReceiver.class);
-        IntentFilter intentFilter = new IntentFilter(CastWebContentsActivity.ACTION_STOP_ACTIVITY);
+        IntentFilter intentFilter = new IntentFilter(CastIntents.ACTION_STOP_ACTIVITY);
         intentFilter.addDataScheme(CastWebContentsComponent.ACTION_DATA_SCHEME);
         intentFilter.addDataAuthority(CastWebContentsComponent.ACTION_DATA_AUTHORITY, null);
         intentFilter.addDataPath("/" + INSTANCE_ID, PatternMatcher.PATTERN_LITERAL);
@@ -151,4 +151,4 @@
 
         verify(mActivity, never()).unbindService(any(ServiceConnection.class));
     }
-}
\ No newline at end of file
+}
diff --git a/chromecast/public/cast_media_shlib.h b/chromecast/public/cast_media_shlib.h
index f2ff0763..e9976c8 100644
--- a/chromecast/public/cast_media_shlib.h
+++ b/chromecast/public/cast_media_shlib.h
@@ -125,6 +125,13 @@
   static void SetPostProcessorConfig(const std::string& name,
                                      const std::string& config)
       __attribute__((__weak__));
+
+  // Only used on Chromecast: set and clear an image on the video plane.
+  // Image data is 8-bit ARGB format; |data| buffer byte length must be
+  // |width|*|height|*4. Returns whether the image could be successfully set.
+  static bool SetVideoPlaneImage(int width, int height, const uint8_t* data)
+      __attribute__((__weak__));
+  static void ClearVideoPlaneImage() __attribute__((__weak__));
 };
 
 }  // namespace media
diff --git a/components/domain_reliability/context.h b/components/domain_reliability/context.h
index db62852..aa77580 100644
--- a/components/domain_reliability/context.h
+++ b/components/domain_reliability/context.h
@@ -7,10 +7,10 @@
 
 #include <stddef.h>
 
-#include <deque>
 #include <memory>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
@@ -119,8 +119,7 @@
   DomainReliabilityDispatcher* dispatcher_;
   DomainReliabilityUploader* uploader_;
 
-  // We use erase() so this can't be a base::circular_deque.
-  std::deque<std::unique_ptr<DomainReliabilityBeacon>> beacons_;
+  base::circular_deque<std::unique_ptr<DomainReliabilityBeacon>> beacons_;
   size_t uploading_beacons_size_;
   base::TimeTicks upload_time_;
   base::TimeTicks last_upload_time_;
diff --git a/components/drive/job_queue.h b/components/drive/job_queue.h
index 5da2ac3b..341527b 100644
--- a/components/drive/job_queue.h
+++ b/components/drive/job_queue.h
@@ -8,10 +8,10 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <deque>
 #include <set>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "components/drive/job_list.h"
 
@@ -79,9 +79,7 @@
   };
 
   const size_t num_max_concurrent_jobs_;
-  // TODO(http://crbug.com/757231) use a base::circular_deque when it supports
-  // erase().
-  std::vector<std::deque<Item>> queue_;
+  std::vector<base::circular_deque<Item>> queue_;
   const size_t num_max_batch_jobs_;
   const size_t max_batch_size_;
   std::set<JobID> running_;
diff --git a/components/keyed_service/core/dependency_graph.cc b/components/keyed_service/core/dependency_graph.cc
index d776f217..8d500f6 100644
--- a/components/keyed_service/core/dependency_graph.cc
+++ b/components/keyed_service/core/dependency_graph.cc
@@ -7,9 +7,9 @@
 #include <stddef.h>
 
 #include <algorithm>
-#include <deque>
 #include <iterator>
 
+#include "base/containers/circular_deque.h"
 #include "base/stl_util.h"
 #include "base/strings/string_piece.h"
 
@@ -91,9 +91,8 @@
 
 bool DependencyGraph::BuildConstructionOrder() {
   // Step 1: Build a set of nodes with no incoming edges.
-  // TODO(http://crbug.com/757231) use a base::circular_deque when it supports
-  // erase().
-  std::deque<DependencyNode*> queue(all_nodes_.begin(), all_nodes_.end());
+  base::circular_deque<DependencyNode*> queue(all_nodes_.begin(),
+                                              all_nodes_.end());
   for (const auto& pair : edges_)
     base::Erase(queue, pair.second);
 
@@ -144,9 +143,8 @@
   std::string escaped_toplevel_name = Escape(toplevel_name);
 
   // Make a copy of all nodes.
-  // TODO(http://crbug.com/757231) use a base::circular_deque when it supports
-  // erase().
-  std::deque<DependencyNode*> nodes(all_nodes_.begin(), all_nodes_.end());
+  base::circular_deque<DependencyNode*> nodes(all_nodes_.begin(),
+                                              all_nodes_.end());
 
   // State all dependencies and remove |second| so we don't generate an
   // implicit dependency on the top level node.
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
index cf0eda9..da04ece 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h"
 
-#include <deque>
 #include <map>
 #include <utility>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/json/json_reader.h"
 #include "base/memory/ptr_util.h"
 #include "base/optional.h"
@@ -218,9 +218,7 @@
     DropAndCallDelegate(fetcher_id);
   }
 
-  // TODO(http://crbug.com/757231) use a base::circular_deque when it supports
-  // erase().
-  std::deque<int> fetchers_;
+  base::circular_deque<int> fetchers_;
 };
 
 // Factory for FakeURLFetcher objects that always generate errors.
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl.h b/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
index ea6036b..f450c3c1 100644
--- a/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
+++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
@@ -6,7 +6,6 @@
 #define COMPONENTS_NTP_SNIPPETS_REMOTE_REMOTE_SUGGESTIONS_PROVIDER_IMPL_H_
 
 #include <cstddef>
-#include <deque>
 #include <map>
 #include <memory>
 #include <set>
@@ -15,6 +14,7 @@
 #include <vector>
 
 #include "base/callback_forward.h"
+#include "base/containers/circular_deque.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/optional.h"
@@ -226,9 +226,7 @@
     // be on some open NTP. We do not persist this list so that on a new start
     // of Chrome, this is empty.
     // |archived| is a FIFO buffer with a maximum length.
-    // TODO(http://crbug.com/757231) use a base::circular_deque when it
-    // supports insert().
-    std::deque<std::unique_ptr<RemoteSuggestion>> archived;
+    base::circular_deque<std::unique_ptr<RemoteSuggestion>> archived;
 
     // Suggestions that the user dismissed. We keep these around until they
     // expire so we won't re-add them to |suggestions| on the next fetch.
diff --git a/components/offline_pages/core/background/pick_request_task.cc b/components/offline_pages/core/background/pick_request_task.cc
index d2faeac..59f338a 100644
--- a/components/offline_pages/core/background/pick_request_task.cc
+++ b/components/offline_pages/core/background/pick_request_task.cc
@@ -31,14 +31,15 @@
 
 namespace offline_pages {
 
-PickRequestTask::PickRequestTask(RequestQueueStore* store,
-                                 OfflinerPolicy* policy,
-                                 RequestPickedCallback picked_callback,
-                                 RequestNotPickedCallback not_picked_callback,
-                                 RequestCountCallback request_count_callback,
-                                 DeviceConditions& device_conditions,
-                                 const std::set<int64_t>& disabled_requests,
-                                 std::deque<int64_t>& prioritized_requests)
+PickRequestTask::PickRequestTask(
+    RequestQueueStore* store,
+    OfflinerPolicy* policy,
+    RequestPickedCallback picked_callback,
+    RequestNotPickedCallback not_picked_callback,
+    RequestCountCallback request_count_callback,
+    DeviceConditions& device_conditions,
+    const std::set<int64_t>& disabled_requests,
+    base::circular_deque<int64_t>& prioritized_requests)
     : store_(store),
       policy_(policy),
       picked_callback_(picked_callback),
diff --git a/components/offline_pages/core/background/pick_request_task.h b/components/offline_pages/core/background/pick_request_task.h
index b6cad2c..3c25615 100644
--- a/components/offline_pages/core/background/pick_request_task.h
+++ b/components/offline_pages/core/background/pick_request_task.h
@@ -5,9 +5,9 @@
 #ifndef COMPONENTS_OFFLINE_PAGES_CORE_BACKGROUND_PICK_REQUEST_TASK_H_
 #define COMPONENTS_OFFLINE_PAGES_CORE_BACKGROUND_PICK_REQUEST_TASK_H_
 
-#include <deque>
 #include <set>
 
+#include "base/containers/circular_deque.h"
 #include "base/memory/weak_ptr.h"
 #include "components/offline_pages/core/background/request_queue_results.h"
 #include "components/offline_pages/core/background/save_page_request.h"
@@ -45,7 +45,7 @@
                   RequestCountCallback request_count_callback,
                   DeviceConditions& device_conditions,
                   const std::set<int64_t>& disabled_requests,
-                  std::deque<int64_t>& prioritized_requests);
+                  base::circular_deque<int64_t>& prioritized_requests);
 
   ~PickRequestTask() override;
 
@@ -96,7 +96,7 @@
   RequestCountCallback request_count_callback_;
   std::unique_ptr<DeviceConditions> device_conditions_;
   const std::set<int64_t>& disabled_requests_;
-  std::deque<int64_t>& prioritized_requests_;
+  base::circular_deque<int64_t>& prioritized_requests_;
   // Allows us to pass a weak pointer to callbacks.
   base::WeakPtrFactory<PickRequestTask> weak_ptr_factory_;
 };
diff --git a/components/offline_pages/core/background/pick_request_task_unittest.cc b/components/offline_pages/core/background/pick_request_task_unittest.cc
index 7f686246..c43a363 100644
--- a/components/offline_pages/core/background/pick_request_task_unittest.cc
+++ b/components/offline_pages/core/background/pick_request_task_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "components/offline_pages/core/background/pick_request_task.h"
 
-#include <deque>
 #include <memory>
 #include <set>
 
 #include "base/bind.h"
+#include "base/containers/circular_deque.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -128,7 +128,7 @@
   std::unique_ptr<OfflinerPolicy> policy_;
   RequestCoordinatorEventLogger event_logger_;
   std::set<int64_t> disabled_requests_;
-  std::deque<int64_t> prioritized_requests_;
+  base::circular_deque<int64_t> prioritized_requests_;
   std::unique_ptr<PickRequestTask> task_;
   bool request_queue_not_picked_called_;
   bool cleanup_needed_;
diff --git a/components/offline_pages/core/background/request_coordinator.h b/components/offline_pages/core/background/request_coordinator.h
index 0380b3d..a113156 100644
--- a/components/offline_pages/core/background/request_coordinator.h
+++ b/components/offline_pages/core/background/request_coordinator.h
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
@@ -483,7 +484,7 @@
   //   it was completed or cancelled), the task will remove it.
   // Currently it's used as LIFO.
   // TODO(romax): see if LIFO is a good idea or change to FIFO. crbug.com/705106
-  std::deque<int64_t> prioritized_requests_;
+  base::circular_deque<int64_t> prioritized_requests_;
   // Allows us to pass a weak pointer to callbacks.
   base::WeakPtrFactory<RequestCoordinator> weak_ptr_factory_;
 
diff --git a/components/offline_pages/core/background/request_coordinator_unittest.cc b/components/offline_pages/core/background/request_coordinator_unittest.cc
index d16f9d5..cc1003e 100644
--- a/components/offline_pages/core/background/request_coordinator_unittest.cc
+++ b/components/offline_pages/core/background/request_coordinator_unittest.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/containers/circular_deque.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/synchronization/waitable_event.h"
@@ -313,7 +314,7 @@
     return coordinator()->disabled_requests_;
   }
 
-  const std::deque<int64_t>& prioritized_requests() {
+  const base::circular_deque<int64_t>& prioritized_requests() {
     return coordinator()->prioritized_requests_;
   }
 
diff --git a/components/offline_pages/core/background/request_queue.cc b/components/offline_pages/core/background/request_queue.cc
index 86158362..45ae3d0 100644
--- a/components/offline_pages/core/background/request_queue.cc
+++ b/components/offline_pages/core/background/request_queue.cc
@@ -125,7 +125,7 @@
     PickRequestTask::RequestCountCallback request_count_callback,
     DeviceConditions& conditions,
     std::set<int64_t>& disabled_requests,
-    std::deque<int64_t>& prioritized_requests) {
+    base::circular_deque<int64_t>& prioritized_requests) {
   // Using the PickerContext, create a picker task.
   std::unique_ptr<Task> task(
       new PickRequestTask(store_.get(), policy, picked_callback,
diff --git a/components/offline_pages/core/background/request_queue.h b/components/offline_pages/core/background/request_queue.h
index 06f6423..a8156b32 100644
--- a/components/offline_pages/core/background/request_queue.h
+++ b/components/offline_pages/core/background/request_queue.h
@@ -7,13 +7,13 @@
 
 #include <stdint.h>
 
-#include <deque>
 #include <memory>
 #include <set>
 #include <string>
 #include <vector>
 
 #include "base/callback.h"
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "components/offline_pages/core/background/cleanup_task_factory.h"
@@ -100,7 +100,7 @@
       PickRequestTask::RequestCountCallback request_count_callback,
       DeviceConditions& conditions,
       std::set<int64_t>& disabled_requests,
-      std::deque<int64_t>& prioritized_requests);
+      base::circular_deque<int64_t>& prioritized_requests);
 
   // Reconcile any requests that were active the last time chrome exited.
   void ReconcileRequests(const UpdateCallback& callback);
diff --git a/components/offline_pages/core/offline_event_logger.h b/components/offline_pages/core/offline_event_logger.h
index 40bb9c4..4eafff15 100644
--- a/components/offline_pages/core/offline_event_logger.h
+++ b/components/offline_pages/core/offline_event_logger.h
@@ -5,10 +5,10 @@
 #ifndef COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_EVENT_LOGGER_H_
 #define COMPONENTS_OFFLINE_PAGES_CORE_OFFLINE_EVENT_LOGGER_H_
 
-#include <deque>
 #include <string>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 
 namespace offline_pages {
@@ -62,7 +62,7 @@
 
  private:
   // Recorded offline page activities.
-  std::deque<std::string> activities_;
+  base::circular_deque<std::string> activities_;
 
   // Whether we are currently recording logs or not.
   bool is_logging_;
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
index 750f83c..59654f1 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -147,6 +147,7 @@
 
 void PrefetchDispatcherImpl::QueueActionTasks() {
   service_->GetLogger()->RecordActivity("Dispatcher: Adding action tasks.");
+
   std::unique_ptr<Task> download_archives_task =
       base::MakeUnique<DownloadArchivesTask>(service_->GetPrefetchStore(),
                                              service_->GetPrefetchDownloader());
diff --git a/components/offline_pages/core/prefetch/prefetch_types.h b/components/offline_pages/core/prefetch/prefetch_types.h
index 4ae7ff69..87dc2ec4 100644
--- a/components/offline_pages/core/prefetch/prefetch_types.h
+++ b/components/offline_pages/core/prefetch/prefetch_types.h
@@ -150,8 +150,10 @@
   GENERATE_PAGE_BUNDLE_REQUEST_MAX_ATTEMPTS_REACHED = 1300,
   // Exceeded maximum retries for download.
   DOWNLOAD_MAX_ATTEMPTS_REACHED = 1400,
+  // Clock was set back too far in time.
+  MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED = 1500,
   // Note: Must always have the same value as the last actual entry.
-  MAX = DOWNLOAD_MAX_ATTEMPTS_REACHED
+  MAX = MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED
 };
 
 // Callback invoked upon completion of a prefetch request.
diff --git a/components/offline_pages/core/prefetch/stale_entry_finalizer_task.cc b/components/offline_pages/core/prefetch/stale_entry_finalizer_task.cc
index 3e491ad..63c6d858 100644
--- a/components/offline_pages/core/prefetch/stale_entry_finalizer_task.cc
+++ b/components/offline_pages/core/prefetch/stale_entry_finalizer_task.cc
@@ -90,6 +90,28 @@
   return statement.ColumnInt(0) > 0;
 }
 
+// If the user shifted the clock backwards too far, our items will stay around
+// for a very long time.  Don't allow that so we don't waste resources with
+// potentially outdated content.
+bool FinalizeFutureItems(PrefetchItemState state,
+                         base::Time now,
+                         sql::Connection* db) {
+  static const char kSql[] =
+      "UPDATE prefetch_items SET state = ?, error_code = ?"
+      " WHERE state = ? AND freshness_time > ?";
+  const int64_t future_fresh_db_time_limit =
+      ToDatabaseTime(now + base::TimeDelta::FromDays(1));
+  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+  statement.BindInt(0, static_cast<int>(PrefetchItemState::FINISHED));
+  statement.BindInt(
+      1, static_cast<int>(
+             PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED));
+  statement.BindInt(2, static_cast<int>(state));
+  statement.BindInt64(3, future_fresh_db_time_limit);
+
+  return statement.Run();
+}
+
 Result FinalizeStaleEntriesSync(StaleEntryFinalizerTask::NowGetter now_getter,
                                 sql::Connection* db) {
   if (!db)
@@ -112,6 +134,9 @@
   for (PrefetchItemState state : expirable_states) {
     if (!FinalizeStaleItems(state, now, db))
       return Result::NO_MORE_WORK;
+
+    if (!FinalizeFutureItems(state, now, db))
+      return Result::NO_MORE_WORK;
   }
 
   Result result = Result::MORE_WORK_NEEDED;
diff --git a/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc b/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc
index a7ab0fa..762f76b3 100644
--- a/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc
+++ b/components/offline_pages/core/prefetch/stale_entry_finalizer_task_unittest.cc
@@ -42,7 +42,7 @@
   void TearDown() override;
 
   PrefetchItem CreateAndInsertItem(PrefetchItemState state,
-                                   int hours_in_the_past);
+                                   int time_delta_in_hours);
 
   TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
 
@@ -68,10 +68,10 @@
 
 PrefetchItem StaleEntryFinalizerTaskTest::CreateAndInsertItem(
     PrefetchItemState state,
-    int hours_in_the_past) {
+    int time_delta_in_hours) {
   PrefetchItem item(item_generator()->CreateItem(state));
   item.freshness_time =
-      fake_now_ - base::TimeDelta::FromHours(hours_in_the_past);
+      fake_now_ + base::TimeDelta::FromHours(time_delta_in_hours);
   EXPECT_TRUE(store_util()->InsertPrefetchItem(item))
       << "Failed inserting item with state " << static_cast<int>(state);
   return item;
@@ -95,27 +95,27 @@
 TEST_F(StaleEntryFinalizerTaskTest, HandlesFreshnessTimesCorrectly) {
   // Insert fresh and stale items for all expirable states from all buckets.
   PrefetchItem b1_item1_fresh =
-      CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, 23);
+      CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, -23);
   PrefetchItem b1_item2_stale =
-      CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, 25);
+      CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, -25);
 
   PrefetchItem b2_item1_fresh =
-      CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, 23);
+      CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, -23);
   PrefetchItem b2_item2_stale =
-      CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, 25);
+      CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, -25);
   PrefetchItem b2_item3_fresh =
-      CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, 23);
+      CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, -23);
   PrefetchItem b2_item4_stale =
-      CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, 25);
+      CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, -25);
   PrefetchItem b2_item5_fresh =
-      CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, 23);
+      CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, -23);
   PrefetchItem b2_item6_stale =
-      CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, 25);
+      CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, -25);
 
   PrefetchItem b3_item1_fresh =
-      CreateAndInsertItem(PrefetchItemState::DOWNLOADING, 47);
+      CreateAndInsertItem(PrefetchItemState::DOWNLOADING, -47);
   PrefetchItem b3_item2_stale =
-      CreateAndInsertItem(PrefetchItemState::DOWNLOADING, 49);
+      CreateAndInsertItem(PrefetchItemState::DOWNLOADING, -49);
 
   // Check inserted initial items.
   std::set<PrefetchItem> initial_items = {
@@ -165,7 +165,7 @@
 // their freshness dates are really old.
 TEST_F(StaleEntryFinalizerTaskTest, HandlesStalesInAllStatesCorrectly) {
   // Insert "stale" items for every state.
-  const int many_hours = 7 * 24;
+  const int many_hours = -7 * 24;
   CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, many_hours);
   CreateAndInsertItem(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE, many_hours);
   CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, many_hours);
@@ -241,4 +241,125 @@
   }
 }
 
+// Verifies that expired and non-expired items from all expirable states are
+// properly handled.
+TEST_F(StaleEntryFinalizerTaskTest, HandlesClockSetBackwardsCorrectly) {
+  // Insert fresh and stale items for all expirable states from all buckets.
+  PrefetchItem b1_item1_recent =
+      CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, 23);
+  PrefetchItem b1_item2_future =
+      CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, 25);
+
+  PrefetchItem b2_item1_recent =
+      CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, 23);
+  PrefetchItem b2_item2_future =
+      CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, 25);
+  PrefetchItem b2_item3_recent =
+      CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, 23);
+  PrefetchItem b2_item4_future =
+      CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, 25);
+  PrefetchItem b2_item5_recent =
+      CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, 23);
+  PrefetchItem b2_item6_future =
+      CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, 25);
+
+  PrefetchItem b3_item1_recent =
+      CreateAndInsertItem(PrefetchItemState::DOWNLOADING, 23);
+  PrefetchItem b3_item2_future =
+      CreateAndInsertItem(PrefetchItemState::DOWNLOADING, 25);
+
+  PrefetchItem b4_item1_future =
+      CreateAndInsertItem(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE, 25);
+
+  // Check inserted initial items.
+  std::set<PrefetchItem> initial_items = {
+      b1_item1_recent, b1_item2_future, b2_item1_recent, b2_item2_future,
+      b2_item3_recent, b2_item4_future, b2_item5_recent, b2_item6_future,
+      b3_item1_recent, b3_item2_future, b4_item1_future};
+  std::set<PrefetchItem> all_inserted_items;
+  EXPECT_EQ(11U, store_util()->GetAllItems(&all_inserted_items));
+  EXPECT_EQ(initial_items, all_inserted_items);
+
+  // Execute the expiration task.
+  ExpectTaskCompletes(stale_finalizer_task_.get());
+  stale_finalizer_task_->Run();
+  RunUntilIdle();
+  EXPECT_EQ(Result::MORE_WORK_NEEDED, stale_finalizer_task_->final_status());
+
+  // Create the expected finished version of each stale item.
+  PrefetchItem b1_item2_finished(b1_item2_future);
+  b1_item2_finished.state = PrefetchItemState::FINISHED;
+  b1_item2_finished.error_code =
+      PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED;
+  PrefetchItem b2_item2_finished(b2_item2_future);
+  b2_item2_finished.state = PrefetchItemState::FINISHED;
+  b2_item2_finished.error_code =
+      PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED;
+  PrefetchItem b2_item4_finished(b2_item4_future);
+  b2_item4_finished.state = PrefetchItemState::FINISHED;
+  b2_item4_finished.error_code =
+      PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED;
+  PrefetchItem b2_item6_finished(b2_item6_future);
+  b2_item6_finished.state = PrefetchItemState::FINISHED;
+  b2_item6_finished.error_code =
+      PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED;
+  PrefetchItem b3_item2_finished(b3_item2_future);
+  b3_item2_finished.state = PrefetchItemState::FINISHED;
+  b3_item2_finished.error_code =
+      PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED;
+  PrefetchItem b4_item_finished(b4_item1_future);
+  b4_item1_future.state = PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE;
+  b4_item1_future.error_code = PrefetchItemErrorCode::SUCCESS;
+
+  // Creates the expected set of final items and compares with what's in
+  // store.
+  std::set<PrefetchItem> expected_final_items = {
+      b1_item1_recent, b1_item2_finished, b2_item1_recent, b2_item2_finished,
+      b2_item3_recent, b2_item4_finished, b2_item5_recent, b2_item6_finished,
+      b3_item1_recent, b3_item2_finished, b4_item1_future};
+  EXPECT_EQ(11U, expected_final_items.size());
+  std::set<PrefetchItem> all_items_post_expiration;
+  EXPECT_EQ(11U, store_util()->GetAllItems(&all_items_post_expiration));
+  EXPECT_EQ(expected_final_items, all_items_post_expiration);
+}
+
+// Checks that items from all states are handled properly by the task when all
+// their freshness dates are really old.
+TEST_F(StaleEntryFinalizerTaskTest,
+       HandleClockChangeBackwardsInAllStatesCorrectly) {
+  // Insert "future" items for every state.
+  const int many_hours = 7 * 24;
+  CreateAndInsertItem(PrefetchItemState::NEW_REQUEST, many_hours);
+  CreateAndInsertItem(PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE, many_hours);
+  CreateAndInsertItem(PrefetchItemState::AWAITING_GCM, many_hours);
+  CreateAndInsertItem(PrefetchItemState::RECEIVED_GCM, many_hours);
+  CreateAndInsertItem(PrefetchItemState::SENT_GET_OPERATION, many_hours);
+  CreateAndInsertItem(PrefetchItemState::RECEIVED_BUNDLE, many_hours);
+  CreateAndInsertItem(PrefetchItemState::DOWNLOADING, many_hours);
+  CreateAndInsertItem(PrefetchItemState::DOWNLOADED, many_hours);
+  CreateAndInsertItem(PrefetchItemState::IMPORTING, many_hours);
+  CreateAndInsertItem(PrefetchItemState::FINISHED, many_hours);
+  CreateAndInsertItem(PrefetchItemState::ZOMBIE, many_hours);
+  EXPECT_EQ(11, store_util()->CountPrefetchItems());
+
+  // Execute the expiration task.
+  ExpectTaskCompletes(stale_finalizer_task_.get());
+  stale_finalizer_task_->Run();
+  RunUntilIdle();
+  EXPECT_EQ(Result::MORE_WORK_NEEDED, stale_finalizer_task_->final_status());
+
+  // Checks item counts for states expected to still exist.
+  std::set<PrefetchItem> post_items;
+  EXPECT_EQ(11U, store_util()->GetAllItems(&post_items));
+  EXPECT_EQ(
+      1U,
+      Filter(post_items, PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE).size());
+  EXPECT_EQ(1U,
+            Filter(post_items, PrefetchItemState::SENT_GET_OPERATION).size());
+  EXPECT_EQ(1U, Filter(post_items, PrefetchItemState::DOWNLOADED).size());
+  EXPECT_EQ(1U, Filter(post_items, PrefetchItemState::IMPORTING).size());
+  EXPECT_EQ(6U, Filter(post_items, PrefetchItemState::FINISHED).size());
+  EXPECT_EQ(1U, Filter(post_items, PrefetchItemState::ZOMBIE).size());
+}
+
 }  // namespace offline_pages
diff --git a/components/omnibox/browser/history_match.h b/components/omnibox/browser/history_match.h
index 7a0d2159..8e451f1 100644
--- a/components/omnibox/browser/history_match.h
+++ b/components/omnibox/browser/history_match.h
@@ -7,8 +7,7 @@
 
 #include <stddef.h>
 
-#include <deque>
-
+#include "base/containers/circular_deque.h"
 #include "components/history/core/browser/url_row.h"
 
 namespace history {
@@ -50,9 +49,7 @@
   bool innermost_match;
 };
 
-// TODO(http://crbug.com/757231) use a base::circular_deque when it supports
-// erase().
-typedef std::deque<HistoryMatch> HistoryMatches;
+typedef base::circular_deque<HistoryMatch> HistoryMatches;
 
 }  // namespace history
 
diff --git a/components/omnibox/browser/omnibox_client.h b/components/omnibox/browser/omnibox_client.h
index afd6e6b..6279159 100644
--- a/components/omnibox/browser/omnibox_client.h
+++ b/components/omnibox/browser/omnibox_client.h
@@ -18,6 +18,10 @@
 struct AutocompleteMatch;
 struct OmniboxLog;
 
+namespace base {
+class CancelableTaskTracker;
+}
+
 namespace bookmarks {
 class BookmarkModel;
 }
@@ -27,6 +31,7 @@
 }
 
 typedef base::Callback<void(const SkBitmap& bitmap)> BitmapFetchedCallback;
+typedef base::Callback<void(const gfx::Image& favicon)> FaviconFetchedCallback;
 
 // Interface that allows the omnibox component to interact with its embedder
 // (e.g., getting information about the current page, retrieving objects
@@ -117,6 +122,14 @@
                                const BitmapFetchedCallback& on_bitmap_fetched) {
   }
 
+  // Fetchs the favicon for |page_url|. If the embedder supports fetching
+  // favicons (not all embedders do), |on_favicon_fetched| will be be called
+  // once the favicon has been fetched.
+  virtual void GetFaviconForPageUrl(
+      base::CancelableTaskTracker* tracker,
+      const GURL& page_url,
+      const FaviconFetchedCallback& on_favicon_fetched) {}
+
   // Called when the current autocomplete match has changed.
   virtual void OnCurrentMatchChanged(const AutocompleteMatch& match) {}
 
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc
index 291da34..0af1fd6 100644
--- a/components/omnibox/browser/omnibox_popup_model.cc
+++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -6,18 +6,20 @@
 
 #include <algorithm>
 
+#include "base/feature_list.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/omnibox_client.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/omnibox_popup_model_observer.h"
 #include "components/omnibox/browser/omnibox_popup_view.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_service.h"
 #include "third_party/icu/source/common/unicode/ubidi.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/image/image.h"
 
 using bookmarks::BookmarkModel;
 
@@ -26,13 +28,13 @@
 
 const size_t OmniboxPopupModel::kNoMatch = static_cast<size_t>(-1);
 
-OmniboxPopupModel::OmniboxPopupModel(
-    OmniboxPopupView* popup_view,
-    OmniboxEditModel* edit_model)
+OmniboxPopupModel::OmniboxPopupModel(OmniboxPopupView* popup_view,
+                                     OmniboxEditModel* edit_model)
     : view_(popup_view),
       edit_model_(edit_model),
       selected_line_(kNoMatch),
-      selected_line_state_(NORMAL) {
+      selected_line_state_(NORMAL),
+      weak_factory_(this) {
   edit_model->set_popup_model(this);
 }
 
@@ -249,6 +251,41 @@
   manually_selected_match_.Clear();
   selected_line_state_ = NORMAL;
 
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  // Update all match icons.
+  if (base::FeatureList::IsEnabled(
+          omnibox::kUIExperimentShowSuggestionFavicons)) {
+    favicon_task_tracker_.TryCancelAll();
+
+    if (result.size() != displayed_page_favicons_.size())
+      displayed_page_favicons_.resize(result.size());
+
+    for (size_t i = 0; i < result.size(); i++) {
+      const AutocompleteMatch& match = result.match_at(i);
+      if (AutocompleteMatch::IsSearchType(match.type)) {
+        // Clear any existing icon.
+        if (!displayed_page_favicons_[i].is_empty())
+          OnPageFaviconFetched(i, GURL(), gfx::Image());
+        continue;
+      }
+
+      // If we already show the correct favicon, skip refetching to avoid
+      // hitting the favicon database and to avoid flicker.
+      //
+      // TODO(tommycli): Investigate whether the fetching can be done in the
+      // autocomplete controller, which already has knowledge of whether and
+      // when the matches are changing.
+      if (match.destination_url == displayed_page_favicons_[i])
+        continue;
+
+      edit_model_->client()->GetFaviconForPageUrl(
+          &favicon_task_tracker_, match.destination_url,
+          base::Bind(&OmniboxPopupModel::OnPageFaviconFetched,
+                     weak_factory_.GetWeakPtr(), i, match.destination_url));
+    }
+  }
+#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+
   bool popup_was_open = view_->IsOpen();
   view_->UpdatePopupAppearance();
   // If popup has just been shown or hidden, notify observers.
@@ -270,3 +307,13 @@
   answer_bitmap_ = bitmap;
   view_->UpdatePopupAppearance();
 }
+
+void OmniboxPopupModel::OnPageFaviconFetched(size_t match_index,
+                                             const GURL& page_url,
+                                             const gfx::Image& icon) {
+  DCHECK_LT(match_index, displayed_page_favicons_.size());
+  DCHECK_NE(displayed_page_favicons_[match_index], page_url);
+
+  displayed_page_favicons_[match_index] = page_url;
+  view_->SetMatchIcon(match_index, icon);
+}
\ No newline at end of file
diff --git a/components/omnibox/browser/omnibox_popup_model.h b/components/omnibox/browser/omnibox_popup_model.h
index ad2ed56..20108db 100644
--- a/components/omnibox/browser/omnibox_popup_model.h
+++ b/components/omnibox/browser/omnibox_popup_model.h
@@ -6,13 +6,17 @@
 #define COMPONENTS_OMNIBOX_BROWSER_OMNIBOX_POPUP_MODEL_H_
 
 #include <stddef.h>
+#include <vector>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/task/cancelable_task_tracker.h"
 #include "components/omnibox/browser/autocomplete_controller.h"
 #include "components/omnibox/browser/autocomplete_result.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/image/image.h"
 
 class OmniboxPopupModelObserver;
 class OmniboxPopupView;
@@ -139,8 +143,17 @@
   static const size_t kNoMatch;
 
  private:
+  void OnPageFaviconFetched(size_t match_index,
+                            const GURL& page_url,
+                            const gfx::Image& icon);
+
   SkBitmap answer_bitmap_;
 
+  // The GURLs track which pages' favicon is displayed for each match view.
+  // An empty GURL means no favicon is displayed for that match view.
+  std::vector<GURL> displayed_page_favicons_;
+  base::CancelableTaskTracker favicon_task_tracker_;
+
   OmniboxPopupView* view_;
 
   OmniboxEditModel* edit_model_;
@@ -160,6 +173,8 @@
   // Observers.
   base::ObserverList<OmniboxPopupModelObserver> observers_;
 
+  base::WeakPtrFactory<OmniboxPopupModel> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(OmniboxPopupModel);
 };
 
diff --git a/components/omnibox/browser/omnibox_popup_view.h b/components/omnibox/browser/omnibox_popup_view.h
index 74dd208..89e4ad7 100644
--- a/components/omnibox/browser/omnibox_popup_view.h
+++ b/components/omnibox/browser/omnibox_popup_view.h
@@ -16,6 +16,7 @@
 #include "build/build_config.h"
 
 namespace gfx {
+class Image;
 class Rect;
 }
 
@@ -36,6 +37,11 @@
   // mean opening or closing the window.
   virtual void UpdatePopupAppearance() = 0;
 
+  // Updates the icon used for the given match. The passed |icon| is not
+  // retained by the caller, and implementing classes are expected to make
+  // a copy if they wish to use |icon|.
+  virtual void SetMatchIcon(size_t match_index, const gfx::Image& icon) = 0;
+
   // Returns the target bounds for the popup. This returns the popup's current
   // bounds when not animating, or the desired target bounds when animating.
   // The return value is in screen coordinates.
diff --git a/components/pairing/message_buffer.h b/components/pairing/message_buffer.h
index 8b2fcc018..74a18224f 100644
--- a/components/pairing/message_buffer.h
+++ b/components/pairing/message_buffer.h
@@ -5,8 +5,7 @@
 #ifndef COMPONENTS_PAIRING_MESSAGE_BUFFER_H_
 #define COMPONENTS_PAIRING_MESSAGE_BUFFER_H_
 
-#include <deque>
-
+#include "base/containers/circular_deque.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -42,7 +41,8 @@
   // Total number of bytes in IOBuffers in |pending_data_|, including bytes that
   // have already been read.
   int total_buffer_size_;
-  std::deque<std::pair<scoped_refptr<net::IOBuffer>, int> > pending_data_;
+  base::circular_deque<std::pair<scoped_refptr<net::IOBuffer>, int>>
+      pending_data_;
 
   DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
 };
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index 7a0389a6..1521297 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -29,6 +29,7 @@
 #include "components/password_manager/core/browser/password_manager_client.h"
 #include "components/password_manager/core/browser/password_manager_driver.h"
 #include "components/password_manager/core/browser/password_manager_metrics_recorder.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/security_state/core/security_state.h"
 #include "components/strings/grit/components_strings.h"
@@ -135,12 +136,14 @@
   }
 }
 
-bool IsPreLollipopAndroid() {
+bool ShouldShowManualFallbackForPreLollipop(syncer::SyncService* sync_service) {
 #if defined(OS_ANDROID)
-  return (base::android::BuildInfo::GetInstance()->sdk_int() <
-          base::android::SDK_VERSION_LOLLIPOP);
+  return ((base::android::BuildInfo::GetInstance()->sdk_int() >=
+           base::android::SDK_VERSION_LOLLIPOP) ||
+          (password_manager_util::GetPasswordSyncState(sync_service) ==
+           SYNCING_NORMAL_ENCRYPTION));
 #else
-  return false;
+  return true;
 #endif
 }
 
@@ -286,7 +289,8 @@
     suggestions.back().frontend_id = autofill::POPUP_ITEM_ID_SEPARATOR;
 #endif
 
-    if (!IsPreLollipopAndroid()) {
+    if (ShouldShowManualFallbackForPreLollipop(
+            autofill_client_->GetSyncService())) {
       autofill::Suggestion all_saved_passwords(
           l10n_util::GetStringUTF8(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK),
           std::string(), std::string(),
@@ -335,7 +339,8 @@
   // CroS SimpleWebviewDialog used for the captive portal dialog is a special
   // case because it doesn't instantiate many helper classes. |autofill_client_|
   // is NULL too.
-  if (!autofill_client_ || IsPreLollipopAndroid())
+  if (!autofill_client_ || !ShouldShowManualFallbackForPreLollipop(
+                               autofill_client_->GetSyncService()))
     return;
   if (!password_client_ ||
       !password_client_->IsFillingFallbackEnabledForCurrentPage())
diff --git a/components/payments/content/BUILD.gn b/components/payments/content/BUILD.gn
index 0d788c1..e7ea851 100644
--- a/components/payments/content/BUILD.gn
+++ b/components/payments/content/BUILD.gn
@@ -26,6 +26,7 @@
     "//components/payments/core",
     "//components/prefs",
     "//components/strings:components_strings_grit",
+    "//components/url_formatter",
     "//content/public/browser",
     "//mojo/public/cpp/bindings",
     "//third_party/WebKit/public:blink_headers",
diff --git a/components/payments/content/DEPS b/components/payments/content/DEPS
index a2a378b6..78d416a1 100644
--- a/components/payments/content/DEPS
+++ b/components/payments/content/DEPS
@@ -5,6 +5,7 @@
   "+components/keyed_service/content",
   "+components/prefs",
   "+components/strings",
+  "+components/url_formatter",
   "+content/public",
   "+mojo/public/cpp",
   "+net",
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc
index d24a672e..342e457 100644
--- a/components/payments/content/payment_request.cc
+++ b/components/payments/content/payment_request.cc
@@ -16,6 +16,7 @@
 #include "components/payments/core/can_make_payment_query.h"
 #include "components/payments/core/payment_prefs.h"
 #include "components/prefs/pref_service.h"
+#include "components/url_formatter/elide_url.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
@@ -33,8 +34,10 @@
       delegate_(std::move(delegate)),
       manager_(manager),
       binding_(this, std::move(request)),
-      top_level_origin_(web_contents_->GetLastCommittedURL().GetOrigin()),
-      frame_origin_(render_frame_host->GetLastCommittedURL().GetOrigin()),
+      top_level_origin_(url_formatter::FormatUrlForSecurityDisplay(
+          web_contents_->GetLastCommittedURL())),
+      frame_origin_(url_formatter::FormatUrlForSecurityDisplay(
+          render_frame_host->GetLastCommittedURL())),
       observer_for_testing_(observer_for_testing),
       journey_logger_(delegate_->IsIncognito(),
                       web_contents_->GetLastCommittedURL(),
@@ -242,8 +245,7 @@
             ? mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT
             : mojom::CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT);
     journey_logger_.SetCanMakePaymentValue(can_make_payment);
-  } else if (OriginSecurityChecker::IsOriginLocalhostOrFile(
-                 frame_origin_.GetURL())) {
+  } else if (OriginSecurityChecker::IsOriginLocalhostOrFile(frame_origin_)) {
     client_->OnCanMakePayment(
         can_make_payment
             ? mojom::CanMakePaymentQueryResult::WARNING_CAN_MAKE_PAYMENT
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h
index 5708cde..9be4d539 100644
--- a/components/payments/content/payment_request.h
+++ b/components/payments/content/payment_request.h
@@ -17,7 +17,7 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "third_party/WebKit/public/platform/modules/payments/payment_request.mojom.h"
-#include "url/origin.h"
+#include "url/gurl.h"
 
 namespace content {
 class RenderFrameHost;
@@ -117,11 +117,11 @@
 
   // The RFC 6454 origin of the top level frame that has invoked PaymentRequest
   // API. This is what the user sees in the address bar.
-  const url::Origin top_level_origin_;
+  const GURL top_level_origin_;
 
   // The RFC 6454 origin of the frame that has invoked PaymentRequest API. This
   // can be either the main frame or an iframe.
-  const url::Origin frame_origin_;
+  const GURL frame_origin_;
 
   // May be null, must outlive this object.
   ObserverForTest* observer_for_testing_;
diff --git a/components/payments/core/BUILD.gn b/components/payments/core/BUILD.gn
index a0ac16cf..8895c1b 100644
--- a/components/payments/core/BUILD.gn
+++ b/components/payments/core/BUILD.gn
@@ -107,6 +107,7 @@
     "address_normalizer_impl_unittest.cc",
     "autofill_payment_instrument_unittest.cc",
     "basic_card_response_unittest.cc",
+    "can_make_payment_query_unittest.cc",
     "currency_formatter_unittest.cc",
     "journey_logger_unittest.cc",
     "payment_address_unittest.cc",
diff --git a/components/payments/core/can_make_payment_query.cc b/components/payments/core/can_make_payment_query.cc
index b6ad36b..8836b4a 100644
--- a/components/payments/core/can_make_payment_query.cc
+++ b/components/payments/core/can_make_payment_query.cc
@@ -11,7 +11,7 @@
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/time/time.h"
-#include "url/origin.h"
+#include "url/gurl.h"
 
 namespace payments {
 
@@ -20,11 +20,10 @@
 CanMakePaymentQuery::~CanMakePaymentQuery() {}
 
 bool CanMakePaymentQuery::CanQuery(
-    const url::Origin& top_level_origin,
-    const url::Origin& frame_origin,
+    const GURL& top_level_origin,
+    const GURL& frame_origin,
     const std::map<std::string, std::set<std::string>>& query) {
-  const std::string id =
-      frame_origin.Serialize() + ":" + top_level_origin.Serialize();
+  const std::string id = frame_origin.spec() + ":" + top_level_origin.spec();
 
   const auto& it = queries_.find(id);
   if (it == queries_.end()) {
diff --git a/components/payments/core/can_make_payment_query.h b/components/payments/core/can_make_payment_query.h
index 0e14935..db2f7cf 100644
--- a/components/payments/core/can_make_payment_query.h
+++ b/components/payments/core/can_make_payment_query.h
@@ -14,9 +14,7 @@
 #include "base/timer/timer.h"
 #include "components/keyed_service/core/keyed_service.h"
 
-namespace url {
-class Origin;
-}
+class GURL;
 
 namespace payments {
 
@@ -26,12 +24,24 @@
   CanMakePaymentQuery();
   ~CanMakePaymentQuery() override;
 
-  // Returns whether |frame_origin| can call canMakePayment() with |query|,
-  // which is a mapping of payment method names to the corresponding
-  // JSON-stringified payment method data. Remembers the frame-to-query mapping
-  // for 30 minutes to enforce the quota.
-  bool CanQuery(const url::Origin& top_level_origin,
-                const url::Origin& frame_origin,
+  // Returns whether |top_level_origin| and |frame_origin| can call
+  // canMakePayment() with |query|, which is a mapping of payment method names
+  // to the corresponding JSON-stringified payment method data. Remembers the
+  // origins-to-query mapping for 30 minutes to enforce the quota.
+  //
+  // GURL type is used instead of url::Origin to represent origins, because they
+  // need to be serialized into map keys and url::Origin serializations must not
+  // be relied upon for security checks, according to url/origin.h.
+  //
+  // The best method to retrieve the origin of GURL for serialization is
+  // url_formatter::FormatUrlForSecurityDisplay() found in
+  // components/url_formatter/elide_url.h, because it preserves the path part of
+  // a file:// scheme GURL, in contrast to to GURL::GetOrigin(), which strips
+  // the path part of a file:// scheme GURL. There's no difference between these
+  // two methods for localhost and https:// schemes, where PaymentRequest is
+  // also allowed.
+  bool CanQuery(const GURL& top_level_origin,
+                const GURL& frame_origin,
                 const std::map<std::string, std::set<std::string>>& query);
 
  private:
diff --git a/components/payments/core/can_make_payment_query_unittest.cc b/components/payments/core/can_make_payment_query_unittest.cc
new file mode 100644
index 0000000..eb3ea09
--- /dev/null
+++ b/components/payments/core/can_make_payment_query_unittest.cc
@@ -0,0 +1,66 @@
+// 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 "components/payments/core/can_make_payment_query.h"
+
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace payments {
+namespace {
+
+struct TestCase {
+  TestCase(const char* first_origin,
+           const char* second_origin,
+           bool expected_second_origin_different_query_allowed)
+      : first_origin(first_origin),
+        second_origin(second_origin),
+        expected_second_origin_different_query_allowed(
+            expected_second_origin_different_query_allowed) {}
+
+  ~TestCase() {}
+
+  const char* const first_origin;
+  const char* const second_origin;
+  const bool expected_second_origin_different_query_allowed;
+};
+
+class CanMakePaymentQueryTest : public ::testing::TestWithParam<TestCase> {
+ private:
+  base::MessageLoop message_loop_;
+};
+
+TEST_P(CanMakePaymentQueryTest, SecondOriginDifferentQuery) {
+  std::map<std::string, std::set<std::string>> query1;
+  query1["amex"] = std::set<std::string>();
+  std::map<std::string, std::set<std::string>> query2;
+  query2["visa"] = std::set<std::string>();
+  CanMakePaymentQuery guard;
+  EXPECT_TRUE(guard.CanQuery(GURL(GetParam().first_origin),
+                             GURL(GetParam().first_origin), query1));
+
+  EXPECT_EQ(GetParam().expected_second_origin_different_query_allowed,
+            guard.CanQuery(GURL(GetParam().second_origin),
+                           GURL(GetParam().second_origin), query2));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    Denied,
+    CanMakePaymentQueryTest,
+    testing::Values(
+        TestCase("https://example.com", "https://example.com", false),
+        TestCase("http://localhost", "http://localhost", false),
+        TestCase("file:///tmp/test.html", "file:///tmp/test.html", false)));
+
+INSTANTIATE_TEST_CASE_P(
+    Allowed,
+    CanMakePaymentQueryTest,
+    testing::Values(
+        TestCase("https://example.com", "https://not-example.com", true),
+        TestCase("http://localhost", "http://not-localhost", true),
+        TestCase("file:///tmp/test.html", "file:///tmp/not-test.html", true)));
+
+}  // namespace
+}  // namespace payments
diff --git a/components/payments/core/currency_formatter_unittest.cc b/components/payments/core/currency_formatter_unittest.cc
index 41793ef4..8a4f235 100644
--- a/components/payments/core/currency_formatter_unittest.cc
+++ b/components/payments/core/currency_formatter_unittest.cc
@@ -9,6 +9,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace payments {
+namespace {
 
 struct TestCase {
   TestCase(const char* amount,
@@ -182,4 +183,5 @@
                  "USD",
                  "http://currsystem.com")));
 
+}  // namespace
 }  // namespace payments
diff --git a/components/policy/core/common/cloud/device_management_service.h b/components/policy/core/common/cloud/device_management_service.h
index 8314438..9efde08 100644
--- a/components/policy/core/common/cloud/device_management_service.h
+++ b/components/policy/core/common/cloud/device_management_service.h
@@ -7,7 +7,6 @@
 
 #include <stdint.h>
 
-#include <deque>
 #include <map>
 #include <memory>
 #include <string>
@@ -15,6 +14,7 @@
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -178,7 +178,7 @@
  private:
   typedef std::map<const net::URLFetcher*,
                    DeviceManagementRequestJobImpl*> JobFetcherMap;
-  typedef std::deque<DeviceManagementRequestJobImpl*> JobQueue;
+  typedef base::circular_deque<DeviceManagementRequestJobImpl*> JobQueue;
 
   friend class DeviceManagementRequestJobImpl;
 
diff --git a/components/policy/core/common/remote_commands/remote_commands_service.h b/components/policy/core/common/remote_commands/remote_commands_service.h
index 402eae0..6d5bca27 100644
--- a/components/policy/core/common/remote_commands/remote_commands_service.h
+++ b/components/policy/core/common/remote_commands/remote_commands_service.h
@@ -5,10 +5,10 @@
 #ifndef COMPONENTS_POLICY_CORE_COMMON_REMOTE_COMMANDS_REMOTE_COMMANDS_SERVICE_H_
 #define COMPONENTS_POLICY_CORE_COMMON_REMOTE_COMMANDS_REMOTE_COMMANDS_SERVICE_H_
 
-#include <deque>
 #include <memory>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
@@ -90,7 +90,7 @@
   // IDs will be stored in the order that they are fetched from the server,
   // and acknowledging a command will discard its ID from
   // |fetched_command_ids_|, as well as the IDs of every command before it.
-  std::deque<RemoteCommandJob::UniqueIDType> fetched_command_ids_;
+  base::circular_deque<RemoteCommandJob::UniqueIDType> fetched_command_ids_;
 
   RemoteCommandsQueue queue_;
   std::unique_ptr<RemoteCommandsFactory> factory_;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 4a3ffcf..ecd8be0 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -8191,7 +8191,7 @@
       'name': 'ForceBrowserSignin',
       'type': 'main',
       'schema': { 'type': 'boolean' },
-      'supported_on': ['chrome.win:61-', 'chrome.linux:61-', 'android:63-'],
+      'supported_on': ['chrome.win:62-', 'chrome.linux:62-', 'android:63-'],
       'features': {
         'dynamic_refresh': False,
         'per_profile': False,
@@ -9751,7 +9751,7 @@
       'type': 'int-enum',
       'schema': {
         'type': 'integer',
-        'enum': [ 0, 1, 2, 3],
+        'enum': [ 0, 1, 2, 3, 4, 5],
       },
       'items': [
         {
@@ -9774,6 +9774,16 @@
           'value': 3,
           'caption': '''Ask the user if they would like to migrate or skip migration and disallow ARC.''',
         },
+        {
+          'name': 'MinimalMigrate',
+          'value': 4,
+          'caption': '''Similar to Wipe (value 2), but tries to preserve login tokens so the user does not have to sign in again.''',
+        },
+        {
+          'name': 'AskForEcryptfsArcUsers',
+          'value': 5,
+          'caption': '''If the client device model already supported ARC before migration to ext4 was necessary to run ARC and if the ArcEnabled policy is set to true, this option will behave as AskUser (value 3). In all other cases (if the device model did not support ARC before, or if ArcEnabled policy is set to false), this value is equivalent to DisallowArc (value 0).''',
+        }
       ],
       'supported_on': ['chrome_os:61-'],
       'device_only': False,
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.h b/components/signin/core/browser/gaia_cookie_manager_service.h
index afa4b8a5..b9a2521 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.h
+++ b/components/signin/core/browser/gaia_cookie_manager_service.h
@@ -5,13 +5,13 @@
 #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_GAIA_COOKIE_MANAGER_SERVICE_H_
 #define COMPONENTS_SIGNIN_CORE_BROWSER_GAIA_COOKIE_MANAGER_SERVICE_H_
 
-#include <deque>
 #include <map>
 #include <memory>
 #include <string>
 #include <utility>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/timer/timer.h"
@@ -308,9 +308,7 @@
   // A worklist for this class. Stores any pending requests that couldn't be
   // executed right away, since this class only permits one request to be
   // executed at a time.
-  // TODO(http://crbug.com/757231) use a base::circular_deque when it supports
-  // erase().
-  std::deque<GaiaCookieRequest> requests_;
+  base::circular_deque<GaiaCookieRequest> requests_;
 
   // List of observers to notify when merge session completes.
   // Makes sure list is empty on destruction.
diff --git a/components/signin/ios/browser/account_consistency_service.h b/components/signin/ios/browser/account_consistency_service.h
index 8df4874..e05b4c7 100644
--- a/components/signin/ios/browser/account_consistency_service.h
+++ b/components/signin/ios/browser/account_consistency_service.h
@@ -5,12 +5,12 @@
 #ifndef COMPONENTS_SIGNIN_IOS_BROWSER_ACCOUNT_CONSISTENCY_SERVICE_H_
 #define COMPONENTS_SIGNIN_IOS_BROWSER_ACCOUNT_CONSISTENCY_SERVICE_H_
 
-#include <deque>
 #include <map>
 #include <memory>
 #include <set>
 #include <string>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
@@ -170,7 +170,7 @@
   // Whether a CHROME_CONNECTED cookie request is currently being applied.
   bool applying_cookie_requests_;
   // The queue of CHROME_CONNECTED cookie requests to be applied.
-  std::deque<CookieRequest> cookie_requests_;
+  base::circular_deque<CookieRequest> cookie_requests_;
   // The map between domains where a CHROME_CONNECTED cookie is present and
   // the time when the cookie was last updated.
   std::map<std::string, base::Time> last_cookie_update_map_;
diff --git a/components/sync/base/immutable_unittest.cc b/components/sync/base/immutable_unittest.cc
index 6c8d2a8..9108d69 100644
--- a/components/sync/base/immutable_unittest.cc
+++ b/components/sync/base/immutable_unittest.cc
@@ -5,12 +5,12 @@
 #include "components/sync/base/immutable.h"
 
 #include <cstddef>
-#include <deque>
 #include <list>
 #include <set>
 #include <string>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace syncer {
@@ -218,8 +218,8 @@
 }
 
 TEST_F(ImmutableTest, Deque) {
-  RunTokenContainerTest<std::deque<Token>, Immutable<std::deque<Token>>>(
-      "Deque");
+  RunTokenContainerTest<base::circular_deque<Token>,
+                        Immutable<base::circular_deque<Token>>>("Deque");
 }
 
 TEST_F(ImmutableTest, List) {
diff --git a/components/sync/engine_impl/debug_info_event_listener.h b/components/sync/engine_impl/debug_info_event_listener.h
index cd97fb3b..6022e3f 100644
--- a/components/sync/engine_impl/debug_info_event_listener.h
+++ b/components/sync/engine_impl/debug_info_event_listener.h
@@ -5,11 +5,11 @@
 #ifndef COMPONENTS_SYNC_ENGINE_IMPL_DEBUG_INFO_EVENT_LISTENER_H_
 #define COMPONENTS_SYNC_ENGINE_IMPL_DEBUG_INFO_EVENT_LISTENER_H_
 
-#include <deque>
 #include <string>
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/containers/circular_deque.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "components/sync/base/model_type.h"
@@ -94,7 +94,7 @@
   void AddEventToQueue(const sync_pb::DebugEventInfo& event_info);
   void CreateAndAddEvent(sync_pb::SyncEnums::SingletonDebugEventType type);
 
-  using DebugEventInfoQueue = std::deque<sync_pb::DebugEventInfo>;
+  using DebugEventInfoQueue = base::circular_deque<sync_pb::DebugEventInfo>;
   DebugEventInfoQueue events_;
 
   // True indicates we had to drop one or more events to keep our limit of
diff --git a/components/sync/engine_impl/events/protocol_event_buffer.h b/components/sync/engine_impl/events/protocol_event_buffer.h
index bca62fb..1dd892d2 100644
--- a/components/sync/engine_impl/events/protocol_event_buffer.h
+++ b/components/sync/engine_impl/events/protocol_event_buffer.h
@@ -7,10 +7,10 @@
 
 #include <stddef.h>
 
-#include <deque>
 #include <memory>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 
 namespace syncer {
@@ -34,7 +34,7 @@
   std::vector<std::unique_ptr<ProtocolEvent>> GetBufferedProtocolEvents() const;
 
  private:
-  std::deque<std::unique_ptr<ProtocolEvent>> buffer_;
+  base::circular_deque<std::unique_ptr<ProtocolEvent>> buffer_;
 
   DISALLOW_COPY_AND_ASSIGN(ProtocolEventBuffer);
 };
diff --git a/components/sync/model_impl/attachments/task_queue.h b/components/sync/model_impl/attachments/task_queue.h
index aa7d5c10..05ea9495 100644
--- a/components/sync/model_impl/attachments/task_queue.h
+++ b/components/sync/model_impl/attachments/task_queue.h
@@ -7,13 +7,13 @@
 
 #include <stddef.h>
 
-#include <deque>
 #include <memory>
 #include <set>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
@@ -151,7 +151,7 @@
   std::unique_ptr<net::BackoffEntry> backoff_entry_;
   // The number of tasks currently being handled.
   int num_in_progress_;
-  std::deque<T> queue_;
+  base::circular_deque<T> queue_;
   // The set of tasks in queue_ or currently being handled.
   std::set<T> tasks_;
   base::Closure dispatch_closure_;
diff --git a/components/sync/syncable/directory.cc b/components/sync/syncable/directory.cc
index 80edde2..5b98d9de 100644
--- a/components/sync/syncable/directory.cc
+++ b/components/sync/syncable/directory.cc
@@ -309,7 +309,7 @@
     return false;
 
   int count = 1;
-  std::deque<const OrderedChildSet*> child_sets;
+  base::circular_deque<const OrderedChildSet*> child_sets;
 
   GetChildSetForKernel(trans, kernel, &child_sets);
   while (!child_sets.empty()) {
@@ -328,7 +328,7 @@
 void Directory::GetChildSetForKernel(
     BaseTransaction* trans,
     EntryKernel* kernel,
-    std::deque<const OrderedChildSet*>* child_sets) const {
+    base::circular_deque<const OrderedChildSet*>* child_sets) const {
   if (!kernel->ref(IS_DIR))
     return;  // Not a directory => no children.
 
diff --git a/components/sync/syncable/directory.h b/components/sync/syncable/directory.h
index 5ac3296..240d9732 100644
--- a/components/sync/syncable/directory.h
+++ b/components/sync/syncable/directory.h
@@ -8,7 +8,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <deque>
 #include <memory>
 #include <set>
 #include <string>
@@ -16,6 +15,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/containers/circular_deque.h"
 #include "base/containers/hash_tables.h"
 #include "base/files/file_util.h"
 #include "base/gtest_prod_util.h"
@@ -617,7 +617,7 @@
   void GetChildSetForKernel(
       BaseTransaction*,
       EntryKernel* kernel_,
-      std::deque<const OrderedChildSet*>* child_sets) const;
+      base::circular_deque<const OrderedChildSet*>* child_sets) const;
 
   // Append the handles of the children of |parent_id| to |result|.
   void AppendChildHandles(const ScopedKernelLock& lock,
diff --git a/components/sync/test/engine/mock_model_type_worker.h b/components/sync/test/engine/mock_model_type_worker.h
index 5c6f209a..66444bc 100644
--- a/components/sync/test/engine/mock_model_type_worker.h
+++ b/components/sync/test/engine/mock_model_type_worker.h
@@ -8,11 +8,11 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <deque>
 #include <map>
 #include <string>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "components/sync/engine/commit_queue.h"
 #include "components/sync/engine/model_type_processor.h"
@@ -125,7 +125,7 @@
   ModelTypeProcessor* processor_;
 
   // A record of past commits requests.
-  std::deque<CommitRequestDataList> pending_commits_;
+  base::circular_deque<CommitRequestDataList> pending_commits_;
 
   // Map of versions by client tag hash.
   // This is an essential part of the mocked server state.
diff --git a/components/viz/common/gl_helper_benchmark.cc b/components/viz/common/gl_helper_benchmark.cc
index 59c3a73..7d9a76b 100644
--- a/components/viz/common/gl_helper_benchmark.cc
+++ b/components/viz/common/gl_helper_benchmark.cc
@@ -120,7 +120,7 @@
   gpu::gles2::GLES2Interface* gl_;
   std::unique_ptr<GLHelper> helper_;
   std::unique_ptr<GLHelperScaling> helper_scaling_;
-  std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
+  base::circular_deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
 };
 
 TEST_F(GLHelperBenchmark, ScaleBenchmark) {
diff --git a/components/viz/common/gl_helper_scaling.cc b/components/viz/common/gl_helper_scaling.cc
index e394202d..4fa88db 100644
--- a/components/viz/common/gl_helper_scaling.cc
+++ b/components/viz/common/gl_helper_scaling.cc
@@ -6,11 +6,11 @@
 
 #include <stddef.h>
 
-#include <deque>
 #include <string>
 #include <vector>
 
 #include "base/bind.h"
+#include "base/containers/circular_deque.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -271,12 +271,12 @@
     const gfx::Size& dst_size,
     bool vertically_flip_texture,
     bool swizzle,
-    std::deque<GLHelperScaling::ScaleOp>* x_ops,
-    std::deque<GLHelperScaling::ScaleOp>* y_ops,
+    base::circular_deque<GLHelperScaling::ScaleOp>* x_ops,
+    base::circular_deque<GLHelperScaling::ScaleOp>* y_ops,
     std::vector<ScalerStage>* scaler_stages) {
   while (!x_ops->empty() || !y_ops->empty()) {
     gfx::Size intermediate_size = src_subrect.size();
-    std::deque<ScaleOp>* current_queue = NULL;
+    base::circular_deque<ScaleOp>* current_queue = NULL;
 
     if (!y_ops->empty()) {
       current_queue = y_ops;
@@ -397,7 +397,7 @@
     return;
   }
 
-  std::deque<GLHelperScaling::ScaleOp> x_ops, y_ops;
+  base::circular_deque<GLHelperScaling::ScaleOp> x_ops, y_ops;
   GLHelperScaling::ScaleOp::AddOps(src_subrect.width(), dst_size.width(), true,
                                    quality == GLHelper::SCALER_QUALITY_GOOD,
                                    &x_ops);
diff --git a/components/viz/common/gl_helper_scaling.h b/components/viz/common/gl_helper_scaling.h
index a37ea91..1d21916 100644
--- a/components/viz/common/gl_helper_scaling.h
+++ b/components/viz/common/gl_helper_scaling.h
@@ -5,10 +5,10 @@
 #ifndef COMPONENTS_VIZ_COMMON_GL_HELPER_SCALING_H_
 #define COMPONENTS_VIZ_COMMON_GL_HELPER_SCALING_H_
 
-#include <deque>
 #include <map>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "components/viz/common/gl_helper.h"
 #include "components/viz/common/viz_common_export.h"
@@ -97,7 +97,7 @@
                        int dst,
                        bool scale_x,
                        bool allow3,
-                       std::deque<ScaleOp>* ops) {
+                       base::circular_deque<ScaleOp>* ops) {
       int num_downscales = 0;
       if (allow3 && dst * 3 >= src && dst * 2 < src) {
         // Technically, this should be a scale up and then a
@@ -177,8 +177,8 @@
       const gfx::Size& dst_size,
       bool vertically_flip_texture,
       bool swizzle,
-      std::deque<GLHelperScaling::ScaleOp>* x_ops,
-      std::deque<GLHelperScaling::ScaleOp>* y_ops,
+      base::circular_deque<GLHelperScaling::ScaleOp>* x_ops,
+      base::circular_deque<GLHelperScaling::ScaleOp>* y_ops,
       std::vector<ScalerStage>* scaler_stages);
 
   scoped_refptr<ShaderProgram> GetShaderProgram(ShaderType type, bool swizzle);
diff --git a/components/viz/common/gl_helper_unittest.cc b/components/viz/common/gl_helper_unittest.cc
index 103cf61..49a42f5 100644
--- a/components/viz/common/gl_helper_unittest.cc
+++ b/components/viz/common/gl_helper_unittest.cc
@@ -1073,7 +1073,7 @@
   }
 
   void TestAddOps(int src, int dst, bool scale_x, bool allow3) {
-    std::deque<GLHelperScaling::ScaleOp> ops;
+    base::circular_deque<GLHelperScaling::ScaleOp> ops;
     GLHelperScaling::ScaleOp::AddOps(src, dst, scale_x, allow3, &ops);
     // Scale factor 3 is a special case.
     // It is currently only allowed by itself.
@@ -1249,7 +1249,7 @@
   gpu::gles2::GLES2Interface* gl_;
   std::unique_ptr<GLHelper> helper_;
   std::unique_ptr<GLHelperScaling> helper_scaling_;
-  std::deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
+  base::circular_deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
 };
 
 class GLHelperPixelTest : public GLHelperTest {
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h
index 1c7da262..760554c 100644
--- a/components/viz/service/display/gl_renderer.h
+++ b/components/viz/service/display/gl_renderer.h
@@ -5,11 +5,11 @@
 #ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_H_
 #define COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_H_
 
-#include <deque>
 #include <unordered_map>
 #include <vector>
 
 #include "base/cancelable_callback.h"
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "cc/output/direct_renderer.h"
 #include "cc/quads/debug_border_draw_quad.h"
@@ -287,7 +287,7 @@
   OverlayResourceLockList pending_overlay_resources_;
 
   // Resources that should be shortly swapped by the GPU process.
-  std::deque<OverlayResourceLockList> swapping_overlay_resources_;
+  base::circular_deque<OverlayResourceLockList> swapping_overlay_resources_;
 
   // Resources that the GPU process has finished swapping. The key is the
   // texture id of the resource.
@@ -338,8 +338,8 @@
   ResourceFormat current_framebuffer_format_;
 
   class SyncQuery;
-  std::deque<std::unique_ptr<SyncQuery>> pending_sync_queries_;
-  std::deque<std::unique_ptr<SyncQuery>> available_sync_queries_;
+  base::circular_deque<std::unique_ptr<SyncQuery>> pending_sync_queries_;
+  base::circular_deque<std::unique_ptr<SyncQuery>> available_sync_queries_;
   std::unique_ptr<SyncQuery> current_sync_query_;
   bool use_discard_framebuffer_ = false;
   bool use_sync_query_ = false;
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 3e71b5c..4ab0fc9 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -31,6 +31,7 @@
 #include "third_party/skia/include/core/SkShader.h"
 #include "third_party/skia/include/effects/SkLayerRasterizer.h"
 #include "third_party/skia/include/effects/SkOverdrawColorFilter.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/GrContext.h"
 #include "ui/gfx/geometry/axis_transform2d.h"
 #include "ui/gfx/geometry/rect_conversions.h"
@@ -179,14 +180,12 @@
           current_frame()->device_viewport_size) {
     // Either no SkSurface setup yet, or new GrContext, need to create new
     // surface.
-    GrBackendRenderTargetDesc desc;
-    desc.fWidth = current_frame()->device_viewport_size.width();
-    desc.fHeight = current_frame()->device_viewport_size.height();
-    desc.fConfig = kRGBA_8888_GrPixelConfig;
-    desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
-    desc.fSampleCnt = 1;
-    desc.fStencilBits = 8;
-    desc.fRenderTargetHandle = 0;
+    GrGLFramebufferInfo framebuffer_info;
+    framebuffer_info.fFBOID = 0;
+    GrBackendRenderTarget render_target(
+        current_frame()->device_viewport_size.width(),
+        current_frame()->device_viewport_size.height(), 0, 8,
+        kRGBA_8888_GrPixelConfig, framebuffer_info);
 
     // This is for use_distance_field_text false, and can_use_lcd_text true.
     // LegacyFontHost will get LCD text and skia figures out what type to use.
@@ -194,7 +193,8 @@
         SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
 
     root_surface_ = SkSurface::MakeFromBackendRenderTarget(
-        gr_context, desc, nullptr, &surface_props);
+        gr_context, render_target, kBottomLeft_GrSurfaceOrigin, nullptr,
+        &surface_props);
   }
 
   root_canvas_ = root_surface_->getCanvas();
diff --git a/components/viz/service/display_embedder/buffer_queue.h b/components/viz/service/display_embedder/buffer_queue.h
index 2ab49158..3fa44ab 100644
--- a/components/viz/service/display_embedder/buffer_queue.h
+++ b/components/viz/service/display_embedder/buffer_queue.h
@@ -7,10 +7,10 @@
 
 #include <stddef.h>
 
-#include <deque>
 #include <memory>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "components/viz/service/viz_service_export.h"
@@ -124,7 +124,7 @@
   std::vector<std::unique_ptr<AllocatedSurface>> available_surfaces_;
   // These have been swapped but are not displayed yet. Entries of this deque
   // may be nullptr, if they represent frames that have been destroyed.
-  std::deque<std::unique_ptr<AllocatedSurface>> in_flight_surfaces_;
+  base::circular_deque<std::unique_ptr<AllocatedSurface>> in_flight_surfaces_;
   GLHelper* gl_helper_;
   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
   gpu::SurfaceHandle surface_handle_;
diff --git a/components/viz/service/display_embedder/buffer_queue_unittest.cc b/components/viz/service/display_embedder/buffer_queue_unittest.cc
index 245c133..2e7d71956 100644
--- a/components/viz/service/display_embedder/buffer_queue_unittest.cc
+++ b/components/viz/service/display_embedder/buffer_queue_unittest.cc
@@ -139,7 +139,7 @@
   available_surfaces() {
     return output_surface_->available_surfaces_;
   }
-  std::deque<std::unique_ptr<BufferQueue::AllocatedSurface>>&
+  base::circular_deque<std::unique_ptr<BufferQueue::AllocatedSurface>>&
   in_flight_surfaces() {
     return output_surface_->in_flight_surfaces_;
   }
diff --git a/components/wallpaper/wallpaper_manager_base.cc b/components/wallpaper/wallpaper_manager_base.cc
index f55d28a5..222bffd7 100644
--- a/components/wallpaper/wallpaper_manager_base.cc
+++ b/components/wallpaper/wallpaper_manager_base.cc
@@ -565,6 +565,8 @@
     // Falls back to custom wallpaper that uses AccountId as part of its file
     // path.
     // Note that account id is used instead of wallpaper_files_id here.
+    LOG(ERROR) << "Failed to load custom wallpaper from its original fallback "
+                  "file path: " << valid_path.value();
     const std::string& old_path = account_id.GetUserEmail();  // Migrated
     valid_path = GetCustomWallpaperPath(kOriginalWallpaperSubDir,
                                         WallpaperFilesId::FromString(old_path),
@@ -572,22 +574,13 @@
   }
 
   if (!base::PathExists(valid_path)) {
-    user_manager::UserManager* user_manager = user_manager::UserManager::Get();
-    const user_manager::User* user = user_manager->FindUser(account_id);
     LOG(ERROR) << "Failed to load previously selected custom wallpaper. "
                << "Fallback to default wallpaper. Expected wallpaper path: "
-               << wallpaper_path.value() << ". Number of users on the device: "
-               << user_manager->GetUsers().size()
-               << ", Number of logged in users on the device: "
-               << user_manager->GetLoggedInUsers().size()
-               << ". Current user type: " << user->GetType()
-               << ", IsActiveUser=" << (user_manager->GetActiveUser() == user)
-               << ", IsPrimaryUser=" << (user_manager->GetPrimaryUser() == user)
-               << ".";
+               << wallpaper_path.value();
     reply_task_runner->PostTask(
-        FROM_HERE, base::Bind(&WallpaperManagerBase::DoSetDefaultWallpaper,
-                              weak_ptr, account_id, update_wallpaper,
-                              base::Passed(std::move(on_finish))));
+        FROM_HERE,
+        base::Bind(&WallpaperManagerBase::DoSetDefaultWallpaper, weak_ptr,
+                   account_id, base::Passed(std::move(on_finish))));
   } else {
     reply_task_runner->PostTask(
         FROM_HERE, base::Bind(&WallpaperManagerBase::StartLoad, weak_ptr,
@@ -838,7 +831,7 @@
     // In unexpected cases, revert to default wallpaper to fail safely. See
     // crosbug.com/38429.
     LOG(ERROR) << "Wallpaper reverts to default unexpected.";
-    DoSetDefaultWallpaper(account_id, update_wallpaper, std::move(on_finish));
+    DoSetDefaultWallpaper(account_id, std::move(on_finish));
   }
 }
 
diff --git a/components/wallpaper/wallpaper_manager_base.h b/components/wallpaper/wallpaper_manager_base.h
index 8a895e95..711ae1f 100644
--- a/components/wallpaper/wallpaper_manager_base.h
+++ b/components/wallpaper/wallpaper_manager_base.h
@@ -7,12 +7,12 @@
 
 #include <stddef.h>
 
-#include <deque>
 #include <map>
 #include <memory>
 #include <string>
 #include <vector>
 
+#include "base/containers/circular_deque.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted_memory.h"
@@ -481,11 +481,9 @@
   virtual void ScheduleSetUserWallpaper(const AccountId& account_id,
                                         bool delayed) = 0;
 
-  // Sets wallpaper to default if |update_wallpaper| is true. Otherwise just
-  // load defaut wallpaper to cache.
+  // Sets wallpaper to default.
   virtual void DoSetDefaultWallpaper(
       const AccountId& account_id,
-      bool update_wallpaper,
       MovableOnDestroyCallbackHolder on_finish) = 0;
 
   // Starts to load wallpaper at |wallpaper_path|. If |wallpaper_path| is
@@ -535,21 +533,18 @@
   virtual void SetDefaultWallpaperPathsFromCommandLine(
       base::CommandLine* command_line) = 0;
 
-  // Sets wallpaper to decoded default if |update_wallpaper| is true.
+  // Sets wallpaper to decoded default.
   virtual void OnDefaultWallpaperDecoded(
       const base::FilePath& path,
       const WallpaperLayout layout,
-      bool update_wallpaper,
       std::unique_ptr<user_manager::UserImage>* result,
       MovableOnDestroyCallbackHolder on_finish,
       std::unique_ptr<user_manager::UserImage> user_image) = 0;
 
-  // Start decoding given default wallpaper and set it as wallpaper if
-  // |update_wallpaper| is true.
+  // Start decoding given default wallpaper.
   virtual void StartLoadAndSetDefaultWallpaper(
       const base::FilePath& path,
       const WallpaperLayout layout,
-      bool update_wallpaper,
       MovableOnDestroyCallbackHolder on_finish,
       std::unique_ptr<user_manager::UserImage>* result_out) = 0;
 
@@ -592,7 +587,7 @@
   base::Time last_load_finished_at_;
 
   // last N wallpaper loads times.
-  std::deque<base::TimeDelta> last_load_times_;
+  base::circular_deque<base::TimeDelta> last_load_times_;
 
   base::FilePath default_small_wallpaper_file_;
   base::FilePath default_large_wallpaper_file_;
diff --git a/components/web_modal/web_contents_modal_dialog_manager.h b/components/web_modal/web_contents_modal_dialog_manager.h
index fdb684f..ce5df834 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.h
+++ b/components/web_modal/web_contents_modal_dialog_manager.h
@@ -5,9 +5,9 @@
 #ifndef COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_MANAGER_H_
 #define COMPONENTS_WEB_MODAL_WEB_CONTENTS_MODAL_DIALOG_MANAGER_H_
 
-#include <deque>
 #include <memory>
 
+#include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "components/web_modal/single_web_contents_dialog_manager.h"
@@ -85,7 +85,7 @@
     std::unique_ptr<SingleWebContentsDialogManager> manager;
   };
 
-  typedef std::deque<DialogState*> WebContentsModalDialogList;
+  typedef base::circular_deque<DialogState*> WebContentsModalDialogList;
 
   // Utility function to get the dialog state for a dialog.
   WebContentsModalDialogList::iterator FindDialogState(
diff --git a/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc b/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc
index 19e58a9..9d32091 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc
@@ -17,300 +17,227 @@
 
 namespace content {
 namespace {
-
-class AccessibilityEnumMap {
- public:
-  static AccessibilityEnumMap* GetInstance();
-
-  std::map<int32_t, base::string16> ia_role_string_map;
-  std::map<int32_t, base::string16> ia2_role_string_map;
-  std::map<int32_t, base::string16> ia_state_string_map;
-  std::map<int32_t, base::string16> ia2_state_string_map;
-  std::map<int32_t, base::string16> event_string_map;
-
- private:
-  AccessibilityEnumMap();
-  virtual ~AccessibilityEnumMap() {}
-
-  friend struct base::DefaultSingletonTraits<AccessibilityEnumMap>;
-
-  DISALLOW_COPY_AND_ASSIGN(AccessibilityEnumMap);
+struct PlatformConstantToNameEntry {
+  int32_t value;
+  const char* name;
 };
 
-// static
-AccessibilityEnumMap* AccessibilityEnumMap::GetInstance() {
-  return base::Singleton<
-      AccessibilityEnumMap,
-      base::LeakySingletonTraits<AccessibilityEnumMap>>::get();
+base::string16 GetNameForPlatformConstant(
+    const PlatformConstantToNameEntry table[],
+    size_t table_size,
+    int32_t value) {
+  for (size_t i = 0; i < table_size; ++i) {
+    auto& entry = table[i];
+    if (entry.value == value)
+      return base::ASCIIToUTF16(entry.name);
+  }
+  return L"";
+}
 }
 
-AccessibilityEnumMap::AccessibilityEnumMap() {
-// Convenience macros for generating readable strings.
-#define IA_ROLE_MAP(x) ia_role_string_map[x] = L###x;  \
-                       ia2_role_string_map[x] = L###x;
-#define IA2_ROLE_MAP(x) ia2_role_string_map[x] = L###x;
-#define IA_STATE_MAP(x) ia_state_string_map[STATE_SYSTEM_##x] = L###x;
-#define IA2_STATE_MAP(x) ia2_state_string_map[x] = L###x;
-#define EVENT_MAP(x) event_string_map[x] = L###x;
+#define QUOTE(X) \
+  { X, #X }
 
+CONTENT_EXPORT base::string16 IAccessibleRoleToString(int32_t ia_role) {
   // MSAA / IAccessible roles. Each one of these is also a valid
-  // IAccessible2 role, the IA_ROLE_MAP macro adds it to both.
-  IA_ROLE_MAP(ROLE_SYSTEM_ALERT)
-  IA_ROLE_MAP(ROLE_SYSTEM_ANIMATION)
-  IA_ROLE_MAP(ROLE_SYSTEM_APPLICATION)
-  IA_ROLE_MAP(ROLE_SYSTEM_BORDER)
-  IA_ROLE_MAP(ROLE_SYSTEM_BUTTONDROPDOWN)
-  IA_ROLE_MAP(ROLE_SYSTEM_BUTTONDROPDOWNGRID)
-  IA_ROLE_MAP(ROLE_SYSTEM_BUTTONMENU)
-  IA_ROLE_MAP(ROLE_SYSTEM_CARET)
-  IA_ROLE_MAP(ROLE_SYSTEM_CELL)
-  IA_ROLE_MAP(ROLE_SYSTEM_CHARACTER)
-  IA_ROLE_MAP(ROLE_SYSTEM_CHART)
-  IA_ROLE_MAP(ROLE_SYSTEM_CHECKBUTTON)
-  IA_ROLE_MAP(ROLE_SYSTEM_CLIENT)
-  IA_ROLE_MAP(ROLE_SYSTEM_CLOCK)
-  IA_ROLE_MAP(ROLE_SYSTEM_COLUMN)
-  IA_ROLE_MAP(ROLE_SYSTEM_COLUMNHEADER)
-  IA_ROLE_MAP(ROLE_SYSTEM_COMBOBOX)
-  IA_ROLE_MAP(ROLE_SYSTEM_CURSOR)
-  IA_ROLE_MAP(ROLE_SYSTEM_DIAGRAM)
-  IA_ROLE_MAP(ROLE_SYSTEM_DIAL)
-  IA_ROLE_MAP(ROLE_SYSTEM_DIALOG)
-  IA_ROLE_MAP(ROLE_SYSTEM_DOCUMENT)
-  IA_ROLE_MAP(ROLE_SYSTEM_DROPLIST)
-  IA_ROLE_MAP(ROLE_SYSTEM_EQUATION)
-  IA_ROLE_MAP(ROLE_SYSTEM_GRAPHIC)
-  IA_ROLE_MAP(ROLE_SYSTEM_GRIP)
-  IA_ROLE_MAP(ROLE_SYSTEM_GROUPING)
-  IA_ROLE_MAP(ROLE_SYSTEM_HELPBALLOON)
-  IA_ROLE_MAP(ROLE_SYSTEM_HOTKEYFIELD)
-  IA_ROLE_MAP(ROLE_SYSTEM_INDICATOR)
-  IA_ROLE_MAP(ROLE_SYSTEM_IPADDRESS)
-  IA_ROLE_MAP(ROLE_SYSTEM_LINK)
-  IA_ROLE_MAP(ROLE_SYSTEM_LIST)
-  IA_ROLE_MAP(ROLE_SYSTEM_LISTITEM)
-  IA_ROLE_MAP(ROLE_SYSTEM_MENUBAR)
-  IA_ROLE_MAP(ROLE_SYSTEM_MENUITEM)
-  IA_ROLE_MAP(ROLE_SYSTEM_MENUPOPUP)
-  IA_ROLE_MAP(ROLE_SYSTEM_OUTLINE)
-  IA_ROLE_MAP(ROLE_SYSTEM_OUTLINEBUTTON)
-  IA_ROLE_MAP(ROLE_SYSTEM_OUTLINEITEM)
-  IA_ROLE_MAP(ROLE_SYSTEM_PAGETAB)
-  IA_ROLE_MAP(ROLE_SYSTEM_PAGETABLIST)
-  IA_ROLE_MAP(ROLE_SYSTEM_PANE)
-  IA_ROLE_MAP(ROLE_SYSTEM_PROGRESSBAR)
-  IA_ROLE_MAP(ROLE_SYSTEM_PROPERTYPAGE)
-  IA_ROLE_MAP(ROLE_SYSTEM_PUSHBUTTON)
-  IA_ROLE_MAP(ROLE_SYSTEM_RADIOBUTTON)
-  IA_ROLE_MAP(ROLE_SYSTEM_ROW)
-  IA_ROLE_MAP(ROLE_SYSTEM_ROWHEADER)
-  IA_ROLE_MAP(ROLE_SYSTEM_SCROLLBAR)
-  IA_ROLE_MAP(ROLE_SYSTEM_SEPARATOR)
-  IA_ROLE_MAP(ROLE_SYSTEM_SLIDER)
-  IA_ROLE_MAP(ROLE_SYSTEM_SOUND)
-  IA_ROLE_MAP(ROLE_SYSTEM_SPINBUTTON)
-  IA_ROLE_MAP(ROLE_SYSTEM_SPLITBUTTON)
-  IA_ROLE_MAP(ROLE_SYSTEM_STATICTEXT)
-  IA_ROLE_MAP(ROLE_SYSTEM_STATUSBAR)
-  IA_ROLE_MAP(ROLE_SYSTEM_TABLE)
-  IA_ROLE_MAP(ROLE_SYSTEM_TEXT)
-  IA_ROLE_MAP(ROLE_SYSTEM_TITLEBAR)
-  IA_ROLE_MAP(ROLE_SYSTEM_TOOLBAR)
-  IA_ROLE_MAP(ROLE_SYSTEM_TOOLTIP)
-  IA_ROLE_MAP(ROLE_SYSTEM_WHITESPACE)
-  IA_ROLE_MAP(ROLE_SYSTEM_WINDOW)
+  // IAccessible2 role.
+  static const PlatformConstantToNameEntry ia_table[] = {
+      QUOTE(ROLE_SYSTEM_ALERT),          QUOTE(ROLE_SYSTEM_ANIMATION),
+      QUOTE(ROLE_SYSTEM_APPLICATION),    QUOTE(ROLE_SYSTEM_BORDER),
+      QUOTE(ROLE_SYSTEM_BUTTONDROPDOWN), QUOTE(ROLE_SYSTEM_BUTTONDROPDOWNGRID),
+      QUOTE(ROLE_SYSTEM_BUTTONMENU),     QUOTE(ROLE_SYSTEM_CARET),
+      QUOTE(ROLE_SYSTEM_CELL),           QUOTE(ROLE_SYSTEM_CHARACTER),
+      QUOTE(ROLE_SYSTEM_CHART),          QUOTE(ROLE_SYSTEM_CHECKBUTTON),
+      QUOTE(ROLE_SYSTEM_CLIENT),         QUOTE(ROLE_SYSTEM_CLOCK),
+      QUOTE(ROLE_SYSTEM_COLUMN),         QUOTE(ROLE_SYSTEM_COLUMNHEADER),
+      QUOTE(ROLE_SYSTEM_COMBOBOX),       QUOTE(ROLE_SYSTEM_CURSOR),
+      QUOTE(ROLE_SYSTEM_DIAGRAM),        QUOTE(ROLE_SYSTEM_DIAL),
+      QUOTE(ROLE_SYSTEM_DIALOG),         QUOTE(ROLE_SYSTEM_DOCUMENT),
+      QUOTE(ROLE_SYSTEM_DROPLIST),       QUOTE(ROLE_SYSTEM_EQUATION),
+      QUOTE(ROLE_SYSTEM_GRAPHIC),        QUOTE(ROLE_SYSTEM_GRIP),
+      QUOTE(ROLE_SYSTEM_GROUPING),       QUOTE(ROLE_SYSTEM_HELPBALLOON),
+      QUOTE(ROLE_SYSTEM_HOTKEYFIELD),    QUOTE(ROLE_SYSTEM_INDICATOR),
+      QUOTE(ROLE_SYSTEM_IPADDRESS),      QUOTE(ROLE_SYSTEM_LINK),
+      QUOTE(ROLE_SYSTEM_LIST),           QUOTE(ROLE_SYSTEM_LISTITEM),
+      QUOTE(ROLE_SYSTEM_MENUBAR),        QUOTE(ROLE_SYSTEM_MENUITEM),
+      QUOTE(ROLE_SYSTEM_MENUPOPUP),      QUOTE(ROLE_SYSTEM_OUTLINE),
+      QUOTE(ROLE_SYSTEM_OUTLINEBUTTON),  QUOTE(ROLE_SYSTEM_OUTLINEITEM),
+      QUOTE(ROLE_SYSTEM_PAGETAB),        QUOTE(ROLE_SYSTEM_PAGETABLIST),
+      QUOTE(ROLE_SYSTEM_PANE),           QUOTE(ROLE_SYSTEM_PROGRESSBAR),
+      QUOTE(ROLE_SYSTEM_PROPERTYPAGE),   QUOTE(ROLE_SYSTEM_PUSHBUTTON),
+      QUOTE(ROLE_SYSTEM_RADIOBUTTON),    QUOTE(ROLE_SYSTEM_ROW),
+      QUOTE(ROLE_SYSTEM_ROWHEADER),      QUOTE(ROLE_SYSTEM_SCROLLBAR),
+      QUOTE(ROLE_SYSTEM_SEPARATOR),      QUOTE(ROLE_SYSTEM_SLIDER),
+      QUOTE(ROLE_SYSTEM_SOUND),          QUOTE(ROLE_SYSTEM_SPINBUTTON),
+      QUOTE(ROLE_SYSTEM_SPLITBUTTON),    QUOTE(ROLE_SYSTEM_STATICTEXT),
+      QUOTE(ROLE_SYSTEM_STATUSBAR),      QUOTE(ROLE_SYSTEM_TABLE),
+      QUOTE(ROLE_SYSTEM_TEXT),           QUOTE(ROLE_SYSTEM_TITLEBAR),
+      QUOTE(ROLE_SYSTEM_TOOLBAR),        QUOTE(ROLE_SYSTEM_TOOLTIP),
+      QUOTE(ROLE_SYSTEM_WHITESPACE),     QUOTE(ROLE_SYSTEM_WINDOW),
+  };
 
-  // IAccessible2 roles.
-  IA2_ROLE_MAP(IA2_ROLE_CANVAS)
-  IA2_ROLE_MAP(IA2_ROLE_CAPTION)
-  IA2_ROLE_MAP(IA2_ROLE_CHECK_MENU_ITEM)
-  IA2_ROLE_MAP(IA2_ROLE_COLOR_CHOOSER)
-  IA2_ROLE_MAP(IA2_ROLE_DATE_EDITOR)
-  IA2_ROLE_MAP(IA2_ROLE_DESKTOP_ICON)
-  IA2_ROLE_MAP(IA2_ROLE_DESKTOP_PANE)
-  IA2_ROLE_MAP(IA2_ROLE_DIRECTORY_PANE)
-  IA2_ROLE_MAP(IA2_ROLE_EDITBAR)
-  IA2_ROLE_MAP(IA2_ROLE_EMBEDDED_OBJECT)
-  IA2_ROLE_MAP(IA2_ROLE_ENDNOTE)
-  IA2_ROLE_MAP(IA2_ROLE_FILE_CHOOSER)
-  IA2_ROLE_MAP(IA2_ROLE_FONT_CHOOSER)
-  IA2_ROLE_MAP(IA2_ROLE_FOOTER)
-  IA2_ROLE_MAP(IA2_ROLE_FOOTNOTE)
-  IA2_ROLE_MAP(IA2_ROLE_FORM)
-  IA2_ROLE_MAP(IA2_ROLE_FRAME)
-  IA2_ROLE_MAP(IA2_ROLE_GLASS_PANE)
-  IA2_ROLE_MAP(IA2_ROLE_HEADER)
-  IA2_ROLE_MAP(IA2_ROLE_HEADING)
-  IA2_ROLE_MAP(IA2_ROLE_ICON)
-  IA2_ROLE_MAP(IA2_ROLE_IMAGE_MAP)
-  IA2_ROLE_MAP(IA2_ROLE_INPUT_METHOD_WINDOW)
-  IA2_ROLE_MAP(IA2_ROLE_INTERNAL_FRAME)
-  IA2_ROLE_MAP(IA2_ROLE_LABEL)
-  IA2_ROLE_MAP(IA2_ROLE_LAYERED_PANE)
-  IA2_ROLE_MAP(IA2_ROLE_NOTE)
-  IA2_ROLE_MAP(IA2_ROLE_OPTION_PANE)
-  IA2_ROLE_MAP(IA2_ROLE_PAGE)
-  IA2_ROLE_MAP(IA2_ROLE_PARAGRAPH)
-  IA2_ROLE_MAP(IA2_ROLE_RADIO_MENU_ITEM)
-  IA2_ROLE_MAP(IA2_ROLE_REDUNDANT_OBJECT)
-  IA2_ROLE_MAP(IA2_ROLE_ROOT_PANE)
-  IA2_ROLE_MAP(IA2_ROLE_RULER)
-  IA2_ROLE_MAP(IA2_ROLE_SCROLL_PANE)
-  IA2_ROLE_MAP(IA2_ROLE_SECTION)
-  IA2_ROLE_MAP(IA2_ROLE_SHAPE)
-  IA2_ROLE_MAP(IA2_ROLE_SPLIT_PANE)
-  IA2_ROLE_MAP(IA2_ROLE_TEAR_OFF_MENU)
-  IA2_ROLE_MAP(IA2_ROLE_TERMINAL)
-  IA2_ROLE_MAP(IA2_ROLE_TEXT_FRAME)
-  IA2_ROLE_MAP(IA2_ROLE_TOGGLE_BUTTON)
-  IA2_ROLE_MAP(IA2_ROLE_UNKNOWN)
-  IA2_ROLE_MAP(IA2_ROLE_VIEW_PORT)
-
-  // MSAA / IAccessible states. Unlike roles, these are not also IA2 states.
-  IA_STATE_MAP(ALERT_HIGH)
-  IA_STATE_MAP(ALERT_LOW)
-  IA_STATE_MAP(ALERT_MEDIUM)
-  IA_STATE_MAP(ANIMATED)
-  IA_STATE_MAP(BUSY)
-  IA_STATE_MAP(CHECKED)
-  IA_STATE_MAP(COLLAPSED)
-  IA_STATE_MAP(DEFAULT)
-  IA_STATE_MAP(EXPANDED)
-  IA_STATE_MAP(EXTSELECTABLE)
-  IA_STATE_MAP(FLOATING)
-  IA_STATE_MAP(FOCUSABLE)
-  IA_STATE_MAP(FOCUSED)
-  IA_STATE_MAP(HASPOPUP)
-  IA_STATE_MAP(HOTTRACKED)
-  IA_STATE_MAP(INVISIBLE)
-  IA_STATE_MAP(LINKED)
-  IA_STATE_MAP(MARQUEED)
-  IA_STATE_MAP(MIXED)
-  IA_STATE_MAP(MOVEABLE)
-  IA_STATE_MAP(MULTISELECTABLE)
-  IA_STATE_MAP(OFFSCREEN)
-  IA_STATE_MAP(PRESSED)
-  IA_STATE_MAP(PROTECTED)
-  IA_STATE_MAP(READONLY)
-  IA_STATE_MAP(SELECTABLE)
-  IA_STATE_MAP(SELECTED)
-  IA_STATE_MAP(SELFVOICING)
-  IA_STATE_MAP(SIZEABLE)
-  IA_STATE_MAP(TRAVERSED)
-  IA_STATE_MAP(UNAVAILABLE)
-
-  // IAccessible2 states.
-  IA2_STATE_MAP(IA2_STATE_ACTIVE)
-  IA2_STATE_MAP(IA2_STATE_ARMED)
-  IA2_STATE_MAP(IA2_STATE_CHECKABLE)
-  IA2_STATE_MAP(IA2_STATE_DEFUNCT)
-  IA2_STATE_MAP(IA2_STATE_EDITABLE)
-  IA2_STATE_MAP(IA2_STATE_HORIZONTAL)
-  IA2_STATE_MAP(IA2_STATE_ICONIFIED)
-  IA2_STATE_MAP(IA2_STATE_INVALID_ENTRY)
-  IA2_STATE_MAP(IA2_STATE_MANAGES_DESCENDANTS)
-  IA2_STATE_MAP(IA2_STATE_MODAL)
-  IA2_STATE_MAP(IA2_STATE_MULTI_LINE)
-  IA2_STATE_MAP(IA2_STATE_REQUIRED)
-  IA2_STATE_MAP(IA2_STATE_SELECTABLE_TEXT)
-  IA2_STATE_MAP(IA2_STATE_SINGLE_LINE)
-  IA2_STATE_MAP(IA2_STATE_STALE)
-  IA2_STATE_MAP(IA2_STATE_SUPPORTS_AUTOCOMPLETION)
-  IA2_STATE_MAP(IA2_STATE_TRANSIENT)
-  IA2_STATE_MAP(IA2_STATE_VERTICAL)
-
-  // Untested states include those that would be repeated on nearly every node,
-  // or would vary based on window size.
-  // IA2_STATE_MAP(IA2_STATE_OPAQUE) // Untested.
-
-  EVENT_MAP(EVENT_OBJECT_CREATE)
-  EVENT_MAP(EVENT_OBJECT_DESTROY)
-  EVENT_MAP(EVENT_OBJECT_SHOW)
-  EVENT_MAP(EVENT_OBJECT_HIDE)
-  EVENT_MAP(EVENT_OBJECT_REORDER)
-  EVENT_MAP(EVENT_OBJECT_FOCUS)
-  EVENT_MAP(EVENT_OBJECT_SELECTION)
-  EVENT_MAP(EVENT_OBJECT_SELECTIONADD)
-  EVENT_MAP(EVENT_OBJECT_SELECTIONREMOVE)
-  EVENT_MAP(EVENT_OBJECT_SELECTIONWITHIN)
-  EVENT_MAP(EVENT_OBJECT_STATECHANGE)
-  EVENT_MAP(EVENT_OBJECT_LOCATIONCHANGE)
-  EVENT_MAP(EVENT_OBJECT_NAMECHANGE)
-  EVENT_MAP(EVENT_OBJECT_DESCRIPTIONCHANGE)
-  EVENT_MAP(EVENT_OBJECT_VALUECHANGE)
-  EVENT_MAP(EVENT_OBJECT_PARENTCHANGE)
-  EVENT_MAP(EVENT_OBJECT_HELPCHANGE)
-  EVENT_MAP(EVENT_OBJECT_DEFACTIONCHANGE)
-  EVENT_MAP(EVENT_OBJECT_ACCELERATORCHANGE)
-  EVENT_MAP(EVENT_OBJECT_INVOKED)
-  EVENT_MAP(EVENT_OBJECT_TEXTSELECTIONCHANGED)
-  EVENT_MAP(EVENT_OBJECT_CONTENTSCROLLED)
-  EVENT_MAP(EVENT_OBJECT_LIVEREGIONCHANGED)
-  EVENT_MAP(EVENT_OBJECT_HOSTEDOBJECTSINVALIDATED)
-  EVENT_MAP(EVENT_OBJECT_DRAGSTART)
-  EVENT_MAP(EVENT_OBJECT_DRAGCANCEL)
-  EVENT_MAP(EVENT_OBJECT_DRAGCOMPLETE)
-  EVENT_MAP(EVENT_OBJECT_DRAGENTER)
-  EVENT_MAP(EVENT_OBJECT_DRAGLEAVE)
-  EVENT_MAP(EVENT_OBJECT_DRAGDROPPED)
-  EVENT_MAP(EVENT_SYSTEM_ALERT)
-  EVENT_MAP(EVENT_SYSTEM_SCROLLINGSTART)
-  EVENT_MAP(EVENT_SYSTEM_SCROLLINGEND)
-  EVENT_MAP(IA2_EVENT_ACTION_CHANGED)
-  EVENT_MAP(IA2_EVENT_ACTIVE_DECENDENT_CHANGED)
-  EVENT_MAP(IA2_EVENT_ACTIVE_DESCENDANT_CHANGED)
-  EVENT_MAP(IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED)
-  EVENT_MAP(IA2_EVENT_DOCUMENT_CONTENT_CHANGED)
-  EVENT_MAP(IA2_EVENT_DOCUMENT_LOAD_COMPLETE)
-  EVENT_MAP(IA2_EVENT_DOCUMENT_LOAD_STOPPED)
-  EVENT_MAP(IA2_EVENT_DOCUMENT_RELOAD)
-  EVENT_MAP(IA2_EVENT_HYPERLINK_END_INDEX_CHANGED)
-  EVENT_MAP(IA2_EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED)
-  EVENT_MAP(IA2_EVENT_HYPERLINK_SELECTED_LINK_CHANGED)
-  EVENT_MAP(IA2_EVENT_HYPERTEXT_LINK_ACTIVATED)
-  EVENT_MAP(IA2_EVENT_HYPERTEXT_LINK_SELECTED)
-  EVENT_MAP(IA2_EVENT_HYPERLINK_START_INDEX_CHANGED)
-  EVENT_MAP(IA2_EVENT_HYPERTEXT_CHANGED)
-  EVENT_MAP(IA2_EVENT_HYPERTEXT_NLINKS_CHANGED)
-  EVENT_MAP(IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED)
-  EVENT_MAP(IA2_EVENT_PAGE_CHANGED)
-  EVENT_MAP(IA2_EVENT_SECTION_CHANGED)
-  EVENT_MAP(IA2_EVENT_TABLE_CAPTION_CHANGED)
-  EVENT_MAP(IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED)
-  EVENT_MAP(IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED)
-  EVENT_MAP(IA2_EVENT_TABLE_MODEL_CHANGED)
-  EVENT_MAP(IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED)
-  EVENT_MAP(IA2_EVENT_TABLE_ROW_HEADER_CHANGED)
-  EVENT_MAP(IA2_EVENT_TABLE_SUMMARY_CHANGED)
-  EVENT_MAP(IA2_EVENT_TEXT_ATTRIBUTE_CHANGED)
-  EVENT_MAP(IA2_EVENT_TEXT_CARET_MOVED)
-  EVENT_MAP(IA2_EVENT_TEXT_CHANGED)
-  EVENT_MAP(IA2_EVENT_TEXT_COLUMN_CHANGED)
-  EVENT_MAP(IA2_EVENT_TEXT_INSERTED)
-  EVENT_MAP(IA2_EVENT_TEXT_REMOVED)
-  EVENT_MAP(IA2_EVENT_TEXT_UPDATED)
-  EVENT_MAP(IA2_EVENT_TEXT_SELECTION_CHANGED)
-  EVENT_MAP(IA2_EVENT_VISIBLE_DATA_CHANGED)
+  return GetNameForPlatformConstant(ia_table, arraysize(ia_table), ia_role);
 }
 
-}  // namespace.
+CONTENT_EXPORT base::string16 IAccessible2RoleToString(int32_t ia2_role) {
+  base::string16 result = IAccessibleRoleToString(ia2_role);
+  if (!result.empty())
+    return result;
 
-base::string16 IAccessibleRoleToString(int32_t ia_role) {
-  return AccessibilityEnumMap::GetInstance()->ia_role_string_map[ia_role];
+  static const PlatformConstantToNameEntry ia2_table[] = {
+      QUOTE(IA2_ROLE_CANVAS),
+      QUOTE(IA2_ROLE_CAPTION),
+      QUOTE(IA2_ROLE_CHECK_MENU_ITEM),
+      QUOTE(IA2_ROLE_COLOR_CHOOSER),
+      QUOTE(IA2_ROLE_DATE_EDITOR),
+      QUOTE(IA2_ROLE_DESKTOP_ICON),
+      QUOTE(IA2_ROLE_DESKTOP_PANE),
+      QUOTE(IA2_ROLE_DIRECTORY_PANE),
+      QUOTE(IA2_ROLE_EDITBAR),
+      QUOTE(IA2_ROLE_EMBEDDED_OBJECT),
+      QUOTE(IA2_ROLE_ENDNOTE),
+      QUOTE(IA2_ROLE_FILE_CHOOSER),
+      QUOTE(IA2_ROLE_FONT_CHOOSER),
+      QUOTE(IA2_ROLE_FOOTER),
+      QUOTE(IA2_ROLE_FOOTNOTE),
+      QUOTE(IA2_ROLE_FORM),
+      QUOTE(IA2_ROLE_FRAME),
+      QUOTE(IA2_ROLE_GLASS_PANE),
+      QUOTE(IA2_ROLE_HEADER),
+      QUOTE(IA2_ROLE_HEADING),
+      QUOTE(IA2_ROLE_ICON),
+      QUOTE(IA2_ROLE_IMAGE_MAP),
+      QUOTE(IA2_ROLE_INPUT_METHOD_WINDOW),
+      QUOTE(IA2_ROLE_INTERNAL_FRAME),
+      QUOTE(IA2_ROLE_LABEL),
+      QUOTE(IA2_ROLE_LAYERED_PANE),
+      QUOTE(IA2_ROLE_NOTE),
+      QUOTE(IA2_ROLE_OPTION_PANE),
+      QUOTE(IA2_ROLE_PAGE),
+      QUOTE(IA2_ROLE_PARAGRAPH),
+      QUOTE(IA2_ROLE_RADIO_MENU_ITEM),
+      QUOTE(IA2_ROLE_REDUNDANT_OBJECT),
+      QUOTE(IA2_ROLE_ROOT_PANE),
+      QUOTE(IA2_ROLE_RULER),
+      QUOTE(IA2_ROLE_SCROLL_PANE),
+      QUOTE(IA2_ROLE_SECTION),
+      QUOTE(IA2_ROLE_SHAPE),
+      QUOTE(IA2_ROLE_SPLIT_PANE),
+      QUOTE(IA2_ROLE_TEAR_OFF_MENU),
+      QUOTE(IA2_ROLE_TERMINAL),
+      QUOTE(IA2_ROLE_TEXT_FRAME),
+      QUOTE(IA2_ROLE_TOGGLE_BUTTON),
+      QUOTE(IA2_ROLE_UNKNOWN),
+      QUOTE(IA2_ROLE_VIEW_PORT),
+  };
+
+  return GetNameForPlatformConstant(ia2_table, arraysize(ia2_table), ia2_role);
 }
 
-base::string16 IAccessible2RoleToString(int32_t ia_role) {
-  return AccessibilityEnumMap::GetInstance()->ia2_role_string_map[ia_role];
+CONTENT_EXPORT base::string16 AccessibilityEventToString(int32_t event) {
+  static const PlatformConstantToNameEntry event_table[] = {
+      QUOTE(EVENT_OBJECT_CREATE),
+      QUOTE(EVENT_OBJECT_DESTROY),
+      QUOTE(EVENT_OBJECT_SHOW),
+      QUOTE(EVENT_OBJECT_HIDE),
+      QUOTE(EVENT_OBJECT_REORDER),
+      QUOTE(EVENT_OBJECT_FOCUS),
+      QUOTE(EVENT_OBJECT_SELECTION),
+      QUOTE(EVENT_OBJECT_SELECTIONADD),
+      QUOTE(EVENT_OBJECT_SELECTIONREMOVE),
+      QUOTE(EVENT_OBJECT_SELECTIONWITHIN),
+      QUOTE(EVENT_OBJECT_STATECHANGE),
+      QUOTE(EVENT_OBJECT_LOCATIONCHANGE),
+      QUOTE(EVENT_OBJECT_NAMECHANGE),
+      QUOTE(EVENT_OBJECT_DESCRIPTIONCHANGE),
+      QUOTE(EVENT_OBJECT_VALUECHANGE),
+      QUOTE(EVENT_OBJECT_PARENTCHANGE),
+      QUOTE(EVENT_OBJECT_HELPCHANGE),
+      QUOTE(EVENT_OBJECT_DEFACTIONCHANGE),
+      QUOTE(EVENT_OBJECT_ACCELERATORCHANGE),
+      QUOTE(EVENT_OBJECT_INVOKED),
+      QUOTE(EVENT_OBJECT_TEXTSELECTIONCHANGED),
+      QUOTE(EVENT_OBJECT_CONTENTSCROLLED),
+      QUOTE(EVENT_OBJECT_LIVEREGIONCHANGED),
+      QUOTE(EVENT_OBJECT_HOSTEDOBJECTSINVALIDATED),
+      QUOTE(EVENT_OBJECT_DRAGSTART),
+      QUOTE(EVENT_OBJECT_DRAGCANCEL),
+      QUOTE(EVENT_OBJECT_DRAGCOMPLETE),
+      QUOTE(EVENT_OBJECT_DRAGENTER),
+      QUOTE(EVENT_OBJECT_DRAGLEAVE),
+      QUOTE(EVENT_OBJECT_DRAGDROPPED),
+      QUOTE(EVENT_SYSTEM_ALERT),
+      QUOTE(EVENT_SYSTEM_SCROLLINGSTART),
+      QUOTE(EVENT_SYSTEM_SCROLLINGEND),
+      QUOTE(IA2_EVENT_ACTION_CHANGED),
+      QUOTE(IA2_EVENT_ACTIVE_DESCENDANT_CHANGED),
+      QUOTE(IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED),
+      QUOTE(IA2_EVENT_DOCUMENT_CONTENT_CHANGED),
+      QUOTE(IA2_EVENT_DOCUMENT_LOAD_COMPLETE),
+      QUOTE(IA2_EVENT_DOCUMENT_LOAD_STOPPED),
+      QUOTE(IA2_EVENT_DOCUMENT_RELOAD),
+      QUOTE(IA2_EVENT_HYPERLINK_END_INDEX_CHANGED),
+      QUOTE(IA2_EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED),
+      QUOTE(IA2_EVENT_HYPERLINK_SELECTED_LINK_CHANGED),
+      QUOTE(IA2_EVENT_HYPERTEXT_LINK_ACTIVATED),
+      QUOTE(IA2_EVENT_HYPERTEXT_LINK_SELECTED),
+      QUOTE(IA2_EVENT_HYPERLINK_START_INDEX_CHANGED),
+      QUOTE(IA2_EVENT_HYPERTEXT_CHANGED),
+      QUOTE(IA2_EVENT_HYPERTEXT_NLINKS_CHANGED),
+      QUOTE(IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED),
+      QUOTE(IA2_EVENT_PAGE_CHANGED),
+      QUOTE(IA2_EVENT_SECTION_CHANGED),
+      QUOTE(IA2_EVENT_TABLE_CAPTION_CHANGED),
+      QUOTE(IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED),
+      QUOTE(IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED),
+      QUOTE(IA2_EVENT_TABLE_MODEL_CHANGED),
+      QUOTE(IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED),
+      QUOTE(IA2_EVENT_TABLE_ROW_HEADER_CHANGED),
+      QUOTE(IA2_EVENT_TABLE_SUMMARY_CHANGED),
+      QUOTE(IA2_EVENT_TEXT_ATTRIBUTE_CHANGED),
+      QUOTE(IA2_EVENT_TEXT_CARET_MOVED),
+      QUOTE(IA2_EVENT_TEXT_CHANGED),
+      QUOTE(IA2_EVENT_TEXT_COLUMN_CHANGED),
+      QUOTE(IA2_EVENT_TEXT_INSERTED),
+      QUOTE(IA2_EVENT_TEXT_REMOVED),
+      QUOTE(IA2_EVENT_TEXT_UPDATED),
+      QUOTE(IA2_EVENT_TEXT_SELECTION_CHANGED),
+      QUOTE(IA2_EVENT_VISIBLE_DATA_CHANGED),
+  };
+
+  return GetNameForPlatformConstant(event_table, arraysize(event_table), event);
 }
 
 void IAccessibleStateToStringVector(int32_t ia_state,
                                     std::vector<base::string16>* result) {
-  const std::map<int32_t, base::string16>& state_string_map =
-      AccessibilityEnumMap::GetInstance()->ia_state_string_map;
-  std::map<int32_t, base::string16>::const_iterator it;
-  for (it = state_string_map.begin(); it != state_string_map.end(); ++it) {
-    if (it->first & ia_state)
-      result->push_back(it->second);
+#define QUOTE_STATE(X) \
+  { STATE_SYSTEM_##X, #X }
+  // MSAA / IAccessible states. Unlike roles, these are not also IA2 states.
+  //
+  // Note: for historical reasons these are in numerical order rather than
+  // alphabetical order. Changing the order would change the order in which
+  // the states are printed, which would affect a bunch of tests.
+  static const PlatformConstantToNameEntry ia_table[] = {
+      QUOTE_STATE(UNAVAILABLE),     QUOTE_STATE(SELECTED),
+      QUOTE_STATE(FOCUSED),         QUOTE_STATE(PRESSED),
+      QUOTE_STATE(CHECKED),         QUOTE_STATE(MIXED),
+      QUOTE_STATE(READONLY),        QUOTE_STATE(HOTTRACKED),
+      QUOTE_STATE(DEFAULT),         QUOTE_STATE(EXPANDED),
+      QUOTE_STATE(COLLAPSED),       QUOTE_STATE(BUSY),
+      QUOTE_STATE(FLOATING),        QUOTE_STATE(MARQUEED),
+      QUOTE_STATE(ANIMATED),        QUOTE_STATE(INVISIBLE),
+      QUOTE_STATE(OFFSCREEN),       QUOTE_STATE(SIZEABLE),
+      QUOTE_STATE(MOVEABLE),        QUOTE_STATE(SELFVOICING),
+      QUOTE_STATE(FOCUSABLE),       QUOTE_STATE(SELECTABLE),
+      QUOTE_STATE(LINKED),          QUOTE_STATE(TRAVERSED),
+      QUOTE_STATE(MULTISELECTABLE), QUOTE_STATE(EXTSELECTABLE),
+      QUOTE_STATE(ALERT_LOW),       QUOTE_STATE(ALERT_MEDIUM),
+      QUOTE_STATE(ALERT_HIGH),      QUOTE_STATE(PROTECTED),
+      QUOTE_STATE(HASPOPUP),
+  };
+  for (auto& entry : ia_table) {
+    if (entry.value & ia_state)
+      result->push_back(base::ASCIIToUTF16(entry.name));
   }
 }
 
@@ -322,12 +249,36 @@
 
 void IAccessible2StateToStringVector(int32_t ia2_state,
                                      std::vector<base::string16>* result) {
-  const std::map<int32_t, base::string16>& state_string_map =
-      AccessibilityEnumMap::GetInstance()->ia2_state_string_map;
-  std::map<int32_t, base::string16>::const_iterator it;
-  for (it = state_string_map.begin(); it != state_string_map.end(); ++it) {
-    if (it->first & ia2_state)
-      result->push_back(it->second);
+  // Note: for historical reasons these are in numerical order rather than
+  // alphabetical order. Changing the order would change the order in which
+  // the states are printed, which would affect a bunch of tests.
+  static const PlatformConstantToNameEntry ia2_table[] = {
+      QUOTE(IA2_STATE_ACTIVE),
+      QUOTE(IA2_STATE_ARMED),
+      QUOTE(IA2_STATE_CHECKABLE),
+      QUOTE(IA2_STATE_DEFUNCT),
+      QUOTE(IA2_STATE_EDITABLE),
+      QUOTE(IA2_STATE_HORIZONTAL),
+      QUOTE(IA2_STATE_ICONIFIED),
+      QUOTE(IA2_STATE_INVALID_ENTRY),
+      QUOTE(IA2_STATE_MANAGES_DESCENDANTS),
+      QUOTE(IA2_STATE_MODAL),
+      QUOTE(IA2_STATE_MULTI_LINE),
+      QUOTE(IA2_STATE_REQUIRED),
+      QUOTE(IA2_STATE_SELECTABLE_TEXT),
+      QUOTE(IA2_STATE_SINGLE_LINE),
+      QUOTE(IA2_STATE_STALE),
+      QUOTE(IA2_STATE_SUPPORTS_AUTOCOMPLETION),
+      QUOTE(IA2_STATE_TRANSIENT),
+      QUOTE(IA2_STATE_VERTICAL),
+      // Untested states include those that would be repeated on nearly
+      // every node or would vary based on window size.
+      // QUOTE(IA2_STATE_OPAQUE) // Untested.
+  };
+
+  for (auto& entry : ia2_table) {
+    if (entry.value & ia2_state)
+      result->push_back(base::ASCIIToUTF16(entry.name));
   }
 }
 
@@ -337,8 +288,4 @@
   return base::JoinString(strings, base::ASCIIToUTF16(","));
 }
 
-base::string16 AccessibilityEventToString(int32_t event_id) {
-  return AccessibilityEnumMap::GetInstance()->event_string_map[event_id];
-}
-
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index a44a04f..ee72196 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -185,6 +185,12 @@
   headers->SetHeader(net::HttpRequestHeaders::kOrigin, origin.Serialize());
 }
 
+// Should match the definition of
+// blink::SchemeRegistry::ShouldTreatURLSchemeAsLegacy.
+bool ShouldTreatURLSchemeAsLegacy(const GURL& url) {
+  return url.SchemeIs(url::kFtpScheme) || url.SchemeIs(url::kGopherScheme);
+}
+
 }  // namespace
 
 // static
@@ -426,7 +432,9 @@
   }
 
   if (CheckCredentialedSubresource() ==
-      CredentialedSubresourceCheckResult::BLOCK_REQUEST) {
+          CredentialedSubresourceCheckResult::BLOCK_REQUEST ||
+      CheckLegacyProtocolInSubresource() ==
+          LegacyProtocolInSubresourceCheckResult::BLOCK_REQUEST) {
     // Create a navigation handle so that the correct error code can be set on
     // it by OnRequestFailed().
     CreateNavigationHandle();
@@ -597,10 +605,9 @@
   }
 
   if (CheckCredentialedSubresource() ==
-      CredentialedSubresourceCheckResult::BLOCK_REQUEST) {
-    // Create a navigation handle so that the correct error code can be set on
-    // it by OnRequestFailed().
-    CreateNavigationHandle();
+          CredentialedSubresourceCheckResult::BLOCK_REQUEST ||
+      CheckLegacyProtocolInSubresource() ==
+          LegacyProtocolInSubresourceCheckResult::BLOCK_REQUEST) {
     OnRequestFailed(false, net::ERR_ABORTED);
 
     // DO NOT ADD CODE after this. The previous call to OnRequestFailed has
@@ -1107,4 +1114,32 @@
   return CredentialedSubresourceCheckResult::BLOCK_REQUEST;
 }
 
+NavigationRequest::LegacyProtocolInSubresourceCheckResult
+NavigationRequest::CheckLegacyProtocolInSubresource() const {
+  // It only applies to subframes.
+  if (frame_tree_node_->IsMainFrame())
+    return LegacyProtocolInSubresourceCheckResult::ALLOW_REQUEST;
+
+  if (!ShouldTreatURLSchemeAsLegacy(common_params_.url))
+    return LegacyProtocolInSubresourceCheckResult::ALLOW_REQUEST;
+
+  FrameTreeNode* parent_ftn = frame_tree_node_->parent();
+  DCHECK(parent_ftn);
+  const GURL& parent_url = parent_ftn->current_url();
+  if (ShouldTreatURLSchemeAsLegacy(parent_url))
+    return LegacyProtocolInSubresourceCheckResult::ALLOW_REQUEST;
+
+  // Warn the user about the request being blocked.
+  RenderFrameHostImpl* parent = parent_ftn->current_frame_host();
+  DCHECK(parent);
+  const char* console_message =
+      "Subresource requests using legacy protocols (like `ftp:`) are blocked. "
+      "Please deliver web-accessible resources over modern protocols like "
+      "HTTPS. See https://www.chromestatus.com/feature/5709390967472128 for "
+      "details.";
+  parent->AddMessageToConsole(CONSOLE_MESSAGE_LEVEL_WARNING, console_message);
+
+  return LegacyProtocolInSubresourceCheckResult::BLOCK_REQUEST;
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index 5468f16..53971d2 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -244,6 +244,18 @@
   // request should be allowed to continue or should be blocked.
   CredentialedSubresourceCheckResult CheckCredentialedSubresource() const;
 
+  // This enum describes the result of the legacy protocol check for
+  // the request.
+  enum class LegacyProtocolInSubresourceCheckResult {
+    ALLOW_REQUEST,
+    BLOCK_REQUEST,
+  };
+
+  // Block subresources requests that target "legacy" protocol (like "ftp") when
+  // the main document is not served from a "legacy" protocol.
+  LegacyProtocolInSubresourceCheckResult CheckLegacyProtocolInSubresource()
+      const;
+
   FrameTreeNode* frame_tree_node_;
 
   // Initialized on creation of the NavigationRequest. Sent to the renderer when
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index c17ceae..4c9caf31 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -770,11 +770,6 @@
     command_line->AppendSwitchASCII(switches::kUseGL, use_gl);
   }
 
-  if (!gpu_driver_bugs_.empty()) {
-    command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
-                                    gpu::IntSetToString(gpu_driver_bugs_, ','));
-  }
-
   if (ShouldDisableAcceleratedVideoDecode(command_line)) {
     command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
   }
diff --git a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
index f5f1a9b5..e7d1c515 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc
@@ -649,33 +649,6 @@
 }
 #endif  // OS_LINUX
 
-TEST_F(GpuDataManagerImplPrivateTest, GpuDriverBugListSingle) {
-  ScopedGpuDataManagerImplPrivate manager;
-  manager->gpu_driver_bugs_.insert(5);
-
-  base::CommandLine command_line(0, NULL);
-  manager->AppendGpuCommandLine(&command_line);
-
-  EXPECT_TRUE(command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
-  std::string args = command_line.GetSwitchValueASCII(
-      switches::kGpuDriverBugWorkarounds);
-  EXPECT_STREQ("5", args.c_str());
-}
-
-TEST_F(GpuDataManagerImplPrivateTest, GpuDriverBugListMultiple) {
-  ScopedGpuDataManagerImplPrivate manager;
-  manager->gpu_driver_bugs_.insert(5);
-  manager->gpu_driver_bugs_.insert(7);
-
-  base::CommandLine command_line(0, NULL);
-  manager->AppendGpuCommandLine(&command_line);
-
-  EXPECT_TRUE(command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
-  std::string args = command_line.GetSwitchValueASCII(
-      switches::kGpuDriverBugWorkarounds);
-  EXPECT_STREQ("5,7", args.c_str());
-}
-
 TEST_F(GpuDataManagerImplPrivateTest, BlacklistAllFeatures) {
   ScopedGpuDataManagerImplPrivate manager;
   EXPECT_EQ(0u, manager->GetBlacklistedFeatureCount());
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 5d376045..6118949c 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -136,7 +136,6 @@
 #if defined(OS_CHROMEOS)
     switches::kDisableVaapiAcceleratedVideoEncode,
 #endif
-    switches::kGpuDriverBugWorkarounds,
     switches::kGpuStartupDialog,
     switches::kGpuSandboxAllowSysVShm,
     switches::kGpuSandboxFailuresFatal,
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc
index dfab0ce..f7989d1 100644
--- a/content/browser/service_worker/service_worker_context_core.cc
+++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -312,12 +312,8 @@
 }
 
 void ServiceWorkerContextCore::RemoveDispatcherHost(int process_id) {
-  // Temporary CHECKs for debugging https://crbug.com/750267.
+  // Temporary CHECK for debugging https://crbug.com/750267.
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  CHECK(dispatcher_hosts_.find(process_id) != dispatcher_hosts_.end());
-  // TODO(falken): Is RemoveAllProviderHostsForProcess() needed? The provider
-  // hosts should remove themselves when their Mojo connections break.
-  RemoveAllProviderHostsForProcess(process_id);
   dispatcher_hosts_.erase(process_id);
 }
 
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index 54f1e042..7b7a8c69 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -91,7 +91,8 @@
                                                                      this),
       render_process_id_(render_process_id),
       resource_context_(resource_context),
-      channel_ready_(false) {}
+      channel_ready_(false),
+      weak_ptr_factory_(this) {}
 
 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
   // Temporary CHECK for debugging https://crbug.com/736203.
@@ -140,8 +141,10 @@
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   // Don't wait until the destructor to teardown since a new dispatcher host
   // for this process might be created before then.
-  if (GetContext() && phase_ == Phase::kAddedToContext)
+  if (GetContext() && phase_ == Phase::kAddedToContext) {
     GetContext()->RemoveDispatcherHost(render_process_id_);
+    weak_ptr_factory_.InvalidateWeakPtrs();
+  }
   phase_ = Phase::kRemovedFromContext;
   context_wrapper_ = nullptr;
   channel_ready_ = false;
@@ -259,6 +262,11 @@
   return new_handle_ptr;
 }
 
+base::WeakPtr<ServiceWorkerDispatcherHost>
+ServiceWorkerDispatcherHost::AsWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
 void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
     int thread_id,
     int request_id,
@@ -962,9 +970,9 @@
 
     // If no host is found, create one.
     if (provider_host == nullptr) {
-      GetContext()->AddProviderHost(
-          ServiceWorkerProviderHost::Create(render_process_id_, std::move(info),
-                                            GetContext()->AsWeakPtr(), this));
+      GetContext()->AddProviderHost(ServiceWorkerProviderHost::Create(
+          render_process_id_, std::move(info), GetContext()->AsWeakPtr(),
+          AsWeakPtr()));
       return;
     }
 
@@ -975,7 +983,7 @@
       return;
     }
     provider_host->CompleteNavigationInitialized(render_process_id_,
-                                                 std::move(info), this);
+                                                 std::move(info), AsWeakPtr());
     GetContext()->AddProviderHost(std::move(provider_host));
   } else {
     // Provider host for controller should be pre-created on StartWorker in
@@ -991,7 +999,8 @@
       return;
     }
     GetContext()->AddProviderHost(ServiceWorkerProviderHost::Create(
-        render_process_id_, std::move(info), GetContext()->AsWeakPtr(), this));
+        render_process_id_, std::move(info), GetContext()->AsWeakPtr(),
+        AsWeakPtr()));
   }
 }
 
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index fc7dd23..f4bdb7d2 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -115,6 +115,8 @@
       base::WeakPtr<ServiceWorkerProviderHost> provider_host,
       ServiceWorkerRegistration* registration);
 
+  base::WeakPtr<ServiceWorkerDispatcherHost> AsWeakPtr();
+
  protected:
   ~ServiceWorkerDispatcherHost() override;
 
@@ -295,6 +297,8 @@
   bool channel_ready_;  // True after BrowserMessageFilter::sender_ != NULL.
   std::vector<std::unique_ptr<IPC::Message>> pending_messages_;
 
+  base::WeakPtrFactory<ServiceWorkerDispatcherHost> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDispatcherHost);
 };
 
diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index 6bca0a6..84b2601 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -620,13 +620,17 @@
             base::Callback<WebContents*(void)>()));
   }
 
-  // Deletion of the dispatcher_host should cause providers for that
-  // process to get deleted as well.
+  // Deletion of the dispatcher_host should cause provider hosts for
+  // that process to have a null dispatcher host.
   dispatcher_host_->OnProviderCreated(std::move(host_info_3));
-  EXPECT_TRUE(context()->GetProviderHost(process_id, kProviderId));
+  ServiceWorkerProviderHost* host =
+      context()->GetProviderHost(process_id, kProviderId);
+  EXPECT_TRUE(host->dispatcher_host());
   EXPECT_TRUE(dispatcher_host_->HasOneRef());
   dispatcher_host_ = nullptr;
-  EXPECT_FALSE(context()->GetProviderHost(process_id, kProviderId));
+  host = context()->GetProviderHost(process_id, kProviderId);
+  ASSERT_TRUE(host);
+  EXPECT_FALSE(host->dispatcher_host());
 }
 
 TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_SameOrigin) {
@@ -743,8 +747,13 @@
   // Simulate the render process crashing.
   dispatcher_host_->OnFilterRemoved();
 
-  // The dispatcher host should have removed the provider host.
-  EXPECT_FALSE(context()->GetProviderHost(process_id, provider_id));
+  // The provider host still exists, since it will clean itself up when its Mojo
+  // connection to the renderer breaks. But it should no longer be using the
+  // dispatcher host.
+  ServiceWorkerProviderHost* host =
+      context()->GetProviderHost(process_id, provider_id);
+  ASSERT_TRUE(host);
+  EXPECT_FALSE(host->dispatcher_host());
 
   // The EmbeddedWorkerInstance should still think it is running, since it will
   // clean itself up when its Mojo connection to the renderer breaks.
@@ -758,10 +767,8 @@
                                              helper_.get()));
   new_dispatcher_host->Init(context_wrapper());
 
-  // To show the new dispatcher can operate, simulate provider creation. Since
-  // the old dispatcher cleaned up the old provider host, the new one won't
-  // complain.
-  ServiceWorkerProviderHostInfo host_info(provider_id, MSG_ROUTING_NONE,
+  // To show the new dispatcher can operate, simulate provider creation.
+  ServiceWorkerProviderHostInfo host_info(provider_id + 1, MSG_ROUTING_NONE,
                                           SERVICE_WORKER_PROVIDER_FOR_WINDOW,
                                           true /* is_parent_frame_secure */);
   ServiceWorkerRemoteProviderEndpoint remote_endpoint;
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index 0b5f790e..ec12fdd8 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -982,8 +982,10 @@
 
   UpdateJobTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
   ~UpdateJobTestHelper() override {
-    if (registration_.get())
-      registration_->RemoveListener(this);
+    if (observed_registration_.get())
+      observed_registration_->RemoveListener(this);
+    for (auto& version : observed_versions_)
+      version->RemoveListener(this);
   }
 
   ServiceWorkerStorage* storage() { return context()->storage(); }
@@ -1009,7 +1011,7 @@
     EXPECT_TRUE(registration->active_version());
     EXPECT_FALSE(registration->installing_version());
     EXPECT_FALSE(registration->waiting_version());
-    registration_ = registration;
+    observed_registration_ = registration;
     return registration;
   }
 
@@ -1033,6 +1035,7 @@
                      version != registration->active_version();
 
     ASSERT_TRUE(version);
+    observed_versions_.push_back(make_scoped_refptr(version));
     version->AddListener(this);
 
     // Simulate network access.
@@ -1076,11 +1079,22 @@
           EmbeddedWorkerTestHelper::CreateHttpResponseInfo());
     }
 
+    started_workers_.insert(embedded_worker_id);
     EmbeddedWorkerTestHelper::OnStartWorker(
         embedded_worker_id, version_id, scope, script, pause_after_download,
         std::move(request), std::move(instance_host), std::move(provider_info));
   }
 
+  void OnStopWorker(int embedded_worker_id) override {
+    // Some of our tests don't call the base class in OnStartWorker(), so we
+    // can't call the base class's OnStopWorker() either.
+    auto iter = started_workers_.find(embedded_worker_id);
+    if (iter == started_workers_.end())
+      return;
+    EmbeddedWorkerTestHelper::OnStopWorker(embedded_worker_id);
+    started_workers_.erase(iter);
+  }
+
   void OnResumeAfterDownload(int embedded_worker_id) override {
     if (!force_start_worker_failure_) {
       EmbeddedWorkerTestHelper::OnResumeAfterDownload(embedded_worker_id);
@@ -1118,10 +1132,12 @@
     state_change_log_.push_back(entry);
   }
 
-  scoped_refptr<ServiceWorkerRegistration> registration_;
+  scoped_refptr<ServiceWorkerRegistration> observed_registration_;
+  std::vector<scoped_refptr<ServiceWorkerVersion>> observed_versions_;
 
   std::vector<AttributeChangeLogEntry> attribute_change_log_;
   std::vector<StateChangeLogEntry> state_change_log_;
+  std::set<int /* embedded_worker_id */> started_workers_;
   bool update_found_ = false;
   bool force_start_worker_failure_ = false;
 };
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index e05fd96..fc29d68 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -144,7 +144,7 @@
     int process_id,
     ServiceWorkerProviderHostInfo info,
     base::WeakPtr<ServiceWorkerContextCore> context,
-    ServiceWorkerDispatcherHost* dispatcher_host) {
+    base::WeakPtr<ServiceWorkerDispatcherHost> dispatcher_host) {
   return base::WrapUnique(new ServiceWorkerProviderHost(
       process_id, std::move(info), context, dispatcher_host));
 }
@@ -153,7 +153,7 @@
     int render_process_id,
     ServiceWorkerProviderHostInfo info,
     base::WeakPtr<ServiceWorkerContextCore> context,
-    ServiceWorkerDispatcherHost* dispatcher_host)
+    base::WeakPtr<ServiceWorkerDispatcherHost> dispatcher_host)
     : client_uuid_(base::GenerateGUID()),
       create_time_(base::TimeTicks::Now()),
       render_process_id_(render_process_id),
@@ -491,7 +491,7 @@
     const base::string16& message,
     const std::vector<MessagePort>& sent_message_ports) {
   if (!dispatcher_host_)
-    return;  // Could be NULL in some tests.
+    return;
 
   ServiceWorkerMsg_MessageToDocument_Params params;
   params.thread_id = kDocumentMainThreadId;
@@ -504,7 +504,7 @@
 
 void ServiceWorkerProviderHost::CountFeature(uint32_t feature) {
   if (!dispatcher_host_)
-    return;  // Could be nullptr in some tests.
+    return;
 
   // CountFeature message should be sent only for controllees.
   DCHECK(IsProviderForClient());
@@ -553,7 +553,7 @@
           process_id(),
           ServiceWorkerProviderHostInfo(std::move(info_), binding_.Unbind(),
                                         container_.PassInterface()),
-          context_, dispatcher_host()));
+          context_, dispatcher_host_));
 
   for (const GURL& pattern : associated_patterns_)
     DecreaseProcessReference(pattern);
@@ -583,7 +583,9 @@
 
   render_process_id_ = provisional_host->process_id();
   render_thread_id_ = kDocumentMainThreadId;
-  dispatcher_host_ = provisional_host->dispatcher_host();
+  dispatcher_host_ = provisional_host->dispatcher_host()
+                         ? provisional_host->dispatcher_host()->AsWeakPtr()
+                         : nullptr;
   info_ = std::move(provisional_host->info_);
 
   // Take the connection over from the provisional host.
@@ -611,7 +613,7 @@
 void ServiceWorkerProviderHost::CompleteNavigationInitialized(
     int process_id,
     ServiceWorkerProviderHostInfo info,
-    ServiceWorkerDispatcherHost* dispatcher_host) {
+    base::WeakPtr<ServiceWorkerDispatcherHost> dispatcher_host) {
   CHECK(IsBrowserSideNavigationEnabled());
   DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, render_process_id_);
   DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_WINDOW, info_.type);
@@ -665,7 +667,7 @@
       context_->GetDispatcherHost(process_id);
   DCHECK(dispatcher_host);
   render_process_id_ = process_id;
-  dispatcher_host_ = dispatcher_host;
+  dispatcher_host_ = dispatcher_host->AsWeakPtr();
 
   // Retrieve the registration associated with |version|. The registration
   // must be alive because the version keeps it during starting worker.
@@ -710,7 +712,7 @@
 void ServiceWorkerProviderHost::SendUpdateFoundMessage(
     int registration_handle_id) {
   if (!dispatcher_host_)
-    return;  // Could be nullptr in some tests.
+    return;
 
   if (!IsReadyToSendMessages()) {
     queued_events_.push_back(
@@ -730,7 +732,7 @@
     ServiceWorkerVersion* waiting_version,
     ServiceWorkerVersion* active_version) {
   if (!dispatcher_host_)
-    return;  // Could be nullptr in some tests.
+    return;
   if (!changed_mask.changed())
     return;
 
@@ -852,8 +854,6 @@
 void ServiceWorkerProviderHost::SendSetControllerServiceWorker(
     ServiceWorkerVersion* version,
     bool notify_controllerchange) {
-  // Could be nullptr in: 1) PlzNavigate case, where the renderer (and
-  // dispatcher_host) is not created yet, and 2) in some tests.
   if (!dispatcher_host_)
     return;
 
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 4be1822..b1f0d7c 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -111,7 +111,7 @@
       int process_id,
       ServiceWorkerProviderHostInfo info,
       base::WeakPtr<ServiceWorkerContextCore> context,
-      ServiceWorkerDispatcherHost* dispatcher_host);
+      base::WeakPtr<ServiceWorkerDispatcherHost> dispatcher_host);
 
   ~ServiceWorkerProviderHost() override;
 
@@ -274,7 +274,7 @@
   std::unique_ptr<ServiceWorkerProviderHost> PrepareForCrossSiteTransfer();
   void CompleteCrossSiteTransfer(ServiceWorkerProviderHost* provisional_host);
   ServiceWorkerDispatcherHost* dispatcher_host() const {
-    return dispatcher_host_;
+    return dispatcher_host_.get();
   }
 
   // PlzNavigate
@@ -282,7 +282,7 @@
   void CompleteNavigationInitialized(
       int process_id,
       ServiceWorkerProviderHostInfo info,
-      ServiceWorkerDispatcherHost* dispatcher_host);
+      base::WeakPtr<ServiceWorkerDispatcherHost> dispatcher_host);
 
   // Completes initialization of provider hosts for controllers and returns the
   // value to create ServiceWorkerNetworkProvider on the renderer which will be
@@ -353,10 +353,11 @@
     ~OneShotGetReadyCallback();
   };
 
-  ServiceWorkerProviderHost(int process_id,
-                            ServiceWorkerProviderHostInfo info,
-                            base::WeakPtr<ServiceWorkerContextCore> context,
-                            ServiceWorkerDispatcherHost* dispatcher_host);
+  ServiceWorkerProviderHost(
+      int process_id,
+      ServiceWorkerProviderHostInfo info,
+      base::WeakPtr<ServiceWorkerContextCore> context,
+      base::WeakPtr<ServiceWorkerDispatcherHost> dispatcher_host);
 
   // ServiceWorkerRegistration::Listener overrides.
   void OnVersionAttributesChanged(
@@ -440,7 +441,17 @@
 
   scoped_refptr<ServiceWorkerVersion> running_hosted_version_;
   base::WeakPtr<ServiceWorkerContextCore> context_;
-  ServiceWorkerDispatcherHost* dispatcher_host_;
+
+  // |dispatcher_host_| can be null in several cases:
+  // 1) In some tests.
+  // 2) PlzNavigate and service worker startup pre-create a
+  // ServiceWorkerProviderHost instance before there is a renderer assigned to
+  // it. The dispatcher host is set once the instance starts hosting a
+  // renderer.
+  // 3) During cross-site transfer.
+  // 4) The dispatcher host can be destructed/removed before the provider host.
+  base::WeakPtr<ServiceWorkerDispatcherHost> dispatcher_host_;
+
   bool allow_association_;
 
   // |container_| is the Mojo endpoint to the renderer-side
diff --git a/content/browser/service_worker/service_worker_provider_host_unittest.cc b/content/browser/service_worker/service_worker_provider_host_unittest.cc
index 67b8e7a..df6f1cd 100644
--- a/content/browser/service_worker/service_worker_provider_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_provider_host_unittest.cc
@@ -392,7 +392,8 @@
   // Finish the navigation.
   host->CompleteNavigationInitialized(
       helper_->mock_render_process_id(), std::move(info),
-      helper_->GetDispatcherHostForProcess(helper_->mock_render_process_id()));
+      helper_->GetDispatcherHostForProcess(helper_->mock_render_process_id())
+          ->AsWeakPtr());
 
   // The page should be controlled since there was an active version at the
   // time navigation started. The SetController IPC should have been sent.
@@ -430,7 +431,8 @@
   // Finish the navigation.
   host->CompleteNavigationInitialized(
       helper_->mock_render_process_id(), std::move(info),
-      helper_->GetDispatcherHostForProcess(helper_->mock_render_process_id()));
+      helper_->GetDispatcherHostForProcess(helper_->mock_render_process_id())
+          ->AsWeakPtr());
 
   // The page should not be controlled since there was no active version at the
   // time navigation started. Furthermore, no SetController IPC should have been
diff --git a/content/browser/service_worker/service_worker_test_utils.cc b/content/browser/service_worker/service_worker_test_utils.cc
index 11ec5dd..6d41dad 100644
--- a/content/browser/service_worker/service_worker_test_utils.cc
+++ b/content/browser/service_worker/service_worker_test_utils.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "content/browser/service_worker/service_worker_dispatcher_host.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/common/service_worker/service_worker_provider.mojom.h"
 #include "content/public/common/child_process_host.h"
@@ -77,7 +78,8 @@
                                      SERVICE_WORKER_PROVIDER_FOR_WINDOW, true);
   output_endpoint->BindWithProviderHostInfo(&info);
   return ServiceWorkerProviderHost::Create(process_id, std::move(info),
-                                           std::move(context), dispatcher_host);
+                                           std::move(context),
+                                           dispatcher_host->AsWeakPtr());
 }
 
 }  // namespace content
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 0f2da0d..5651f6c 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -7865,11 +7865,29 @@
   // Navigate the popup cross-site.  This should keep the unique origin and the
   // inherited sandbox flags.
   GURL c_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
-  TestFrameNavigationObserver popup_observer(foo_root);
-  EXPECT_TRUE(
-      ExecuteScript(foo_root, "location.href = '" + c_url.spec() + "';"));
-  popup_observer.Wait();
-  EXPECT_EQ(c_url, foo_shell->web_contents()->GetLastCommittedURL());
+  {
+    TestFrameNavigationObserver popup_observer(foo_root);
+    EXPECT_TRUE(
+        ExecuteScript(foo_root, "location.href = '" + c_url.spec() + "';"));
+    popup_observer.Wait();
+    EXPECT_EQ(c_url, foo_shell->web_contents()->GetLastCommittedURL());
+  }
+
+  // Confirm that the popup is still sandboxed, both on browser and renderer
+  // sides.
+  EXPECT_EQ(expected_flags, foo_root->effective_sandbox_flags());
+  EXPECT_EQ("null", GetDocumentOrigin(foo_root));
+
+  // Navigate the popup back to b.com.  The popup should perform a
+  // remote-to-local navigation in the b.com process, and keep the unique
+  // origin and the inherited sandbox flags.
+  {
+    TestFrameNavigationObserver popup_observer(foo_root);
+    EXPECT_TRUE(
+        ExecuteScript(foo_root, "location.href = '" + frame_url.spec() + "';"));
+    popup_observer.Wait();
+    EXPECT_EQ(frame_url, foo_shell->web_contents()->GetLastCommittedURL());
+  }
 
   // Confirm that the popup is still sandboxed, both on browser and renderer
   // sides.
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn
index 5a4f0b53..405f820ef 100644
--- a/content/child/BUILD.gn
+++ b/content/child/BUILD.gn
@@ -67,8 +67,8 @@
     "child_resource_message_filter.h",
     "child_thread_impl.cc",
     "child_thread_impl.h",
-    "child_url_loader_factory_getter.cc",
-    "child_url_loader_factory_getter.h",
+    "child_url_loader_factory_getter_impl.cc",
+    "child_url_loader_factory_getter_impl.h",
     "content_child_helpers.cc",
     "content_child_helpers.h",
     "database_util.cc",
diff --git a/content/child/child_url_loader_factory_getter.h b/content/child/child_url_loader_factory_getter.h
deleted file mode 100644
index 65e51bdf..0000000
--- a/content/child/child_url_loader_factory_getter.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_CHILD_CHILD_URL_LOADER_FACTORY_GETTER_H_
-#define CONTENT_CHILD_CHILD_URL_LOADER_FACTORY_GETTER_H_
-
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "content/common/content_export.h"
-#include "content/common/possibly_associated_interface_ptr.h"
-#include "content/public/common/url_loader_factory.mojom.h"
-
-namespace content {
-
-// ChildProcess version's URLLoaderFactoryGetter, i.e. a getter that holds
-// on to URLLoaderFactory's for a given loading context (e.g. a frame)
-// and allows code to access them.
-class CONTENT_EXPORT ChildURLLoaderFactoryGetter
-    : public base::RefCounted<ChildURLLoaderFactoryGetter> {
- public:
-  using PossiblyAssociatedURLLoaderFactory =
-      PossiblyAssociatedInterfacePtr<mojom::URLLoaderFactory>;
-  using URLLoaderFactoryGetterCallback =
-      base::OnceCallback<mojom::URLLoaderFactoryPtr()>;
-
-  // Info class stores necessary information to create a clone of
-  // ChildURLLoaderFactoryGetter in worker thread.
-  class Info {
-   public:
-    Info(mojom::URLLoaderFactoryPtrInfo network_loader_factory_info,
-         mojom::URLLoaderFactoryPtrInfo blob_loader_factory_info);
-    Info(Info&& other);
-    ~Info();
-
-    scoped_refptr<ChildURLLoaderFactoryGetter> Bind();
-
-   private:
-    mojom::URLLoaderFactoryPtrInfo network_loader_factory_info_;
-    mojom::URLLoaderFactoryPtrInfo blob_loader_factory_info_;
-  };
-
-  ChildURLLoaderFactoryGetter();
-
-  ChildURLLoaderFactoryGetter(
-      PossiblyAssociatedURLLoaderFactory network_loader_factory,
-      URLLoaderFactoryGetterCallback blob_loader_factory_getter);
-
-  ChildURLLoaderFactoryGetter(
-      PossiblyAssociatedURLLoaderFactory network_loader_factory,
-      PossiblyAssociatedURLLoaderFactory blob_loader_factory_getter);
-
-  Info GetClonedInfo();
-
-  mojom::URLLoaderFactory* GetNetworkLoaderFactory();
-  mojom::URLLoaderFactory* GetBlobLoaderFactory();
-
- private:
-  friend class base::RefCounted<ChildURLLoaderFactoryGetter>;
-  ~ChildURLLoaderFactoryGetter();
-
-  PossiblyAssociatedURLLoaderFactory network_loader_factory_;
-
-  // Either factory_getter or factory is non-null (to support
-  // lazy instantiation), or both could be null (if the default
-  // ctor is used).
-  URLLoaderFactoryGetterCallback blob_loader_factory_getter_;
-  PossiblyAssociatedURLLoaderFactory blob_loader_factory_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_CHILD_CHILD_URL_LOADER_FACTORY_GETTER_H_
diff --git a/content/child/child_url_loader_factory_getter.cc b/content/child/child_url_loader_factory_getter_impl.cc
similarity index 79%
rename from content/child/child_url_loader_factory_getter.cc
rename to content/child/child_url_loader_factory_getter_impl.cc
index 8ff679b..330280c 100644
--- a/content/child/child_url_loader_factory_getter.cc
+++ b/content/child/child_url_loader_factory_getter_impl.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/child/child_url_loader_factory_getter.h"
+#include "content/child/child_url_loader_factory_getter_impl.h"
 
 namespace content {
 
@@ -26,25 +26,26 @@
   mojom::URLLoaderFactoryPtr blob_loader_factory;
   network_loader_factory.Bind(std::move(network_loader_factory_info_));
   blob_loader_factory.Bind(std::move(blob_loader_factory_info_));
-  return base::MakeRefCounted<ChildURLLoaderFactoryGetter>(
+  return base::MakeRefCounted<ChildURLLoaderFactoryGetterImpl>(
       std::move(network_loader_factory), std::move(blob_loader_factory));
 }
 
-ChildURLLoaderFactoryGetter::ChildURLLoaderFactoryGetter() = default;
+ChildURLLoaderFactoryGetterImpl::ChildURLLoaderFactoryGetterImpl() = default;
 
-ChildURLLoaderFactoryGetter::ChildURLLoaderFactoryGetter(
+ChildURLLoaderFactoryGetterImpl::ChildURLLoaderFactoryGetterImpl(
     PossiblyAssociatedURLLoaderFactory network_loader_factory,
     URLLoaderFactoryGetterCallback blob_loader_factory_getter)
     : network_loader_factory_(std::move(network_loader_factory)),
       blob_loader_factory_getter_(std::move(blob_loader_factory_getter)) {}
 
-ChildURLLoaderFactoryGetter::ChildURLLoaderFactoryGetter(
+ChildURLLoaderFactoryGetterImpl::ChildURLLoaderFactoryGetterImpl(
     PossiblyAssociatedURLLoaderFactory network_loader_factory,
     PossiblyAssociatedURLLoaderFactory blob_loader_factory)
     : network_loader_factory_(std::move(network_loader_factory)),
       blob_loader_factory_(std::move(blob_loader_factory)) {}
 
-ChildURLLoaderFactoryGetter::Info ChildURLLoaderFactoryGetter::GetClonedInfo() {
+ChildURLLoaderFactoryGetterImpl::Info
+ChildURLLoaderFactoryGetterImpl::GetClonedInfo() {
   mojom::URLLoaderFactoryPtrInfo network_loader_factory_info;
   GetNetworkLoaderFactory()->Clone(
       mojo::MakeRequest(&network_loader_factory_info));
@@ -57,11 +58,12 @@
 }
 
 mojom::URLLoaderFactory*
-ChildURLLoaderFactoryGetter::GetNetworkLoaderFactory() {
+ChildURLLoaderFactoryGetterImpl::GetNetworkLoaderFactory() {
   return network_loader_factory_.get();
 }
 
-mojom::URLLoaderFactory* ChildURLLoaderFactoryGetter::GetBlobLoaderFactory() {
+mojom::URLLoaderFactory*
+ChildURLLoaderFactoryGetterImpl::GetBlobLoaderFactory() {
   if (!blob_loader_factory_) {
     if (blob_loader_factory_getter_.is_null()) {
       return GetNetworkLoaderFactory();
@@ -71,6 +73,6 @@
   return blob_loader_factory_.get();
 }
 
-ChildURLLoaderFactoryGetter::~ChildURLLoaderFactoryGetter() = default;
+ChildURLLoaderFactoryGetterImpl::~ChildURLLoaderFactoryGetterImpl() = default;
 
 }  // namespace content
diff --git a/content/child/child_url_loader_factory_getter_impl.h b/content/child/child_url_loader_factory_getter_impl.h
new file mode 100644
index 0000000..80a33ee
--- /dev/null
+++ b/content/child/child_url_loader_factory_getter_impl.h
@@ -0,0 +1,53 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_CHILD_URL_LOADER_FACTORY_GETTER_IMPL_H_
+#define CONTENT_CHILD_CHILD_URL_LOADER_FACTORY_GETTER_IMPL_H_
+
+#include "base/callback.h"
+#include "content/common/content_export.h"
+#include "content/common/possibly_associated_interface_ptr.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
+#include "content/public/common/url_loader_factory.mojom.h"
+
+namespace content {
+
+class CONTENT_EXPORT ChildURLLoaderFactoryGetterImpl
+    : public ChildURLLoaderFactoryGetter {
+ public:
+  using PossiblyAssociatedURLLoaderFactory =
+      PossiblyAssociatedInterfacePtr<mojom::URLLoaderFactory>;
+  using URLLoaderFactoryGetterCallback =
+      base::OnceCallback<mojom::URLLoaderFactoryPtr()>;
+
+  ChildURLLoaderFactoryGetterImpl();
+
+  ChildURLLoaderFactoryGetterImpl(
+      PossiblyAssociatedURLLoaderFactory network_loader_factory,
+      URLLoaderFactoryGetterCallback blob_loader_factory_getter);
+
+  ChildURLLoaderFactoryGetterImpl(
+      PossiblyAssociatedURLLoaderFactory network_loader_factory,
+      PossiblyAssociatedURLLoaderFactory blob_loader_factory_getter);
+
+  Info GetClonedInfo() override;
+
+  mojom::URLLoaderFactory* GetNetworkLoaderFactory() override;
+  mojom::URLLoaderFactory* GetBlobLoaderFactory() override;
+
+ private:
+  ~ChildURLLoaderFactoryGetterImpl() override;
+
+  PossiblyAssociatedURLLoaderFactory network_loader_factory_;
+
+  // Either factory_getter or factory is non-null (to support
+  // lazy instantiation), or both could be null (if the default
+  // ctor is used).
+  URLLoaderFactoryGetterCallback blob_loader_factory_getter_;
+  PossiblyAssociatedURLLoaderFactory blob_loader_factory_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_CHILD_CHILD_URL_LOADER_FACTORY_GETTER_IMPL_H_
diff --git a/content/child/service_worker/service_worker_network_provider.cc b/content/child/service_worker/service_worker_network_provider.cc
index cd376b9..65ff2b6 100644
--- a/content/child/service_worker/service_worker_network_provider.cc
+++ b/content/child/service_worker/service_worker_network_provider.cc
@@ -6,7 +6,6 @@
 
 #include "base/atomic_sequence_num.h"
 #include "content/child/child_thread_impl.h"
-#include "content/child/child_url_loader_factory_getter.h"
 #include "content/child/request_extra_data.h"
 #include "content/child/service_worker/service_worker_dispatcher.h"
 #include "content/child/service_worker/service_worker_handle_reference.h"
@@ -17,6 +16,7 @@
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_provider_host_info.h"
 #include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "ipc/ipc_sync_channel.h"
 #include "mojo/public/cpp/bindings/associated_group.h"
diff --git a/content/child/service_worker/service_worker_provider_context.cc b/content/child/service_worker/service_worker_provider_context.cc
index 9b647c1..d9ccb3e 100644
--- a/content/child/service_worker/service_worker_provider_context.cc
+++ b/content/child/service_worker/service_worker_provider_context.cc
@@ -11,7 +11,6 @@
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/child/child_thread_impl.h"
-#include "content/child/child_url_loader_factory_getter.h"
 #include "content/child/service_worker/service_worker_dispatcher.h"
 #include "content/child/service_worker/service_worker_event_dispatcher_holder.h"
 #include "content/child/service_worker/service_worker_handle_reference.h"
@@ -20,6 +19,7 @@
 #include "content/child/thread_safe_sender.h"
 #include "content/child/worker_thread_registry.h"
 #include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/url_loader_factory.mojom.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
diff --git a/content/child/service_worker/service_worker_provider_context.h b/content/child/service_worker/service_worker_provider_context.h
index f90538f3..dd240b9 100644
--- a/content/child/service_worker/service_worker_provider_context.h
+++ b/content/child/service_worker/service_worker_provider_context.h
@@ -10,13 +10,13 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/sequenced_task_runner_helpers.h"
-#include "content/child/child_url_loader_factory_getter.h"
 #include "content/child/service_worker/service_worker_dispatcher.h"
 #include "content/common/content_export.h"
 #include "content/common/service_worker/service_worker_container.mojom.h"
 #include "content/common/service_worker/service_worker_event_dispatcher.mojom.h"
 #include "content/common/service_worker/service_worker_provider.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 
 namespace base {
diff --git a/content/child/service_worker/service_worker_provider_context_unittest.cc b/content/child/service_worker/service_worker_provider_context_unittest.cc
index ebfb14d..884b007 100644
--- a/content/child/service_worker/service_worker_provider_context_unittest.cc
+++ b/content/child/service_worker/service_worker_provider_context_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
-#include "content/child/child_url_loader_factory_getter.h"
 #include "content/child/service_worker/service_worker_dispatcher.h"
 #include "content/child/service_worker/service_worker_handle_reference.h"
 #include "content/child/service_worker/service_worker_provider_context.h"
@@ -17,6 +16,7 @@
 #include "content/common/service_worker/service_worker_container.mojom.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/url_loader_factory.mojom.h"
 #include "ipc/ipc_sync_message_filter.h"
 #include "ipc/ipc_test_sink.h"
diff --git a/content/child/service_worker/service_worker_subresource_loader.cc b/content/child/service_worker/service_worker_subresource_loader.cc
index 1bcce62d..6197dee 100644
--- a/content/child/service_worker/service_worker_subresource_loader.cc
+++ b/content/child/service_worker/service_worker_subresource_loader.cc
@@ -8,10 +8,10 @@
 #include "base/callback.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "content/child/child_url_loader_factory_getter.h"
 #include "content/child/service_worker/service_worker_event_dispatcher_holder.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/content_features.h"
 #include "net/base/io_buffer.h"
 #include "net/http/http_util.h"
diff --git a/content/child/service_worker/service_worker_subresource_loader_unittest.cc b/content/child/service_worker/service_worker_subresource_loader_unittest.cc
index 7fd41197..7cc760c 100644
--- a/content/child/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/child/service_worker/service_worker_subresource_loader_unittest.cc
@@ -5,7 +5,7 @@
 #include "content/child/service_worker/service_worker_subresource_loader.h"
 
 #include "base/run_loop.h"
-#include "content/child/child_url_loader_factory_getter.h"
+#include "content/child/child_url_loader_factory_getter_impl.h"
 #include "content/child/service_worker/service_worker_event_dispatcher_holder.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_url_loader_client.h"
@@ -136,7 +136,7 @@
     request.method = method;
 
     auto loader_factory_getter =
-        base::MakeRefCounted<ChildURLLoaderFactoryGetter>();
+        base::MakeRefCounted<ChildURLLoaderFactoryGetterImpl>();
 
     mojom::URLLoaderPtr url_loader;
     TestURLLoaderClient url_loader_client;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 89cc6c26..b962787 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -357,7 +357,6 @@
     "//content:content_implementation",
     "//build/config:precompiled_headers",
     "//build/config/compiler:no_size_t_to_int_warning",
-    "//media/gpu:gpu_config",
   ]
 
   public_deps = [
@@ -399,6 +398,7 @@
     "//media/base/ipc",
     "//media/capture",
     "//media/capture/ipc",
+    "//media/gpu:features",
     "//media/gpu/ipc/client",
     "//media/gpu/ipc/common",
     "//media/midi",
diff --git a/content/common/sandbox_linux/bpf_gpu_policy_linux.cc b/content/common/sandbox_linux/bpf_gpu_policy_linux.cc
index f8a0f6c..ac5dc5aa 100644
--- a/content/common/sandbox_linux/bpf_gpu_policy_linux.cc
+++ b/content/common/sandbox_linux/bpf_gpu_policy_linux.cc
@@ -28,6 +28,7 @@
 #include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h"
 #include "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h"
 #include "content/public/common/content_switches.h"
+#include "media/gpu/features.h"
 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
 #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
@@ -81,7 +82,7 @@
 }
 
 inline bool UseV4L2Codec() {
-#if defined(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_V4L2_CODEC)
   return true;
 #else
   return false;
@@ -89,7 +90,7 @@
 }
 
 inline bool UseLibV4L2() {
-#if defined(USE_LIBV4L2)
+#if BUILDFLAG(USE_LIBV4L2)
   return true;
 #else
   return false;
diff --git a/content/gpu/in_process_gpu_thread.cc b/content/gpu/in_process_gpu_thread.cc
index bd6c1f6c..c0ff230 100644
--- a/content/gpu/in_process_gpu_thread.cc
+++ b/content/gpu/in_process_gpu_thread.cc
@@ -59,8 +59,8 @@
   gpu::GPUInfo gpu_info;
   gpu::GpuFeatureInfo gpu_feature_info;
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (!gl::init::InitializeGLOneOff()) {
-    VLOG(1) << "gl::init::InitializeGLOneOff failed";
+  if (!gl::init::InitializeGLNoExtensionsOneOff()) {
+    VLOG(1) << "gl::init::InitializeGLNoExtensionsOneOff failed";
   } else if (GetContentClient()->gpu() &&
              GetContentClient()->gpu()->GetGPUInfo() &&
              GetContentClient()->gpu()->GetGpuFeatureInfo()) {
@@ -72,6 +72,13 @@
     gpu::CollectContextGraphicsInfo(&gpu_info);
     gpu_feature_info = gpu::GetGpuFeatureInfo(gpu_info, *command_line);
   }
+  if (!gpu_feature_info.disabled_extensions.empty()) {
+    gl::init::SetDisabledExtensionsPlatform(
+        gpu_feature_info.disabled_extensions);
+  }
+  if (!gl::init::InitializeExtensionSettingsOneOffPlatform()) {
+    VLOG(1) << "gl::init::InitializeExtensionSettingsOneOffPlatform failed";
+  }
   GetContentClient()->SetGpuInfo(gpu_info);
 
   // The process object takes ownership of the thread object, so do not
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
index a2cef5c..002e819 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
@@ -31,6 +31,8 @@
 @RunWith(BaseJUnit4ClassRunner.class)
 @RetryOnFailure
 public class ContentViewPopupZoomerTest {
+    private static final String TARGET_NODE_ID = "target";
+
     @Rule
     public ContentShellActivityTestRule mActivityTestRule = new ContentShellActivityTestRule();
 
@@ -73,19 +75,17 @@
         }
     }
 
-    private String generateTestUrl(int totalUrls, int targetIdAt, String targetId) {
-        StringBuilder testUrl = new StringBuilder();
+    /**
+     * Creates a webpage that has a couple links next to one another with a zero-width node between
+     * them. Clicking on the zero-width node should trigger the popup zoomer to appear.
+     */
+    private String generateTestUrl() {
+        final StringBuilder testUrl = new StringBuilder();
         testUrl.append("<html><body>");
-        for (int i = 0; i < totalUrls; i++) {
-            boolean isTargeted = i == targetIdAt;
-            testUrl.append("<a href=\"data:text/html;utf-8,<html><head><script>"
-                    + "function doesItWork() { return 'yes'; }</script></head></html>\""
-                    + (isTargeted ? (" id=\"" + targetId + "\"") : "") + ">"
-                    + "<small><sup>"
-                    + (isTargeted ? "<b>" : "") + i + (isTargeted ? "</b>" : "")
-                    + "</sup></small></a>");
-        }
-        testUrl.append("</small></div></body></html>");
+        testUrl.append("<a href=\"javascript:void(0);\">A</a>");
+        testUrl.append("<a id=\"" + TARGET_NODE_ID + "\"></a>");
+        testUrl.append("<a href=\"javascript:void(0);\">Z</a>");
+        testUrl.append("</body></html>");
         return UrlUtils.encodeHtmlDataUri(testUrl.toString());
     }
 
@@ -99,7 +99,7 @@
     @MediumTest
     @Feature({"Browser"})
     public void testPopupZoomerShowsUp() throws InterruptedException, TimeoutException {
-        mActivityTestRule.launchContentShellWithUrl(generateTestUrl(100, 15, "clickme"));
+        mActivityTestRule.launchContentShellWithUrl(generateTestUrl());
         mActivityTestRule.waitForActiveShellToBeDoneLoading();
 
         final ContentViewCore viewCore = mActivityTestRule.getContentViewCore();
@@ -109,7 +109,7 @@
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, false));
 
         // Once clicked, the popup should show up.
-        DOMUtils.clickNode(viewCore, "clickme");
+        DOMUtils.clickNode(viewCore, TARGET_NODE_ID);
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, true));
 
         // The shown popup should have valid dimensions eventually.
@@ -124,14 +124,14 @@
     @Feature({"Browser"})
     @RetryOnFailure
     public void testBackKeyDismissesPopupZoomer() throws InterruptedException, TimeoutException {
-        mActivityTestRule.launchContentShellWithUrl(generateTestUrl(100, 15, "clickme"));
+        mActivityTestRule.launchContentShellWithUrl(generateTestUrl());
         mActivityTestRule.waitForActiveShellToBeDoneLoading();
 
         final ContentViewCore viewCore = mActivityTestRule.getContentViewCore();
         final ViewGroup view = viewCore.getContainerView();
 
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, false));
-        DOMUtils.clickNode(viewCore, "clickme");
+        DOMUtils.clickNode(viewCore, TARGET_NODE_ID);
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, true));
         InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
         // When device key is pressed, popup zoomer should hide if already showing.
diff --git a/content/public/child/BUILD.gn b/content/public/child/BUILD.gn
index 36a0155..2f289af 100644
--- a/content/public/child/BUILD.gn
+++ b/content/public/child/BUILD.gn
@@ -30,6 +30,7 @@
   sources = [
     "child_process_sandbox_support_linux.h",
     "child_thread.h",
+    "child_url_loader_factory_getter.h",
     "fixed_received_data.cc",
     "fixed_received_data.h",
     "image_decoder_utils.h",
diff --git a/content/public/child/child_url_loader_factory_getter.h b/content/public/child/child_url_loader_factory_getter.h
new file mode 100644
index 0000000..61b9589
--- /dev/null
+++ b/content/public/child/child_url_loader_factory_getter.h
@@ -0,0 +1,47 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_CHILD_CHILD_URL_LOADER_FACTORY_GETTER_H_
+#define CONTENT_PUBLIC_CHILD_CHILD_URL_LOADER_FACTORY_GETTER_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/public/common/url_loader_factory.mojom.h"
+
+namespace content {
+
+// ChildProcess version's URLLoaderFactoryGetter, i.e. a getter that holds
+// on to URLLoaderFactory's for a given loading context (e.g. a frame)
+// and allows code to access them.
+class ChildURLLoaderFactoryGetter
+    : public base::RefCounted<ChildURLLoaderFactoryGetter> {
+ public:
+  // Info class stores necessary information to create a clone of
+  // ChildURLLoaderFactoryGetter in worker thread.
+  class Info {
+   public:
+    Info(mojom::URLLoaderFactoryPtrInfo network_loader_factory_info,
+         mojom::URLLoaderFactoryPtrInfo blob_loader_factory_info);
+    Info(Info&& other);
+    ~Info();
+
+    scoped_refptr<ChildURLLoaderFactoryGetter> Bind();
+
+   private:
+    mojom::URLLoaderFactoryPtrInfo network_loader_factory_info_;
+    mojom::URLLoaderFactoryPtrInfo blob_loader_factory_info_;
+  };
+
+  virtual Info GetClonedInfo() = 0;
+
+  virtual mojom::URLLoaderFactory* GetNetworkLoaderFactory() = 0;
+  virtual mojom::URLLoaderFactory* GetBlobLoaderFactory() = 0;
+
+ protected:
+  friend class base::RefCounted<ChildURLLoaderFactoryGetter>;
+  virtual ~ChildURLLoaderFactoryGetter() = default;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_CHILD_CHILD_URL_LOADER_FACTORY_GETTER_H_
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h
index 8abce53..5a4b1ec 100644
--- a/content/public/renderer/render_frame.h
+++ b/content/public/renderer/render_frame.h
@@ -55,6 +55,7 @@
 namespace content {
 class AssociatedInterfaceProvider;
 class AssociatedInterfaceRegistry;
+class ChildURLLoaderFactoryGetter;
 class ContextMenuClient;
 class PluginInstanceThrottler;
 class RenderAccessibility;
@@ -270,6 +271,10 @@
   // BindingsPolicy for details.
   virtual int GetEnabledBindings() const = 0;
 
+  // Returns a default ChildURLLoaderFactoryGetter for the RenderFrame.
+  // Used to obtain a right mojom::URLLoaderFactory.
+  virtual ChildURLLoaderFactoryGetter* GetDefaultURLLoaderFactoryGetter() = 0;
+
  protected:
   ~RenderFrame() override {}
 
diff --git a/content/renderer/fetchers/resource_fetcher_impl.cc b/content/renderer/fetchers/resource_fetcher_impl.cc
index ec5cb20..370fa70 100644
--- a/content/renderer/fetchers/resource_fetcher_impl.cc
+++ b/content/renderer/fetchers/resource_fetcher_impl.cc
@@ -8,13 +8,12 @@
 
 #include "base/logging.h"
 #include "base/macros.h"
-#include "content/child/child_url_loader_factory_getter.h"
 #include "content/child/resource_dispatcher.h"
 #include "content/child/web_url_request_util.h"
 #include "content/common/possibly_associated_interface_ptr.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/resource_request_body.h"
-#include "content/renderer/render_frame_impl.h"
-#include "content/renderer/renderer_blink_platform_impl.h"
+#include "content/public/renderer/render_frame.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_request_headers.h"
@@ -334,7 +333,7 @@
 
   // TODO(toyoshim): mojom::URLLoaderFactory should be given by each caller.
   mojom::URLLoaderFactory* url_loader_factory =
-      RenderFrameImpl::FromWebFrame(frame)
+      RenderFrame::FromWebFrame(frame)
           ->GetDefaultURLLoaderFactoryGetter()
           ->GetNetworkLoaderFactory();
   DCHECK(url_loader_factory);
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 51fbdc21..0158f9d 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -40,7 +40,6 @@
 #include "build/build_config.h"
 #include "cc/base/switches.h"
 #include "content/child/appcache/appcache_dispatcher.h"
-#include "content/child/child_url_loader_factory_getter.h"
 #include "content/child/feature_policy/feature_policy_platform.h"
 #include "content/child/quota_dispatcher.h"
 #include "content/child/request_extra_data.h"
@@ -75,6 +74,7 @@
 #include "content/common/site_isolation_policy.h"
 #include "content/common/swapped_out_messages.h"
 #include "content/common/view_messages.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/appcache_info.h"
 #include "content/public/common/associated_interface_provider.h"
 #include "content/public/common/bindings_policy.h"
@@ -768,6 +768,7 @@
 #if defined(SYZYASAN)
   const char kCorruptHeapBlock[] = "/corrupt-heap-block";
   const char kCorruptHeap[] = "/corrupt-heap";
+  const char kDcheck[] = "/dcheck";
 #endif
 
   if (!url.DomainIs(kCrashDomain))
@@ -798,6 +799,11 @@
     LOG(ERROR) << "Intentionally causing ASAN corrupt heap"
                << " because user navigated to " << url.spec();
     base::debug::AsanCorruptHeap();
+  } else if (crash_type == kDcheck) {
+    LOG(ERROR) << "Intentionally DCHECKING because user navigated to "
+               << url.spec();
+
+    DCHECK(false) << "Intentional DCHECK.";
 #endif
   }
 }
@@ -6845,17 +6851,6 @@
     observer.DraggableRegionsChanged();
 }
 
-ChildURLLoaderFactoryGetter*
-RenderFrameImpl::GetDefaultURLLoaderFactoryGetter() {
-  RenderThreadImpl* render_thread = RenderThreadImpl::current();
-  DCHECK(render_thread);
-  if (!url_loader_factory_getter_) {
-    url_loader_factory_getter_ = render_thread->blink_platform_impl()
-                                     ->CreateDefaultURLLoaderFactoryGetter();
-  }
-  return url_loader_factory_getter_.get();
-}
-
 blink::WebPageVisibilityState RenderFrameImpl::GetVisibilityState() const {
   return VisibilityState();
 }
@@ -6880,6 +6875,17 @@
   return enabled_bindings_;
 }
 
+ChildURLLoaderFactoryGetter*
+RenderFrameImpl::GetDefaultURLLoaderFactoryGetter() {
+  RenderThreadImpl* render_thread = RenderThreadImpl::current();
+  DCHECK(render_thread);
+  if (!url_loader_factory_getter_) {
+    url_loader_factory_getter_ = render_thread->blink_platform_impl()
+                                     ->CreateDefaultURLLoaderFactoryGetter();
+  }
+  return url_loader_factory_getter_.get();
+}
+
 blink::WebPlugin* RenderFrameImpl::GetWebPluginForFind() {
   if (frame_->GetDocument().IsPluginDocument())
     return frame_->GetDocument().To<WebPluginDocument>().Plugin();
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 1fde4f9..28dda06 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -469,6 +469,10 @@
   base::SingleThreadTaskRunner* GetLoadingTaskRunner() override;
   base::SingleThreadTaskRunner* GetUnthrottledTaskRunner() override;
   int GetEnabledBindings() const override;
+  // Returns non-null.
+  // It is invalid to call this in an incomplete env where
+  // RenderThreadImpl::current() returns nullptr (e.g. in some tests).
+  ChildURLLoaderFactoryGetter* GetDefaultURLLoaderFactoryGetter() override;
 
   // blink::mojom::EngagementClient implementation:
   void SetEngagementLevel(const url::Origin& origin,
@@ -682,11 +686,6 @@
       base::SingleThreadTaskRunner* task_runner) override;
   void DraggableRegionsChanged() override;
 
-  // Returns non-null.
-  // It is invalid to call this in an incomplete env where
-  // RenderThreadImpl::current() returns nullptr (e.g. in some tests).
-  ChildURLLoaderFactoryGetter* GetDefaultURLLoaderFactoryGetter();
-
   // WebFrameSerializerClient implementation:
   void DidSerializeDataForFrame(
       const blink::WebVector<char>& data,
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index dfc3f52e..ad9796e 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -27,7 +27,7 @@
 #include "build/build_config.h"
 #include "components/url_formatter/url_formatter.h"
 #include "content/child/blob_storage/webblobregistry_impl.h"
-#include "content/child/child_url_loader_factory_getter.h"
+#include "content/child/child_url_loader_factory_getter_impl.h"
 #include "content/child/database_util.h"
 #include "content/child/file_info_util.h"
 #include "content/child/fileapi/webfilesystem_impl.h"
@@ -337,11 +337,11 @@
 
 scoped_refptr<ChildURLLoaderFactoryGetter>
 RendererBlinkPlatformImpl::CreateDefaultURLLoaderFactoryGetter() {
-  return base::MakeRefCounted<ChildURLLoaderFactoryGetter>(
+  return base::MakeRefCounted<ChildURLLoaderFactoryGetterImpl>(
       CreateNetworkURLLoaderFactory(),
       base::FeatureList::IsEnabled(features::kNetworkService)
           ? base::BindOnce(&GetBlobURLLoaderFactoryGetter)
-          : ChildURLLoaderFactoryGetter::URLLoaderFactoryGetterCallback());
+          : ChildURLLoaderFactoryGetterImpl::URLLoaderFactoryGetterCallback());
 }
 
 PossiblyAssociatedInterfacePtr<mojom::URLLoaderFactory>
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 8e2755de..0493c145 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -19,7 +19,6 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "content/child/background_sync/background_sync_type_converters.h"
-#include "content/child/child_url_loader_factory_getter.h"
 #include "content/child/notifications/notification_data_conversions.h"
 #include "content/child/request_extra_data.h"
 #include "content/child/service_worker/service_worker_dispatcher.h"
@@ -40,6 +39,7 @@
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_status_code.h"
 #include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/push_event_payload.h"
 #include "content/public/common/referrer.h"
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.h b/content/renderer/service_worker/service_worker_fetch_context_impl.h
index b6d0ff8..0a740cc 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_FETCH_CONTEXT_IMPL_H_
 #define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_FETCH_CONTEXT_IMPL_H_
 
-#include "content/child/child_url_loader_factory_getter.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/url_loader_factory.mojom.h"
 #include "third_party/WebKit/public/platform/WebWorkerFetchContext.h"
 #include "url/gurl.h"
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.h b/content/renderer/service_worker/worker_fetch_context_impl.h
index 01b2e41..8f8e344 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/worker_fetch_context_impl.h
@@ -5,9 +5,9 @@
 #ifndef CONTENT_RENDERER_SERVICE_WORKER_WORKER_FETCH_CONTEXT_IMPL_H_
 #define CONTENT_RENDERER_SERVICE_WORKER_WORKER_FETCH_CONTEXT_IMPL_H_
 
-#include "content/child/child_url_loader_factory_getter.h"
 #include "content/common/service_worker/service_worker_provider.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/service_worker_modes.h"
 #include "content/public/common/url_loader_factory.mojom.h"
 #include "ipc/ipc_message.h"
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index e36a57f..601fffe 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -11,7 +11,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/child/appcache/appcache_dispatcher.h"
 #include "content/child/appcache/web_application_cache_host_impl.h"
-#include "content/child/child_url_loader_factory_getter.h"
 #include "content/child/request_extra_data.h"
 #include "content/child/scoped_child_process_reference.h"
 #include "content/child/service_worker/service_worker_handle_reference.h"
@@ -20,6 +19,7 @@
 #include "content/child/shared_worker_devtools_agent.h"
 #include "content/child/webmessageportchannel_impl.h"
 #include "content/common/worker_messages.h"
+#include "content/public/child/child_url_loader_factory_getter.h"
 #include "content/public/common/appcache_info.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/origin_util.h"
diff --git a/content/shell/renderer/layout_test/blink_test_runner.cc b/content/shell/renderer/layout_test/blink_test_runner.cc
index c025cbea3..ba1a218 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.cc
+++ b/content/shell/renderer/layout_test/blink_test_runner.cc
@@ -820,7 +820,8 @@
   render_view()->ClearEditCommands();
   if (for_new_test) {
     if (render_view()->GetWebView()->MainFrame()->IsWebLocalFrame())
-      render_view()->GetWebView()->MainFrame()->SetName(WebString());
+      render_view()->GetWebView()->MainFrame()->ToWebLocalFrame()->SetName(
+          WebString());
     render_view()->GetWebView()->MainFrame()->ClearOpener();
   }
 
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index 9850990..2a24782 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -265,7 +265,6 @@
   const SharedMemoryLimits limits;
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  DCHECK(!command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
   DCHECK(!command_line.HasSwitch(switches::kDisableGLExtensions));
   InitializeGpuPreferencesForTestingFromCommandLine(command_line,
                                                     &gpu_preferences_);
diff --git a/gpu/config/gpu_driver_bug_list.cc b/gpu/config/gpu_driver_bug_list.cc
index 7a32c285..e7039151 100644
--- a/gpu/config/gpu_driver_bug_list.cc
+++ b/gpu/config/gpu_driver_bug_list.cc
@@ -67,15 +67,6 @@
     std::set<int>* workarounds,
     const base::CommandLine& command_line) {
   DCHECK(workarounds);
-
-  if (command_line.HasSwitch(switches::kGpuDriverBugWorkarounds)) {
-    std::string cmd_workarounds_str =
-        command_line.GetSwitchValueASCII(switches::kGpuDriverBugWorkarounds);
-    std::set<int> cmd_workarounds;
-    gpu::StringToFeatureSet(cmd_workarounds_str, &cmd_workarounds);
-    workarounds->insert(cmd_workarounds.begin(), cmd_workarounds.end());
-  }
-
   for (int i = 0; i < NUMBER_OF_GPU_DRIVER_BUG_WORKAROUND_TYPES; i++) {
     if (command_line.HasSwitch(kFeatureList[i].name)) {
       // Check for disabling workaround flag.
diff --git a/gpu/config/gpu_switches.cc b/gpu/config/gpu_switches.cc
index fc37290..68be558 100644
--- a/gpu/config/gpu_switches.cc
+++ b/gpu/config/gpu_switches.cc
@@ -32,9 +32,6 @@
 // Passes gpu device_id from browser process to GPU process.
 const char kGpuDeviceID[] = "gpu-device-id";
 
-// Pass a set of GpuDriverBugWorkaroundType ids, seperated by ','.
-const char kGpuDriverBugWorkarounds[] = "gpu-driver-bug-workarounds";
-
 // Passes gpu driver_vendor from browser process to GPU process.
 const char kGpuDriverVendor[] = "gpu-driver-vendor";
 
diff --git a/gpu/config/gpu_switches.h b/gpu/config/gpu_switches.h
index 69d642b..dd172745 100644
--- a/gpu/config/gpu_switches.h
+++ b/gpu/config/gpu_switches.h
@@ -16,7 +16,6 @@
 GPU_EXPORT extern const char kGpuActiveVendorID[];
 GPU_EXPORT extern const char kGpuActiveDeviceID[];
 GPU_EXPORT extern const char kGpuDeviceID[];
-GPU_EXPORT extern const char kGpuDriverBugWorkarounds[];
 GPU_EXPORT extern const char kGpuDriverVendor[];
 GPU_EXPORT extern const char kGpuDriverVersion[];
 GPU_EXPORT extern const char kGpuDriverDate[];
diff --git a/gpu/config/gpu_util.cc b/gpu/config/gpu_util.cc
index 1d4fb47..9802c40 100644
--- a/gpu/config/gpu_util.cc
+++ b/gpu/config/gpu_util.cc
@@ -30,18 +30,6 @@
 
 namespace {
 
-void StringToIntSet(const std::string& str, std::set<int>* list) {
-  DCHECK(list);
-  for (const base::StringPiece& piece :
-       base::SplitStringPiece(str, ",", base::TRIM_WHITESPACE,
-                              base::SPLIT_WANT_ALL)) {
-    int number = 0;
-    bool succeed = base::StringToInt(piece, &number);
-    DCHECK(succeed);
-    list->insert(number);
-  }
-}
-
 // |str| is in the format of "0x040a;0x10de;...;hex32_N".
 void StringToIds(const std::string& str, std::vector<uint32_t>* list) {
   DCHECK(list);
@@ -82,21 +70,6 @@
 
 }  // namespace anonymous
 
-std::string IntSetToString(const std::set<int>& list, char divider) {
-  std::string rt;
-  for (auto number : list) {
-    if (!rt.empty())
-      rt += divider;
-    rt += base::IntToString(number);
-  }
-  return rt;
-}
-
-void StringToFeatureSet(
-    const std::string& str, std::set<int>* feature_set) {
-  StringToIntSet(str, feature_set);
-}
-
 void ParseSecondaryGpuDevicesFromCommandLine(
     const base::CommandLine& command_line,
     GPUInfo* gpu_info) {
diff --git a/gpu/config/gpu_util.h b/gpu/config/gpu_util.h
index ec18165..489b96f2 100644
--- a/gpu/config/gpu_util.h
+++ b/gpu/config/gpu_util.h
@@ -5,9 +5,6 @@
 #ifndef GPU_CONFIG_GPU_UTIL_H_
 #define GPU_CONFIG_GPU_UTIL_H_
 
-#include <set>
-#include <string>
-
 #include "build/build_config.h"
 #include "gpu/config/gpu_feature_info.h"
 #include "gpu/gpu_export.h"
@@ -20,10 +17,6 @@
 
 struct GPUInfo;
 
-// |str| is in the format of "feature1,feature2,...,featureN".
-GPU_EXPORT void StringToFeatureSet(
-    const std::string& str, std::set<int>* feature_set);
-
 // With provided command line, fill gpu_info->secondary_gpus with parsed
 // secondary vendor and device ids.
 GPU_EXPORT void ParseSecondaryGpuDevicesFromCommandLine(
@@ -38,9 +31,6 @@
                   const base::CommandLine& command_line);
 
 GPU_EXPORT void SetKeysForCrashLogging(const GPUInfo& gpu_info);
-
-// Combine the integers into a string, separated by divider.
-GPU_EXPORT std::string IntSetToString(const std::set<int>& list, char divider);
 }  // namespace gpu
 
 #endif  // GPU_CONFIG_GPU_UTIL_H_
diff --git a/gpu/config/gpu_util_unittest.cc b/gpu/config/gpu_util_unittest.cc
index d5ccb11..5fc2e5b 100644
--- a/gpu/config/gpu_util_unittest.cc
+++ b/gpu/config/gpu_util_unittest.cc
@@ -6,33 +6,13 @@
 
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/config/gpu_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace gpu {
 
-TEST(GpuUtilTest, StringToFeatureSet) {
-  {
-    // zero feature.
-    std::set<int> features;
-    StringToFeatureSet("", &features);
-    EXPECT_EQ(0u, features.size());
-  }
-  {
-    // One features.
-    std::set<int> features;
-    StringToFeatureSet("4", &features);
-    EXPECT_EQ(1u, features.size());
-  }
-  {
-    // Multiple features.
-    std::set<int> features;
-    StringToFeatureSet("1,9", &features);
-    EXPECT_EQ(2u, features.size());
-  }
-}
-
 TEST(GpuUtilTest, ParseSecondaryGpuDevicesFromCommandLine_Simple) {
   base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
   command_line.AppendSwitchASCII(switches::kGpuSecondaryVendorIDs, "0x10de");
@@ -141,4 +121,50 @@
   EXPECT_EQ(gpu_info.secondary_gpus.size(), 0ul);
 }
 
+TEST(GpuUtilTest, GetGpuFeatureInfo_WorkaroundFromCommandLine) {
+  {
+    base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+    GPUInfo gpu_info;
+    GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(gpu_info, command_line);
+    EXPECT_FALSE(gpu_feature_info.IsWorkaroundEnabled(
+        USE_GPU_DRIVER_WORKAROUND_FOR_TESTING));
+  }
+
+  {
+    base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+    command_line.AppendSwitchASCII(GpuDriverBugWorkaroundTypeToString(
+                                       USE_GPU_DRIVER_WORKAROUND_FOR_TESTING),
+                                   "1");
+    GPUInfo gpu_info;
+    GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(gpu_info, command_line);
+    EXPECT_TRUE(gpu_feature_info.IsWorkaroundEnabled(
+        USE_GPU_DRIVER_WORKAROUND_FOR_TESTING));
+  }
+
+  {
+    base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+    GPUInfo gpu_info;
+    // See gpu/config/gpu_driver_bug_list.json, entry 215.
+    gpu_info.gpu.vendor_id = 0xbad9;
+    gpu_info.gpu.device_id = 0xbad9;
+    GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(gpu_info, command_line);
+    EXPECT_TRUE(gpu_feature_info.IsWorkaroundEnabled(
+        USE_GPU_DRIVER_WORKAROUND_FOR_TESTING));
+  }
+
+  {
+    base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+    command_line.AppendSwitchASCII(GpuDriverBugWorkaroundTypeToString(
+                                       USE_GPU_DRIVER_WORKAROUND_FOR_TESTING),
+                                   "0");
+    GPUInfo gpu_info;
+    // See gpu/config/gpu_driver_bug_list.json, entry 215.
+    gpu_info.gpu.vendor_id = 0xbad9;
+    gpu_info.gpu.device_id = 0xbad9;
+    GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(gpu_info, command_line);
+    EXPECT_FALSE(gpu_feature_info.IsWorkaroundEnabled(
+        USE_GPU_DRIVER_WORKAROUND_FOR_TESTING));
+  }
+}
+
 }  // namespace gpu
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index 84188fc..654bc389 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -264,16 +264,6 @@
   UMA_HISTOGRAM_TIMES("GPU.CollectContextGraphicsInfo", collect_context_time);
 
   gpu_feature_info_ = gpu::GetGpuFeatureInfo(gpu_info_, command_line);
-  if (!gpu_feature_info_.enabled_gpu_driver_bug_workarounds.empty()) {
-    // TODO(zmo): Remove this block of code. They are only for existing tests.
-    std::set<int> workarounds;
-    workarounds.insert(
-        gpu_feature_info_.enabled_gpu_driver_bug_workarounds.begin(),
-        gpu_feature_info_.enabled_gpu_driver_bug_workarounds.end());
-    base::CommandLine* cmd_line = const_cast<base::CommandLine*>(&command_line);
-    cmd_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
-                                gpu::IntSetToString(workarounds, ','));
-  }
   if (!gpu_feature_info_.disabled_extensions.empty()) {
     gl::init::SetDisabledExtensionsPlatform(
         gpu_feature_info_.disabled_extensions);
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index 82c81044..84cad42d 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -850,7 +850,7 @@
 
 if (is_fuchsia) {
   fuchsia_executable_runner("headless_shell_fuchsia") {
-    exe_name = "headless_shell"
+    exe_target = ":headless_shell"
   }
 }
 
@@ -867,10 +867,6 @@
   if (is_win) {
     deps += [ "//build/win:default_exe_manifest" ]
   }
-
-  if (is_fuchsia) {
-    deps += [ ":headless_shell_fuchsia" ]
-  }
 }
 
 process_version("version_header") {
diff --git a/headless/public/util/testing/generic_url_request_mocks.cc b/headless/public/util/testing/generic_url_request_mocks.cc
index 2d71c85..c811651e 100644
--- a/headless/public/util/testing/generic_url_request_mocks.cc
+++ b/headless/public/util/testing/generic_url_request_mocks.cc
@@ -137,6 +137,13 @@
   return nullptr;
 }
 
+std::unique_ptr<net::CookieStore::CookieChangedSubscription>
+MockCookieStore::AddCallbackForAllChanges(
+    const CookieChangedCallback& callback) {
+  CHECK(false);
+  return nullptr;
+}
+
 bool MockCookieStore::IsEphemeral() {
   CHECK(false);
   return true;
diff --git a/headless/public/util/testing/generic_url_request_mocks.h b/headless/public/util/testing/generic_url_request_mocks.h
index 1bfa34b..565a138 100644
--- a/headless/public/util/testing/generic_url_request_mocks.h
+++ b/headless/public/util/testing/generic_url_request_mocks.h
@@ -109,6 +109,9 @@
       const std::string& name,
       const CookieChangedCallback& callback) override;
 
+  std::unique_ptr<CookieChangedSubscription> AddCallbackForAllChanges(
+      const CookieChangedCallback& callback) override;
+
   bool IsEphemeral() override;
 
   net::CookieList* cookies() { return &cookies_; }
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 61a7157..8ac86d9 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -2226,6 +2226,7 @@
       // They must be started after the BVC view is added in the hierarchy.
       self.NTPActionAfterTabSwitcherDismissal =
           [_startupParameters postOpeningAction];
+      [self setStartupParameters:nil];
       tab = [_tabSwitcherController
           dismissWithNewTabAnimationToModel:targetBVC.tabModel
                                     withURL:url
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 21e8a5b..be8c9134 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -122,6 +122,7 @@
     "//ios/chrome/browser/drag_and_drop",
     "//ios/chrome/browser/ssl:features",
     "//ios/chrome/browser/sync/glue",
+    "//ios/chrome/browser/web:features",
     "//ios/chrome/common",
     "//ios/components/io_thread",
     "//ios/net",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 278154f..df9416b 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -39,6 +39,7 @@
 #include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
 #include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
 #include "ios/chrome/browser/ssl/captive_portal_features.h"
+#include "ios/chrome/browser/web/features.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/web/public/user_agent.h"
@@ -179,6 +180,10 @@
      flag_descriptions::kBookmarkNewGenerationDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(
          bookmark_new_generation::features::kBookmarkNewGeneration)},
+    {"mailto-prompt-for-user-choice",
+     flag_descriptions::kMailtoPromptForUserChoiceName,
+     flag_descriptions::kMailtoPromptForUserChoiceDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kMailtoPromptForUserChoice)},
 #if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0)
     {"drag_and_drop", flag_descriptions::kDragAndDropName,
      flag_descriptions::kDragAndDropDescription, flags_ui::kOsIos,
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index 0974fa2..5faa1f9c 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -46,6 +46,12 @@
 const char kMarkHttpAsNonSecureWhileIncognitoOrEditing[] =
     "Warn on HTTP while in Incognito mode or after editing forms";
 
+const char kMailtoPromptForUserChoiceName[] =
+    "Mailto Handler Prompt for User Choice";
+const char kMailtoPromptForUserChoiceDescription[] =
+    "Enable prompt for user to choose a mail client app when user taps on a "
+    "mailto:// URL link.";
+
 const char kOmniboxUIElideSuggestionUrlAfterHostName[] =
     "Hide the path, query, and ref of omnibox suggestions";
 const char kOmniboxUIElideSuggestionUrlAfterHostDescription[] =
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index 92c643d0..04b563e 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -38,6 +38,11 @@
 extern const char kMarkHttpAsNonSecureWhileIncognito[];
 extern const char kMarkHttpAsNonSecureWhileIncognitoOrEditing[];
 
+// Title and descript for the flag to enable a prompt asking user to choose
+// which mail client app to use to handle mailto:// URLs.
+extern const char kMailtoPromptForUserChoiceName[];
+extern const char kMailtoPromptForUserChoiceDescription[];
+
 // Title and description for the flag to enable elision of the URL path, query,
 // and ref in omnibox URL suggestions.
 extern const char kOmniboxUIElideSuggestionUrlAfterHostName[];
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn
index ec9bc7d3..37034c1 100644
--- a/ios/chrome/browser/ui/authentication/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -179,3 +179,17 @@
   ]
   libs = [ "XCTest.framework" ]
 }
+
+source_set("eg_test_support") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "signin_promo_view_earlgrey_utils.h",
+    "signin_promo_view_earlgrey_utils.mm",
+  ]
+  deps = [
+    ":authentication_ui",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/third_party/earl_grey",
+  ]
+}
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h b/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h
new file mode 100644
index 0000000..da7f9a7
--- /dev/null
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h
@@ -0,0 +1,20 @@
+// 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_UI_AUTHENTICATION_SIGN_PROMO_VIEW_EARLGREY_UTILS_H_
+#define IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGN_PROMO_VIEW_EARLGREY_UTILS_H_
+
+#import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
+
+@interface SignPromoViewEarlgreyUtils : NSObject
+
+// Checks that the sign-in promo view is visible using the right mode.
++ (void)checkSigninPromoVisibleWithMode:(SigninPromoViewMode)mode;
+
+// Checks that the sign-in promo view is not visible.
++ (void)checkSigninPromoNotVisible;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGN_PROMO_VIEW_EARLGREY_UTILS_H_
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.mm
new file mode 100644
index 0000000..a19fb1ca
--- /dev/null
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.mm
@@ -0,0 +1,62 @@
+// 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.
+
+#import "ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h"
+
+#import <EarlGrey/EarlGrey.h>
+
+#import "ios/chrome/test/earl_grey/chrome_matchers.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+using chrome_test_util::PrimarySignInButton;
+using chrome_test_util::SecondarySignInButton;
+
+@implementation SignPromoViewEarlgreyUtils
+
++ (void)checkSigninPromoVisibleWithMode:(SigninPromoViewMode)mode {
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(
+                                   grey_accessibilityID(kSigninPromoViewId),
+                                   grey_sufficientlyVisible(), nil)]
+      assertWithMatcher:grey_notNil()];
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
+                                          grey_sufficientlyVisible(), nil)]
+      assertWithMatcher:grey_notNil()];
+  switch (mode) {
+    case SigninPromoViewModeColdState:
+      [[EarlGrey
+          selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
+                                              grey_sufficientlyVisible(), nil)]
+          assertWithMatcher:grey_nil()];
+      break;
+    case SigninPromoViewModeWarmState:
+      [[EarlGrey
+          selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
+                                              grey_sufficientlyVisible(), nil)]
+          assertWithMatcher:grey_notNil()];
+      break;
+  }
+}
+
++ (void)checkSigninPromoNotVisible {
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(
+                                   grey_accessibilityID(kSigninPromoViewId),
+                                   grey_sufficientlyVisible(), nil)]
+      assertWithMatcher:grey_nil()];
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
+                                          grey_sufficientlyVisible(), nil)]
+      assertWithMatcher:grey_nil()];
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
+                                          grey_sufficientlyVisible(), nil)]
+      assertWithMatcher:grey_nil()];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index 861f6c8..45d3f4cb 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -195,6 +195,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui/authentication:authentication_ui",
+    "//ios/chrome/browser/ui/authentication:eg_test_support",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/toolbar",
     "//ios/chrome/browser/ui/tools_menu",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index 6c56fd0..be0bbfb 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -193,6 +193,7 @@
                                          style:UIBarButtonItemStyleDone
                                         target:self
                                         action:@selector(navigationBarCancel:)];
+    doneButton.accessibilityIdentifier = @"DONE";
     self.navigationItem.rightBarButtonItem = doneButton;
     self.navigationItem.backBarButtonItem =
         [[UIBarButtonItem alloc] initWithTitle:@""
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
index bea273e..0922794d 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -20,6 +20,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
+#import "ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_controller.h"
@@ -1051,10 +1052,10 @@
   [self setTearDownHandler:^{
     [BookmarksTestCase setPromoAlreadySeen:NO];
   }];
-  // Check that promo is visible.
+  // Check that sign-in promo view is visible.
   [BookmarksTestCase verifyPromoAlreadySeen:NO];
-  [[EarlGrey selectElementWithMatcher:PrimarySignInButton()]
-      assertWithMatcher:grey_sufficientlyVisible()];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
 
   // Tap the dismiss button.
   [[EarlGrey
@@ -1062,39 +1063,96 @@
       performAction:grey_tap()];
 
   // Wait until promo is gone.
-  [[EarlGrey selectElementWithMatcher:SecondarySignInButton()]
-      assertWithMatcher:grey_notVisible()];
+  [SignPromoViewEarlgreyUtils checkSigninPromoNotVisible];
 
   // Check that the promo already seen state is updated.
   [BookmarksTestCase verifyPromoAlreadySeen:YES];
 }
 
-// Tests that tapping Sign in on the promo make the Sign in sheet appear and
-// the promo still appears after dismissing the Sign in sheet.
-- (void)testUIPromoSignIn {
+// Tests the tapping on the primary button of sign-in promo view in a cold
+// state makes the sign-in sheet appear, and the promo still appears after
+// dismissing the sheet.
+- (void)testSignInPromoWithColdStateUsingPrimaryButton {
+  [BookmarksTestCase openBookmarks];
+
+  // Check that sign-in promo view are visible.
+  [BookmarksTestCase verifyPromoAlreadySeen:NO];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
+
+  // Tap the primary button.
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
+                                          grey_sufficientlyVisible(), nil)]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Cancel")]
+      performAction:grey_tap()];
+
+  // Check that the bookmarks UI reappeared and the cell is still here.
+  [BookmarksTestCase verifyPromoAlreadySeen:NO];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
+}
+
+// Tests the tapping on the primary button of sign-in promo view in a warm
+// state makes the confirmaiton sheet appear, and the promo still appears after
+// dismissing the sheet.
+- (void)testSignInPromoWithWarmStateUsingPrimaryButton {
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openTopLevelBookmarksFolder];
 
   // Set up a fake identity.
   ChromeIdentity* identity =
+      [FakeChromeIdentity identityWithEmail:@"fakefoo@gmail.com"
+                                     gaiaID:@"fakefoopassword"
+                                       name:@"Fake Foo"];
+  ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
+      identity);
+
+  // Check that sign-in promo view are visible.
+  [BookmarksTestCase verifyPromoAlreadySeen:NO];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
+
+  // Tap the secondary button.
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
+                                          grey_sufficientlyVisible(), nil)]
+      performAction:grey_tap()];
+
+  // Tap the UNDO button.
+  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"UNDO")]
+      performAction:grey_tap()];
+
+  // Check that the bookmarks UI reappeared and the cell is still here.
+  [BookmarksTestCase verifyPromoAlreadySeen:NO];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
+}
+
+// Tests the tapping on the secondary button of sign-in promo view in a warm
+// state makes the sign-in sheet appear, and the promo still appears after
+// dismissing the sheet.
+- (void)testSignInPromoWithWarmStateUsingSecondaryButton {
+  [BookmarksTestCase setupStandardBookmarks];
+  [BookmarksTestCase openTopLevelBookmarksFolder];
+  // Set up a fake identity.
+  ChromeIdentity* identity =
       [FakeChromeIdentity identityWithEmail:@"fakefoo@egmail.com"
                                      gaiaID:@"fakefoopassword"
                                        name:@"Fake Foo"];
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
       identity);
 
-  // Check that promo is visible.
+  // Check that sign-in promo view are visible.
   [BookmarksTestCase verifyPromoAlreadySeen:NO];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
+
+  // Tap the secondary button.
   [[EarlGrey
       selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
                                           grey_sufficientlyVisible(), nil)]
-      assertWithMatcher:grey_notNil()];
-
-  // Tap the Sign in button.
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(grey_accessibilityID(
-                                              kSigninPromoSecondaryButtonId),
-                                          grey_sufficientlyVisible(), nil)]
       performAction:grey_tap()];
 
   // Tap the CANCEL button.
@@ -1104,12 +1162,38 @@
                      uppercaseString])] performAction:grey_tap()];
 
   // Check that the bookmarks UI reappeared and the cell is still here.
-  [[EarlGrey
-      selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
-                                          grey_sufficientlyVisible(), nil)]
-      assertWithMatcher:grey_notNil()];
-
   [BookmarksTestCase verifyPromoAlreadySeen:NO];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
+}
+
+// Tests that the sign-in promo should not be shown after been shown 19 times.
+- (void)testAutomaticSigninPromoDismiss {
+  ios::ChromeBrowserState* browser_state =
+      chrome_test_util::GetOriginalBrowserState();
+  PrefService* prefs = browser_state->GetPrefs();
+  prefs->SetInteger(prefs::kIosBookmarkSigninPromoDisplayedCount, 19);
+  [BookmarksTestCase openBookmarks];
+  // Check the sign-in promo view is visible.
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
+  // Check the sign-in promo will not be shown anymore.
+  [BookmarksTestCase verifyPromoAlreadySeen:YES];
+  GREYAssertEqual(
+      20, prefs->GetInteger(prefs::kIosBookmarkSigninPromoDisplayedCount),
+      @"Should have incremented the display count");
+  // Close the bookmark view and open it again.
+  if (IsCompact()) {
+    [[EarlGrey selectElementWithMatcher:BookmarksDoneButton()]
+        performAction:grey_tap()];
+    [BookmarksTestCase openBookmarks];
+  } else {
+    [BookmarksTestCase closeAllTabs];
+    chrome_test_util::OpenNewTab();
+  }
+  [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
+  // Check that the sign-in promo is not visible anymore.
+  [SignPromoViewEarlgreyUtils checkSigninPromoNotVisible];
 }
 
 // Tests that all elements on the bookmarks landing page are accessible.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
index 0c00147..c17d2bf7 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_new_generation_egtest.mm
@@ -17,6 +17,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
+#import "ios/chrome/browser/ui/authentication/signin_promo_view_earlgrey_utils.h"
 #include "ios/chrome/browser/ui/tools_menu/tools_menu_constants.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -53,6 +54,12 @@
   return ButtonWithAccessibilityLabel(@"Back");
 }
 
+// Matcher for the Back button on the bookmarks UI.
+id<GREYMatcher> BookmarksDoneButton() {
+  return grey_allOf(grey_accessibilityID(@"DONE"), grey_sufficientlyVisible(),
+                    nil);
+}
+
 // Bookmark integration tests for Chrome.
 @interface BookmarksNewGenTestCase : ChromeTestCase
 @end
@@ -160,17 +167,16 @@
   [self setTearDownHandler:^{
     [BookmarksNewGenTestCase setPromoAlreadySeen:NO];
   }];
-  // Check that promo is visible.
+  // Check that sign-in promo view is visible.
   [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
-  [[EarlGrey selectElementWithMatcher:PrimarySignInButton()]
-      assertWithMatcher:grey_sufficientlyVisible()];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
 
   // Go to child node.
   [BookmarksNewGenTestCase openMobileBookmarks];
 
   // Wait until promo is gone.
-  [[EarlGrey selectElementWithMatcher:SecondarySignInButton()]
-      assertWithMatcher:grey_notVisible()];
+  [SignPromoViewEarlgreyUtils checkSigninPromoNotVisible];
 
   // Check that the promo already seen state is not updated.
   [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
@@ -201,10 +207,10 @@
   [self setTearDownHandler:^{
     [BookmarksNewGenTestCase setPromoAlreadySeen:NO];
   }];
-  // Check that promo is visible.
+  // Check that sign-in promo view is visible.
   [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
-  [[EarlGrey selectElementWithMatcher:PrimarySignInButton()]
-      assertWithMatcher:grey_sufficientlyVisible()];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
 
   // Tap the dismiss button.
   [[EarlGrey
@@ -212,16 +218,48 @@
       performAction:grey_tap()];
 
   // Wait until promo is gone.
-  [[EarlGrey selectElementWithMatcher:SecondarySignInButton()]
-      assertWithMatcher:grey_notVisible()];
+  [SignPromoViewEarlgreyUtils checkSigninPromoNotVisible];
 
   // Check that the promo already seen state is updated.
   [BookmarksNewGenTestCase verifyPromoAlreadySeen:YES];
 }
 
-// Tests that tapping Sign in on the promo make the Sign in sheet appear and
-// the promo still appears after dismissing the Sign in sheet.
-- (void)testUIPromoSignIn {
+// Tests the tapping on the primary button of sign-in promo view in a cold
+// state makes the sign-in sheet appear, and the promo still appears after
+// dismissing the sheet.
+- (void)testSignInPromoWithColdStateUsingPrimaryButton {
+  if (IsIPadIdiom()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
+  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      bookmark_new_generation::features::kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase openBookmarks];
+
+  // Check that sign-in promo view are visible.
+  [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
+
+  // Tap the primary button.
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(PrimarySignInButton(),
+                                          grey_sufficientlyVisible(), nil)]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Cancel")]
+      performAction:grey_tap()];
+
+  // Check that the bookmarks UI reappeared and the cell is still here.
+  [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeColdState];
+}
+
+// Tests the tapping on the primary button of sign-in promo view in a warm
+// state makes the confirmaiton sheet appear, and the promo still appears after
+// dismissing the sheet.
+- (void)testSignInPromoWithWarmStateUsingPrimaryButton {
   if (IsIPadIdiom()) {
     EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
   }
@@ -234,7 +272,7 @@
 
   // Set up a fake identity.
   ChromeIdentity* identity =
-      [FakeChromeIdentity identityWithEmail:@"fakefoo@egmail.com"
+      [FakeChromeIdentity identityWithEmail:@"fakefoo@gmail.com"
                                      gaiaID:@"fakefoopassword"
                                        name:@"Fake Foo"];
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
@@ -269,6 +307,50 @@
   [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
 }
 
+// Tests the tapping on the secondary button of sign-in promo view in a warm
+// state makes the sign-in sheet appear, and the promo still appears after
+// dismissing the sheet.
+- (void)testSignInPromoWithWarmStateUsingSecondaryButton {
+  if (IsIPadIdiom()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iPad.");
+  }
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      bookmark_new_generation::features::kBookmarkNewGeneration);
+
+  [BookmarksNewGenTestCase setupStandardBookmarks];
+  [BookmarksNewGenTestCase openBookmarks];
+  // Set up a fake identity.
+  ChromeIdentity* identity =
+      [FakeChromeIdentity identityWithEmail:@"fakefoo@egmail.com"
+                                     gaiaID:@"fakefoopassword"
+                                       name:@"Fake Foo"];
+  ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
+      identity);
+
+  // Check that sign-in promo view are visible.
+  [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
+
+  // Tap the secondary button.
+  [[EarlGrey
+      selectElementWithMatcher:grey_allOf(SecondarySignInButton(),
+                                          grey_sufficientlyVisible(), nil)]
+      performAction:grey_tap()];
+
+  // Tap the CANCEL button.
+  [[EarlGrey selectElementWithMatcher:
+                 grey_buttonTitle([l10n_util::GetNSString(
+                     IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SKIP_BUTTON)
+                     uppercaseString])] performAction:grey_tap()];
+
+  // Check that the bookmarks UI reappeared and the cell is still here.
+  [BookmarksNewGenTestCase verifyPromoAlreadySeen:NO];
+  [SignPromoViewEarlgreyUtils
+      checkSigninPromoVisibleWithMode:SigninPromoViewModeWarmState];
+}
+
 #pragma mark - Helpers
 
 // Navigates to the bookmark manager UI.
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h
index 6261f2d..29a276d 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h
@@ -38,6 +38,7 @@
   void InvalidateLine(size_t line) override {}
   void OnLineSelected(size_t line) override {}
   void UpdatePopupAppearance() override;
+  void SetMatchIcon(size_t match_index, const gfx::Image& icon) override {}
   gfx::Rect GetTargetBounds() override;
   void PaintUpdatesNow() override {}
   void OnDragCanceled() override {}
diff --git a/ios/chrome/browser/ui/payments/BUILD.gn b/ios/chrome/browser/ui/payments/BUILD.gn
index 668f6efe..ce35d1d 100644
--- a/ios/chrome/browser/ui/payments/BUILD.gn
+++ b/ios/chrome/browser/ui/payments/BUILD.gn
@@ -68,6 +68,7 @@
     "//components/payments/core",
     "//components/signin/core/browser",
     "//components/strings",
+    "//components/url_formatter",
     "//ios/chrome/app/strings",
     "//ios/chrome/app/theme",
     "//ios/chrome/browser",
diff --git a/ios/chrome/browser/ui/payments/cells/page_info_item.mm b/ios/chrome/browser/ui/payments/cells/page_info_item.mm
index 2a919dd..f56a5596a 100644
--- a/ios/chrome/browser/ui/payments/cells/page_info_item.mm
+++ b/ios/chrome/browser/ui/payments/cells/page_info_item.mm
@@ -71,10 +71,10 @@
   [super configureCell:cell];
   cell.pageFaviconView.image = self.pageFavicon;
   cell.pageTitleLabel.text = self.pageTitle;
+  cell.pageHostLabel.text = self.pageHost;
+  cell.pageLockIndicatorView.image = nil;
 
   if (self.connectionSecure) {
-    cell.pageHostLabel.text = [NSString
-        stringWithFormat:@"%s://%@", url::kHttpsScheme, self.pageHost];
     NSMutableAttributedString* text = [[NSMutableAttributedString alloc]
         initWithString:cell.pageHostLabel.text];
     [text addAttribute:NSForegroundColorAttributeName
@@ -88,9 +88,6 @@
         CGSizeMake(kLockIndicatorDimension, kLockIndicatorDimension),
         ProjectionMode::kAspectFillNoClipping)
         imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
-  } else {
-    cell.pageHostLabel.text = self.pageHost;
-    cell.pageLockIndicatorView.image = nil;
   }
 
   // Invalidate the constraints so that layout can account for whether or not a
diff --git a/ios/chrome/browser/ui/payments/cells/page_info_item_unittest.mm b/ios/chrome/browser/ui/payments/cells/page_info_item_unittest.mm
index c4e4cd7..29eb222 100644
--- a/ios/chrome/browser/ui/payments/cells/page_info_item_unittest.mm
+++ b/ios/chrome/browser/ui/payments/cells/page_info_item_unittest.mm
@@ -21,7 +21,7 @@
 
   UIImage* pageFavicon = ios_internal::CollectionViewTestImage();
   NSString* pageTitle = @"The Greatest Website Ever";
-  NSString* pageHost = @"www.greatest.example.com";
+  NSString* pageHost = @"http://localhost";
   NSString* pageHostSecure = @"https://www.greatest.example.com";
 
   item.pageFavicon = pageFavicon;
@@ -44,6 +44,7 @@
   EXPECT_NSEQ(pageFavicon, pageInfoCell.pageFaviconView.image);
   EXPECT_FALSE(pageInfoCell.pageLockIndicatorView.image);
 
+  item.pageHost = pageHostSecure;
   item.connectionSecure = true;
 
   id cell2 = [[[item cellClass] alloc] init];
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
index 3569c9df..b9a3d61b 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -37,6 +37,7 @@
 #include "components/payments/core/payment_request_data_util.h"
 #include "components/payments/core/payment_shipping_option.h"
 #include "components/prefs/pref_service.h"
+#include "components/url_formatter/elide_url.h"
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/autofill/validation_rules_storage_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
@@ -68,7 +69,6 @@
 #include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
 #include "third_party/libaddressinput/chromium/chrome_storage_impl.h"
 #include "url/gurl.h"
-#include "url/origin.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -557,7 +557,8 @@
     pageFavicon = navigationItem->GetFavicon().image.ToUIImage();
   NSString* pageTitle = base::SysUTF16ToNSString(_activeWebState->GetTitle());
   NSString* pageHost =
-      base::SysUTF8ToNSString(_activeWebState->GetLastCommittedURL().host());
+      base::SysUTF16ToNSString(url_formatter::FormatUrlForSecurityDisplay(
+          _activeWebState->GetLastCommittedURL()));
   BOOL connectionSecure =
       _activeWebState->GetLastCommittedURL().SchemeIs(url::kHttpsScheme);
   autofill::AutofillManager* autofillManager =
@@ -650,8 +651,10 @@
   DCHECK(canMakePaymentQuery);
   // iOS PaymentRequest does not support iframes.
   if (canMakePaymentQuery->CanQuery(
-          url::Origin(_activeWebState->GetLastCommittedURL().GetOrigin()),
-          url::Origin(_activeWebState->GetLastCommittedURL().GetOrigin()),
+          GURL(url_formatter::FormatUrlForSecurityDisplay(
+              _activeWebState->GetLastCommittedURL())),
+          GURL(url_formatter::FormatUrlForSecurityDisplay(
+              _activeWebState->GetLastCommittedURL())),
           paymentRequest->stringified_method_data())) {
     [_paymentRequestJsManager
         resolveCanMakePaymentPromiseWithValue:canMakePayment
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index fb51e209..aeca277e 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -152,6 +152,7 @@
     "//ios/chrome/browser/ui/settings/utils",
     "//ios/chrome/browser/ui/sync",
     "//ios/chrome/browser/voice",
+    "//ios/chrome/browser/web:features",
     "//ios/chrome/browser/web:web",
     "//ios/chrome/common",
     "//ios/public/provider/chrome/browser",
@@ -291,6 +292,7 @@
     "//ios/chrome/browser/ui/sync",
     "//ios/chrome/browser/voice",
     "//ios/chrome/browser/web",
+    "//ios/chrome/browser/web:features",
     "//ios/chrome/browser/web:test_support",
     "//ios/chrome/common",
     "//ios/chrome/test:test_support",
diff --git a/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller_unittest.mm
index 4105ea7..991c4583 100644
--- a/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/compose_email_handler_collection_view_controller_unittest.mm
@@ -7,8 +7,10 @@
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h"
 #import "ios/chrome/browser/web/fake_mailto_handler_helpers.h"
+#include "ios/chrome/browser/web/features.h"
 #import "ios/chrome/browser/web/legacy_mailto_url_rewriter.h"
 #import "ios/chrome/browser/web/mailto_handler_system_mail.h"
+#import "ios/chrome/browser/web/nullable_mailto_url_rewriter.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MDCPalettes.h"
 #include "testing/gtest_mac.h"
@@ -26,10 +28,13 @@
  protected:
   // Before CreateController() is called, set |handers_| and optionally
   // |defaultHandlerID_| ivars. They will be used to seed the construction of
-  // the LegacyMailtoURLRewriter which in turn used for the construction of the
+  // a MailtoURLRewriter which in turn used for the construction of the
   // CollectionViewController.
   CollectionViewController* InstantiateController() override {
-    rewriter_ = [[LegacyMailtoURLRewriter alloc] init];
+    rewriter_ =
+        base::FeatureList::IsEnabled(kMailtoPromptForUserChoice)
+            ? [NullableMailtoURLRewriter mailtoURLRewriterWithStandardHandlers]
+            : [[LegacyMailtoURLRewriter alloc] init];
     [rewriter_ setDefaultHandlers:handlers_];
     if (defaultHandlerID_)
       [rewriter_ setDefaultHandlerID:defaultHandlerID_];
diff --git a/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.mm
index a8a6eef..cff81ec 100644
--- a/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/content_settings_collection_view_controller.mm
@@ -25,6 +25,7 @@
 #import "ios/chrome/browser/ui/settings/utils/content_setting_backed_boolean.h"
 #include "ios/chrome/browser/web/features.h"
 #import "ios/chrome/browser/web/legacy_mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/nullable_mailto_url_rewriter.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
@@ -108,7 +109,9 @@
     [_disablePopupsSetting setObserver:self];
 
     _mailtoURLRewriter =
-        [LegacyMailtoURLRewriter mailtoURLRewriterWithStandardHandlers];
+        base::FeatureList::IsEnabled(kMailtoPromptForUserChoice)
+            ? [NullableMailtoURLRewriter mailtoURLRewriterWithStandardHandlers]
+            : [LegacyMailtoURLRewriter mailtoURLRewriterWithStandardHandlers];
     [_mailtoURLRewriter setObserver:self];
 
     [self loadModel];
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index f8e28f1..e487417 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -9,8 +9,6 @@
   sources = [
     "dom_altering_lock.h",
     "dom_altering_lock.mm",
-    "features.h",
-    "features.mm",
     "legacy_mailto_url_rewriter.h",
     "legacy_mailto_url_rewriter.mm",
     "mailto_handler.h",
@@ -37,6 +35,7 @@
     "tab_id_tab_helper.mm",
   ]
   deps = [
+    ":features",
     ":tab_helper_delegates",
     "//base",
     "//components/strings",
@@ -52,6 +51,16 @@
   ]
 }
 
+source_set("features") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "features.h",
+    "features.mm",
+  ]
+  deps = [
+    "//base",
+  ]
+}
 source_set("tab_helper_delegates") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
@@ -143,6 +152,7 @@
   ]
   deps = [
     ":chrome_bundle",
+    ":features",
     "//base",
     "//components/content_settings/core/browser",
     "//components/dom_distiller/core",
diff --git a/ios/chrome/browser/web/external_app_launcher.mm b/ios/chrome/browser/web/external_app_launcher.mm
index ecc8c4f..b86c4837 100644
--- a/ios/chrome/browser/web/external_app_launcher.mm
+++ b/ios/chrome/browser/web/external_app_launcher.mm
@@ -14,7 +14,9 @@
 #import "ios/chrome/browser/open_url_util.h"
 #include "ios/chrome/browser/web/features.h"
 #import "ios/chrome/browser/web/legacy_mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/mailto_handler.h"
 #import "ios/chrome/browser/web/mailto_url_rewriter.h"
+#import "ios/chrome/browser/web/nullable_mailto_url_rewriter.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -71,11 +73,24 @@
   return @"";
 }
 
+// Launches the mail client app chosen by |rewriter| and records metrics.
+void LaunchMailClientApp(const GURL& URL, MailtoURLRewriter* rewriter) {
+  NSString* launchURL = [rewriter rewriteMailtoURL:URL];
+  UMA_HISTOGRAM_BOOLEAN("IOS.MailtoURLRewritten", launchURL != nil);
+  NSURL* URLToOpen = [launchURL length] ? [NSURL URLWithString:launchURL]
+                                        : net::NSURLWithGURL(URL);
+  [[UIApplication sharedApplication] openURL:URLToOpen];
+}
+
 }  // namespace
 
 @interface ExternalAppLauncher ()
 // Returns the Phone/FaceTime call argument from |URL|.
 + (NSString*)formatCallArgument:(NSURL*)URL;
+// Shows a prompt for the user to choose which mail client app to use to
+// handle a mailto:// URL.
+- (void)promptForMailClientWithURL:(const GURL)URL
+                       URLRewriter:(MailtoURLRewriter*)rewriter;
 // Presents an alert controller with |prompt| and |openLabel| as button label
 // on the root view controller before launching an external app identified by
 // |URL|.
@@ -102,6 +117,35 @@
   return prompt;
 }
 
+- (void)promptForMailClientWithURL:(const GURL)URL
+                       URLRewriter:(MailtoURLRewriter*)rewriter {
+  // No user chosen default. Prompt user now.
+  NSString* prompt = l10n_util::GetNSString(IDS_IOS_CHOOSE_EMAIL_CLIENT_APP);
+  UIAlertController* alertController = [UIAlertController
+      alertControllerWithTitle:nil
+                       message:prompt
+                preferredStyle:UIAlertControllerStyleActionSheet];
+  // There must be more than one available handlers to present a prompt to user.
+  DCHECK([[rewriter defaultHandlers] count] > 1U);
+  for (MailtoHandler* handler in [rewriter defaultHandlers]) {
+    if (![handler isAvailable])
+      continue;
+    UIAlertAction* action = [UIAlertAction
+        actionWithTitle:[handler appName]
+                  style:UIAlertActionStyleDefault
+                handler:^(UIAlertAction* _Nonnull action) {
+                  DCHECK(handler);
+                  [rewriter setDefaultHandlerID:[handler appStoreID]];
+                  LaunchMailClientApp(URL, rewriter);
+                }];
+    [alertController addAction:action];
+  }
+  [[[[UIApplication sharedApplication] keyWindow] rootViewController]
+      presentViewController:alertController
+                   animated:YES
+                 completion:nil];
+}
+
 - (void)openExternalAppWithURL:(NSURL*)URL
                         prompt:(NSString*)prompt
                      openLabel:(NSString*)openLabel {
@@ -176,11 +220,15 @@
   if (base::FeatureList::IsEnabled(kMailtoUrlRewriting) &&
       gURL.SchemeIs(url::kMailToScheme)) {
     MailtoURLRewriter* rewriter =
-        [LegacyMailtoURLRewriter mailtoURLRewriterWithStandardHandlers];
-    NSString* launchURL = [rewriter rewriteMailtoURL:gURL];
-    if (launchURL)
-      URL = [NSURL URLWithString:launchURL];
-    UMA_HISTOGRAM_BOOLEAN("IOS.MailtoURLRewritten", launchURL != nil);
+        base::FeatureList::IsEnabled(kMailtoPromptForUserChoice)
+            ? [NullableMailtoURLRewriter mailtoURLRewriterWithStandardHandlers]
+            : [LegacyMailtoURLRewriter mailtoURLRewriterWithStandardHandlers];
+    if (![rewriter defaultHandlerID]) {
+      [self promptForMailClientWithURL:gURL URLRewriter:rewriter];
+      return YES;
+    }
+    LaunchMailClientApp(gURL, rewriter);
+    return YES;
   }
 
   // If the following call returns YES, an external application is about to be
diff --git a/ios/chrome/browser/web/features.h b/ios/chrome/browser/web/features.h
index b2589b64..0ba4a39 100644
--- a/ios/chrome/browser/web/features.h
+++ b/ios/chrome/browser/web/features.h
@@ -11,4 +11,9 @@
 // of user's choice.
 extern const base::Feature kMailtoUrlRewriting;
 
+// Feature flag to prompt user to choose a mail client app. User is prompted
+// at the first time that the user taps on a mailto: URL. This feature can be
+// enabled only when kMailtoUrlRewriting is also enabled.
+extern const base::Feature kMailtoPromptForUserChoice;
+
 #endif  // IOS_CHROME_BROWSER_WEB_FEATURES_H_
diff --git a/ios/chrome/browser/web/features.mm b/ios/chrome/browser/web/features.mm
index b1362e2..778d3d5 100644
--- a/ios/chrome/browser/web/features.mm
+++ b/ios/chrome/browser/web/features.mm
@@ -8,3 +8,8 @@
 // Change the default value here to enable or disable this feature.
 const base::Feature kMailtoUrlRewriting{"MailtoUrlRewriting",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Feature flag to prompt user to choose a mail client app. Change the default
+// value here to enable or disable this feature.
+const base::Feature kMailtoPromptForUserChoice{
+    "MailtoPromptForUserChoice", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/net/cookies/cookie_store_ios.h b/ios/net/cookies/cookie_store_ios.h
index 3877586..25a5173 100644
--- a/ios/net/cookies/cookie_store_ios.h
+++ b/ios/net/cookies/cookie_store_ios.h
@@ -123,6 +123,9 @@
       const std::string& name,
       const CookieChangedCallback& callback) override;
 
+  std::unique_ptr<CookieChangedSubscription> AddCallbackForAllChanges(
+      const CookieChangedCallback& callback) override;
+
   bool IsEphemeral() override;
 
  protected:
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index 87baca6b..c1880af 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -743,6 +743,14 @@
   return hook_map_[key]->Add(callback);
 }
 
+std::unique_ptr<net::CookieStore::CookieChangedSubscription>
+CookieStoreIOS::AddCallbackForAllChanges(
+    const CookieChangedCallback& callback) {
+  // Implement when needed by iOS consumers.
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
 bool CookieStoreIOS::IsEphemeral() {
   return cookie_monster_->IsEphemeral();
 }
diff --git a/ios/net/cookies/cookie_store_ios_persistent_unittest.mm b/ios/net/cookies/cookie_store_ios_persistent_unittest.mm
index 86736e0..9c60679 100644
--- a/ios/net/cookies/cookie_store_ios_persistent_unittest.mm
+++ b/ios/net/cookies/cookie_store_ios_persistent_unittest.mm
@@ -35,6 +35,7 @@
   static const bool filters_schemes = false;
   static const bool has_path_prefix_bug = false;
   static const bool forbids_setting_empty_name = false;
+  static const bool supports_global_cookie_tracking = false;
   static const int creation_time_granularity_in_ms = 0;
   static const int enforces_prefixes = true;
   static const bool enforce_strict_secure = false;
diff --git a/ios/net/cookies/cookie_store_ios_unittest.mm b/ios/net/cookies/cookie_store_ios_unittest.mm
index 45df02d..3be15bee 100644
--- a/ios/net/cookies/cookie_store_ios_unittest.mm
+++ b/ios/net/cookies/cookie_store_ios_unittest.mm
@@ -38,6 +38,7 @@
   static const bool filters_schemes = false;
   static const bool has_path_prefix_bug = true;
   static const bool forbids_setting_empty_name = true;
+  static const bool supports_global_cookie_tracking = false;
   static const int creation_time_granularity_in_ms = 1000;
 
   base::MessageLoop loop_;
diff --git a/media/audio/cras/audio_manager_cras.cc b/media/audio/cras/audio_manager_cras.cc
index 633d7ee9..156d348b 100644
--- a/media/audio/cras/audio_manager_cras.cc
+++ b/media/audio/cras/audio_manager_cras.cc
@@ -13,8 +13,6 @@
 #include "base/command_line.h"
 #include "base/environment.h"
 #include "base/logging.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/nix/xdg_util.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -46,13 +44,12 @@
 // Default input buffer size.
 const int kDefaultInputBufferSize = 1024;
 
-const char kBeamformingOnDeviceId[] = "default-beamforming-on";
-const char kBeamformingOffDeviceId[] = "default-beamforming-off";
-
 const char kInternalInputVirtualDevice[] = "Built-in mic";
 const char kInternalOutputVirtualDevice[] = "Built-in speaker";
 const char kHeadphoneLineOutVirtualDevice[] = "Headphone/Line Out";
 
+// Used for the Media.CrosBeamformingDeviceState histogram, currently not used
+// since beamforming is disabled.
 enum CrosBeamformingDeviceState {
   BEAMFORMING_DEFAULT_ENABLED = 0,
   BEAMFORMING_USER_ENABLED,
@@ -61,32 +58,6 @@
   BEAMFORMING_STATE_MAX = BEAMFORMING_USER_DISABLED
 };
 
-void RecordBeamformingDeviceState(CrosBeamformingDeviceState state) {
-  UMA_HISTOGRAM_ENUMERATION("Media.CrosBeamformingDeviceState", state,
-                            BEAMFORMING_STATE_MAX + 1);
-}
-
-bool IsBeamformingDefaultEnabled() {
-  return base::FieldTrialList::FindFullName("ChromebookBeamforming") ==
-         "Enabled";
-}
-
-// Returns a mic positions string if the machine has a beamforming capable
-// internal mic and otherwise an empty string.
-std::string MicPositions() {
-  // Get the list of devices from CRAS. An internal mic with a non-empty
-  // positions field indicates the machine has a beamforming capable mic array.
-  chromeos::AudioDeviceList devices;
-  chromeos::CrasAudioHandler::Get()->GetAudioDevices(&devices);
-  for (const auto& device : devices) {
-    if (device.type == chromeos::AUDIO_TYPE_INTERNAL_MIC) {
-      // There should be only one internal mic device.
-      return device.mic_positions;
-    }
-  }
-  return "";
-}
-
 // Process |device_list| that two shares the same dev_index by creating a
 // virtual device name for them.
 void ProcessVirtualDeviceName(AudioDeviceNames* device_names,
@@ -110,37 +81,6 @@
 
 }  // namespace
 
-// Adds the beamforming on and off devices to |device_names|.
-void AudioManagerCras::AddBeamformingDevices(AudioDeviceNames* device_names) {
-  DCHECK(device_names->empty());
-  const std::string beamforming_on_name =
-      GetLocalizedStringUTF8(BEAMFORMING_ON_DEFAULT_AUDIO_INPUT_DEVICE_NAME);
-  const std::string beamforming_off_name =
-      GetLocalizedStringUTF8(BEAMFORMING_OFF_DEFAULT_AUDIO_INPUT_DEVICE_NAME);
-
-  if (IsBeamformingDefaultEnabled()) {
-    // The first device in the list is expected to have a "default" device ID.
-    // Web apps may depend on this behavior.
-    beamforming_on_device_id_ = AudioDeviceDescription::kDefaultDeviceId;
-    beamforming_off_device_id_ = kBeamformingOffDeviceId;
-
-    // Users in the experiment will have the "beamforming on" device appear
-    // first in the list. This causes it to be selected by default.
-    device_names->push_back(
-        AudioDeviceName(beamforming_on_name, beamforming_on_device_id_));
-    device_names->push_back(
-        AudioDeviceName(beamforming_off_name, beamforming_off_device_id_));
-  } else {
-    beamforming_off_device_id_ = AudioDeviceDescription::kDefaultDeviceId;
-    beamforming_on_device_id_ = kBeamformingOnDeviceId;
-
-    device_names->push_back(
-        AudioDeviceName(beamforming_off_name, beamforming_off_device_id_));
-    device_names->push_back(
-        AudioDeviceName(beamforming_on_name, beamforming_on_device_id_));
-  }
-}
-
 bool AudioManagerCras::HasAudioOutputDevices() {
   return true;
 }
@@ -157,9 +97,7 @@
 
 AudioManagerCras::AudioManagerCras(std::unique_ptr<AudioThread> audio_thread,
                                    AudioLogFactory* audio_log_factory)
-    : AudioManagerBase(std::move(audio_thread), audio_log_factory),
-      beamforming_on_device_id_(nullptr),
-      beamforming_off_device_id_(nullptr) {
+    : AudioManagerBase(std::move(audio_thread), audio_log_factory) {
   SetMaxOutputStreamsAllowed(kMaxOutputStreams);
 }
 
@@ -168,13 +106,8 @@
 void AudioManagerCras::GetAudioDeviceNamesImpl(bool is_input,
                                                AudioDeviceNames* device_names) {
   DCHECK(device_names->empty());
-  // At least two mic positions indicates we have a beamforming capable mic
-  // array. Add the virtual beamforming device to the list. When this device is
-  // queried through GetInputStreamParameters, provide the cached mic positions.
-  if (is_input && mic_positions_.size() > 1)
-    AddBeamformingDevices(device_names);
-  else
-    device_names->push_back(AudioDeviceName::CreateDefault());
+
+  device_names->push_back(AudioDeviceName::CreateDefault());
 
   if (base::FeatureList::IsEnabled(features::kEnumerateAudioDevices)) {
     chromeos::AudioDeviceList devices;
@@ -205,7 +138,6 @@
 
 void AudioManagerCras::GetAudioInputDeviceNames(
     AudioDeviceNames* device_names) {
-  mic_positions_ = ParsePointsFromString(MicPositions());
   GetAudioDeviceNamesImpl(true, device_names);
 }
 
@@ -230,31 +162,6 @@
   if (chromeos::CrasAudioHandler::Get()->HasKeyboardMic())
     params.set_effects(AudioParameters::KEYBOARD_MIC);
 
-  if (mic_positions_.size() > 1) {
-    // We have the mic_positions_ check here because one of the beamforming
-    // devices will have been assigned the "default" ID, which could otherwise
-    // be confused with the ID in the non-beamforming-capable-device case.
-    DCHECK(beamforming_on_device_id_);
-    DCHECK(beamforming_off_device_id_);
-
-    if (device_id == beamforming_on_device_id_) {
-      params.set_mic_positions(mic_positions_);
-
-      // Record a UMA metric based on the state of the experiment and the
-      // selected device. This will tell us i) how common it is for users to
-      // manually adjust the beamforming device and ii) how contaminated our
-      // metric experiment buckets are.
-      if (IsBeamformingDefaultEnabled())
-        RecordBeamformingDeviceState(BEAMFORMING_DEFAULT_ENABLED);
-      else
-        RecordBeamformingDeviceState(BEAMFORMING_USER_ENABLED);
-    } else if (device_id == beamforming_off_device_id_) {
-      if (!IsBeamformingDefaultEnabled())
-        RecordBeamformingDeviceState(BEAMFORMING_DEFAULT_DISABLED);
-      else
-        RecordBeamformingDeviceState(BEAMFORMING_USER_DISABLED);
-    }
-  }
   return params;
 }
 
@@ -267,17 +174,6 @@
   chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get();
   audio_handler->GetAudioDevices(&devices);
 
-  if ((beamforming_on_device_id_ &&
-       input_device_id == beamforming_on_device_id_) ||
-      (beamforming_off_device_id_ &&
-       input_device_id == beamforming_off_device_id_)) {
-    // These are special devices derived from the internal mic array, so they
-    // should be associated to the internal speaker.
-    const chromeos::AudioDevice* internal_speaker =
-        audio_handler->GetDeviceByType(chromeos::AUDIO_TYPE_INTERNAL_SPEAKER);
-    return internal_speaker ? base::Uint64ToString(internal_speaker->id) : "";
-  }
-
   // At this point, we know we have an ordinary input device, so we look up its
   // device_name, which identifies which hardware device it belongs to.
   uint64_t device_id = 0;
diff --git a/media/audio/cras/audio_manager_cras.h b/media/audio/cras/audio_manager_cras.h
index 391c95a..f80900d6 100644
--- a/media/audio/cras/audio_manager_cras.h
+++ b/media/audio/cras/audio_manager_cras.h
@@ -78,14 +78,6 @@
 
   void GetAudioDeviceNamesImpl(bool is_input, AudioDeviceNames* device_names);
 
-  void AddBeamformingDevices(AudioDeviceNames* device_names);
-
-  // Stores the mic positions field from the device.
-  std::vector<Point> mic_positions_;
-
-  const char* beamforming_on_device_id_;
-  const char* beamforming_off_device_id_;
-
   DISALLOW_COPY_AND_ASSIGN(AudioManagerCras);
 };
 
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 33512fb..613e830 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -14,6 +14,8 @@
 
   flags = [
     "USE_VAAPI=$use_vaapi",
+    "USE_V4L2_CODEC=$use_v4l2_codec",
+    "USE_LIBV4L2=$use_v4lplugin",
     "ENABLE_MEDIA_CODEC_VIDEO_DECODER=$enable_media_codec_video_decoder",
   ]
 }
@@ -100,16 +102,6 @@
   }
 }
 
-config("gpu_config") {
-  defines = []
-  if (is_chromeos && use_v4lplugin) {
-    defines += [ "USE_LIBV4L2" ]
-  }
-  if (is_chromeos && use_v4l2_codec) {
-    defines += [ "USE_V4L2_CODEC" ]
-  }
-}
-
 component("gpu") {
   output_name = "media_gpu"
 
@@ -172,8 +164,6 @@
   libs = []
   ldflags = []
 
-  configs += [ ":gpu_config" ]
-
   if (is_mac) {
     sources += [
       "vt_video_decode_accelerator_mac.cc",
@@ -256,7 +246,7 @@
     }
   }
 
-  if (is_chromeos) {
+  if (use_v4l2_codec || use_vaapi) {
     sources += [
       "vp8_decoder.cc",
       "vp8_decoder.h",
@@ -267,41 +257,43 @@
       "vp9_picture.cc",
       "vp9_picture.h",
     ]
-    if (use_v4lplugin) {
-      sources += get_target_outputs(":libv4l2_generate_stubs")
-      deps += [ ":libv4l2_generate_stubs" ]
-    }
-    if (use_v4l2_codec) {
-      deps += [
-        "//third_party/libyuv",
-        "//ui/ozone",
-      ]
+  }
+
+  if (use_v4lplugin) {
+    sources += get_target_outputs(":libv4l2_generate_stubs")
+    deps += [ ":libv4l2_generate_stubs" ]
+  }
+
+  if (use_v4l2_codec) {
+    deps += [
+      "//third_party/libyuv",
+      "//ui/ozone",
+    ]
+    sources += [
+      "generic_v4l2_device.cc",
+      "generic_v4l2_device.h",
+      "v4l2_device.cc",
+      "v4l2_device.h",
+      "v4l2_image_processor.cc",
+      "v4l2_image_processor.h",
+      "v4l2_jpeg_decode_accelerator.cc",
+      "v4l2_jpeg_decode_accelerator.h",
+      "v4l2_slice_video_decode_accelerator.cc",
+      "v4l2_slice_video_decode_accelerator.h",
+      "v4l2_video_decode_accelerator.cc",
+      "v4l2_video_decode_accelerator.h",
+      "v4l2_video_encode_accelerator.cc",
+      "v4l2_video_encode_accelerator.h",
+    ]
+    libs = [
+      "EGL",
+      "GLESv2",
+    ]
+    if (current_cpu == "arm") {
       sources += [
-        "generic_v4l2_device.cc",
-        "generic_v4l2_device.h",
-        "v4l2_device.cc",
-        "v4l2_device.h",
-        "v4l2_image_processor.cc",
-        "v4l2_image_processor.h",
-        "v4l2_jpeg_decode_accelerator.cc",
-        "v4l2_jpeg_decode_accelerator.h",
-        "v4l2_slice_video_decode_accelerator.cc",
-        "v4l2_slice_video_decode_accelerator.h",
-        "v4l2_video_decode_accelerator.cc",
-        "v4l2_video_decode_accelerator.h",
-        "v4l2_video_encode_accelerator.cc",
-        "v4l2_video_encode_accelerator.h",
+        "tegra_v4l2_device.cc",
+        "tegra_v4l2_device.h",
       ]
-      libs = [
-        "EGL",
-        "GLESv2",
-      ]
-      if (current_cpu == "arm") {
-        sources += [
-          "tegra_v4l2_device.cc",
-          "tegra_v4l2_device.h",
-        ]
-      }
     }
   }
 
@@ -414,10 +406,7 @@
       "//ui/gl/init",
     ]
 
-    configs += [
-      "//third_party/khronos:khronos_headers",
-      ":gpu_config",
-    ]
+    configs += [ "//third_party/khronos:khronos_headers" ]
 
     if (is_win || is_chromeos) {
       sources += [
@@ -514,10 +503,7 @@
       "//ui/gl",
       "//ui/gl:test_support",
     ]
-    configs += [
-      "//third_party/libyuv:libyuv_config",
-      ":gpu_config",
-    ]
+    configs += [ "//third_party/libyuv:libyuv_config" ]
     sources = [
       "video_accelerator_unittest_helpers.h",
       "video_encode_accelerator_unittest.cc",
@@ -547,10 +533,7 @@
       "//ui/gl",
       "//ui/gl:test_support",
     ]
-    configs += [
-      "//third_party/libyuv:libyuv_config",
-      ":gpu_config",
-    ]
+    configs += [ "//third_party/libyuv:libyuv_config" ]
     sources = [
       "jpeg_decode_accelerator_unittest.cc",
       "video_accelerator_unittest_helpers.h",
diff --git a/media/gpu/generic_v4l2_device.cc b/media/gpu/generic_v4l2_device.cc
index b536e74..8804394 100644
--- a/media/gpu/generic_v4l2_device.cc
+++ b/media/gpu/generic_v4l2_device.cc
@@ -24,6 +24,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "media/gpu/features.h"
 #include "media/gpu/generic_v4l2_device.h"
 #include "ui/gfx/native_pixmap.h"
 #include "ui/gl/egl_util.h"
@@ -32,7 +33,7 @@
 #include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 
-#if defined(USE_LIBV4L2)
+#if BUILDFLAG(USE_LIBV4L2)
 // Auto-generated for dlopen libv4l2 libraries
 #include "media/gpu/v4l2/v4l2_stubs.h"
 #include "third_party/v4l-utils/lib/include/libv4l2.h"
@@ -48,7 +49,7 @@
 namespace media {
 
 GenericV4L2Device::GenericV4L2Device() {
-#if defined(USE_LIBV4L2)
+#if BUILDFLAG(USE_LIBV4L2)
   use_libv4l2_ = false;
 #endif
 }
@@ -59,7 +60,7 @@
 
 int GenericV4L2Device::Ioctl(int request, void* arg) {
   DCHECK(device_fd_.is_valid());
-#if defined(USE_LIBV4L2)
+#if BUILDFLAG(USE_LIBV4L2)
   if (use_libv4l2_)
     return HANDLE_EINTR(v4l2_ioctl(device_fd_.get(), request, arg));
 #endif
@@ -463,7 +464,7 @@
   if (!device_fd_.is_valid())
     return false;
 
-#if defined(USE_LIBV4L2)
+#if BUILDFLAG(USE_LIBV4L2)
   if (type == Type::kEncoder &&
       HANDLE_EINTR(v4l2_fd_open(device_fd_.get(), V4L2_DISABLE_CONVERSION)) !=
           -1) {
@@ -475,7 +476,7 @@
 }
 
 void GenericV4L2Device::CloseDevice() {
-#if defined(USE_LIBV4L2)
+#if BUILDFLAG(USE_LIBV4L2)
   if (use_libv4l2_ && device_fd_.is_valid())
     v4l2_close(device_fd_.release());
 #endif
@@ -484,7 +485,7 @@
 
 // static
 bool GenericV4L2Device::PostSandboxInitialization() {
-#if defined(USE_LIBV4L2)
+#if BUILDFLAG(USE_LIBV4L2)
   StubPathMap paths;
   paths[kModuleV4l2].push_back(kV4l2Lib);
 
diff --git a/media/gpu/generic_v4l2_device.h b/media/gpu/generic_v4l2_device.h
index 8ef07b6..91847c7 100644
--- a/media/gpu/generic_v4l2_device.h
+++ b/media/gpu/generic_v4l2_device.h
@@ -15,6 +15,7 @@
 
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
+#include "media/gpu/features.h"
 #include "media/gpu/v4l2_device.h"
 
 namespace media {
@@ -114,7 +115,7 @@
   // interrupted.
   base::ScopedFD device_poll_interrupt_fd_;
 
-#if USE_LIBV4L2
+#if BUILDFLAG(USE_LIBV4L2)
   // Use libv4l2 when operating |device_fd_|.
   bool use_libv4l2_;
 #endif
diff --git a/media/gpu/gpu_video_decode_accelerator_factory.cc b/media/gpu/gpu_video_decode_accelerator_factory.cc
index 25c4b314..22f8f4a 100644
--- a/media/gpu/gpu_video_decode_accelerator_factory.cc
+++ b/media/gpu/gpu_video_decode_accelerator_factory.cc
@@ -16,16 +16,17 @@
 #include "base/win/windows_version.h"
 #include "media/gpu/d3d11_video_decode_accelerator_win.h"
 #include "media/gpu/dxva_video_decode_accelerator_win.h"
-#elif defined(OS_MACOSX)
+#endif
+#if defined(OS_MACOSX)
 #include "media/gpu/vt_video_decode_accelerator_mac.h"
-#elif defined(OS_CHROMEOS)
-#if defined(USE_V4L2_CODEC)
+#endif
+#if BUILDFLAG(USE_V4L2_CODEC)
 #include "media/gpu/v4l2_device.h"
 #include "media/gpu/v4l2_slice_video_decode_accelerator.h"
 #include "media/gpu/v4l2_video_decode_accelerator.h"
 #include "ui/gl/gl_surface_egl.h"
 #endif
-#elif defined(OS_ANDROID)
+#if defined(OS_ANDROID)
 #include "media/gpu/android/device_info.h"
 #include "media/gpu/android_video_decode_accelerator.h"
 #include "media/gpu/android_video_surface_chooser_impl.h"
@@ -89,9 +90,9 @@
   capabilities.supported_profiles =
       DXVAVideoDecodeAccelerator::GetSupportedProfiles(gpu_preferences,
                                                        workarounds);
-#elif defined(OS_CHROMEOS) || BUILDFLAG(USE_VAAPI)
+#elif BUILDFLAG(USE_V4L2_CODEC) || BUILDFLAG(USE_VAAPI)
   VideoDecodeAccelerator::SupportedProfiles vda_profiles;
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_V4L2_CODEC)
   vda_profiles = V4L2VideoDecodeAccelerator::GetSupportedProfiles();
   GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(
       vda_profiles, &capabilities.supported_profiles);
@@ -138,7 +139,7 @@
     &GpuVideoDecodeAcceleratorFactory::CreateD3D11VDA,
     &GpuVideoDecodeAcceleratorFactory::CreateDXVAVDA,
 #endif
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_V4L2_CODEC)
     &GpuVideoDecodeAcceleratorFactory::CreateV4L2VDA,
     &GpuVideoDecodeAcceleratorFactory::CreateV4L2SVDA,
 #endif
@@ -193,7 +194,7 @@
 }
 #endif
 
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_V4L2_CODEC)
 std::unique_ptr<VideoDecodeAccelerator>
 GpuVideoDecodeAcceleratorFactory::CreateV4L2VDA(
     const gpu::GpuDriverBugWorkarounds& workarounds,
diff --git a/media/gpu/gpu_video_decode_accelerator_factory.h b/media/gpu/gpu_video_decode_accelerator_factory.h
index 819569bf..b089f6a 100644
--- a/media/gpu/gpu_video_decode_accelerator_factory.h
+++ b/media/gpu/gpu_video_decode_accelerator_factory.h
@@ -98,7 +98,7 @@
       const gpu::GpuDriverBugWorkarounds& workarounds,
       const gpu::GpuPreferences& gpu_preferences) const;
 #endif
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_V4L2_CODEC)
   std::unique_ptr<VideoDecodeAccelerator> CreateV4L2VDA(
       const gpu::GpuDriverBugWorkarounds& workarounds,
       const gpu::GpuPreferences& gpu_preferences) const;
diff --git a/media/gpu/gpu_video_encode_accelerator_factory.cc b/media/gpu/gpu_video_encode_accelerator_factory.cc
index d1b8ff3..2f8cd980 100644
--- a/media/gpu/gpu_video_encode_accelerator_factory.cc
+++ b/media/gpu/gpu_video_encode_accelerator_factory.cc
@@ -9,15 +9,16 @@
 #include "media/gpu/features.h"
 #include "media/gpu/gpu_video_accelerator_util.h"
 
-#if defined(OS_CHROMEOS)
-#if defined(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_V4L2_CODEC)
 #include "media/gpu/v4l2_video_encode_accelerator.h"
 #endif
-#elif defined(OS_ANDROID) && BUILDFLAG(ENABLE_WEBRTC)
+#if defined(OS_ANDROID) && BUILDFLAG(ENABLE_WEBRTC)
 #include "media/gpu/android_video_encode_accelerator.h"
-#elif defined(OS_MACOSX)
+#endif
+#if defined(OS_MACOSX)
 #include "media/gpu/vt_video_encode_accelerator_mac.h"
-#elif defined(OS_WIN)
+#endif
+#if defined(OS_WIN)
 #include "base/feature_list.h"
 #include "media/base/media_switches.h"
 #include "media/gpu/media_foundation_video_encode_accelerator_win.h"
@@ -29,7 +30,7 @@
 namespace media {
 
 namespace {
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_V4L2_CODEC)
 std::unique_ptr<VideoEncodeAccelerator> CreateV4L2VEA() {
   auto device = V4L2Device::Create();
   if (device)
@@ -75,7 +76,7 @@
   // platform. This list is ordered by priority, from most to least preferred,
   // if applicable.
   std::vector<VEAFactoryFunction> vea_factory_functions;
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
+#if BUILDFLAG(USE_V4L2_CODEC)
   vea_factory_functions.push_back(&CreateV4L2VEA);
 #endif
 #if BUILDFLAG(USE_VAAPI)
diff --git a/media/gpu/ipc/client/BUILD.gn b/media/gpu/ipc/client/BUILD.gn
index 2499e6f..78a1240 100644
--- a/media/gpu/ipc/client/BUILD.gn
+++ b/media/gpu/ipc/client/BUILD.gn
@@ -12,10 +12,7 @@
     "gpu_video_encode_accelerator_host.h",
   ]
 
-  configs += [
-    "//build/config/compiler:no_size_t_to_int_warning",
-    "//media/gpu:gpu_config",
-  ]
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
   deps = [
     "//base",
diff --git a/media/gpu/ipc/service/BUILD.gn b/media/gpu/ipc/service/BUILD.gn
index edfb314..c68e3a1 100644
--- a/media/gpu/ipc/service/BUILD.gn
+++ b/media/gpu/ipc/service/BUILD.gn
@@ -42,14 +42,13 @@
   deps = [
     "//gpu/ipc/service",
     "//media:media_features",
+    "//media/gpu:features",
     "//media/gpu/ipc/common",
     "//media/gpu/mojo:jpeg_decoder",
     "//third_party/mesa:mesa_headers",
     "//ui/gfx/ipc/color",
   ]
 
-  configs += [ "//media/gpu:gpu_config" ]
-
   if (is_win) {
     configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
   }
diff --git a/media/gpu/ipc/service/gpu_jpeg_decode_accelerator_factory_provider.cc b/media/gpu/ipc/service/gpu_jpeg_decode_accelerator_factory_provider.cc
index f95f6d5..3b3cfd6a 100644
--- a/media/gpu/ipc/service/gpu_jpeg_decode_accelerator_factory_provider.cc
+++ b/media/gpu/ipc/service/gpu_jpeg_decode_accelerator_factory_provider.cc
@@ -12,8 +12,7 @@
 #include "media/gpu/fake_jpeg_decode_accelerator.h"
 #include "media/gpu/features.h"
 
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) && \
-    defined(ARCH_CPU_ARM_FAMILY)
+#if BUILDFLAG(USE_V4L2_CODEC) && defined(ARCH_CPU_ARM_FAMILY)
 #define USE_V4L2_JDA
 #endif
 
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc
index d8c30687..2545016d 100644
--- a/media/gpu/video_decode_accelerator_unittest.cc
+++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -73,17 +73,10 @@
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
 #include "media/gpu/dxva_video_decode_accelerator_win.h"
-#else
-#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
-#include "media/gpu/v4l2_device.h"
-#include "media/gpu/v4l2_slice_video_decode_accelerator.h"
-#include "media/gpu/v4l2_video_decode_accelerator.h"
-#endif
+#endif  // defined(OS_WIN)
 #if BUILDFLAG(USE_VAAPI)
-#include "media/gpu/vaapi_video_decode_accelerator.h"
 #include "media/gpu/vaapi_wrapper.h"
 #endif  // BUILDFLAG(USE_VAAPI)
-#endif  // defined(OS_WIN)
 
 #if defined(USE_OZONE)
 #include "ui/gfx/native_pixmap.h"
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 5ecfe3b1..f518937 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -390,6 +390,7 @@
       channel_id_service_(channel_id_service),
       last_statistic_record_time_(base::Time::Now()),
       persist_session_cookies_(false),
+      global_hook_map_(base::MakeUnique<CookieChangedCallbackList>()),
       weak_ptr_factory_(this) {
   InitializeHistograms();
   cookieable_schemes_.insert(
@@ -639,6 +640,14 @@
       base::Bind(&RunAsync, base::ThreadTaskRunnerHandle::Get(), callback));
 }
 
+std::unique_ptr<CookieStore::CookieChangedSubscription>
+CookieMonster::AddCallbackForAllChanges(const CookieChangedCallback& callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  return global_hook_map_->Add(
+      base::Bind(&RunAsync, base::ThreadTaskRunnerHandle::Get(), callback));
+}
+
 bool CookieMonster::IsEphemeral() {
   return store_.get() == nullptr;
 }
@@ -1370,7 +1379,7 @@
   type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0;
   histogram_cookie_type_->Add(type_sample);
 
-  RunCookieChangedCallbacks(*cc_ptr, CookieStore::ChangeCause::INSERTED);
+  RunCookieChangedCallbacks(*cc_ptr, true, CookieStore::ChangeCause::INSERTED);
 
   return inserted;
 }
@@ -1556,7 +1565,7 @@
   ChangeCausePair mapping = kChangeCauseMapping[deletion_cause];
   if (delegate_.get() && mapping.notify)
     delegate_->OnCookieChanged(*cc, true, mapping.cause);
-  RunCookieChangedCallbacks(*cc, mapping.cause);
+  RunCookieChangedCallbacks(*cc, mapping.notify, mapping.cause);
   cookies_.erase(it);
 }
 
@@ -2031,6 +2040,7 @@
 }
 
 void CookieMonster::RunCookieChangedCallbacks(const CanonicalCookie& cookie,
+                                              bool notify_global_hooks,
                                               ChangeCause cause) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -2050,6 +2060,9 @@
       it->second->Notify(cookie, cause);
     }
   }
+
+  if (notify_global_hooks)
+    global_hook_map_->Notify(cookie, cause);
 }
 
 }  // namespace net
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 016444a0..480c4cd 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -226,6 +226,9 @@
       const std::string& name,
       const CookieChangedCallback& callback) override;
 
+  std::unique_ptr<CookieChangedSubscription> AddCallbackForAllChanges(
+      const CookieChangedCallback& callback) override;
+
   bool IsEphemeral() override;
 
   void SetCookieWithCreationTimeForTesting(const GURL& url,
@@ -654,8 +657,10 @@
   void DoCookieCallbackForURL(base::OnceClosure callback, const GURL& url);
 
   // Run all cookie changed callbacks that are monitoring |cookie|.
-  // |removed| is true if the cookie was deleted.
+  // |notify_global_hooks| is true if the function should run the
+  // global hooks in addition to the per-cookie hooks.
   void RunCookieChangedCallbacks(const CanonicalCookie& cookie,
+                                 bool notify_global_hooks,
                                  CookieStore::ChangeCause cause);
 
   // Histogram variables; see CookieMonster::InitializeHistograms() in
@@ -736,6 +741,7 @@
       std::map<std::pair<GURL, std::string>,
                std::unique_ptr<CookieChangedCallbackList>>;
   CookieChangedHookMap hook_map_;
+  std::unique_ptr<CookieChangedCallbackList> global_hook_map_;
 
   base::ThreadChecker thread_checker_;
 
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 927725f804..2d3f805 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -114,6 +114,7 @@
   static const bool filters_schemes = true;
   static const bool has_path_prefix_bug = false;
   static const bool forbids_setting_empty_name = false;
+  static const bool supports_global_cookie_tracking = true;
   static const int creation_time_granularity_in_ms = 0;
 };
 
@@ -3326,7 +3327,56 @@
   SetCookie(monster(), test_url_, "abc=def");
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1U, cookies0.size());
-  EXPECT_EQ(1U, cookies0.size());
+  EXPECT_EQ(1U, cookies1.size());
+}
+
+TEST_F(CookieMonsterNotificationTest, GlobalNotBroadcast) {
+  // Create a persistent store that will not synchronously satisfy the
+  // loading requirement.
+  scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
+  store->set_store_load_commands(true);
+
+  // Bind it to a CookieMonster
+  std::unique_ptr<CookieMonster> monster(
+      base::MakeUnique<CookieMonster>(store.get(), nullptr));
+
+  // Trigger load dispatch and confirm it.
+  monster->GetAllCookiesAsync(CookieStore::GetCookieListCallback());
+  EXPECT_EQ(1u, store->commands().size());
+  EXPECT_EQ(CookieStoreCommand::LOAD, store->commands()[0].type);
+
+  // Attach a change subscription.
+  std::vector<CanonicalCookie> cookies;
+  std::vector<CookieStore::ChangeCause> causes;
+  std::unique_ptr<CookieStore::CookieChangedSubscription> sub(
+      monster->AddCallbackForAllChanges(
+          base::Bind(&RecordCookieChanges, &cookies, &causes)));
+
+  // Set up a set of cookies with a duplicate.
+  std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies;
+  AddCookieToList(GURL("http://www.foo.com"),
+                  "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
+                  base::Time::Now() + base::TimeDelta::FromDays(3),
+                  &initial_cookies);
+
+  AddCookieToList(GURL("http://www.foo.com"),
+                  "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
+                  base::Time::Now() + base::TimeDelta::FromDays(1),
+                  &initial_cookies);
+
+  // Execute the load
+  store->commands()[0].loaded_callback.Run(std::move(initial_cookies));
+  base::RunLoop().RunUntilIdle();
+
+  // We should see two insertions, no deletions, and only one cookie in the
+  // monster.
+  // TODO(rdsmith): Why yes, this is an internally inconsistent interface.
+  EXPECT_EQ(2U, cookies.size());
+  EXPECT_EQ("X", cookies[0].Name());
+  EXPECT_EQ(CookieStore::ChangeCause::INSERTED, causes[0]);
+  EXPECT_EQ("X", cookies[1].Name());
+  EXPECT_EQ(CookieStore::ChangeCause::INSERTED, causes[1]);
+  EXPECT_EQ(1u, this->GetAllCookies(monster.get()).size());
 }
 
 }  // namespace net
diff --git a/net/cookies/cookie_store.h b/net/cookies/cookie_store.h
index 461f607c..e9bf8cb 100644
--- a/net/cookies/cookie_store.h
+++ b/net/cookies/cookie_store.h
@@ -251,6 +251,12 @@
       const std::string& name,
       const CookieChangedCallback& callback) = 0;
 
+  // Add a callback to be notified on all cookie changes (with a few
+  // bookkeeping exceptions; see kChangeCauseMapping in
+  // cookie_monster.cc).
+  virtual std::unique_ptr<CookieChangedSubscription> AddCallbackForAllChanges(
+      const CookieChangedCallback& callback) = 0;
+
   // Returns true if this cookie store is ephemeral, and false if it is backed
   // by some sort of persistence layer.
   // TODO(nharper): Remove this method once crbug.com/548423 has been closed.
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index 3a1f349..cf846b8 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -222,6 +222,13 @@
   return std::unique_ptr<CookieStore::CookieChangedSubscription>();
 }
 
+std::unique_ptr<CookieStore::CookieChangedSubscription>
+DelayedCookieMonster::AddCallbackForAllChanges(
+    const CookieChangedCallback& callback) {
+  ADD_FAILURE();
+  return std::unique_ptr<CookieStore::CookieChangedSubscription>();
+}
+
 bool DelayedCookieMonster::IsEphemeral() {
   return true;
 }
diff --git a/net/cookies/cookie_store_test_helpers.h b/net/cookies/cookie_store_test_helpers.h
index bd55a3d..5004b7a 100644
--- a/net/cookies/cookie_store_test_helpers.h
+++ b/net/cookies/cookie_store_test_helpers.h
@@ -97,6 +97,9 @@
       const std::string& name,
       const CookieChangedCallback& callback) override;
 
+  std::unique_ptr<CookieStore::CookieChangedSubscription>
+  AddCallbackForAllChanges(const CookieChangedCallback& callback) override;
+
   bool IsEphemeral() override;
 
  private:
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 415e37e7..58599b0f 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -64,6 +64,13 @@
 //   // another.
 //   static const bool has_path_prefix_bug;
 //
+//   // The cookie store forbids setting a cookie with an empty name.
+//   static const bool forbids_setting_empty_name;
+//
+//   // The cookie store supports global tracking of cookie changes (i.e.
+//   // calls to CookieStore::AddCallbackForAllChanges()).
+//   static const bool supports_global_cookie_tracking;
+//
 //   // Time to wait between two cookie insertions to ensure that cookies have
 //   // different creation times.
 //   static const int creation_time_granularity_in_ms;
@@ -286,6 +293,17 @@
     return callback.result();
   }
 
+  bool FindAndDeleteCookie(CookieStore* cs,
+                           const std::string& domain,
+                           const std::string& name) {
+    for (auto& cookie : this->GetAllCookies(cs)) {
+      if (cookie.Domain() == domain && cookie.Name() == name)
+        return this->DeleteCanonicalCookie(cs, cookie);
+    }
+
+    return false;
+  }
+
   // Returns the CookieStore for the test - each test only uses one CookieStore.
   CookieStore* GetCookieStore() {
     if (!cookie_store_)
@@ -1654,6 +1672,168 @@
   EXPECT_EQ("C=D", this->GetCookies(cs, this->http_www_foo_.url()));
 }
 
+namespace {
+
+typedef std::pair<CanonicalCookie, CookieStore::ChangeCause> CookieNotification;
+
+void OnCookieChanged(std::vector<CookieNotification>* changes,
+                     const CanonicalCookie& cookie,
+                     CookieStore::ChangeCause cause) {
+  CookieNotification notification(cookie, cause);
+  changes->push_back(notification);
+}
+
+}  // namespace
+
+TYPED_TEST_P(CookieStoreTest, GlobalChangeTracking_Insert) {
+  if (!TypeParam::supports_global_cookie_tracking)
+    return;
+
+  CookieStore* cs = this->GetCookieStore();
+  std::vector<CookieNotification> cookie_changes;
+  std::unique_ptr<CookieStore::CookieChangedSubscription> subscription(
+      cs->AddCallbackForAllChanges(
+          base::Bind(&OnCookieChanged, base::Unretained(&cookie_changes))));
+  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "A=B"));
+  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "C=D"));
+  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "E=F"));
+  EXPECT_EQ("A=B; C=D; E=F", this->GetCookies(cs, this->http_www_foo_.url()));
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(3u, cookie_changes.size());
+  EXPECT_EQ(CookieStore::ChangeCause::INSERTED, cookie_changes[0].second);
+  EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[0].first.Domain());
+  EXPECT_EQ("A", cookie_changes[0].first.Name());
+  EXPECT_EQ("B", cookie_changes[0].first.Value());
+  EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[1].first.Domain());
+  EXPECT_EQ(CookieStore::ChangeCause::INSERTED, cookie_changes[1].second);
+  EXPECT_EQ("C", cookie_changes[1].first.Name());
+  EXPECT_EQ("D", cookie_changes[1].first.Value());
+  EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[2].first.Domain());
+  EXPECT_EQ(CookieStore::ChangeCause::INSERTED, cookie_changes[2].second);
+  EXPECT_EQ("E", cookie_changes[2].first.Name());
+  EXPECT_EQ("F", cookie_changes[2].first.Value());
+}
+
+TYPED_TEST_P(CookieStoreTest, GlobalChangeTracking_Delete) {
+  if (!TypeParam::supports_global_cookie_tracking)
+    return;
+
+  CookieStore* cs = this->GetCookieStore();
+  std::vector<CookieNotification> cookie_changes;
+  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "A=B"));
+  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "C=D"));
+  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "E=F"));
+
+  std::unique_ptr<CookieStore::CookieChangedSubscription> subscription(
+      cs->AddCallbackForAllChanges(
+          base::Bind(&OnCookieChanged, base::Unretained(&cookie_changes))));
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(0u, cookie_changes.size());
+
+  EXPECT_TRUE(
+      this->FindAndDeleteCookie(cs, this->http_www_foo_.url().host(), "C"));
+  EXPECT_EQ("A=B; E=F", this->GetCookies(cs, this->http_www_foo_.url()));
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(1u, cookie_changes.size());
+  EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[0].first.Domain());
+  EXPECT_EQ(CookieStore::ChangeCause::EXPLICIT_DELETE_CANONICAL,
+            cookie_changes[0].second);
+  EXPECT_EQ("C", cookie_changes[0].first.Name());
+  EXPECT_EQ("D", cookie_changes[0].first.Value());
+}
+
+TYPED_TEST_P(CookieStoreTest, GlobalChangeTracking_Overwrite) {
+  if (!TypeParam::supports_global_cookie_tracking)
+    return;
+
+  // Insert a cookie "a" for path "/path1"
+  CookieStore* cs = this->GetCookieStore();
+  std::vector<CookieNotification> cookie_changes;
+  std::unique_ptr<CookieStore::CookieChangedSubscription> subscription(
+      cs->AddCallbackForAllChanges(
+          base::Bind(&OnCookieChanged, base::Unretained(&cookie_changes))));
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(0u, cookie_changes.size());
+
+  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(),
+                              "a=val1; path=/path1; "
+                              "expires=Mon, 18-Apr-22 22:50:13 GMT"));
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(1u, cookie_changes.size());
+  EXPECT_EQ(CookieStore::ChangeCause::INSERTED, cookie_changes[0].second);
+  EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[0].first.Domain());
+  EXPECT_EQ("a", cookie_changes[0].first.Name());
+  EXPECT_EQ("val1", cookie_changes[0].first.Value());
+  cookie_changes.clear();
+
+  // Insert a cookie "a" for path "/path1", that is httponly. This should
+  // overwrite the non-http-only version.
+  CookieOptions allow_httponly;
+  allow_httponly.set_include_httponly();
+  EXPECT_TRUE(this->SetCookieWithOptions(cs, this->http_www_foo_.url(),
+                                         "a=val2; path=/path1; httponly; "
+                                         "expires=Mon, 18-Apr-22 22:50:14 GMT",
+                                         allow_httponly));
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(2u, cookie_changes.size());
+  EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[0].first.Domain());
+  EXPECT_EQ(CookieStore::ChangeCause::OVERWRITE, cookie_changes[0].second);
+  EXPECT_EQ("a", cookie_changes[0].first.Name());
+  EXPECT_EQ("val1", cookie_changes[0].first.Value());
+  EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[1].first.Domain());
+  EXPECT_EQ(CookieStore::ChangeCause::INSERTED, cookie_changes[1].second);
+  EXPECT_EQ("a", cookie_changes[1].first.Name());
+  EXPECT_EQ("val2", cookie_changes[1].first.Value());
+}
+
+TYPED_TEST_P(CookieStoreTest, GlobalChangeTracking_Deregister) {
+  if (!TypeParam::supports_global_cookie_tracking)
+    return;
+
+  CookieStore* cs = this->GetCookieStore();
+
+  // Register two notifiers.
+  std::vector<CookieNotification> cookie_changes_1;
+  std::unique_ptr<CookieStore::CookieChangedSubscription> subscription1(
+      cs->AddCallbackForAllChanges(
+          base::Bind(&OnCookieChanged, base::Unretained(&cookie_changes_1))));
+
+  std::vector<CookieNotification> cookie_changes_2;
+  std::unique_ptr<CookieStore::CookieChangedSubscription> subscription2(
+      cs->AddCallbackForAllChanges(
+          base::Bind(&OnCookieChanged, base::Unretained(&cookie_changes_2))));
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(0u, cookie_changes_1.size());
+  ASSERT_EQ(0u, cookie_changes_2.size());
+
+  // Insert a cookie and make sure both see it.
+  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "A=B"));
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(1u, cookie_changes_1.size());
+  EXPECT_EQ("A", cookie_changes_1[0].first.Name());
+  EXPECT_EQ("B", cookie_changes_1[0].first.Value());
+  cookie_changes_1.clear();
+
+  ASSERT_EQ(1u, cookie_changes_2.size());
+  EXPECT_EQ("A", cookie_changes_2[0].first.Name());
+  EXPECT_EQ("B", cookie_changes_2[0].first.Value());
+  cookie_changes_2.clear();
+
+  // De-register the second registration.
+  subscription2.reset();
+
+  // Insert a second cookie and make sure that it's only visible in one
+  // change array.
+  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "C=D"));
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(1u, cookie_changes_1.size());
+  EXPECT_EQ("C", cookie_changes_1[0].first.Name());
+  EXPECT_EQ("D", cookie_changes_1[0].first.Value());
+  cookie_changes_1.clear();
+
+  ASSERT_EQ(0u, cookie_changes_2.size());
+}
+
 REGISTER_TYPED_TEST_CASE_P(CookieStoreTest,
                            SetCookieWithDetailsAsync,
                            SetCanonicalCookieTest,
@@ -1694,7 +1874,11 @@
                            GetAllCookiesAsync,
                            DeleteCookieAsync,
                            DeleteCanonicalCookieAsync,
-                           DeleteSessionCookie);
+                           DeleteSessionCookie,
+                           GlobalChangeTracking_Insert,
+                           GlobalChangeTracking_Delete,
+                           GlobalChangeTracking_Overwrite,
+                           GlobalChangeTracking_Deregister);
 
 }  // namespace net
 
diff --git a/net/disk_cache/disk_cache.cc b/net/disk_cache/disk_cache.cc
index e860aef..345a649e 100644
--- a/net/disk_cache/disk_cache.cc
+++ b/net/disk_cache/disk_cache.cc
@@ -292,4 +292,10 @@
   return net::ERR_NOT_IMPLEMENTED;
 }
 
+uint8_t Backend::GetEntryInMemoryData(const std::string& key) {
+  return 0;
+}
+
+void Backend::SetEntryInMemoryData(const std::string& key, uint8_t data) {}
+
 }  // namespace disk_cache
diff --git a/net/disk_cache/disk_cache.h b/net/disk_cache/disk_cache.h
index dbafe94f..2429402 100644
--- a/net/disk_cache/disk_cache.h
+++ b/net/disk_cache/disk_cache.h
@@ -223,6 +223,21 @@
   virtual size_t DumpMemoryStats(
       base::trace_event::ProcessMemoryDump* pmd,
       const std::string& parent_absolute_name) const = 0;
+
+  // Backends can optionally permit one to store, probabilistically, up to a
+  // byte associated with a key of an existing entry in memory.
+
+  // GetEntryInMemoryData has the following behavior:
+  // - If the data is not available at this time for any reason, returns 0.
+  // - Otherwise, returns a value that was with very high probability
+  //   given to SetEntryInMemoryData(|key|) (and with a very low probability
+  //   to a different key that collides in the in-memory index).
+  //
+  // Due to the probability of collisions, including those that can be induced
+  // by hostile 3rd parties, this interface should not be used to make decisions
+  // that affect correctness (especially security).
+  virtual uint8_t GetEntryInMemoryData(const std::string& key);
+  virtual void SetEntryInMemoryData(const std::string& key, uint8_t data);
 };
 
 // This interface represents an entry in the disk cache.
diff --git a/net/http/mock_http_cache.cc b/net/http/mock_http_cache.cc
index c21e1fc0d..fcafea32 100644
--- a/net/http/mock_http_cache.cc
+++ b/net/http/mock_http_cache.cc
@@ -68,6 +68,7 @@
 
 MockDiskEntry::MockDiskEntry(const std::string& key)
     : key_(key),
+      in_memory_data_(0),
       doomed_(false),
       sparse_(false),
       fail_requests_(false),
@@ -394,6 +395,7 @@
       soft_failures_(false),
       double_create_check_(true),
       fail_sparse_requests_(false),
+      support_in_memory_entry_data_(true),
       defer_op_(MockDiskEntry::DEFER_NONE),
       resume_return_code_(0) {}
 
@@ -552,6 +554,22 @@
   return 0u;
 }
 
+uint8_t MockDiskCache::GetEntryInMemoryData(const std::string& key) {
+  if (!support_in_memory_entry_data_)
+    return 0;
+
+  EntryMap::iterator it = entries_.find(key);
+  if (it != entries_.end())
+    return it->second->in_memory_data();
+  return 0;
+}
+
+void MockDiskCache::SetEntryInMemoryData(const std::string& key, uint8_t data) {
+  EntryMap::iterator it = entries_.find(key);
+  if (it != entries_.end())
+    it->second->set_in_memory_data(data);
+}
+
 void MockDiskCache::ReleaseAll() {
   for (auto entry : entries_)
     entry.second->Release();
diff --git a/net/http/mock_http_cache.h b/net/http/mock_http_cache.h
index bc7847b..97bfded 100644
--- a/net/http/mock_http_cache.h
+++ b/net/http/mock_http_cache.h
@@ -70,6 +70,9 @@
   void CancelSparseIO() override;
   int ReadyForSparseIO(const CompletionCallback& completion_callback) override;
 
+  uint8_t in_memory_data() const { return in_memory_data_; }
+  void set_in_memory_data(uint8_t val) { in_memory_data_ = val; }
+
   // Fail most subsequent requests.
   void set_fail_requests() { fail_requests_ = true; }
 
@@ -112,6 +115,7 @@
 
   std::string key_;
   std::vector<char> data_[kNumCacheEntryDataIndices];
+  uint8_t in_memory_data_;
   int test_mode_;
   bool doomed_;
   bool sparse_;
@@ -157,6 +161,8 @@
   size_t DumpMemoryStats(
       base::trace_event::ProcessMemoryDump* pmd,
       const std::string& parent_absolute_name) const override;
+  uint8_t GetEntryInMemoryData(const std::string& key) override;
+  void SetEntryInMemoryData(const std::string& key, uint8_t data) override;
 
   // Returns number of times a cache entry was successfully opened.
   int open_count() const { return open_count_; }
@@ -176,6 +182,12 @@
   // Makes sure that CreateEntry is not called twice for a given key.
   void set_double_create_check(bool value) { double_create_check_ = value; }
 
+  // Determines whether to provide the GetEntryInMemoryData/SetEntryInMemoryData
+  // interface.  Default is true.
+  void set_support_in_memory_entry_data(bool value) {
+    support_in_memory_entry_data_ = value;
+  }
+
   // Makes all requests for data ranges to fail as not implemented.
   void set_fail_sparse_requests() { fail_sparse_requests_ = true; }
 
@@ -209,6 +221,7 @@
   bool soft_failures_;
   bool double_create_check_;
   bool fail_sparse_requests_;
+  bool support_in_memory_entry_data_;
 
   // Used for pause and restart.
   MockDiskEntry::DeferOp defer_op_;
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index b57fb7a..0d1cd38 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -10998,7 +10998,8 @@
         "args": [
           "--browser=exact",
           "--browser-executable=./test_chrome",
-          "--xvfb"
+          "--xvfb",
+          "--skip=scripts_smoke_unittest.ScriptsSmokeTest.testRunTelemetryBenchmarkAsGoogletest"
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
@@ -11012,7 +11013,8 @@
         "args": [
           "--browser=exact",
           "--browser-executable=./test_chrome",
-          "--jobs=1"
+          "--jobs=1",
+          "--skip=telemetry.page.page_run_end_to_end_unittest.ActualPageRunEndToEndTests.testTrafficSettings"
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 2134659d..7f0d5e9 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -3898,6 +3898,7 @@
 crbug.com/591099 external/wpt/editing/run/inserttext.html [ Failure Timeout ]
 crbug.com/591099 external/wpt/editing/run/insertunorderedlist.html [ Crash Timeout ]
 crbug.com/591099 external/wpt/editing/run/italic.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/editing/run/justifycenter.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/justifyfull.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/justifyleft.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/justifyright.html [ Pass Timeout ]
@@ -8311,6 +8312,7 @@
 crbug.com/591099 fast/forms/text/input-delete.html [ Crash Failure ]
 crbug.com/591099 fast/forms/text/input-disabled-color.html [ Crash Failure ]
 crbug.com/591099 fast/forms/text/input-double-click-selection-gap-bug.html [ Failure ]
+crbug.com/591099 fast/forms/text/input-element-attach-crash.html [ Failure ]
 crbug.com/591099 fast/forms/text/input-field-text-truncated.html [ Crash Failure ]
 crbug.com/591099 fast/forms/text/input-hit-test-border.html [ Failure ]
 crbug.com/591099 fast/forms/text/input-live-pseudo-selectors.html [ Crash Failure ]
@@ -13500,6 +13502,8 @@
 crbug.com/667560 virtual/mojo-loading/http/tests/devtools/elements/styles-1/empty-background-url.html [ Crash Failure Timeout ]
 crbug.com/591099 http/tests/devtools/elements/styles-1/filter-matched-styles.html [ Crash Failure ]
 crbug.com/667560 virtual/mojo-loading/http/tests/devtools/elements/styles-1/filter-matched-styles.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/elements/styles-2/add-import-rule.html [ Failure ]
+crbug.com/591099 virtual/mojo-loading/http/tests/devtools/elements/styles-2/add-import-rule.html [ Failure ]
 crbug.com/591099 http/tests/devtools/elements/styles-2/cssom-shorthand-important.html [ Crash Failure ]
 crbug.com/667560 virtual/mojo-loading/http/tests/devtools/elements/styles-2/cssom-shorthand-important.html [ Crash Failure ]
 crbug.com/591099 http/tests/devtools/elements/styles-2/filter-matched-styles-hides-separators.html [ Crash Failure ]
@@ -15227,6 +15231,7 @@
 crbug.com/591099 paint/markers/inline-spelling-markers-hidpi-composited.html [ Failure ]
 crbug.com/591099 paint/markers/inline-spelling-markers-hidpi.html [ Failure ]
 crbug.com/591099 paint/markers/inline_spelling_markers.html [ Failure ]
+crbug.com/591099 paint/markers/suggestion-marker-split.html [ Failure ]
 crbug.com/591099 paint/masks/fieldset-mask.html [ Failure ]
 crbug.com/591099 paint/overflow/composited-rounded-clip-floating-element.html [ Failure ]
 crbug.com/591099 paint/overflow/fixed-background-scroll-window.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index ba4d78b..1110d88b6 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1595,8 +1595,6 @@
 crbug.com/705125 fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-element.html [ Failure ]
 crbug.com/705125 http/tests/security/cors-rfc1918/addressspace-document-appcache.html [ Failure ]
 crbug.com/705125 http/tests/security/cors-rfc1918/addressspace-document-csp-appcache.html [ Failure ]
-crbug.com/705125 http/tests/w3c/webperf/submission/Intel/user-timing/test_user_timing_clearMarks.html [ Failure ]
-crbug.com/705125 virtual/mojo-loading/http/tests/w3c/webperf/submission/Intel/user-timing/test_user_timing_clearMarks.html [ Failure ]
 crbug.com/705125 virtual/mojo-loading/http/tests/security/cors-rfc1918/addressspace-document-appcache.html [ Failure ]
 crbug.com/705125 virtual/mojo-loading/http/tests/security/cors-rfc1918/addressspace-document-csp-appcache.html [ Failure ]
 crbug.com/705125 virtual/mojo-loading/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php [ Failure Pass ]
@@ -3629,3 +3627,5 @@
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.html [ Pass Timeout ]
 crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.html [ Pass Timeout ]
+crbug.com/760543 [ Linux Release ] virtual/mojo-loading/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.html [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/hdr/color-jpeg-with-color-profile-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/hdr/color-jpeg-with-color-profile-expected.txt
new file mode 100644
index 0000000..1026b1c5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/hdr/color-jpeg-with-color-profile-expected.txt
@@ -0,0 +1,7 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x228
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x228
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x212
+      LayoutImage {IMG} at (0,0) size 275x207
+      LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/hdr/video-canvas-alpha-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/hdr/video-canvas-alpha-expected.txt
new file mode 100644
index 0000000..a81591a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/hdr/video-canvas-alpha-expected.txt
@@ -0,0 +1,15 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x261
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x261
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x245
+      LayoutText {#text} at (0,0) size 0x0
+layer at (8,8) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,8) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutNGBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,8) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (228,8) size 320x240
+  LayoutHTMLCanvas (relative positioned) {CANVAS} at (320,0) size 320x240
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/markers/suggestion-marker-basic-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/markers/suggestion-marker-basic-expected.txt
new file mode 100644
index 0000000..9eb9c58
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/markers/suggestion-marker-basic-expected.txt
@@ -0,0 +1,102 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x460
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x460
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x0
+      LayoutNGBlockFlow (floating) {DIV} at (586,0) size 198x192
+        LayoutNGBlockFlow {P} at (0,16) size 198x20
+          LayoutText {#text} at (167,0) size 31x19
+            text run at (167,0) width 31: "RTL"
+        LayoutNGBlockFlow {DIV} at (0,52) size 198x20
+          LayoutText {#text} at (127,0) size 71x19
+            text run at (127,0) width 71: "markRtlAll"
+        LayoutNGBlockFlow {DIV} at (0,72) size 198x20
+          LayoutText {#text} at (90,0) size 108x19
+            text run at (90,0) width 108: "markRtlAllThick"
+        LayoutNGBlockFlow {DIV} at (0,92) size 198x20
+          LayoutText {#text} at (81,0) size 117x19
+            text run at (81,0) width 117: "markRtlBeginning"
+        LayoutNGBlockFlow {DIV} at (0,112) size 198x20
+          LayoutText {#text} at (0,0) size 198x19
+            text run at (0,0) width 198: "markRtlAllExceptFirstAndLast"
+        LayoutNGBlockFlow {DIV} at (0,132) size 198x20
+          LayoutText {#text} at (121,0) size 77x19
+            text run at (121,0) width 77: "markRtlEnd"
+        LayoutNGBlockFlow {DIV} at (0,152) size 198x40
+          LayoutNGBlockFlow {DIV} at (0,0) size 198x20
+            LayoutText {#text} at (147,0) size 32x19
+              text run at (147,0) width 32: "mark"
+            LayoutInline {SPAN} at (0,0) size 19x19
+              LayoutText {#text} at (179,0) size 19x19
+                text run at (179,0) width 19: "Rtl"
+          LayoutNGBlockFlow {DIV} at (0,20) size 198x20
+            LayoutText {#text} at (113,0) size 85x19
+              text run at (113,0) width 85: "AcrossNodes"
+      LayoutNGBlockFlow (floating) {DIV} at (0,0) size 331x452
+        LayoutNGBlockFlow {P} at (0,16) size 331x20
+          LayoutText {#text} at (0,0) size 30x19
+            text run at (0,0) width 30: "LTR"
+        LayoutNGBlockFlow {DIV} at (0,52) size 331x20
+          LayoutText {#text} at (0,0) size 52x19
+            text run at (0,0) width 52: "markAll"
+        LayoutNGBlockFlow {DIV} at (0,72) size 331x20
+          LayoutText {#text} at (0,0) size 89x19
+            text run at (0,0) width 89: "markAllThick"
+        LayoutNGBlockFlow {DIV} at (0,92) size 331x20
+          LayoutText {#text} at (0,0) size 151x19
+            text run at (0,0) width 151: "markAllDifferentColors"
+        LayoutNGBlockFlow {DIV} at (0,112) size 331x20
+          LayoutText {#text} at (0,0) size 98x19
+            text run at (0,0) width 98: "markBeginning"
+        LayoutNGBlockFlow {DIV} at (0,132) size 331x20
+          LayoutText {#text} at (0,0) size 179x19
+            text run at (0,0) width 179: "markAllExceptFirstAndLast"
+        LayoutNGBlockFlow {DIV} at (0,152) size 331x20
+          LayoutText {#text} at (0,0) size 58x19
+            text run at (0,0) width 58: "markEnd"
+        LayoutNGBlockFlow {DIV} at (0,172) size 331x20
+          LayoutText {#text} at (0,0) size 114x19
+            text run at (0,0) width 114: "markNothingZero"
+        LayoutNGBlockFlow {DIV} at (0,192) size 331x20
+          LayoutText {#text} at (0,0) size 110x19
+            text run at (0,0) width 110: "markNothingEnd"
+        LayoutNGBlockFlow {DIV} at (0,212) size 331x40
+          LayoutNGBlockFlow {DIV} at (0,0) size 331x20
+            LayoutText {#text} at (0,0) size 32x19
+              text run at (0,0) width 32: "mark"
+            LayoutInline {SPAN} at (0,0) size 44x19
+              LayoutText {#text} at (32,0) size 44x19
+                text run at (32,0) width 44: "Across"
+          LayoutNGBlockFlow {DIV} at (0,20) size 331x20
+            LayoutText {#text} at (0,0) size 41x19
+              text run at (0,0) width 41: "Nodes"
+        LayoutNGBlockFlow {DIV} at (0,252) size 331x20
+          LayoutText {#text} at (0,0) size 245x19
+            text run at (0,0) width 245: "overridingSpellingMarkerAtBeginning"
+        LayoutNGBlockFlow {DIV} at (0,272) size 331x20
+          LayoutText {#text} at (0,0) size 205x19
+            text run at (0,0) width 205: "overridingSpellingMarkerAtEnd"
+        LayoutNGBlockFlow {DIV} at (0,292) size 331x20
+          LayoutText {#text} at (0,0) size 302x19
+            text run at (0,0) width 302: "overridingSpellingMarkerIntersectingBeginning"
+        LayoutNGBlockFlow {DIV} at (0,312) size 331x20
+          LayoutText {#text} at (0,0) size 262x19
+            text run at (0,0) width 262: "overridingSpellingMarkerIntersectingEnd"
+        LayoutNGBlockFlow {DIV} at (0,332) size 331x20
+          LayoutText {#text} at (0,0) size 253x19
+            text run at (0,0) width 253: "notOverridingSpellingMarkersTouching"
+        LayoutNGBlockFlow {DIV} at (0,352) size 331x20
+          LayoutText {#text} at (0,0) size 274x19
+            text run at (0,0) width 274: "overridingCompositionMarkerAtBeginning"
+        LayoutNGBlockFlow {DIV} at (0,372) size 331x20
+          LayoutText {#text} at (0,0) size 234x19
+            text run at (0,0) width 234: "overridingCompositionMarkerAtEnd"
+        LayoutNGBlockFlow {DIV} at (0,392) size 331x20
+          LayoutText {#text} at (0,0) size 331x19
+            text run at (0,0) width 331: "overridingCompositionMarkerIntersectingBeginning"
+        LayoutNGBlockFlow {DIV} at (0,412) size 331x20
+          LayoutText {#text} at (0,0) size 291x19
+            text run at (0,0) width 291: "overridingCompositionMarkerIntersectingEnd"
+        LayoutNGBlockFlow {DIV} at (0,432) size 331x20
+          LayoutText {#text} at (0,0) size 282x19
+            text run at (0,0) width 282: "notOverridingCompositionMarkersTouching"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/markers/suggestion-marker-split-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/markers/suggestion-marker-split-expected.txt
new file mode 100644
index 0000000..d5a0f9f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/markers/suggestion-marker-split-expected.txt
@@ -0,0 +1,20 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x56
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x56
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x40
+      LayoutNGBlockFlow {DIV} at (0,0) size 784x20
+        LayoutText {#text} at (0,0) size 22x19
+          text run at (0,0) width 22: "abc"
+        LayoutText {#text} at (22,0) size 32x19
+          text run at (22,0) width 32: " xxx "
+        LayoutText {#text} at (54,0) size 20x19
+          text run at (54,0) width 20: "def"
+layer at (8,28) size 128x20 scrollWidth 160
+  LayoutNGBlockFlow {DIV} at (0,20) size 128x20
+    LayoutText {#text} at (0,0) size 62x19
+      text run at (0,0) width 62: "abcdefghi"
+    LayoutText {#text} at (62,0) size 32x19
+      text run at (62,0) width 32: " xxx "
+    LayoutText {#text} at (94,0) size 65x19
+      text run at (94,0) width 65: "jklmnopqr"
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 01d4bc5..bdbabd1e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -956,6 +956,13 @@
     method getEntries
     method getEntriesByName
     method getEntriesByType
+interface PerformanceServerTiming
+    attribute @@toStringTag
+    getter description
+    getter duration
+    getter name
+    method constructor
+    method toJSON
 interface PermissionStatus : EventTarget
     attribute @@toStringTag
     getter onchange
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/resources/webperftestharnessextension.js b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/resources/webperftestharnessextension.js
index 4350d94..e5168c23 100644
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/resources/webperftestharnessextension.js
+++ b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/resources/webperftestharnessextension.js
@@ -92,17 +92,17 @@
 {
     var entryType = type;
 
-    function entry_check(entry, expectedNames)
+    function entry_check(entry, expectedNames, testDescription='')
     {
-        var msg = 'Entry \"' + entry.name + '\" should be one that we have set.';
+        var msg = testDescription + 'Entry \"' + entry.name + '\" should be one that we have set.';
         wp_test(function() { assert_in_array(entry.name, expectedNames, msg); }, msg);
-        test_equals(entry.entryType, entryType, 'entryType should be \"' + entryType + '\".');
+        test_equals(entry.entryType, entryType, testDescription + 'entryType should be \"' + entryType + '\".');
         if (type === "measure") {
-            test_true(isFinite(entry.startTime), 'startTime should be a number.');
-            test_true(isFinite(entry.duration), 'duration should be a number.');
+            test_true(isFinite(entry.startTime), testDescription + 'startTime should be a number.');
+            test_true(isFinite(entry.duration), testDescription + 'duration should be a number.');
         } else if (type === "mark") {
-            test_greater_than(entry.startTime, 0, 'startTime should greater than 0.');
-            test_equals(entry.duration, 0, 'duration of mark should be 0.');
+            test_greater_than(entry.startTime, 0, testDescription + 'startTime should greater than 0.');
+            test_equals(entry.duration, 0, testDescription + 'duration of mark should be 0.');
         }
     }
 
@@ -119,13 +119,16 @@
         return inOrder;
     }
 
-    function entrylist_check(entryList, expectedLength, expectedNames)
+    function entrylist_check(entryList, expectedLength, expectedNames, testDescription='')
     {
-        test_equals(entryList.length, expectedLength, 'There should be ' + expectedLength + ' entries.');
-        test_true(entrylist_order_check(entryList), 'Entries in entrylist should be in order.');
+        test_equals(entryList.length, expectedLength, testDescription + 'There should be ' + expectedLength + ' entries.');
+        test_true(entrylist_order_check(entryList), testDescription + 'Entries in entrylist should be in order.');
         for (var i = 0; i < entryList.length; ++i)
         {
-            entry_check(entryList[i], expectedNames);
+            if (testDescription != '')
+                entry_check(entryList[i], expectedNames, testDescription + 'Entry_list ' + i + '. ');
+            else
+                entry_check(entryList[i], expectedNames);
         }
     }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/submission/Intel/user-timing/test_user_timing_clearMarks-expected.txt b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/submission/Intel/user-timing/test_user_timing_clearMarks-expected.txt
deleted file mode 100644
index 4778f3e2..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/submission/Intel/user-timing/test_user_timing_clearMarks-expected.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = 9 duplicate test names: "entryType should be "mark".", "startTime should greater than 0.", "duration of mark should be 0.", "Entries in entrylist should be in order.", "Entry "abc" should be one that we have set.", "Marks that we cleared should not exist anymore.", "Entry "1" should be one that we have set.", "There should be 2 entries.", "There should be 0 entries."
-PASS There should be 2 entries.
-PASS Entries in entrylist should be in order.
-PASS Entry "1" should be one that we have set.
-PASS entryType should be "mark".
-PASS startTime should greater than 0.
-PASS duration of mark should be 0.
-PASS Entry "abc" should be one that we have set.
-PASS entryType should be "mark".
-PASS startTime should greater than 0.
-PASS duration of mark should be 0.
-PASS Marks that we cleared should not exist anymore.
-PASS There should be 1 entries.
-PASS Entries in entrylist should be in order.
-PASS Entry "abc" should be one that we have set.
-PASS entryType should be "mark".
-PASS startTime should greater than 0.
-PASS duration of mark should be 0.
-PASS Marks that we cleared should not exist anymore.
-PASS There should be 0 entries.
-PASS Entries in entrylist should be in order.
-PASS Marks that we cleared should not exist anymore.
-PASS No marks should exist after we clear all.
-PASS There should be 4 entries.
-PASS Entries in entrylist should be in order.
-PASS Entry "1" should be one that we have set.
-PASS entryType should be "mark".
-PASS startTime should greater than 0.
-PASS duration of mark should be 0.
-PASS Entry "abc" should be one that we have set.
-PASS entryType should be "mark".
-PASS startTime should greater than 0.
-PASS duration of mark should be 0.
-PASS Entry "1" should be one that we have set.
-PASS entryType should be "mark".
-PASS startTime should greater than 0.
-PASS duration of mark should be 0.
-PASS Entry "abc" should be one that we have set.
-PASS entryType should be "mark".
-PASS startTime should greater than 0.
-PASS duration of mark should be 0.
-PASS Marks that we cleared should not exist anymore.
-PASS There should be 2 entries.
-PASS Entries in entrylist should be in order.
-PASS Entry "abc" should be one that we have set.
-PASS entryType should be "mark".
-PASS startTime should greater than 0.
-PASS duration of mark should be 0.
-PASS Entry "abc" should be one that we have set.
-PASS entryType should be "mark".
-PASS startTime should greater than 0.
-PASS duration of mark should be 0.
-PASS Marks that we cleared should not exist anymore.
-PASS There should be 0 entries.
-PASS Entries in entrylist should be in order.
-PASS Marks that we cleared should not exist anymore.
-PASS Nothing should happen if we clear a non-exist mark.
-PASS No marks should exist when we clear all.
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/submission/Intel/user-timing/test_user_timing_clearMarks.html b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/submission/Intel/user-timing/test_user_timing_clearMarks.html
index c1a583f..4667796 100644
--- a/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/submission/Intel/user-timing/test_user_timing_clearMarks.html
+++ b/third_party/WebKit/LayoutTests/http/tests/w3c/webperf/submission/Intel/user-timing/test_user_timing_clearMarks.html
@@ -24,8 +24,10 @@
                 context.clearMarks(mark_names[i]);
                 var retained_entries = context.getEntriesByType('mark');
                 var non_retained_entries = context.getEntriesByName(mark_names[i], 'mark');
-                entrylist_checker.entrylist_check(retained_entries, mark_names.length - i - 1, string_mark_names);
-                test_equals(non_retained_entries.length, 0, 'Marks that we cleared should not exist anymore.');
+                entrylist_checker.entrylist_check(retained_entries, mark_names.length - i - 1, string_mark_names,
+                    'First loop: checking entries after removing "' + mark_names[i] + '". ');
+                test_equals(non_retained_entries.length, 0,
+                    'First loop: marks that we cleared for "' + mark_names[i] + '" should not exist anymore.');
             }
 
             mark_names.forEach(context.mark, context);
@@ -41,8 +43,10 @@
                 context.clearMarks(mark_names[i]);
                 var retained_entries = context.getEntriesByType('mark');
                 var non_retained_entries = context.getEntriesByName(mark_names[i], 'mark');
-                entrylist_checker.entrylist_check(retained_entries, (mark_names.length - i - 1) * 2, string_mark_names);
-                test_equals(non_retained_entries.length, 0, 'Marks that we cleared should not exist anymore.');
+                entrylist_checker.entrylist_check(retained_entries, (mark_names.length - i - 1) * 2, string_mark_names,
+                    'Second loop: checking entries after removing "' + mark_names[i] + '". ');
+                test_equals(non_retained_entries.length, 0,
+                    'Second loop: marks that we cleared for "' + mark_names[i] + '" should not exist anymore.');
             }
 
             // Following cases test clear functionality when mark names are tied for two times. 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/performance/perf-metrics-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/performance/perf-metrics-expected.txt
index 0513c655..c26ecd0 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/performance/perf-metrics-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/performance/perf-metrics-expected.txt
@@ -1,6 +1,7 @@
 Test that page performance metrics are retrieved.
 Received metrics:
 Received metrics:
+	Timestamp
 	AudioHandlerCount
 	DocumentCount
 	FrameCount
@@ -22,7 +23,9 @@
 	TaskDuration
 	FirstMeaningfulPaint
 	DomContentLoaded
+	NavigationStart
 Received metrics:
+	Timestamp
 	AudioHandlerCount
 	DocumentCount
 	FrameCount
@@ -44,5 +47,6 @@
 	TaskDuration
 	FirstMeaningfulPaint
 	DomContentLoaded
+	NavigationStart
 Received metrics:
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/performance/perf-push-metrics-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/performance/perf-push-metrics-expected.txt
index f50a0f55..6b4f22ce 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/performance/perf-push-metrics-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/performance/perf-push-metrics-expected.txt
@@ -1,5 +1,6 @@
 Test that console.timeStamp generates Performance.metrics event
 title: test1
+	Timestamp
 	AudioHandlerCount
 	DocumentCount
 	FrameCount
@@ -21,7 +22,9 @@
 	TaskDuration
 	FirstMeaningfulPaint
 	DomContentLoaded
+	NavigationStart
 title: test1
+	Timestamp
 	AudioHandlerCount
 	DocumentCount
 	FrameCount
@@ -43,7 +46,9 @@
 	TaskDuration
 	FirstMeaningfulPaint
 	DomContentLoaded
+	NavigationStart
 title: 
+	Timestamp
 	AudioHandlerCount
 	DocumentCount
 	FrameCount
@@ -65,4 +70,5 @@
 	TaskDuration
 	FirstMeaningfulPaint
 	DomContentLoaded
+	NavigationStart
 
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
index 5007bb92..6c5547a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3785,6 +3785,7 @@
     getter connection
     getter cookieEnabled
     getter credentials
+    getter deviceMemory
     getter doNotTrack
     getter geolocation
     getter hardwareConcurrency
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
index d4afd52..c5b984b9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3713,6 +3713,7 @@
     getter connection
     getter cookieEnabled
     getter credentials
+    getter deviceMemory
     getter doNotTrack
     getter geolocation
     getter hardwareConcurrency
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index fb41212..efb44db 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -869,6 +869,13 @@
 [Worker]     method getEntries
 [Worker]     method getEntriesByName
 [Worker]     method getEntriesByType
+[Worker] interface PerformanceServerTiming
+[Worker]     attribute @@toStringTag
+[Worker]     getter description
+[Worker]     getter duration
+[Worker]     getter name
+[Worker]     method constructor
+[Worker]     method toJSON
 [Worker] interface PermissionStatus : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter onchange
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
index 798c08b..8f62685 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -864,6 +864,13 @@
 [Worker]     method getEntries
 [Worker]     method getEntriesByName
 [Worker]     method getEntriesByType
+[Worker] interface PerformanceServerTiming
+[Worker]     attribute @@toStringTag
+[Worker]     getter description
+[Worker]     getter duration
+[Worker]     getter name
+[Worker]     method constructor
+[Worker]     method toJSON
 [Worker] interface PermissionStatus : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter onchange
diff --git a/third_party/WebKit/PerformanceTests/OWPStorage/README.md b/third_party/WebKit/PerformanceTests/OWPStorage/README.md
index fffd908..ab58a6b 100644
--- a/third_party/WebKit/PerformanceTests/OWPStorage/README.md
+++ b/third_party/WebKit/PerformanceTests/OWPStorage/README.md
@@ -4,4 +4,16 @@
 
 # IDB Docs Load
 
-This models an offline load of a Google doc. See [this document](https://docs.google.com/document/d/1JC1RgMyxBAjUPSHjm2Bd1KPzcqpPPvxRomKevOkMPm0/edit) for a breakdown of the database and the transactions, along with the traces used to extract this information.
\ No newline at end of file
+This models an offline load of a Google doc. See [this document](https://docs.google.com/document/d/1JC1RgMyxBAjUPSHjm2Bd1KPzcqpPPvxRomKevOkMPm0/edit) for a breakdown of the database and the transactions, along with the traces used to extract this information.
+
+# Blob Build All Then Read Serially
+
+This benchmark models the creation and reading of a large number of blobs. The blobs are created first, then read one at a time.
+
+# Blob Build All Then Read in Parallel
+
+This benchmark models the creation and reading of a large number of blobs. The blobs are created first, then read all at once.
+
+# Blob Build And Read Immediately
+
+This benchmark models the creation and reading of a large number of blobs. Each blob is read immediately after creation.
diff --git a/third_party/WebKit/PerformanceTests/OWPStorage/blob-build-all-then-read-parallel.html b/third_party/WebKit/PerformanceTests/OWPStorage/blob-build-all-then-read-parallel.html
new file mode 100644
index 0000000..0d2ca86f
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/OWPStorage/blob-build-all-then-read-parallel.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>Blob Build All Then Read in Parallel</title>
+<script src="../resources/runner.js"></script>
+<script src="resources/shared.js"></script>
+<script>
+let runnerParams = { size: 2, numBlobs: 200 };
+let test = {
+  description:
+    'Benchmark for creating blobs and then reading them in parallel.',
+  unit: 'ms',
+  iterationCount: 10,
+  tracingCategories: 'Blob',
+  traceEventsToMeasure: [
+    'BlobReader::ReadBytesItem', 'Registry::RegisterBlob',
+    'BlobRequest::ReadRawData', 'BlobRequest'
+  ],
+  path: 'resources/blob-build-all-then-read-parallel-runner.html',
+  params: runnerParams
+}
+PerfTestRunner.measurePageLoadTimeAfterDoneMessage(test);
+</script>
diff --git a/third_party/WebKit/PerformanceTests/OWPStorage/blob-build-all-then-read-serially.html b/third_party/WebKit/PerformanceTests/OWPStorage/blob-build-all-then-read-serially.html
new file mode 100644
index 0000000..7dd1775
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/OWPStorage/blob-build-all-then-read-serially.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>Blob Build All Then Read Serially</title>
+<script src="../resources/runner.js"></script>
+<script src="resources/shared.js"></script>
+<script>
+let runnerParams = { size: 2, numBlobs: 200 };
+let test = {
+  description: 'Benchmark for creating blobs and then reading them serially.',
+  unit: 'ms',
+  iterationCount: 10,
+  tracingCategories: 'Blob',
+  traceEventsToMeasure: [
+    'BlobReader::ReadBytesItem', 'Registry::RegisterBlob',
+    'BlobRequest::ReadRawData', 'BlobRequest'
+  ],
+  path: 'resources/blob-build-all-then-read-serially-runner.html',
+  params: runnerParams
+}
+PerfTestRunner.measurePageLoadTimeAfterDoneMessage(test);
+</script>
diff --git a/third_party/WebKit/PerformanceTests/OWPStorage/blob-build-and-read-immediately.html b/third_party/WebKit/PerformanceTests/OWPStorage/blob-build-and-read-immediately.html
new file mode 100644
index 0000000..09adc261
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/OWPStorage/blob-build-and-read-immediately.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>Blob Build and Read Immediately</title>
+<script src="../resources/runner.js"></script>
+<script src="resources/shared.js"></script>
+<script>
+let runnerParams = { size: 2, numBlobs: 200 };
+let test = {
+  description:
+    'Benchmark for creating blobs and then reading them immediately.',
+  unit: 'ms',
+  iterationCount: 10,
+  tracingCategories: 'Blob',
+  traceEventsToMeasure: [
+    'BlobReader::ReadBytesItem', 'Registry::RegisterBlob',
+    'BlobRequest::ReadRawData', 'BlobRequest'
+  ],
+  path: 'resources/blob-build-and-read-immediately-runner.html',
+  params: runnerParams
+}
+PerfTestRunner.measurePageLoadTimeAfterDoneMessage(test);
+</script>
diff --git a/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-build-all-then-read-parallel-runner.html b/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-build-all-then-read-parallel-runner.html
new file mode 100644
index 0000000..7b3477791
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-build-all-then-read-parallel-runner.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<title>Blob Build All Then Read in Parallel Runner</title>
+<script src="resources/blob-shared.js"></script>
+<script src="resources/shared.js"></script>
+<body></body>
+<script>
+  async function start(testParams) {
+    logToDocumentBody(`Starting benchmark: ${testParams.numBlobs} blobs of ` +
+                      `size ${testParams.size}`);
+    let start = Date.now();
+    await blobCreateAllThenReadInParallel(testParams.numBlobs, testParams.size);
+    logToDocumentBody('Time: ' + (Date.now() - start));
+    reportDone();
+  }
+
+  function getParams() {
+    let testParams = {
+      size: Number(document.getElementById('blob_size').value),
+      numBlobs: Number(document.getElementById('num_blobs').value)
+    };
+    start(testParams);
+  }
+
+  if (typeof params !== 'undefined')
+    start(params);
+  else
+    showManualInput();
+</script>
diff --git a/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-build-all-then-read-serially-runner.html b/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-build-all-then-read-serially-runner.html
new file mode 100644
index 0000000..3bd5ba7
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-build-all-then-read-serially-runner.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<title>Blob Build All Then Read Serially Runner</title>
+<script src="resources/blob-shared.js"></script>
+<script src="resources/shared.js"></script>
+<body></body>
+<script>
+  async function start(testParams) {
+    logToDocumentBody(`Starting benchmark: ${testParams.numBlobs} blobs of ` +
+                      `size ${testParams.size}`);
+    let start = Date.now();
+    await blobCreateAllThenReadSerially(testParams.numBlobs, testParams.size);
+    logToDocumentBody('Time: ' + (Date.now() - start));
+    reportDone();
+  }
+
+  function getParams() {
+    let testParams = {
+      size: Number(document.getElementById('blob_size').value),
+      numBlobs: Number(document.getElementById('num_blobs').value)
+    };
+    start(testParams);
+  }
+
+  if (typeof params !== 'undefined')
+    start(params);
+  else
+    showManualInput();
+</script>
diff --git a/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-build-and-read-immediately-runner.html b/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-build-and-read-immediately-runner.html
new file mode 100644
index 0000000..331f48f
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-build-and-read-immediately-runner.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<title>Blob Build and Read Immediately Runner</title>
+<script src="resources/blob-shared.js"></script>
+<script src="resources/shared.js"></script>
+<body></body>
+<script>
+  async function start(testParams) {
+    logToDocumentBody(`Starting benchmark: ${testParams.numBlobs} blobs of ` +
+                      `size ${testParams.size}`);
+    let start = Date.now();
+    await blobCreateAndImmediatelyRead(testParams.numBlobs, testParams.size);
+    logToDocumentBody('Time: ' + (Date.now() - start));
+    reportDone();
+  }
+
+  function getParams() {
+    let testParams = {
+      size: Number(document.getElementById('blob_size').value),
+      numBlobs: Number(document.getElementById('num_blobs').value)
+    };
+    start(testParams);
+  }
+
+  if (typeof params !== 'undefined')
+    start(params);
+  else
+    showManualInput();
+</script>
diff --git a/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-shared.js b/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-shared.js
new file mode 100644
index 0000000..cc88496
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/OWPStorage/resources/blob-shared.js
@@ -0,0 +1,145 @@
+let blobs = [];
+let totalBytes = 0;
+let errors = [];
+
+function showManualInput() {
+  document.body.innerHTML =
+  `
+  <h4><b>Manual Input:</b></h4>
+  <form>
+    Blob size: <input type="text" id="blob_size"><br>
+    Number of blobs: <input type="text" id="num_blobs"><br>
+    <input type="button" value="Start Benchmark" onclick="getParams();" />
+  </form>
+  <h4><b>Benchmark Output:</b></h4>
+  `;
+}
+
+function recordError(message) {
+  console.log(message);
+  errors.push(message);
+
+  let error = document.createElement('div');
+  error.textContent = message;
+  document.body.appendChild(error);
+}
+
+function createBlob(size) {
+  let blob = new Blob([new Uint8Array(size)],
+                      {type: 'application/octet-string'});
+  blobs.push(blob);
+  totalBytes += size;
+}
+
+function readBlobAsync(blob) {
+  const reader = new FileReader();
+  return new Promise(resolve => {
+    reader.onerror = reportError;
+    reader.onloadend = e => { resolve(reader); };
+    reader.readAsArrayBuffer(blob);
+  });
+}
+
+async function createAndRead(size) {
+  let blob = new Blob([new Uint8Array(size)],
+                      {type: 'application/octet-string'});
+  const reader = await readBlobAsync(blob);
+  if (reader.error)
+    recordError(`Error reading blob: ${reader.error}`);
+  else if (reader.result.byteLength != size)
+    recordError('Error reading blob: Blob size does not match.');
+}
+
+async function readBlobsSerially() {
+  if (blobs.length == 0)
+    return;
+
+  let totalReadSize = 0;
+  for (let i = 0; i < blobs.length; i++) {
+    const reader = await readBlobAsync(blobs[i]);
+    if (reader.error) {
+      recordError(`Error reading blob ${i}: ${reader.error}`);
+      return;
+    }
+    totalReadSize += reader.result.byteLength;
+    if (i == blobs.length - 1 && totalReadSize != totalBytes) {
+      recordError('Error reading blob: Total blob sizes do not match, ' +
+                  `${totalReadSize} vs ${totalBytes}`);
+    }
+  }
+}
+
+function readBlobsInParallel(callback) {
+  if (blobs.length == 0)
+    return;
+
+  let totalReadSize = 0;
+  let numRead = 0;
+
+  let getReader = e => {
+    const reader = new FileReader();
+    reader.onerror = reportError;
+    reader.onloadend = () => {
+      if (reader.error) {
+        recordError(`Error reading blob: ${reader.error}`);
+      } else {
+        totalReadSize += reader.result.byteLength;
+        if (++numRead == blobs.length) {
+          if (totalReadSize != totalBytes) {
+            recordError('Error reading blob: Total blob sizes do not match, ' +
+                        `${totalReadSize} vs ${totalBytes}`);
+          }
+          callback();
+        }
+      }
+    };
+    return reader;
+  }
+
+  blobs.map(blob => getReader().readAsArrayBuffer(blob));
+}
+
+async function blobCreateAndImmediatelyRead(numBlobs, size) {
+  let start = performance.now();
+  errors = [];
+
+  logToDocumentBody(`Creating and reading ${numBlobs} blobs...`);
+  for (let i = 0; i < numBlobs; i++)
+    await createAndRead(size);
+  logToDocumentBody('Finished.');
+
+  if (errors.length)
+    logToDocumentBody('Errors on page: ' + errors.join(', '));
+}
+
+async function blobCreateAllThenReadSerially(numBlobs, size) {
+  errors = [];
+
+  logToDocumentBody(`Creating ${numBlobs} blobs...`);
+  for (let i = 0; i < numBlobs; i++)
+    createBlob(size);
+  logToDocumentBody('Finished creating.');
+
+  logToDocumentBody(`Reading ${numBlobs} blobs serially...`);
+  await readBlobsSerially();
+  logToDocumentBody('Finished reading.');
+
+  if (errors.length)
+    logToDocumentBody('Errors on page: ' + errors.join(', '));
+}
+
+async function blobCreateAllThenReadInParallel(numBlobs, size) {
+  errors = [];
+
+  logToDocumentBody(`Creating ${numBlobs} blobs...`);
+  for (let i = 0; i < numBlobs; i++)
+    createBlob(size);
+  logToDocumentBody('Finished creating.');
+
+  logToDocumentBody(`Reading ${numBlobs} blobs in parallel...`);
+  await new Promise(readBlobsInParallel);
+  logToDocumentBody('Finished reading.');
+
+  if (errors.length)
+    logToDocumentBody('Errors on page: ' + errors.join(', '));
+}
diff --git a/third_party/WebKit/PerformanceTests/OWPStorage/resources/shared.js b/third_party/WebKit/PerformanceTests/OWPStorage/resources/shared.js
index 3d9073d..9f53e727 100644
--- a/third_party/WebKit/PerformanceTests/OWPStorage/resources/shared.js
+++ b/third_party/WebKit/PerformanceTests/OWPStorage/resources/shared.js
@@ -124,6 +124,9 @@
         PerfTestRunner.addRunTestStartMarker();
         startTime = PerfTestRunner.now();
 
+        if (test.params)
+          iframe.contentWindow.params = test.params;
+
         iframe.contentDocument.write(file);
         PerfTestRunner.forceLayout(iframe.contentDocument);
 
diff --git a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
index d891ac58..bf4fc7b 100644
--- a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
+++ b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
@@ -21,7 +21,7 @@
   // TODO(haraken): Optimize the mapping from TaskTypes to task runners.
   switch (type) {
     case TaskType::kTimer:
-      return frame ? frame->FrameScheduler()->ThrottleableTaskRunner()
+      return frame ? frame->FrameScheduler()->TimerTaskRunner()
                    : Platform::Current()->CurrentThread()->GetWebTaskRunner();
     case TaskType::kUnspecedLoading:
     case TaskType::kNetworking:
@@ -36,6 +36,8 @@
     // or provide a mechanism that web pages can opt-out it if throttling is not
     // desirable.
     case TaskType::kDatabaseAccess:
+      return frame ? frame->FrameScheduler()->SuspendableTaskRunner()
+                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
     case TaskType::kDOMManipulation:
     case TaskType::kHistoryTraversal:
     case TaskType::kEmbed:
@@ -52,18 +54,18 @@
     case TaskType::kWebGL:
     case TaskType::kUnspecedTimer:
     case TaskType::kMiscPlatformAPI:
-      // TODO(altimin): Move appropriate tasks to throttleable task queue.
-      return frame ? frame->FrameScheduler()->DeferrableTaskRunner()
-                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
-    // PostedMessage can be used for navigation, so we shouldn't defer it
+      // TODO(altimin): Move all these tasks to suspendable or unthrottled
+      // task runner.
+      return frame
+                 ? frame->FrameScheduler()->UnthrottledButBlockableTaskRunner()
+                 : Platform::Current()->CurrentThread()->GetWebTaskRunner();
+    // PostedMessage can be used for navigation, so we shouldn't block it
     // when expecting a user gesture.
     case TaskType::kPostedMessage:
     // UserInteraction tasks should be run even when expecting a user gesture.
     case TaskType::kUserInteraction:
-      return frame ? frame->FrameScheduler()->PausableTaskRunner()
-                   : Platform::Current()->CurrentThread()->GetWebTaskRunner();
     case TaskType::kUnthrottled:
-      return frame ? frame->FrameScheduler()->UnpausableTaskRunner()
+      return frame ? frame->FrameScheduler()->UnthrottledTaskRunner()
                    : Platform::Current()->CurrentThread()->GetWebTaskRunner();
   }
   NOTREACHED();
diff --git a/third_party/WebKit/Source/core/editing/BUILD.gn b/third_party/WebKit/Source/core/editing/BUILD.gn
index f14c3796..0e6cbae 100644
--- a/third_party/WebKit/Source/core/editing/BUILD.gn
+++ b/third_party/WebKit/Source/core/editing/BUILD.gn
@@ -246,6 +246,8 @@
     "markers/TextMatchMarker.h",
     "markers/TextMatchMarkerListImpl.cpp",
     "markers/TextMatchMarkerListImpl.h",
+    "markers/UnsortedDocumentMarkerListEditor.cpp",
+    "markers/UnsortedDocumentMarkerListEditor.h",
     "serializers/HTMLInterchange.cpp",
     "serializers/HTMLInterchange.h",
     "serializers/MarkupAccumulator.cpp",
@@ -367,6 +369,7 @@
     "markers/SuggestionMarkerListImplTest.cpp",
     "markers/SuggestionMarkerTest.cpp",
     "markers/TextMatchMarkerListImplTest.cpp",
+    "markers/UnsortedDocumentMarkerListEditorTest.cpp",
     "serializers/StyledMarkupSerializerTest.cpp",
     "spellcheck/IdleSpellCheckCallbackTest.cpp",
     "spellcheck/SpellCheckTestBase.cpp",
diff --git a/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImpl.cpp b/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImpl.cpp
index 2574086..3aac516 100644
--- a/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImpl.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImpl.cpp
@@ -82,25 +82,6 @@
       markers_, start_offset, end_offset);
 }
 
-// TODO(rlanday): move to UnsortedDocumentMarkerListEditor.cpp.
-DocumentMarker* UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
-    const MarkerList& list,
-    unsigned start_offset,
-    unsigned end_offset) {
-  DCHECK_LE(start_offset, end_offset);
-
-  const auto it =
-      std::find_if(list.begin(), list.end(),
-                   [start_offset, end_offset](const DocumentMarker* marker) {
-                     return marker->StartOffset() < end_offset &&
-                            marker->EndOffset() > start_offset;
-                   });
-
-  if (it == list.end())
-    return nullptr;
-  return *it;
-}
-
 HeapVector<Member<DocumentMarker>>
 SuggestionMarkerListImpl::MarkersIntersectingRange(unsigned start_offset,
                                                    unsigned end_offset) const {
@@ -108,86 +89,18 @@
       markers_, start_offset, end_offset);
 }
 
-// TODO(rlanday): move to UnsortedDocumentMarkerListEditor.cpp.
-HeapVector<Member<DocumentMarker>>
-UnsortedDocumentMarkerListEditor::MarkersIntersectingRange(
-    const MarkerList& list,
-    unsigned start_offset,
-    unsigned end_offset) {
-  DCHECK_LE(start_offset, end_offset);
-
-  HeapVector<Member<DocumentMarker>> results;
-  std::copy_if(list.begin(), list.end(), std::back_inserter(results),
-               [start_offset, end_offset](const DocumentMarker* marker) {
-                 return marker->StartOffset() < end_offset &&
-                        marker->EndOffset() > start_offset;
-               });
-  return results;
-}
-
 bool SuggestionMarkerListImpl::MoveMarkers(int length,
                                            DocumentMarkerList* dst_list) {
   return UnsortedDocumentMarkerListEditor::MoveMarkers(&markers_, length,
                                                        dst_list);
 }
 
-// TODO(rlanday): move to UnsortedDocumentMarkerListEditor.cpp.
-bool UnsortedDocumentMarkerListEditor::MoveMarkers(
-    MarkerList* src_list,
-    int length,
-    DocumentMarkerList* dst_list) {
-  DCHECK_GT(length, 0);
-  bool did_move_marker = false;
-  unsigned end_offset = length - 1;
-
-  HeapVector<Member<DocumentMarker>> unmoved_markers;
-  for (auto it = src_list->begin(); it != src_list->end(); ++it) {
-    DocumentMarker& marker = **it;
-    if (marker.StartOffset() > end_offset) {
-      unmoved_markers.push_back(marker);
-      continue;
-    }
-
-    // If we're splitting a text node in the middle of a marker, remove the
-    // marker.
-    if (marker.EndOffset() > end_offset)
-      continue;
-
-    dst_list->Add(&marker);
-    did_move_marker = true;
-  }
-
-  *src_list = std::move(unmoved_markers);
-  return did_move_marker;
-}
-
 bool SuggestionMarkerListImpl::RemoveMarkers(unsigned start_offset,
                                              int length) {
   return UnsortedDocumentMarkerListEditor::RemoveMarkers(&markers_,
                                                          start_offset, length);
 }
 
-// TODO(rlanday): move to UnsortedDocumentMarkerListEditor.cpp.
-bool UnsortedDocumentMarkerListEditor::RemoveMarkers(MarkerList* list,
-                                                     unsigned start_offset,
-                                                     int length) {
-  // For an unsorted marker list, the quickest way to perform this operation is
-  // to build a new list with the markers that aren't being removed.
-  const unsigned end_offset = start_offset + length;
-  HeapVector<Member<DocumentMarker>> unremoved_markers;
-  for (const Member<DocumentMarker>& marker : *list) {
-    if (marker->EndOffset() <= start_offset ||
-        marker->StartOffset() >= end_offset) {
-      unremoved_markers.push_back(marker);
-      continue;
-    }
-  }
-
-  const bool did_remove_marker = (unremoved_markers.size() != list->size());
-  *list = std::move(unremoved_markers);
-  return did_remove_marker;
-}
-
 bool SuggestionMarkerListImpl::ShiftMarkers(const String& node_text,
                                             unsigned offset,
                                             unsigned old_length,
diff --git a/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImplTest.cpp b/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImplTest.cpp
index 00b7e2f5..ba1f84e 100644
--- a/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImplTest.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/SuggestionMarkerListImplTest.cpp
@@ -6,7 +6,6 @@
 
 #include "core/editing/markers/SuggestionMarker.h"
 #include "core/editing/markers/SuggestionMarkerReplacementScope.h"
-#include "core/editing/markers/UnsortedDocumentMarkerListEditor.h"
 #include "platform/heap/Handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -27,19 +26,6 @@
   Persistent<SuggestionMarkerListImpl> marker_list_;
 };
 
-// TODO(rlanday): split UnsortedDocumentMarkerListEditorTest into its own file.
-class UnsortedDocumentMarkerListEditorTest : public ::testing::Test {
- protected:
-  DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) {
-    return new SuggestionMarker(start_offset, end_offset, Vector<String>(),
-                                Color::kTransparent, Color::kTransparent,
-                                StyleableMarker::Thickness::kThin,
-                                Color::kTransparent);
-  }
-
-  PersistentHeapVector<Member<DocumentMarker>> marker_list_;
-};
-
 namespace {
 
 bool compare_markers(const Member<DocumentMarker>& marker1,
@@ -105,182 +91,6 @@
   EXPECT_EQ(50u, markers[9]->EndOffset());
 }
 
-TEST_F(UnsortedDocumentMarkerListEditorTest,
-       FirstMarkerIntersectingRange_Empty) {
-  DocumentMarker* marker =
-      UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
-          marker_list_, 0, 10);
-  EXPECT_EQ(nullptr, marker);
-}
-
-TEST_F(UnsortedDocumentMarkerListEditorTest,
-       FirstMarkerIntersectingRange_TouchingStart) {
-  marker_list_.push_back(CreateMarker(1, 10));
-  marker_list_.push_back(CreateMarker(0, 10));
-
-  DocumentMarker* marker =
-      UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
-          marker_list_, 0, 1);
-
-  EXPECT_NE(nullptr, marker);
-  EXPECT_EQ(0u, marker->StartOffset());
-  EXPECT_EQ(10u, marker->EndOffset());
-}
-
-TEST_F(UnsortedDocumentMarkerListEditorTest,
-       FirstMarkerIntersectingRange_TouchingEnd) {
-  marker_list_.push_back(CreateMarker(0, 9));
-  marker_list_.push_back(CreateMarker(0, 10));
-
-  DocumentMarker* marker =
-      UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
-          marker_list_, 9, 10);
-
-  EXPECT_NE(nullptr, marker);
-  EXPECT_EQ(0u, marker->StartOffset());
-  EXPECT_EQ(10u, marker->EndOffset());
-}
-
-TEST_F(UnsortedDocumentMarkerListEditorTest,
-       MarkersIntersectingRange_TouchingStart) {
-  marker_list_.push_back(CreateMarker(0, 9));
-  marker_list_.push_back(CreateMarker(1, 9));
-  marker_list_.push_back(CreateMarker(0, 10));
-  marker_list_.push_back(CreateMarker(1, 10));
-
-  UnsortedDocumentMarkerListEditor::MarkerList markers_intersecting_range =
-      UnsortedDocumentMarkerListEditor::MarkersIntersectingRange(marker_list_,
-                                                                 0, 1);
-
-  EXPECT_EQ(2u, markers_intersecting_range.size());
-
-  EXPECT_EQ(0u, markers_intersecting_range[0]->StartOffset());
-  EXPECT_EQ(9u, markers_intersecting_range[0]->EndOffset());
-
-  EXPECT_EQ(0u, markers_intersecting_range[1]->StartOffset());
-  EXPECT_EQ(10u, markers_intersecting_range[1]->EndOffset());
-}
-
-TEST_F(UnsortedDocumentMarkerListEditorTest,
-       MarkersIntersectingRange_TouchingEnd) {
-  marker_list_.push_back(CreateMarker(0, 9));
-  marker_list_.push_back(CreateMarker(1, 9));
-  marker_list_.push_back(CreateMarker(0, 10));
-  marker_list_.push_back(CreateMarker(1, 10));
-
-  UnsortedDocumentMarkerListEditor::MarkerList markers_intersecting_range =
-      UnsortedDocumentMarkerListEditor::MarkersIntersectingRange(marker_list_,
-                                                                 9, 10);
-
-  EXPECT_EQ(2u, markers_intersecting_range.size());
-
-  EXPECT_EQ(0u, markers_intersecting_range[0]->StartOffset());
-  EXPECT_EQ(10u, markers_intersecting_range[0]->EndOffset());
-
-  EXPECT_EQ(1u, markers_intersecting_range[1]->StartOffset());
-  EXPECT_EQ(10u, markers_intersecting_range[1]->EndOffset());
-}
-
-TEST_F(UnsortedDocumentMarkerListEditorTest, MoveMarkers) {
-  marker_list_.push_back(CreateMarker(30, 40));
-  marker_list_.push_back(CreateMarker(0, 30));
-  marker_list_.push_back(CreateMarker(10, 40));
-  marker_list_.push_back(CreateMarker(0, 20));
-  marker_list_.push_back(CreateMarker(0, 40));
-  marker_list_.push_back(CreateMarker(20, 40));
-  marker_list_.push_back(CreateMarker(20, 30));
-  marker_list_.push_back(CreateMarker(0, 10));
-  marker_list_.push_back(CreateMarker(10, 30));
-  marker_list_.push_back(CreateMarker(10, 20));
-  marker_list_.push_back(CreateMarker(11, 21));
-
-  DocumentMarkerList* dst_list = new SuggestionMarkerListImpl();
-  // The markers with start and end offset < 11 should be moved to dst_list.
-  // Markers that start before 11 and end at 11 or later should be removed.
-  // Markers that start at 11 or later should not be moved.
-  UnsortedDocumentMarkerListEditor::MoveMarkers(&marker_list_, 11, dst_list);
-
-  std::sort(marker_list_.begin(), marker_list_.end(), compare_markers);
-
-  EXPECT_EQ(4u, marker_list_.size());
-
-  EXPECT_EQ(11u, marker_list_[0]->StartOffset());
-  EXPECT_EQ(21u, marker_list_[0]->EndOffset());
-
-  EXPECT_EQ(20u, marker_list_[1]->StartOffset());
-  EXPECT_EQ(30u, marker_list_[1]->EndOffset());
-
-  EXPECT_EQ(20u, marker_list_[2]->StartOffset());
-  EXPECT_EQ(40u, marker_list_[2]->EndOffset());
-
-  EXPECT_EQ(30u, marker_list_[3]->StartOffset());
-  EXPECT_EQ(40u, marker_list_[3]->EndOffset());
-
-  DocumentMarkerVector dst_list_markers = dst_list->GetMarkers();
-  std::sort(dst_list_markers.begin(), dst_list_markers.end(), compare_markers);
-
-  // Markers
-  EXPECT_EQ(1u, dst_list_markers.size());
-
-  EXPECT_EQ(0u, dst_list_markers[0]->StartOffset());
-  EXPECT_EQ(10u, dst_list_markers[0]->EndOffset());
-}
-
-TEST_F(UnsortedDocumentMarkerListEditorTest, RemoveMarkersEmptyList) {
-  EXPECT_FALSE(
-      UnsortedDocumentMarkerListEditor::RemoveMarkers(&marker_list_, 0, 10));
-  EXPECT_EQ(0u, marker_list_.size());
-}
-
-TEST_F(UnsortedDocumentMarkerListEditorTest, RemoveMarkersTouchingEndpoints) {
-  marker_list_.push_back(CreateMarker(30, 40));
-  marker_list_.push_back(CreateMarker(40, 50));
-  marker_list_.push_back(CreateMarker(10, 20));
-  marker_list_.push_back(CreateMarker(0, 10));
-  marker_list_.push_back(CreateMarker(20, 30));
-
-  EXPECT_TRUE(
-      UnsortedDocumentMarkerListEditor::RemoveMarkers(&marker_list_, 20, 10));
-
-  std::sort(marker_list_.begin(), marker_list_.end(), compare_markers);
-
-  EXPECT_EQ(4u, marker_list_.size());
-
-  EXPECT_EQ(0u, marker_list_[0]->StartOffset());
-  EXPECT_EQ(10u, marker_list_[0]->EndOffset());
-
-  EXPECT_EQ(10u, marker_list_[1]->StartOffset());
-  EXPECT_EQ(20u, marker_list_[1]->EndOffset());
-
-  EXPECT_EQ(30u, marker_list_[2]->StartOffset());
-  EXPECT_EQ(40u, marker_list_[2]->EndOffset());
-
-  EXPECT_EQ(40u, marker_list_[3]->StartOffset());
-  EXPECT_EQ(50u, marker_list_[3]->EndOffset());
-}
-
-TEST_F(UnsortedDocumentMarkerListEditorTest,
-       RemoveMarkersOneCharacterIntoInterior) {
-  marker_list_.push_back(CreateMarker(30, 40));
-  marker_list_.push_back(CreateMarker(40, 50));
-  marker_list_.push_back(CreateMarker(10, 20));
-  marker_list_.push_back(CreateMarker(0, 10));
-  marker_list_.push_back(CreateMarker(20, 30));
-
-  EXPECT_TRUE(
-      UnsortedDocumentMarkerListEditor::RemoveMarkers(&marker_list_, 19, 12));
-
-  std::sort(marker_list_.begin(), marker_list_.end(), compare_markers);
-
-  EXPECT_EQ(2u, marker_list_.size());
-
-  EXPECT_EQ(0u, marker_list_[0]->StartOffset());
-  EXPECT_EQ(10u, marker_list_[0]->EndOffset());
-
-  EXPECT_EQ(40u, marker_list_[1]->StartOffset());
-  EXPECT_EQ(50u, marker_list_[1]->EndOffset());
-}
-
 TEST_F(SuggestionMarkerListImplTest,
        ShiftMarkersForSuggestionReplacement_ReturnsFalseWhenNoShift) {
   marker_list_->Add(CreateMarker(0, 10));
diff --git a/third_party/WebKit/Source/core/editing/markers/UnsortedDocumentMarkerListEditor.cpp b/third_party/WebKit/Source/core/editing/markers/UnsortedDocumentMarkerListEditor.cpp
new file mode 100644
index 0000000..93dd7774
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/UnsortedDocumentMarkerListEditor.cpp
@@ -0,0 +1,93 @@
+// 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 "core/editing/markers/UnsortedDocumentMarkerListEditor.h"
+
+#include "core/editing/markers/SpellCheckMarkerListImpl.h"
+
+namespace blink {
+
+bool UnsortedDocumentMarkerListEditor::MoveMarkers(
+    MarkerList* src_list,
+    int length,
+    DocumentMarkerList* dst_list) {
+  DCHECK_GT(length, 0);
+  bool did_move_marker = false;
+  const unsigned end_offset = length - 1;
+
+  HeapVector<Member<DocumentMarker>> unmoved_markers;
+  for (DocumentMarker* marker : *src_list) {
+    if (marker->StartOffset() > end_offset) {
+      unmoved_markers.push_back(marker);
+      continue;
+    }
+
+    // If we're splitting a text node in the middle of a suggestion marker,
+    // remove the marker
+    if (marker->EndOffset() > end_offset)
+      continue;
+
+    dst_list->Add(marker);
+    did_move_marker = true;
+  }
+
+  *src_list = std::move(unmoved_markers);
+  return did_move_marker;
+}
+
+bool UnsortedDocumentMarkerListEditor::RemoveMarkers(MarkerList* list,
+                                                     unsigned start_offset,
+                                                     int length) {
+  // For an unsorted marker list, the quickest way to perform this operation is
+  // to build a new list with the markers that aren't being removed.
+  const unsigned end_offset = start_offset + length;
+  HeapVector<Member<DocumentMarker>> unremoved_markers;
+  for (const Member<DocumentMarker>& marker : *list) {
+    if (marker->EndOffset() <= start_offset ||
+        marker->StartOffset() >= end_offset) {
+      unremoved_markers.push_back(marker);
+      continue;
+    }
+  }
+
+  const bool did_remove_marker = (unremoved_markers.size() != list->size());
+  *list = std::move(unremoved_markers);
+  return did_remove_marker;
+}
+
+DocumentMarker* UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
+    const MarkerList& list,
+    unsigned start_offset,
+    unsigned end_offset) {
+  DCHECK_LE(start_offset, end_offset);
+
+  const auto it =
+      std::find_if(list.begin(), list.end(),
+                   [start_offset, end_offset](const DocumentMarker* marker) {
+                     return marker->StartOffset() < end_offset &&
+                            marker->EndOffset() > start_offset;
+                   });
+
+  if (it == list.end())
+    return nullptr;
+  return *it;
+}
+
+HeapVector<Member<DocumentMarker>>
+UnsortedDocumentMarkerListEditor::MarkersIntersectingRange(
+    const MarkerList& list,
+    unsigned start_offset,
+    unsigned end_offset) {
+  DCHECK_LE(start_offset, end_offset);
+
+  HeapVector<Member<DocumentMarker>> results;
+  std::copy_if(list.begin(), list.end(), std::back_inserter(results),
+               [start_offset, end_offset](const DocumentMarker* marker) {
+                 return marker->StartOffset() < end_offset &&
+                        marker->EndOffset() > start_offset;
+               });
+  return results;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/UnsortedDocumentMarkerListEditorTest.cpp b/third_party/WebKit/Source/core/editing/markers/UnsortedDocumentMarkerListEditorTest.cpp
new file mode 100644
index 0000000..e94c832
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/UnsortedDocumentMarkerListEditorTest.cpp
@@ -0,0 +1,213 @@
+// 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 "core/editing/markers/UnsortedDocumentMarkerListEditor.h"
+
+#include "core/editing/markers/SuggestionMarker.h"
+#include "core/editing/markers/SuggestionMarkerListImpl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+class UnsortedDocumentMarkerListEditorTest : public ::testing::Test {
+ protected:
+  DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) {
+    return new SuggestionMarker(start_offset, end_offset, Vector<String>(),
+                                Color::kTransparent, Color::kTransparent,
+                                StyleableMarker::Thickness::kThin,
+                                Color::kTransparent);
+  }
+
+  PersistentHeapVector<Member<DocumentMarker>> marker_list_;
+};
+
+namespace {
+
+bool compare_markers(const Member<DocumentMarker>& marker1,
+                     const Member<DocumentMarker>& marker2) {
+  if (marker1->StartOffset() != marker2->StartOffset())
+    return marker1->StartOffset() < marker2->StartOffset();
+
+  return marker1->EndOffset() < marker2->EndOffset();
+}
+
+}  // namespace
+
+TEST_F(UnsortedDocumentMarkerListEditorTest, MoveMarkers) {
+  marker_list_.push_back(CreateMarker(30, 40));
+  marker_list_.push_back(CreateMarker(0, 30));
+  marker_list_.push_back(CreateMarker(10, 40));
+  marker_list_.push_back(CreateMarker(0, 20));
+  marker_list_.push_back(CreateMarker(0, 40));
+  marker_list_.push_back(CreateMarker(20, 40));
+  marker_list_.push_back(CreateMarker(20, 30));
+  marker_list_.push_back(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(10, 30));
+  marker_list_.push_back(CreateMarker(10, 20));
+  marker_list_.push_back(CreateMarker(11, 21));
+
+  DocumentMarkerList* dst_list = new SuggestionMarkerListImpl();
+  // The markers with start and end offset < 11 should be moved to dst_list.
+  // Markers that start before 11 and end at 11 or later should be removed.
+  // Markers that start at 11 or later should not be moved.
+  UnsortedDocumentMarkerListEditor::MoveMarkers(&marker_list_, 11, dst_list);
+
+  std::sort(marker_list_.begin(), marker_list_.end(), compare_markers);
+
+  EXPECT_EQ(4u, marker_list_.size());
+
+  EXPECT_EQ(11u, marker_list_[0]->StartOffset());
+  EXPECT_EQ(21u, marker_list_[0]->EndOffset());
+
+  EXPECT_EQ(20u, marker_list_[1]->StartOffset());
+  EXPECT_EQ(30u, marker_list_[1]->EndOffset());
+
+  EXPECT_EQ(20u, marker_list_[2]->StartOffset());
+  EXPECT_EQ(40u, marker_list_[2]->EndOffset());
+
+  EXPECT_EQ(30u, marker_list_[3]->StartOffset());
+  EXPECT_EQ(40u, marker_list_[3]->EndOffset());
+
+  DocumentMarkerVector dst_list_markers = dst_list->GetMarkers();
+  std::sort(dst_list_markers.begin(), dst_list_markers.end(), compare_markers);
+
+  // Markers
+  EXPECT_EQ(1u, dst_list_markers.size());
+
+  EXPECT_EQ(0u, dst_list_markers[0]->StartOffset());
+  EXPECT_EQ(10u, dst_list_markers[0]->EndOffset());
+}
+
+TEST_F(UnsortedDocumentMarkerListEditorTest, RemoveMarkersEmptyList) {
+  EXPECT_FALSE(
+      UnsortedDocumentMarkerListEditor::RemoveMarkers(&marker_list_, 0, 10));
+  EXPECT_EQ(0u, marker_list_.size());
+}
+
+TEST_F(UnsortedDocumentMarkerListEditorTest, RemoveMarkersTouchingEndpoints) {
+  marker_list_.push_back(CreateMarker(30, 40));
+  marker_list_.push_back(CreateMarker(40, 50));
+  marker_list_.push_back(CreateMarker(10, 20));
+  marker_list_.push_back(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(20, 30));
+
+  EXPECT_TRUE(
+      UnsortedDocumentMarkerListEditor::RemoveMarkers(&marker_list_, 20, 10));
+
+  std::sort(marker_list_.begin(), marker_list_.end(), compare_markers);
+
+  EXPECT_EQ(4u, marker_list_.size());
+
+  EXPECT_EQ(0u, marker_list_[0]->StartOffset());
+  EXPECT_EQ(10u, marker_list_[0]->EndOffset());
+
+  EXPECT_EQ(10u, marker_list_[1]->StartOffset());
+  EXPECT_EQ(20u, marker_list_[1]->EndOffset());
+
+  EXPECT_EQ(30u, marker_list_[2]->StartOffset());
+  EXPECT_EQ(40u, marker_list_[2]->EndOffset());
+
+  EXPECT_EQ(40u, marker_list_[3]->StartOffset());
+  EXPECT_EQ(50u, marker_list_[3]->EndOffset());
+}
+
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       RemoveMarkersOneCharacterIntoInterior) {
+  marker_list_.push_back(CreateMarker(30, 40));
+  marker_list_.push_back(CreateMarker(40, 50));
+  marker_list_.push_back(CreateMarker(10, 20));
+  marker_list_.push_back(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(20, 30));
+
+  EXPECT_TRUE(
+      UnsortedDocumentMarkerListEditor::RemoveMarkers(&marker_list_, 19, 12));
+
+  std::sort(marker_list_.begin(), marker_list_.end(), compare_markers);
+
+  EXPECT_EQ(2u, marker_list_.size());
+
+  EXPECT_EQ(0u, marker_list_[0]->StartOffset());
+  EXPECT_EQ(10u, marker_list_[0]->EndOffset());
+
+  EXPECT_EQ(40u, marker_list_[1]->StartOffset());
+  EXPECT_EQ(50u, marker_list_[1]->EndOffset());
+}
+
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       FirstMarkerIntersectingRange_Empty) {
+  DocumentMarker* marker =
+      UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
+          marker_list_, 0, 10);
+  EXPECT_EQ(nullptr, marker);
+}
+
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       FirstMarkerIntersectingRange_TouchingStart) {
+  marker_list_.push_back(CreateMarker(1, 10));
+  marker_list_.push_back(CreateMarker(0, 10));
+
+  DocumentMarker* marker =
+      UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
+          marker_list_, 0, 1);
+
+  EXPECT_NE(nullptr, marker);
+  EXPECT_EQ(0u, marker->StartOffset());
+  EXPECT_EQ(10u, marker->EndOffset());
+}
+
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       FirstMarkerIntersectingRange_TouchingEnd) {
+  marker_list_.push_back(CreateMarker(0, 9));
+  marker_list_.push_back(CreateMarker(0, 10));
+
+  DocumentMarker* marker =
+      UnsortedDocumentMarkerListEditor::FirstMarkerIntersectingRange(
+          marker_list_, 9, 10);
+
+  EXPECT_NE(nullptr, marker);
+  EXPECT_EQ(0u, marker->StartOffset());
+  EXPECT_EQ(10u, marker->EndOffset());
+}
+
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       MarkersIntersectingRange_TouchingStart) {
+  marker_list_.push_back(CreateMarker(0, 9));
+  marker_list_.push_back(CreateMarker(1, 9));
+  marker_list_.push_back(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(1, 10));
+
+  UnsortedDocumentMarkerListEditor::MarkerList markers_intersecting_range =
+      UnsortedDocumentMarkerListEditor::MarkersIntersectingRange(marker_list_,
+                                                                 0, 1);
+
+  EXPECT_EQ(2u, markers_intersecting_range.size());
+
+  EXPECT_EQ(0u, markers_intersecting_range[0]->StartOffset());
+  EXPECT_EQ(9u, markers_intersecting_range[0]->EndOffset());
+
+  EXPECT_EQ(0u, markers_intersecting_range[1]->StartOffset());
+  EXPECT_EQ(10u, markers_intersecting_range[1]->EndOffset());
+}
+
+TEST_F(UnsortedDocumentMarkerListEditorTest,
+       MarkersIntersectingRange_TouchingEnd) {
+  marker_list_.push_back(CreateMarker(0, 9));
+  marker_list_.push_back(CreateMarker(1, 9));
+  marker_list_.push_back(CreateMarker(0, 10));
+  marker_list_.push_back(CreateMarker(1, 10));
+
+  UnsortedDocumentMarkerListEditor::MarkerList markers_intersecting_range =
+      UnsortedDocumentMarkerListEditor::MarkersIntersectingRange(marker_list_,
+                                                                 9, 10);
+
+  EXPECT_EQ(2u, markers_intersecting_range.size());
+
+  EXPECT_EQ(0u, markers_intersecting_range[0]->StartOffset());
+  EXPECT_EQ(10u, markers_intersecting_range[0]->EndOffset());
+
+  EXPECT_EQ(1u, markers_intersecting_range[1]->StartOffset());
+  EXPECT_EQ(10u, markers_intersecting_range[1]->EndOffset());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp
index 81e8a7a2..57106a7c 100644
--- a/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.cpp
@@ -102,15 +102,6 @@
   self_keep_alive_.Clear();
 }
 
-WebString WebRemoteFrameImpl::AssignedName() const {
-  NOTREACHED();
-  return WebString();
-}
-
-void WebRemoteFrameImpl::SetName(const WebString&) {
-  NOTREACHED();
-}
-
 WebRect WebRemoteFrameImpl::VisibleContentRect() const {
   NOTREACHED();
   return WebRect();
diff --git a/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.h b/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.h
index f0c3987..6556994a 100644
--- a/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebRemoteFrameImpl.h
@@ -34,8 +34,6 @@
 
   // WebFrame methods:
   void Close() override;
-  WebString AssignedName() const override;
-  void SetName(const WebString&) override;
   WebRect VisibleContentRect() const override;
   WebView* View() const override;
   void StopLoading() override;
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index 19ed7324..dc87f868 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -1085,19 +1085,7 @@
   if (!IsCurrentlyDisplayedInFrame())
     return;
 
-  // Avoid calling out to notify the embedder if the browsing context name
-  // didn't change. This is important to avoid violating the browser assumption
-  // that the unique name doesn't change if the browsing context name doesn't
-  // change.
-  // TODO(dcheng): This comment is indicative of a problematic layering
-  // violation. The browser should not be relying on the renderer to get this
-  // correct; unique name calculation should be moved up into the browser.
-  if (name == GetFrame()->Tree().GetName())
-    return;
-
-  GetFrame()->Tree().SetName(name);
-  DCHECK(GetFrame()->Client());
-  GetFrame()->Client()->DidChangeName(name);
+  GetFrame()->Tree().SetName(name, FrameTree::kReplicate);
 }
 
 void LocalDOMWindow::setStatus(const String& string) {
diff --git a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
index cb39dc87..55a5a46e 100644
--- a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
@@ -543,7 +543,7 @@
 }
 
 void WebLocalFrameImpl::SetName(const WebString& name) {
-  GetFrame()->Tree().SetName(name);
+  GetFrame()->Tree().SetName(name, FrameTree::kReplicate);
 }
 
 WebVector<WebIconURL> WebLocalFrameImpl::IconURLs(int icon_types_mask) const {
@@ -1583,7 +1583,13 @@
         ->SetSandboxFlags(static_cast<SandboxFlags>(flags));
     ToRemoteFrameOwner(new_frame->Owner())
         ->SetContainerPolicy(container_policy);
+  } else if (!new_frame->Owner()) {
+    // Provisional main frames need to force sandbox flags.  This is necessary
+    // to inherit sandbox flags when a sandboxed frame does a window.open()
+    // which triggers a cross-process navigation.
+    new_frame->Loader().ForceSandboxFlags(static_cast<SandboxFlags>(flags));
   }
+
   return web_frame;
 }
 
@@ -2431,7 +2437,7 @@
 SingleThreadTaskRunner* WebLocalFrameImpl::TimerTaskRunner() {
   return GetFrame()
       ->FrameScheduler()
-      ->ThrottleableTaskRunner()
+      ->TimerTaskRunner()
       ->ToSingleThreadTaskRunner();
 }
 
@@ -2445,7 +2451,7 @@
 SingleThreadTaskRunner* WebLocalFrameImpl::UnthrottledTaskRunner() {
   return GetFrame()
       ->FrameScheduler()
-      ->PausableTaskRunner()
+      ->UnthrottledTaskRunner()
       ->ToSingleThreadTaskRunner();
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.cpp
index 0b7d5b7..04c4028 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorPerformanceAgent.cpp
@@ -6,6 +6,7 @@
 
 #include "core/frame/LocalFrame.h"
 #include "core/inspector/InspectedFrames.h"
+#include "core/loader/DocumentLoader.h"
 #include "core/paint/PaintTiming.h"
 #include "core/probe/CoreProbes.h"
 #include "platform/InstanceCounters.h"
@@ -82,6 +83,9 @@
   std::unique_ptr<protocol::Array<protocol::Performance::Metric>> result =
       protocol::Array<protocol::Performance::Metric>::create();
 
+  AppendMetric(result.get(), "Timestamp",
+               (TimeTicks::Now() - TimeTicks()).InSecondsF());
+
   // Renderer instance counters.
   for (size_t i = 0; i < ARRAY_SIZE(kInstanceCounterNames); ++i) {
     AppendMetric(result.get(), kInstanceCounterNames[i],
@@ -101,12 +105,12 @@
   // Performance timings.
   Document* document = inspected_frames_->Root()->GetDocument();
   if (document) {
-    const PaintTiming& paint_timing = PaintTiming::From(*document);
     AppendMetric(result.get(), "FirstMeaningfulPaint",
-                 paint_timing.FirstMeaningfulPaint());
-    const DocumentTiming& document_timing = document->GetTiming();
+                 PaintTiming::From(*document).FirstMeaningfulPaint());
     AppendMetric(result.get(), "DomContentLoaded",
-                 document_timing.DomContentLoadedEventStart());
+                 document->GetTiming().DomContentLoadedEventStart());
+    AppendMetric(result.get(), "NavigationStart",
+                 document->Loader()->GetTiming().NavigationStart());
   }
 
   *out_result = std::move(result);
diff --git a/third_party/WebKit/Source/core/loader/BaseFetchContext.cpp b/third_party/WebKit/Source/core/loader/BaseFetchContext.cpp
index ce3ddb6..b1e3fe43 100644
--- a/third_party/WebKit/Source/core/loader/BaseFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/BaseFetchContext.cpp
@@ -252,10 +252,7 @@
             embedding_origin->Protocol())) {
       CountDeprecation(WebFeature::kLegacyProtocolEmbeddedAsSubresource);
 
-      // TODO(mkwst): Enabled by default in M59. Drop the runtime-enabled check
-      // in M60: https://www.chromestatus.com/feature/5709390967472128
-      if (RuntimeEnabledFeatures::BlockLegacySubresourcesEnabled())
-        return ResourceRequestBlockedReason::kOrigin;
+      return ResourceRequestBlockedReason::kOrigin;
     }
 
     if (ShouldBlockFetchAsCredentialedSubresource(resource_request, url))
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.cpp b/third_party/WebKit/Source/core/loader/EmptyClients.cpp
index ad449af..4f034592 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.cpp
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.cpp
@@ -76,10 +76,10 @@
   void SetFrameVisible(bool) override {}
   RefPtr<WebTaskRunner> LoadingTaskRunner() override;
   RefPtr<WebTaskRunner> LoadingControlTaskRunner() override;
-  RefPtr<WebTaskRunner> ThrottleableTaskRunner() override;
-  RefPtr<WebTaskRunner> DeferrableTaskRunner() override;
-  RefPtr<WebTaskRunner> PausableTaskRunner() override;
-  RefPtr<WebTaskRunner> UnpausableTaskRunner() override;
+  RefPtr<WebTaskRunner> TimerTaskRunner() override;
+  RefPtr<WebTaskRunner> UnthrottledTaskRunner() override;
+  RefPtr<WebTaskRunner> SuspendableTaskRunner() override;
+  RefPtr<WebTaskRunner> UnthrottledButBlockableTaskRunner() override;
 };
 
 RefPtr<WebTaskRunner> EmptyFrameScheduler::LoadingTaskRunner() {
@@ -90,19 +90,19 @@
   return Platform::Current()->MainThread()->GetWebTaskRunner();
 }
 
-RefPtr<WebTaskRunner> EmptyFrameScheduler::ThrottleableTaskRunner() {
+RefPtr<WebTaskRunner> EmptyFrameScheduler::TimerTaskRunner() {
   return Platform::Current()->MainThread()->GetWebTaskRunner();
 }
 
-RefPtr<WebTaskRunner> EmptyFrameScheduler::DeferrableTaskRunner() {
+RefPtr<WebTaskRunner> EmptyFrameScheduler::UnthrottledTaskRunner() {
   return Platform::Current()->MainThread()->GetWebTaskRunner();
 }
 
-RefPtr<WebTaskRunner> EmptyFrameScheduler::PausableTaskRunner() {
+RefPtr<WebTaskRunner> EmptyFrameScheduler::SuspendableTaskRunner() {
   return Platform::Current()->MainThread()->GetWebTaskRunner();
 }
 
-RefPtr<WebTaskRunner> EmptyFrameScheduler::UnpausableTaskRunner() {
+RefPtr<WebTaskRunner> EmptyFrameScheduler::UnthrottledButBlockableTaskRunner() {
   return Platform::Current()->MainThread()->GetWebTaskRunner();
 }
 
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 5bb08b5..2b21539 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -125,23 +125,6 @@
   return type == kFrameLoadTypeBackForward || IsReloadLoadType(type);
 }
 
-static void CheckForLegacyProtocolInSubresource(
-    const ResourceRequest& resource_request,
-    Document* document) {
-  if (resource_request.GetFrameType() == WebURLRequest::kFrameTypeTopLevel)
-    return;
-  if (!SchemeRegistry::ShouldTreatURLSchemeAsLegacy(
-          resource_request.Url().Protocol())) {
-    return;
-  }
-  if (SchemeRegistry::ShouldTreatURLSchemeAsLegacy(
-          document->GetSecurityOrigin()->Protocol())) {
-    return;
-  }
-  Deprecation::CountDeprecation(
-      document, WebFeature::kLegacyProtocolEmbeddedAsSubresource);
-}
-
 static NavigationPolicy MaybeCheckCSP(
     const ResourceRequest& request,
     NavigationType type,
@@ -1535,13 +1518,6 @@
     // is available while sending the request.
     probe::frameClearedScheduledClientNavigation(frame_);
   } else {
-    // PlzNavigate
-    // Check for usage of legacy schemes now. Unsupported schemes will be
-    // rewritten by the client, so the FrameFetchContext will not be able to
-    // check for those when the navigation commits.
-    if (navigation_policy == kNavigationPolicyHandledByClient)
-      CheckForLegacyProtocolInSubresource(resource_request,
-                                          frame_->GetDocument());
     probe::frameScheduledClientNavigation(frame_);
   }
 
diff --git a/third_party/WebKit/Source/core/page/FrameTree.cpp b/third_party/WebKit/Source/core/page/FrameTree.cpp
index d12d5c44..95ae447 100644
--- a/third_party/WebKit/Source/core/page/FrameTree.cpp
+++ b/third_party/WebKit/Source/core/page/FrameTree.cpp
@@ -23,6 +23,7 @@
 #include "core/dom/Document.h"
 #include "core/frame/FrameClient.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/LocalFrameClient.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/RemoteFrame.h"
 #include "core/frame/RemoteFrameView.h"
@@ -72,7 +73,24 @@
   experimental_set_nulled_name_ = true;
 }
 
-void FrameTree::SetName(const AtomicString& name) {
+void FrameTree::SetName(const AtomicString& name,
+                        ReplicationPolicy replication) {
+  if (replication == kReplicate) {
+    // Avoid calling out to notify the embedder if the browsing context name
+    // didn't change. This is important to avoid violating the browser
+    // assumption that the unique name doesn't change if the browsing context
+    // name doesn't change.
+    // TODO(dcheng): This comment is indicative of a problematic layering
+    // violation. The browser should not be relying on the renderer to get this
+    // correct; unique name calculation should be moved up into the browser.
+    if (name != name_) {
+      // TODO(lukasza): https://crbug.com/660485: Eventually we need to also
+      // support replication of name changes that originate in a *remote* frame.
+      DCHECK(this_frame_->IsLocalFrame());
+      ToLocalFrame(this_frame_)->Client()->DidChangeName(name);
+    }
+  }
+
   // TODO(andypaicu): remove this once we have gathered the data
   experimental_set_nulled_name_ = false;
   name_ = name;
diff --git a/third_party/WebKit/Source/core/page/FrameTree.h b/third_party/WebKit/Source/core/page/FrameTree.h
index 07ab236..5916ea1 100644
--- a/third_party/WebKit/Source/core/page/FrameTree.h
+++ b/third_party/WebKit/Source/core/page/FrameTree.h
@@ -37,7 +37,15 @@
   ~FrameTree();
 
   const AtomicString& GetName() const;
-  void SetName(const AtomicString&);
+
+  enum ReplicationPolicy {
+    // Does not propagate name changes beyond this FrameTree object.
+    kDoNotReplicate,
+
+    // Kicks-off propagation of name changes to other renderers.
+    kReplicate,
+  };
+  void SetName(const AtomicString&, ReplicationPolicy = kDoNotReplicate);
 
   // TODO(andypaicu): remove this once we have gathered the data
   void ExperimentalSetNulledName();
diff --git a/third_party/WebKit/Source/core/timing/PerformanceServerTiming.idl b/third_party/WebKit/Source/core/timing/PerformanceServerTiming.idl
index e1ce24a..3bc1dbd1 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceServerTiming.idl
+++ b/third_party/WebKit/Source/core/timing/PerformanceServerTiming.idl
@@ -5,7 +5,8 @@
 // https://w3c.github.io/server-timing/
 
 [
-    RuntimeEnabled=ServerTiming
+    RuntimeEnabled=ServerTiming,
+    Exposed=(Window,Worker)
 ] interface PerformanceServerTiming {
     readonly attribute DOMString name;
     readonly attribute DOMHighResTimeStamp duration;
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceMonitor.js b/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceMonitor.js
index 9af417b..dec33cae 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceMonitor.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/PerformanceMonitor.js
@@ -17,7 +17,7 @@
     this._pixelsPerMs = 20 / 1000;
     /** @const */
     this._pollIntervalMs = 500;
-    this._gridColor = 'hsla(0, 0%, 0%, 0.08)';
+    this._gridColor = 'rgba(0, 0, 0, 0.08)';
     this._controlPane = new Timeline.PerformanceMonitor.ControlPane(this.contentElement);
     this._canvas = /** @type {!HTMLCanvasElement} */ (this.contentElement.createChild('canvas'));
   }
@@ -57,18 +57,18 @@
   }
 
   /**
-   * @param {!Array<!Protocol.Performance.Metric>} metrics
+   * @param {!Array<!Protocol.Performance.Metric>} rawMetrics
    */
-  _processMetrics(metrics) {
-    var metricsMap = new Map();
+  _processMetrics(rawMetrics) {
+    var metrics = new Map();
     var timestamp = performance.now();
-    for (var metric of metrics) {
+    for (var metric of rawMetrics) {
       var info = this._controlPane.metricInfo(metric.name);
       var value;
       switch (info.mode) {
         case Timeline.PerformanceMonitor.Mode.CumulativeTime:
           value = info.lastTimestamp ?
-              100 * Number.constrain((metric.value - info.lastValue) * 1000 / (timestamp - info.lastTimestamp), 0, 1) :
+              Number.constrain((metric.value - info.lastValue) * 1000 / (timestamp - info.lastTimestamp), 0, 1) :
               0;
           info.lastValue = metric.value;
           info.lastTimestamp = timestamp;
@@ -84,17 +84,15 @@
           value = metric.value;
           break;
       }
-      metricsMap.set(metric.name, value);
+      metrics.set(metric.name, value);
     }
-    if (!this._metricsBuffer.length)
-      this._startTimestamp = timestamp;
-    this._metricsBuffer.push({timestamp, metrics: metricsMap});
+    this._metricsBuffer.push({timestamp, metrics: metrics});
     var millisPerWidth = this._width / this._pixelsPerMs;
     // Multiply by 2 as the pollInterval has some jitter and to have some extra samples if window is resized.
     var maxCount = Math.ceil(millisPerWidth / this._pollIntervalMs * 2);
     if (this._metricsBuffer.length > maxCount * 2)  // Multiply by 2 to have a hysteresis.
       this._metricsBuffer.splice(0, this._metricsBuffer.length - maxCount);
-    this._controlPane.updateMetrics(metricsMap);
+    this._controlPane.updateMetrics(metrics);
   }
 
   _draw() {
@@ -132,21 +130,19 @@
    * @param {!CanvasRenderingContext2D} ctx
    */
   _drawGrid(ctx) {
-    if (!this._startTimestamp)
-      return;
-    var lightGray = 'hsla(0, 0%, 0%, 0.02)';
-    ctx.font = '10px ' + Host.fontFamily();
+    var lightGray = 'rgba(0, 0, 0, 0.02)';
+    ctx.font = '9px ' + Host.fontFamily();
     ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
-    var duration = performance.now() - this._startTimestamp;
-    for (var sec = Math.floor(duration / 1000); sec >= 0; --sec) {
-      var x = this._width - (duration - sec * 1000 - this._pollIntervalMs) * this._pixelsPerMs;
-      if (x < -40)
+    var currentTime = Date.now() / 1000;
+    for (var sec = Math.ceil(currentTime);; --sec) {
+      var x = this._width - ((currentTime - sec) * 1000 - this._pollIntervalMs) * this._pixelsPerMs;
+      if (x < -50)
         break;
       ctx.beginPath();
       ctx.moveTo(Math.round(x) + 0.5, 0);
       ctx.lineTo(Math.round(x) + 0.5, this._height);
-      if (sec % 5 === 0)
-        ctx.fillText(Common.UIString('%d sec', sec), Math.round(x) + 4, 12);
+      if (sec >= 0 && sec % 5 === 0)
+        ctx.fillText(new Date(sec * 1000).toLocaleTimeString(), Math.round(x) + 4, 12);
       ctx.strokeStyle = sec % 5 ? lightGray : this._gridColor;
       ctx.stroke();
     }
@@ -338,7 +334,7 @@
           title: Common.UIString('CPU utilization'),
           color: 'red',
           mode: Timeline.PerformanceMonitor.Mode.CumulativeTime,
-          max: 100
+          max: 1
         }
       ],
       [
@@ -346,14 +342,14 @@
           title: Common.UIString('Script duration'),
           color: 'orange',
           mode: Timeline.PerformanceMonitor.Mode.CumulativeTime,
-          max: 100
+          max: 1
         }
       ],
       [
         'LayoutDuration', {
           title: Common.UIString('Layout duration'),
           color: 'magenta',
-          max: 100,
+          max: 1,
           mode: Timeline.PerformanceMonitor.Mode.CumulativeTime
         }
       ],
@@ -361,7 +357,7 @@
         'RecalcStyleDuration', {
           title: Common.UIString('Style recalc duration'),
           color: 'violet',
-          max: 100,
+          max: 1,
           mode: Timeline.PerformanceMonitor.Mode.CumulativeTime
         }
       ],
@@ -469,8 +465,8 @@
    */
   static _formatNumber(value, info) {
     return info.mode === Timeline.PerformanceMonitor.Mode.CumulativeTime ?
-        value.toFixed() + '%' :
-        Timeline.PerformanceMonitor.MetricIndicator._format.format(value);
+        value.toLocaleString('en-US', {maximumFractionDigits: 1, style: 'percent'}) :
+        value.toLocaleString('en-US', {maximumFractionDigits: 1});
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/performanceMonitor.css b/third_party/WebKit/Source/devtools/front_end/timeline/performanceMonitor.css
index c7126af1..d8d4e15 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/performanceMonitor.css
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/performanceMonitor.css
@@ -45,6 +45,10 @@
   flex: 0 0 115px;
 }
 
+.perfmon-indicator:not(.active) .perfmon-indicator-title {
+  color: #aaa;
+}
+
 .perfmon-indicator-value {
   flex: 0 0 44px;
   text-align: right;
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index 4c10cdc0..ca95437 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -119,10 +119,6 @@
       status: "stable",
     },
     {
-      name: "BlockLegacySubresources",
-      status: "stable",
-    },
-    {
       name: "BroadcastChannel",
       status: "stable",
     },
@@ -704,7 +700,7 @@
     },
     {
       name: "NavigatorDeviceMemory",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "NetInfoDownlink",
diff --git a/third_party/WebKit/Source/platform/TimerTest.cpp b/third_party/WebKit/Source/platform/TimerTest.cpp
index e024dac8..4fc596d 100644
--- a/third_party/WebKit/Source/platform/TimerTest.cpp
+++ b/third_party/WebKit/Source/platform/TimerTest.cpp
@@ -539,7 +539,7 @@
 TEST_F(TimerTest, UserSuppliedWebTaskRunner) {
   scoped_refptr<scheduler::TaskQueue> task_runner(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner =
       scheduler::WebTaskRunnerImpl::Create(task_runner);
   TimerForTest<TimerTest> timer(web_task_runner, this,
@@ -627,7 +627,7 @@
 
   scoped_refptr<scheduler::TaskQueue> task_runner1(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner1 =
       scheduler::WebTaskRunnerImpl::Create(task_runner1);
   TaskObserver task_observer1(web_task_runner1, &run_order);
@@ -635,7 +635,7 @@
 
   scoped_refptr<scheduler::TaskQueue> task_runner2(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner2 =
       scheduler::WebTaskRunnerImpl::Create(task_runner2);
   TaskObserver task_observer2(web_task_runner2, &run_order);
@@ -667,7 +667,7 @@
 
   scoped_refptr<scheduler::TaskQueue> task_runner1(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner1 =
       scheduler::WebTaskRunnerImpl::Create(task_runner1);
   TaskObserver task_observer1(web_task_runner1, &run_order);
@@ -675,7 +675,7 @@
 
   scoped_refptr<scheduler::TaskQueue> task_runner2(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner2 =
       scheduler::WebTaskRunnerImpl::Create(task_runner2);
   TaskObserver task_observer2(web_task_runner2, &run_order);
@@ -709,13 +709,13 @@
 TEST_F(TimerTest, MoveToNewTaskRunnerWithoutTasks) {
   scoped_refptr<scheduler::TaskQueue> task_runner1(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner1 =
       scheduler::WebTaskRunnerImpl::Create(task_runner1);
 
   scoped_refptr<scheduler::TaskQueue> task_runner2(
       platform_->GetRendererScheduler()->NewTimerTaskQueue(
-          scheduler::MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE));
+          scheduler::MainThreadTaskQueue::QueueType::FRAME_TIMER));
   RefPtr<scheduler::WebTaskRunnerImpl> web_task_runner2 =
       scheduler::WebTaskRunnerImpl::Create(task_runner2);
 
diff --git a/third_party/WebKit/Source/platform/WebFrameScheduler.h b/third_party/WebKit/Source/platform/WebFrameScheduler.h
index 237a9dc..a08537f4 100644
--- a/third_party/WebKit/Source/platform/WebFrameScheduler.h
+++ b/third_party/WebKit/Source/platform/WebFrameScheduler.h
@@ -69,53 +69,21 @@
   virtual void SetCrossOrigin(bool) {}
 
   // The tasks runners below are listed in increasing QoS order.
-  // - throttleable task queue. Designed for custom user-provided javascript
-  //   tasks. Lowest guarantees. Can be paused, blocked during user gesture,
-  //   throttled when backgrounded or stopped completely after some time in
-  //   background.
-  // - deferrable task queue. These tasks can be deferred for a small period
-  //   (several seconds) when high-priority work is anticipated. These tasks
-  //   can be paused.
-  // - pausable task queue. Default queue for high-priority javascript tasks.
-  //   They can be paused according to the spec during javascript alert
-  //   dialogs, printing windows and devtools debugging. Otherwise scheduler
-  //   does not tamper with their execution.
-  // - unpausable task queue. Should be used for control tasks which should
-  //   run when the context is paused. Usage should be extremely rare.
-  //   Please consult scheduler-dev@ before using it. Running javascript
-  //   on it is strictly verboten and can lead to hard-to-diagnose errors.
-  //
-  //
-  // These queues below are separate due to special handling for their
-  // priorities.
-  // - loading task queue. Similar to deferrable task queue. Throttling might
-  //   be considered in the future.
-  // - loading control task queue. Loading task queue with increased priority
-  //   to run small loading tasks which schedule other loading tasks.
-
-  // Note: old-style timer task runner corresponds to throttleable task runner
-  // and unthrottled task runner corresponds to pausable task runner.
-
-  // Returns a WebTaskRunner for throtteable tasks, e.g. javascript timers.
-  // WebFrameScheduler owns the returned WebTaskRunner.
-  virtual RefPtr<WebTaskRunner> ThrottleableTaskRunner() = 0;
-
-  // Returns a WebTaskRunner for tasks which can be deferred for several
-  // seconds due to anticipated high-priority work like user gesture.
-  virtual RefPtr<WebTaskRunner> DeferrableTaskRunner() = 0;
-
-  // Returns a WebTaskRunner for high-priority javascript tasks. They run
-  // unrestricted in most cases except context pausing (e.g. alert dialog).
-  virtual RefPtr<WebTaskRunner> PausableTaskRunner() = 0;
-
-  // Returns a WebTaskRunner for tasks which should run during context pausing.
-  // The usage should be rare and limited to tasks controlling context pausing
-  // and unpausing.
-  virtual RefPtr<WebTaskRunner> UnpausableTaskRunner() = 0;
-
-  // Returns the WebTaskRunner for loading tasks.
-  // WebFrameScheduler owns the returned WebTaskRunner.
-  virtual RefPtr<WebTaskRunner> LoadingTaskRunner() = 0;
+  // - timer task queue. Designed for custom user-provided javascript tasks.
+  //   Lowest guarantees. Can be suspended, blocked during user gesture or
+  //   throttled when backgrounded.
+  // - loading task queue. Can be suspended or blocked during user gesture.
+  //   Throttling might be considered in the future.
+  // - suspendable task queue. Can be suspended and blocked during user gesture,
+  //   can't be throttled.
+  // - unthrottled-but-blockable task queue. Can't be throttled, can't
+  //   be suspended but can be blocked during user gesture.
+  //   NOTE: existence of this queue is a temporary fix for scroll latency
+  //   regression. All tasks should be moved from this queue to suspendable
+  //   or unthrottled queues and it should be deleted.
+  // - unthrottled task queue. Highest guarantees. Can't be throttled,
+  //   suspended or blocked. Should be used only when necessary after
+  //   consulting scheduler-dev@.
 
   // Return a WebTaskRunner for very short control messages between loading
   // tasks. Caution is needed when posting tasks to this WebTaskRunner because
@@ -123,6 +91,36 @@
   // WebFrameScheduler owns the returned WebTaskRunner.
   virtual RefPtr<WebTaskRunner> LoadingControlTaskRunner() = 0;
 
+  // Returns the WebTaskRunner for timer tasks.
+  // WebFrameScheduler owns the returned WebTaskRunner.
+  virtual RefPtr<WebTaskRunner> TimerTaskRunner() = 0;
+
+  // Returns the WebTaskRunner for loading tasks.
+  // WebFrameScheduler owns the returned WebTaskRunner.
+  virtual RefPtr<WebTaskRunner> LoadingTaskRunner() = 0;
+
+  // Returns the WebTaskRunner for tasks which shouldn't get throttled,
+  // but can be suspended.
+  // TODO(altimin): This is a transitional task runner. Unthrottled task runner
+  // would become suspendable in the nearest future and a new unsuspended
+  // task runner will be added.
+  virtual RefPtr<WebTaskRunner> SuspendableTaskRunner() = 0;
+
+  // Retuns the WebTaskRunner for tasks which should not be suspended or
+  // throttled, but should be blocked during user gesture.
+  // This is a temporary task runner needed for a fix for touch latency
+  // regression. All tasks from it should be moved to suspendable or
+  // unthrottled task runner.
+  virtual RefPtr<WebTaskRunner> UnthrottledButBlockableTaskRunner() = 0;
+
+  // Returns the WebTaskRunner for tasks which should never get throttled.
+  // This is generally used for executing internal browser tasks which should
+  // never be throttled. Ideally only tasks whose performance characteristics
+  // are known should be posted to this task runner; for example user
+  // JavaScript is discouraged. WebFrameScheduler owns the returned
+  // WebTaskRunner.
+  virtual RefPtr<WebTaskRunner> UnthrottledTaskRunner() = 0;
+
   // Returns the parent WebViewScheduler.
   virtual WebViewScheduler* GetWebViewScheduler() { return nullptr; }
 
diff --git a/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h b/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
index e5c9802..d30afd3 100644
--- a/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
+++ b/third_party/WebKit/Source/platform/loader/testing/MockFetchContext.h
@@ -96,14 +96,16 @@
         : runner_(std::move(runner)) {}
     void AddThrottlingObserver(ObserverType, Observer*) override {}
     void RemoveThrottlingObserver(ObserverType, Observer*) override {}
+    RefPtr<WebTaskRunner> TimerTaskRunner() override { return runner_; }
     RefPtr<WebTaskRunner> LoadingTaskRunner() override { return runner_; }
     RefPtr<WebTaskRunner> LoadingControlTaskRunner() override {
       return runner_;
     }
-    RefPtr<WebTaskRunner> ThrottleableTaskRunner() override { return runner_; }
-    RefPtr<WebTaskRunner> DeferrableTaskRunner() override { return runner_; }
-    RefPtr<WebTaskRunner> PausableTaskRunner() override { return runner_; }
-    RefPtr<WebTaskRunner> UnpausableTaskRunner() override { return runner_; }
+    RefPtr<WebTaskRunner> SuspendableTaskRunner() override { return runner_; }
+    RefPtr<WebTaskRunner> UnthrottledTaskRunner() override { return runner_; }
+    RefPtr<WebTaskRunner> UnthrottledButBlockableTaskRunner() override {
+      return runner_;
+    }
 
    private:
     RefPtr<WebTaskRunner> runner_;
diff --git a/third_party/WebKit/Source/platform/scheduler/BUILD.gn b/third_party/WebKit/Source/platform/scheduler/BUILD.gn
index 0685a99..c18975f 100644
--- a/third_party/WebKit/Source/platform/scheduler/BUILD.gn
+++ b/third_party/WebKit/Source/platform/scheduler/BUILD.gn
@@ -114,6 +114,7 @@
     "renderer/web_view_scheduler_impl.h",
     "renderer/webthread_impl_for_renderer_scheduler.cc",
     "renderer/webthread_impl_for_renderer_scheduler.h",
+    "util/state_tracer.h",
     "utility/webthread_impl_for_utility_thread.cc",
     "utility/webthread_impl_for_utility_thread.h",
   ]
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc
index ade141c..e2fd7ddc 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/budget_pool_unittest.cc
@@ -134,7 +134,7 @@
       task_queue_throttler_->CreateWakeUpBudgetPool("test");
 
   scoped_refptr<TaskQueue> queue = scheduler_->NewTimerTaskQueue(
-      MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
+      MainThreadTaskQueue::QueueType::FRAME_TIMER);
 
   pool->SetWakeUpRate(0.1);
   pool->SetWakeUpDuration(base::TimeDelta::FromMilliseconds(10));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
index e3a7de42..ac3c659a 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
@@ -26,14 +26,10 @@
       return "unthrottled_tq";
     case MainThreadTaskQueue::QueueType::FRAME_LOADING:
       return "frame_loading_tq";
-    case MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE:
-      return "frame_throttleable_tq";
-    case MainThreadTaskQueue::QueueType::FRAME_DEFERRABLE:
-      return "frame_deferrable_tq";
-    case MainThreadTaskQueue::QueueType::FRAME_PAUSABLE:
-      return "frame_pausable_tq";
-    case MainThreadTaskQueue::QueueType::FRAME_UNPAUSABLE:
-      return "frame_unpausable_tq";
+    case MainThreadTaskQueue::QueueType::FRAME_TIMER:
+      return "frame_timer_tq";
+    case MainThreadTaskQueue::QueueType::FRAME_UNTHROTTLED:
+      return "frame_unthrottled_tq";
     case MainThreadTaskQueue::QueueType::COMPOSITOR:
       return "compositor_tq";
     case MainThreadTaskQueue::QueueType::IDLE:
@@ -63,11 +59,11 @@
     case QueueType::FRAME_LOADING_CONTROL:
       return QueueClass::LOADING;
     case QueueType::DEFAULT_TIMER:
+    case QueueType::FRAME_TIMER:
+    // Unthrottled tasks are considered timers which can't be throttled and
+    // fall into TIMER class.
+    case QueueType::FRAME_UNTHROTTLED:
     case QueueType::UNTHROTTLED:
-    case QueueType::FRAME_THROTTLEABLE:
-    case QueueType::FRAME_DEFERRABLE:
-    case QueueType::FRAME_PAUSABLE:
-    case QueueType::FRAME_UNPAUSABLE:
       return QueueClass::TIMER;
     case QueueType::COMPOSITOR:
       return QueueClass::COMPOSITOR;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.h b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.h
index 21d90ae8..b014ee9e 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.h
@@ -20,28 +20,20 @@
   enum class QueueType {
     // Keep MainThreadTaskQueue::NameForQueueType in sync.
     // This enum is used for a histogram and it should not be re-numbered.
-    // TODO(altimin): Clean up obsolete names and use a new histogram when
-    // the situation settles.
     CONTROL = 0,
     DEFAULT = 1,
     DEFAULT_LOADING = 2,
-    // DEFAULT_TIMER is deprecated and should be replaced with appropriate
-    // per-frame task queues.
     DEFAULT_TIMER = 3,
     UNTHROTTLED = 4,
     FRAME_LOADING = 5,
-    // 6 : FRAME_THROTTLEABLE, replaced with FRAME_THROTTLEABLE.
-    // 7 : FRAME_PAUSABLE, replaced with FRAME_PAUSABLE
+    FRAME_TIMER = 6,
+    FRAME_UNTHROTTLED = 7,
     COMPOSITOR = 8,
     IDLE = 9,
     TEST = 10,
     FRAME_LOADING_CONTROL = 11,
-    FRAME_THROTTLEABLE = 12,
-    FRAME_DEFERRABLE = 13,
-    FRAME_PAUSABLE = 14,
-    FRAME_UNPAUSABLE = 15,
 
-    COUNT = 16
+    COUNT = 12
   };
 
   // Returns name of the given queue type. Returned string has application
@@ -70,7 +62,7 @@
           can_be_stopped(false),
           used_for_control_tasks(false) {}
 
-    QueueCreationParams SetCanBeDeferred(bool value) {
+    QueueCreationParams SetCanBeBlocked(bool value) {
       can_be_blocked = value;
       return *this;
     }
@@ -134,7 +126,7 @@
 
   QueueClass queue_class() const { return queue_class_; }
 
-  bool CanBeDeferred() const { return can_be_blocked_; }
+  bool CanBeBlocked() const { return can_be_blocked_; }
 
   bool CanBeThrottled() const { return can_be_throttled_; }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc
index bfeb1562..18e7557 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper_unittest.cc
@@ -20,7 +20,6 @@
 
 using QueueType = MainThreadTaskQueue::QueueType;
 using testing::ElementsAre;
-using testing::UnorderedElementsAre;
 using base::Bucket;
 
 class RendererMetricsHelperTest : public ::testing::Test {
@@ -89,7 +88,7 @@
           base::TimeDelta::FromMilliseconds(5));
   RunTask(QueueType::FRAME_LOADING, Milliseconds(800),
           base::TimeDelta::FromMilliseconds(70));
-  RunTask(QueueType::FRAME_PAUSABLE, Milliseconds(1000),
+  RunTask(QueueType::FRAME_UNTHROTTLED, Milliseconds(1000),
           base::TimeDelta::FromMilliseconds(20));
   RunTask(QueueType::COMPOSITOR, Milliseconds(1200),
           base::TimeDelta::FromMilliseconds(25));
@@ -100,13 +99,13 @@
 
   RunTask(QueueType::CONTROL, Milliseconds(2000),
           base::TimeDelta::FromMilliseconds(25));
-  RunTask(QueueType::FRAME_THROTTLEABLE, Milliseconds(2600),
+  RunTask(QueueType::FRAME_TIMER, Milliseconds(2600),
           base::TimeDelta::FromMilliseconds(175));
   RunTask(QueueType::UNTHROTTLED, Milliseconds(2800),
           base::TimeDelta::FromMilliseconds(25));
   RunTask(QueueType::FRAME_LOADING, Milliseconds(3000),
           base::TimeDelta::FromMilliseconds(35));
-  RunTask(QueueType::FRAME_THROTTLEABLE, Milliseconds(3200),
+  RunTask(QueueType::FRAME_TIMER, Milliseconds(3200),
           base::TimeDelta::FromMilliseconds(5));
   RunTask(QueueType::COMPOSITOR, Milliseconds(3400),
           base::TimeDelta::FromMilliseconds(20));
@@ -116,9 +115,9 @@
           base::TimeDelta::FromMilliseconds(5));
   RunTask(QueueType::CONTROL, Milliseconds(4200),
           base::TimeDelta::FromMilliseconds(20));
-  RunTask(QueueType::FRAME_THROTTLEABLE, Milliseconds(4400),
+  RunTask(QueueType::FRAME_TIMER, Milliseconds(4400),
           base::TimeDelta::FromMilliseconds(115));
-  RunTask(QueueType::FRAME_PAUSABLE, Milliseconds(4600),
+  RunTask(QueueType::FRAME_UNTHROTTLED, Milliseconds(4600),
           base::TimeDelta::FromMilliseconds(175));
   RunTask(QueueType::IDLE, Milliseconds(5000),
           base::TimeDelta::FromMilliseconds(1600));
@@ -130,37 +129,37 @@
       {static_cast<int>(QueueType::DEFAULT_TIMER), 5},
       {static_cast<int>(QueueType::UNTHROTTLED), 25},
       {static_cast<int>(QueueType::FRAME_LOADING), 105},
+      {static_cast<int>(QueueType::FRAME_TIMER), 295},
+      {static_cast<int>(QueueType::FRAME_UNTHROTTLED), 195},
       {static_cast<int>(QueueType::COMPOSITOR), 45},
       {static_cast<int>(QueueType::IDLE), 1650},
       {static_cast<int>(QueueType::TEST), 85},
-      {static_cast<int>(QueueType::FRAME_LOADING_CONTROL), 5},
-      {static_cast<int>(QueueType::FRAME_THROTTLEABLE), 295},
-      {static_cast<int>(QueueType::FRAME_PAUSABLE), 195}};
+      {static_cast<int>(QueueType::FRAME_LOADING_CONTROL), 5}};
   EXPECT_THAT(histogram_tester_->GetAllSamples(
                   "RendererScheduler.TaskDurationPerQueueType2"),
               testing::ContainerEq(expected_samples));
 
-  EXPECT_THAT(histogram_tester_->GetAllSamples(
-                  "RendererScheduler.TaskDurationPerQueueType2.Foreground"),
-              UnorderedElementsAre(
-                  Bucket(static_cast<int>(QueueType::CONTROL), 30),
+  EXPECT_THAT(
+      histogram_tester_->GetAllSamples(
+          "RendererScheduler.TaskDurationPerQueueType2.Foreground"),
+      ElementsAre(Bucket(static_cast<int>(QueueType::CONTROL), 30),
                   Bucket(static_cast<int>(QueueType::DEFAULT), 2),
                   Bucket(static_cast<int>(QueueType::DEFAULT_LOADING), 20),
                   Bucket(static_cast<int>(QueueType::DEFAULT_TIMER), 5),
                   Bucket(static_cast<int>(QueueType::FRAME_LOADING), 70),
+                  Bucket(static_cast<int>(QueueType::FRAME_UNTHROTTLED), 20),
                   Bucket(static_cast<int>(QueueType::COMPOSITOR), 25),
-                  Bucket(static_cast<int>(QueueType::TEST), 85),
-                  Bucket(static_cast<int>(QueueType::FRAME_PAUSABLE), 20)));
+                  Bucket(static_cast<int>(QueueType::TEST), 85)));
 
   EXPECT_THAT(
       histogram_tester_->GetAllSamples(
           "RendererScheduler.TaskDurationPerQueueType2.Background"),
-      UnorderedElementsAre(
+      ElementsAre(
           Bucket(static_cast<int>(QueueType::CONTROL), 45),
           Bucket(static_cast<int>(QueueType::UNTHROTTLED), 25),
           Bucket(static_cast<int>(QueueType::FRAME_LOADING), 35),
-          Bucket(static_cast<int>(QueueType::FRAME_THROTTLEABLE), 295),
-          Bucket(static_cast<int>(QueueType::FRAME_PAUSABLE), 175),
+          Bucket(static_cast<int>(QueueType::FRAME_TIMER), 295),
+          Bucket(static_cast<int>(QueueType::FRAME_UNTHROTTLED), 175),
           Bucket(static_cast<int>(QueueType::COMPOSITOR), 20),
           Bucket(static_cast<int>(QueueType::IDLE), 1650),
           Bucket(static_cast<int>(QueueType::FRAME_LOADING_CONTROL), 5)));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
index c099903..44ea41c 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -53,6 +53,14 @@
 constexpr base::TimeDelta kQueueingTimeWindowDuration =
     base::TimeDelta::FromSeconds(1);
 
+const char* BackgroundStateToString(bool is_backgrounded) {
+  if (is_backgrounded) {
+    return "backgrounded";
+  } else {
+    return "foregrounded";
+  }
+}
+
 }  // namespace
 
 RendererSchedulerImpl::RendererSchedulerImpl(
@@ -197,7 +205,10 @@
       rail_mode_observer(nullptr),
       wake_up_budget_pool(nullptr),
       metrics_helper(renderer_scheduler_impl, now, renderer_backgrounded),
-      process_type(RendererProcessType::kRenderer) {}
+      process_type(RendererProcessType::kRenderer),
+      use_case_tracer("RendererScheduler.UseCase", renderer_scheduler_impl),
+      backgrounding_tracer("RendererScheduler.Backgrounded",
+                           renderer_scheduler_impl) {}
 
 RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {}
 
@@ -319,11 +330,6 @@
   if (task_queue->CanBeThrottled())
     AddQueueToWakeUpBudgetPool(task_queue.get());
 
-  if (queue_class == MainThreadTaskQueue::QueueClass::TIMER) {
-    if (main_thread_only().virtual_time_stopped)
-      task_queue->InsertFence(TaskQueue::InsertFencePosition::NOW);
-  }
-
   return task_queue;
 }
 
@@ -334,7 +340,7 @@
   return NewTaskQueue(
       MainThreadTaskQueue::QueueCreationParams(queue_type)
           .SetCanBePaused(true)
-          .SetCanBeDeferred(true)
+          .SetCanBeBlocked(true)
           .SetUsedForControlTasks(
               queue_type ==
               MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL));
@@ -344,12 +350,16 @@
     MainThreadTaskQueue::QueueType queue_type) {
   DCHECK_EQ(MainThreadTaskQueue::QueueClassForQueueType(queue_type),
             MainThreadTaskQueue::QueueClass::TIMER);
-  return NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(queue_type)
-                          .SetShouldReportWhenExecutionBlocked(true)
-                          .SetCanBePaused(true)
-                          .SetCanBeStopped(true)
-                          .SetCanBeDeferred(true)
-                          .SetCanBeThrottled(true));
+  auto timer_task_queue =
+      NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(queue_type)
+                       .SetShouldReportWhenExecutionBlocked(true)
+                       .SetCanBePaused(true)
+                       .SetCanBeStopped(true)
+                       .SetCanBeBlocked(true)
+                       .SetCanBeThrottled(true));
+  if (main_thread_only().virtual_time_stopped)
+    timer_task_queue->InsertFence(TaskQueue::InsertFencePosition::NOW);
+  return timer_task_queue;
 }
 
 std::unique_ptr<RenderWidgetSchedulingState>
@@ -535,6 +545,8 @@
   if (helper_.IsShutdown() ||
       main_thread_only().renderer_backgrounded == backgrounded)
     return;
+  main_thread_only().backgrounding_tracer.SetState(
+      BackgroundStateToString(main_thread_only().renderer_backgrounded));
 
   main_thread_only().renderer_backgrounded = backgrounded;
   if (!backgrounded)
@@ -928,6 +940,8 @@
 
   base::TimeDelta expected_use_case_duration;
   UseCase use_case = ComputeCurrentUseCase(now, &expected_use_case_duration);
+  if (main_thread_only().current_use_case != use_case)
+    main_thread_only().use_case_tracer.SetState(UseCaseToString(use_case));
   main_thread_only().current_use_case = use_case;
 
   base::TimeDelta touchstart_expected_flag_valid_for_duration;
@@ -1574,7 +1588,7 @@
     return false;
   if (is_paused && task_queue->CanBePaused())
     return false;
-  if (is_blocked && task_queue->CanBeDeferred())
+  if (is_blocked && task_queue->CanBeBlocked())
     return false;
   if (is_stopped && task_queue->CanBeStopped())
     return false;
@@ -2020,6 +2034,11 @@
 
 void RendererSchedulerImpl::OnTraceLogEnabled() {
   CreateTraceEventObjectSnapshot();
+
+  main_thread_only().use_case_tracer.Start(
+      UseCaseToString(main_thread_only().current_use_case));
+  main_thread_only().backgrounding_tracer.Start(
+      BackgroundStateToString(main_thread_only().renderer_backgrounded));
 }
 
 void RendererSchedulerImpl::OnTraceLogDisabled() {}
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
index 95c9ed6..65436d230 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
@@ -29,6 +29,7 @@
 #include "platform/scheduler/renderer/task_cost_estimator.h"
 #include "platform/scheduler/renderer/user_model.h"
 #include "platform/scheduler/renderer/web_view_scheduler_impl.h"
+#include "platform/scheduler/util/state_tracer.h"
 #include "public/platform/scheduler/renderer/renderer_scheduler.h"
 
 namespace base {
@@ -594,6 +595,8 @@
     WakeUpBudgetPool* wake_up_budget_pool;                // Not owned.
     RendererMetricsHelper metrics_helper;
     RendererProcessType process_type;
+    StateTracer use_case_tracer;
+    StateTracer backgrounding_tracer;
   };
 
   struct AnyThread {
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
index f650780..eb6f4fc 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -3769,7 +3769,7 @@
   scoped_refptr<TaskQueue> loading_control_tq = scheduler_->NewLoadingTaskQueue(
       MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL);
   scoped_refptr<MainThreadTaskQueue> timer_tq = scheduler_->NewTimerTaskQueue(
-      MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
+      MainThreadTaskQueue::QueueType::FRAME_TIMER);
   scoped_refptr<MainThreadTaskQueue> unthrottled_tq =
       scheduler_->NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
           MainThreadTaskQueue::QueueType::UNTHROTTLED));
@@ -3801,11 +3801,10 @@
           ->NewLoadingTaskQueue(MainThreadTaskQueue::QueueType::FRAME_LOADING)
           ->GetTimeDomain(),
       scheduler_->GetVirtualTimeDomain());
-  EXPECT_EQ(scheduler_
-                ->NewTimerTaskQueue(
-                    MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE)
-                ->GetTimeDomain(),
-            scheduler_->GetVirtualTimeDomain());
+  EXPECT_EQ(
+      scheduler_->NewTimerTaskQueue(MainThreadTaskQueue::QueueType::FRAME_TIMER)
+          ->GetTimeDomain(),
+      scheduler_->GetVirtualTimeDomain());
   EXPECT_EQ(scheduler_
                 ->NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
                     MainThreadTaskQueue::QueueType::UNTHROTTLED))
@@ -3822,7 +3821,7 @@
   scheduler_->EnableVirtualTime();
 
   scoped_refptr<MainThreadTaskQueue> timer_tq = scheduler_->NewTimerTaskQueue(
-      MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
+      MainThreadTaskQueue::QueueType::FRAME_TIMER);
   scoped_refptr<MainThreadTaskQueue> unthrottled_tq =
       scheduler_->NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
           MainThreadTaskQueue::QueueType::UNTHROTTLED));
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc
index 9533f3d..84f6234 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler_unittest.cc
@@ -90,7 +90,7 @@
     scheduler_.reset(new RendererSchedulerImpl(delegate_));
     task_queue_throttler_ = scheduler_->task_queue_throttler();
     timer_queue_ = scheduler_->NewTimerTaskQueue(
-        MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
+        MainThreadTaskQueue::QueueType::FRAME_TIMER);
   }
 
   void TearDown() override {
@@ -745,7 +745,7 @@
   std::vector<base::TimeTicks> run_times;
 
   scoped_refptr<TaskQueue> second_queue = scheduler_->NewTimerTaskQueue(
-      MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
+      MainThreadTaskQueue::QueueType::FRAME_TIMER);
 
   CPUTimeBudgetPool* pool =
       task_queue_throttler_->CreateCPUTimeBudgetPool("test");
@@ -1071,7 +1071,7 @@
 
   scoped_refptr<MainThreadTaskQueue> second_queue =
       scheduler_->NewTimerTaskQueue(
-          MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
+          MainThreadTaskQueue::QueueType::FRAME_TIMER);
 
   task_queue_throttler_->IncreaseThrottleRefCount(timer_queue_.get());
   task_queue_throttler_->IncreaseThrottleRefCount(second_queue.get());
@@ -1107,7 +1107,7 @@
   std::vector<base::TimeTicks> run_times;
 
   scoped_refptr<TaskQueue> second_queue = scheduler_->NewTimerTaskQueue(
-      MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE);
+      MainThreadTaskQueue::QueueType::FRAME_TIMER);
 
   CPUTimeBudgetPool* pool1 =
       task_queue_throttler_->CreateCPUTimeBudgetPool("test");
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
index e51dbc3f9d..d56d3dec 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
@@ -46,29 +46,45 @@
       active_connection_count_(0),
       weak_factory_(this) {}
 
-namespace {
-
-void CleanUpQueue(MainThreadTaskQueue* queue) {
-  if (!queue)
-    return;
-  queue->UnregisterTaskQueue();
-  queue->SetFrameScheduler(nullptr);
-  queue->SetBlameContext(nullptr);
-}
-
-}  // namespace
-
 WebFrameSchedulerImpl::~WebFrameSchedulerImpl() {
   weak_factory_.InvalidateWeakPtrs();
 
-  RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool();
+  if (loading_task_queue_) {
+    loading_task_queue_->UnregisterTaskQueue();
+    loading_task_queue_->SetFrameScheduler(nullptr);
+    loading_task_queue_->SetBlameContext(nullptr);
+  }
 
-  CleanUpQueue(loading_task_queue_.get());
-  CleanUpQueue(loading_control_task_queue_.get());
-  CleanUpQueue(throttleable_task_queue_.get());
-  CleanUpQueue(deferrable_task_queue_.get());
-  CleanUpQueue(pausable_task_queue_.get());
-  CleanUpQueue(unpausable_task_queue_.get());
+  if (loading_control_task_queue_) {
+    loading_control_task_queue_->UnregisterTaskQueue();
+    loading_control_task_queue_->SetFrameScheduler(nullptr);
+    loading_control_task_queue_->SetBlameContext(nullptr);
+  }
+
+  if (timer_task_queue_) {
+    RemoveTimerQueueFromBackgroundCPUTimeBudgetPool();
+    timer_task_queue_->UnregisterTaskQueue();
+    timer_task_queue_->SetFrameScheduler(nullptr);
+    timer_task_queue_->SetBlameContext(nullptr);
+  }
+
+  if (unthrottled_task_queue_) {
+    unthrottled_task_queue_->UnregisterTaskQueue();
+    unthrottled_task_queue_->SetFrameScheduler(nullptr);
+    unthrottled_task_queue_->SetBlameContext(nullptr);
+  }
+
+  if (suspendable_task_queue_) {
+    suspendable_task_queue_->UnregisterTaskQueue();
+    suspendable_task_queue_->SetFrameScheduler(nullptr);
+    suspendable_task_queue_->SetBlameContext(nullptr);
+  }
+
+  if (unthrottled_but_blockable_task_queue_) {
+    unthrottled_but_blockable_task_queue_->UnregisterTaskQueue();
+    unthrottled_but_blockable_task_queue_->SetFrameScheduler(nullptr);
+    unthrottled_but_blockable_task_queue_->SetBlameContext(nullptr);
+  }
 
   if (parent_web_view_scheduler_) {
     parent_web_view_scheduler_->Unregister(this);
@@ -79,14 +95,13 @@
 }
 
 void WebFrameSchedulerImpl::DetachFromWebViewScheduler() {
-  RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool();
+  RemoveTimerQueueFromBackgroundCPUTimeBudgetPool();
 
   parent_web_view_scheduler_ = nullptr;
 }
 
-void WebFrameSchedulerImpl::
-    RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool() {
-  if (!throttleable_task_queue_)
+void WebFrameSchedulerImpl::RemoveTimerQueueFromBackgroundCPUTimeBudgetPool() {
+  if (!timer_task_queue_)
     return;
 
   if (!parent_web_view_scheduler_)
@@ -99,7 +114,7 @@
     return;
 
   time_budget_pool->RemoveQueue(renderer_scheduler_->tick_clock()->NowTicks(),
-                                throttleable_task_queue_.get());
+                                timer_task_queue_.get());
 }
 
 void WebFrameSchedulerImpl::AddThrottlingObserver(ObserverType type,
@@ -127,7 +142,7 @@
     return;
   bool was_throttled = ShouldThrottleTimers();
   frame_visible_ = frame_visible;
-  UpdateThrottling(was_throttled);
+  UpdateTimerThrottling(was_throttled);
 }
 
 void WebFrameSchedulerImpl::SetCrossOrigin(bool cross_origin) {
@@ -136,7 +151,7 @@
     return;
   bool was_throttled = ShouldThrottleTimers();
   cross_origin_ = cross_origin;
-  UpdateThrottling(was_throttled);
+  UpdateTimerThrottling(was_throttled);
 }
 
 RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::LoadingTaskRunner() {
@@ -144,8 +159,8 @@
   if (!loading_web_task_runner_) {
     loading_task_queue_ = renderer_scheduler_->NewLoadingTaskQueue(
         MainThreadTaskQueue::QueueType::FRAME_LOADING);
-    loading_task_queue_->SetBlameContext(blame_context_);
     loading_task_queue_->SetFrameScheduler(this);
+    loading_task_queue_->SetBlameContext(blame_context_);
     loading_queue_enabled_voter_ =
         loading_task_queue_->CreateQueueEnabledVoter();
     loading_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
@@ -159,8 +174,8 @@
   if (!loading_control_web_task_runner_) {
     loading_control_task_queue_ = renderer_scheduler_->NewLoadingTaskQueue(
         MainThreadTaskQueue::QueueType::FRAME_LOADING_CONTROL);
-    loading_control_task_queue_->SetBlameContext(blame_context_);
     loading_control_task_queue_->SetFrameScheduler(this);
+    loading_control_task_queue_->SetBlameContext(blame_context_);
     loading_control_queue_enabled_voter_ =
         loading_control_task_queue_->CreateQueueEnabledVoter();
     loading_control_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
@@ -170,90 +185,81 @@
   return loading_control_web_task_runner_;
 }
 
-RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::ThrottleableTaskRunner() {
+RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::TimerTaskRunner() {
   DCHECK(parent_web_view_scheduler_);
-  if (!throttleable_web_task_runner_) {
-    throttleable_task_queue_ = renderer_scheduler_->NewTaskQueue(
-        MainThreadTaskQueue::QueueCreationParams(
-            MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE)
-            .SetShouldReportWhenExecutionBlocked(true)
-            .SetCanBeThrottled(true)
-            .SetCanBeStopped(true)
-            .SetCanBeDeferred(true)
-            .SetCanBePaused(true));
-    throttleable_task_queue_->SetBlameContext(blame_context_);
-    throttleable_task_queue_->SetFrameScheduler(this);
-    throttleable_queue_enabled_voter_ =
-        throttleable_task_queue_->CreateQueueEnabledVoter();
-    throttleable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
+  if (!timer_web_task_runner_) {
+    timer_task_queue_ = renderer_scheduler_->NewTimerTaskQueue(
+        MainThreadTaskQueue::QueueType::FRAME_TIMER);
+    timer_task_queue_->SetFrameScheduler(this);
+    timer_task_queue_->SetBlameContext(blame_context_);
+    timer_queue_enabled_voter_ = timer_task_queue_->CreateQueueEnabledVoter();
+    timer_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
 
     CPUTimeBudgetPool* time_budget_pool =
         parent_web_view_scheduler_->BackgroundCPUTimeBudgetPool();
     if (time_budget_pool) {
       time_budget_pool->AddQueue(renderer_scheduler_->tick_clock()->NowTicks(),
-                                 throttleable_task_queue_.get());
+                                 timer_task_queue_.get());
     }
 
     if (ShouldThrottleTimers()) {
       renderer_scheduler_->task_queue_throttler()->IncreaseThrottleRefCount(
-          throttleable_task_queue_.get());
+          timer_task_queue_.get());
     }
-    throttleable_web_task_runner_ =
-        WebTaskRunnerImpl::Create(throttleable_task_queue_);
+    timer_web_task_runner_ = WebTaskRunnerImpl::Create(timer_task_queue_);
   }
-  return throttleable_web_task_runner_;
+  return timer_web_task_runner_;
 }
 
-RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::DeferrableTaskRunner() {
+RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::SuspendableTaskRunner() {
   DCHECK(parent_web_view_scheduler_);
-  if (!deferrable_web_task_runner_) {
-    deferrable_task_queue_ = renderer_scheduler_->NewTaskQueue(
+  if (!suspendable_web_task_runner_) {
+    // TODO(altimin): Split FRAME_UNTHROTTLED into FRAME_UNTHROTTLED and
+    // FRAME_UNSUSPENDED.
+    suspendable_task_queue_ = renderer_scheduler_->NewTaskQueue(
         MainThreadTaskQueue::QueueCreationParams(
-            MainThreadTaskQueue::QueueType::FRAME_THROTTLEABLE)
-            .SetShouldReportWhenExecutionBlocked(true)
-            .SetCanBeDeferred(true)
+            MainThreadTaskQueue::QueueType::FRAME_UNTHROTTLED)
+            .SetCanBeBlocked(true)
             .SetCanBePaused(true));
-    deferrable_task_queue_->SetBlameContext(blame_context_);
-    deferrable_task_queue_->SetFrameScheduler(this);
-    deferrable_web_task_runner_ =
-        WebTaskRunnerImpl::Create(deferrable_task_queue_);
-    deferrable_queue_enabled_voter_ =
-        deferrable_task_queue_->CreateQueueEnabledVoter();
-    deferrable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
+    suspendable_task_queue_->SetFrameScheduler(this);
+    suspendable_task_queue_->SetBlameContext(blame_context_);
+    suspendable_web_task_runner_ =
+        WebTaskRunnerImpl::Create(suspendable_task_queue_);
+    suspendable_queue_enabled_voter_ =
+        suspendable_task_queue_->CreateQueueEnabledVoter();
+    suspendable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
   }
-  return deferrable_web_task_runner_;
+  return suspendable_web_task_runner_;
 }
 
-RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::PausableTaskRunner() {
+RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::UnthrottledTaskRunner() {
   DCHECK(parent_web_view_scheduler_);
-  if (!pausable_web_task_runner_) {
-    pausable_task_queue_ = renderer_scheduler_->NewTaskQueue(
+  if (!unthrottled_web_task_runner_) {
+    unthrottled_task_queue_ = renderer_scheduler_->NewTaskQueue(
         MainThreadTaskQueue::QueueCreationParams(
-            MainThreadTaskQueue::QueueType::FRAME_PAUSABLE)
-            .SetShouldReportWhenExecutionBlocked(true)
-            .SetCanBePaused(true));
-    pausable_task_queue_->SetBlameContext(blame_context_);
-    pausable_task_queue_->SetFrameScheduler(this);
-    pausable_web_task_runner_ = WebTaskRunnerImpl::Create(pausable_task_queue_);
-    pausable_queue_enabled_voter_ =
-        pausable_task_queue_->CreateQueueEnabledVoter();
-    pausable_queue_enabled_voter_->SetQueueEnabled(!frame_paused_);
+            MainThreadTaskQueue::QueueType::FRAME_UNTHROTTLED));
+    unthrottled_task_queue_->SetFrameScheduler(this);
+    unthrottled_task_queue_->SetBlameContext(blame_context_);
+    unthrottled_web_task_runner_ =
+        WebTaskRunnerImpl::Create(unthrottled_task_queue_);
   }
-  return pausable_web_task_runner_;
+  return unthrottled_web_task_runner_;
 }
 
-RefPtr<blink::WebTaskRunner> WebFrameSchedulerImpl::UnpausableTaskRunner() {
+RefPtr<blink::WebTaskRunner>
+WebFrameSchedulerImpl::UnthrottledButBlockableTaskRunner() {
   DCHECK(parent_web_view_scheduler_);
-  if (!unpausable_web_task_runner_) {
-    unpausable_task_queue_ = renderer_scheduler_->NewTaskQueue(
+  if (!unthrottled_but_blockable_web_task_runner_) {
+    unthrottled_but_blockable_task_queue_ = renderer_scheduler_->NewTaskQueue(
         MainThreadTaskQueue::QueueCreationParams(
-            MainThreadTaskQueue::QueueType::FRAME_UNPAUSABLE));
-    unpausable_task_queue_->SetBlameContext(blame_context_);
-    unpausable_task_queue_->SetFrameScheduler(this);
-    unpausable_web_task_runner_ =
-        WebTaskRunnerImpl::Create(unpausable_task_queue_);
+            MainThreadTaskQueue::QueueType::FRAME_UNTHROTTLED)
+            .SetCanBeBlocked(true));
+    unthrottled_but_blockable_task_queue_->SetFrameScheduler(this);
+    unthrottled_but_blockable_task_queue_->SetBlameContext(blame_context_);
+    unthrottled_but_blockable_web_task_runner_ =
+        WebTaskRunnerImpl::Create(unthrottled_but_blockable_task_queue_);
   }
-  return unpausable_web_task_runner_;
+  return unthrottled_but_blockable_web_task_runner_;
 }
 
 blink::WebViewScheduler* WebFrameSchedulerImpl::GetWebViewScheduler() {
@@ -327,23 +333,18 @@
         "loading_control_task_queue",
         trace_helper::PointerToString(loading_control_task_queue_.get()));
   }
-  if (throttleable_task_queue_)
+  if (timer_task_queue_)
+    state->SetString("timer_task_queue",
+                     trace_helper::PointerToString(timer_task_queue_.get()));
+  if (unthrottled_task_queue_) {
     state->SetString(
-        "throttleable_task_queue",
-        trace_helper::PointerToString(throttleable_task_queue_.get()));
-  if (deferrable_task_queue_) {
-    state->SetString(
-        "deferrable_task_queue",
-        trace_helper::PointerToString(deferrable_task_queue_.get()));
+        "unthrottled_task_queue",
+        trace_helper::PointerToString(unthrottled_task_queue_.get()));
   }
-  if (pausable_task_queue_) {
-    state->SetString("pausable_task_queue",
-                     trace_helper::PointerToString(pausable_task_queue_.get()));
-  }
-  if (unpausable_task_queue_) {
+  if (suspendable_task_queue_) {
     state->SetString(
-        "unpausable_task_queue",
-        trace_helper::PointerToString(unpausable_task_queue_.get()));
+        "suspendable_task_queue",
+        trace_helper::PointerToString(suspendable_task_queue_.get()));
   }
   if (blame_context_) {
     state->BeginDictionary("blame_context");
@@ -361,7 +362,7 @@
     return;
   bool was_throttled = ShouldThrottleTimers();
   page_visible_ = page_visible;
-  UpdateThrottling(was_throttled);
+  UpdateTimerThrottling(was_throttled);
 
   for (auto observer : loader_observers_) {
     observer->OnThrottlingStateChanged(page_visible_
@@ -380,12 +381,10 @@
     loading_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
   if (loading_control_queue_enabled_voter_)
     loading_control_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
-  if (throttleable_queue_enabled_voter_)
-    throttleable_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
-  if (deferrable_queue_enabled_voter_)
-    deferrable_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
-  if (pausable_queue_enabled_voter_)
-    pausable_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
+  if (timer_queue_enabled_voter_)
+    timer_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
+  if (suspendable_queue_enabled_voter_)
+    suspendable_queue_enabled_voter_->SetQueueEnabled(!frame_paused);
 }
 
 void WebFrameSchedulerImpl::OnFirstMeaningfulPaint() {
@@ -405,16 +404,16 @@
          !frame_visible_ && cross_origin_;
 }
 
-void WebFrameSchedulerImpl::UpdateThrottling(bool was_throttled) {
+void WebFrameSchedulerImpl::UpdateTimerThrottling(bool was_throttled) {
   bool should_throttle = ShouldThrottleTimers();
-  if (was_throttled == should_throttle || !throttleable_web_task_runner_)
+  if (was_throttled == should_throttle || !timer_web_task_runner_)
     return;
   if (should_throttle) {
     renderer_scheduler_->task_queue_throttler()->IncreaseThrottleRefCount(
-        throttleable_task_queue_.get());
+        timer_task_queue_.get());
   } else {
     renderer_scheduler_->task_queue_throttler()->DecreaseThrottleRefCount(
-        throttleable_task_queue_.get());
+        timer_task_queue_.get());
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
index a746fd68..b42f137 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
@@ -49,10 +49,10 @@
   void SetCrossOrigin(bool cross_origin) override;
   RefPtr<WebTaskRunner> LoadingTaskRunner() override;
   RefPtr<WebTaskRunner> LoadingControlTaskRunner() override;
-  RefPtr<WebTaskRunner> ThrottleableTaskRunner() override;
-  RefPtr<WebTaskRunner> DeferrableTaskRunner() override;
-  RefPtr<WebTaskRunner> PausableTaskRunner() override;
-  RefPtr<WebTaskRunner> UnpausableTaskRunner() override;
+  RefPtr<WebTaskRunner> TimerTaskRunner() override;
+  RefPtr<WebTaskRunner> SuspendableTaskRunner() override;
+  RefPtr<WebTaskRunner> UnthrottledTaskRunner() override;
+  RefPtr<WebTaskRunner> UnthrottledButBlockableTaskRunner() override;
   WebViewScheduler* GetWebViewScheduler() override;
   void WillNavigateBackForwardSoon() override;
   void DidStartProvisionalLoad(bool is_main_frame) override;
@@ -84,10 +84,10 @@
   };
 
   void DetachFromWebViewScheduler();
-  void RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool();
-  void ApplyPolicyToThrottleableQueue();
+  void RemoveTimerQueueFromBackgroundCPUTimeBudgetPool();
+  void ApplyPolicyToTimerQueue();
   bool ShouldThrottleTimers() const;
-  void UpdateThrottling(bool was_throttled);
+  void UpdateTimerThrottling(bool was_throttled);
 
   void DidOpenActiveConnection();
   void DidCloseActiveConnection();
@@ -96,23 +96,22 @@
 
   scoped_refptr<MainThreadTaskQueue> loading_task_queue_;
   scoped_refptr<MainThreadTaskQueue> loading_control_task_queue_;
-  scoped_refptr<MainThreadTaskQueue> throttleable_task_queue_;
-  scoped_refptr<MainThreadTaskQueue> deferrable_task_queue_;
-  scoped_refptr<MainThreadTaskQueue> pausable_task_queue_;
-  scoped_refptr<MainThreadTaskQueue> unpausable_task_queue_;
+  scoped_refptr<MainThreadTaskQueue> timer_task_queue_;
+  scoped_refptr<MainThreadTaskQueue> unthrottled_task_queue_;
+  scoped_refptr<MainThreadTaskQueue> suspendable_task_queue_;
+  scoped_refptr<MainThreadTaskQueue> unthrottled_but_blockable_task_queue_;
   std::unique_ptr<TaskQueue::QueueEnabledVoter> loading_queue_enabled_voter_;
   std::unique_ptr<TaskQueue::QueueEnabledVoter>
       loading_control_queue_enabled_voter_;
+  std::unique_ptr<TaskQueue::QueueEnabledVoter> timer_queue_enabled_voter_;
   std::unique_ptr<TaskQueue::QueueEnabledVoter>
-      throttleable_queue_enabled_voter_;
-  std::unique_ptr<TaskQueue::QueueEnabledVoter> deferrable_queue_enabled_voter_;
-  std::unique_ptr<TaskQueue::QueueEnabledVoter> pausable_queue_enabled_voter_;
+      suspendable_queue_enabled_voter_;
   RefPtr<WebTaskRunnerImpl> loading_web_task_runner_;
   RefPtr<WebTaskRunnerImpl> loading_control_web_task_runner_;
-  RefPtr<WebTaskRunnerImpl> throttleable_web_task_runner_;
-  RefPtr<WebTaskRunnerImpl> deferrable_web_task_runner_;
-  RefPtr<WebTaskRunnerImpl> pausable_web_task_runner_;
-  RefPtr<WebTaskRunnerImpl> unpausable_web_task_runner_;
+  RefPtr<WebTaskRunnerImpl> timer_web_task_runner_;
+  RefPtr<WebTaskRunnerImpl> unthrottled_web_task_runner_;
+  RefPtr<WebTaskRunnerImpl> suspendable_web_task_runner_;
+  RefPtr<WebTaskRunnerImpl> unthrottled_but_blockable_web_task_runner_;
   RendererSchedulerImpl* renderer_scheduler_;        // NOT OWNED
   WebViewSchedulerImpl* parent_web_view_scheduler_;  // NOT OWNED
   base::trace_event::BlameContext* blame_context_;   // NOT OWNED
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
index 8d45dbd..317cb4e 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
@@ -114,10 +114,9 @@
   RuntimeEnabledFeatures::SetTimerThrottlingForHiddenFramesEnabled(true);
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -129,10 +128,9 @@
   web_view_scheduler_->SetPageVisible(false);
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -144,10 +142,9 @@
   web_frame_scheduler_->SetFrameVisible(false);
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -160,10 +157,9 @@
   web_frame_scheduler_->SetCrossOrigin(true);
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -176,10 +172,9 @@
   web_frame_scheduler_->SetCrossOrigin(true);
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -191,10 +186,9 @@
   web_view_scheduler_->SetPageVisible(false);
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -208,10 +202,9 @@
   web_frame_scheduler_->SetCrossOrigin(true);
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -222,24 +215,24 @@
   int counter = 0;
   web_frame_scheduler_->LoadingTaskRunner()->PostTask(
       BLINK_FROM_HERE, WTF::Bind(&IncrementCounter, WTF::Unretained(&counter)));
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostTask(
       BLINK_FROM_HERE, WTF::Bind(&IncrementCounter, WTF::Unretained(&counter)));
-  web_frame_scheduler_->DeferrableTaskRunner()->PostTask(
+  web_frame_scheduler_->UnthrottledTaskRunner()->PostTask(
       BLINK_FROM_HERE, WTF::Bind(&IncrementCounter, WTF::Unretained(&counter)));
-  web_frame_scheduler_->PausableTaskRunner()->PostTask(
+  web_frame_scheduler_->SuspendableTaskRunner()->PostTask(
       BLINK_FROM_HERE, WTF::Bind(&IncrementCounter, WTF::Unretained(&counter)));
-  web_frame_scheduler_->UnpausableTaskRunner()->PostTask(
+  web_frame_scheduler_->UnthrottledButBlockableTaskRunner()->PostTask(
       BLINK_FROM_HERE, WTF::Bind(&IncrementCounter, WTF::Unretained(&counter)));
 
   web_frame_scheduler_->SetPaused(true);
 
   EXPECT_EQ(0, counter);
   mock_task_runner_->RunUntilIdle();
-  EXPECT_EQ(1, counter);
+  EXPECT_EQ(2, counter);
 
   web_frame_scheduler_->SetPaused(false);
 
-  EXPECT_EQ(1, counter);
+  EXPECT_EQ(2, counter);
   mock_task_runner_->RunUntilIdle();
   EXPECT_EQ(5, counter);
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
index e16411b8..740300a 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -106,10 +106,9 @@
   web_view_scheduler_->SetPageVisible(true);
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -121,10 +120,9 @@
   web_view_scheduler_->SetPageVisible(false);
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -165,15 +163,13 @@
 
   int run_count1 = 0;
   int run_count2 = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count1),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count1),
       TimeDelta::FromMilliseconds(1));
-  web_frame_scheduler2->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler2->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler2->ThrottleableTaskRunner(),
-                        &run_count2),
+      MakeRepeatingTask(web_frame_scheduler2->TimerTaskRunner(), &run_count2),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -209,31 +205,31 @@
   std::vector<size_t> virtual_times_ms;
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
   size_t initial_virtual_time_ms =
-      web_frame_scheduler_->ThrottleableTaskRunner()
+      web_frame_scheduler_->TimerTaskRunner()
           ->MonotonicallyIncreasingVirtualTimeSeconds() *
       1000.0;
 
   web_view_scheduler_->EnableVirtualTime();
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(
-          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
-          &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->TimerTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(2));
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(
-          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
-          &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->TimerTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(20));
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(
-          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
-          &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->TimerTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(200));
 
   mock_task_runner_->RunUntilIdle();
@@ -250,7 +246,7 @@
   std::vector<size_t> virtual_times_ms;
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
   size_t initial_virtual_time_ms =
-      web_frame_scheduler_->ThrottleableTaskRunner()
+      web_frame_scheduler_->TimerTaskRunner()
           ->MonotonicallyIncreasingVirtualTimeSeconds() *
       1000.0;
 
@@ -293,10 +289,9 @@
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunTasksWhile(mock_task_runner_->TaskRunCountBelow(2000));
@@ -330,21 +325,21 @@
   web_view_scheduler_->SetVirtualTimePolicy(VirtualTimePolicy::PAUSE);
   web_view_scheduler_->EnableVirtualTime();
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostTask(
       BLINK_FROM_HERE,
       WTF::Bind(&RunOrderTask, 0, WTF::Unretained(&run_order)));
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
       WTF::Bind(&DelayedRunOrderTask, 1,
-                WTF::Passed(web_frame_scheduler_->ThrottleableTaskRunner()),
+                WTF::Passed(web_frame_scheduler_->TimerTaskRunner()),
                 WTF::Unretained(&run_order)),
       TimeDelta::FromMilliseconds(2));
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
       WTF::Bind(&DelayedRunOrderTask, 3,
-                WTF::Passed(web_frame_scheduler_->ThrottleableTaskRunner()),
+                WTF::Passed(web_frame_scheduler_->TimerTaskRunner()),
                 WTF::Unretained(&run_order)),
       TimeDelta::FromMilliseconds(4));
 
@@ -360,21 +355,21 @@
   web_view_scheduler_->SetVirtualTimePolicy(VirtualTimePolicy::ADVANCE);
   web_view_scheduler_->EnableVirtualTime();
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostTask(
       BLINK_FROM_HERE,
       WTF::Bind(&RunOrderTask, 0, WTF::Unretained(&run_order)));
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
       WTF::Bind(&DelayedRunOrderTask, 1,
-                WTF::Passed(web_frame_scheduler_->ThrottleableTaskRunner()),
+                WTF::Passed(web_frame_scheduler_->TimerTaskRunner()),
                 WTF::Unretained(&run_order)),
       TimeDelta::FromMilliseconds(2));
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
       WTF::Bind(&DelayedRunOrderTask, 3,
-                WTF::Passed(web_frame_scheduler_->ThrottleableTaskRunner()),
+                WTF::Passed(web_frame_scheduler_->TimerTaskRunner()),
                 WTF::Unretained(&run_order)),
       TimeDelta::FromMilliseconds(4));
 
@@ -397,10 +392,9 @@
   web_view_scheduler_->SetPageVisible(false);
 
   int run_count = 0;
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeRepeatingTask(web_frame_scheduler_->ThrottleableTaskRunner(),
-                        &run_count),
+      MakeRepeatingTask(web_frame_scheduler_->TimerTaskRunner(), &run_count),
       TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
@@ -416,7 +410,7 @@
   std::unique_ptr<WebFrameSchedulerImpl> web_frame_scheduler =
       web_view_scheduler_->CreateWebFrameSchedulerImpl(nullptr);
 
-  web_frame_scheduler->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE, WTF::Bind(&RunOrderTask, 1, WTF::Unretained(&run_order)),
       TimeDelta::FromMilliseconds(1));
 
@@ -442,7 +436,7 @@
   for (int i = 0; i < 10; i++) {
     WebFrameSchedulerImpl* web_frame_scheduler =
         web_view_scheduler_->CreateWebFrameSchedulerImpl(nullptr).release();
-    web_frame_scheduler->ThrottleableTaskRunner()->PostDelayedTask(
+    web_frame_scheduler->TimerTaskRunner()->PostDelayedTask(
         BLINK_FROM_HERE, MakeDeletionTask(web_frame_scheduler),
         TimeDelta::FromMilliseconds(1));
   }
@@ -450,7 +444,7 @@
 }
 
 TEST_F(WebViewSchedulerImplTest, DeleteWebViewScheduler_InTask) {
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostTask(
       BLINK_FROM_HERE, MakeDeletionTask(web_view_scheduler_.release()));
   mock_task_runner_->RunUntilIdle();
 }
@@ -461,7 +455,7 @@
   WebFrameSchedulerImpl* web_frame_scheduler =
       web_view_scheduler_->CreateWebFrameSchedulerImpl(nullptr).release();
   RefPtr<blink::WebTaskRunner> timer_task_runner =
-      web_frame_scheduler->ThrottleableTaskRunner();
+      web_frame_scheduler->TimerTaskRunner();
 
   int run_count = 0;
   timer_task_runner->PostDelayedTask(
@@ -622,7 +616,7 @@
   web_view_scheduler_->SetVirtualTimePolicy(VirtualTimePolicy::PAUSE);
   web_view_scheduler_->EnableVirtualTime();
 
-  web_frame_scheduler->ThrottleableTaskRunner()->PostTask(
+  web_frame_scheduler->TimerTaskRunner()->PostTask(
       BLINK_FROM_HERE,
       WTF::Bind(&RunOrderTask, 1, WTF::Unretained(&run_order)));
 
@@ -640,38 +634,38 @@
   std::vector<size_t> virtual_times_ms;
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
   size_t initial_virtual_time_ms =
-      web_frame_scheduler_->ThrottleableTaskRunner()
+      web_frame_scheduler_->TimerTaskRunner()
           ->MonotonicallyIncreasingVirtualTimeSeconds() *
       1000.0;
 
   web_view_scheduler_->EnableVirtualTime();
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(
-          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
-          &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->TimerTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(1));
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(
-          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
-          &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->TimerTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(2));
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(
-          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
-          &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->TimerTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(5));
 
-  web_frame_scheduler_->ThrottleableTaskRunner()->PostDelayedTask(
+  web_frame_scheduler_->TimerTaskRunner()->PostDelayedTask(
       BLINK_FROM_HERE,
-      MakeVirtualTimeRecorderTask(
-          clock_.get(), web_frame_scheduler_->ThrottleableTaskRunner(),
-          &real_times, &virtual_times_ms),
+      MakeVirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->TimerTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       TimeDelta::FromMilliseconds(7));
 
   web_view_scheduler_->GrantVirtualTimeBudget(
@@ -741,13 +735,13 @@
   mock_task_runner_->RunUntilTime(base::TimeTicks() +
                                   base::TimeDelta::FromMilliseconds(2500));
 
-  web_frame_scheduler_->ThrottleableTaskRunner()
+  web_frame_scheduler_->TimerTaskRunner()
       ->ToSingleThreadTaskRunner()
       ->PostDelayedTask(
           BLINK_FROM_HERE,
           base::Bind(&ExpensiveTestTask, clock_.get(), &run_times),
           TimeDelta::FromMilliseconds(1));
-  web_frame_scheduler_->ThrottleableTaskRunner()
+  web_frame_scheduler_->TimerTaskRunner()
       ->ToSingleThreadTaskRunner()
       ->PostDelayedTask(
           BLINK_FROM_HERE,
@@ -767,13 +761,13 @@
 
   web_view_scheduler_->SetPageVisible(false);
 
-  web_frame_scheduler_->ThrottleableTaskRunner()
+  web_frame_scheduler_->TimerTaskRunner()
       ->ToSingleThreadTaskRunner()
       ->PostDelayedTask(
           BLINK_FROM_HERE,
           base::Bind(&ExpensiveTestTask, clock_.get(), &run_times),
           TimeDelta::FromMicroseconds(1));
-  web_frame_scheduler_->ThrottleableTaskRunner()
+  web_frame_scheduler_->TimerTaskRunner()
       ->ToSingleThreadTaskRunner()
       ->PostDelayedTask(
           BLINK_FROM_HERE,
@@ -815,7 +809,7 @@
                                   base::TimeDelta::FromMilliseconds(20500));
 
   for (size_t i = 0; i < 3; ++i) {
-    web_frame_scheduler1->ThrottleableTaskRunner()
+    web_frame_scheduler1->TimerTaskRunner()
         ->ToSingleThreadTaskRunner()
         ->PostDelayedTask(
             BLINK_FROM_HERE,
@@ -838,7 +832,7 @@
       websocket_connection = web_frame_scheduler1->OnActiveConnectionCreated();
 
   for (size_t i = 0; i < 3; ++i) {
-    web_frame_scheduler1->ThrottleableTaskRunner()
+    web_frame_scheduler1->TimerTaskRunner()
         ->ToSingleThreadTaskRunner()
         ->PostDelayedTask(
             BLINK_FROM_HERE,
@@ -860,7 +854,7 @@
   run_times.clear();
 
   for (size_t i = 0; i < 3; ++i) {
-    web_frame_scheduler2->ThrottleableTaskRunner()
+    web_frame_scheduler2->TimerTaskRunner()
         ->ToSingleThreadTaskRunner()
         ->PostDelayedTask(
             BLINK_FROM_HERE,
@@ -887,7 +881,7 @@
                                   base::TimeDelta::FromMilliseconds(70500));
 
   for (size_t i = 0; i < 3; ++i) {
-    web_frame_scheduler1->ThrottleableTaskRunner()
+    web_frame_scheduler1->TimerTaskRunner()
         ->ToSingleThreadTaskRunner()
         ->PostDelayedTask(
             BLINK_FROM_HERE,
diff --git a/third_party/WebKit/Source/platform/scheduler/util/state_tracer.h b/third_party/WebKit/Source/platform/scheduler/util/state_tracer.h
new file mode 100644
index 0000000..2f7d623
--- /dev/null
+++ b/third_party/WebKit/Source/platform/scheduler/util/state_tracer.h
@@ -0,0 +1,81 @@
+// 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 THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_UTIL_STATE_TRACING_HELPER_H_
+#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_UTIL_STATE_TRACING_HELPER_H_
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+
+// TODO(altimin): this class is header-only because it is supposed to
+// be a template with tracing category as a template parameter.
+// It will happen as soon as all compilers will properly support
+// constexpr char[] in templates.
+
+namespace blink {
+namespace scheduler {
+
+// Helper class to visualize a state of an object using async trace events.
+// It relies on the caller to listen to OnTraceLogEnabled and call Start.
+class StateTracer {
+ public:
+  StateTracer(const char* name, void* object)
+      : name_(name),
+        object_(object),
+        started_(false),
+        category_enabled_(
+            TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("renderer.scheduler")) {}
+
+  ~StateTracer() {
+    if (started_)
+      TRACE_EVENT_ASYNC_END0("renderer.scheduler", name_, object_);
+  }
+
+  void Start(const char* state) {
+    if (started_)
+      return;
+    StartImpl(state);
+  }
+
+  void SetState(const char* state) {
+    if (started_)
+      TRACE_EVENT_ASYNC_END0("renderer.scheduler", name_, object_);
+    StartImpl(state);
+  }
+
+ private:
+  const char* const name_;
+  const void* const object_;
+
+  void StartImpl(const char* state) {
+    if (!started_)
+      started_ = IsEnabled();
+    if (started_) {
+      // Trace viewer logic relies on subslice starting at the exact same time
+      // as the async event.
+      base::TimeTicks now = base::TimeTicks::Now();
+      TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0("renderer.scheduler", name_,
+                                              object_, now);
+      TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0("renderer.scheduler", name_,
+                                                  object_, state, now);
+    }
+  }
+
+  bool IsEnabled() const { return *category_enabled_; }
+
+  // We need to explicitly track |started_| state to avoid race condition
+  // during RendererScheduler creation — it's created before receiving a
+  // OnTraceLogEnabled notification.
+  bool started_;
+
+  const unsigned char* category_enabled_;  // NOT OWNED
+
+  DISALLOW_COPY_AND_ASSIGN(StateTracer);
+};
+
+}  // namespace scheduler
+}  // namespace blink
+
+#endif  // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_UTIL_STATE_TRACING_HELPER_H_
diff --git a/third_party/WebKit/public/web/WebFrame.h b/third_party/WebKit/public/web/WebFrame.h
index bd94657..6aa857c 100644
--- a/third_party/WebKit/public/web/WebFrame.h
+++ b/third_party/WebKit/public/web/WebFrame.h
@@ -51,7 +51,6 @@
 class WebLocalFrame;
 class WebRemoteFrame;
 class WebSecurityOrigin;
-class WebString;
 class WebView;
 enum class WebSandboxFlags;
 struct WebFrameOwnerProperties;
@@ -98,14 +97,6 @@
 
   // Basic properties ---------------------------------------------------
 
-  // The name of this frame. If no name is given, empty string is returned.
-  virtual WebString AssignedName() const = 0;
-
-  // Sets the name of this frame. For child frames (frames that are not a
-  // top-most frame) the actual name may have a suffix appended to make the
-  // frame name unique within the hierarchy.
-  virtual void SetName(const WebString&) = 0;
-
   // The security origin of this frame.
   WebSecurityOrigin GetSecurityOrigin() const;
 
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h
index d3372d7..4811b37 100644
--- a/third_party/WebKit/public/web/WebLocalFrame.h
+++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -48,6 +48,7 @@
 class WebScriptExecutionCallback;
 class WebSharedWorkerRepositoryClient;
 class WebSpellCheckPanelHostClient;
+class WebString;
 class WebTextCheckClient;
 class WebURL;
 class WebURLLoader;
@@ -151,6 +152,12 @@
 
   virtual WebDocument GetDocument() const = 0;
 
+  // The name of this frame. If no name is given, empty string is returned.
+  virtual WebString AssignedName() const = 0;
+
+  // Sets the name of this frame.
+  virtual void SetName(const WebString&) = 0;
+
   // Hierarchy ----------------------------------------------------------
 
   // Get the highest-level LocalFrame in this frame's in-process subtree.
diff --git a/third_party/gvr-android-sdk/BUILD.gn b/third_party/gvr-android-sdk/BUILD.gn
index 3fa19e67..bc7e79ec 100644
--- a/third_party/gvr-android-sdk/BUILD.gn
+++ b/third_party/gvr-android-sdk/BUILD.gn
@@ -49,6 +49,9 @@
 
 android_aar_prebuilt("gvr_controller_java") {
   aar_path = "src/libraries/sdk-controller-1.80.0.aar"
+  deps = [
+    ":gvr_common_java",
+  ]
 }
 
 config("libgvr_config") {
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index e1637b09..062b384 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -1207,6 +1207,15 @@
   </description>
 </action>
 
+<action name="Android.ChromeHome.IPHMenuItemClicked">
+  <owner>mdjones@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <description>
+    User tapped the app menu item that triggers the Chrome Home in-product help
+    bubble.
+  </description>
+</action>
+
 <action name="Android.ChromeHome.NativeNTPShown">
   <owner>mdjones@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 998f262..1dcfa7a 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -28137,6 +28137,9 @@
   <int value="1400" label="DOWNLOAD_MAX_ATTEMPTS_REACHED">
     Exceeded maximum retries for download.
   </int>
+  <int value="1500" label="MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED">
+    The clock was set backwards too far in time.
+  </int>
 </enum>
 
 <enum name="OfflinePrefetchPageImportResult">
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 985c29d..d162a14 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -955,12 +955,26 @@
     const int forward_dir = base::i18n::IsRTL() ? -1 : 1;
     switch (event.key_code()) {
       case ui::VKEY_LEFT:
+        if (is_fullscreen_app_list_enabled_ && suggestions_container_ &&
+            suggestions_container_->selected_index() == 0) {
+          // Left arrow key moves focus back to search box when
+          // |suggestions_container|'s first app is selected.
+          ClearAnySelectedView();
+          return false;
+        }
         MoveSelected(0, -forward_dir, 0);
         return true;
       case ui::VKEY_RIGHT:
         MoveSelected(0, forward_dir, 0);
         return true;
       case ui::VKEY_UP:
+        if (is_fullscreen_app_list_enabled_ && suggestions_container_ &&
+            suggestions_container_->selected_index() != -1) {
+          // Up arrow key moves focus back to search box when
+          // |suggestions_container| is selected.
+          ClearAnySelectedView();
+          return false;
+        }
         if (is_fullscreen_app_list_enabled_ || selected_view_) {
           // Don't initiate selection with UP in non-fullscreen app list. In
           // fullscreen app list, UP is already handled by SearchBoxView.
diff --git a/ui/app_list/views/apps_grid_view_unittest.cc b/ui/app_list/views/apps_grid_view_unittest.cc
index 4ac78824..1e9a5451 100644
--- a/ui/app_list/views/apps_grid_view_unittest.cc
+++ b/ui/app_list/views/apps_grid_view_unittest.cc
@@ -932,15 +932,22 @@
   // Moves selection to the first app in the suggestions container.
   SimulateKeyPress(ui::VKEY_DOWN);
 
-  // Tests moving to previous page and moving up.
+  // Tests moving to previous page.
   SimulateKeyPress(ui::VKEY_PRIOR);
   CheckSelectionAtSuggestionsContainer(0);
+
+  // Tests moving up.
   SimulateKeyPress(ui::VKEY_UP);
+  CheckNoSelection();
+  SimulateKeyPress(ui::VKEY_DOWN);
+
+  // Tests moving left and right.
+  SimulateKeyPress(ui::VKEY_LEFT);
+  CheckNoSelection();
+  SimulateKeyPress(ui::VKEY_RIGHT);
   CheckSelectionAtSuggestionsContainer(0);
 
-  // Tests moving left, moving right and moving right out of suggestions.
-  SimulateKeyPress(ui::VKEY_LEFT);
-  CheckSelectionAtSuggestionsContainer(0);
+  // Tests moving right out of suggestions.
   SimulateKeyPress(ui::VKEY_RIGHT);
   SimulateKeyPress(ui::VKEY_RIGHT);
   CheckSelectionAtSuggestionsContainer(kNumOfSuggestedApps - 1);
@@ -1042,10 +1049,10 @@
 }
 
 // Tests that in state start when selection is on app in suggestions container,
-// hitting up key does nothing. Hitting left/right key moves the selection to
-// app on the left/right if index is valid. Hitting right key when selection is
-// on the last app in suggestions container or hitting down key move the
-// selection to the expand arrow.
+// hitting up key moves clear selection. Hitting left/right key moves the
+// selection to app on the left/right if index is valid. Hitting right key when
+// selection is on the last app in suggestions container or hitting down key
+// move the selection to the expand arrow.
 TEST_P(AppsGridViewTest, SuggestionsContainerSelectionInStateStart) {
   if (!test_with_fullscreen_)
     return;
@@ -1055,15 +1062,20 @@
   model_->PopulateApps(GetTilesPerPage(0));
   SimulateKeyPress(ui::VKEY_DOWN);
 
+  // Tests moving up.
   SimulateKeyPress(ui::VKEY_UP);
-  CheckSelectionAtSuggestionsContainer(0);
+  CheckNoSelection();
+  SimulateKeyPress(ui::VKEY_DOWN);
 
+  // Tests moving right.
   SimulateKeyPress(ui::VKEY_RIGHT);
   CheckSelectionAtSuggestionsContainer(1);
 
+  // Tests moving left.
   SimulateKeyPress(ui::VKEY_LEFT);
   CheckSelectionAtSuggestionsContainer(0);
 
+  // Tests moving down.
   SimulateKeyPress(ui::VKEY_DOWN);
   CheckSelectionAtExpandArrow();
 
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 3b73ebb9..66c7bc6f 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -352,7 +352,9 @@
   DCHECK(IsArrowKey(event));
   DCHECK(is_fullscreen_app_list_enabled_);
 
-  // Left and right arrow should work in the same way as shift+tab and tab.
+  // Special case when focus is on |search_box_| and query exists has already
+  // been handled before. Here, left and right arrow should work in the same way
+  // as shift+tab and tab.
   if (event.key_code() == ui::VKEY_LEFT)
     return MoveTabFocus(true);
   if (event.key_code() == ui::VKEY_RIGHT)
@@ -379,8 +381,7 @@
       NOTREACHED();
   }
 
-  SetSelected(IsSearchBoxTrimmedQueryEmpty() &&
-              focused_view_ == FOCUS_SEARCH_BOX);
+  SetSelected(focused_view_ == FOCUS_SEARCH_BOX);
   return (focused_view_ < FOCUS_CONTENTS_VIEW);
 }
 
@@ -394,7 +395,6 @@
     speech_button_->SetSelected(false);
   if (close_button_)
     close_button_->SetSelected(false);
-  bool search_box_selected = false;
 
   if (is_fullscreen_app_list_enabled_) {
     switch (focused_view_) {
@@ -470,13 +470,6 @@
       if (back_button_)
         back_button_->SetSelected(true);
       break;
-    case FOCUS_SEARCH_BOX:
-      if (!IsSearchBoxTrimmedQueryEmpty())
-        break;
-      // The search box should only be selected in PEEKING or
-      // FULLSCREEN_ALL_APPS state.
-      search_box_selected = true;
-      break;
     case FOCUS_MIC_BUTTON:
       if (speech_button_)
         speech_button_->SetSelected(true);
@@ -489,9 +482,9 @@
       break;
   }
 
-  SetSelected(search_box_selected);
+  SetSelected(focused_view_ == FOCUS_SEARCH_BOX);
 
-  if (focused_view_ < FOCUS_CONTENTS_VIEW)
+  if (!is_fullscreen_app_list_enabled_ && focused_view_ < FOCUS_CONTENTS_VIEW)
     delegate_->SetSearchResultSelection(focused_view_ == FOCUS_SEARCH_BOX);
 
   return (focused_view_ < FOCUS_CONTENTS_VIEW);
@@ -765,11 +758,10 @@
   const bool is_trimmed_query_empty = IsSearchBoxTrimmedQueryEmpty();
   // If the query is only whitespace, don't transition the AppListView state.
   app_list_view_->SetStateFromSearchBoxView(is_trimmed_query_empty);
-  if (is_trimmed_query_empty)
-    return;
-  // Unselect the search box when the state is transiting to HALF or
-  // FULLSCREEN_SEARCH.
-  SetSelected(false);
+  // Opened search box is shown when |is_trimmed_query_empty| is false and vice
+  // versa. Set the focus to the search results page when opened search box is
+  // shown. Otherwise, set the focus to search box.
+  ResetTabFocus(!is_trimmed_query_empty);
 }
 
 bool SearchBoxView::HandleKeyEvent(views::Textfield* sender,
@@ -780,6 +772,16 @@
         MoveTabFocus(key_event.IsShiftDown()))
       return true;
 
+    if (is_fullscreen_app_list_enabled_ &&
+        (key_event.key_code() == ui::VKEY_LEFT ||
+         key_event.key_code() == ui::VKEY_RIGHT) &&
+        focused_view_ == FOCUS_SEARCH_BOX && !search_box_->text().empty()) {
+      // When focus is on |search_box_| and query is not empty, then left and
+      // arrow key should move cursor in |search_box_|. In this situation only
+      // tab key could move the focus outside |search_box_|.
+      return false;
+    }
+
     if (is_fullscreen_app_list_enabled_ && IsArrowKey(key_event) &&
         focused_view_ != FOCUS_CONTENTS_VIEW && MoveArrowFocus(key_event))
       return true;
@@ -1022,15 +1024,21 @@
     return;
   selected_ = selected;
   if (selected) {
-    SetBorder(views::CreateRoundedRectBorder(kSearchBoxBorderWidth,
-                                             kSearchBoxFocusBorderCornerRadius,
-                                             kSearchBoxBorderColor));
-    // Set the ChromeVox focus to the search box. However, DO NOT do this if
-    // we are in the search results state (i.e., if the search box has text in
-    // it), because the focus is about to be shifted to the first search
-    // result and we do not want to read out the name of the search box as
-    // well.
+    // Set the ChromeVox focus to the search box.
     search_box_->NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true);
+    if (IsSearchBoxTrimmedQueryEmpty()) {
+      // This includes two situations: query is empty or query is a string of
+      // spaces. In both situations, opened search box is hidden and we need to
+      // show a ring around search box to indicate that it is selected.
+      SetBorder(views::CreateRoundedRectBorder(
+          kSearchBoxBorderWidth, kSearchBoxFocusBorderCornerRadius,
+          kSearchBoxBorderColor));
+    }
+    if (!search_box_->text().empty()) {
+      // If query is not empty (including a string of spaces), we need to select
+      // the entire text range.
+      search_box_->SelectAll(false);
+    }
   } else {
     SetDefaultBorder();
   }
diff --git a/ui/app_list/views/search_box_view_unittest.cc b/ui/app_list/views/search_box_view_unittest.cc
index 068b496..6cf46577 100644
--- a/ui/app_list/views/search_box_view_unittest.cc
+++ b/ui/app_list/views/search_box_view_unittest.cc
@@ -241,13 +241,7 @@
 
   KeyPress(ui::VKEY_DOWN);
   EXPECT_EQ(0, GetQueryChangedCountAndReset());
-  if (test_with_fullscreen()) {
-    // The initial down arrow key is handled by search box in fullscreen
-    // app list.
-    EXPECT_EQ(0, GetContentsViewKeyPressCountAndReset());
-  } else {
-    EXPECT_EQ(1, GetContentsViewKeyPressCountAndReset());
-  }
+  EXPECT_EQ(1, GetContentsViewKeyPressCountAndReset());
 
   view()->ClearSearch();
   EXPECT_EQ(1, GetQueryChangedCountAndReset());
diff --git a/ui/app_list/views/search_result_list_view.cc b/ui/app_list/views/search_result_list_view.cc
index 180bdc1..6d070a1 100644
--- a/ui/app_list/views/search_result_list_view.cc
+++ b/ui/app_list/views/search_result_list_view.cc
@@ -42,13 +42,13 @@
     : delegate_(delegate),
       view_delegate_(view_delegate),
       results_container_(new views::View),
-      auto_launch_indicator_(new views::View) {
+      auto_launch_indicator_(new views::View),
+      is_fullscreen_app_list_enabled_(features::IsFullscreenAppListEnabled()) {
   results_container_->SetLayoutManager(
       new views::BoxLayout(views::BoxLayout::kVertical));
 
-  const int max_results = features::IsFullscreenAppListEnabled()
-                              ? kMaxResultsFullscreen
-                              : kMaxResults;
+  const int max_results =
+      is_fullscreen_app_list_enabled_ ? kMaxResultsFullscreen : kMaxResults;
   for (int i = 0; i < max_results; ++i)
     results_container_->AddChildView(new SearchResultView(this));
   AddChildView(results_container_);
@@ -82,6 +82,7 @@
   }
 
   int selection_index = -1;
+  const int forward_dir = base::i18n::IsRTL() ? -1 : 1;
   switch (event.key_code()) {
     case ui::VKEY_TAB:
       if (event.IsShiftDown())
@@ -95,6 +96,14 @@
     case ui::VKEY_DOWN:
       selection_index = selected_index() + 1;
       break;
+    case ui::VKEY_LEFT:
+      if (is_fullscreen_app_list_enabled_)
+        selection_index = selected_index() - forward_dir;
+      break;
+    case ui::VKEY_RIGHT:
+      if (is_fullscreen_app_list_enabled_)
+        selection_index = selected_index() + forward_dir;
+      break;
     default:
       break;
   }
diff --git a/ui/app_list/views/search_result_list_view.h b/ui/app_list/views/search_result_list_view.h
index 0a1e95f5..13e9d7b 100644
--- a/ui/app_list/views/search_result_list_view.h
+++ b/ui/app_list/views/search_result_list_view.h
@@ -94,6 +94,9 @@
   views::View* auto_launch_indicator_;
   std::unique_ptr<gfx::LinearAnimation> auto_launch_animation_;
 
+  // True if the fullscreen app list feature is enabled.
+  const bool is_fullscreen_app_list_enabled_;
+
   DISALLOW_COPY_AND_ASSIGN(SearchResultListView);
 };
 
diff --git a/ui/app_list/views/search_result_page_view.cc b/ui/app_list/views/search_result_page_view.cc
index 4c4b4d93..c1e32d4 100644
--- a/ui/app_list/views/search_result_page_view.cc
+++ b/ui/app_list/views/search_result_page_view.cc
@@ -220,6 +220,7 @@
 
   int dir = 0;
   bool directional_movement = false;
+  const int forward_dir = base::i18n::IsRTL() ? -1 : 1;
   switch (event.key_code()) {
     case ui::VKEY_TAB:
       dir = event.IsShiftDown() ? -1 : 1;
@@ -232,6 +233,16 @@
       dir = 1;
       directional_movement = true;
       break;
+    case ui::VKEY_LEFT:
+      if (!is_fullscreen_app_list_enabled_)
+        return false;
+      dir = -forward_dir;
+      break;
+    case ui::VKEY_RIGHT:
+      if (!is_fullscreen_app_list_enabled_)
+        return false;
+      dir = forward_dir;
+      break;
     default:
       return false;
   }
@@ -248,6 +259,13 @@
     return true;
   }
 
+  if (!is_fullscreen_app_list_enabled_)
+    return false;
+
+  if (dir == -1) {
+    // Shift+tab/up/left key could move focus back to search box.
+    ClearSelectedIndex();
+  }
   return false;
 }
 
diff --git a/ui/app_list/views/search_result_page_view_unittest.cc b/ui/app_list/views/search_result_page_view_unittest.cc
index 35e8080..e23d630 100644
--- a/ui/app_list/views/search_result_page_view_unittest.cc
+++ b/ui/app_list/views/search_result_page_view_unittest.cc
@@ -10,6 +10,8 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "ui/app_list/app_list_features.h"
 #include "ui/app_list/app_list_model.h"
 #include "ui/app_list/app_list_switches.h"
 #include "ui/app_list/test/app_list_test_view_delegate.h"
@@ -27,8 +29,8 @@
 class SearchResultPageViewTest : public views::ViewsTestBase,
                                  public SearchResultListViewDelegate {
  public:
-  SearchResultPageViewTest() {}
-  ~SearchResultPageViewTest() override {}
+  SearchResultPageViewTest() = default;
+  ~SearchResultPageViewTest() override = default;
 
   // Overridden from testing::Test:
   void SetUp() override {
@@ -99,6 +101,43 @@
   DISALLOW_COPY_AND_ASSIGN(SearchResultPageViewTest);
 };
 
+class SearchResultPageViewFullscreenTest
+    : public SearchResultPageViewTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  SearchResultPageViewFullscreenTest() = default;
+  ~SearchResultPageViewFullscreenTest() override = default;
+
+  // Overridden from testing::Test:
+  void SetUp() override {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kEnableFullscreenAppList);
+    SearchResultPageViewTest::SetUp();
+  }
+
+ protected:
+  // Add search results for test on focus movement.
+  void SetUpFocusTestEnv() {
+    std::vector<std::pair<SearchResult::DisplayType, int>> result_types;
+    // 3 tile results, followed by 2 list results.
+    const int kTileResults = 3;
+    const int kListResults = 2;
+    const int kNoneResults = 3;
+    result_types.push_back(
+        std::make_pair(SearchResult::DISPLAY_TILE, kTileResults));
+    result_types.push_back(
+        std::make_pair(SearchResult::DISPLAY_LIST, kListResults));
+    result_types.push_back(
+        std::make_pair(SearchResult::DISPLAY_NONE, kNoneResults));
+    SetUpSearchResults(result_types);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(SearchResultPageViewFullscreenTest);
+};
+
 TEST_F(SearchResultPageViewTest, DirectionalMovement) {
   std::vector<std::pair<SearchResult::DisplayType, int>> result_types;
   // 3 tile results, followed by 2 list results.
@@ -331,5 +370,137 @@
   EXPECT_EQ(0, list_view()->selected_index());
 }
 
+TEST_F(SearchResultPageViewFullscreenTest, LeftRightMovement) {
+  SetUpFocusTestEnv();
+  EXPECT_EQ(0, GetSelectedIndex());
+  EXPECT_EQ(0, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+
+  // Navigate to the second tile in the tile group.
+  EXPECT_TRUE(KeyPress(ui::VKEY_RIGHT));
+  EXPECT_EQ(0, GetSelectedIndex());
+  EXPECT_EQ(1, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+
+  // Navigate to the list group.
+  EXPECT_TRUE(KeyPress(ui::VKEY_RIGHT));
+  EXPECT_TRUE(KeyPress(ui::VKEY_RIGHT));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(-1, tile_list_view()->selected_index());
+  EXPECT_EQ(0, list_view()->selected_index());
+
+  // Navigate to the second result in the list view.
+  EXPECT_TRUE(KeyPress(ui::VKEY_RIGHT));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(1, list_view()->selected_index());
+
+  // Attempt to navigate off bottom of list items.
+  EXPECT_FALSE(KeyPress(ui::VKEY_RIGHT));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(1, list_view()->selected_index());
+
+  // Navigate back to the tile group (should select the last tile result).
+  EXPECT_TRUE(KeyPress(ui::VKEY_LEFT));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(0, list_view()->selected_index());
+  EXPECT_TRUE(KeyPress(ui::VKEY_LEFT));
+  EXPECT_EQ(0, GetSelectedIndex());
+  EXPECT_EQ(2, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+
+  // Navigate off top of list.
+  EXPECT_TRUE(KeyPress(ui::VKEY_LEFT));
+  EXPECT_TRUE(KeyPress(ui::VKEY_LEFT));
+  EXPECT_FALSE(KeyPress(ui::VKEY_LEFT));
+  EXPECT_EQ(-1, GetSelectedIndex());
+  EXPECT_EQ(-1, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+}
+
+TEST_F(SearchResultPageViewFullscreenTest, UpDownMovement) {
+  SetUpFocusTestEnv();
+  EXPECT_EQ(0, GetSelectedIndex());
+  EXPECT_EQ(0, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+
+  // Navigate to the first result in the list view.
+  EXPECT_TRUE(KeyPress(ui::VKEY_DOWN));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(-1, tile_list_view()->selected_index());
+  EXPECT_EQ(0, list_view()->selected_index());
+
+  // Navigate to the second result in the list view.
+  EXPECT_TRUE(KeyPress(ui::VKEY_DOWN));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(1, list_view()->selected_index());
+
+  // Attempt to navigate off bottom of list items.
+  EXPECT_FALSE(KeyPress(ui::VKEY_DOWN));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(1, list_view()->selected_index());
+
+  // Navigate back to the tile group (should select the first tile result).
+  EXPECT_TRUE(KeyPress(ui::VKEY_UP));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(0, list_view()->selected_index());
+  EXPECT_TRUE(KeyPress(ui::VKEY_UP));
+  EXPECT_EQ(0, GetSelectedIndex());
+  EXPECT_EQ(0, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+
+  // Navigate off top of list.
+  EXPECT_FALSE(KeyPress(ui::VKEY_UP));
+  EXPECT_EQ(-1, GetSelectedIndex());
+  EXPECT_EQ(-1, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+}
+
+TEST_F(SearchResultPageViewFullscreenTest, TabMovement) {
+  SetUpFocusTestEnv();
+  EXPECT_EQ(0, GetSelectedIndex());
+  EXPECT_EQ(0, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+
+  // Navigate to the second tile in the tile group.
+  EXPECT_TRUE(KeyPress(ui::VKEY_TAB));
+  EXPECT_EQ(0, GetSelectedIndex());
+  EXPECT_EQ(1, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+
+  // Navigate to the list group.
+  EXPECT_TRUE(KeyPress(ui::VKEY_TAB));
+  EXPECT_TRUE(KeyPress(ui::VKEY_TAB));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(-1, tile_list_view()->selected_index());
+  EXPECT_EQ(0, list_view()->selected_index());
+
+  // Navigate to the second result in the list view.
+  EXPECT_TRUE(KeyPress(ui::VKEY_TAB));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(1, list_view()->selected_index());
+
+  // Attempt to navigate off bottom of list items.
+  EXPECT_FALSE(KeyPress(ui::VKEY_TAB));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(1, list_view()->selected_index());
+
+  // Navigate back to the tile group (should select the last tile result).
+  EXPECT_TRUE(KeyPress(ui::VKEY_TAB, true));
+  EXPECT_EQ(1, GetSelectedIndex());
+  EXPECT_EQ(0, list_view()->selected_index());
+  EXPECT_TRUE(KeyPress(ui::VKEY_TAB, true));
+  EXPECT_EQ(0, GetSelectedIndex());
+  EXPECT_EQ(2, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+
+  // Navigate off top of list.
+  EXPECT_TRUE(KeyPress(ui::VKEY_TAB, true));
+  EXPECT_TRUE(KeyPress(ui::VKEY_TAB, true));
+  EXPECT_FALSE(KeyPress(ui::VKEY_TAB, true));
+  EXPECT_EQ(-1, GetSelectedIndex());
+  EXPECT_EQ(-1, tile_list_view()->selected_index());
+  EXPECT_EQ(-1, list_view()->selected_index());
+}
+
 }  // namespace test
 }  // namespace app_list
diff --git a/ui/app_list/views/search_result_tile_item_list_view.cc b/ui/app_list/views/search_result_tile_item_list_view.cc
index 4a8d8c1..fd57b36 100644
--- a/ui/app_list/views/search_result_tile_item_list_view.cc
+++ b/ui/app_list/views/search_result_tile_item_list_view.cc
@@ -205,14 +205,16 @@
       // the beginning of the list. This means that the text cursor in the
       // search box will be allowed to handle the keypress. This will also
       // ignore the keypress if the user has clicked somewhere in the middle of
-      // the searchbox.
-      if (cursor_at_end_of_searchbox)
+      // the searchbox. In fullscreen app list, the cursor will be moved only
+      // when search box is selected.
+      if (is_fullscreen_app_list_enabled_ || cursor_at_end_of_searchbox)
         dir = -forward_dir;
       break;
     case ui::VKEY_RIGHT:
       // Only move right if the search box text cursor is at the end of the
-      // text.
-      if (cursor_at_end_of_searchbox)
+      // text. In fullscreen app list, the cursor will be moved only when search
+      // box is selected.
+      if (is_fullscreen_app_list_enabled_ || cursor_at_end_of_searchbox)
         dir = forward_dir;
       break;
     default:
diff --git a/ui/display/display.cc b/ui/display/display.cc
index dfa60075..fd5852e 100644
--- a/ui/display/display.cc
+++ b/ui/display/display.cc
@@ -95,6 +95,7 @@
 // static
 void Display::SetForceDeviceScaleFactor(double dsf) {
   // Reset any previously set values and unset the flag.
+  g_has_forced_device_scale_factor = -1;
   g_forced_device_scale_factor = -1.0;
 
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
diff --git a/ui/events/gestures/gesture_recognizer_impl.h b/ui/events/gestures/gesture_recognizer_impl.h
index f06cf6d..52901ce 100644
--- a/ui/events/gestures/gesture_recognizer_impl.h
+++ b/ui/events/gestures/gesture_recognizer_impl.h
@@ -59,6 +59,10 @@
   virtual GestureProviderAura* GetGestureProviderForConsumer(
       GestureConsumer* c);
 
+  // Overridden from GestureRecognizer
+  bool ProcessTouchEventPreDispatch(TouchEvent* event,
+                                    GestureConsumer* consumer) override;
+
  private:
   // Sets up the target consumer for gestures based on the touch-event.
   void SetupTargets(const TouchEvent& event, GestureConsumer* consumer);
@@ -66,10 +70,6 @@
   void DispatchGestureEvent(GestureConsumer* raw_input_consumer,
                             GestureEvent* event);
 
-  // Overridden from GestureRecognizer
-  bool ProcessTouchEventPreDispatch(TouchEvent* event,
-                                    GestureConsumer* consumer) override;
-
   Gestures AckTouchEvent(uint32_t unique_event_id,
                          ui::EventResult result,
                          bool is_source_touch_event_set_non_blocking,
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 2dceb8c..4af7811 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -2713,6 +2713,15 @@
     SetMsgHandled(FALSE);
     return -1;
   }
+
+  // Ignore enter/leave events, otherwise they will be converted in
+  // |GetTouchEventType| to ET_TOUCH_PRESSED/ET_TOUCH_RELEASED events, which
+  // is not correct.
+  if (message == WM_POINTERENTER || message == WM_POINTERLEAVE) {
+    SetMsgHandled(TRUE);
+    return 0;
+  }
+
   unsigned int mapped_pointer_id = id_generator_.GetGeneratedID(pointer_id);
   POINTER_INFO pointer_info = pointer_touch_info.pointerInfo;
   POINT client_point = pointer_info.ptPixelLocationRaw;
diff --git a/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.html b/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.html
index 80e7d76..a6c8777e 100644
--- a/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.html
+++ b/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.html
@@ -39,6 +39,7 @@
         border-radius: 50%;
         margin: 6px;
         padding: 20px;
+        position: static;
       }
 
       iron-icon.iron-selected {